From dc5b204126cdfbf38de3ef1df6bb00731835a6f6 Mon Sep 17 00:00:00 2001 From: Darren Reid Date: Thu, 2 May 2024 14:37:21 +1000 Subject: [PATCH 01/36] Low log levels to help ID possible issue. --- MyApp/appsettings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MyApp/appsettings.json b/MyApp/appsettings.json index e87c7bd..3b4149b 100644 --- a/MyApp/appsettings.json +++ b/MyApp/appsettings.json @@ -3,12 +3,12 @@ "IncludeScopes": false, "Debug": { "LogLevel": { - "Default": "Warning" + "Default": "Debug" } }, "Console": { "LogLevel": { - "Default": "Warning" + "Default": "Debug" } } }, From 1fb6245af6be1fc9508c1ec6ecfdcf07cd292a33 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Thu, 2 May 2024 13:12:19 +0800 Subject: [PATCH 02/36] Optimize SearchService only add Question/Answer that needs indexing --- MyApp.ServiceInterface/AiServerServices.cs | 4 +- .../Data/QuestionsProvider.cs | 28 +++- MyApp.ServiceInterface/Data/Tasks.cs | 1 + MyApp.ServiceInterface/SearchServices.cs | 142 +++++++----------- MyApp.ServiceModel/Posts.cs | 2 +- MyApp/appsettings.json | 4 +- 6 files changed, 88 insertions(+), 93 deletions(-) diff --git a/MyApp.ServiceInterface/AiServerServices.cs b/MyApp.ServiceInterface/AiServerServices.cs index 01a3dc1..3bf887e 100644 --- a/MyApp.ServiceInterface/AiServerServices.cs +++ b/MyApp.ServiceInterface/AiServerServices.cs @@ -74,7 +74,9 @@ public async Task Any(CreateAnswerCallback request) } }); - MessageProducer.Publish(new SearchTasks { AddPostToIndex = request.PostId }); + MessageProducer.Publish(new SearchTasks { + AddAnswerToIndex = answer.RefId + }); } public async Task Any(RankAnswerCallback request) diff --git a/MyApp.ServiceInterface/Data/QuestionsProvider.cs b/MyApp.ServiceInterface/Data/QuestionsProvider.cs index 75b796d..5f28255 100644 --- a/MyApp.ServiceInterface/Data/QuestionsProvider.cs +++ b/MyApp.ServiceInterface/Data/QuestionsProvider.cs @@ -108,6 +108,17 @@ public async Task WriteMetaAsync(Meta meta) await SaveFileAsync(GetMetaPath(meta.Id), ToJson(meta)); } + public async Task GetQuestionFileAsPostAsync(int id) + { + var file = await GetQuestionFileAsync(id); + if (file == null) + return null; + + var json = await file.ReadAllTextAsync(); + var post = json.FromJson(); + return post; + } + public async Task GetQuestionFilesAsync(int id) { var localFiles = GetLocalQuestionFiles(id); @@ -151,16 +162,15 @@ public async Task GetQuestionAsync(int id) : GetHumanAnswerPath(postId, userName); var file = fs.GetFile(answerPath) - ?? r2.GetFile(answerPath); + ?? await r2.GetFileAsync(answerPath); if (file == null) { // After first edit AI Model is converted to h. (Post) answer var modelAnswerPath = GetHumanAnswerPath(postId, userName); file = fs.GetFile(modelAnswerPath) - ?? r2.GetFile(modelAnswerPath); + ?? await r2.GetFileAsync(modelAnswerPath); } - return file; } @@ -199,8 +209,7 @@ public async Task SaveRemoteFileAsync(string virtualPath, string contents) public async Task GetQuestionFileAsync(int id) { - var (dir1, dir2, fileId) = id.ToFileParts(); - var questionPath = $"{dir1}/{dir2}/{fileId}.json"; + var questionPath = GetQuestionPath(id); var file = fs.GetFile(questionPath) ?? await r2.GetFileAsync(questionPath); return file; @@ -273,6 +282,15 @@ public async Task SaveQuestionEditAsync(Post question) await Task.WhenAll(tasks); } + public async Task GetAnswerAsPostAsync(string answerId) + { + var answerFile = await GetAnswerFileAsync(answerId); + if (answerFile == null) + return null; + + return await GetAnswerAsPostAsync(answerFile); + } + public async Task GetAnswerAsPostAsync(IVirtualFile existingAnswer) { var existingAnswerJson = await existingAnswer.ReadAllTextAsync(); diff --git a/MyApp.ServiceInterface/Data/Tasks.cs b/MyApp.ServiceInterface/Data/Tasks.cs index 7b348bc..cffddfa 100644 --- a/MyApp.ServiceInterface/Data/Tasks.cs +++ b/MyApp.ServiceInterface/Data/Tasks.cs @@ -191,5 +191,6 @@ public class RenderComponent : IReturnVoid public class SearchTasks { public int? AddPostToIndex { get; set; } + public string? AddAnswerToIndex { get; set; } public int? DeletePost { get; set; } } diff --git a/MyApp.ServiceInterface/SearchServices.cs b/MyApp.ServiceInterface/SearchServices.cs index 52b14c6..28081af 100644 --- a/MyApp.ServiceInterface/SearchServices.cs +++ b/MyApp.ServiceInterface/SearchServices.cs @@ -2,7 +2,6 @@ using MyApp.Data; using MyApp.ServiceModel; using ServiceStack; -using ServiceStack.IO; using ServiceStack.OrmLite; namespace MyApp.ServiceInterface; @@ -11,105 +10,80 @@ public class SearchServices(ILogger log, QuestionsProvider quest { public async Task Any(SearchTasks request) { + using var db = HostContext.AppHost.GetDbConnection(Databases.Search); + string QuotedValue(string? value) => db.GetDialectProvider().GetQuotedValue(value); + var minDate = new DateTime(2008,08,1); + if (request.AddPostToIndex != null) { var id = request.AddPostToIndex.Value; - var questionFiles = await questions.GetQuestionAsync(id); + + log.LogInformation("Adding Post '{PostId}' Question to Search Index...", id); + + var post = await questions.GetQuestionFileAsPostAsync(id); + if (post.Id == default) + throw new ArgumentNullException(nameof(post.Id)); + + var refId = post.RefId ?? post.GetRefId(); + log.LogDebug("Adding Question {Id} {Title}", post.Id, post.Title); + + var modifiedDate = post.LastEditDate ?? (post.CreationDate > minDate ? post.CreationDate : minDate); + await db.ExecuteNonQueryAsync($"DELETE FROM {nameof(PostFts)} WHERE rowid = {post.Id}"); + await db.ExecuteNonQueryAsync($@"INSERT INTO {nameof(PostFts)} ( + rowid, + {nameof(PostFts.RefId)}, + {nameof(PostFts.UserName)}, + {nameof(PostFts.Body)}, + {nameof(PostFts.Tags)}, + {nameof(PostFts.ModifiedDate)} + ) VALUES ( + {post.Id}, + '{refId}', + 'stackoverflow', + {QuotedValue(post.Title + "\n\n" + post.Body)}, + {QuotedValue(string.Join(',', post.Tags))}, + {QuotedValue(modifiedDate.ToString("yyyy-MM-dd HH:mm:ss"))} + )"); + } + else if (request.AddAnswerToIndex != null) + { + var answerId = request.AddAnswerToIndex; + var post = await questions.GetAnswerAsPostAsync(answerId); + if (post == null) + { + log.LogError("Answer '{AnswerId}' does not exist", answerId); + return; + } - log.LogInformation("Adding Post '{PostId}' Question and {AnswerCount} to Search Index...", - id, - questionFiles.GetAnswerFiles().Count()); - using var db = HostContext.AppHost.GetDbConnection(Databases.Search); var nextId = await db.ScalarAsync("SELECT MAX(rowid) FROM PostFts"); nextId += 1; - var existingIds = new HashSet(); - var minDate = new DateTime(2008,08,1); - string QuotedValue(string? value) => db.GetDialectProvider().GetQuotedValue(value); + var refId = post.RefId ?? post.GetRefId(); - var i = 0; - foreach (var file in questionFiles.Files) - { - try - { - var fileType = file.Name.RightPart('.').LastLeftPart('.'); - if (fileType == "json") - { - var post = await ToPostAsync(file); - if (post.Id == default) - throw new ArgumentNullException(nameof(post.Id)); - var refId = post.RefId ?? $"{post.Id}"; - if (!existingIds.Add(refId)) - continue; - log.LogDebug("Adding Question {FilePath}", file.VirtualPath); - var modifiedDate = post.LastEditDate ?? (post.CreationDate > minDate ? post.CreationDate : minDate); - await db.ExecuteNonQueryAsync($"DELETE FROM {nameof(PostFts)} WHERE rowid = {post.Id}"); - await db.ExecuteNonQueryAsync($@"INSERT INTO {nameof(PostFts)} ( - rowid, - {nameof(PostFts.RefId)}, - {nameof(PostFts.UserName)}, - {nameof(PostFts.Body)}, - {nameof(PostFts.Tags)}, - {nameof(PostFts.ModifiedDate)} - ) VALUES ( - {post.Id}, - '{refId}', - 'stackoverflow', - {QuotedValue(post.Title + "\n\n" + post.Body)}, - {QuotedValue(string.Join(',',post.Tags))}, - {QuotedValue(modifiedDate.ToString("yyyy-MM-dd HH:mm:ss"))} - )"); - } - else if (fileType.StartsWith("h.")) - { - var post = await ToPostAsync(file); - post.CreatedBy ??= fileType.Substring(2); - var refId = post.RefId ?? post.GetRefId(); - if (!existingIds.Add(refId)) - continue; + log.LogInformation("Adding Answer '{RefId}' to Search Index...", answerId); - log.LogDebug("Adding Human Answer {FilePath}", file.VirtualPath); - var modifiedDate = post.LastEditDate ?? (post.CreationDate > minDate ? post.CreationDate : minDate); - await db.ExecuteNonQueryAsync($"DELETE FROM {nameof(PostFts)} where {nameof(PostFts.RefId)} = {QuotedValue(refId)}"); - await db.ExecuteNonQueryAsync($@"INSERT INTO {nameof(PostFts)} ( - rowid, - {nameof(PostFts.RefId)}, - {nameof(PostFts.UserName)}, - {nameof(PostFts.Body)}, - {nameof(PostFts.ModifiedDate)} - ) VALUES ( - {nextId++}, - {QuotedValue(refId)}, - {QuotedValue(post.CreatedBy)}, - {QuotedValue(post.Body)}, - {QuotedValue(modifiedDate.ToString("yyyy-MM-dd HH:mm:ss"))} - )"); - } - else - { - log.LogDebug("Skipping {FilePath}", file.VirtualPath); - } - } - catch (Exception e) - { - log.LogError(e, "Error indexing {File}", file.VirtualPath); - } - } + var modifiedDate = post.LastEditDate ?? (post.CreationDate > minDate ? post.CreationDate : minDate); + await db.ExecuteNonQueryAsync($"DELETE FROM {nameof(PostFts)} where {nameof(PostFts.RefId)} = {QuotedValue(refId)}"); + await db.ExecuteNonQueryAsync($@"INSERT INTO {nameof(PostFts)} ( + rowid, + {nameof(PostFts.RefId)}, + {nameof(PostFts.UserName)}, + {nameof(PostFts.Body)}, + {nameof(PostFts.ModifiedDate)} + ) VALUES ( + {nextId}, + {QuotedValue(refId)}, + {QuotedValue(post.CreatedBy)}, + {QuotedValue(post.Body)}, + {QuotedValue(modifiedDate.ToString("yyyy-MM-dd HH:mm:ss"))} + )"); } if (request.DeletePost != null) { var id = request.DeletePost.Value; log.LogInformation("Deleting Post '{PostId}' from Search Index...", id); - using var db = HostContext.AppHost.GetDbConnection(Databases.Search); await db.ExecuteNonQueryAsync($"DELETE FROM PostFts where RefId = '{id}' or RefId LIKE '{id}-%'"); } } - - async Task ToPostAsync(IVirtualFile file) - { - var json = await file.ReadAllTextAsync(); - var post = json.FromJson(); - return post; - } } diff --git a/MyApp.ServiceModel/Posts.cs b/MyApp.ServiceModel/Posts.cs index cbdc86b..48e456d 100644 --- a/MyApp.ServiceModel/Posts.cs +++ b/MyApp.ServiceModel/Posts.cs @@ -65,7 +65,7 @@ public class Post : IMeta public Dictionary? Meta { get; set; } - public string GetRefId() => RefId ?? $"{Id}-{CreatedBy}"; + public string GetRefId() => RefId ?? (PostTypeId == 1 ? $"{Id}" : $"{Id}-{CreatedBy}"); } public static class PostUtils diff --git a/MyApp/appsettings.json b/MyApp/appsettings.json index 3b4149b..e87c7bd 100644 --- a/MyApp/appsettings.json +++ b/MyApp/appsettings.json @@ -3,12 +3,12 @@ "IncludeScopes": false, "Debug": { "LogLevel": { - "Default": "Debug" + "Default": "Warning" } }, "Console": { "LogLevel": { - "Default": "Debug" + "Default": "Warning" } } }, From 0546ea8ffb2b10a7bbb97bd5bfac73675f082803 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Thu, 2 May 2024 14:11:11 +0800 Subject: [PATCH 03/36] improved logging to Search Services --- MyApp.ServiceInterface/SearchServices.cs | 27 ++++++++++++------------ 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/MyApp.ServiceInterface/SearchServices.cs b/MyApp.ServiceInterface/SearchServices.cs index 28081af..5b5ab5a 100644 --- a/MyApp.ServiceInterface/SearchServices.cs +++ b/MyApp.ServiceInterface/SearchServices.cs @@ -17,16 +17,16 @@ public async Task Any(SearchTasks request) if (request.AddPostToIndex != null) { var id = request.AddPostToIndex.Value; - - log.LogInformation("Adding Post '{PostId}' Question to Search Index...", id); - var post = await questions.GetQuestionFileAsPostAsync(id); - if (post.Id == default) - throw new ArgumentNullException(nameof(post.Id)); + if (post?.Id == default) + { + log.LogError("[SEARCH] Question '{Id}' does not exist", id); + return; + } var refId = post.RefId ?? post.GetRefId(); - log.LogDebug("Adding Question {Id} {Title}", post.Id, post.Title); - + log.LogInformation("[SEARCH] Adding Question {PostId} '{Title}' to Search Index...", id, post.Title); + var modifiedDate = post.LastEditDate ?? (post.CreationDate > minDate ? post.CreationDate : minDate); await db.ExecuteNonQueryAsync($"DELETE FROM {nameof(PostFts)} WHERE rowid = {post.Id}"); await db.ExecuteNonQueryAsync($@"INSERT INTO {nameof(PostFts)} ( @@ -51,19 +51,18 @@ await db.ExecuteNonQueryAsync($@"INSERT INTO {nameof(PostFts)} ( var post = await questions.GetAnswerAsPostAsync(answerId); if (post == null) { - log.LogError("Answer '{AnswerId}' does not exist", answerId); + log.LogError("[SEARCH] Answer '{AnswerId}' does not exist", answerId); return; } - var nextId = await db.ScalarAsync("SELECT MAX(rowid) FROM PostFts"); - nextId += 1; - var refId = post.RefId ?? post.GetRefId(); - - log.LogInformation("Adding Answer '{RefId}' to Search Index...", answerId); + log.LogInformation("[SEARCH] Adding Answer '{RefId}' to Search Index...", answerId); var modifiedDate = post.LastEditDate ?? (post.CreationDate > minDate ? post.CreationDate : minDate); await db.ExecuteNonQueryAsync($"DELETE FROM {nameof(PostFts)} where {nameof(PostFts.RefId)} = {QuotedValue(refId)}"); + + var nextId = await db.ScalarAsync("SELECT MAX(rowid) FROM PostFts"); + nextId += 1; await db.ExecuteNonQueryAsync($@"INSERT INTO {nameof(PostFts)} ( rowid, {nameof(PostFts.RefId)}, @@ -82,7 +81,7 @@ await db.ExecuteNonQueryAsync($@"INSERT INTO {nameof(PostFts)} ( if (request.DeletePost != null) { var id = request.DeletePost.Value; - log.LogInformation("Deleting Post '{PostId}' from Search Index...", id); + log.LogInformation("[SEARCH] Deleting Post '{PostId}' from Search Index...", id); await db.ExecuteNonQueryAsync($"DELETE FROM PostFts where RefId = '{id}' or RefId LIKE '{id}-%'"); } } From f51427d67c64d6a1312c90286796ec4034f17de2 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Thu, 2 May 2024 15:44:59 +0800 Subject: [PATCH 04/36] Update appsettings.json --- MyApp/appsettings.json | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/MyApp/appsettings.json b/MyApp/appsettings.json index e87c7bd..2a570c2 100644 --- a/MyApp/appsettings.json +++ b/MyApp/appsettings.json @@ -1,15 +1,8 @@ { "Logging": { - "IncludeScopes": false, - "Debug": { - "LogLevel": { - "Default": "Warning" - } - }, - "Console": { - "LogLevel": { - "Default": "Warning" - } + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", From d24b49b06cedda4cdd84572f978d2f14e4e4450f Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Thu, 2 May 2024 16:46:53 +0800 Subject: [PATCH 05/36] Raise the quotas --- MyApp.ServiceInterface/Data/AppConfig.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index 723da81..2bc2627 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -47,11 +47,11 @@ public static (string Model, int Questions)[] ModelsForQuestions = ("gpt3.5-turbo", 10), ("claude3-haiku", 25), ("command-r", 50), - ("wizardlm", 75), - ("claude3-sonnet", 100), + ("wizardlm", 100), + ("claude3-sonnet", 175), ("command-r-plus", 150), - ("gpt4-turbo", 200), - ("claude3-opus", 300), + ("gpt4-turbo", 250), + ("claude3-opus", 400), ]; public static int[] QuestionLevels = ModelsForQuestions.Select(x => x.Questions).Distinct().OrderBy(x => x).ToArray(); From 2e3e3cd64585a5a152bb63d5cd392a77848c6f3f Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 May 2024 03:18:34 +0800 Subject: [PATCH 06/36] Add Tag to OpenAiChat tasks --- MyApp.ServiceInterface/AiServer/CreateAnswerTasksCommand.cs | 1 + MyApp.ServiceInterface/AiServer/CreateRankAnswerTaskCommand.cs | 1 + MyApp.ServiceModel/OpenAi.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/MyApp.ServiceInterface/AiServer/CreateAnswerTasksCommand.cs b/MyApp.ServiceInterface/AiServer/CreateAnswerTasksCommand.cs index c08073c..a165647 100644 --- a/MyApp.ServiceInterface/AiServer/CreateAnswerTasksCommand.cs +++ b/MyApp.ServiceInterface/AiServer/CreateAnswerTasksCommand.cs @@ -46,6 +46,7 @@ public async Task ExecuteAsync(CreateAnswerTasks request) log.LogInformation("Creating Question {Id} OpenAiChat Model for {UserName} to AI Server", question.Id, userName); var response = await client.PostAsync(new CreateOpenAiChat { + Tag = "pvq", ReplyTo = appConfig.BaseUrl.CombineWith("api", nameof(CreateAnswerCallback).AddQueryParams(new() { [nameof(CreateAnswerCallback.PostId)] = question.Id, [nameof(CreateAnswerCallback.UserId)] = modelUser.Id, diff --git a/MyApp.ServiceInterface/AiServer/CreateRankAnswerTaskCommand.cs b/MyApp.ServiceInterface/AiServer/CreateRankAnswerTaskCommand.cs index e933eba..dd96b63 100644 --- a/MyApp.ServiceInterface/AiServer/CreateRankAnswerTaskCommand.cs +++ b/MyApp.ServiceInterface/AiServer/CreateRankAnswerTaskCommand.cs @@ -62,6 +62,7 @@ Concisely articulate what a good answer needs to contain and how the answer prov var client = appConfig.CreateAiServerClient(); var api = await client.ApiAsync(new CreateOpenAiChat { RefId = Guid.NewGuid().ToString("N"), + Tag = "pvq", Provider = null, ReplyTo = appConfig.BaseUrl.CombineWith("api", nameof(RankAnswerCallback).AddQueryParams(new() { [nameof(RankAnswerCallback.PostId)] = postId, diff --git a/MyApp.ServiceModel/OpenAi.cs b/MyApp.ServiceModel/OpenAi.cs index 06c7281..d079002 100644 --- a/MyApp.ServiceModel/OpenAi.cs +++ b/MyApp.ServiceModel/OpenAi.cs @@ -49,6 +49,7 @@ public class CreateOpenAiChat : IReturn public string? RefId { get; set; } public string? Provider { get; set; } public string? ReplyTo { get; set; } + public string? Tag { get; set; } public OpenAiChat Request { get; set; } } From 3d87f6af254a0c343c8286ffdf538df7490963be Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 May 2024 13:27:40 +0800 Subject: [PATCH 07/36] reduce models used for stackoverflow/mythz/pvq --- MyApp.ServiceInterface/Data/AppConfig.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index 2bc2627..3f9e5fc 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -198,6 +198,9 @@ await db.UpdateOnlyAsync(() => public List GetAnswerModelUsersFor(string? userName) { var questionsCount = GetQuestionCount(userName); + if (userName is "stackoverflow" or "mythz" or "pvq") + questionsCount = 5; + var models = ModelsForQuestions.Where(x => x.Questions <= questionsCount) .Select(x => x.Model) .ToList(); From 81fd044001edf11f3bc92695824acf88623570bd Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 May 2024 13:31:24 +0800 Subject: [PATCH 08/36] give different counts for different users --- MyApp.ServiceInterface/Data/AppConfig.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index 3f9e5fc..b1b2c53 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -198,8 +198,12 @@ await db.UpdateOnlyAsync(() => public List GetAnswerModelUsersFor(string? userName) { var questionsCount = GetQuestionCount(userName); - if (userName is "stackoverflow" or "mythz" or "pvq") + if (userName is "stackoverflow" or "reddit" or "discourse") questionsCount = 5; + if (userName is "pvq") + questionsCount = 25; + if (userName is "mythz") + questionsCount = 100; var models = ModelsForQuestions.Where(x => x.Questions <= questionsCount) .Select(x => x.Model) From e1eb3b314c86918099e01d6a697aa1e81e4795f1 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 May 2024 13:42:50 +0800 Subject: [PATCH 09/36] Update AppConfig.cs --- MyApp.ServiceInterface/Data/AppConfig.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index b1b2c53..6efc520 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -103,10 +103,15 @@ public int GetReputationValue(string? userName) => ? 1 : reputation; - public int GetQuestionCount(string? userName) => - userName == null || !UsersQuestions.TryGetValue(userName, out var count) - ? 0 - : count + (Stats.IsAdminOrModerator(userName) ? 10 : 0); + public int GetQuestionCount(string? userName) => userName switch + { + "stackoverflow" or "reddit" or "discourse" => 5, + "pvq" => 25, + "mythz" => 100, + _ => userName == null || !UsersQuestions.TryGetValue(userName, out var count) + ? 0 + : count + (Stats.IsAdminOrModerator(userName) ? 10 : 0) + }; public void Init(IDbConnection db) { @@ -198,12 +203,6 @@ await db.UpdateOnlyAsync(() => public List GetAnswerModelUsersFor(string? userName) { var questionsCount = GetQuestionCount(userName); - if (userName is "stackoverflow" or "reddit" or "discourse") - questionsCount = 5; - if (userName is "pvq") - questionsCount = 25; - if (userName is "mythz") - questionsCount = 100; var models = ModelsForQuestions.Where(x => x.Questions <= questionsCount) .Select(x => x.Model) From 6b7f0b9ea6b0cb165b8c4c185ff41cd4cd8e744b Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 May 2024 14:53:36 +0800 Subject: [PATCH 10/36] replace using C# client with curl for importing from reddit --- .../App/ImportQuestionCommand.cs | 46 +++++++++++++++---- MyApp.Tests/TestUtils.cs | 5 +- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/MyApp.ServiceInterface/App/ImportQuestionCommand.cs b/MyApp.ServiceInterface/App/ImportQuestionCommand.cs index 55db483..1bf835f 100644 --- a/MyApp.ServiceInterface/App/ImportQuestionCommand.cs +++ b/MyApp.ServiceInterface/App/ImportQuestionCommand.cs @@ -132,13 +132,7 @@ public async Task ExecuteAsync(ImportQuestion request) else if (request.Site == ImportSite.Reddit) { var url = request.Url.Trim('/') + ".json"; - var json = await url.GetJsonFromUrlAsync(requestFilter: c => - { - c.AddHeader(HttpHeaders.UserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0"); - c.AddHeader(HttpHeaders.Accept, "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"); - c.AddHeader(HttpHeaders.AcceptLanguage, "en-US,en;q=0.9"); - c.AddHeader(HttpHeaders.CacheControl, "max-age=0"); - }); + var json = await GetJsonFromRedditAsync(url); var objs = (List)JSON.parse(json); var obj = (Dictionary)objs[0]; var data = (Dictionary)obj["data"]; @@ -170,7 +164,43 @@ public async Task ExecuteAsync(ImportQuestion request) if (Result == null) throw new Exception("Import failed"); } - + + private static async Task GetJsonFromRedditAsync(string url) + { + // C# HttpClient requests are getting blocked + // var json = await url.GetJsonFromUrlAsync(requestFilter: c => + // { + // c.AddHeader(HttpHeaders.UserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0"); + // c.AddHeader(HttpHeaders.Accept, "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"); + // c.AddHeader(HttpHeaders.AcceptLanguage, "en-US,en;q=0.9"); + // c.AddHeader(HttpHeaders.CacheControl, "max-age=0"); + // }); + // return json; + + // Using curl Instead: + var args = new[] + { + $"curl -s '{url}'", + "-H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'", + "-H 'accept-language: en-US,en;q=0.9'", + "-H 'cache-control: max-age=0'", + "-H 'dnt: 1'", + "-H 'priority: u=0, i'", + "-H 'upgrade-insecure-requests: 1'", + "-H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'" + }.ToList(); + if (Env.IsWindows) + { + args = args.Map(x => x.Replace('\'', '"')); + } + + var argsString = string.Join(" ", args); + var sb = StringBuilderCache.Allocate(); + await ProcessUtils.RunShellAsync(argsString, onOut:line => sb.AppendLine(line)); + var json = StringBuilderCache.ReturnAndFree(sb); + return json; + } + public static AskQuestion? CreateFromStackOverflowInlineEdit(string html) { var span = html.AsSpan(); diff --git a/MyApp.Tests/TestUtils.cs b/MyApp.Tests/TestUtils.cs index 592245c..94254a1 100644 --- a/MyApp.Tests/TestUtils.cs +++ b/MyApp.Tests/TestUtils.cs @@ -8,7 +8,8 @@ public static class TestUtils public static string GetHostDir() { LogManager.LogFactory = new ConsoleLogFactory(); - var appSettings = JSON.parse(File.ReadAllText(Path.GetFullPath("appsettings.json"))); - return appSettings.ToObjectDictionary()["HostDir"].ToString()!; + return "../../../../MyApp"; + // var appSettings = JSON.parse(File.ReadAllText(Path.GetFullPath("appsettings.json"))); + // return appSettings.ToObjectDictionary()["HostDir"].ToString()!; } } \ No newline at end of file From 67cc18297f9cc33ff2afeace6aa5d5f3bb91263f Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 May 2024 16:14:26 +0800 Subject: [PATCH 11/36] Update ImportTests.cs --- MyApp.Tests/ImportTests.cs | 71 ++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/MyApp.Tests/ImportTests.cs b/MyApp.Tests/ImportTests.cs index 6095eac..bb3add3 100644 --- a/MyApp.Tests/ImportTests.cs +++ b/MyApp.Tests/ImportTests.cs @@ -3,6 +3,7 @@ using MyApp.ServiceInterface.App; using MyApp.ServiceModel; using NUnit.Framework; +using ServiceStack; using ServiceStack.Text; namespace MyApp.Tests; @@ -154,21 +155,71 @@ await command.ExecuteAsync(new ImportQuestion Assert.That(result.RefId, Is.EqualTo("askubuntu.com:1509058")); } + record RedditTest(string Url, string Title, string BodyPrefix, string[] Tags, string RefUrn); + RedditTest[] RedditTests = + [ + new RedditTest( + "https://www.reddit.com/r/dotnet/comments/1byolum/all_the_net_tech_i_use_what_else_is_out_there/", + "All the .NET tech I use. What else is out there that is a must-have?", + "Sitting here tonight writing down everything in my technical stack", + [".net", "stack", "bit", "dump", "oop"], + "reddit.dotnet:1byolum" + ), + new RedditTest( + "https://www.reddit.com/r/dotnet/comments/1cfr36q/rpc_calls_state_of_the_art/", + "RPC calls - state of the art", + "Hi", + [".net", "database", "client", ".net", "odbc"], + "reddit.dotnet:1cfr36q" + ) + ]; + [Test] public async Task Can_import_from_reddit() { var command = CreateCommand(); - - await command.ExecuteAsync(new ImportQuestion + + foreach (var reddit in RedditTests) { - Site = ImportSite.Reddit, - Url = "https://www.reddit.com/r/dotnet/comments/1byolum/all_the_net_tech_i_use_what_else_is_out_there/", - }); + await command.ExecuteAsync(new ImportQuestion + { + Site = ImportSite.Reddit, + Url = reddit.Url, + }); + + var result = command.Result!; + Assert.That(result.Title, Is.EqualTo(reddit.Title)); + Assert.That(result.Body, Does.StartWith(reddit.BodyPrefix)); + Assert.That(result.Tags, Is.EquivalentTo(reddit.Tags)); + Assert.That(result.RefUrn, Is.EqualTo(reddit.RefUrn)); + } + } - var result = command.Result!; - Assert.That(result.Title, Is.EqualTo("All the .NET tech I use. What else is out there that is a must-have?")); - Assert.That(result.Body, Does.StartWith("Sitting here tonight writing down everything in my technical stack")); - Assert.That(result.Tags, Is.EquivalentTo(new[]{ "bit", "dump", "oop", "solid", "stack" })); - Assert.That(result.RefId, Is.EqualTo("reddit.dotnet:1byolum")); + [Explicit("Requires curl")] + [Test] + public async Task Can_call_curl_to_get_url() + { + var url = "https://www.reddit.com/r/dotnet/comments/1byolum/all_the_net_tech_i_use_what_else_is_out_there.json"; + var args = new[] + { + $"curl -s '{url}'", + "-H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'", + "-H 'accept-language: en-US,en;q=0.9'", + "-H 'cache-control: max-age=0'", + "-H 'dnt: 1'", + "-H 'priority: u=0, i'", + "-H 'upgrade-insecure-requests: 1'", + "-H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'" + }.ToList(); + if (Env.IsWindows) + { + args = args.Map(x => x.Replace('\'', '"')); + } + + var argsString = string.Join(" ", args); + var sb = StringBuilderCache.Allocate(); + await ProcessUtils.RunShellAsync(argsString, onOut:line => sb.AppendLine(line)); + var result = StringBuilderCache.ReturnAndFree(sb); + Assert.That(result.Trim(), Does.StartWith("[{")); } } \ No newline at end of file From a4f0fbc8a2b2bc9f7612e88d540c3893ebd9d4f3 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 May 2024 21:50:51 +0800 Subject: [PATCH 12/36] Add proper support for Reddit Import --- .../App/ImportQuestionCommand.cs | 68 +++++++++++-------- MyApp.ServiceInterface/Data/AppConfig.cs | 3 + MyApp.Tests/ImportTests.cs | 46 ++++++++++--- MyApp/Configure.AppHost.cs | 3 + 4 files changed, 83 insertions(+), 37 deletions(-) diff --git a/MyApp.ServiceInterface/App/ImportQuestionCommand.cs b/MyApp.ServiceInterface/App/ImportQuestionCommand.cs index 1bf835f..2e2de3a 100644 --- a/MyApp.ServiceInterface/App/ImportQuestionCommand.cs +++ b/MyApp.ServiceInterface/App/ImportQuestionCommand.cs @@ -165,42 +165,52 @@ public async Task ExecuteAsync(ImportQuestion request) throw new Exception("Import failed"); } - private static async Task GetJsonFromRedditAsync(string url) + private async Task GetJsonFromRedditAsync(string url) { - // C# HttpClient requests are getting blocked - // var json = await url.GetJsonFromUrlAsync(requestFilter: c => - // { - // c.AddHeader(HttpHeaders.UserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0"); - // c.AddHeader(HttpHeaders.Accept, "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"); - // c.AddHeader(HttpHeaders.AcceptLanguage, "en-US,en;q=0.9"); - // c.AddHeader(HttpHeaders.CacheControl, "max-age=0"); - // }); - // return json; - - // Using curl Instead: - var args = new[] - { - $"curl -s '{url}'", - "-H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'", - "-H 'accept-language: en-US,en;q=0.9'", - "-H 'cache-control: max-age=0'", - "-H 'dnt: 1'", - "-H 'priority: u=0, i'", - "-H 'upgrade-insecure-requests: 1'", - "-H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'" - }.ToList(); - if (Env.IsWindows) + url = url.Replace("www.reddit.com", "oauth.reddit.com"); + if (appConfig.RedditAccessToken != null) { - args = args.Map(x => x.Replace('\'', '"')); + try + { + return await url.GetJsonFromUrlAsync(requestFilter: req => { + req.AddBearerToken(appConfig.RedditAccessToken); + req.AddHeader("User-Agent", "pvq.app"); + }); + } + catch (Exception e) + { + log.LogWarning("Failed to fetch Reddit API: {Message}\nRetrieving new access_token...", e.Message); + appConfig.RedditAccessToken = null; + } } + + appConfig.RedditAccessToken = await FetchNewRedditAccessTokenAsync(); - var argsString = string.Join(" ", args); - var sb = StringBuilderCache.Allocate(); - await ProcessUtils.RunShellAsync(argsString, onOut:line => sb.AppendLine(line)); - var json = StringBuilderCache.ReturnAndFree(sb); + var json = await url.GetJsonFromUrlAsync(requestFilter: req => { + req.AddBearerToken(appConfig.RedditAccessToken); + req.AddHeader("User-Agent", "pvq.app"); + }); return json; } + private async Task FetchNewRedditAccessTokenAsync() + { + Dictionary postData = new() + { + ["grant_type"] = "client_credentials", + ["device_id"] = Guid.NewGuid().ToString("N"), + }; + var response = await "https://www.reddit.com/api/v1/access_token".PostToUrlAsync(postData, requestFilter: req => + { + req.AddBasicAuth( + appConfig.RedditClient ?? throw new ArgumentNullException(nameof(appConfig.RedditClient)), + appConfig.RedditSecret ?? throw new ArgumentNullException(nameof(appConfig.RedditSecret))); + req.AddHeader("User-Agent", "pvq.app"); + }); + var obj = (Dictionary)JSON.parse(response); + return (string)obj["access_token"]; + } + public static AskQuestion? CreateFromStackOverflowInlineEdit(string html) { var span = html.AsSpan(); diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index 6efc520..47d0f55 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -20,6 +20,9 @@ public class AppConfig public string AiServerBaseUrl { get; set; } public string AiServerApiKey { get; set; } + public string? RedditClient { get; set; } + public string? RedditSecret { get; set; } + public string? RedditAccessToken { get; set; } public JsonApiClient CreateAiServerClient() => new(AiServerBaseUrl) { BearerToken = AiServerApiKey }; public string CacheDir { get; set; } diff --git a/MyApp.Tests/ImportTests.cs b/MyApp.Tests/ImportTests.cs index bb3add3..b314291 100644 --- a/MyApp.Tests/ImportTests.cs +++ b/MyApp.Tests/ImportTests.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using MyApp.Data; using MyApp.ServiceInterface.App; using MyApp.ServiceModel; @@ -17,7 +18,11 @@ private static AppConfig CreateAppConfig() var hostDir = TestUtils.GetHostDir(); var allTagsFile = new FileInfo(Path.GetFullPath(Path.Combine(hostDir, "wwwroot", "data", "tags.txt"))); - var to = new AppConfig(); + var to = new AppConfig + { + RedditClient = Environment.GetEnvironmentVariable("REDDIT_CLIENT"), + RedditSecret = Environment.GetEnvironmentVariable("REDDIT_SECRET") + }; to.LoadTags(allTagsFile); return to; } @@ -27,13 +32,7 @@ public ImportTests() appConfig = CreateAppConfig(); } - class MockLogger : ILogger - { - public IDisposable? BeginScope(TState state) where TState : notnull => null; - public bool IsEnabled(LogLevel logLevel) => false; - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) {} - } - private ImportQuestionCommand CreateCommand() => new (new MockLogger(), appConfig); + private ImportQuestionCommand CreateCommand() => new(new NullLogger(), appConfig); [Test] public async Task Can_import_from_discourse_url() @@ -174,6 +173,7 @@ record RedditTest(string Url, string Title, string BodyPrefix, string[] Tags, st ) ]; + [Explicit("Requires REDDIT_CLIENT and REDDIT_SECRET env vars")] [Test] public async Task Can_import_from_reddit() { @@ -195,6 +195,36 @@ await command.ExecuteAsync(new ImportQuestion } } + [Explicit("Requires REDDIT_CLIENT and REDDIT_SECRET env vars")] + [Test] + public async Task Can_request_using_OAuth() + { + var redditOAuthUrl = "https://www.reddit.com/api/v1/access_token"; + var uuid = Guid.NewGuid().ToString("N"); + Dictionary postData = new() + { + ["grant_type"] = "client_credentials", + ["device_id"] = uuid, + }; + var response = await redditOAuthUrl.PostToUrlAsync(postData, requestFilter: req => + { + req.AddBasicAuth(Environment.GetEnvironmentVariable("REDDIT_CLIENT")!, Environment.GetEnvironmentVariable("REDDIT_SECRET")!); + req.AddHeader("User-Agent", "pvq.app"); + }); + + var obj = (Dictionary)JSON.parse(response); + obj.PrintDump(); + var accessToken = (string)obj["access_token"]; + var json = await "https://oauth.reddit.com/r/dotnet/comments/1byolum/all_the_net_tech_i_use_what_else_is_out_there.json" + .GetJsonFromUrlAsync(requestFilter: req => + { + req.AddBearerToken(accessToken); + req.AddHeader("User-Agent", "pvq.app"); + }); + + json.Print(); + } + [Explicit("Requires curl")] [Test] public async Task Can_call_curl_to_get_url() diff --git a/MyApp/Configure.AppHost.cs b/MyApp/Configure.AppHost.cs index eef9568..197c611 100644 --- a/MyApp/Configure.AppHost.cs +++ b/MyApp/Configure.AppHost.cs @@ -24,6 +24,9 @@ public void Configure(IWebHostBuilder builder) => builder services.AddSingleton(); + AppConfig.Instance.RedditClient ??= Environment.GetEnvironmentVariable("REDDIT_CLIENT"); + AppConfig.Instance.RedditSecret ??= Environment.GetEnvironmentVariable("REDDIT_SECRET"); + var r2Bucket = context.Configuration.GetValue("R2Bucket", "pvq-dev"); var r2AccountId = context.Configuration.GetValue("R2AccountId", Environment.GetEnvironmentVariable("R2_ACCOUNT_ID")); var r2AccessId = context.Configuration.GetValue("R2AccessKeyId", Environment.GetEnvironmentVariable("R2_ACCESS_KEY_ID")); From d1054a232a754bd48a2b267cd9dc95d0a439cc75 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 May 2024 22:19:53 +0800 Subject: [PATCH 13/36] Update AppConfig.cs --- MyApp.ServiceInterface/Data/AppConfig.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index 47d0f55..32c1768 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -162,7 +162,7 @@ public void UpdateUsersQuestions(IDbConnection db) public void ResetInitialPostId(IDbConnection db) { var maxPostId = db.Scalar("SELECT MAX(Id) FROM Post"); - SetInitialPostId(Math.Max(100_000_000, maxPostId)); + SetInitialPostId(Math.Max(100_000_000, maxPostId + 1)); } public void ResetUsersReputation(IDbConnection db) From d249cc1bd5b9ad38b45cbeb53f712519e95854fa Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Fri, 3 May 2024 23:21:49 +0800 Subject: [PATCH 14/36] Add ResaveQuestionFromFile --- MyApp.ServiceInterface/AdminServices.cs | 32 +++++++++++++++++++++++-- MyApp.ServiceModel/Moderation.cs | 7 ++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/MyApp.ServiceInterface/AdminServices.cs b/MyApp.ServiceInterface/AdminServices.cs index d7695f6..3190327 100644 --- a/MyApp.ServiceInterface/AdminServices.cs +++ b/MyApp.ServiceInterface/AdminServices.cs @@ -3,10 +3,12 @@ using MyApp.ServiceInterface.Renderers; using MyApp.ServiceModel; using ServiceStack; +using ServiceStack.OrmLite; namespace MyApp.ServiceInterface; -public class AdminServices(AppConfig appConfig, ICommandExecutor executor, UserManager userManager) +public class AdminServices(AppConfig appConfig, ICommandExecutor executor, UserManager userManager, + QuestionsProvider questions) : Service { private static readonly List initUserNames = new() @@ -80,4 +82,30 @@ public async Task Any(AdminResetCommonPassword request) return new AdminResetCommonPasswordResponse { UpdatedUsers = updatedUsers }; } -} \ No newline at end of file + + public async Task Any(ResaveQuestionFromFile request) + { + var post = await questions.GetQuestionFileAsPostAsync(request.Id); + if (post == null) + throw HttpError.NotFound("Post not found"); + + var refId = $"{request.Id}"; + await Db.SaveAsync(post); + var statTotal = await Db.SingleAsync(Db.From().Where(x => x.Id == refId)); + if (statTotal != null) + { + await Db.InsertAsync(new StatTotals + { + Id = refId, + PostId = post.Id, + ViewCount = 0, + FavoriteCount = 0, + UpVotes = 0, + DownVotes = 0, + StartingUpVotes = 0, + CreatedBy = post.CreatedBy, + }); + } + return post; + } +} diff --git a/MyApp.ServiceModel/Moderation.cs b/MyApp.ServiceModel/Moderation.cs index b72418a..56910b0 100644 --- a/MyApp.ServiceModel/Moderation.cs +++ b/MyApp.ServiceModel/Moderation.cs @@ -14,3 +14,10 @@ public class GenerateMeta : IGet, IReturn [ValidateGreaterThan(0)] public int Id { get; set; } } + +[ValidateHasRole(Roles.Moderator)] +public class ResaveQuestionFromFile : IPost, IReturn +{ + [ValidateGreaterThan(0)] + public int Id { get; set; } +} From 2fb30e8c680e3a143f403d2376b790f915bee15e Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 00:02:08 +0800 Subject: [PATCH 15/36] Update AdminServices.cs --- MyApp.ServiceInterface/AdminServices.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MyApp.ServiceInterface/AdminServices.cs b/MyApp.ServiceInterface/AdminServices.cs index 3190327..cd64fff 100644 --- a/MyApp.ServiceInterface/AdminServices.cs +++ b/MyApp.ServiceInterface/AdminServices.cs @@ -106,6 +106,7 @@ await Db.InsertAsync(new StatTotals CreatedBy = post.CreatedBy, }); } + appConfig.ResetInitialPostId(Db); return post; } } From cfafd1c38bfbb1a9c83915377c30ce654da21934 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 01:13:40 +0800 Subject: [PATCH 16/36] Add same behavior to human answers vs llm answers --- MyApp.ServiceInterface/AiServerServices.cs | 21 +---------- MyApp.ServiceInterface/Data/DbExtensions.cs | 26 ++++++++++++++ MyApp.ServiceInterface/QuestionServices.cs | 40 +++++++++++++++++---- MyApp.ServiceModel/Posts.cs | 3 ++ 4 files changed, 63 insertions(+), 27 deletions(-) diff --git a/MyApp.ServiceInterface/AiServerServices.cs b/MyApp.ServiceInterface/AiServerServices.cs index 3bf887e..8975fa1 100644 --- a/MyApp.ServiceInterface/AiServerServices.cs +++ b/MyApp.ServiceInterface/AiServerServices.cs @@ -45,26 +45,7 @@ public async Task Any(CreateAnswerCallback request) } }); - // Only add notifications for answers older than 1hr - var post = await Db.SingleByIdAsync(request.PostId); - if (post?.CreatedBy != null && DateTime.UtcNow - post.CreationDate > TimeSpan.FromHours(1)) - { - if (!string.IsNullOrEmpty(answer.Summary)) - { - MessageProducer.Publish(new DbWrites { - CreateNotification = new() - { - UserName = post.CreatedBy, - PostId = post.Id, - Type = NotificationType.NewAnswer, - CreatedDate = DateTime.UtcNow, - RefId = answer.RefId!, - Summary = answer.Summary, - RefUserName = answer.CreatedBy, - }, - }); - } - } + await Db.NotifyQuestionAuthorIfRequiredAsync(MessageProducer, answer); MessageProducer.Publish(new AiServerTasks { diff --git a/MyApp.ServiceInterface/Data/DbExtensions.cs b/MyApp.ServiceInterface/Data/DbExtensions.cs index 3693cc9..a32f37a 100644 --- a/MyApp.ServiceInterface/Data/DbExtensions.cs +++ b/MyApp.ServiceInterface/Data/DbExtensions.cs @@ -1,6 +1,7 @@ using System.Data; using MyApp.ServiceModel; using ServiceStack; +using ServiceStack.Messaging; using ServiceStack.OrmLite; namespace MyApp.Data; @@ -101,4 +102,29 @@ public static async Task IsWatchingPostAsync(this IDbConnection db, string public static async Task IsWatchingTagAsync(this IDbConnection db, string userName, string tag) => await db.ExistsAsync(db.From().Where(x => x.UserName == userName && x.Tag == tag)); + + public static async Task NotifyQuestionAuthorIfRequiredAsync(this IDbConnection db, IMessageProducer mq, Post answer) + { + // Only add notifications for answers older than 1hr + var post = await db.SingleByIdAsync(answer.ParentId); + if (post?.CreatedBy != null && DateTime.UtcNow - post.CreationDate > TimeSpan.FromHours(1)) + { + if (!string.IsNullOrEmpty(answer.Summary)) + { + mq.Publish(new DbWrites { + CreateNotification = new() + { + UserName = post.CreatedBy, + PostId = post.Id, + Type = NotificationType.NewAnswer, + CreatedDate = DateTime.UtcNow, + RefId = answer.RefId!, + Summary = answer.Summary, + RefUserName = answer.CreatedBy, + }, + }); + } + } + } + } diff --git a/MyApp.ServiceInterface/QuestionServices.cs b/MyApp.ServiceInterface/QuestionServices.cs index 7b7b13a..97bedf5 100644 --- a/MyApp.ServiceInterface/QuestionServices.cs +++ b/MyApp.ServiceInterface/QuestionServices.cs @@ -155,26 +155,52 @@ public async Task Any(AnswerQuestion request) { var userName = GetUserName(); var now = DateTime.UtcNow; - var post = new Post + var answer = new Post { ParentId = request.PostId, - Summary = request.Body.StripHtml().SubstringWithEllipsis(0,200), + Summary = request.Body.GenerateSummary(), CreationDate = now, CreatedBy = userName, LastActivityDate = now, Body = request.Body, - RefId = request.RefId, // Optional External Ref Id, not '{PostId}-{UserName}' + RefUrn = request.RefUrn, + RefId = $"{request.PostId}-{userName}" }; MessageProducer.Publish(new DbWrites { - CreateAnswer = post, + CreateAnswer = answer, AnswerAddedToPost = new() { Id = request.PostId}, }); - await questions.SaveHumanAnswerAsync(post); - rendererCache.DeleteCachedQuestionPostHtml(post.Id); + rendererCache.DeleteCachedQuestionPostHtml(answer.Id); + + await questions.SaveHumanAnswerAsync(answer); + + MessageProducer.Publish(new DbWrites + { + SaveStartingUpVotes = new() + { + Id = answer.RefId!, + PostId = request.PostId, + StartingUpVotes = 0, + CreatedBy = userName, + } + }); - answerNotifier.NotifyNewAnswer(request.PostId, post.CreatedBy); + answerNotifier.NotifyNewAnswer(request.PostId, answer.CreatedBy); + + var userId = Request.GetClaimsPrincipal().GetUserId(); + MessageProducer.Publish(new AiServerTasks + { + CreateRankAnswerTask = new CreateRankAnswerTask { + AnswerId = answer.RefId!, + UserId = userId!, + } + }); + + MessageProducer.Publish(new SearchTasks { + AddAnswerToIndex = answer.RefId + }); return new AnswerQuestionResponse(); } diff --git a/MyApp.ServiceModel/Posts.cs b/MyApp.ServiceModel/Posts.cs index 48e456d..bfd9201 100644 --- a/MyApp.ServiceModel/Posts.cs +++ b/MyApp.ServiceModel/Posts.cs @@ -373,6 +373,9 @@ public class AnswerQuestion : IPost, IReturn [Input(Type="hidden")] public string? RefId { get; set; } + + [Input(Type="hidden")] + public string? RefUrn { get; set; } } public class AnswerQuestionResponse { From cdae7a5691cdb7c74cbc80f5bee72efdd434b761 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 02:01:38 +0800 Subject: [PATCH 17/36] Add API to trigger answer task --- MyApp.ServiceInterface/AdminServices.cs | 22 ++++++++++++++++++++++ MyApp.ServiceInterface/AiServerServices.cs | 19 ++++++++++--------- MyApp.ServiceModel/Moderation.cs | 7 +++++++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/MyApp.ServiceInterface/AdminServices.cs b/MyApp.ServiceInterface/AdminServices.cs index cd64fff..ac8424e 100644 --- a/MyApp.ServiceInterface/AdminServices.cs +++ b/MyApp.ServiceInterface/AdminServices.cs @@ -109,4 +109,26 @@ await Db.InsertAsync(new StatTotals appConfig.ResetInitialPostId(Db); return post; } + + public async Task Any(RankAnswer request) + { + var answer = await questions.GetAnswerAsPostAsync(request.Id); + if (answer == null) + throw HttpError.NotFound("Answer not found"); + + var answerCreator = !string.IsNullOrEmpty(answer.CreatedBy) + ? await Db.ScalarAsync(Db.From().Where(x => x.UserName == answer.CreatedBy).Select(x => x.Id)) + : null; + + if (answerCreator == null) + throw HttpError.NotFound($"Answer Creator '{answer.CreatedBy}' not found"); + + MessageProducer.Publish(new AiServerTasks + { + CreateRankAnswerTask = new CreateRankAnswerTask { + AnswerId = answer.RefId!, + UserId = answerCreator, + } + }); + } } diff --git a/MyApp.ServiceInterface/AiServerServices.cs b/MyApp.ServiceInterface/AiServerServices.cs index 8975fa1..2268af7 100644 --- a/MyApp.ServiceInterface/AiServerServices.cs +++ b/MyApp.ServiceInterface/AiServerServices.cs @@ -72,13 +72,14 @@ public async Task Any(RankAnswerCallback request) if (string.IsNullOrEmpty(request.Grader)) request.Grader = Request!.QueryString[nameof(request.Grader)] ?? throw new ArgumentNullException(nameof(request.Grader)); - var modelUser = appConfig.GetModelUserById(request.UserId); - if (modelUser?.UserName == null) - throw HttpError.Forbidden("Invalid Model User Id"); + var answerCreator = appConfig.GetModelUserById(request.UserId)?.UserName + ?? await Db.ScalarAsync(Db.From().Where(x => x.Id == request.UserId).Select(x => x.UserName)); + if (answerCreator == null) + throw HttpError.Forbidden("Invalid User Id: " + request.UserId); var graderUser = appConfig.GetModelUser(request.Grader); if (graderUser?.UserName == null) - throw HttpError.Forbidden("Invalid Model Grader " + request.Model); + throw HttpError.Forbidden("Invalid Model Grader: " + request.Model); var body = request.GetBody()?.Trim(); if (string.IsNullOrEmpty(body)) @@ -102,20 +103,20 @@ public async Task Any(RankAnswerCallback request) var meta = await questions.GetMetaAsync(request.PostId); meta.GradedBy ??= new(); - meta.GradedBy[modelUser.UserName] = graderUser.UserName; + meta.GradedBy[answerCreator] = graderUser.UserName; meta.ModelReasons ??= new(); - meta.ModelReasons[modelUser.UserName] = reason ?? ""; + meta.ModelReasons[answerCreator] = reason ?? ""; meta.ModelVotes ??= new(); - meta.ModelVotes[modelUser.UserName] = score; + meta.ModelVotes[answerCreator] = score; var statTotals = new StatTotals { - Id = $"{request.PostId}-{modelUser.UserName}", + Id = $"{request.PostId}-{answerCreator}", PostId = request.PostId, StartingUpVotes = score, - CreatedBy = modelUser.UserName, + CreatedBy = answerCreator, LastUpdated = DateTime.UtcNow, }; diff --git a/MyApp.ServiceModel/Moderation.cs b/MyApp.ServiceModel/Moderation.cs index 56910b0..53b4fe9 100644 --- a/MyApp.ServiceModel/Moderation.cs +++ b/MyApp.ServiceModel/Moderation.cs @@ -21,3 +21,10 @@ public class ResaveQuestionFromFile : IPost, IReturn [ValidateGreaterThan(0)] public int Id { get; set; } } + +[ValidateHasRole(Roles.Moderator)] +public class RankAnswer : IPost, IReturn +{ + [ValidateNotEmpty] + public string Id { get; set; } +} From fcdd46c322927dc5f54b1ba0dce3f0bdfbb3d1eb Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 02:28:46 +0800 Subject: [PATCH 18/36] Update AdminServices.cs --- MyApp.ServiceInterface/AdminServices.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MyApp.ServiceInterface/AdminServices.cs b/MyApp.ServiceInterface/AdminServices.cs index ac8424e..d69bfda 100644 --- a/MyApp.ServiceInterface/AdminServices.cs +++ b/MyApp.ServiceInterface/AdminServices.cs @@ -130,5 +130,7 @@ public async Task Any(RankAnswer request) UserId = answerCreator, } }); + + return answer; } } From 08464c29c0bccd07d964f0fc712f7378bda1d72e Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 10:07:13 +0800 Subject: [PATCH 19/36] Add GetProfileImage API --- MyApp.ServiceInterface/UserServices.cs | 38 +++++++++++++++++--------- MyApp.ServiceModel/User.cs | 6 ++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/MyApp.ServiceInterface/UserServices.cs b/MyApp.ServiceInterface/UserServices.cs index c5eb72c..cc40ba1 100644 --- a/MyApp.ServiceInterface/UserServices.cs +++ b/MyApp.ServiceInterface/UserServices.cs @@ -49,6 +49,30 @@ public async Task Any(UpdateUserProfile request) return new UpdateUserProfileResponse(); } + public async Task GetProfileImageResultAsync(string profilePath) + { + var localProfilePath = AppData.CombineWith(profilePath); + var file = VirtualFiles.GetFile(localProfilePath); + if (file != null) + { + return new HttpResult(file, MimeTypes.GetMimeType(file.Extension)); + } + file = await r2.GetFileAsync(profilePath); + var bytes = file != null ? await file.ReadAllBytesAsync() : null; + if (bytes is { Length: > 0 }) + { + await VirtualFiles.WriteFileAsync(localProfilePath, bytes); + return new HttpResult(bytes, MimeTypes.GetMimeType(file!.Extension)); + } + return new HttpResult(Svg.GetImage(Svg.Icons.Users), MimeTypes.ImageSvg); + } + + public async Task Any(GetProfileImage request) + { + var profilePath = "profiles".CombineWith(request.Path); + return await GetProfileImageResultAsync(profilePath); + } + public async Task Any(GetUserAvatar request) { if (!string.IsNullOrEmpty(request.UserName)) @@ -65,19 +89,7 @@ public async Task Any(GetUserAvatar request) } if (profilePath.StartsWith('/')) { - var localProfilePath = AppData.CombineWith(profilePath); - var file = VirtualFiles.GetFile(localProfilePath); - if (file != null) - { - return new HttpResult(file, MimeTypes.GetMimeType(file.Extension)); - } - file = r2.GetFile(profilePath); - var bytes = file != null ? await file.ReadAllBytesAsync() : null; - if (bytes is { Length: > 0 }) - { - await VirtualFiles.WriteFileAsync(localProfilePath, bytes); - return new HttpResult(bytes, MimeTypes.GetMimeType(file!.Extension)); - } + return await GetProfileImageResultAsync(profilePath); } } } diff --git a/MyApp.ServiceModel/User.cs b/MyApp.ServiceModel/User.cs index fb78d5a..0ae732c 100644 --- a/MyApp.ServiceModel/User.cs +++ b/MyApp.ServiceModel/User.cs @@ -19,6 +19,12 @@ public class GetUserAvatar : IGet, IReturn public string UserName { get; set; } } +[Route("/profiles/{*Path}", "GET")] +public class GetProfileImage : IGet, IReturn +{ + public string Path { get; set; } +} + public class UserInfo { [PrimaryKey] From 383d95edd3bc1c3036c184274be4e1ce01a198e8 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 11:25:08 +0800 Subject: [PATCH 20/36] Use the same ext method to generate summaries --- MyApp.ServiceInterface/AiServerServices.cs | 5 +++++ MyApp.ServiceInterface/App/CreateAnswerCommand.cs | 4 ++-- MyApp.ServiceInterface/App/CreatePostCommand.cs | 2 +- MyApp.ServiceInterface/App/NewCommentCommand.cs | 4 ++-- MyApp.ServiceInterface/Data/DbExtensions.cs | 3 ++- MyApp.ServiceInterface/QuestionServices.cs | 6 +++--- MyApp.ServiceInterface/UserServices.cs | 4 ++-- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/MyApp.ServiceInterface/AiServerServices.cs b/MyApp.ServiceInterface/AiServerServices.cs index 2268af7..425c7e1 100644 --- a/MyApp.ServiceInterface/AiServerServices.cs +++ b/MyApp.ServiceInterface/AiServerServices.cs @@ -146,6 +146,11 @@ public static class AiServerExtensions static readonly Regex CollapseNewLines = new(@"[\r\n]+", RegexOptions.Compiled | RegexOptions.Multiline); static readonly Regex CollapseSpaces = new(@"\s+", RegexOptions.Compiled | RegexOptions.Multiline); + public static string GenerateNotificationTitle(this string title) => title.SubstringWithEllipsis(0, 100); + + public static string GenerateNotificationSummary(this string summary, int startPos=0) => + summary.SubstringWithEllipsis(startPos, 100); + public static string GenerateSummary(this string body) { string withoutHtml = StripHtmlRegEx.Replace(body, string.Empty); // naive html stripping diff --git a/MyApp.ServiceInterface/App/CreateAnswerCommand.cs b/MyApp.ServiceInterface/App/CreateAnswerCommand.cs index ccf2c4b..7dcf17c 100644 --- a/MyApp.ServiceInterface/App/CreateAnswerCommand.cs +++ b/MyApp.ServiceInterface/App/CreateAnswerCommand.cs @@ -45,7 +45,7 @@ await db.InsertAsync(new Notification RefId = refId, PostId = postId, CreatedDate = answer.CreationDate, - Summary = answer.Summary.SubstringWithEllipsis(0, 100), + Summary = answer.Summary, RefUserName = answer.CreatedBy, }); appConfig.IncrUnreadNotificationsFor(post.CreatedBy); @@ -77,7 +77,7 @@ await db.InsertAsync(new Notification RefId = $"{postId}", PostId = postId, CreatedDate = answer.CreationDate, - Summary = cleanBody.SubstringWithEllipsis(startPos, 100), + Summary = cleanBody.GenerateNotificationSummary(startPos), RefUserName = answer.CreatedBy, }); appConfig.IncrUnreadNotificationsFor(existingUser.UserName!); diff --git a/MyApp.ServiceInterface/App/CreatePostCommand.cs b/MyApp.ServiceInterface/App/CreatePostCommand.cs index b165c5d..32e5337 100644 --- a/MyApp.ServiceInterface/App/CreatePostCommand.cs +++ b/MyApp.ServiceInterface/App/CreatePostCommand.cs @@ -77,7 +77,7 @@ await db.InsertAsync(new Notification RefId = $"{post.Id}", PostId = post.Id, CreatedDate = post.CreationDate, - Summary = cleanBody.SubstringWithEllipsis(startPos, 100), + Summary = cleanBody.GenerateNotificationSummary(startPos), RefUserName = createdBy, }); appConfig.IncrUnreadNotificationsFor(existingUser.UserName!); diff --git a/MyApp.ServiceInterface/App/NewCommentCommand.cs b/MyApp.ServiceInterface/App/NewCommentCommand.cs index e5c8f6d..d81698c 100644 --- a/MyApp.ServiceInterface/App/NewCommentCommand.cs +++ b/MyApp.ServiceInterface/App/NewCommentCommand.cs @@ -34,7 +34,7 @@ await db.InsertAsync(new Notification RefId = commentRefId, PostId = postId, CreatedDate = createdDate, - Summary = cleanBody.SubstringWithEllipsis(0, 100), + Summary = cleanBody.GenerateNotificationSummary(), RefUserName = comment.CreatedBy, }); appConfig.IncrUnreadNotificationsFor(createdBy); @@ -63,7 +63,7 @@ await db.InsertAsync(new Notification RefId = commentRefId, PostId = postId, CreatedDate = createdDate, - Summary = cleanBody.SubstringWithEllipsis(startPos, 100), + Summary = cleanBody.GenerateNotificationSummary(startPos), RefUserName = comment.CreatedBy, }); appConfig.IncrUnreadNotificationsFor(existingUser.UserName!); diff --git a/MyApp.ServiceInterface/Data/DbExtensions.cs b/MyApp.ServiceInterface/Data/DbExtensions.cs index a32f37a..ff6ab52 100644 --- a/MyApp.ServiceInterface/Data/DbExtensions.cs +++ b/MyApp.ServiceInterface/Data/DbExtensions.cs @@ -1,4 +1,5 @@ using System.Data; +using MyApp.ServiceInterface; using MyApp.ServiceModel; using ServiceStack; using ServiceStack.Messaging; @@ -64,7 +65,7 @@ public static SqlExpression OrderByView(this SqlExpression q, { Id = x.RefId.LeftPart('-').ToInt(), PostTypeId = x.RefId.Contains('-') ? 2 : 1, - Summary = x.Body.StripHtml().SubstringWithEllipsis(0, 200), + Summary = x.Body.GenerateSummary(), CreationDate = x.ModifiedDate, LastEditDate = x.ModifiedDate, }; diff --git a/MyApp.ServiceInterface/QuestionServices.cs b/MyApp.ServiceInterface/QuestionServices.cs index 97bedf5..257a7a8 100644 --- a/MyApp.ServiceInterface/QuestionServices.cs +++ b/MyApp.ServiceInterface/QuestionServices.cs @@ -75,7 +75,7 @@ public async Task Any(AskQuestion request) var title = request.Title.Trim(); var body = request.Body.Trim(); var slug = request.Title.GenerateSlug(200); - var summary = request.Body.StripHtml().SubstringWithEllipsis(0, 200); + var summary = request.Body.GenerateSummary(); var existingPost = await Db.SingleAsync(Db.From().Where(x => x.Title == title)); if (existingPost != null) @@ -229,7 +229,7 @@ public async Task Any(UpdateQuestion request) question.Title = request.Title; question.Tags = ValidateQuestionTags(request.Tags); question.Slug = request.Title.GenerateSlug(200); - question.Summary = request.Body.StripHtml().SubstringWithEllipsis(0, 200); + question.Summary = request.Body.GenerateSummary(); question.Body = request.Body; question.ModifiedBy = userName; question.LastActivityDate = DateTime.UtcNow; @@ -416,7 +416,7 @@ public async Task Any(CreateWorkerAnswer request) Type = NotificationType.NewAnswer, CreatedDate = DateTime.UtcNow, RefId = $"{post.Id}-{userName}", - Summary = cleanBody.SubstringWithEllipsis(0,100), + Summary = cleanBody.GenerateNotificationSummary(), RefUserName = userName, }, }); diff --git a/MyApp.ServiceInterface/UserServices.cs b/MyApp.ServiceInterface/UserServices.cs index cc40ba1..6cba7c7 100644 --- a/MyApp.ServiceInterface/UserServices.cs +++ b/MyApp.ServiceInterface/UserServices.cs @@ -186,7 +186,7 @@ public async Task Any(GetLatestNotifications request) Notification Merge(Notification notification, Post post) { - notification.Title ??= post.Title.SubstringWithEllipsis(0,100); + notification.Title ??= post.Title.GenerateNotificationTitle(); notification.Href ??= $"/questions/{notification.PostId}/{post.Slug}#{notification.RefId}"; return notification; } @@ -227,7 +227,7 @@ FROM Achievement A LEFT JOIN Post P on (A.PostId = P.Id) Id = ++i, PostId = x.PostId, RefId = x.RefId, - Title = x.Title.SubstringWithEllipsis(0,100), + Title = x.Title.GenerateNotificationTitle(), Score = x.Score, CreatedDate = x.CreatedDate, Href = $"/questions/{x.PostId}/{x.Slug}", From aac90cc9ec810fd5af352957fbd127b4c9d283b8 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 11:26:32 +0800 Subject: [PATCH 21/36] switch to declarative validation now that v8.2.3 populates empty Request DTO props from querystring --- MyApp.ServiceInterface/AiServerServices.cs | 17 ----------------- MyApp.ServiceInterface/QuestionServices.cs | 20 +++++++++++--------- MyApp.ServiceModel/OpenAi.cs | 7 ++++++- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/MyApp.ServiceInterface/AiServerServices.cs b/MyApp.ServiceInterface/AiServerServices.cs index 425c7e1..47cf338 100644 --- a/MyApp.ServiceInterface/AiServerServices.cs +++ b/MyApp.ServiceInterface/AiServerServices.cs @@ -17,13 +17,6 @@ public class AiServerServices(ILogger log, { public async Task Any(CreateAnswerCallback request) { - if (request.PostId == 0) - request.PostId = int.TryParse(Request!.QueryString[nameof(request.PostId)], out var postId) - ? postId - : throw new ArgumentNullException(nameof(request.PostId)); - if (string.IsNullOrEmpty(request.UserId)) - request.UserId = Request!.QueryString[nameof(request.UserId)] ?? throw new ArgumentNullException(nameof(request.UserId)); - var modelUser = appConfig.GetModelUserById(request.UserId); if (modelUser?.UserName == null) throw HttpError.Forbidden("Invalid Model User Id"); @@ -62,16 +55,6 @@ public async Task Any(CreateAnswerCallback request) public async Task Any(RankAnswerCallback request) { - if (request.PostId == 0) - request.PostId = int.TryParse(Request!.QueryString[nameof(request.PostId)], out var postId) - ? postId - : throw new ArgumentNullException(nameof(request.PostId)); - if (string.IsNullOrEmpty(request.UserId)) - request.UserId = Request!.QueryString[nameof(request.UserId)] ?? throw new ArgumentNullException(nameof(request.UserId)); - - if (string.IsNullOrEmpty(request.Grader)) - request.Grader = Request!.QueryString[nameof(request.Grader)] ?? throw new ArgumentNullException(nameof(request.Grader)); - var answerCreator = appConfig.GetModelUserById(request.UserId)?.UserName ?? await Db.ScalarAsync(Db.From().Where(x => x.Id == request.UserId).Select(x => x.UserName)); if (answerCreator == null) diff --git a/MyApp.ServiceInterface/QuestionServices.cs b/MyApp.ServiceInterface/QuestionServices.cs index 257a7a8..056f459 100644 --- a/MyApp.ServiceInterface/QuestionServices.cs +++ b/MyApp.ServiceInterface/QuestionServices.cs @@ -155,24 +155,26 @@ public async Task Any(AnswerQuestion request) { var userName = GetUserName(); var now = DateTime.UtcNow; + var postId = request.PostId; + var answerId = $"{postId}-{userName}"; var answer = new Post { - ParentId = request.PostId, + ParentId = postId, Summary = request.Body.GenerateSummary(), CreationDate = now, CreatedBy = userName, LastActivityDate = now, Body = request.Body, RefUrn = request.RefUrn, - RefId = $"{request.PostId}-{userName}" + RefId = answerId }; MessageProducer.Publish(new DbWrites { CreateAnswer = answer, - AnswerAddedToPost = new() { Id = request.PostId}, + AnswerAddedToPost = new() { Id = postId }, }); - rendererCache.DeleteCachedQuestionPostHtml(answer.Id); + rendererCache.DeleteCachedQuestionPostHtml(postId); await questions.SaveHumanAnswerAsync(answer); @@ -180,26 +182,26 @@ public async Task Any(AnswerQuestion request) { SaveStartingUpVotes = new() { - Id = answer.RefId!, - PostId = request.PostId, + Id = answerId, + PostId = postId, StartingUpVotes = 0, CreatedBy = userName, } }); - answerNotifier.NotifyNewAnswer(request.PostId, answer.CreatedBy); + answerNotifier.NotifyNewAnswer(postId, answer.CreatedBy); var userId = Request.GetClaimsPrincipal().GetUserId(); MessageProducer.Publish(new AiServerTasks { CreateRankAnswerTask = new CreateRankAnswerTask { - AnswerId = answer.RefId!, + AnswerId = answerId, UserId = userId!, } }); MessageProducer.Publish(new SearchTasks { - AddAnswerToIndex = answer.RefId + AddAnswerToIndex = answerId }); return new AnswerQuestionResponse(); diff --git a/MyApp.ServiceModel/OpenAi.cs b/MyApp.ServiceModel/OpenAi.cs index d079002..574668c 100644 --- a/MyApp.ServiceModel/OpenAi.cs +++ b/MyApp.ServiceModel/OpenAi.cs @@ -6,18 +6,23 @@ namespace MyApp.ServiceModel; [SystemJson(UseSystemJson.Never)] public class CreateAnswerCallback : OpenAiChatResponse, IPost, IReturnVoid { + [ValidateGreaterThan(9)] public int PostId { get; set; } - + + [ValidateNotEmpty] public string UserId { get; set; } } [SystemJson(UseSystemJson.Never)] public class RankAnswerCallback : OpenAiChatResponse, IPost, IReturnVoid { + [ValidateGreaterThan(9)] public int PostId { get; set; } + [ValidateNotEmpty] public string UserId { get; set; } // Use User GUID to prevent tampering + [ValidateNotEmpty] public string Grader { get; set; } } From c215e004c06fcd94498678cb8777adcb4238fdc7 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 13:30:29 +0800 Subject: [PATCH 22/36] Add support for auto responding to comments to model answers --- .../CreateAnswerCommentTaskCommand.cs | 76 ++++++++++++++++++ .../AiServer/CreateAnswerTasksCommand.cs | 52 ++++++++++--- .../AiServer/CreateRankAnswerTaskCommand.cs | 10 ++- MyApp.ServiceInterface/AiServerServices.cs | 78 +++++++++++++++++-- MyApp.ServiceInterface/Data/Tasks.cs | 5 +- MyApp.ServiceInterface/QuestionServices.cs | 60 ++++++++++++-- MyApp.ServiceModel/OpenAi.cs | 20 +++++ MyApp.ServiceModel/Posts.cs | 2 +- 8 files changed, 278 insertions(+), 25 deletions(-) create mode 100644 MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs diff --git a/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs b/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs new file mode 100644 index 0000000..a0347ea --- /dev/null +++ b/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs @@ -0,0 +1,76 @@ +using AiServer.ServiceModel; +using MyApp.Data; +using MyApp.ServiceModel; +using ServiceStack; + +namespace MyApp.ServiceInterface.AiServer; + +public class CreateAnswerCommentTaskCommand(AppConfig appConfig) : IAsyncCommand +{ + public const string SystemPrompt = + """ + You are an IT expert helping a user with a technical issue using your computer science, network infrastructure, + and IT security knowledge to solve my problem using data from StackOverflow, Hacker News, and GitHub of content + like issues submitted, closed issues, number of stars on a repository, and overall StackOverflow activity. + I will provide you with my original question and your initial answer attempt to solve my problem and + my follow up questions asking for further explanation and clarification of your answer. + You should use your expertise to provide specific, concise answers to my follow up questions. + """; + + public async Task ExecuteAsync(CreateAnswerCommentTask request) + { + var question = request.Question; + + var answerPrompt = + $$""" + ## Original Answer Attempt + + {{request.Answer.Body}} + --- + """; + + var questionPrompt = CreateAnswerTasksCommand.CreateQuestionPrompt(question); + var openAiChat = new OpenAiChat + { + Model = request.Model, + Messages = [ + new() { Role = "system", Content = SystemPrompt }, + new() { Role = "user", Content = questionPrompt }, + new() { Role = "assistant", Content = answerPrompt }, + ], + Temperature = 0.2, + MaxTokens = 100, + }; + + var modelUser = appConfig.GetModelUser(request.Model); + if (modelUser == null) + throw new ArgumentException("Model User not found: " + request.Model); + + foreach (var comment in request.Comments) + { + if (comment.CreatedBy == request.UserName) + { + openAiChat.Messages.Add(new() { Role = "user", Content = comment.Body }); + } + else if (comment.CreatedBy == modelUser.UserName) + { + openAiChat.Messages.Add(new() { Role = "assistant", Content = comment.Body }); + } + } + + var client = appConfig.CreateAiServerClient(); + + var api = await client.ApiAsync(new CreateOpenAiChat { + RefId = Guid.NewGuid().ToString("N"), + Tag = "pvq", + Provider = null, + ReplyTo = appConfig.BaseUrl.CombineWith("api", nameof(AnswerCommentCallback).AddQueryParams(new() { + [nameof(AnswerCommentCallback.AnswerId)] = request.Answer.RefId, + [nameof(AnswerCommentCallback.UserId)] = request.UserId, + })), + Request = openAiChat + }); + + api.ThrowIfError(); + } +} diff --git a/MyApp.ServiceInterface/AiServer/CreateAnswerTasksCommand.cs b/MyApp.ServiceInterface/AiServer/CreateAnswerTasksCommand.cs index a165647..4fc64d4 100644 --- a/MyApp.ServiceInterface/AiServer/CreateAnswerTasksCommand.cs +++ b/MyApp.ServiceInterface/AiServer/CreateAnswerTasksCommand.cs @@ -9,7 +9,35 @@ namespace MyApp.ServiceInterface.AiServer; public class CreateAnswerTasksCommand(ILogger log, AppConfig appConfig, QuestionsProvider questions) : IAsyncCommand { - const string SystemPrompt = "You are a friendly AI Assistant that helps answer developer questions. Think step by step and assist the user with their question, ensuring that your answer is relevant, on topic and provides actionable advice with code examples as appropriate."; + //https://github.com/f/awesome-chatgpt-prompts?tab=readme-ov-file#act-as-an-it-expert + //https://github.com/f/awesome-chatgpt-prompts?tab=readme-ov-file#act-as-a-developer-relations-consultant + public const string SystemPrompt = + """ + You are an IT expert helping a user with a technical issue. + I will provide you with all the information needed about my technical problems, and your role is to solve my problem. + You should use your computer science, network infrastructure, and IT security knowledge to solve my problem + using data from StackOverflow, Hacker News, and GitHub of content like issues submitted, closed issues, + number of stars on a repository, and overall StackOverflow activity. + Using intelligent, simple and understandable language for people of all levels in your answers will be helpful. + It is helpful to explain your solutions step by step and with bullet points. + Try to avoid too many technical details, but use them when necessary. + I want you to reply with the solution, not write any explanations. + """; + + public static string CreateQuestionPrompt(Post question) + { + if (string.IsNullOrEmpty(question.Body)) + throw new ArgumentNullException(nameof(question.Body)); + + var content = $$""" + Title: {{question.Title}} + + Tags: {{string.Join(", ", question.Tags)}} + + {{question.Body}} + """; + return content; + } public async Task ExecuteAsync(CreateAnswerTasks request) { @@ -44,6 +72,17 @@ public async Task ExecuteAsync(CreateAnswerTasks request) } log.LogInformation("Creating Question {Id} OpenAiChat Model for {UserName} to AI Server", question.Id, userName); + var prompt = CreateQuestionPrompt(question); + var openAiChat = new OpenAiChat + { + Model = modelUser.Model!, + Messages = [ + new() { Role = "system", Content = SystemPrompt }, + new() { Role = "user", Content = prompt }, + ], + Temperature = 0.7, + MaxTokens = 2048, + }; var response = await client.PostAsync(new CreateOpenAiChat { Tag = "pvq", @@ -51,16 +90,7 @@ public async Task ExecuteAsync(CreateAnswerTasks request) [nameof(CreateAnswerCallback.PostId)] = question.Id, [nameof(CreateAnswerCallback.UserId)] = modelUser.Id, })), - Request = new OpenAiChat - { - Model = modelUser.Model!, - Messages = [ - new() { Role = "system", Content = SystemPrompt }, - new() { Role = "user", Content = question.Body }, - ], - Temperature = 0.7, - MaxTokens = 2048, - } + Request = openAiChat }); } catch (Exception e) diff --git a/MyApp.ServiceInterface/AiServer/CreateRankAnswerTaskCommand.cs b/MyApp.ServiceInterface/AiServer/CreateRankAnswerTaskCommand.cs index dd96b63..00cedbb 100644 --- a/MyApp.ServiceInterface/AiServer/CreateRankAnswerTaskCommand.cs +++ b/MyApp.ServiceInterface/AiServer/CreateRankAnswerTaskCommand.cs @@ -6,6 +6,14 @@ namespace MyApp.ServiceInterface.AiServer; public class CreateRankAnswerTaskCommand(AppConfig appConfig, QuestionsProvider questions) : IAsyncCommand { + //https://github.com/f/awesome-chatgpt-prompts?tab=readme-ov-file#act-as-a-tech-reviewer + public const string SystemPrompt = + """ + I want you to act as a tech reviewer that votes on the quality and relevance of answers to a given question. + I will give you the user's question and the answer that you should review and respond with a score out of 10. + Before giving a score, give a critique of the answer based on quality and relevance to the user's question. + """; + public async Task ExecuteAsync(CreateRankAnswerTask request) { var postId = request.AnswerId.LeftPart('-').ToInt(); @@ -73,7 +81,7 @@ Concisely articulate what a good answer needs to contain and how the answer prov { Model = "mixtral", Messages = [ - new() { Role = "system", Content = "You are an AI assistant that votes on the quality and relevance of answers to a given question. Before giving votes, give an critique of each answer based on quality and relevance." }, + new() { Role = "system", Content = SystemPrompt }, new() { Role = "user", Content = content }, ], Temperature = 0.1, diff --git a/MyApp.ServiceInterface/AiServerServices.cs b/MyApp.ServiceInterface/AiServerServices.cs index 47cf338..06380c1 100644 --- a/MyApp.ServiceInterface/AiServerServices.cs +++ b/MyApp.ServiceInterface/AiServerServices.cs @@ -19,7 +19,7 @@ public async Task Any(CreateAnswerCallback request) { var modelUser = appConfig.GetModelUserById(request.UserId); if (modelUser?.UserName == null) - throw HttpError.Forbidden("Invalid Model User Id"); + throw HttpError.BadRequest("Invalid Model User Id"); rendererCache.DeleteCachedQuestionPostHtml(request.PostId); @@ -55,14 +55,11 @@ public async Task Any(CreateAnswerCallback request) public async Task Any(RankAnswerCallback request) { - var answerCreator = appConfig.GetModelUserById(request.UserId)?.UserName - ?? await Db.ScalarAsync(Db.From().Where(x => x.Id == request.UserId).Select(x => x.UserName)); - if (answerCreator == null) - throw HttpError.Forbidden("Invalid User Id: " + request.UserId); + var answerCreator = await AssertUserNameById(request.UserId); var graderUser = appConfig.GetModelUser(request.Grader); if (graderUser?.UserName == null) - throw HttpError.Forbidden("Invalid Model Grader: " + request.Model); + throw HttpError.BadRequest("Invalid Model Grader: " + request.Model); var body = request.GetBody()?.Trim(); if (string.IsNullOrEmpty(body)) @@ -120,6 +117,63 @@ public async Task Any(RankAnswerCallback request) request.PostId, request.Model, request.UserId, body); } } + + public async Task Any(AnswerCommentCallback request) + { + var commentCreator = await AssertUserNameById(request.UserId); + var postId = request.AnswerId.LeftPart('-').ToInt(); + var modelUserName = request.AnswerId.RightPart('-'); + + var modelUser = appConfig.GetModelUser(modelUserName); + if (modelUser?.UserName == null) + throw HttpError.BadRequest("Invalid Model: " + modelUserName); + + var metaFile = await questions.GetMetaFileAsync(postId); + if (metaFile == null) + throw HttpError.BadRequest("Invalid Post: " + postId); + + var metaJson = await metaFile.ReadAllTextAsync(); + var meta = metaJson.FromJson(); + + var comments = meta.Comments.GetOrAdd(request.AnswerId, key => new()); + + var body = request.Choices?.FirstOrDefault()?.Message?.Content.GenerateModelComment(); + if (string.IsNullOrEmpty(body)) + { + log.LogError("Invalid AnswerCommentCallback: {AnswerId} for {UserId}: body missing", + request.AnswerId, request.UserId); + return; + } + + var commentBody = $"@{commentCreator} {body}"; + var newComment = new Comment + { + Body = commentBody, + Created = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), + CreatedBy = modelUser.UserName, + }; + comments.Add(newComment); + + MessageProducer.Publish(new DbWrites + { + NewComment = new() + { + RefId = request.Id, + Comment = newComment, + }, + }); + + await questions.SaveMetaAsync(postId, meta); + } + + private async Task AssertUserNameById(string userId) + { + var userName = appConfig.GetModelUserById(userId)?.UserName + ?? await Db.ScalarAsync(Db.From().Where(x => x.Id == userId).Select(x => x.UserName)); + if (userName == null) + throw HttpError.BadRequest("Invalid User Id: " + userId); + return userName; + } } public static class AiServerExtensions @@ -151,6 +205,18 @@ public static string GenerateSummary(this string body) return summary; } + public static string GenerateComment(this string body) + { + body = body.Replace("\r\n", " ").Replace('\n', ' '); + return body; + } + + public static string GenerateModelComment(this string body) + { + body = body.TrimStart('#').Replace("\r\n", " ").Replace('\n', ' '); + return body; + } + public static string? GetBody(this OpenAiChatResponse request) => request.Choices?.FirstOrDefault()?.Message?.Content; public static Post ToAnswer(this OpenAiChatResponse request, int postId, string userName) diff --git a/MyApp.ServiceInterface/Data/Tasks.cs b/MyApp.ServiceInterface/Data/Tasks.cs index cffddfa..fcb6573 100644 --- a/MyApp.ServiceInterface/Data/Tasks.cs +++ b/MyApp.ServiceInterface/Data/Tasks.cs @@ -162,7 +162,10 @@ public class AiServerTasks public CreateAnswerTasks? CreateAnswerTasks { get; set; } [Command] - public CreateRankAnswerTask? CreateRankAnswerTask { get; set; } + public CreateRankAnswerTask? CreateRankAnswerTask { get; set; } + + [Command] + public CreateAnswerCommentTask? CreateAnswerCommentTask { get; set; } } public class RenderHome diff --git a/MyApp.ServiceInterface/QuestionServices.cs b/MyApp.ServiceInterface/QuestionServices.cs index 056f459..b25a5fb 100644 --- a/MyApp.ServiceInterface/QuestionServices.cs +++ b/MyApp.ServiceInterface/QuestionServices.cs @@ -1,5 +1,6 @@ using System.Net; using System.Text.RegularExpressions; +using Microsoft.Extensions.Logging; using MyApp.Data; using MyApp.ServiceInterface.App; using ServiceStack; @@ -9,7 +10,8 @@ namespace MyApp.ServiceInterface; -public class QuestionServices(AppConfig appConfig, +public class QuestionServices(ILogger log, + AppConfig appConfig, QuestionsProvider questions, RendererCache rendererCache, WorkerAnswerNotifier answerNotifier, @@ -444,12 +446,15 @@ public async Task Any(CreateComment request) meta.Comments ??= new(); var comments = meta.Comments.GetOrAdd(request.Id, key => new()); - var body = request.Body.Replace("\r\n", " ").Replace('\n', ' '); + var body = request.Body.GenerateComment(); + + var createdBy = GetUserName(); + var newComment = new Comment { Body = body, Created = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), - CreatedBy = GetUserName(), + CreatedBy = createdBy, }; comments.Add(newComment); @@ -463,6 +468,44 @@ public async Task Any(CreateComment request) }); await questions.SaveMetaAsync(postId, meta); + + // If the comment is for a model answer, have the model respond to the comment + var answerCreator = request.Id.Contains('-') + ? request.Id.RightPart('-') + : null; + var modelCreator = answerCreator != null + ? appConfig.GetModelUser(answerCreator) + : null; + if (modelCreator != null) + { + var answer = await questions.GetAnswerAsPostAsync(request.Id); + if (answer != null) + { + var mention = $"@{createdBy}"; + var userConversation = comments + .Where(x => x.CreatedBy == createdBy || x.Body.Contains(mention)) + .ToList(); + + var createdById = GetUserId(); + var model = modelCreator.Model ?? throw new ArgumentNullException(nameof(modelCreator.Model)); + MessageProducer.Publish(new AiServerTasks + { + CreateAnswerCommentTask = new() + { + Model = model, + Question = question, + Answer = answer, + UserName = newComment.CreatedBy, + UserId = createdById, + Comments = userConversation, + } + }); + } + else + { + log.LogError("Answer {Id} not found", request.Id); + } + } return new CommentsResponse { @@ -475,7 +518,7 @@ private async Task AssertValidQuestion(string refId) var postId = refId.LeftPart('-').ToInt(); var postType = refId.IndexOf('-') >= 0 ? "Answer" : "Question"; - var question = await Db.SingleByIdAsync(postId); + var question = await questions.GetQuestionFileAsPostAsync(postId); if (question == null) throw HttpError.NotFound($"{postType} {postId} not found"); @@ -534,10 +577,17 @@ public object Any(GetUserReputations request) private string GetUserName() { var userName = Request.GetClaimsPrincipal().GetUserName() - ?? throw new ArgumentNullException(nameof(ApplicationUser.UserName)); + ?? throw new ArgumentNullException(nameof(ApplicationUser.UserName)); return userName; } + private string GetUserId() + { + var userId = Request.GetClaimsPrincipal().GetUserId() + ?? throw new ArgumentNullException(nameof(ApplicationUser.Id)); + return userId; + } + public async Task Any(ImportQuestion request) { var command = executor.Command(); diff --git a/MyApp.ServiceModel/OpenAi.cs b/MyApp.ServiceModel/OpenAi.cs index 574668c..306645e 100644 --- a/MyApp.ServiceModel/OpenAi.cs +++ b/MyApp.ServiceModel/OpenAi.cs @@ -37,6 +37,16 @@ public void Deconstruct(out string reason, out int score) } } +[SystemJson(UseSystemJson.Never)] +public class AnswerCommentCallback : OpenAiChatResponse, IPost, IReturnVoid +{ + [ValidateNotEmpty] + public string AnswerId { get; set; } + + [ValidateNotEmpty] + public string UserId { get; set; } // Use User GUID to prevent tampering +} + public class CreateAnswerTasks { public Post Post { get; set; } @@ -49,6 +59,16 @@ public class CreateRankAnswerTask public string UserId { get; set; } } +public class CreateAnswerCommentTask +{ + public string Model { get; set; } + public Post Question { get; set; } + public Post Answer { get; set; } + public string UserId { get; set; } + public string UserName { get; set; } + public List Comments { get; set; } +} + public class CreateOpenAiChat : IReturn { public string? RefId { get; set; } diff --git a/MyApp.ServiceModel/Posts.cs b/MyApp.ServiceModel/Posts.cs index bfd9201..aa03747 100644 --- a/MyApp.ServiceModel/Posts.cs +++ b/MyApp.ServiceModel/Posts.cs @@ -409,7 +409,7 @@ public class CreateComment : IPost, IReturn [ValidateNotEmpty] public required string Id { get; set; } - [ValidateNotEmpty, ValidateMinimumLength(15)] + [ValidateNotEmpty, ValidateMinimumLength(15), ValidateMaximumLength(600)] public required string Body { get; set; } } From 3b714108b52dcee40c0529ae5c5ab4857094eb3c Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 23:02:34 +0800 Subject: [PATCH 23/36] Remove old concept of model answers and older worker answer / PostJob --- MyApp.ServiceInterface/AiServerServices.cs | 2 +- MyApp.ServiceInterface/Data/QuestionFiles.cs | 4 +- .../Data/QuestionsProvider.cs | 121 +++--------------- MyApp.ServiceInterface/Data/Tasks.cs | 4 - MyApp.ServiceInterface/OpenAiExtensions.cs | 15 +++ MyApp.ServiceInterface/QuestionServices.cs | 107 +--------------- MyApp.ServiceModel/Posts.cs | 27 +--- 7 files changed, 37 insertions(+), 243 deletions(-) create mode 100644 MyApp.ServiceInterface/OpenAiExtensions.cs diff --git a/MyApp.ServiceInterface/AiServerServices.cs b/MyApp.ServiceInterface/AiServerServices.cs index 06380c1..e21def1 100644 --- a/MyApp.ServiceInterface/AiServerServices.cs +++ b/MyApp.ServiceInterface/AiServerServices.cs @@ -25,7 +25,7 @@ public async Task Any(CreateAnswerCallback request) var answer = request.ToAnswer(request.PostId, modelUser.UserName); - await questions.SaveHumanAnswerAsync(answer); + await questions.SaveAnswerAsync(answer); MessageProducer.Publish(new DbWrites { diff --git a/MyApp.ServiceInterface/Data/QuestionFiles.cs b/MyApp.ServiceInterface/Data/QuestionFiles.cs index a4a1397..c8db18f 100644 --- a/MyApp.ServiceInterface/Data/QuestionFiles.cs +++ b/MyApp.ServiceInterface/Data/QuestionFiles.cs @@ -50,7 +50,7 @@ public static List WithoutDuplicateAnswers(List file : files; } - public IEnumerable GetAnswerFiles() => Files.Where(x => x.Name.Contains(".a.") || x.Name.Contains(".h.")); + public IEnumerable GetAnswerFiles() => Files.Where(x => x.Name.Contains(".h.")); public int GetAnswerFilesCount() => GetAnswerFiles().Count(); @@ -88,7 +88,7 @@ public async Task LoadContentsAsync() await Task.WhenAll(tasks); } - public string GetAnswerUserName(string answerFileName) => answerFileName[(FileId + ".a.").Length..].LastLeftPart('.'); + public string GetAnswerUserName(string answerFileName) => answerFileName[(FileId + ".h.").Length..].LastLeftPart('.'); public string GetAnswerId(string answerFileName) => Id + "-" + GetAnswerUserName(answerFileName); diff --git a/MyApp.ServiceInterface/Data/QuestionsProvider.cs b/MyApp.ServiceInterface/Data/QuestionsProvider.cs index 5f28255..6c5da9a 100644 --- a/MyApp.ServiceInterface/Data/QuestionsProvider.cs +++ b/MyApp.ServiceInterface/Data/QuestionsProvider.cs @@ -69,14 +69,7 @@ public static string GetQuestionPath(int id) return path; } - public static string GetModelAnswerPath(int id, string model) - { - var (dir1, dir2, fileId) = id.ToFileParts(); - var path = $"{dir1}/{dir2}/{fileId}.a.{model.Replace(':','-')}.json"; - return path; - } - - public static string GetHumanAnswerPath(int id, string userName) + public static string GetAnswerPath(int id, string userName) { var (dir1, dir2, fileId) = id.ToFileParts(); var path = $"{dir1}/{dir2}/{fileId}.h.{userName}.json"; @@ -108,17 +101,6 @@ public async Task WriteMetaAsync(Meta meta) await SaveFileAsync(GetMetaPath(meta.Id), ToJson(meta)); } - public async Task GetQuestionFileAsPostAsync(int id) - { - var file = await GetQuestionFileAsync(id); - if (file == null) - return null; - - var json = await file.ReadAllTextAsync(); - var post = json.FromJson(); - return post; - } - public async Task GetQuestionFilesAsync(int id) { var localFiles = GetLocalQuestionFiles(id); @@ -157,20 +139,11 @@ public async Task GetQuestionAsync(int id) var postId = refId.LeftPart('-').ToInt(); var userName = refId.RightPart('-'); - var answerPath = ModelUserNames.Contains(userName) - ? GetModelAnswerPath(postId, userName) - : GetHumanAnswerPath(postId, userName); + var answerPath = GetAnswerPath(postId, userName); var file = fs.GetFile(answerPath) ?? await r2.GetFileAsync(answerPath); - if (file == null) - { - // After first edit AI Model is converted to h. (Post) answer - var modelAnswerPath = GetHumanAnswerPath(postId, userName); - file = fs.GetFile(modelAnswerPath) - ?? await r2.GetFileAsync(modelAnswerPath); - } return file; } @@ -179,34 +152,19 @@ public async Task SaveQuestionAsync(Post post) await SaveFileAsync(GetQuestionPath(post.Id), ToJson(post)); } - public async Task SaveModelAnswerAsync(int postId, string model, string json) - { - await SaveFileAsync(GetModelAnswerPath(postId, model), json); - } - - public async Task SaveHumanAnswerAsync(Post post) + public async Task SaveAnswerAsync(Post post) { - await SaveFileAsync(GetHumanAnswerPath( + await SaveFileAsync(GetAnswerPath( post.ParentId ?? throw new ArgumentNullException(nameof(Post.ParentId)), post.CreatedBy ?? throw new ArgumentNullException(nameof(Post.CreatedBy))), ToJson(post)); } - public async Task SaveHumanAnswerAsync(int postId, string userName, string json) - { - await SaveFileAsync(GetHumanAnswerPath(postId, userName), json); - } - public async Task SaveLocalFileAsync(string virtualPath, string contents) { await fs.WriteFileAsync(virtualPath, contents); } - public async Task SaveRemoteFileAsync(string virtualPath, string contents) - { - await r2.WriteFileAsync(virtualPath, contents); - } - public async Task GetQuestionFileAsync(int id) { var questionPath = GetQuestionPath(id); @@ -215,12 +173,12 @@ public async Task SaveRemoteFileAsync(string virtualPath, string contents) return file; } - public async Task GetQuestionFilePostAsync(int id) + public async Task GetQuestionFileAsPostAsync(int id) { - var (dir1, dir2, fileId) = id.ToFileParts(); - var questionPath = $"{dir1}/{dir2}/{fileId}.json"; - var file = fs.GetFile(questionPath) - ?? await r2.GetFileAsync(questionPath); + var file = await GetQuestionFileAsync(id); + if (file == null) + return null; + var json = await file.ReadAllTextAsync(); var post = json.FromJson(); return post; @@ -296,21 +254,11 @@ public async Task GetAnswerAsPostAsync(IVirtualFile existingAnswer) var existingAnswerJson = await existingAnswer.ReadAllTextAsync(); var fileName = existingAnswer.VirtualPath.TrimStart('/').Replace("/", ""); var postId = fileName.LeftPart('.').ToInt(); - var newAnswer = new Post - { + var newAnswer = new Post { Id = postId, }; - if (fileName.Contains(".a.")) - { - newAnswer.CreatedBy ??= fileName.RightPart(".a.").LastLeftPart('.'); - var obj = (Dictionary)JSON.parse(existingAnswerJson); - newAnswer.CreationDate = obj.TryGetValue("created", out var oCreated) && oCreated is int created - ? DateTimeOffset.FromUnixTimeSeconds(created).DateTime - : existingAnswer.LastModified; - newAnswer.Body = GetModelAnswerBody(obj); - } - else if (fileName.Contains(".h.")) + if (fileName.Contains(".h.")) { newAnswer = existingAnswerJson.FromJson(); newAnswer.CreatedBy ??= fileName.RightPart(".h.").LastLeftPart('.'); @@ -329,25 +277,11 @@ public async Task SaveAnswerEditAsync(IVirtualFile existingAnswer, string userNa var fileName = existingAnswer.VirtualPath.TrimStart('/').Replace("/", ""); var postId = fileName.LeftPart('.').ToInt(); string existingAnswerBy = ""; - var newAnswer = new Post - { - Id = postId, + var newAnswer = new Post { + Id = postId }; - if (fileName.Contains(".a.")) - { - existingAnswerBy = fileName.RightPart(".a.").LastLeftPart('.'); - var datePart = DateTime.UtcNow.ToString("yyMMdd-HHmmss"); - var editFilePath = existingAnswer.VirtualPath.LastLeftPart('/') + "/edit.a." + postId + "-" + userName + "_" + datePart + ".json"; - tasks.Add(SaveFileAsync(editFilePath, existingAnswerJson)); - tasks.Add(DeleteFileAsync(existingAnswer.VirtualPath)); - - var obj = (Dictionary)JSON.parse(existingAnswerJson); - newAnswer.CreationDate = obj.TryGetValue("created", out var oCreated) && oCreated is int created - ? DateTimeOffset.FromUnixTimeSeconds(created).DateTime - : existingAnswer.LastModified; - } - else if (fileName.Contains(".h.")) + if (fileName.Contains(".h.")) { existingAnswerBy = fileName.RightPart(".h.").LastLeftPart('.'); var datePart = DateTime.UtcNow.ToString("yyMMdd-HHmmss"); @@ -380,7 +314,7 @@ public async Task DeleteQuestionFilesAsync(int id) var localQuestionFiles = GetLocalQuestionFiles(id); fs.DeleteFiles(localQuestionFiles.Files.Select(x => x.VirtualPath)); var remoteQuestionFiles = await GetRemoteQuestionFilesAsync(id); - r2.DeleteFiles(remoteQuestionFiles.Files.Select(x => x.VirtualPath)); + await r2.DeleteFilesAsync(remoteQuestionFiles.Files.Select(x => x.VirtualPath)); } public async Task GetAnswerBodyAsync(string answerId) @@ -390,31 +324,6 @@ public async Task DeleteQuestionFilesAsync(int id) return null; var json = await answerFile.ReadAllTextAsync(); - var body = answerFile.Name.Contains(".a.") - ? GetModelAnswerBody(json) - : GetHumanAnswerBody(json); - return body; - } - - public string? GetModelAnswerBody(string json) - { - var obj = (Dictionary)JSON.parse(json); - return GetModelAnswerBody(obj); - } - - public static string? GetModelAnswerBody(Dictionary obj) - { - if (!obj.TryGetValue("choices", out var oChoices) || oChoices is not List choices) - return null; - if (choices.Count <= 0 || choices[0] is not Dictionary choice) - return null; - if (choice["message"] is Dictionary message) - return message["content"] as string; - return null; - } - - public string? GetHumanAnswerBody(string json) - { var answer = json.FromJson(); return answer.Body; } diff --git a/MyApp.ServiceInterface/Data/Tasks.cs b/MyApp.ServiceInterface/Data/Tasks.cs index fcb6573..8bf85c7 100644 --- a/MyApp.ServiceInterface/Data/Tasks.cs +++ b/MyApp.ServiceInterface/Data/Tasks.cs @@ -103,10 +103,6 @@ public class DbWrites : IGet, IReturn [Command] public DeletePost? DeletePost { get; set; } - [Obsolete("Replaced with AI Server")] - [Command] - public CreatePostJobs? CreatePostJobs { get; set; } - [Command] public StartJob? StartJob { get; set; } diff --git a/MyApp.ServiceInterface/OpenAiExtensions.cs b/MyApp.ServiceInterface/OpenAiExtensions.cs new file mode 100644 index 0000000..e1322f7 --- /dev/null +++ b/MyApp.ServiceInterface/OpenAiExtensions.cs @@ -0,0 +1,15 @@ +namespace MyApp.ServiceInterface; + +public static class OpenAiExtensions +{ + public static string? GetModelAnswerBody(this Dictionary obj) + { + if (!obj.TryGetValue("choices", out var oChoices) || oChoices is not List choices) + return null; + if (choices.Count <= 0 || choices[0] is not Dictionary choice) + return null; + if (choice["message"] is Dictionary message) + return message["content"] as string; + return null; + } +} diff --git a/MyApp.ServiceInterface/QuestionServices.cs b/MyApp.ServiceInterface/QuestionServices.cs index b25a5fb..4a3aa97 100644 --- a/MyApp.ServiceInterface/QuestionServices.cs +++ b/MyApp.ServiceInterface/QuestionServices.cs @@ -178,7 +178,7 @@ public async Task Any(AnswerQuestion request) rendererCache.DeleteCachedQuestionPostHtml(postId); - await questions.SaveHumanAnswerAsync(answer); + await questions.SaveAnswerAsync(answer); MessageProducer.Publish(new DbWrites { @@ -252,10 +252,10 @@ public async Task Any(UpdateQuestion request) } /* /100/000 - * 001.a.model.json + * 001.h.model.json * Edit 1: * 001.h.model.json - * edit.a.100000001-model_20240301-1200.json // original model answer, Modified Date + * edit.h.100000001-model_20240301-1200.json // original model answer, Modified Date */ public async Task Any(UpdateAnswer request) { @@ -344,97 +344,6 @@ public async Task Any(GetAnswerBody request) return new HttpResult(body, MimeTypes.PlainText); } - /// - /// DEBUG - /// - /// - /// - public async Task Any(CreateRankingPostJob request) - { - MessageProducer.Publish(new DbWrites - { - CreatePostJobs = new() - { - PostJobs = [ - new PostJob - { - PostId = request.PostId, - Model = "rank", - Title = $"rank-{request.PostId}", - CreatedDate = DateTime.UtcNow, - CreatedBy = nameof(DbWrites), - } - ] - } - }); - return new EmptyResponse(); - } - - public async Task Any(CreateWorkerAnswer request) - { - var json = request.Json; - if (string.IsNullOrEmpty(json)) - { - var file = base.Request!.Files.FirstOrDefault(); - if (file != null) - { - using var reader = new StreamReader(file.InputStream); - json = await reader.ReadToEndAsync(); - } - } - - json = json.Trim(); - if (string.IsNullOrEmpty(json)) - throw new ArgumentException("Json is required", nameof(request.Json)); - if (!json.StartsWith('{')) - throw new ArgumentException("Invalid Json", nameof(request.Json)); - - rendererCache.DeleteCachedQuestionPostHtml(request.PostId); - - if (request.PostJobId != null) - { - MessageProducer.Publish(new DbWrites { - AnswerAddedToPost = new() { Id = request.PostId }, - CompletePostJobs = new() { Ids = [request.PostJobId.Value] } - }); - } - - await questions.SaveModelAnswerAsync(request.PostId, request.Model, json); - - answerNotifier.NotifyNewAnswer(request.PostId, request.Model); - - // Only add notifications for answers older than 1hr - var post = await Db.SingleByIdAsync(request.PostId); - if (post?.CreatedBy != null && DateTime.UtcNow - post.CreationDate > TimeSpan.FromHours(1)) - { - var userName = appConfig.GetUserName(request.Model); - var body = questions.GetModelAnswerBody(json); - var cleanBody = body.StripHtml()?.Trim(); - if (!string.IsNullOrEmpty(cleanBody)) - { - MessageProducer.Publish(new DbWrites { - CreateNotification = new() - { - UserName = post.CreatedBy, - PostId = post.Id, - Type = NotificationType.NewAnswer, - CreatedDate = DateTime.UtcNow, - RefId = $"{post.Id}-{userName}", - Summary = cleanBody.GenerateNotificationSummary(), - RefUserName = userName, - }, - }); - } - } - - return new IdResponse { Id = $"{request.PostId}" }; - } - - public async Task Any(RankAnswers request) - { - return new IdResponse { Id = $"{request.PostId}" }; - } - public async Task Any(CreateComment request) { var question = await AssertValidQuestion(request.Id); @@ -600,16 +509,6 @@ public async Task Any(ImportQuestion request) } } - -/// -/// DEBUG -/// -[ValidateIsAuthenticated] -public class CreateRankingPostJob : IReturn -{ - public int PostId { get; set; } -} - [ValidateHasRole(Roles.Moderator)] public class GetAnswerFile : IGet, IReturn { diff --git a/MyApp.ServiceModel/Posts.cs b/MyApp.ServiceModel/Posts.cs index aa03747..2d3e14d 100644 --- a/MyApp.ServiceModel/Posts.cs +++ b/MyApp.ServiceModel/Posts.cs @@ -220,6 +220,7 @@ public class UserPostData : IGet, IReturn public class UserPostDataResponse { public bool Watching { get; set; } + public int QuestionsAsked { get; set; } public HashSet UpVoteIds { get; set; } = []; public HashSet DownVoteIds { get; set; } = []; public ResponseStatus? ResponseStatus { get; set; } @@ -241,32 +242,6 @@ public class CommentVote : IReturnVoid public bool? Down { get; set; } } -[ValidateHasRole(Roles.Moderator)] -public class CreateWorkerAnswer : IPost, IReturn -{ - public int PostId { get; set; } - [ValidateNotEmpty] - public string Model { get; set; } - public string Json { get; set; } - public int? PostJobId { get; set; } -} - -[ValidateHasRole(Roles.Moderator)] -public class RankAnswers : IPost, IReturn -{ - [ValidateGreaterThan(0)] - public int PostId { get; set; } - - /// - /// Model used to rank the answers - /// - public string Model { get; set; } - - public Dictionary ModelVotes { get; set; } - - public int? PostJobId { get; set; } -} - [ValidateIsAuthenticated] public class GetQuestion : IGet, IReturn { From 0c2e5e466eb05b9d4ba221e296444ed41138f736 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sat, 4 May 2024 23:03:28 +0800 Subject: [PATCH 24/36] Move Answer to own component --- MyApp/Components/Shared/AnswerPost.razor | 94 ++++++++++++++++++++++ MyApp/Components/Shared/QuestionPost.razor | 85 +------------------ 2 files changed, 95 insertions(+), 84 deletions(-) create mode 100644 MyApp/Components/Shared/AnswerPost.razor diff --git a/MyApp/Components/Shared/AnswerPost.razor b/MyApp/Components/Shared/AnswerPost.razor new file mode 100644 index 0000000..941031c --- /dev/null +++ b/MyApp/Components/Shared/AnswerPost.razor @@ -0,0 +1,94 @@ +@using MyApp.Data +@inject AppConfig AppConfig +@inject MarkdownQuestions Markdown +@inject ServiceInterface.ImageCreator ImageCreator + +
+
+
+
+ + Up Vote + + @Question.GetAnswerScore(Answer.GetRefId()).ToHumanReadable() + + Down Vote + +
+
+ + +
+ + + + @AppConfig.GetReputation(UserName) +
+
+
+
+ @if (Question.Meta?.ModelVotes?.TryGetValue(Answer.CreatedBy!, out var votes) == true && + Question.Meta?.ModelReasons?.TryGetValue(Answer.CreatedBy!, out var reason) == true) + { + var grader = Question.Meta?.GradedBy.TryGetValue(Answer.CreatedBy!, out var model) == true ? model : "mixtral"; + var grade = ImageCreator.GradeLetter(votes); +
+
+ @($"Grade: + + +
+
+ } + +
+ @BlazorHtml.Raw(Markdown.GenerateHtml(Answer.Body)) +
+ + + +
+
+
+ +@code { + [Parameter] public required QuestionAndAnswers Question { get; set; } + [Parameter] public required Post Answer { get; set; } + string UserName => Answer.CreatedBy!; +} \ No newline at end of file diff --git a/MyApp/Components/Shared/QuestionPost.razor b/MyApp/Components/Shared/QuestionPost.razor index e5064e9..7ff5833 100644 --- a/MyApp/Components/Shared/QuestionPost.razor +++ b/MyApp/Components/Shared/QuestionPost.razor @@ -148,90 +148,7 @@
@foreach (var answer in Question.Answers) { - var userName = answer.CreatedBy; - -
-
-
-
- - Up Vote - - @Question.GetAnswerScore(answer.GetRefId()).ToHumanReadable() - - Down Vote - -
-
- - -
- - - - @AppConfig.GetReputation(userName) -
-
-
-
- @if (Question.Meta?.ModelVotes?.TryGetValue(answer.CreatedBy!, out var votes) == true && - Question.Meta?.ModelReasons?.TryGetValue(answer.CreatedBy!, out var reason) == true) - { - var grade = ImageCreator.GradeLetter(votes); -
-
- @($"Grade: - - -
-
- } - -
- @BlazorHtml.Raw(Markdown.GenerateHtml(answer.Body)) -
- - - -
-
-
+ }
From f1c83339352f94d0b23f672f98db582c8a8307a6 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 May 2024 01:43:13 +0800 Subject: [PATCH 25/36] Implement markdown comments + Ask Model --- MyApp.ServiceInterface/Data/AppConfig.cs | 53 +- MyApp.ServiceInterface/QuestionServices.cs | 33 +- MyApp.ServiceInterface/UserServices.cs | 1 + MyApp/Components/App.razor | 3 +- MyApp/Components/Pages/Questions/Ask.razor | 2 +- MyApp/Components/Shared/PostComments.razor | 4 +- MyApp/wwwroot/css/app.css | 18 + MyApp/wwwroot/lib/mjs/markdown.mjs | 104 + MyApp/wwwroot/lib/mjs/marked.min.mjs | 8 + MyApp/wwwroot/lib/mjs/marked.mjs | 2432 ++++++++++++++++++++ MyApp/wwwroot/mjs/app.mjs | 32 + MyApp/wwwroot/mjs/dtos.mjs | 1325 +++++++++-- MyApp/wwwroot/mjs/question.mjs | 119 +- 13 files changed, 3880 insertions(+), 254 deletions(-) create mode 100644 MyApp/wwwroot/lib/mjs/markdown.mjs create mode 100644 MyApp/wwwroot/lib/mjs/marked.min.mjs create mode 100644 MyApp/wwwroot/lib/mjs/marked.mjs diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index 32c1768..344c512 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -38,8 +38,18 @@ public class AppConfig public HashSet AllTags { get; set; } = []; public List ModelUsers { get; set; } = []; + public static string[] DeprecatedModels = ["deepseek-coder","gemma-2b","qwen-4b","deepseek-coder-33b"]; + + public static (string Model, int Questions)[] GetActiveModelsForQuestions(int level) => + ModelsForQuestions.Where(x => x.Questions == level && !DeprecatedModels.Contains(x.Model)).ToArray(); + public static (string Model, int Questions)[] ModelsForQuestions = [ + ("deepseek-coder", 0), + ("gemma-2b", 0), + ("qwen-4b", 0), + ("deepseek-coder-33b", 100), + ("phi", 0), ("codellama", 0), ("mistral", 0), @@ -49,12 +59,13 @@ public static (string Model, int Questions)[] ModelsForQuestions = ("mixtral", 5), ("gpt3.5-turbo", 10), ("claude3-haiku", 25), - ("command-r", 50), - ("wizardlm", 100), - ("claude3-sonnet", 175), - ("command-r-plus", 150), - ("gpt4-turbo", 250), - ("claude3-opus", 400), + ("llama3-70b", 50), + ("command-r", 100), + ("wizardlm", 175), + ("claude3-sonnet", 250), + ("command-r-plus", 350), + ("gpt4-turbo", 450), + ("claude3-opus", 600), ]; public static int[] QuestionLevels = ModelsForQuestions.Select(x => x.Questions).Distinct().OrderBy(x => x).ToArray(); @@ -106,6 +117,26 @@ public int GetReputationValue(string? userName) => ? 1 : reputation; + public bool CanUseModel(string userName, string model) + { + if (Stats.IsAdminOrModerator(userName)) + return true; + var questionsCount = GetQuestionCount(userName); + + var modelLevel = GetModelLevel(model); + return modelLevel != -1 && questionsCount >= modelLevel; + } + + public int GetModelLevel(string model) + { + foreach (var entry in ModelsForQuestions) + { + if (entry.Model == model) + return entry.Questions; + } + return -1; + } + public int GetQuestionCount(string? userName) => userName switch { "stackoverflow" or "reddit" or "discourse" => 5, @@ -207,13 +238,21 @@ public List GetAnswerModelUsersFor(string? userName) { var questionsCount = GetQuestionCount(userName); - var models = ModelsForQuestions.Where(x => x.Questions <= questionsCount) + var models = GetActiveModelsForQuestions(questionsCount) .Select(x => x.Model) .ToList(); + + // Remove lower quality models if (models.Contains("gemma")) models.RemoveAll(x => x == "gemma:2b"); + if (models.Contains("mixtral")) + models.RemoveAll(x => x == "mistral"); if (models.Contains("deepseek-coder:33b")) models.RemoveAll(x => x == "deepseek-coder:6.7b"); + if (models.Contains("gpt-4-turbo")) + models.RemoveAll(x => x == "gpt3.5-turbo"); + if (models.Contains("command-r-plus")) + models.RemoveAll(x => x == "command-r"); if (models.Contains("claude-3-opus")) models.RemoveAll(x => x is "claude-3-haiku" or "claude-3-sonnet"); if (models.Contains("claude-3-sonnet")) diff --git a/MyApp.ServiceInterface/QuestionServices.cs b/MyApp.ServiceInterface/QuestionServices.cs index 4a3aa97..6bc8104 100644 --- a/MyApp.ServiceInterface/QuestionServices.cs +++ b/MyApp.ServiceInterface/QuestionServices.cs @@ -350,6 +350,28 @@ public async Task Any(CreateComment request) if (question.LockedDate != null) throw HttpError.Conflict($"{question.GetPostType()} is locked"); + var createdBy = GetUserName(); + + // If the comment is for a model answer, have the model respond to the comment + var answerCreator = request.Id.Contains('-') + ? request.Id.RightPart('-') + : null; + var modelCreator = answerCreator != null + ? appConfig.GetModelUser(answerCreator) + : null; + + if (modelCreator?.UserName != null) + { + var canUseModel = appConfig.CanUseModel(createdBy, modelCreator.UserName); + if (!canUseModel) + { + var userCount = appConfig.GetQuestionCount(createdBy); + log.LogWarning("User {UserName} ({UserCount}) attempted to use model {ModelUserName} ({ModelCount})", + createdBy, userCount, modelCreator.UserName, appConfig.GetModelLevel(modelCreator.UserName)); + throw HttpError.Forbidden("You have not met the requirements to access this model"); + } + } + var postId = question.Id; var meta = await questions.GetMetaAsync(postId); @@ -357,8 +379,6 @@ public async Task Any(CreateComment request) var comments = meta.Comments.GetOrAdd(request.Id, key => new()); var body = request.Body.GenerateComment(); - var createdBy = GetUserName(); - var newComment = new Comment { Body = body, @@ -378,14 +398,7 @@ public async Task Any(CreateComment request) await questions.SaveMetaAsync(postId, meta); - // If the comment is for a model answer, have the model respond to the comment - var answerCreator = request.Id.Contains('-') - ? request.Id.RightPart('-') - : null; - var modelCreator = answerCreator != null - ? appConfig.GetModelUser(answerCreator) - : null; - if (modelCreator != null) + if (modelCreator?.UserName != null) { var answer = await questions.GetAnswerAsPostAsync(request.Id); if (answer != null) diff --git a/MyApp.ServiceInterface/UserServices.cs b/MyApp.ServiceInterface/UserServices.cs index 6cba7c7..61af0c7 100644 --- a/MyApp.ServiceInterface/UserServices.cs +++ b/MyApp.ServiceInterface/UserServices.cs @@ -106,6 +106,7 @@ public async Task Any(UserPostData request) var to = new UserPostDataResponse { Watching = watchingPost, + QuestionsAsked = appConfig.GetQuestionCount(userName), UpVoteIds = allUserPostVotes.Where(x => x.Score > 0).Select(x => x.RefId).ToSet(), DownVoteIds = allUserPostVotes.Where(x => x.Score < 0).Select(x => x.RefId).ToSet(), }; diff --git a/MyApp/Components/App.razor b/MyApp/Components/App.razor index bfb03ce..27a674d 100644 --- a/MyApp/Components/App.razor +++ b/MyApp/Components/App.razor @@ -18,10 +18,11 @@ ["app.mjs"] = ($"{baseUrl}/mjs/app.mjs", $"{baseUrl}/mjs/app.mjs"), ["dtos.mjs"] = ($"{baseUrl}/mjs/dtos.mjs", $"{baseUrl}/mjs/dtos.mjs"), ["vue"] = ($"{baseUrl}/lib/mjs/vue.mjs", $"{baseUrl}/lib/mjs/vue.min.mjs"), + ["marked"] = ($"{baseUrl}/lib/mjs/marked.mjs", $"{baseUrl}/lib/mjs/marked.min.mjs"), + ["markdown"] = ($"{baseUrl}/lib/mjs/markdown.mjs", $"{baseUrl}/lib/mjs/markdown.mjs"), ["@servicestack/client"] = ($"{baseUrl}/lib/mjs/servicestack-client.mjs", $"{baseUrl}/lib/mjs/servicestack-client.min.mjs"), ["@servicestack/vue"] = ($"{baseUrl}/lib/mjs/servicestack-vue.mjs", $"{baseUrl}/lib/mjs/servicestack-vue.min.mjs"), }) - diff --git a/MyApp/Components/Pages/Questions/Ask.razor b/MyApp/Components/Pages/Questions/Ask.razor index 4ddbf0f..dc9f1f1 100644 --- a/MyApp/Components/Pages/Questions/Ask.razor +++ b/MyApp/Components/Pages/Questions/Ask.razor @@ -71,7 +71,7 @@ }
    - @foreach (var model in AppConfig.ModelsForQuestions.Where(x => x.Questions == questionLevel)) + @foreach (var model in AppConfig.GetActiveModelsForQuestions(questionLevel)) { var assistant = AppConfig.GetModelUser(model.Model)!;
  • diff --git a/MyApp/Components/Shared/PostComments.razor b/MyApp/Components/Shared/PostComments.razor index 8d13e00..baff315 100644 --- a/MyApp/Components/Shared/PostComments.razor +++ b/MyApp/Components/Shared/PostComments.razor @@ -8,7 +8,9 @@ @foreach (var comment in Comments) {
    - @BlazorHtml.Raw(Markdown.GenerateCommentHtml(comment.Body)) + + @BlazorHtml.Raw(Markdown.GenerateCommentHtml(comment.Body)) + @comment.CreatedBy diff --git a/MyApp/wwwroot/css/app.css b/MyApp/wwwroot/css/app.css index 0c945a0..2a7ea9f 100644 --- a/MyApp/wwwroot/css/app.css +++ b/MyApp/wwwroot/css/app.css @@ -1144,6 +1144,10 @@ select{ margin-left: -0.25rem; } +.-ml-12 { + margin-left: -3rem; +} + .-ml-20 { margin-left: -5rem; } @@ -3451,6 +3455,16 @@ select{ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } +.\!invert { + --tw-invert: invert(100%) !important; + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow) !important; +} + +.invert { + --tw-invert: invert(100%); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} + .\!filter { filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow) !important; } @@ -3545,6 +3559,10 @@ select{ transition-timing-function: cubic-bezier(0, 0, 0.2, 1); } +.\[a-zA-Z\:_\] { + a-z-a--z: ; +} + .\[index\:string\] { index: string; } diff --git a/MyApp/wwwroot/lib/mjs/markdown.mjs b/MyApp/wwwroot/lib/mjs/markdown.mjs new file mode 100644 index 0000000..7aabf4c --- /dev/null +++ b/MyApp/wwwroot/lib/mjs/markdown.mjs @@ -0,0 +1,104 @@ +import { MarkedMin } from "./marked.min.mjs" + +const marked = new MarkedMin( + markedHighlight({ + langPrefix: 'hljs language-', + highlight(code, lang, info) { + const hljs = globalThis.hljs + const language = hljs.getLanguage(lang) ? lang : 'plaintext' + return hljs.highlight(code, { language }).value + } + }) +) + +export async function renderMarkdown(body) { + const rawHtml = marked.parse(body, { async:false }) + return rawHtml +} + +export function markedHighlight(options) { + if (typeof options === 'function') { + options = { + highlight: options + } + } + + if (!options || typeof options.highlight !== 'function') { + throw new Error('Must provide highlight function') + } + + if (typeof options.langPrefix !== 'string') { + options.langPrefix = 'language-' + } + + return { + async: !!options.async, + walkTokens(token) { + if (token.type !== 'code') { + return + } + + const lang = getLang(token.lang) + + if (options.async) { + return Promise.resolve(options.highlight(token.text, lang, token.lang || '')).then(updateToken(token)) + } + + const code = options.highlight(token.text, lang, token.lang || '') + if (code instanceof Promise) { + throw new Error('markedHighlight is not set to async but the highlight function is async. Set the async option to true on markedHighlight to await the async highlight function.') + } + updateToken(token)(code) + }, + renderer: { + code(code, infoString, escaped) { + const lang = getLang(infoString) + const classAttr = lang + ? ` class="${options.langPrefix}${escape(lang)}"` + : ' class="hljs"'; + code = code.replace(/\n$/, '') + return `
    ${escaped ? code : escape(code, true)}\n
    ` + } + } + } +} + +function getLang(lang) { + return (lang || '').match(/\S*/)[0] +} + +function updateToken(token) { + return code => { + if (typeof code === 'string' && code !== token.text) { + token.escaped = true + token.text = code + } + } +} + +// copied from marked helpers +const escapeTest = /[&<>"']/ +const escapeReplace = new RegExp(escapeTest.source, 'g') +const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/ +const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g') +const escapeReplacements = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' +} +const getEscapeReplacement = ch => escapeReplacements[ch] +function escape(html, encode) { + if (encode) { + if (escapeTest.test(html)) { + return html.replace(escapeReplace, getEscapeReplacement) + } + } else { + if (escapeTestNoEncode.test(html)) { + return html.replace(escapeReplaceNoEncode, getEscapeReplacement) + } + } + + return html +} diff --git a/MyApp/wwwroot/lib/mjs/marked.min.mjs b/MyApp/wwwroot/lib/mjs/marked.min.mjs new file mode 100644 index 0000000..6c08fe0 --- /dev/null +++ b/MyApp/wwwroot/lib/mjs/marked.min.mjs @@ -0,0 +1,8 @@ +/** from: https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.min.js + * Minified by jsDelivr using Terser v5.19.2. + * Original file: /npm/marked@12.0.2/lib/marked.esm.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +function _getDefaults(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}let _defaults=_getDefaults();function changeDefaults(e){_defaults=e}const escapeTest=/[&<>"']/,escapeReplace=new RegExp(escapeTest.source,"g"),escapeTestNoEncode=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode=new RegExp(escapeTestNoEncode.source,"g"),escapeReplacements={"&":"&","<":"<",">":">",'"':""","'":"'"},getEscapeReplacement=e=>escapeReplacements[e];function escape$1(e,t){if(t){if(escapeTest.test(e))return e.replace(escapeReplace,getEscapeReplacement)}else if(escapeTestNoEncode.test(e))return e.replace(escapeReplaceNoEncode,getEscapeReplacement);return e}const unescapeTest=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function unescape(e){return e.replace(unescapeTest,((e,t)=>"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""))}const caret=/(^|[^\[])\^/g;function edit(e,t){let n="string"==typeof e?e:e.source;t=t||"";const s={replace:(e,t)=>{let r="string"==typeof t?t:t.source;return r=r.replace(caret,"$1"),n=n.replace(e,r),s},getRegex:()=>new RegExp(n,t)};return s}function cleanUrl(e){try{e=encodeURI(e).replace(/%25/g,"%")}catch(e){return null}return e}const noopTest={exec:()=>null};function splitCells(e,t){const n=e.replace(/\|/g,((e,t,n)=>{let s=!1,r=t;for(;--r>=0&&"\\"===n[r];)s=!s;return s?"|":" |"})).split(/ \|/);let s=0;if(n[0].trim()||n.shift(),n.length>0&&!n[n.length-1].trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length{const t=e.match(/^\s+/);if(null===t)return e;const[n]=t;return n.length>=s.length?e.slice(s.length):e})).join("\n")}class _Tokenizer{options;rules;lexer;constructor(e){this.options=e||_defaults}space(e){const t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:rtrim(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],n=indentCodeCompensation(e,t[3]||"");return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:n}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(/#$/.test(e)){const t=rtrim(e,"#");this.options.pedantic?e=t.trim():t&&!/ $/.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){let e=t[0].replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,"\n $1");e=rtrim(e.replace(/^ *>[ \t]?/gm,""),"\n");const n=this.lexer.state.top;this.lexer.state.top=!0;const s=this.lexer.blockTokens(e);return this.lexer.state.top=n,{type:"blockquote",raw:t[0],tokens:s,text:e}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim();const s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");const i=new RegExp(`^( {0,3}${n})((?:[\t ][^\\n]*)?(?:\\n|$))`);let l="",o="",a=!1;for(;e;){let n=!1;if(!(t=i.exec(e)))break;if(this.rules.block.hr.test(e))break;l=t[0],e=e.substring(l.length);let s=t[2].split("\n",1)[0].replace(/^\t+/,(e=>" ".repeat(3*e.length))),c=e.split("\n",1)[0],p=0;this.options.pedantic?(p=2,o=s.trimStart()):(p=t[2].search(/[^ ]/),p=p>4?1:p,o=s.slice(p),p+=t[1].length);let h=!1;if(!s&&/^ *$/.test(c)&&(l+=c+"\n",e=e.substring(c.length+1),n=!0),!n){const t=new RegExp(`^ {0,${Math.min(3,p-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),n=new RegExp(`^ {0,${Math.min(3,p-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),r=new RegExp(`^ {0,${Math.min(3,p-1)}}(?:\`\`\`|~~~)`),i=new RegExp(`^ {0,${Math.min(3,p-1)}}#`);for(;e;){const a=e.split("\n",1)[0];if(c=a,this.options.pedantic&&(c=c.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),r.test(c))break;if(i.test(c))break;if(t.test(c))break;if(n.test(e))break;if(c.search(/[^ ]/)>=p||!c.trim())o+="\n"+c.slice(p);else{if(h)break;if(s.search(/[^ ]/)>=4)break;if(r.test(s))break;if(i.test(s))break;if(n.test(s))break;o+="\n"+c}h||c.trim()||(h=!0),l+=a+"\n",e=e.substring(a.length+1),s=c.slice(p)}}r.loose||(a?r.loose=!0:/\n *\n *$/.test(l)&&(a=!0));let u,k=null;this.options.gfm&&(k=/^\[[ xX]\] /.exec(o),k&&(u="[ ] "!==k[0],o=o.replace(/^\[[ xX]\] +/,""))),r.items.push({type:"list_item",raw:l,task:!!k,checked:u,loose:!1,text:o,tokens:[]}),r.raw+=l}r.items[r.items.length-1].raw=l.trimEnd(),r.items[r.items.length-1].text=o.trimEnd(),r.raw=r.raw.trimEnd();for(let e=0;e"space"===e.type)),n=t.length>0&&t.some((e=>/\n.*\n/.test(e.raw)));r.loose=n}if(r.loose)for(let e=0;e$/,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",s=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return{type:"def",tag:e,raw:t[0],href:n,title:s}}}table(e){const t=this.rules.block.table.exec(e);if(!t)return;if(!/[:|]/.test(t[2]))return;const n=splitCells(t[1]),s=t[2].replace(/^\||\| *$/g,"").split("|"),r=t[3]&&t[3].trim()?t[3].replace(/\n[ \t]*$/,"").split("\n"):[],i={type:"table",raw:t[0],header:[],align:[],rows:[]};if(n.length===s.length){for(const e of s)/^ *-+: *$/.test(e)?i.align.push("right"):/^ *:-+: *$/.test(e)?i.align.push("center"):/^ *:-+ *$/.test(e)?i.align.push("left"):i.align.push(null);for(const e of n)i.header.push({text:e,tokens:this.lexer.inline(e)});for(const e of r)i.rows.push(splitCells(e,i.header.length).map((e=>({text:e,tokens:this.lexer.inline(e)}))));return i}}lheading(e){const t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){const t=this.rules.block.paragraph.exec(e);if(t){const e="\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:e,tokens:this.lexer.inline(e)}}}text(e){const t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){const t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:escape$1(t[1])}}tag(e){const t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&/^/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&/^$/.test(e))return;const t=rtrim(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=findClosingBracket(t[2],"()");if(e>-1){const n=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,n).trim(),t[3]=""}}let n=t[2],s="";if(this.options.pedantic){const e=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(n);e&&(n=e[1],s=e[3])}else s=t[3]?t[3].slice(1,-1):"";return n=n.trim(),/^$/.test(e)?n.slice(1):n.slice(1,-1)),outputLink(t,{href:n?n.replace(this.rules.inline.anyPunctuation,"$1"):n,title:s?s.replace(this.rules.inline.anyPunctuation,"$1"):s},t[0],this.lexer)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){const e=t[(n[2]||n[1]).replace(/\s+/g," ").toLowerCase()];if(!e){const e=n[0].charAt(0);return{type:"text",raw:e,text:e}}return outputLink(n,e,n[0],this.lexer)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s)return;if(s[3]&&n.match(/[\p{L}\p{N}]/u))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){const n=[...s[0]].length-1;let r,i,l=n,o=0;const a="*"===s[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(a.lastIndex=0,t=t.slice(-1*e.length+n);null!=(s=a.exec(t));){if(r=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!r)continue;if(i=[...r].length,s[3]||s[4]){l+=i;continue}if((s[5]||s[6])&&n%3&&!((n+i)%3)){o+=i;continue}if(l-=i,l>0)continue;i=Math.min(i,i+l+o);const t=[...s[0]][0].length,a=e.slice(0,n+s.index+t+i);if(Math.min(n,i)%2){const e=a.slice(1,-1);return{type:"em",raw:a,text:e,tokens:this.lexer.inlineTokens(e)}}const c=a.slice(2,-2);return{type:"strong",raw:a,text:c,tokens:this.lexer.inlineTokens(c)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(/\n/g," ");const n=/[^ ]/.test(e),s=/^ /.test(e)&&/ $/.test(e);return n&&s&&(e=e.substring(1,e.length-1)),e=escape$1(e,!0),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){const t=this.rules.inline.autolink.exec(e);if(t){let e,n;return"@"===t[2]?(e=escape$1(t[1]),n="mailto:"+e):(e=escape$1(t[1]),n=e),{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let e,n;if("@"===t[2])e=escape$1(t[0]),n="mailto:"+e;else{let s;do{s=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??""}while(s!==t[0]);e=escape$1(t[0]),n="www."===t[1]?"http://"+t[0]:t[0]}return{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e){const t=this.rules.inline.text.exec(e);if(t){let e;return e=this.lexer.state.inRawBlock?t[0]:escape$1(t[0]),{type:"text",raw:t[0],text:e}}}}const newline=/^(?: *(?:\n|$))+/,blockCode=/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,hr=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,heading=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,bullet=/(?:[*+-]|\d{1,9}[.)])/,lheading=edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,bullet).replace(/blockCode/g,/ {4}/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).getRegex(),_paragraph=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,blockText=/^[^\n]+/,_blockLabel=/(?!\s*\])(?:\\.|[^\[\]\\])+/,def=edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label",_blockLabel).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),list=edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,bullet).getRegex(),_tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",_comment=/|$))/,html=edit("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))","i").replace("comment",_comment).replace("tag",_tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),paragraph=edit(_paragraph).replace("hr",hr).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",_tag).getRegex(),blockquote=edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",paragraph).getRegex(),blockNormal={blockquote:blockquote,code:blockCode,def:def,fences:fences,heading:heading,hr:hr,html:html,lheading:lheading,list:list,newline:newline,paragraph:paragraph,table:noopTest,text:blockText},gfmTable=edit("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",hr).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",_tag).getRegex(),blockGfm={...blockNormal,table:gfmTable,paragraph:edit(_paragraph).replace("hr",hr).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",gfmTable).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",_tag).getRegex()},blockPedantic={...blockNormal,html:edit("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",_comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:noopTest,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:edit(_paragraph).replace("hr",hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",lheading).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},escape=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,inlineCode=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br=/^( {2,}|\\)\n(?!\s*$)/,inlineText=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\]*?>/g,emStrongLDelim=edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,"u").replace(/punct/g,"\\p{P}\\p{S}").getRegex(),emStrongRDelimAst=edit("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])","gu").replace(/punct/g,"\\p{P}\\p{S}").getRegex(),emStrongRDelimUnd=edit("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])","gu").replace(/punct/g,"\\p{P}\\p{S}").getRegex(),anyPunctuation=edit(/\\([punct])/,"gu").replace(/punct/g,"\\p{P}\\p{S}").getRegex(),autolink=edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),_inlineComment=edit(_comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),tag=edit("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",_inlineComment).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),_inlineLabel=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,link=edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",_inlineLabel).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),reflink=edit(/^!?\[(label)\]\[(ref)\]/).replace("label",_inlineLabel).replace("ref",_blockLabel).getRegex(),nolink=edit(/^!?\[(ref)\](?:\[\])?/).replace("ref",_blockLabel).getRegex(),reflinkSearch=edit("reflink|nolink(?!\\()","g").replace("reflink",reflink).replace("nolink",nolink).getRegex(),inlineNormal={_backpedal:noopTest,anyPunctuation:anyPunctuation,autolink:autolink,blockSkip:blockSkip,br:br,code:inlineCode,del:noopTest,emStrongLDelim:emStrongLDelim,emStrongRDelimAst:emStrongRDelimAst,emStrongRDelimUnd:emStrongRDelimUnd,escape:escape,link:link,nolink:nolink,punctuation:punctuation,reflink:reflink,reflinkSearch:reflinkSearch,tag:tag,text:inlineText,url:noopTest},inlinePedantic={...inlineNormal,link:edit(/^!?\[(label)\]\((.*?)\)/).replace("label",_inlineLabel).getRegex(),reflink:edit(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",_inlineLabel).getRegex()},inlineGfm={...inlineNormal,escape:edit(escape).replace("])","~|])").getRegex(),url:edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\t+" ".repeat(n.length)));e;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((s=>!!(n=s.call({lexer:this},e,t))&&(e=e.substring(n.raw.length),t.push(n),!0)))))if(n=this.tokenizer.space(e))e=e.substring(n.raw.length),1===n.raw.length&&t.length>0?t[t.length-1].raw+="\n":t.push(n);else if(n=this.tokenizer.code(e))e=e.substring(n.raw.length),s=t[t.length-1],!s||"paragraph"!==s.type&&"text"!==s.type?t.push(n):(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue[this.inlineQueue.length-1].src=s.text);else if(n=this.tokenizer.fences(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.heading(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.hr(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.blockquote(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.list(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.html(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.def(e))e=e.substring(n.raw.length),s=t[t.length-1],!s||"paragraph"!==s.type&&"text"!==s.type?this.tokens.links[n.tag]||(this.tokens.links[n.tag]={href:n.href,title:n.title}):(s.raw+="\n"+n.raw,s.text+="\n"+n.raw,this.inlineQueue[this.inlineQueue.length-1].src=s.text);else if(n=this.tokenizer.table(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.lheading(e))e=e.substring(n.raw.length),t.push(n);else{if(r=e,this.options.extensions&&this.options.extensions.startBlock){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startBlock.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(this.state.top&&(n=this.tokenizer.paragraph(r)))s=t[t.length-1],i&&"paragraph"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=s.text):t.push(n),i=r.length!==e.length,e=e.substring(n.raw.length);else if(n=this.tokenizer.text(e))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=s.text):t.push(n);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n,s,r,i,l,o,a=e;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(i=this.tokenizer.rules.inline.reflinkSearch.exec(a));)e.includes(i[0].slice(i[0].lastIndexOf("[")+1,-1))&&(a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(i=this.tokenizer.rules.inline.blockSkip.exec(a));)a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(i=this.tokenizer.rules.inline.anyPunctuation.exec(a));)a=a.slice(0,i.index)+"++"+a.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;e;)if(l||(o=""),l=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((s=>!!(n=s.call({lexer:this},e,t))&&(e=e.substring(n.raw.length),t.push(n),!0)))))if(n=this.tokenizer.escape(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.tag(e))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.link(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.emStrong(e,a,o))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.codespan(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.br(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.del(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.autolink(e))e=e.substring(n.raw.length),t.push(n);else if(this.state.inLink||!(n=this.tokenizer.url(e))){if(r=e,this.options.extensions&&this.options.extensions.startInline){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startInline.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(n=this.tokenizer.inlineText(r))e=e.substring(n.raw.length),"_"!==n.raw.slice(-1)&&(o=n.raw.slice(-1)),l=!0,s=t[t.length-1],s&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}else e=e.substring(n.raw.length),t.push(n);return t}}class _Renderer{options;constructor(e){this.options=e||_defaults}code(e,t,n){const s=(t||"").match(/^\S*/)?.[0];return e=e.replace(/\n$/,"")+"\n",s?'
    '+(n?e:escape$1(e,!0))+"
    \n":"
    "+(n?e:escape$1(e,!0))+"
    \n"}blockquote(e){return`
    \n${e}
    \n`}html(e,t){return e}heading(e,t,n){return`${e}\n`}hr(){return"
    \n"}list(e,t,n){const s=t?"ol":"ul";return"<"+s+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"}listitem(e,t,n){return`
  • ${e}
  • \n`}checkbox(e){return"'}paragraph(e){return`

    ${e}

    \n`}table(e,t){return t&&(t=`${t}`),"\n\n"+e+"\n"+t+"
    \n"}tablerow(e){return`\n${e}\n`}tablecell(e,t){const n=t.header?"th":"td";return(t.align?`<${n} align="${t.align}">`:`<${n}>`)+e+`\n`}strong(e){return`${e}`}em(e){return`${e}`}codespan(e){return`${e}`}br(){return"
    "}del(e){return`${e}`}link(e,t,n){const s=cleanUrl(e);if(null===s)return n;let r='
    ",r}image(e,t,n){const s=cleanUrl(e);if(null===s)return n;let r=`${n}0&&"paragraph"===n.tokens[0].type?(n.tokens[0].text=e+" "+n.tokens[0].text,n.tokens[0].tokens&&n.tokens[0].tokens.length>0&&"text"===n.tokens[0].tokens[0].type&&(n.tokens[0].tokens[0].text=e+" "+n.tokens[0].tokens[0].text)):n.tokens.unshift({type:"text",text:e+" "}):o+=e+" "}o+=this.parse(n.tokens,i),l+=this.renderer.listitem(o,r,!!s)}n+=this.renderer.list(l,t,s);continue}case"html":{const e=r;n+=this.renderer.html(e.text,e.block);continue}case"paragraph":{const e=r;n+=this.renderer.paragraph(this.parseInline(e.tokens));continue}case"text":{let i=r,l=i.tokens?this.parseInline(i.tokens):i.text;for(;s+1{const r=e[s].flat(1/0);n=n.concat(this.walkTokens(r,t))})):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach((e=>{const n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if("renderer"in e){const n=t.renderers[e.name];t.renderers[e.name]=n?function(...t){let s=e.renderer.apply(this,t);return!1===s&&(s=n.apply(this,t)),s}:e.renderer}if("tokenizer"in e){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");const n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}"childTokens"in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),n.extensions=t),e.renderer){const t=this.defaults.renderer||new _Renderer(this.defaults);for(const n in e.renderer){if(!(n in t))throw new Error(`renderer '${n}' does not exist`);if("options"===n)continue;const s=n,r=e.renderer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n||""}}n.renderer=t}if(e.tokenizer){const t=this.defaults.tokenizer||new _Tokenizer(this.defaults);for(const n in e.tokenizer){if(!(n in t))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;const s=n,r=e.tokenizer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){const t=this.defaults.hooks||new _Hooks;for(const n in e.hooks){if(!(n in t))throw new Error(`hook '${n}' does not exist`);if("options"===n)continue;const s=n,r=e.hooks[s],i=t[s];_Hooks.passThroughHooks.has(n)?t[s]= e=>{if(this.defaults.async)return Promise.resolve(r.call(t,e)).then((e=>i.call(t,e)));const n=r.call(t,e);return i.call(t,n)}:t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){const t=this.defaults.walkTokens,s=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(s.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}})),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e, t){return _Lexer.lex(e,t??this.defaults)}parser(e, t){return _Parser.parse(e,t??this.defaults)}#e(e, t){return(n, s)=>{const r={...s},i={...this.defaults,...r};!0===this.defaults.async&&!1===r.async&&(i.silent||console.warn("marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored."),i.async=!0);const l=this.#t(!!i.silent,!!i.async);if(null==n)return l(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof n)return l(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(i.hooks&&(i.hooks.options=i),i.async)return Promise.resolve(i.hooks?i.hooks.preprocess(n):n).then((t=>e(t,i))).then((e=>i.hooks?i.hooks.processAllTokens(e):e)).then((e=>i.walkTokens?Promise.all(this.walkTokens(e,i.walkTokens)).then((()=>e)):e)).then((e=>t(e,i))).then((e=>i.hooks?i.hooks.postprocess(e):e)).catch(l);try{i.hooks&&(n=i.hooks.preprocess(n));let s=e(n,i);i.hooks&&(s=i.hooks.processAllTokens(s)),i.walkTokens&&this.walkTokens(s,i.walkTokens);let r=t(s,i);return i.hooks&&(r=i.hooks.postprocess(r)),r}catch(e){return l(e)}}}#t(e, t){return n=>{if(n.message+="\nPlease report this to https://github.com/markedjs/marked.",e){const e="

    An error occurred:

    "+escape$1(n.message+"",!0)+"
    ";return t?Promise.resolve(e):e}if(t)return Promise.reject(n);throw n}}}const markedInstance=new MarkedMin;function marked(e, t){return markedInstance.parse(e,t)}marked.options=marked.setOptions=function(e){return markedInstance.setOptions(e),marked.defaults=markedInstance.defaults,changeDefaults(marked.defaults),marked},marked.getDefaults=_getDefaults,marked.defaults=_defaults,marked.use=function(...e){return markedInstance.use(...e),marked.defaults=markedInstance.defaults,changeDefaults(marked.defaults),marked},marked.walkTokens=function(e, t){return markedInstance.walkTokens(e,t)},marked.parseInline=markedInstance.parseInline,marked.Parser=_Parser,marked.parser=_Parser.parse,marked.Renderer=_Renderer,marked.TextRenderer=_TextRenderer,marked.Lexer=_Lexer,marked.lexer=_Lexer.lex,marked.Tokenizer=_Tokenizer,marked.Hooks=_Hooks,marked.parse=marked;const options=marked.options,setOptions=marked.setOptions,use=marked.use,walkTokens=marked.walkTokens,parseInline=marked.parseInline,parse=marked,parser=_Parser.parse,lexer=_Lexer.lex;export{_Hooks as Hooks,_Lexer as Lexer,MarkedMin,_Parser as Parser,_Renderer as Renderer,_TextRenderer as TextRenderer,_Tokenizer as Tokenizer,_defaults as defaults,_getDefaults as getDefaults,lexer,marked,options,parse,parseInline,parser,setOptions,use,walkTokens}; +//# sourceMappingURL=/sm/32ef376af63ec3f3f0868d716d707116263d6dc56c25384b7c6add79e1beae73.map \ No newline at end of file diff --git a/MyApp/wwwroot/lib/mjs/marked.mjs b/MyApp/wwwroot/lib/mjs/marked.mjs new file mode 100644 index 0000000..5d758dc --- /dev/null +++ b/MyApp/wwwroot/lib/mjs/marked.mjs @@ -0,0 +1,2432 @@ +/** + * marked v12.0.2 - a markdown parser + * Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed) + * https://github.com/markedjs/marked + */ + +/** + * DO NOT EDIT THIS FILE + * The code in this file is generated from files in ./src/ + */ + +/** + * Gets the original marked default options. + */ +function _getDefaults() { + return { + async: false, + breaks: false, + extensions: null, + gfm: true, + hooks: null, + pedantic: false, + renderer: null, + silent: false, + tokenizer: null, + walkTokens: null + }; +} +let _defaults = _getDefaults(); +function changeDefaults(newDefaults) { + _defaults = newDefaults; +} + +/** + * Helpers + */ +const escapeTest = /[&<>"']/; +const escapeReplace = new RegExp(escapeTest.source, 'g'); +const escapeTestNoEncode = /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/; +const escapeReplaceNoEncode = new RegExp(escapeTestNoEncode.source, 'g'); +const escapeReplacements = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' +}; +const getEscapeReplacement = (ch) => escapeReplacements[ch]; +function escape$1(html, encode) { + if (encode) { + if (escapeTest.test(html)) { + return html.replace(escapeReplace, getEscapeReplacement); + } + } + else { + if (escapeTestNoEncode.test(html)) { + return html.replace(escapeReplaceNoEncode, getEscapeReplacement); + } + } + return html; +} +const unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig; +function unescape(html) { + // explicitly match decimal, hex, and named HTML entities + return html.replace(unescapeTest, (_, n) => { + n = n.toLowerCase(); + if (n === 'colon') + return ':'; + if (n.charAt(0) === '#') { + return n.charAt(1) === 'x' + ? String.fromCharCode(parseInt(n.substring(2), 16)) + : String.fromCharCode(+n.substring(1)); + } + return ''; + }); +} +const caret = /(^|[^\[])\^/g; +function edit(regex, opt) { + let source = typeof regex === 'string' ? regex : regex.source; + opt = opt || ''; + const obj = { + replace: (name, val) => { + let valSource = typeof val === 'string' ? val : val.source; + valSource = valSource.replace(caret, '$1'); + source = source.replace(name, valSource); + return obj; + }, + getRegex: () => { + return new RegExp(source, opt); + } + }; + return obj; +} +function cleanUrl(href) { + try { + href = encodeURI(href).replace(/%25/g, '%'); + } + catch (e) { + return null; + } + return href; +} +const noopTest = { exec: () => null }; +function splitCells(tableRow, count) { + // ensure that every cell-delimiting pipe has a space + // before it to distinguish it from an escaped pipe + const row = tableRow.replace(/\|/g, (match, offset, str) => { + let escaped = false; + let curr = offset; + while (--curr >= 0 && str[curr] === '\\') + escaped = !escaped; + if (escaped) { + // odd number of slashes means | is escaped + // so we leave it alone + return '|'; + } + else { + // add space before unescaped | + return ' |'; + } + }), cells = row.split(/ \|/); + let i = 0; + // First/last cell in a row cannot be empty if it has no leading/trailing pipe + if (!cells[0].trim()) { + cells.shift(); + } + if (cells.length > 0 && !cells[cells.length - 1].trim()) { + cells.pop(); + } + if (count) { + if (cells.length > count) { + cells.splice(count); + } + else { + while (cells.length < count) + cells.push(''); + } + } + for (; i < cells.length; i++) { + // leading or trailing whitespace is ignored per the gfm spec + cells[i] = cells[i].trim().replace(/\\\|/g, '|'); + } + return cells; +} +/** + * Remove trailing 'c's. Equivalent to str.replace(/c*$/, ''). + * /c*$/ is vulnerable to REDOS. + * + * @param str + * @param c + * @param invert Remove suffix of non-c chars instead. Default falsey. + */ +function rtrim(str, c, invert) { + const l = str.length; + if (l === 0) { + return ''; + } + // Length of suffix matching the invert condition. + let suffLen = 0; + // Step left until we fail to match the invert condition. + while (suffLen < l) { + const currChar = str.charAt(l - suffLen - 1); + if (currChar === c && !invert) { + suffLen++; + } + else if (currChar !== c && invert) { + suffLen++; + } + else { + break; + } + } + return str.slice(0, l - suffLen); +} +function findClosingBracket(str, b) { + if (str.indexOf(b[1]) === -1) { + return -1; + } + let level = 0; + for (let i = 0; i < str.length; i++) { + if (str[i] === '\\') { + i++; + } + else if (str[i] === b[0]) { + level++; + } + else if (str[i] === b[1]) { + level--; + if (level < 0) { + return i; + } + } + } + return -1; +} + +function outputLink(cap, link, raw, lexer) { + const href = link.href; + const title = link.title ? escape$1(link.title) : null; + const text = cap[1].replace(/\\([\[\]])/g, '$1'); + if (cap[0].charAt(0) !== '!') { + lexer.state.inLink = true; + const token = { + type: 'link', + raw, + href, + title, + text, + tokens: lexer.inlineTokens(text) + }; + lexer.state.inLink = false; + return token; + } + return { + type: 'image', + raw, + href, + title, + text: escape$1(text) + }; +} +function indentCodeCompensation(raw, text) { + const matchIndentToCode = raw.match(/^(\s+)(?:```)/); + if (matchIndentToCode === null) { + return text; + } + const indentToCode = matchIndentToCode[1]; + return text + .split('\n') + .map(node => { + const matchIndentInNode = node.match(/^\s+/); + if (matchIndentInNode === null) { + return node; + } + const [indentInNode] = matchIndentInNode; + if (indentInNode.length >= indentToCode.length) { + return node.slice(indentToCode.length); + } + return node; + }) + .join('\n'); +} +/** + * Tokenizer + */ +class _Tokenizer { + options; + rules; // set by the lexer + lexer; // set by the lexer + constructor(options) { + this.options = options || _defaults; + } + space(src) { + const cap = this.rules.block.newline.exec(src); + if (cap && cap[0].length > 0) { + return { + type: 'space', + raw: cap[0] + }; + } + } + code(src) { + const cap = this.rules.block.code.exec(src); + if (cap) { + const text = cap[0].replace(/^ {1,4}/gm, ''); + return { + type: 'code', + raw: cap[0], + codeBlockStyle: 'indented', + text: !this.options.pedantic + ? rtrim(text, '\n') + : text + }; + } + } + fences(src) { + const cap = this.rules.block.fences.exec(src); + if (cap) { + const raw = cap[0]; + const text = indentCodeCompensation(raw, cap[3] || ''); + return { + type: 'code', + raw, + lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2], + text + }; + } + } + heading(src) { + const cap = this.rules.block.heading.exec(src); + if (cap) { + let text = cap[2].trim(); + // remove trailing #s + if (/#$/.test(text)) { + const trimmed = rtrim(text, '#'); + if (this.options.pedantic) { + text = trimmed.trim(); + } + else if (!trimmed || / $/.test(trimmed)) { + // CommonMark requires space before trailing #s + text = trimmed.trim(); + } + } + return { + type: 'heading', + raw: cap[0], + depth: cap[1].length, + text, + tokens: this.lexer.inline(text) + }; + } + } + hr(src) { + const cap = this.rules.block.hr.exec(src); + if (cap) { + return { + type: 'hr', + raw: cap[0] + }; + } + } + blockquote(src) { + const cap = this.rules.block.blockquote.exec(src); + if (cap) { + // precede setext continuation with 4 spaces so it isn't a setext + let text = cap[0].replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g, '\n $1'); + text = rtrim(text.replace(/^ *>[ \t]?/gm, ''), '\n'); + const top = this.lexer.state.top; + this.lexer.state.top = true; + const tokens = this.lexer.blockTokens(text); + this.lexer.state.top = top; + return { + type: 'blockquote', + raw: cap[0], + tokens, + text + }; + } + } + list(src) { + let cap = this.rules.block.list.exec(src); + if (cap) { + let bull = cap[1].trim(); + const isordered = bull.length > 1; + const list = { + type: 'list', + raw: '', + ordered: isordered, + start: isordered ? +bull.slice(0, -1) : '', + loose: false, + items: [] + }; + bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`; + if (this.options.pedantic) { + bull = isordered ? bull : '[*+-]'; + } + // Get next list item + const itemRegex = new RegExp(`^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`); + let raw = ''; + let itemContents = ''; + let endsWithBlankLine = false; + // Check if current bullet point can start a new List Item + while (src) { + let endEarly = false; + if (!(cap = itemRegex.exec(src))) { + break; + } + if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?) + break; + } + raw = cap[0]; + src = src.substring(raw.length); + let line = cap[2].split('\n', 1)[0].replace(/^\t+/, (t) => ' '.repeat(3 * t.length)); + let nextLine = src.split('\n', 1)[0]; + let indent = 0; + if (this.options.pedantic) { + indent = 2; + itemContents = line.trimStart(); + } + else { + indent = cap[2].search(/[^ ]/); // Find first non-space char + indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent + itemContents = line.slice(indent); + indent += cap[1].length; + } + let blankLine = false; + if (!line && /^ *$/.test(nextLine)) { // Items begin with at most one blank line + raw += nextLine + '\n'; + src = src.substring(nextLine.length + 1); + endEarly = true; + } + if (!endEarly) { + const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`); + const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`); + const fencesBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\`\`\`|~~~)`); + const headingBeginRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`); + // Check if following lines should be included in List Item + while (src) { + const rawLine = src.split('\n', 1)[0]; + nextLine = rawLine; + // Re-align to follow commonmark nesting rules + if (this.options.pedantic) { + nextLine = nextLine.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' '); + } + // End list item if found code fences + if (fencesBeginRegex.test(nextLine)) { + break; + } + // End list item if found start of new heading + if (headingBeginRegex.test(nextLine)) { + break; + } + // End list item if found start of new bullet + if (nextBulletRegex.test(nextLine)) { + break; + } + // Horizontal rule found + if (hrRegex.test(src)) { + break; + } + if (nextLine.search(/[^ ]/) >= indent || !nextLine.trim()) { // Dedent if possible + itemContents += '\n' + nextLine.slice(indent); + } + else { + // not enough indentation + if (blankLine) { + break; + } + // paragraph continuation unless last line was a different block level element + if (line.search(/[^ ]/) >= 4) { // indented code block + break; + } + if (fencesBeginRegex.test(line)) { + break; + } + if (headingBeginRegex.test(line)) { + break; + } + if (hrRegex.test(line)) { + break; + } + itemContents += '\n' + nextLine; + } + if (!blankLine && !nextLine.trim()) { // Check if current line is blank + blankLine = true; + } + raw += rawLine + '\n'; + src = src.substring(rawLine.length + 1); + line = nextLine.slice(indent); + } + } + if (!list.loose) { + // If the previous item ended with a blank line, the list is loose + if (endsWithBlankLine) { + list.loose = true; + } + else if (/\n *\n *$/.test(raw)) { + endsWithBlankLine = true; + } + } + let istask = null; + let ischecked; + // Check for task list items + if (this.options.gfm) { + istask = /^\[[ xX]\] /.exec(itemContents); + if (istask) { + ischecked = istask[0] !== '[ ] '; + itemContents = itemContents.replace(/^\[[ xX]\] +/, ''); + } + } + list.items.push({ + type: 'list_item', + raw, + task: !!istask, + checked: ischecked, + loose: false, + text: itemContents, + tokens: [] + }); + list.raw += raw; + } + // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic + list.items[list.items.length - 1].raw = raw.trimEnd(); + (list.items[list.items.length - 1]).text = itemContents.trimEnd(); + list.raw = list.raw.trimEnd(); + // Item child tokens handled here at end because we needed to have the final item to trim it first + for (let i = 0; i < list.items.length; i++) { + this.lexer.state.top = false; + list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []); + if (!list.loose) { + // Check if list should be loose + const spacers = list.items[i].tokens.filter(t => t.type === 'space'); + const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => /\n.*\n/.test(t.raw)); + list.loose = hasMultipleLineBreaks; + } + } + // Set all items to loose if list is loose + if (list.loose) { + for (let i = 0; i < list.items.length; i++) { + list.items[i].loose = true; + } + } + return list; + } + } + html(src) { + const cap = this.rules.block.html.exec(src); + if (cap) { + const token = { + type: 'html', + block: true, + raw: cap[0], + pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style', + text: cap[0] + }; + return token; + } + } + def(src) { + const cap = this.rules.block.def.exec(src); + if (cap) { + const tag = cap[1].toLowerCase().replace(/\s+/g, ' '); + const href = cap[2] ? cap[2].replace(/^<(.*)>$/, '$1').replace(this.rules.inline.anyPunctuation, '$1') : ''; + const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, '$1') : cap[3]; + return { + type: 'def', + tag, + raw: cap[0], + href, + title + }; + } + } + table(src) { + const cap = this.rules.block.table.exec(src); + if (!cap) { + return; + } + if (!/[:|]/.test(cap[2])) { + // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading + return; + } + const headers = splitCells(cap[1]); + const aligns = cap[2].replace(/^\||\| *$/g, '').split('|'); + const rows = cap[3] && cap[3].trim() ? cap[3].replace(/\n[ \t]*$/, '').split('\n') : []; + const item = { + type: 'table', + raw: cap[0], + header: [], + align: [], + rows: [] + }; + if (headers.length !== aligns.length) { + // header and align columns must be equal, rows can be different. + return; + } + for (const align of aligns) { + if (/^ *-+: *$/.test(align)) { + item.align.push('right'); + } + else if (/^ *:-+: *$/.test(align)) { + item.align.push('center'); + } + else if (/^ *:-+ *$/.test(align)) { + item.align.push('left'); + } + else { + item.align.push(null); + } + } + for (const header of headers) { + item.header.push({ + text: header, + tokens: this.lexer.inline(header) + }); + } + for (const row of rows) { + item.rows.push(splitCells(row, item.header.length).map(cell => { + return { + text: cell, + tokens: this.lexer.inline(cell) + }; + })); + } + return item; + } + lheading(src) { + const cap = this.rules.block.lheading.exec(src); + if (cap) { + return { + type: 'heading', + raw: cap[0], + depth: cap[2].charAt(0) === '=' ? 1 : 2, + text: cap[1], + tokens: this.lexer.inline(cap[1]) + }; + } + } + paragraph(src) { + const cap = this.rules.block.paragraph.exec(src); + if (cap) { + const text = cap[1].charAt(cap[1].length - 1) === '\n' + ? cap[1].slice(0, -1) + : cap[1]; + return { + type: 'paragraph', + raw: cap[0], + text, + tokens: this.lexer.inline(text) + }; + } + } + text(src) { + const cap = this.rules.block.text.exec(src); + if (cap) { + return { + type: 'text', + raw: cap[0], + text: cap[0], + tokens: this.lexer.inline(cap[0]) + }; + } + } + escape(src) { + const cap = this.rules.inline.escape.exec(src); + if (cap) { + return { + type: 'escape', + raw: cap[0], + text: escape$1(cap[1]) + }; + } + } + tag(src) { + const cap = this.rules.inline.tag.exec(src); + if (cap) { + if (!this.lexer.state.inLink && /^
    /i.test(cap[0])) { + this.lexer.state.inLink = false; + } + if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.lexer.state.inRawBlock = true; + } + else if (this.lexer.state.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.lexer.state.inRawBlock = false; + } + return { + type: 'html', + raw: cap[0], + inLink: this.lexer.state.inLink, + inRawBlock: this.lexer.state.inRawBlock, + block: false, + text: cap[0] + }; + } + } + link(src) { + const cap = this.rules.inline.link.exec(src); + if (cap) { + const trimmedUrl = cap[2].trim(); + if (!this.options.pedantic && /^$/.test(trimmedUrl))) { + return; + } + // ending angle bracket cannot be escaped + const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\'); + if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) { + return; + } + } + else { + // find closing parenthesis + const lastParenIndex = findClosingBracket(cap[2], '()'); + if (lastParenIndex > -1) { + const start = cap[0].indexOf('!') === 0 ? 5 : 4; + const linkLen = start + cap[1].length + lastParenIndex; + cap[2] = cap[2].substring(0, lastParenIndex); + cap[0] = cap[0].substring(0, linkLen).trim(); + cap[3] = ''; + } + } + let href = cap[2]; + let title = ''; + if (this.options.pedantic) { + // split pedantic href and title + const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); + if (link) { + href = link[1]; + title = link[3]; + } + } + else { + title = cap[3] ? cap[3].slice(1, -1) : ''; + } + href = href.trim(); + if (/^$/.test(trimmedUrl))) { + // pedantic allows starting angle bracket without ending angle bracket + href = href.slice(1); + } + else { + href = href.slice(1, -1); + } + } + return outputLink(cap, { + href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href, + title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title + }, cap[0], this.lexer); + } + } + reflink(src, links) { + let cap; + if ((cap = this.rules.inline.reflink.exec(src)) + || (cap = this.rules.inline.nolink.exec(src))) { + const linkString = (cap[2] || cap[1]).replace(/\s+/g, ' '); + const link = links[linkString.toLowerCase()]; + if (!link) { + const text = cap[0].charAt(0); + return { + type: 'text', + raw: text, + text + }; + } + return outputLink(cap, link, cap[0], this.lexer); + } + } + emStrong(src, maskedSrc, prevChar = '') { + let match = this.rules.inline.emStrongLDelim.exec(src); + if (!match) + return; + // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well + if (match[3] && prevChar.match(/[\p{L}\p{N}]/u)) + return; + const nextChar = match[1] || match[2] || ''; + if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) { + // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below) + const lLength = [...match[0]].length - 1; + let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0; + const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd; + endReg.lastIndex = 0; + // Clip maskedSrc to same section of string as src (move to lexer?) + maskedSrc = maskedSrc.slice(-1 * src.length + lLength); + while ((match = endReg.exec(maskedSrc)) != null) { + rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6]; + if (!rDelim) + continue; // skip single * in __abc*abc__ + rLength = [...rDelim].length; + if (match[3] || match[4]) { // found another Left Delim + delimTotal += rLength; + continue; + } + else if (match[5] || match[6]) { // either Left or Right Delim + if (lLength % 3 && !((lLength + rLength) % 3)) { + midDelimTotal += rLength; + continue; // CommonMark Emphasis Rules 9-10 + } + } + delimTotal -= rLength; + if (delimTotal > 0) + continue; // Haven't found enough closing delimiters + // Remove extra characters. *a*** -> *a* + rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal); + // char length can be >1 for unicode characters; + const lastCharLength = [...match[0]][0].length; + const raw = src.slice(0, lLength + match.index + lastCharLength + rLength); + // Create `em` if smallest delimiter has odd char count. *a*** + if (Math.min(lLength, rLength) % 2) { + const text = raw.slice(1, -1); + return { + type: 'em', + raw, + text, + tokens: this.lexer.inlineTokens(text) + }; + } + // Create 'strong' if smallest delimiter has even char count. **a*** + const text = raw.slice(2, -2); + return { + type: 'strong', + raw, + text, + tokens: this.lexer.inlineTokens(text) + }; + } + } + } + codespan(src) { + const cap = this.rules.inline.code.exec(src); + if (cap) { + let text = cap[2].replace(/\n/g, ' '); + const hasNonSpaceChars = /[^ ]/.test(text); + const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text); + if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) { + text = text.substring(1, text.length - 1); + } + text = escape$1(text, true); + return { + type: 'codespan', + raw: cap[0], + text + }; + } + } + br(src) { + const cap = this.rules.inline.br.exec(src); + if (cap) { + return { + type: 'br', + raw: cap[0] + }; + } + } + del(src) { + const cap = this.rules.inline.del.exec(src); + if (cap) { + return { + type: 'del', + raw: cap[0], + text: cap[2], + tokens: this.lexer.inlineTokens(cap[2]) + }; + } + } + autolink(src) { + const cap = this.rules.inline.autolink.exec(src); + if (cap) { + let text, href; + if (cap[2] === '@') { + text = escape$1(cap[1]); + href = 'mailto:' + text; + } + else { + text = escape$1(cap[1]); + href = text; + } + return { + type: 'link', + raw: cap[0], + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text + } + ] + }; + } + } + url(src) { + let cap; + if (cap = this.rules.inline.url.exec(src)) { + let text, href; + if (cap[2] === '@') { + text = escape$1(cap[0]); + href = 'mailto:' + text; + } + else { + // do extended autolink path validation + let prevCapZero; + do { + prevCapZero = cap[0]; + cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? ''; + } while (prevCapZero !== cap[0]); + text = escape$1(cap[0]); + if (cap[1] === 'www.') { + href = 'http://' + cap[0]; + } + else { + href = cap[0]; + } + } + return { + type: 'link', + raw: cap[0], + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text + } + ] + }; + } + } + inlineText(src) { + const cap = this.rules.inline.text.exec(src); + if (cap) { + let text; + if (this.lexer.state.inRawBlock) { + text = cap[0]; + } + else { + text = escape$1(cap[0]); + } + return { + type: 'text', + raw: cap[0], + text + }; + } + } +} + +/** + * Block-Level Grammar + */ +const newline = /^(?: *(?:\n|$))+/; +const blockCode = /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/; +const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/; +const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/; +const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/; +const bullet = /(?:[*+-]|\d{1,9}[.)])/; +const lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/) + .replace(/bull/g, bullet) // lists can interrupt + .replace(/blockCode/g, / {4}/) // indented code blocks can interrupt + .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt + .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt + .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt + .replace(/html/g, / {0,3}<[^\n>]+>\n/) // block html can interrupt + .getRegex(); +const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/; +const blockText = /^[^\n]+/; +const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/; +const def = edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/) + .replace('label', _blockLabel) + .replace('title', /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/) + .getRegex(); +const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/) + .replace(/bull/g, bullet) + .getRegex(); +const _tag = 'address|article|aside|base|basefont|blockquote|body|caption' + + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' + + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' + + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' + + '|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title' + + '|tr|track|ul'; +const _comment = /|$))/; +const html = edit('^ {0,3}(?:' // optional indentation + + '<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)' // (1) + + '|comment[^\\n]*(\\n+|$)' // (2) + + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3) + + '|\\n*|$)' // (4) + + '|\\n*|$)' // (5) + + '|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6) + + '|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag + + '|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag + + ')', 'i') + .replace('comment', _comment) + .replace('tag', _tag) + .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/) + .getRegex(); +const paragraph = edit(_paragraph) + .replace('hr', hr) + .replace('heading', ' {0,3}#{1,6}(?:\\s|$)') + .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs + .replace('|table', '') + .replace('blockquote', ' {0,3}>') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|textarea|!--)') + .replace('tag', _tag) // pars can be interrupted by type (6) html blocks + .getRegex(); +const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/) + .replace('paragraph', paragraph) + .getRegex(); +/** + * Normal Block Grammar + */ +const blockNormal = { + blockquote, + code: blockCode, + def, + fences, + heading, + hr, + html, + lheading, + list, + newline, + paragraph, + table: noopTest, + text: blockText +}; +/** + * GFM Block Grammar + */ +const gfmTable = edit('^ *([^\\n ].*)\\n' // Header + + ' {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)' // Align + + '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)') // Cells + .replace('hr', hr) + .replace('heading', ' {0,3}#{1,6}(?:\\s|$)') + .replace('blockquote', ' {0,3}>') + .replace('code', ' {4}[^\\n]') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|textarea|!--)') + .replace('tag', _tag) // tables can be interrupted by type (6) html blocks + .getRegex(); +const blockGfm = { + ...blockNormal, + table: gfmTable, + paragraph: edit(_paragraph) + .replace('hr', hr) + .replace('heading', ' {0,3}#{1,6}(?:\\s|$)') + .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs + .replace('table', gfmTable) // interrupt paragraphs with table + .replace('blockquote', ' {0,3}>') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|textarea|!--)') + .replace('tag', _tag) // pars can be interrupted by type (6) html blocks + .getRegex() +}; +/** + * Pedantic grammar (original John Gruber's loose markdown specification) + */ +const blockPedantic = { + ...blockNormal, + html: edit('^ *(?:comment *(?:\\n|\\s*$)' + + '|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)' // closed tag + + '|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))') + .replace('comment', _comment) + .replace(/tag/g, '(?!(?:' + + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b') + .getRegex(), + def: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, + heading: /^(#{1,6})(.*)(?:\n+|$)/, + fences: noopTest, // fences not supported + lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, + paragraph: edit(_paragraph) + .replace('hr', hr) + .replace('heading', ' *#{1,6} *[^\n]') + .replace('lheading', lheading) + .replace('|table', '') + .replace('blockquote', ' {0,3}>') + .replace('|fences', '') + .replace('|list', '') + .replace('|html', '') + .replace('|tag', '') + .getRegex() +}; +/** + * Inline-Level Grammar + */ +const escape = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/; +const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/; +const br = /^( {2,}|\\)\n(?!\s*$)/; +const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\ +const blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g; +const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, 'u') + .replace(/punct/g, _punctuation) + .getRegex(); +const emStrongRDelimAst = edit('^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)' // Skip orphan inside strong + + '|[^*]+(?=[^*])' // Consume to delim + + '|(?!\\*)[punct](\\*+)(?=[\\s]|$)' // (1) #*** can only be a Right Delimiter + + '|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)' // (2) a***#, a*** can only be a Right Delimiter + + '|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])' // (3) #***a, ***a can only be Left Delimiter + + '|[\\s](\\*+)(?!\\*)(?=[punct])' // (4) ***# can only be Left Delimiter + + '|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])' // (5) #***# can be either Left or Right Delimiter + + '|[^punct\\s](\\*+)(?=[^punct\\s])', 'gu') // (6) a***a can be either Left or Right Delimiter + .replace(/punct/g, _punctuation) + .getRegex(); +// (6) Not allowed for _ +const emStrongRDelimUnd = edit('^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)' // Skip orphan inside strong + + '|[^_]+(?=[^_])' // Consume to delim + + '|(?!_)[punct](_+)(?=[\\s]|$)' // (1) #___ can only be a Right Delimiter + + '|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)' // (2) a___#, a___ can only be a Right Delimiter + + '|(?!_)[punct\\s](_+)(?=[^punct\\s])' // (3) #___a, ___a can only be Left Delimiter + + '|[\\s](_+)(?!_)(?=[punct])' // (4) ___# can only be Left Delimiter + + '|(?!_)[punct](_+)(?!_)(?=[punct])', 'gu') // (5) #___# can be either Left or Right Delimiter + .replace(/punct/g, _punctuation) + .getRegex(); +const anyPunctuation = edit(/\\([punct])/, 'gu') + .replace(/punct/g, _punctuation) + .getRegex(); +const autolink = edit(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/) + .replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/) + .replace('email', /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/) + .getRegex(); +const _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex(); +const tag = edit('^comment' + + '|^' // self-closing tag + + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag + + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. + + '|^' // declaration, e.g. + + '|^') // CDATA section + .replace('comment', _inlineComment) + .replace('attribute', /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/) + .getRegex(); +const _inlineLabel = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/; +const link = edit(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/) + .replace('label', _inlineLabel) + .replace('href', /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/) + .replace('title', /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/) + .getRegex(); +const reflink = edit(/^!?\[(label)\]\[(ref)\]/) + .replace('label', _inlineLabel) + .replace('ref', _blockLabel) + .getRegex(); +const nolink = edit(/^!?\[(ref)\](?:\[\])?/) + .replace('ref', _blockLabel) + .getRegex(); +const reflinkSearch = edit('reflink|nolink(?!\\()', 'g') + .replace('reflink', reflink) + .replace('nolink', nolink) + .getRegex(); +/** + * Normal Inline Grammar + */ +const inlineNormal = { + _backpedal: noopTest, // only used for GFM url + anyPunctuation, + autolink, + blockSkip, + br, + code: inlineCode, + del: noopTest, + emStrongLDelim, + emStrongRDelimAst, + emStrongRDelimUnd, + escape, + link, + nolink, + punctuation, + reflink, + reflinkSearch, + tag, + text: inlineText, + url: noopTest +}; +/** + * Pedantic Inline Grammar + */ +const inlinePedantic = { + ...inlineNormal, + link: edit(/^!?\[(label)\]\((.*?)\)/) + .replace('label', _inlineLabel) + .getRegex(), + reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/) + .replace('label', _inlineLabel) + .getRegex() +}; +/** + * GFM Inline Grammar + */ +const inlineGfm = { + ...inlineNormal, + escape: edit(escape).replace('])', '~|])').getRegex(), + url: edit(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, 'i') + .replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/) + .getRegex(), + _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, + del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/, + text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\ { + return leading + ' '.repeat(tabs.length); + }); + } + let token; + let lastToken; + let cutSrc; + let lastParagraphClipped; + while (src) { + if (this.options.extensions + && this.options.extensions.block + && this.options.extensions.block.some((extTokenizer) => { + if (token = extTokenizer.call({ lexer: this }, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); + return true; + } + return false; + })) { + continue; + } + // newline + if (token = this.tokenizer.space(src)) { + src = src.substring(token.raw.length); + if (token.raw.length === 1 && tokens.length > 0) { + // if there's a single \n as a spacer, it's terminating the last line, + // so move it there so that we don't get unnecessary paragraph tags + tokens[tokens.length - 1].raw += '\n'; + } + else { + tokens.push(token); + } + continue; + } + // code + if (token = this.tokenizer.code(src)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + // An indented code block cannot interrupt a paragraph. + if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) { + lastToken.raw += '\n' + token.raw; + lastToken.text += '\n' + token.text; + this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; + } + else { + tokens.push(token); + } + continue; + } + // fences + if (token = this.tokenizer.fences(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // heading + if (token = this.tokenizer.heading(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // hr + if (token = this.tokenizer.hr(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // blockquote + if (token = this.tokenizer.blockquote(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // list + if (token = this.tokenizer.list(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // html + if (token = this.tokenizer.html(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // def + if (token = this.tokenizer.def(src)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) { + lastToken.raw += '\n' + token.raw; + lastToken.text += '\n' + token.raw; + this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; + } + else if (!this.tokens.links[token.tag]) { + this.tokens.links[token.tag] = { + href: token.href, + title: token.title + }; + } + continue; + } + // table (gfm) + if (token = this.tokenizer.table(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // lheading + if (token = this.tokenizer.lheading(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // top-level paragraph + // prevent paragraph consuming extensions by clipping 'src' to extension start + cutSrc = src; + if (this.options.extensions && this.options.extensions.startBlock) { + let startIndex = Infinity; + const tempSrc = src.slice(1); + let tempStart; + this.options.extensions.startBlock.forEach((getStartIndex) => { + tempStart = getStartIndex.call({ lexer: this }, tempSrc); + if (typeof tempStart === 'number' && tempStart >= 0) { + startIndex = Math.min(startIndex, tempStart); + } + }); + if (startIndex < Infinity && startIndex >= 0) { + cutSrc = src.substring(0, startIndex + 1); + } + } + if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) { + lastToken = tokens[tokens.length - 1]; + if (lastParagraphClipped && lastToken.type === 'paragraph') { + lastToken.raw += '\n' + token.raw; + lastToken.text += '\n' + token.text; + this.inlineQueue.pop(); + this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; + } + else { + tokens.push(token); + } + lastParagraphClipped = (cutSrc.length !== src.length); + src = src.substring(token.raw.length); + continue; + } + // text + if (token = this.tokenizer.text(src)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + if (lastToken && lastToken.type === 'text') { + lastToken.raw += '\n' + token.raw; + lastToken.text += '\n' + token.text; + this.inlineQueue.pop(); + this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text; + } + else { + tokens.push(token); + } + continue; + } + if (src) { + const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); + if (this.options.silent) { + console.error(errMsg); + break; + } + else { + throw new Error(errMsg); + } + } + } + this.state.top = true; + return tokens; + } + inline(src, tokens = []) { + this.inlineQueue.push({ src, tokens }); + return tokens; + } + /** + * Lexing/Compiling + */ + inlineTokens(src, tokens = []) { + let token, lastToken, cutSrc; + // String with links masked to avoid interference with em and strong + let maskedSrc = src; + let match; + let keepPrevChar, prevChar; + // Mask out reflinks + if (this.tokens.links) { + const links = Object.keys(this.tokens.links); + if (links.length > 0) { + while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) { + if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) { + maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex); + } + } + } + } + // Mask out other blocks + while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) { + maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex); + } + // Mask out escaped characters + while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) { + maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex); + } + while (src) { + if (!keepPrevChar) { + prevChar = ''; + } + keepPrevChar = false; + // extensions + if (this.options.extensions + && this.options.extensions.inline + && this.options.extensions.inline.some((extTokenizer) => { + if (token = extTokenizer.call({ lexer: this }, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); + return true; + } + return false; + })) { + continue; + } + // escape + if (token = this.tokenizer.escape(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // tag + if (token = this.tokenizer.tag(src)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + if (lastToken && token.type === 'text' && lastToken.type === 'text') { + lastToken.raw += token.raw; + lastToken.text += token.text; + } + else { + tokens.push(token); + } + continue; + } + // link + if (token = this.tokenizer.link(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // reflink, nolink + if (token = this.tokenizer.reflink(src, this.tokens.links)) { + src = src.substring(token.raw.length); + lastToken = tokens[tokens.length - 1]; + if (lastToken && token.type === 'text' && lastToken.type === 'text') { + lastToken.raw += token.raw; + lastToken.text += token.text; + } + else { + tokens.push(token); + } + continue; + } + // em & strong + if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // code + if (token = this.tokenizer.codespan(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // br + if (token = this.tokenizer.br(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // del (gfm) + if (token = this.tokenizer.del(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // autolink + if (token = this.tokenizer.autolink(src)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // url (gfm) + if (!this.state.inLink && (token = this.tokenizer.url(src))) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; + } + // text + // prevent inlineText consuming extensions by clipping 'src' to extension start + cutSrc = src; + if (this.options.extensions && this.options.extensions.startInline) { + let startIndex = Infinity; + const tempSrc = src.slice(1); + let tempStart; + this.options.extensions.startInline.forEach((getStartIndex) => { + tempStart = getStartIndex.call({ lexer: this }, tempSrc); + if (typeof tempStart === 'number' && tempStart >= 0) { + startIndex = Math.min(startIndex, tempStart); + } + }); + if (startIndex < Infinity && startIndex >= 0) { + cutSrc = src.substring(0, startIndex + 1); + } + } + if (token = this.tokenizer.inlineText(cutSrc)) { + src = src.substring(token.raw.length); + if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started + prevChar = token.raw.slice(-1); + } + keepPrevChar = true; + lastToken = tokens[tokens.length - 1]; + if (lastToken && lastToken.type === 'text') { + lastToken.raw += token.raw; + lastToken.text += token.text; + } + else { + tokens.push(token); + } + continue; + } + if (src) { + const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); + if (this.options.silent) { + console.error(errMsg); + break; + } + else { + throw new Error(errMsg); + } + } + } + return tokens; + } +} + +/** + * Renderer + */ +class _Renderer { + options; + constructor(options) { + this.options = options || _defaults; + } + code(code, infostring, escaped) { + const lang = (infostring || '').match(/^\S*/)?.[0]; + code = code.replace(/\n$/, '') + '\n'; + if (!lang) { + return '
    '
    +                + (escaped ? code : escape$1(code, true))
    +                + '
    \n'; + } + return '
    '
    +            + (escaped ? code : escape$1(code, true))
    +            + '
    \n'; + } + blockquote(quote) { + return `
    \n${quote}
    \n`; + } + html(html, block) { + return html; + } + heading(text, level, raw) { + // ignore IDs + return `${text}\n`; + } + hr() { + return '
    \n'; + } + list(body, ordered, start) { + const type = ordered ? 'ol' : 'ul'; + const startatt = (ordered && start !== 1) ? (' start="' + start + '"') : ''; + return '<' + type + startatt + '>\n' + body + '\n'; + } + listitem(text, task, checked) { + return `
  • ${text}
  • \n`; + } + checkbox(checked) { + return ''; + } + paragraph(text) { + return `

    ${text}

    \n`; + } + table(header, body) { + if (body) + body = `${body}`; + return '\n' + + '\n' + + header + + '\n' + + body + + '
    \n'; + } + tablerow(content) { + return `\n${content}\n`; + } + tablecell(content, flags) { + const type = flags.header ? 'th' : 'td'; + const tag = flags.align + ? `<${type} align="${flags.align}">` + : `<${type}>`; + return tag + content + `\n`; + } + /** + * span level renderer + */ + strong(text) { + return `${text}`; + } + em(text) { + return `${text}`; + } + codespan(text) { + return `${text}`; + } + br() { + return '
    '; + } + del(text) { + return `${text}`; + } + link(href, title, text) { + const cleanHref = cleanUrl(href); + if (cleanHref === null) { + return text; + } + href = cleanHref; + let out = '
    '; + return out; + } + image(href, title, text) { + const cleanHref = cleanUrl(href); + if (cleanHref === null) { + return text; + } + href = cleanHref; + let out = `${text} 0 && item.tokens[0].type === 'paragraph') { + item.tokens[0].text = checkbox + ' ' + item.tokens[0].text; + if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') { + item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text; + } + } + else { + item.tokens.unshift({ + type: 'text', + text: checkbox + ' ' + }); + } + } + else { + itemBody += checkbox + ' '; + } + } + itemBody += this.parse(item.tokens, loose); + body += this.renderer.listitem(itemBody, task, !!checked); + } + out += this.renderer.list(body, ordered, start); + continue; + } + case 'html': { + const htmlToken = token; + out += this.renderer.html(htmlToken.text, htmlToken.block); + continue; + } + case 'paragraph': { + const paragraphToken = token; + out += this.renderer.paragraph(this.parseInline(paragraphToken.tokens)); + continue; + } + case 'text': { + let textToken = token; + let body = textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text; + while (i + 1 < tokens.length && tokens[i + 1].type === 'text') { + textToken = tokens[++i]; + body += '\n' + (textToken.tokens ? this.parseInline(textToken.tokens) : textToken.text); + } + out += top ? this.renderer.paragraph(body) : body; + continue; + } + default: { + const errMsg = 'Token with "' + token.type + '" type was not found.'; + if (this.options.silent) { + console.error(errMsg); + return ''; + } + else { + throw new Error(errMsg); + } + } + } + } + return out; + } + /** + * Parse Inline Tokens + */ + parseInline(tokens, renderer) { + renderer = renderer || this.renderer; + let out = ''; + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i]; + // Run any renderer extensions + if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) { + const ret = this.options.extensions.renderers[token.type].call({ parser: this }, token); + if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) { + out += ret || ''; + continue; + } + } + switch (token.type) { + case 'escape': { + const escapeToken = token; + out += renderer.text(escapeToken.text); + break; + } + case 'html': { + const tagToken = token; + out += renderer.html(tagToken.text); + break; + } + case 'link': { + const linkToken = token; + out += renderer.link(linkToken.href, linkToken.title, this.parseInline(linkToken.tokens, renderer)); + break; + } + case 'image': { + const imageToken = token; + out += renderer.image(imageToken.href, imageToken.title, imageToken.text); + break; + } + case 'strong': { + const strongToken = token; + out += renderer.strong(this.parseInline(strongToken.tokens, renderer)); + break; + } + case 'em': { + const emToken = token; + out += renderer.em(this.parseInline(emToken.tokens, renderer)); + break; + } + case 'codespan': { + const codespanToken = token; + out += renderer.codespan(codespanToken.text); + break; + } + case 'br': { + out += renderer.br(); + break; + } + case 'del': { + const delToken = token; + out += renderer.del(this.parseInline(delToken.tokens, renderer)); + break; + } + case 'text': { + const textToken = token; + out += renderer.text(textToken.text); + break; + } + default: { + const errMsg = 'Token with "' + token.type + '" type was not found.'; + if (this.options.silent) { + console.error(errMsg); + return ''; + } + else { + throw new Error(errMsg); + } + } + } + } + return out; + } +} + +class _Hooks { + options; + constructor(options) { + this.options = options || _defaults; + } + static passThroughHooks = new Set([ + 'preprocess', + 'postprocess', + 'processAllTokens' + ]); + /** + * Process markdown before marked + */ + preprocess(markdown) { + return markdown; + } + /** + * Process HTML after marked is finished + */ + postprocess(html) { + return html; + } + /** + * Process all tokens before walk tokens + */ + processAllTokens(tokens) { + return tokens; + } +} + +class Marked { + defaults = _getDefaults(); + options = this.setOptions; + parse = this.#parseMarkdown(_Lexer.lex, _Parser.parse); + parseInline = this.#parseMarkdown(_Lexer.lexInline, _Parser.parseInline); + Parser = _Parser; + Renderer = _Renderer; + TextRenderer = _TextRenderer; + Lexer = _Lexer; + Tokenizer = _Tokenizer; + Hooks = _Hooks; + constructor(...args) { + this.use(...args); + } + /** + * Run callback for every token + */ + walkTokens(tokens, callback) { + let values = []; + for (const token of tokens) { + values = values.concat(callback.call(this, token)); + switch (token.type) { + case 'table': { + const tableToken = token; + for (const cell of tableToken.header) { + values = values.concat(this.walkTokens(cell.tokens, callback)); + } + for (const row of tableToken.rows) { + for (const cell of row) { + values = values.concat(this.walkTokens(cell.tokens, callback)); + } + } + break; + } + case 'list': { + const listToken = token; + values = values.concat(this.walkTokens(listToken.items, callback)); + break; + } + default: { + const genericToken = token; + if (this.defaults.extensions?.childTokens?.[genericToken.type]) { + this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => { + const tokens = genericToken[childTokens].flat(Infinity); + values = values.concat(this.walkTokens(tokens, callback)); + }); + } + else if (genericToken.tokens) { + values = values.concat(this.walkTokens(genericToken.tokens, callback)); + } + } + } + } + return values; + } + use(...args) { + const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} }; + args.forEach((pack) => { + // copy options to new object + const opts = { ...pack }; + // set async to true if it was set to true before + opts.async = this.defaults.async || opts.async || false; + // ==-- Parse "addon" extensions --== // + if (pack.extensions) { + pack.extensions.forEach((ext) => { + if (!ext.name) { + throw new Error('extension name required'); + } + if ('renderer' in ext) { // Renderer extensions + const prevRenderer = extensions.renderers[ext.name]; + if (prevRenderer) { + // Replace extension with func to run new extension but fall back if false + extensions.renderers[ext.name] = function (...args) { + let ret = ext.renderer.apply(this, args); + if (ret === false) { + ret = prevRenderer.apply(this, args); + } + return ret; + }; + } + else { + extensions.renderers[ext.name] = ext.renderer; + } + } + if ('tokenizer' in ext) { // Tokenizer Extensions + if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) { + throw new Error("extension level must be 'block' or 'inline'"); + } + const extLevel = extensions[ext.level]; + if (extLevel) { + extLevel.unshift(ext.tokenizer); + } + else { + extensions[ext.level] = [ext.tokenizer]; + } + if (ext.start) { // Function to check for start of token + if (ext.level === 'block') { + if (extensions.startBlock) { + extensions.startBlock.push(ext.start); + } + else { + extensions.startBlock = [ext.start]; + } + } + else if (ext.level === 'inline') { + if (extensions.startInline) { + extensions.startInline.push(ext.start); + } + else { + extensions.startInline = [ext.start]; + } + } + } + } + if ('childTokens' in ext && ext.childTokens) { // Child tokens to be visited by walkTokens + extensions.childTokens[ext.name] = ext.childTokens; + } + }); + opts.extensions = extensions; + } + // ==-- Parse "overwrite" extensions --== // + if (pack.renderer) { + const renderer = this.defaults.renderer || new _Renderer(this.defaults); + for (const prop in pack.renderer) { + if (!(prop in renderer)) { + throw new Error(`renderer '${prop}' does not exist`); + } + if (prop === 'options') { + // ignore options property + continue; + } + const rendererProp = prop; + const rendererFunc = pack.renderer[rendererProp]; + const prevRenderer = renderer[rendererProp]; + // Replace renderer with func to run extension, but fall back if false + renderer[rendererProp] = (...args) => { + let ret = rendererFunc.apply(renderer, args); + if (ret === false) { + ret = prevRenderer.apply(renderer, args); + } + return ret || ''; + }; + } + opts.renderer = renderer; + } + if (pack.tokenizer) { + const tokenizer = this.defaults.tokenizer || new _Tokenizer(this.defaults); + for (const prop in pack.tokenizer) { + if (!(prop in tokenizer)) { + throw new Error(`tokenizer '${prop}' does not exist`); + } + if (['options', 'rules', 'lexer'].includes(prop)) { + // ignore options, rules, and lexer properties + continue; + } + const tokenizerProp = prop; + const tokenizerFunc = pack.tokenizer[tokenizerProp]; + const prevTokenizer = tokenizer[tokenizerProp]; + // Replace tokenizer with func to run extension, but fall back if false + // @ts-expect-error cannot type tokenizer function dynamically + tokenizer[tokenizerProp] = (...args) => { + let ret = tokenizerFunc.apply(tokenizer, args); + if (ret === false) { + ret = prevTokenizer.apply(tokenizer, args); + } + return ret; + }; + } + opts.tokenizer = tokenizer; + } + // ==-- Parse Hooks extensions --== // + if (pack.hooks) { + const hooks = this.defaults.hooks || new _Hooks(); + for (const prop in pack.hooks) { + if (!(prop in hooks)) { + throw new Error(`hook '${prop}' does not exist`); + } + if (prop === 'options') { + // ignore options property + continue; + } + const hooksProp = prop; + const hooksFunc = pack.hooks[hooksProp]; + const prevHook = hooks[hooksProp]; + if (_Hooks.passThroughHooks.has(prop)) { + // @ts-expect-error cannot type hook function dynamically + hooks[hooksProp] = (arg) => { + if (this.defaults.async) { + return Promise.resolve(hooksFunc.call(hooks, arg)).then(ret => { + return prevHook.call(hooks, ret); + }); + } + const ret = hooksFunc.call(hooks, arg); + return prevHook.call(hooks, ret); + }; + } + else { + // @ts-expect-error cannot type hook function dynamically + hooks[hooksProp] = (...args) => { + let ret = hooksFunc.apply(hooks, args); + if (ret === false) { + ret = prevHook.apply(hooks, args); + } + return ret; + }; + } + } + opts.hooks = hooks; + } + // ==-- Parse WalkTokens extensions --== // + if (pack.walkTokens) { + const walkTokens = this.defaults.walkTokens; + const packWalktokens = pack.walkTokens; + opts.walkTokens = function (token) { + let values = []; + values.push(packWalktokens.call(this, token)); + if (walkTokens) { + values = values.concat(walkTokens.call(this, token)); + } + return values; + }; + } + this.defaults = { ...this.defaults, ...opts }; + }); + return this; + } + setOptions(opt) { + this.defaults = { ...this.defaults, ...opt }; + return this; + } + lexer(src, options) { + return _Lexer.lex(src, options ?? this.defaults); + } + parser(tokens, options) { + return _Parser.parse(tokens, options ?? this.defaults); + } + #parseMarkdown(lexer, parser) { + return (src, options) => { + const origOpt = { ...options }; + const opt = { ...this.defaults, ...origOpt }; + // Show warning if an extension set async to true but the parse was called with async: false + if (this.defaults.async === true && origOpt.async === false) { + if (!opt.silent) { + console.warn('marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored.'); + } + opt.async = true; + } + const throwError = this.#onError(!!opt.silent, !!opt.async); + // throw error in case of non string input + if (typeof src === 'undefined' || src === null) { + return throwError(new Error('marked(): input parameter is undefined or null')); + } + if (typeof src !== 'string') { + return throwError(new Error('marked(): input parameter is of type ' + + Object.prototype.toString.call(src) + ', string expected')); + } + if (opt.hooks) { + opt.hooks.options = opt; + } + if (opt.async) { + return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src) + .then(src => lexer(src, opt)) + .then(tokens => opt.hooks ? opt.hooks.processAllTokens(tokens) : tokens) + .then(tokens => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens) + .then(tokens => parser(tokens, opt)) + .then(html => opt.hooks ? opt.hooks.postprocess(html) : html) + .catch(throwError); + } + try { + if (opt.hooks) { + src = opt.hooks.preprocess(src); + } + let tokens = lexer(src, opt); + if (opt.hooks) { + tokens = opt.hooks.processAllTokens(tokens); + } + if (opt.walkTokens) { + this.walkTokens(tokens, opt.walkTokens); + } + let html = parser(tokens, opt); + if (opt.hooks) { + html = opt.hooks.postprocess(html); + } + return html; + } + catch (e) { + return throwError(e); + } + }; + } + #onError(silent, async) { + return (e) => { + e.message += '\nPlease report this to https://github.com/markedjs/marked.'; + if (silent) { + const msg = '

    An error occurred:

    '
    +                    + escape$1(e.message + '', true)
    +                    + '
    '; + if (async) { + return Promise.resolve(msg); + } + return msg; + } + if (async) { + return Promise.reject(e); + } + throw e; + }; + } +} + +const markedInstance = new Marked(); +function marked(src, opt) { + return markedInstance.parse(src, opt); +} +/** + * Sets the default options. + * + * @param options Hash of options + */ +marked.options = + marked.setOptions = function (options) { + markedInstance.setOptions(options); + marked.defaults = markedInstance.defaults; + changeDefaults(marked.defaults); + return marked; + }; +/** + * Gets the original marked default options. + */ +marked.getDefaults = _getDefaults; +marked.defaults = _defaults; +/** + * Use Extension + */ +marked.use = function (...args) { + markedInstance.use(...args); + marked.defaults = markedInstance.defaults; + changeDefaults(marked.defaults); + return marked; +}; +/** + * Run callback for every token + */ +marked.walkTokens = function (tokens, callback) { + return markedInstance.walkTokens(tokens, callback); +}; +/** + * Compiles markdown to HTML without enclosing `p` tag. + * + * @param src String of markdown source to be compiled + * @param options Hash of options + * @return String of compiled HTML + */ +marked.parseInline = markedInstance.parseInline; +/** + * Expose + */ +marked.Parser = _Parser; +marked.parser = _Parser.parse; +marked.Renderer = _Renderer; +marked.TextRenderer = _TextRenderer; +marked.Lexer = _Lexer; +marked.lexer = _Lexer.lex; +marked.Tokenizer = _Tokenizer; +marked.Hooks = _Hooks; +marked.parse = marked; +const options = marked.options; +const setOptions = marked.setOptions; +const use = marked.use; +const walkTokens = marked.walkTokens; +const parseInline = marked.parseInline; +const parse = marked; +const parser = _Parser.parse; +const lexer = _Lexer.lex; + +export { _Hooks as Hooks, _Lexer as Lexer, Marked, _Parser as Parser, _Renderer as Renderer, _TextRenderer as TextRenderer, _Tokenizer as Tokenizer, _defaults as defaults, _getDefaults as getDefaults, lexer, marked, options, parse, parseInline, parser, setOptions, use, walkTokens }; +//# sourceMappingURL=marked.esm.js.map diff --git a/MyApp/wwwroot/mjs/app.mjs b/MyApp/wwwroot/mjs/app.mjs index 9a271c5..8986848 100644 --- a/MyApp/wwwroot/mjs/app.mjs +++ b/MyApp/wwwroot/mjs/app.mjs @@ -19,6 +19,38 @@ export function assetsUrl(path) { return globalThis.assetsUrl(path) } +// keep in sync with AppConfig +const m = (model,level) => ({ model, level }) +export const ModelUsers = { + // discontinued + 'deepseek-coder': m('deepseek-coder:6.7b',0), + 'gemma-2b': m('gemma:2b',0), + 'qwen-4b': m('qwen:4b',0), + 'deepseek-coder-33b': m('deepseek-coder:33b',100), + + 'phi': m('phi3',0), + 'codellama': m('codellama',0), + 'mistral': m('mistral',0), + 'gemma': m('gemma',0), + 'llama3-8b': m('llama3:8b',0), + 'gemini-pro': m('gemini-pro',3), + 'mixtral': m('mixtral',5), + 'gpt3.5-turbo': m('gpt-3.5-turbo',10), + 'claude3-haiku': m('claude-3-haiku',25), + 'llama3-70b': m('llama3:70b',50), + 'command-r': m('command-r',100), + 'wizardlm': m('wizardlm2:8x22b',175), + 'claude3-sonnet': m('claude-3-sonnet',250), + 'command-r-plus': m('command-r-plus',350), + 'gpt4-turbo': m('gpt-4-turbo',450), + 'claude3-opus': m('claude-3-opus',600), +} +Object.keys(ModelUsers).forEach(userName => { ModelUsers[userName].userName = userName }) +export function isModelUser(userName) { return !!ModelUsers[userName] } +export function modelUser(userName) { return ModelUsers[userName] } +export function modelUserModel(userName) { return ModelUsers[userName]?.model } +export function modelUserLevel(userName) { return ModelUsers[userName]?.level } + export const alreadyMounted = el => el.__vue_app__ const mockArgs = { attrs:{}, slots:{}, emit:() => {}, expose: () => {} } diff --git a/MyApp/wwwroot/mjs/dtos.mjs b/MyApp/wwwroot/mjs/dtos.mjs index 5adf9fb..ebe6085 100644 --- a/MyApp/wwwroot/mjs/dtos.mjs +++ b/MyApp/wwwroot/mjs/dtos.mjs @@ -1,6 +1,6 @@ /* Options: -Date: 2024-04-14 02:12:56 -Version: 8.22 +Date: 2024-05-04 22:38:15 +Version: 8.23 Tip: To override a DTO option, remove "//" prefix before updating BaseUrl: https://localhost:5001 @@ -13,37 +13,244 @@ BaseUrl: https://localhost:5001 */ "use strict"; -/** @typedef {'Unknown'|'StackOverflow'|'Discourse'|'Reddit'|'GitHubDiscussions'} */ -export var ImportSite; -(function (ImportSite) { - ImportSite["Unknown"] = "Unknown" - ImportSite["StackOverflow"] = "StackOverflow" - ImportSite["Discourse"] = "Discourse" - ImportSite["Reddit"] = "Reddit" - ImportSite["GitHubDiscussions"] = "GitHubDiscussions" -})(ImportSite || (ImportSite = {})); -/** @typedef {'Unknown'|'Spam'|'Offensive'|'Duplicate'|'NotRelevant'|'LowQuality'|'Plagiarized'|'NeedsReview'} */ -export var FlagType; -(function (FlagType) { - FlagType["Unknown"] = "Unknown" - FlagType["Spam"] = "Spam" - FlagType["Offensive"] = "Offensive" - FlagType["Duplicate"] = "Duplicate" - FlagType["NotRelevant"] = "NotRelevant" - FlagType["LowQuality"] = "LowQuality" - FlagType["Plagiarized"] = "Plagiarized" - FlagType["NeedsReview"] = "NeedsReview" -})(FlagType || (FlagType = {})); -export class RegenerateMeta { - /** @param {{ifPostModified?:number,forPost?:number}} [init] */ +export class MailTo { + /** @param {{email?:string,name?:string}} [init] */ constructor(init) { Object.assign(this, init) } + /** @type {string} */ + email; + /** @type {string} */ + name; +} +export class EmailMessage { + /** @param {{to?:MailTo[],cc?:MailTo[],bcc?:MailTo[],from?:MailTo,subject?:string,body?:string,bodyHtml?:string,bodyText?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {MailTo[]} */ + to; + /** @type {MailTo[]} */ + cc; + /** @type {MailTo[]} */ + bcc; + /** @type {?MailTo} */ + from; + /** @type {string} */ + subject; + /** @type {?string} */ + body; + /** @type {?string} */ + bodyHtml; + /** @type {?string} */ + bodyText; +} +export class ResponseError { + /** @param {{errorCode?:string,fieldName?:string,message?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + errorCode; + /** @type {string} */ + fieldName; + /** @type {string} */ + message; + /** @type {{ [index: string]: string; }} */ + meta; +} +export class ResponseStatus { + /** @param {{errorCode?:string,message?:string,stackTrace?:string,errors?:ResponseError[],meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + errorCode; + /** @type {string} */ + message; + /** @type {string} */ + stackTrace; + /** @type {ResponseError[]} */ + errors; + /** @type {{ [index: string]: string; }} */ + meta; +} +export class MailMessage { + /** @param {{id?:number,email?:string,layout?:string,template?:string,renderer?:string,rendererArgs?:{ [index: string]: Object; },message?:EmailMessage,draft?:boolean,externalRef?:string,createdDate?:string,startedDate?:string,completedDate?:string,error?:ResponseStatus}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {string} */ + email; + /** @type {?string} */ + layout; + /** @type {?string} */ + template; + /** @type {string} */ + renderer; + /** @type {{ [index: string]: Object; }} */ + rendererArgs; + /** @type {EmailMessage} */ + message; + /** @type {boolean} */ + draft; + /** @type {string} */ + externalRef; + /** @type {string} */ + createdDate; + /** @type {?string} */ + startedDate; + /** @type {?string} */ + completedDate; + /** @type {?ResponseStatus} */ + error; +} +export class SendMailMessages { + /** @param {{ids?:number[],messages?:MailMessage[]}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {?number[]} */ + ids; + /** @type {?MailMessage[]} */ + messages; +} +export class CreateEmailBase { + /** @param {{email?:string,firstName?:string,lastName?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + email; + /** @type {string} */ + firstName; + /** @type {string} */ + lastName; +} +/** @typedef {'Unknown'|'UI'|'Website'|'System'|'Migration'} */ +export var Source; +(function (Source) { + Source["Unknown"] = "Unknown" + Source["UI"] = "UI" + Source["Website"] = "Website" + Source["System"] = "System" + Source["Migration"] = "Migration" +})(Source || (Source = {})); +/** @typedef {number} */ +export var MailingList; +(function (MailingList) { + MailingList[MailingList["None"] = 0] = "None" + MailingList[MailingList["TestGroup"] = 1] = "TestGroup" + MailingList[MailingList["MonthlyNewsletter"] = 2] = "MonthlyNewsletter" + MailingList[MailingList["BlogPostReleases"] = 4] = "BlogPostReleases" + MailingList[MailingList["VideoReleases"] = 8] = "VideoReleases" + MailingList[MailingList["ProductReleases"] = 16] = "ProductReleases" + MailingList[MailingList["YearlyUpdates"] = 32] = "YearlyUpdates" +})(MailingList || (MailingList = {})); +export class Contact { + /** @param {{id?:number,email?:string,firstName?:string,lastName?:string,source?:Source,mailingLists?:MailingList,token?:string,emailLower?:string,nameLower?:string,externalRef?:string,appUserId?:number,createdDate?:string,verifiedDate?:string,deletedDate?:string,unsubscribedDate?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {string} */ + email; + /** @type {string} */ + firstName; + /** @type {?string} */ + lastName; + /** @type {Source} */ + source; + /** @type {MailingList} */ + mailingLists; + /** @type {string} */ + token; + /** @type {string} */ + emailLower; + /** @type {string} */ + nameLower; + /** @type {string} */ + externalRef; /** @type {?number} */ - ifPostModified; - /** @type {?number} */ - forPost; + appUserId; + /** @type {string} */ + createdDate; + /** @type {?string} */ + verifiedDate; + /** @type {?string} */ + deletedDate; + /** @type {?string} */ + unsubscribedDate; +} +export class ChoiceMessage { + /** @param {{content?:string,tool_calls?:ToolCall[],role?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** + * @type {string} + * @description The contents of the message. */ + content; + /** + * @type {ToolCall[]} + * @description The tool calls generated by the model, such as function calls. */ + tool_calls; + /** + * @type {string} + * @description The role of the author of this message. */ + role; +} +export class Choice { + /** @param {{finish_reason?:string,index?:number,message?:ChoiceMessage}} [init] */ + constructor(init) { Object.assign(this, init) } + /** + * @type {string} + * @description The reason the model stopped generating tokens. This will be stop if the model hit a natural stop point or a provided stop sequence, length if the maximum number of tokens specified in the request was reached, content_filter if content was omitted due to a flag from our content filters, tool_calls if the model called a tool */ + finish_reason; + /** + * @type {number} + * @description The index of the choice in the list of choices. */ + index; + /** + * @type {ChoiceMessage} + * @description A chat completion message generated by the model. */ + message; +} +export class OpenAiUsage { + /** @param {{completion_tokens?:number,prompt_tokens?:number,total_tokens?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** + * @type {number} + * @description Number of tokens in the generated completion. */ + completion_tokens; + /** + * @type {number} + * @description Number of tokens in the prompt. */ + prompt_tokens; + /** + * @type {number} + * @description Total number of tokens used in the request (prompt + completion). */ + total_tokens; +} +export class OpenAiChatResponse { + /** @param {{id?:string,choices?:Choice[],created?:number,model?:string,system_fingerprint?:string,object?:string,usage?:OpenAiUsage}} [init] */ + constructor(init) { Object.assign(this, init) } + /** + * @type {string} + * @description A unique identifier for the chat completion. */ + id; + /** + * @type {Choice[]} + * @description A list of chat completion choices. Can be more than one if n is greater than 1. */ + choices; + /** + * @type {number} + * @description The Unix timestamp (in seconds) of when the chat completion was created. */ + created; + /** + * @type {string} + * @description The model used for the chat completion. */ + model; + /** + * @type {string} + * @description This fingerprint represents the backend configuration that the model runs with. */ + system_fingerprint; + /** + * @type {string} + * @description The object type, which is always chat.completion. */ + object; + /** + * @type {OpenAiUsage} + * @description Usage statistics for the completion request. */ + usage; } export class Post { - /** @param {{id?:number,postTypeId?:number,acceptedAnswerId?:number,parentId?:number,score?:number,viewCount?:number,title?:string,favoriteCount?:number,creationDate?:string,lastActivityDate?:string,lastEditDate?:string,lastEditorUserId?:number,ownerUserId?:number,tags?:string[],slug?:string,summary?:string,rankDate?:string,answerCount?:number,createdBy?:string,modifiedBy?:string,refId?:string,body?:string,modifiedReason?:string,lockedDate?:string,lockedReason?:string}} [init] */ + /** @param {{id?:number,postTypeId?:number,acceptedAnswerId?:number,parentId?:number,score?:number,viewCount?:number,title?:string,favoriteCount?:number,creationDate?:string,lastActivityDate?:string,lastEditDate?:string,lastEditorUserId?:number,ownerUserId?:number,tags?:string[],slug?:string,summary?:string,rankDate?:string,answerCount?:number,createdBy?:string,modifiedBy?:string,body?:string,modifiedReason?:string,lockedDate?:string,lockedReason?:string,refId?:string,refUrn?:string,meta?:{ [index: string]: string; }}} [init] */ constructor(init) { Object.assign(this, init) } /** @type {number} */ id; @@ -86,8 +293,6 @@ export class Post { /** @type {?string} */ modifiedBy; /** @type {?string} */ - refId; - /** @type {?string} */ body; /** @type {?string} */ modifiedReason; @@ -95,56 +300,28 @@ export class Post { lockedDate; /** @type {?string} */ lockedReason; -} -export class StatTotals { - /** @param {{id?:string,postId?:number,createdBy?:string,favoriteCount?:number,viewCount?:number,upVotes?:number,downVotes?:number,startingUpVotes?:number}} [init] */ - constructor(init) { Object.assign(this, init) } - /** @type {string} */ - id; - /** @type {number} */ - postId; /** @type {?string} */ - createdBy; - /** @type {number} */ - favoriteCount; - /** @type {number} */ - viewCount; - /** @type {number} */ - upVotes; - /** @type {number} */ - downVotes; - /** @type {number} */ - startingUpVotes; + refId; + /** @type {?string} */ + refUrn; + /** @type {?{ [index: string]: string; }} */ + meta; } -export class Meta { - /** @param {{id?:number,modelVotes?:{ [index: string]: number; },comments?:{ [index: string]: Comment[]; },statTotals?:StatTotals[],modifiedDate?:string}} [init] */ +export class CreateAnswerTasks { + /** @param {{post?:Post,modelUsers?:string[]}} [init] */ constructor(init) { Object.assign(this, init) } - /** @type {number} */ - id; - /** @type {{ [index: string]: number; }} */ - modelVotes; - /** @type {{ [index: string]: Comment[]; }} */ - comments; - /** @type {StatTotals[]} */ - statTotals; - /** @type {string} */ - modifiedDate; + /** @type {Post} */ + post; + /** @type {string[]} */ + modelUsers; } -export class ChoiceMessage { - /** @param {{role?:string,content?:string}} [init] */ +export class CreateRankAnswerTask { + /** @param {{answerId?:string,userId?:string}} [init] */ constructor(init) { Object.assign(this, init) } /** @type {string} */ - role; + answerId; /** @type {string} */ - content; -} -export class Choice { - /** @param {{index?:number,message?:ChoiceMessage}} [init] */ - constructor(init) { Object.assign(this, init) } - /** @type {number} */ - index; - /** @type {ChoiceMessage} */ - message; + userId; } export class Comment { /** @param {{body?:string,created?:number,createdBy?:string,upVotes?:number,reports?:number}} [init] */ @@ -160,43 +337,50 @@ export class Comment { /** @type {?number} */ reports; } -export class Answer { - /** @param {{id?:string,object?:string,created?:number,model?:string,choices?:Choice[],usage?:{ [index: string]: number; },temperature?:number,comments?:Comment[]}} [init] */ +export class CreateAnswerCommentTask { + /** @param {{model?:string,question?:Post,answer?:Post,userId?:string,userName?:string,comments?:Comment[]}} [init] */ constructor(init) { Object.assign(this, init) } /** @type {string} */ - id; + model; + /** @type {Post} */ + question; + /** @type {Post} */ + answer; /** @type {string} */ - object; - /** @type {number} */ - created; + userId; /** @type {string} */ - model; - /** @type {Choice[]} */ - choices; - /** @type {{ [index: string]: number; }} */ - usage; - /** @type {number} */ - temperature; + userName; /** @type {Comment[]} */ comments; } -export class QuestionAndAnswers { - /** @param {{id?:number,post?:Post,meta?:Meta,answers?:Answer[],viewCount?:number,questionScore?:number,questionComments?:Comment[]}} [init] */ +/** @typedef {'Unknown'|'StackOverflow'|'Discourse'|'Reddit'|'GitHubDiscussions'} */ +export var ImportSite; +(function (ImportSite) { + ImportSite["Unknown"] = "Unknown" + ImportSite["StackOverflow"] = "StackOverflow" + ImportSite["Discourse"] = "Discourse" + ImportSite["Reddit"] = "Reddit" + ImportSite["GitHubDiscussions"] = "GitHubDiscussions" +})(ImportSite || (ImportSite = {})); +/** @typedef {'Unknown'|'Spam'|'Offensive'|'Duplicate'|'NotRelevant'|'LowQuality'|'Plagiarized'|'NeedsReview'} */ +export var FlagType; +(function (FlagType) { + FlagType["Unknown"] = "Unknown" + FlagType["Spam"] = "Spam" + FlagType["Offensive"] = "Offensive" + FlagType["Duplicate"] = "Duplicate" + FlagType["NotRelevant"] = "NotRelevant" + FlagType["LowQuality"] = "LowQuality" + FlagType["Plagiarized"] = "Plagiarized" + FlagType["NeedsReview"] = "NeedsReview" +})(FlagType || (FlagType = {})); +export class RegenerateMeta { + /** @param {{ifPostModified?:number,forPost?:number}} [init] */ constructor(init) { Object.assign(this, init) } - /** @type {number} */ - id; - /** @type {Post} */ - post; - /** @type {?Meta} */ - meta; - /** @type {Answer[]} */ - answers; - /** @type {number} */ - viewCount; - /** @type {number} */ - questionScore; - /** @type {Comment[]} */ - questionComments; + /** @type {?number} */ + ifPostModified; + /** @type {?number} */ + forPost; } export class RenderHome { /** @param {{tab?:string,posts?:Post[]}} [init] */ @@ -229,39 +413,123 @@ export class QueryDb extends QueryBase { /** @param {{skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ constructor(init) { super(init); Object.assign(this, init) } } -export class PageStats { - /** @param {{label?:string,total?:number}} [init] */ +/** @typedef {'Invalid'|'AcceptAll'|'Unknown'|'Disposable'} */ +export var InvalidEmailStatus; +(function (InvalidEmailStatus) { + InvalidEmailStatus["Invalid"] = "Invalid" + InvalidEmailStatus["AcceptAll"] = "AcceptAll" + InvalidEmailStatus["Unknown"] = "Unknown" + InvalidEmailStatus["Disposable"] = "Disposable" +})(InvalidEmailStatus || (InvalidEmailStatus = {})); +export class InvalidEmail { + /** @param {{id?:number,email?:string,emailLower?:string,status?:InvalidEmailStatus}} [init] */ constructor(init) { Object.assign(this, init) } - /** @type {string} */ - label; /** @type {number} */ - total; + id; + /** @type {string} */ + email; + /** @type {string} */ + emailLower; + /** @type {InvalidEmailStatus} */ + status; } -export class ResponseError { - /** @param {{errorCode?:string,fieldName?:string,message?:string,meta?:{ [index: string]: string; }}} [init] */ +export class ArchiveMessage extends MailMessage { + /** @param {{id?:number,email?:string,layout?:string,template?:string,renderer?:string,rendererArgs?:{ [index: string]: Object; },message?:EmailMessage,draft?:boolean,externalRef?:string,createdDate?:string,startedDate?:string,completedDate?:string,error?:ResponseStatus}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } +} +export class MailRun { + /** @param {{id?:number,mailingList?:MailingList,generator?:string,generatorArgs?:{ [index: string]: Object; },layout?:string,template?:string,externalRef?:string,createdDate?:string,generatedDate?:string,sentDate?:string,completedDate?:string,emailsCount?:number}} [init] */ constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {MailingList} */ + mailingList; /** @type {string} */ - errorCode; + generator; + /** @type {{ [index: string]: Object; }} */ + generatorArgs; /** @type {string} */ - fieldName; + layout; + /** @type {string} */ + template; + /** @type {string} */ + externalRef; + /** @type {string} */ + createdDate; + /** @type {?string} */ + generatedDate; + /** @type {?string} */ + sentDate; + /** @type {?string} */ + completedDate; + /** @type {number} */ + emailsCount; +} +export class ArchiveRun extends MailRun { + /** @param {{id?:number,mailingList?:MailingList,generator?:string,generatorArgs?:{ [index: string]: Object; },layout?:string,template?:string,externalRef?:string,createdDate?:string,generatedDate?:string,sentDate?:string,completedDate?:string,emailsCount?:number}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } +} +export class ArchiveMessageRun { + /** @param {{id?:number,mailRunId?:number,contactId?:number,renderer?:string,rendererArgs?:{ [index: string]: Object; },externalRef?:string,message?:EmailMessage,createdDate?:string,startedDate?:string,completedDate?:string,error?:ResponseStatus}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {number} */ + mailRunId; + /** @type {number} */ + contactId; + /** @type {string} */ + renderer; + /** @type {{ [index: string]: Object; }} */ + rendererArgs; /** @type {string} */ + externalRef; + /** @type {EmailMessage} */ message; - /** @type {{ [index: string]: string; }} */ - meta; + /** @type {string} */ + createdDate; + /** @type {?string} */ + startedDate; + /** @type {?string} */ + completedDate; + /** @type {?ResponseStatus} */ + error; } -export class ResponseStatus { - /** @param {{errorCode?:string,message?:string,stackTrace?:string,errors?:ResponseError[],meta?:{ [index: string]: string; }}} [init] */ +export class MailMessageRun { + /** @param {{id?:number,mailRunId?:number,contactId?:number,contact?:Contact,renderer?:string,rendererArgs?:{ [index: string]: Object; },externalRef?:string,message?:EmailMessage,createdDate?:string,startedDate?:string,completedDate?:string,error?:ResponseStatus}} [init] */ constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {number} */ + mailRunId; + /** @type {number} */ + contactId; + /** @type {Contact} */ + contact; /** @type {string} */ - errorCode; + renderer; + /** @type {{ [index: string]: Object; }} */ + rendererArgs; /** @type {string} */ + externalRef; + /** @type {EmailMessage} */ message; /** @type {string} */ - stackTrace; - /** @type {ResponseError[]} */ - errors; - /** @type {{ [index: string]: string; }} */ - meta; + createdDate; + /** @type {?string} */ + startedDate; + /** @type {?string} */ + completedDate; + /** @type {?ResponseStatus} */ + error; +} +export class PageStats { + /** @param {{label?:string,total?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + label; + /** @type {number} */ + total; } export class PostJob { /** @param {{id?:number,postId?:number,model?:string,title?:string,createdBy?:string,createdDate?:string,startedDate?:string,worker?:string,workerIp?:string,completedDate?:string,error?:string,retryCount?:number}} [init] */ @@ -327,6 +595,28 @@ export class ModelWinRate { /** @type {number} */ numberOfQuestions; } +export class StatTotals { + /** @param {{id?:string,postId?:number,createdBy?:string,favoriteCount?:number,viewCount?:number,upVotes?:number,downVotes?:number,startingUpVotes?:number,lastUpdated?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + id; + /** @type {number} */ + postId; + /** @type {?string} */ + createdBy; + /** @type {number} */ + favoriteCount; + /** @type {number} */ + viewCount; + /** @type {number} */ + upVotes; + /** @type {number} */ + downVotes; + /** @type {number} */ + startingUpVotes; + /** @type {?string} */ + lastUpdated; +} /** @typedef {'Unknown'|'NewComment'|'NewAnswer'|'QuestionMention'|'AnswerMention'|'CommentMention'} */ export var NotificationType; (function (NotificationType) { @@ -400,6 +690,80 @@ export class Achievement { /** @type {string} */ createdDate; } +export class ToolCall { + /** @param {{id?:string,type?:string,function?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** + * @type {string} + * @description The ID of the tool call. */ + id; + /** + * @type {string} + * @description The type of the tool. Currently, only `function` is supported. */ + type; + /** + * @type {string} + * @description The function that the model called. */ + function; +} +export class FindContactResponse { + /** @param {{result?:Contact,responseStatus?:ResponseStatus}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {Contact} */ + result; + /** @type {ResponseStatus} */ + responseStatus; +} +export class ViewMailRunInfoResponse { + /** @param {{messagesSent?:number,totalMessages?:number,timeTaken?:string,responseStatus?:ResponseStatus}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + messagesSent; + /** @type {number} */ + totalMessages; + /** @type {string} */ + timeTaken; + /** @type {ResponseStatus} */ + responseStatus; +} +export class ViewAppDataResponse { + /** @param {{websiteBaseUrl?:string,baseUrl?:string,vars?:{ [index: string]: { [index:string]: string; }; },bannedUserIds?:number[],responseStatus?:ResponseStatus}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + websiteBaseUrl; + /** @type {string} */ + baseUrl; + /** @type {{ [index: string]: { [index:string]: string; }; }} */ + vars; + /** @type {number[]} */ + bannedUserIds; + /** @type {ResponseStatus} */ + responseStatus; +} +export class ViewAppStatsResponse { + /** @param {{totals?:{ [index: string]: number; },before30DayTotals?:{ [index: string]: number; },last30DayTotals?:{ [index: string]: number; },archivedTotals?:{ [index: string]: number; },responseStatus?:ResponseStatus}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {{ [index: string]: number; }} */ + totals; + /** @type {{ [index: string]: number; }} */ + before30DayTotals; + /** @type {{ [index: string]: number; }} */ + last30DayTotals; + /** @type {{ [index: string]: number; }} */ + archivedTotals; + /** @type {ResponseStatus} */ + responseStatus; +} +export class ArchiveMailResponse { + /** @param {{archivedMessageIds?:number[],archivedMailRunIds?:number[],responseStatus?:ResponseStatus}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number[]} */ + archivedMessageIds; + /** @type {number[]} */ + archivedMailRunIds; + /** @type {ResponseStatus} */ + responseStatus; +} export class HelloResponse { /** @param {{result?:string}} [init] */ constructor(init) { Object.assign(this, init) } @@ -422,6 +786,52 @@ export class StringResponse { /** @type {ResponseStatus} */ responseStatus; } +export class Meta { + /** @param {{id?:number,modelVotes?:{ [index: string]: number; },modelReasons?:{ [index: string]: string; },gradedBy?:{ [index: string]: string; },comments?:{ [index: string]: Comment[]; },statTotals?:StatTotals[],modifiedDate?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {{ [index: string]: number; }} */ + modelVotes; + /** @type {{ [index: string]: string; }} */ + modelReasons; + /** @type {{ [index: string]: string; }} */ + gradedBy; + /** @type {{ [index: string]: Comment[]; }} */ + comments; + /** @type {StatTotals[]} */ + statTotals; + /** @type {string} */ + modifiedDate; +} +export class QuestionAndAnswers { + /** @param {{id?:number,post?:Post,meta?:Meta,answers?:Post[],viewCount?:number,questionScore?:number,questionComments?:Comment[]}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {Post} */ + post; + /** @type {?Meta} */ + meta; + /** @type {Post[]} */ + answers; + /** @type {number} */ + viewCount; + /** @type {number} */ + questionScore; + /** @type {Comment[]} */ + questionComments; +} +export class SearchPostsResponse { + /** @param {{total?:number,results?:Post[],responseStatus?:ResponseStatus}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + total; + /** @type {Post[]} */ + results; + /** @type {?ResponseStatus} */ + responseStatus; +} export class ViewModelQueuesResponse { /** @param {{jobs?:PostJob[],responseStatus?:ResponseStatus}} [init] */ constructor(init) { Object.assign(this, init) } @@ -526,14 +936,6 @@ export class GetAnswerResponse { /** @type {Post} */ result; } -export class IdResponse { - /** @param {{id?:string,responseStatus?:ResponseStatus}} [init] */ - constructor(init) { Object.assign(this, init) } - /** @type {string} */ - id; - /** @type {ResponseStatus} */ - responseStatus; -} export class CommentsResponse { /** @param {{comments?:Comment[],responseStatus?:ResponseStatus}} [init] */ constructor(init) { Object.assign(this, init) } @@ -551,7 +953,7 @@ export class GetUserReputationsResponse { responseStatus; } export class AskQuestion { - /** @param {{title?:string,body?:string,tags?:string[],refId?:string}} [init] */ + /** @param {{title?:string,body?:string,tags?:string[],refId?:string,refUrn?:string}} [init] */ constructor(init) { Object.assign(this, init) } /** @type {string} */ title; @@ -561,6 +963,8 @@ export class AskQuestion { tags; /** @type {?string} */ refId; + /** @type {?string} */ + refUrn; getTypeName() { return 'AskQuestion' } getMethod() { return 'POST' } createResponse() { return new AskQuestionResponse() } @@ -580,10 +984,12 @@ export class UpdateUserProfileResponse { responseStatus; } export class UserPostDataResponse { - /** @param {{watching?:boolean,upVoteIds?:string[],downVoteIds?:string[],responseStatus?:ResponseStatus}} [init] */ + /** @param {{watching?:boolean,questionsAsked?:number,upVoteIds?:string[],downVoteIds?:string[],responseStatus?:ResponseStatus}} [init] */ constructor(init) { Object.assign(this, init) } /** @type {boolean} */ watching; + /** @type {number} */ + questionsAsked; /** @type {string[]} */ upVoteIds; /** @type {string[]} */ @@ -629,6 +1035,21 @@ export class GetWatchedTagsResponse { /** @type {?ResponseStatus} */ responseStatus; } +/** @typedef T {any} */ +export class QueryResponse { + /** @param {{offset?:number,total?:number,results?:T[],meta?:{ [index: string]: string; },responseStatus?:ResponseStatus}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + offset; + /** @type {number} */ + total; + /** @type {T[]} */ + results; + /** @type {{ [index: string]: string; }} */ + meta; + /** @type {ResponseStatus} */ + responseStatus; +} export class AuthenticateResponse { /** @param {{userId?:string,sessionId?:string,userName?:string,displayName?:string,referrerUrl?:string,bearerToken?:string,refreshToken?:string,refreshTokenExpiry?:string,profileUrl?:string,roles?:string[],permissions?:string[],responseStatus?:ResponseStatus,meta?:{ [index: string]: string; }}} [init] */ constructor(init) { Object.assign(this, init) } @@ -659,20 +1080,235 @@ export class AuthenticateResponse { /** @type {{ [index: string]: string; }} */ meta; } -/** @typedef T {any} */ -export class QueryResponse { - /** @param {{offset?:number,total?:number,results?:T[],meta?:{ [index: string]: string; },responseStatus?:ResponseStatus}} [init] */ +export class CreatorKitTasks { + /** @param {{sendMessages?:SendMailMessages}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {?SendMailMessages} */ + sendMessages; + getTypeName() { return 'CreatorKitTasks' } + getMethod() { return 'POST' } + createResponse () { }; +} +export class PreviewEmail { + /** @param {{request?:string,renderer?:string,requestArgs?:{ [index: string]: Object; }}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {?string} */ + request; + /** @type {?string} */ + renderer; + /** @type {{ [index: string]: Object; }} */ + requestArgs; + getTypeName() { return 'PreviewEmail' } + getMethod() { return 'POST' } + createResponse() { return '' } +} +export class UpdateMailMessageDraft { + /** @param {{id?:number,email?:string,renderer?:string,layout?:string,template?:string,subject?:string,body?:string,send?:boolean}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {string} */ + email; + /** @type {string} */ + renderer; + /** @type {?string} */ + layout; + /** @type {?string} */ + template; + /** @type {string} */ + subject; + /** @type {?string} */ + body; + /** @type {?boolean} */ + send; + getTypeName() { return 'UpdateMailMessageDraft' } + getMethod() { return 'POST' } + createResponse() { return new MailMessage() } +} +export class SimpleTextEmail extends CreateEmailBase { + /** @param {{subject?:string,body?:string,draft?:boolean,email?:string,firstName?:string,lastName?:string}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + /** @type {string} */ + subject; + /** @type {string} */ + body; + /** @type {?boolean} */ + draft; + getTypeName() { return 'SimpleTextEmail' } + getMethod() { return 'POST' } + createResponse() { return new MailMessage() } +} +export class CustomHtmlEmail extends CreateEmailBase { + /** @param {{layout?:string,template?:string,subject?:string,body?:string,draft?:boolean,email?:string,firstName?:string,lastName?:string}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + /** @type {string} */ + layout; + /** @type {string} */ + template; + /** @type {string} */ + subject; + /** @type {?string} */ + body; + /** @type {?boolean} */ + draft; + getTypeName() { return 'CustomHtmlEmail' } + getMethod() { return 'POST' } + createResponse() { return new MailMessage() } +} +export class SubscribeToMailingList { + /** @param {{email?:string,firstName?:string,lastName?:string,source?:Source,mailingLists?:string[]}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + email; + /** @type {string} */ + firstName; + /** @type {string} */ + lastName; + /** @type {Source} */ + source; + /** @type {?string[]} */ + mailingLists; + getTypeName() { return 'SubscribeToMailingList' } + getMethod() { return 'POST' } + createResponse() { } +} +export class CreateContact { + /** @param {{email?:string,firstName?:string,lastName?:string,source?:Source,mailingLists?:string[]}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + email; + /** @type {string} */ + firstName; + /** @type {string} */ + lastName; + /** @type {Source} */ + source; + /** @type {?string[]} */ + mailingLists; + getTypeName() { return 'CreateContact' } + getMethod() { return 'POST' } + createResponse() { return new Contact() } +} +export class AdminCreateContact { + /** @param {{email?:string,firstName?:string,lastName?:string,source?:Source,mailingLists?:string[],verifiedDate?:string,appUserId?:number,createdDate?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + email; + /** @type {string} */ + firstName; + /** @type {string} */ + lastName; + /** @type {Source} */ + source; + /** @type {string[]} */ + mailingLists; + /** @type {?string} */ + verifiedDate; + /** @type {?number} */ + appUserId; + /** @type {?string} */ + createdDate; + getTypeName() { return 'AdminCreateContact' } + getMethod() { return 'POST' } + createResponse() { return new Contact() } +} +export class UpdateContactMailingLists { + /** @param {{ref?:string,mailingLists?:string[],unsubscribeAll?:boolean}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + ref; + /** @type {string[]} */ + mailingLists; + /** @type {?boolean} */ + unsubscribeAll; + getTypeName() { return 'UpdateContactMailingLists' } + getMethod() { return 'POST' } + createResponse() { } +} +export class FindContact { + /** @param {{email?:string,ref?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {?string} */ + email; + /** @type {?string} */ + ref; + getTypeName() { return 'FindContact' } + getMethod() { return 'GET' } + createResponse() { return new FindContactResponse() } +} +export class SendMailMessage { + /** @param {{id?:number,force?:boolean}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {?boolean} */ + force; + getTypeName() { return 'SendMailMessage' } + getMethod() { return 'GET' } + createResponse() { return new MailMessage() } +} +export class SendMailMessageRun { + /** @param {{id?:number,force?:boolean}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {?boolean} */ + force; + getTypeName() { return 'SendMailMessageRun' } + getMethod() { return 'GET' } + createResponse() { return new MailMessage() } +} +export class VerifyEmailAddress { + /** @param {{externalRef?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + externalRef; + getTypeName() { return 'VerifyEmailAddress' } + getMethod() { return 'POST' } + createResponse() { } +} +export class SendMailRun { + /** @param {{id?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + getTypeName() { return 'SendMailRun' } + getMethod() { return 'POST' } + createResponse() { } +} +export class ViewMailRunInfo { + /** @param {{id?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + getTypeName() { return 'ViewMailRunInfo' } + getMethod() { return 'GET' } + createResponse() { return new ViewMailRunInfoResponse() } +} +export class ViewAppData { + constructor(init) { Object.assign(this, init) } + getTypeName() { return 'ViewAppData' } + getMethod() { return 'GET' } + createResponse() { return new ViewAppDataResponse() } +} +export class ViewAppStats { + constructor(init) { Object.assign(this, init) } + getTypeName() { return 'ViewAppStats' } + getMethod() { return 'GET' } + createResponse() { return new ViewAppStatsResponse() } +} +export class ArchiveMail { + /** @param {{messages?:boolean,mailRuns?:boolean,olderThanDays?:number}} [init] */ constructor(init) { Object.assign(this, init) } + /** @type {?boolean} */ + messages; + /** @type {?boolean} */ + mailRuns; /** @type {number} */ - offset; - /** @type {number} */ - total; - /** @type {T[]} */ - results; - /** @type {{ [index: string]: string; }} */ - meta; - /** @type {ResponseStatus} */ - responseStatus; + olderThanDays; + getTypeName() { return 'ArchiveMail' } + getMethod() { return 'POST' } + createResponse() { return new ArchiveMailResponse() } } export class Hello { /** @param {{name?:string}} [init] */ @@ -704,6 +1340,102 @@ export class Sync { getMethod() { return 'GET' } createResponse() { return new StringResponse() } } +export class GenerateMeta { + /** @param {{id?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + getTypeName() { return 'GenerateMeta' } + getMethod() { return 'GET' } + createResponse() { return new QuestionAndAnswers() } +} +export class AdminResetCommonPassword { + constructor(init) { Object.assign(this, init) } + getTypeName() { return 'AdminResetCommonPassword' } + getMethod() { return 'POST' } + createResponse () { }; +} +export class ResaveQuestionFromFile { + /** @param {{id?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + getTypeName() { return 'ResaveQuestionFromFile' } + getMethod() { return 'POST' } + createResponse() { return new Post() } +} +export class RankAnswer { + /** @param {{id?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + id; + getTypeName() { return 'RankAnswer' } + getMethod() { return 'POST' } + createResponse() { return new Post() } +} +export class CreateAnswerCallback extends OpenAiChatResponse { + /** @param {{postId?:number,userId?:string,id?:string,choices?:Choice[],created?:number,model?:string,system_fingerprint?:string,object?:string,usage?:OpenAiUsage}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + /** @type {number} */ + postId; + /** @type {string} */ + userId; + getTypeName() { return 'CreateAnswerCallback' } + getMethod() { return 'POST' } + createResponse() { } +} +export class RankAnswerCallback extends OpenAiChatResponse { + /** @param {{postId?:number,userId?:string,grader?:string,id?:string,choices?:Choice[],created?:number,model?:string,system_fingerprint?:string,object?:string,usage?:OpenAiUsage}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + /** @type {number} */ + postId; + /** @type {string} */ + userId; + /** @type {string} */ + grader; + getTypeName() { return 'RankAnswerCallback' } + getMethod() { return 'POST' } + createResponse() { } +} +export class AnswerCommentCallback extends OpenAiChatResponse { + /** @param {{answerId?:string,userId?:string,id?:string,choices?:Choice[],created?:number,model?:string,system_fingerprint?:string,object?:string,usage?:OpenAiUsage}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + /** @type {string} */ + answerId; + /** @type {string} */ + userId; + getTypeName() { return 'AnswerCommentCallback' } + getMethod() { return 'POST' } + createResponse() { } +} +export class SearchPosts { + /** @param {{q?:string,view?:string,skip?:number,take?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {?string} */ + q; + /** @type {?string} */ + view; + /** @type {?number} */ + skip; + /** @type {?number} */ + take; + getTypeName() { return 'SearchPosts' } + getMethod() { return 'GET' } + createResponse() { return new SearchPostsResponse() } +} +export class AiServerTasks { + /** @param {{createAnswerTasks?:CreateAnswerTasks,createRankAnswerTask?:CreateRankAnswerTask,createAnswerCommentTask?:CreateAnswerCommentTask}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {?CreateAnswerTasks} */ + createAnswerTasks; + /** @type {?CreateRankAnswerTask} */ + createRankAnswerTask; + /** @type {?CreateAnswerCommentTask} */ + createAnswerCommentTask; + getTypeName() { return 'AiServerTasks' } + getMethod() { return 'POST' } + createResponse () { }; +} export class DeleteCdnFilesMq { /** @param {{files?:string[]}} [init] */ constructor(init) { Object.assign(this, init) } @@ -731,6 +1463,17 @@ export class GetCdnFile { getMethod() { return 'POST' } createResponse () { }; } +export class SendNewAnswerEmail { + /** @param {{userName?:string,answerId?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + userName; + /** @type {string} */ + answerId; + getTypeName() { return 'SendNewAnswerEmail' } + getMethod() { return 'GET' } + createResponse() { return new StringResponse() } +} export class ViewModelQueues { /** @param {{models?:string[]}} [init] */ constructor(init) { Object.assign(this, init) } @@ -823,7 +1566,7 @@ export class DeleteQuestion { createResponse() { return new EmptyResponse() } } export class AnswerQuestion { - /** @param {{postId?:number,body?:string,refId?:string}} [init] */ + /** @param {{postId?:number,body?:string,refId?:string,refUrn?:string}} [init] */ constructor(init) { Object.assign(this, init) } /** @type {number} */ postId; @@ -831,6 +1574,8 @@ export class AnswerQuestion { body; /** @type {?string} */ refId; + /** @type {?string} */ + refUrn; getTypeName() { return 'AnswerQuestion' } getMethod() { return 'POST' } createResponse() { return new AnswerQuestionResponse() } @@ -883,6 +1628,15 @@ export class GetQuestionFile { getMethod() { return 'GET' } createResponse() { return '' } } +export class GetQuestionBody { + /** @param {{id?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + getTypeName() { return 'GetQuestionBody' } + getMethod() { return 'GET' } + createResponse() { return '' } +} export class GetAnswerFile { /** @param {{id?:string}} [init] */ constructor(init) { Object.assign(this, init) } @@ -910,45 +1664,6 @@ export class GetAnswerBody { getMethod() { return 'GET' } createResponse() { return '' } } -export class CreateRankingPostJob { - /** @param {{postId?:number}} [init] */ - constructor(init) { Object.assign(this, init) } - /** @type {number} */ - postId; - getTypeName() { return 'CreateRankingPostJob' } - getMethod() { return 'POST' } - createResponse() { return new EmptyResponse() } -} -export class CreateWorkerAnswer { - /** @param {{postId?:number,model?:string,json?:string,postJobId?:number}} [init] */ - constructor(init) { Object.assign(this, init) } - /** @type {number} */ - postId; - /** @type {string} */ - model; - /** @type {string} */ - json; - /** @type {?number} */ - postJobId; - getTypeName() { return 'CreateWorkerAnswer' } - getMethod() { return 'POST' } - createResponse() { return new IdResponse() } -} -export class RankAnswers { - /** @param {{postId?:number,model?:string,modelVotes?:{ [index: string]: number; },postJobId?:number}} [init] */ - constructor(init) { Object.assign(this, init) } - /** @type {number} */ - postId; - /** @type {string} */ - model; - /** @type {{ [index: string]: number; }} */ - modelVotes; - /** @type {?number} */ - postJobId; - getTypeName() { return 'RankAnswers' } - getMethod() { return 'POST' } - createResponse() { return new IdResponse() } -} export class CreateComment { /** @param {{id?:string,body?:string}} [init] */ constructor(init) { Object.assign(this, init) } @@ -1010,6 +1725,15 @@ export class UpdateUserProfile { getMethod() { return 'POST' } createResponse() { return new UpdateUserProfileResponse() } } +export class GetProfileImage { + /** @param {{path?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + path; + getTypeName() { return 'GetProfileImage' } + getMethod() { return 'GET' } + createResponse() { return new Blob() } +} export class GetUserAvatar { /** @param {{userName?:string}} [init] */ constructor(init) { Object.assign(this, init) } @@ -1190,6 +1914,232 @@ export class PreviewMarkdown { getMethod() { return 'POST' } createResponse() { return '' } } +export class QueryPosts extends QueryDb { + /** @param {{skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + getTypeName() { return 'QueryPosts' } + getMethod() { return 'GET' } + createResponse() { return new QueryResponse() } +} +export class QueryContacts extends QueryDb { + /** @param {{search?:string,skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + /** @type {?string} */ + search; + getTypeName() { return 'QueryContacts' } + getMethod() { return 'GET' } + createResponse() { return new QueryResponse() } +} +export class QueryInvalidEmails extends QueryDb { + /** @param {{skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + getTypeName() { return 'QueryInvalidEmails' } + getMethod() { return 'GET' } + createResponse() { return new QueryResponse() } +} +export class QueryMailMessages extends QueryDb { + /** @param {{skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + getTypeName() { return 'QueryMailMessages' } + getMethod() { return 'GET' } + createResponse() { return new QueryResponse() } +} +export class QueryMailRuns extends QueryDb { + /** @param {{id?:number,skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + /** @type {?number} */ + id; + getTypeName() { return 'QueryMailRuns' } + getMethod() { return 'GET' } + createResponse() { return new QueryResponse() } +} +export class QueryMailRunMessages extends QueryDb { + /** @param {{skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + getTypeName() { return 'QueryMailRunMessages' } + getMethod() { return 'GET' } + createResponse() { return new QueryResponse() } +} +export class QueryArchiveMessages extends QueryDb { + /** @param {{skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + getTypeName() { return 'QueryArchiveMessages' } + getMethod() { return 'GET' } + createResponse() { return new QueryResponse() } +} +export class QueryArchiveRuns extends QueryDb { + /** @param {{skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + getTypeName() { return 'QueryArchiveRuns' } + getMethod() { return 'GET' } + createResponse() { return new QueryResponse() } +} +export class QueryArchiveMessageRuns extends QueryDb { + /** @param {{skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ + constructor(init) { super(init); Object.assign(this, init) } + getTypeName() { return 'QueryArchiveMessageRuns' } + getMethod() { return 'GET' } + createResponse() { return new QueryResponse() } +} +export class UpdateContact { + /** @param {{id?:number,email?:string,firstName?:string,lastName?:string,source?:Source,mailingLists?:string[],externalRef?:string,appUserId?:number,createdDate?:string,verifiedDate?:string,deletedDate?:string,unsubscribedDate?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {?string} */ + email; + /** @type {?string} */ + firstName; + /** @type {?string} */ + lastName; + /** @type {?Source} */ + source; + /** @type {?string[]} */ + mailingLists; + /** @type {?string} */ + externalRef; + /** @type {?number} */ + appUserId; + /** @type {?string} */ + createdDate; + /** @type {?string} */ + verifiedDate; + /** @type {?string} */ + deletedDate; + /** @type {?string} */ + unsubscribedDate; + getTypeName() { return 'UpdateContact' } + getMethod() { return 'PATCH' } + createResponse() { return new Contact() } +} +export class DeleteContact { + /** @param {{id?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + getTypeName() { return 'DeleteContact' } + getMethod() { return 'DELETE' } + createResponse() { } +} +export class UpdateMailMessage { + /** @param {{id?:number,email?:string,layout?:string,template?:string,renderer?:string,rendererArgs?:{ [index: string]: Object; },message?:EmailMessage,completedDate?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {?string} */ + email; + /** @type {?string} */ + layout; + /** @type {?string} */ + template; + /** @type {?string} */ + renderer; + /** @type {?{ [index: string]: Object; }} */ + rendererArgs; + /** @type {?EmailMessage} */ + message; + /** @type {?string} */ + completedDate; + getTypeName() { return 'UpdateMailMessage' } + getMethod() { return 'PATCH' } + createResponse() { return new MailMessage() } +} +export class DeleteMailMessages { + /** @param {{id?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + getTypeName() { return 'DeleteMailMessages' } + getMethod() { return 'DELETE' } + createResponse() { } +} +export class CreateMailRun { + /** @param {{mailingList?:MailingList,layout?:string,template?:string,generator?:string,generatorArgs?:{ [index: string]: Object; }}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {MailingList} */ + mailingList; + /** @type {string} */ + layout; + /** @type {string} */ + template; + /** @type {string} */ + generator; + /** @type {{ [index: string]: Object; }} */ + generatorArgs; + getTypeName() { return 'CreateMailRun' } + getMethod() { return 'POST' } + createResponse() { return new MailRun() } +} +export class UpdateMailRun { + /** @param {{id?:number,mailingList?:MailingList,layout?:string,template?:string,generator?:string,generatorArgs?:{ [index: string]: Object; },createdDate?:string,generatedDate?:string,sentDate?:string,completedDate?:string,emailsCount?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {?MailingList} */ + mailingList; + /** @type {?string} */ + layout; + /** @type {?string} */ + template; + /** @type {?string} */ + generator; + /** @type {?{ [index: string]: Object; }} */ + generatorArgs; + /** @type {string} */ + createdDate; + /** @type {?string} */ + generatedDate; + /** @type {?string} */ + sentDate; + /** @type {?string} */ + completedDate; + /** @type {?number} */ + emailsCount; + getTypeName() { return 'UpdateMailRun' } + getMethod() { return 'PUT' } + createResponse() { return new MailRun() } +} +export class DeleteMailRun { + /** @param {{id?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + getTypeName() { return 'DeleteMailRun' } + getMethod() { return 'DELETE' } + createResponse() { } +} +export class UpdateMailRunMessage { + /** @param {{id?:number,mailRunId?:number,contactId?:number,renderer?:string,rendererArgs?:{ [index: string]: Object; },message?:EmailMessage,startedDate?:string,completedDate?:string}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + /** @type {number} */ + mailRunId; + /** @type {number} */ + contactId; + /** @type {string} */ + renderer; + /** @type {{ [index: string]: Object; }} */ + rendererArgs; + /** @type {?EmailMessage} */ + message; + /** @type {?string} */ + startedDate; + /** @type {?string} */ + completedDate; + getTypeName() { return 'UpdateMailRunMessage' } + getMethod() { return 'PATCH' } + createResponse() { return new MailMessageRun() } +} +export class DeleteMailRunMessage { + /** @param {{id?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {number} */ + id; + getTypeName() { return 'DeleteMailRunMessage' } + getMethod() { return 'DELETE' } + createResponse() { } +} export class Authenticate { /** @param {{provider?:string,userName?:string,password?:string,rememberMe?:boolean,accessToken?:string,accessTokenSecret?:string,returnUrl?:string,errorView?:string,meta?:{ [index: string]: string; }}} [init] */ constructor(init) { Object.assign(this, init) } @@ -1217,11 +2167,4 @@ export class Authenticate { getMethod() { return 'POST' } createResponse() { return new AuthenticateResponse() } } -export class QueryPosts extends QueryDb { - /** @param {{skip?:number,take?:number,orderBy?:string,orderByDesc?:string,include?:string,fields?:string,meta?:{ [index: string]: string; }}} [init] */ - constructor(init) { super(init); Object.assign(this, init) } - getTypeName() { return 'QueryPosts' } - getMethod() { return 'GET' } - createResponse() { return new QueryResponse() } -} diff --git a/MyApp/wwwroot/mjs/question.mjs b/MyApp/wwwroot/mjs/question.mjs index 27bb7f1..464730b 100644 --- a/MyApp/wwwroot/mjs/question.mjs +++ b/MyApp/wwwroot/mjs/question.mjs @@ -1,8 +1,9 @@ import { ref, computed, watch, watchEffect, nextTick, onMounted, onUpdated, getCurrentInstance } from "vue" import { $$, $1, on, JsonServiceClient, EventBus, toDate, humanize, leftPart, lastRightPart } from "@servicestack/client" import { useClient, useAuth, useUtils } from "@servicestack/vue" -import { mount, alreadyMounted, forceMount } from "app.mjs" +import { mount, alreadyMounted, forceMount, modelUser } from "app.mjs" import { addCopyButtonToCodeBlocks } from "./header.mjs" +import { renderMarkdown } from "markdown" import { UserPostData, PostVote, GetQuestionFile, AnswerQuestion, UpdateQuestion, PreviewMarkdown, GetAnswerBody, CreateComment, GetMeta, @@ -21,7 +22,9 @@ function highlightAll() { function getComments(id) { if (!meta) return [] - return meta.comments && meta.comments[id] || [] + const comments = meta.comments && meta.comments[id] || [] + comments.forEach(async x => x.bodyHtml = await renderMarkdown(x.body)) + return comments } const signInUrl = () => `/Account/Login?ReturnUrl=${location.pathname}` @@ -72,19 +75,19 @@ globalThis.removeComment = async function (el) { } } -let userPostVotes = {upVoteIds:[], downVoteIds:[]} -let origPostValues = {upVoteIds:[], downVoteIds:[]} +let userPostData = {questionsAsked:0, upVoteIds:[], downVoteIds:[]} +let origUserPostData = {questionsAsked:0, upVoteIds:[], downVoteIds:[]} function getValue(postVotes, refId) { return (postVotes.upVoteIds.includes(refId) ? 1 : postVotes.downVoteIds.includes(refId) ? -1 : 0) } function setValue(refId, value) { - userPostVotes.upVoteIds = userPostVotes.upVoteIds.filter(x => x !== refId) - userPostVotes.downVoteIds = userPostVotes.downVoteIds.filter(x => x !== refId) + userPostData.upVoteIds = userPostData.upVoteIds.filter(x => x !== refId) + userPostData.downVoteIds = userPostData.downVoteIds.filter(x => x !== refId) if (value === 1) { - userPostVotes.upVoteIds.push(refId) + userPostData.upVoteIds.push(refId) } if (value === -1) { - userPostVotes.downVoteIds.push(refId) + userPostData.downVoteIds.push(refId) } pageBus.publish('userPostData:load') } @@ -92,8 +95,8 @@ function setValue(refId, value) { async function updateUserData(postId) { const api = await client.api(new UserPostData({ postId })) if (api.succeeded) { - origPostValues = api.response - userPostVotes = Object.assign({}, origPostValues) + origUserPostData = api.response + userPostData = Object.assign({}, origUserPostData) pageBus.publish('userPostData:load') } } @@ -116,12 +119,12 @@ async function loadVoting(ctx) { const down = el.querySelector('.down') const score = el.querySelector('.score') - const value = getValue(userPostVotes, el.dataset.refid) + const value = getValue(userPostData, el.dataset.refid) up.classList.toggle('text-green-600',value === 1) up.innerHTML = value === 1 ? svgPaths.up.solid : svgPaths.up.empty down.classList.toggle('text-green-600',value === -1) down.innerHTML = value === -1 ? svgPaths.down.solid : svgPaths.down.empty - score.innerHTML = toHumanReadable(parseInt(score.dataset.score) + value - getValue(origPostValues, el.dataset.refid)) + score.innerHTML = toHumanReadable(parseInt(score.dataset.score) + value - getValue(origUserPostData, el.dataset.refid)) } $$('.voting').forEach(el => { @@ -135,7 +138,7 @@ async function loadVoting(ctx) { if (userName === createdBy) return - const prevValue = getValue(userPostVotes, refId) + const prevValue = getValue(userPostData, refId) setValue(refId, value) updateVote(el) @@ -158,12 +161,12 @@ async function loadVoting(ctx) { on(disableSelf(el.querySelector('.up')), { click(e) { - vote(getValue(userPostVotes, refId) === 1 ? 0 : 1) + vote(getValue(userPostData, refId) === 1 ? 0 : 1) } }) on(disableSelf(el.querySelector('.down')), { click(e) { - vote(getValue(userPostVotes, refId) === -1 ? 0 : -1) + vote(getValue(userPostData, refId) === -1 ? 0 : -1) } }) }) @@ -450,7 +453,9 @@ const Comments = {
    - Add Comment + + {{model ? 'Ask ' + model.userName : 'Add Comment'}} +
    {{15-txt.length}} characters to go @@ -459,33 +464,53 @@ const Comments = {
    -
    -
    - {{comment.upVotes}} -
    -
    `, - props:['id'], + props:['id','createdBy'], setup(props) { const { user, hasRole } = useAuth() const userName = user.value?.userName @@ -499,6 +524,7 @@ const Comments = { const input = ref() const instance = getCurrentInstance() const postId = parseInt(leftPart(props.id, '-')) + const model = computed(() => modelUser(props.createdBy)) pageBus.subscribe('meta:load', () => { console.log(`Comments: meta:load`) @@ -511,11 +537,17 @@ const Comments = { }) function hasVoted(comment) { - const to = userPostVotes.upVoteIds.includes(`${props.id}-${comment.created}`) + const to = userPostData.upVoteIds.includes(`${props.id}-${comment.created}`) console.log('hasVoted', to) return to } + function remainingToAskModel() { + const userLevel = userPostData.questionsAsked || 0 + const modelLevel = modelUser(props.createdBy).level || 0 + return modelLevel - userLevel + } + function keyDown(e) { if (e.key === 'Enter') { e.preventDefault() @@ -578,8 +610,9 @@ const Comments = { pageBus.publish('showReportDialog', `${props.id}-${comment.created}`) } - return { editing, userName, isModerator, txt, input, comments, keyDown, startEditing, - formatDate, loading, error, submit, close, removeComment, voteUp, flag, hasVoted } + return { editing, userName, isModerator, model, txt, input, comments, keyDown, startEditing, + formatDate, loading, error, submit, close, removeComment, voteUp, flag, hasVoted, + remainingToAskModel, renderMarkdown } } } @@ -596,10 +629,10 @@ const ContentFeatures = { flag
    - +
    `, - props:['bus','id'], + props:['bus','id','createdBy'], setup(props) { const { user, hasRole } = useAuth() const editing = ref(false) @@ -718,7 +751,7 @@ const EditQuestion = {
    - + `, props:['bus','id','createdBy','previewHtml'], @@ -914,7 +947,7 @@ const EditAnswer = { - + `, props:['bus','id','createdBy','previewHtml'], From 5380700c98ce533f0d6fa76ff28d894685605424 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 May 2024 10:51:51 +0800 Subject: [PATCH 26/36] Fix active models --- MyApp.ServiceInterface/Data/AppConfig.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index 344c512..682d4e6 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -40,8 +40,8 @@ public class AppConfig public static string[] DeprecatedModels = ["deepseek-coder","gemma-2b","qwen-4b","deepseek-coder-33b"]; - public static (string Model, int Questions)[] GetActiveModelsForQuestions(int level) => - ModelsForQuestions.Where(x => x.Questions == level && !DeprecatedModels.Contains(x.Model)).ToArray(); + public static (string Model, int Questions)[] GetActiveModelsForQuestions(int questionsCount) => + ModelsForQuestions.Where(x => questionsCount >= x.Questions && !DeprecatedModels.Contains(x.Model)).ToArray(); public static (string Model, int Questions)[] ModelsForQuestions = [ From 2bc50ffc061e15ddbb6e7397d52c4e93a7ac099d Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 May 2024 11:09:32 +0800 Subject: [PATCH 27/36] Add API to GetLastUpdated --- MyApp.ServiceInterface/AiServerServices.cs | 3 ++- MyApp.ServiceInterface/App/NewCommentCommand.cs | 5 +++++ .../App/SaveGradeResultCommand.cs | 2 ++ MyApp.ServiceInterface/QuestionServices.cs | 17 +++++++++++++++++ MyApp.ServiceModel/Posts.cs | 10 ++++++++++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/MyApp.ServiceInterface/AiServerServices.cs b/MyApp.ServiceInterface/AiServerServices.cs index e21def1..24eccad 100644 --- a/MyApp.ServiceInterface/AiServerServices.cs +++ b/MyApp.ServiceInterface/AiServerServices.cs @@ -35,6 +35,7 @@ public async Task Any(CreateAnswerCallback request) PostId = request.PostId, StartingUpVotes = 0, CreatedBy = modelUser.UserName, + LastUpdated = DateTime.UtcNow, } }); @@ -166,7 +167,7 @@ public async Task Any(AnswerCommentCallback request) await questions.SaveMetaAsync(postId, meta); } - private async Task AssertUserNameById(string userId) + private async Task AssertUserNameById(string userId) { var userName = appConfig.GetModelUserById(userId)?.UserName ?? await Db.ScalarAsync(Db.From().Where(x => x.Id == userId).Select(x => x.UserName)); diff --git a/MyApp.ServiceInterface/App/NewCommentCommand.cs b/MyApp.ServiceInterface/App/NewCommentCommand.cs index d81698c..7e26fb1 100644 --- a/MyApp.ServiceInterface/App/NewCommentCommand.cs +++ b/MyApp.ServiceInterface/App/NewCommentCommand.cs @@ -40,6 +40,11 @@ await db.InsertAsync(new Notification appConfig.IncrUnreadNotificationsFor(createdBy); } + await db.UpdateOnlyAsync(() => new StatTotals + { + LastUpdated = DateTime.UtcNow, + }, where: x => x.Id == request.RefId); + var userNameMentions = cleanBody.FindUserNameMentions() .Where(x => x != createdBy && x != comment.CreatedBy && appConfig.IsHuman(x)) .ToList(); diff --git a/MyApp.ServiceInterface/App/SaveGradeResultCommand.cs b/MyApp.ServiceInterface/App/SaveGradeResultCommand.cs index 6b6916f..0a4a597 100644 --- a/MyApp.ServiceInterface/App/SaveGradeResultCommand.cs +++ b/MyApp.ServiceInterface/App/SaveGradeResultCommand.cs @@ -11,10 +11,12 @@ public class SaveGradeResultCommand(IDbConnection db, IMessageProducer mq, Worke { public async Task ExecuteAsync(StatTotals request) { + var lastUpdated = request.LastUpdated ?? DateTime.UtcNow; var updatedRow = await db.UpdateOnlyAsync(() => new StatTotals { StartingUpVotes = request.StartingUpVotes, CreatedBy = request.CreatedBy, + LastUpdated = lastUpdated, }, x => x.Id == request.Id); if (updatedRow == 0) diff --git a/MyApp.ServiceInterface/QuestionServices.cs b/MyApp.ServiceInterface/QuestionServices.cs index 6bc8104..3fbe557 100644 --- a/MyApp.ServiceInterface/QuestionServices.cs +++ b/MyApp.ServiceInterface/QuestionServices.cs @@ -188,6 +188,7 @@ public async Task Any(AnswerQuestion request) PostId = postId, StartingUpVotes = 0, CreatedBy = userName, + LastUpdated = DateTime.UtcNow, } }); @@ -520,6 +521,22 @@ public async Task Any(ImportQuestion request) ?? throw new Exception("Import failed") }; } + + public async Task Any(GetLastUpdated request) + { + var lastUpdated = request.Id != null + ? await Db.ScalarAsync(Db.From().Where(x => x.Id == request.Id) + .Select(x => x.LastUpdated)) + : request.PostId != null + ? await Db.ScalarAsync(Db.From().Where(x => x.PostId == request.PostId) + .Select(x => Sql.Max(x.LastUpdated))) + : null; + + return new GetLastUpdatedResponse + { + Result = lastUpdated + }; + } } [ValidateHasRole(Roles.Moderator)] diff --git a/MyApp.ServiceModel/Posts.cs b/MyApp.ServiceModel/Posts.cs index 2d3e14d..ce0c5f6 100644 --- a/MyApp.ServiceModel/Posts.cs +++ b/MyApp.ServiceModel/Posts.cs @@ -554,3 +554,13 @@ public class ImportQuestionResponse public required AskQuestion Result { get; set; } public ResponseStatus? ResponseStatus { get; set; } } + +public class GetLastUpdated : IGet, IReturn +{ + public string? Id { get; set; } + public int? PostId { get; set; } +} +public class GetLastUpdatedResponse +{ + public DateTime? Result { get; set; } +} \ No newline at end of file From 4006346ddd4b1c3274662e656d025368c6927a48 Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 May 2024 17:20:46 +0800 Subject: [PATCH 28/36] implement waiting for AI to respond to comment --- .../CreateAnswerCommentTaskCommand.cs | 5 +- MyApp.ServiceInterface/AiServerServices.cs | 4 +- .../App/NewCommentCommand.cs | 4 +- .../App/SaveGradeResultCommand.cs | 4 +- MyApp.ServiceInterface/Data/AppConfig.cs | 15 ++++ MyApp.ServiceInterface/Data/Tasks.cs | 1 + MyApp.ServiceInterface/QuestionServices.cs | 82 +++++++++---------- MyApp.ServiceModel/OpenAi.cs | 4 + MyApp.ServiceModel/Posts.cs | 48 ++++++++++- MyApp/wwwroot/mjs/dtos.mjs | 48 +++++++++-- MyApp/wwwroot/mjs/question.mjs | 35 ++++++-- 11 files changed, 188 insertions(+), 62 deletions(-) diff --git a/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs b/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs index a0347ea..e4dc6fa 100644 --- a/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs +++ b/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs @@ -20,6 +20,8 @@ I will provide you with my original question and your initial answer attempt to public async Task ExecuteAsync(CreateAnswerCommentTask request) { var question = request.Question; + + request.AiRef ??= Guid.NewGuid().ToString("N"); var answerPrompt = $$""" @@ -61,12 +63,13 @@ public async Task ExecuteAsync(CreateAnswerCommentTask request) var client = appConfig.CreateAiServerClient(); var api = await client.ApiAsync(new CreateOpenAiChat { - RefId = Guid.NewGuid().ToString("N"), + RefId = request.AiRef, Tag = "pvq", Provider = null, ReplyTo = appConfig.BaseUrl.CombineWith("api", nameof(AnswerCommentCallback).AddQueryParams(new() { [nameof(AnswerCommentCallback.AnswerId)] = request.Answer.RefId, [nameof(AnswerCommentCallback.UserId)] = request.UserId, + [nameof(AnswerCommentCallback.AiRef)] = request.AiRef, })), Request = openAiChat }); diff --git a/MyApp.ServiceInterface/AiServerServices.cs b/MyApp.ServiceInterface/AiServerServices.cs index 24eccad..3b9e6b1 100644 --- a/MyApp.ServiceInterface/AiServerServices.cs +++ b/MyApp.ServiceInterface/AiServerServices.cs @@ -152,6 +152,7 @@ public async Task Any(AnswerCommentCallback request) Body = commentBody, Created = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), CreatedBy = modelUser.UserName, + AiRef = request.AiRef, }; comments.Add(newComment); @@ -159,8 +160,9 @@ public async Task Any(AnswerCommentCallback request) { NewComment = new() { - RefId = request.Id, + RefId = request.AnswerId, Comment = newComment, + LastUpdated = DateTime.UtcNow, }, }); diff --git a/MyApp.ServiceInterface/App/NewCommentCommand.cs b/MyApp.ServiceInterface/App/NewCommentCommand.cs index 7e26fb1..441e20d 100644 --- a/MyApp.ServiceInterface/App/NewCommentCommand.cs +++ b/MyApp.ServiceInterface/App/NewCommentCommand.cs @@ -40,9 +40,11 @@ await db.InsertAsync(new Notification appConfig.IncrUnreadNotificationsFor(createdBy); } + var lastUpdated = request.LastUpdated; + appConfig.SetLastUpdated(request.RefId, lastUpdated); await db.UpdateOnlyAsync(() => new StatTotals { - LastUpdated = DateTime.UtcNow, + LastUpdated = lastUpdated, }, where: x => x.Id == request.RefId); var userNameMentions = cleanBody.FindUserNameMentions() diff --git a/MyApp.ServiceInterface/App/SaveGradeResultCommand.cs b/MyApp.ServiceInterface/App/SaveGradeResultCommand.cs index 0a4a597..e4eadfe 100644 --- a/MyApp.ServiceInterface/App/SaveGradeResultCommand.cs +++ b/MyApp.ServiceInterface/App/SaveGradeResultCommand.cs @@ -7,11 +7,13 @@ namespace MyApp.ServiceInterface.App; -public class SaveGradeResultCommand(IDbConnection db, IMessageProducer mq, WorkerAnswerNotifier answerNotifier) : IAsyncCommand +public class SaveGradeResultCommand(AppConfig appConfig, IDbConnection db, IMessageProducer mq, WorkerAnswerNotifier answerNotifier) + : IAsyncCommand { public async Task ExecuteAsync(StatTotals request) { var lastUpdated = request.LastUpdated ?? DateTime.UtcNow; + appConfig.SetLastUpdated(request.Id, lastUpdated); var updatedRow = await db.UpdateOnlyAsync(() => new StatTotals { StartingUpVotes = request.StartingUpVotes, diff --git a/MyApp.ServiceInterface/Data/AppConfig.cs b/MyApp.ServiceInterface/Data/AppConfig.cs index 682d4e6..ec20c3b 100644 --- a/MyApp.ServiceInterface/Data/AppConfig.cs +++ b/MyApp.ServiceInterface/Data/AppConfig.cs @@ -3,6 +3,7 @@ using MyApp.ServiceModel; using ServiceStack; using ServiceStack.OrmLite; +using ServiceStack.Text; namespace MyApp.Data; @@ -33,6 +34,7 @@ public class AppConfig public ConcurrentDictionary UsersQuestions { get; set; } = new(); public ConcurrentDictionary UsersUnreadAchievements { get; set; } = new(); public ConcurrentDictionary UsersUnreadNotifications { get; set; } = new(); + public ConcurrentDictionary PostsLastUpdated { get; set; } = new(); // RefId => UnixTimeMs public string MasterPassword { get; set; } public HashSet AllTags { get; set; } = []; @@ -110,6 +112,19 @@ public void LoadTags(FileInfo allTagsFile) public long LastPostId => Interlocked.Read(ref nextPostId); public long GetNextPostId() => Interlocked.Increment(ref nextPostId); + public void SetLastUpdated(string id, DateTime lastUpdated) => PostsLastUpdated[id] = lastUpdated.ToUnixTimeMs(); + public void SetLastUpdated(string id, long unixTimeMs) => PostsLastUpdated[id] = unixTimeMs; + + public long GetLastUpdated(IDbConnection db, string id) + { + return PostsLastUpdated.GetOrAdd(id, key => + { + var date = db.Scalar(db.From().Where(x => x.Id == id) + .Select(x => x.LastUpdated)); + return date?.ToUnixTimeMs() ?? DateTimeExtensions.UnixEpoch; + }); + } + public string GetReputation(string? userName) => GetReputationValue(userName).ToHumanReadable(); public int GetReputationValue(string? userName) => diff --git a/MyApp.ServiceInterface/Data/Tasks.cs b/MyApp.ServiceInterface/Data/Tasks.cs index 8bf85c7..73a1bb5 100644 --- a/MyApp.ServiceInterface/Data/Tasks.cs +++ b/MyApp.ServiceInterface/Data/Tasks.cs @@ -55,6 +55,7 @@ public class NewComment // Post or AnswerId public string RefId { get; set; } public Comment Comment { get; set; } + public DateTime LastUpdated { get; set; } } public class DeletePost diff --git a/MyApp.ServiceInterface/QuestionServices.cs b/MyApp.ServiceInterface/QuestionServices.cs index 3fbe557..599225d 100644 --- a/MyApp.ServiceInterface/QuestionServices.cs +++ b/MyApp.ServiceInterface/QuestionServices.cs @@ -7,6 +7,7 @@ using MyApp.ServiceModel; using ServiceStack.IO; using ServiceStack.OrmLite; +using ServiceStack.Text; namespace MyApp.ServiceInterface; @@ -387,18 +388,21 @@ public async Task Any(CreateComment request) CreatedBy = createdBy, }; comments.Add(newComment); - + + var lastUpdated = DateTime.UtcNow; MessageProducer.Publish(new DbWrites { NewComment = new() { RefId = request.Id, Comment = newComment, + LastUpdated = lastUpdated, }, }); await questions.SaveMetaAsync(postId, meta); + string? aiRef = null; if (modelCreator?.UserName != null) { var answer = await questions.GetAnswerAsPostAsync(request.Id); @@ -408,13 +412,15 @@ public async Task Any(CreateComment request) var userConversation = comments .Where(x => x.CreatedBy == createdBy || x.Body.Contains(mention)) .ToList(); - + + aiRef = Guid.NewGuid().ToString("N"); var createdById = GetUserId(); var model = modelCreator.Model ?? throw new ArgumentNullException(nameof(modelCreator.Model)); MessageProducer.Publish(new AiServerTasks { CreateAnswerCommentTask = new() { + AiRef = aiRef, Model = model, Question = question, Answer = answer, @@ -432,6 +438,8 @@ public async Task Any(CreateComment request) return new CommentsResponse { + AiRef = aiRef, + LastUpdated = lastUpdated.ToUnixTimeMs(), Comments = comments }; } @@ -524,48 +532,40 @@ public async Task Any(ImportQuestion request) public async Task Any(GetLastUpdated request) { - var lastUpdated = request.Id != null - ? await Db.ScalarAsync(Db.From().Where(x => x.Id == request.Id) - .Select(x => x.LastUpdated)) - : request.PostId != null - ? await Db.ScalarAsync(Db.From().Where(x => x.PostId == request.PostId) - .Select(x => Sql.Max(x.LastUpdated))) - : null; - - return new GetLastUpdatedResponse - { - Result = lastUpdated + if (request.Id == null && request.PostId == null) + throw new ArgumentNullException(nameof(request.Id)); + + var lastUpdated = request.PostId != null + ? await Db.ScalarAsync(Db.From().Where(x => x.PostId == request.PostId) + .Select(x => Sql.Max(x.LastUpdated))) + : null; + + if (lastUpdated != null) + return new GetLastUpdatedResponse { Result = lastUpdated.Value.ToUnixTimeMs() }; + + if (request.Id != null) + return new GetLastUpdatedResponse { Result = appConfig.GetLastUpdated(Db, request.Id) }; + + return new GetLastUpdatedResponse { + Result = DateTimeExtensions.UnixEpoch }; } -} -[ValidateHasRole(Roles.Moderator)] -public class GetAnswerFile : IGet, IReturn -{ - /// - /// Format is {PostId}-{UserName} - /// - public string Id { get; set; } -} -public class GetAllAnswerModelsResponse -{ - public List Results { get; set; } -} + public async Task Any(WaitForUpdate request) + { + var afterDate = request.UpdatedAfter ?? DateTimeExtensions.UnixEpoch; + var lastUpdated = appConfig.GetLastUpdated(Db, request.Id); -public class GetAnswer : IGet, IReturn -{ - /// - /// Format is {PostId}-{UserName} - /// - public string Id { get; set; } -} -public class GetAnswerResponse -{ - public Post Result { get; set; } + var startedAt = DateTime.UtcNow; + while (DateTime.UtcNow - startedAt < TimeSpan.FromSeconds(120)) + { + lastUpdated = appConfig.GetLastUpdated(Db, request.Id); + if (lastUpdated > afterDate) + return new GetLastUpdatedResponse { Result = lastUpdated }; + await Task.Delay(500); + } + + return new GetLastUpdatedResponse { Result = lastUpdated }; + } } -[ValidateIsAuthenticated] -public class GetAllAnswerModels : IReturn, IGet -{ - public int Id { get; set; } -} diff --git a/MyApp.ServiceModel/OpenAi.cs b/MyApp.ServiceModel/OpenAi.cs index 306645e..1a4437a 100644 --- a/MyApp.ServiceModel/OpenAi.cs +++ b/MyApp.ServiceModel/OpenAi.cs @@ -45,6 +45,9 @@ public class AnswerCommentCallback : OpenAiChatResponse, IPost, IReturnVoid [ValidateNotEmpty] public string UserId { get; set; } // Use User GUID to prevent tampering + + [ValidateNotEmpty] + public string AiRef { get; set; } // Ref for AI Task that generated the comment } public class CreateAnswerTasks @@ -61,6 +64,7 @@ public class CreateRankAnswerTask public class CreateAnswerCommentTask { + public string? AiRef { get; set; } public string Model { get; set; } public Post Question { get; set; } public Post Answer { get; set; } diff --git a/MyApp.ServiceModel/Posts.cs b/MyApp.ServiceModel/Posts.cs index ce0c5f6..925f94d 100644 --- a/MyApp.ServiceModel/Posts.cs +++ b/MyApp.ServiceModel/Posts.cs @@ -172,6 +172,7 @@ public class Comment public string CreatedBy { get; set; } public int? UpVotes { get; set; } public int? Reports { get; set; } + public string? AiRef { get; set; } // comment generated by AI } public class QuestionAndAnswers @@ -390,6 +391,9 @@ public class CreateComment : IPost, IReturn public class CommentsResponse { + // Whether the comment triggered an AI Comment Task + public string? AiRef { get; set; } + public long LastUpdated { get; set; } public List Comments { get; set; } public ResponseStatus ResponseStatus { get; set; } } @@ -421,6 +425,37 @@ public class GetAnswerBody : IGet, IReturn public string Id { get; set; } } +[ValidateHasRole(Roles.Moderator)] +public class GetAnswerFile : IGet, IReturn +{ + /// + /// Format is {PostId}-{UserName} + /// + public string Id { get; set; } +} +public class GetAllAnswerModelsResponse +{ + public List Results { get; set; } +} + +public class GetAnswer : IGet, IReturn +{ + /// + /// Format is {PostId}-{UserName} + /// + public string Id { get; set; } +} +public class GetAnswerResponse +{ + public Post Result { get; set; } +} + +[ValidateIsAuthenticated] +public class GetAllAnswerModels : IReturn, IGet +{ + public int Id { get; set; } +} + [ValidateHasRole(Roles.Moderator)] public class DeleteQuestion : IGet, IReturn { @@ -555,12 +590,19 @@ public class ImportQuestionResponse public ResponseStatus? ResponseStatus { get; set; } } -public class GetLastUpdated : IGet, IReturn +public class GetLastUpdated : IGet, IReturn { public string? Id { get; set; } public int? PostId { get; set; } } public class GetLastUpdatedResponse { - public DateTime? Result { get; set; } -} \ No newline at end of file + public long? Result { get; set; } +} + +public class WaitForUpdate : IGet, IReturn +{ + [ValidateNotEmpty] + public required string Id { get; set; } + public long? UpdatedAfter { get; set; } +} diff --git a/MyApp/wwwroot/mjs/dtos.mjs b/MyApp/wwwroot/mjs/dtos.mjs index ebe6085..78fd1e3 100644 --- a/MyApp/wwwroot/mjs/dtos.mjs +++ b/MyApp/wwwroot/mjs/dtos.mjs @@ -1,5 +1,5 @@ /* Options: -Date: 2024-05-04 22:38:15 +Date: 2024-05-05 17:08:25 Version: 8.23 Tip: To override a DTO option, remove "//" prefix before updating BaseUrl: https://localhost:5001 @@ -324,7 +324,7 @@ export class CreateRankAnswerTask { userId; } export class Comment { - /** @param {{body?:string,created?:number,createdBy?:string,upVotes?:number,reports?:number}} [init] */ + /** @param {{body?:string,created?:number,createdBy?:string,upVotes?:number,reports?:number,aiRef?:string}} [init] */ constructor(init) { Object.assign(this, init) } /** @type {string} */ body; @@ -336,10 +336,14 @@ export class Comment { upVotes; /** @type {?number} */ reports; + /** @type {?string} */ + aiRef; } export class CreateAnswerCommentTask { - /** @param {{model?:string,question?:Post,answer?:Post,userId?:string,userName?:string,comments?:Comment[]}} [init] */ + /** @param {{aiRef?:string,model?:string,question?:Post,answer?:Post,userId?:string,userName?:string,comments?:Comment[]}} [init] */ constructor(init) { Object.assign(this, init) } + /** @type {?string} */ + aiRef; /** @type {string} */ model; /** @type {Post} */ @@ -937,8 +941,12 @@ export class GetAnswerResponse { result; } export class CommentsResponse { - /** @param {{comments?:Comment[],responseStatus?:ResponseStatus}} [init] */ + /** @param {{aiRef?:string,lastUpdated?:number,comments?:Comment[],responseStatus?:ResponseStatus}} [init] */ constructor(init) { Object.assign(this, init) } + /** @type {?string} */ + aiRef; + /** @type {number} */ + lastUpdated; /** @type {Comment[]} */ comments; /** @type {ResponseStatus} */ @@ -977,6 +985,12 @@ export class ImportQuestionResponse { /** @type {?ResponseStatus} */ responseStatus; } +export class GetLastUpdatedResponse { + /** @param {{result?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {?number} */ + result; +} export class UpdateUserProfileResponse { /** @param {{responseStatus?:ResponseStatus}} [init] */ constructor(init) { Object.assign(this, init) } @@ -1398,12 +1412,14 @@ export class RankAnswerCallback extends OpenAiChatResponse { createResponse() { } } export class AnswerCommentCallback extends OpenAiChatResponse { - /** @param {{answerId?:string,userId?:string,id?:string,choices?:Choice[],created?:number,model?:string,system_fingerprint?:string,object?:string,usage?:OpenAiUsage}} [init] */ + /** @param {{answerId?:string,userId?:string,aiRef?:string,id?:string,choices?:Choice[],created?:number,model?:string,system_fingerprint?:string,object?:string,usage?:OpenAiUsage}} [init] */ constructor(init) { super(init); Object.assign(this, init) } /** @type {string} */ answerId; /** @type {string} */ userId; + /** @type {string} */ + aiRef; getTypeName() { return 'AnswerCommentCallback' } getMethod() { return 'POST' } createResponse() { } @@ -1719,6 +1735,28 @@ export class ImportQuestion { getMethod() { return 'GET' } createResponse() { return new ImportQuestionResponse() } } +export class GetLastUpdated { + /** @param {{id?:string,postId?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {?string} */ + id; + /** @type {?number} */ + postId; + getTypeName() { return 'GetLastUpdated' } + getMethod() { return 'GET' } + createResponse() { return new GetLastUpdatedResponse() } +} +export class WaitForUpdate { + /** @param {{id?:string,updatedAfter?:number}} [init] */ + constructor(init) { Object.assign(this, init) } + /** @type {string} */ + id; + /** @type {?number} */ + updatedAfter; + getTypeName() { return 'WaitForUpdate' } + getMethod() { return 'GET' } + createResponse() { return new GetLastUpdatedResponse() } +} export class UpdateUserProfile { constructor(init) { Object.assign(this, init) } getTypeName() { return 'UpdateUserProfile' } diff --git a/MyApp/wwwroot/mjs/question.mjs b/MyApp/wwwroot/mjs/question.mjs index 464730b..726f255 100644 --- a/MyApp/wwwroot/mjs/question.mjs +++ b/MyApp/wwwroot/mjs/question.mjs @@ -9,6 +9,7 @@ import { AnswerQuestion, UpdateQuestion, PreviewMarkdown, GetAnswerBody, CreateComment, GetMeta, DeleteQuestion, DeleteComment, GetUserReputations, CommentVote, ShareContent, FlagContent, GetAnswer, + WaitForUpdate, GetLastUpdated, } from "dtos.mjs" const client = new JsonServiceClient(globalThis.BaseUrl) @@ -499,9 +500,12 @@ const Comments = { unlock after {{remainingToAskModel()}} more {{remainingToAskModel() === 1 ? 'question' : 'questions' }} -
    +
    ask {{model.userName}} +
    + Waiting for {{model.userName}} to respond... +
    @@ -525,6 +529,7 @@ const Comments = { const instance = getCurrentInstance() const postId = parseInt(leftPart(props.id, '-')) const model = computed(() => modelUser(props.createdBy)) + const modelLoading = ref(false) pageBus.subscribe('meta:load', () => { console.log(`Comments: meta:load`) @@ -563,12 +568,23 @@ const Comments = { } async function submit() { - const api = await client.api(new CreateComment({ id: `${props.id}`, body: txt.value })) + const id = `${props.id}` + const api = await client.api(new CreateComment({ id:id, body: txt.value })) if (api.succeeded) { txt.value = '' editing.value = false comments.value = api.response.comments || [] close() + + if (api.response.aiRef) { + modelLoading.value = true + const apiWait = await client.api(new WaitForUpdate({ + id:id, + updatedAfter: api.response.lastUpdated + })) + await loadMeta(leftPart(id, '-')) + modelLoading.value = false + } } else { error.value = api.errorMessage } @@ -611,8 +627,8 @@ const Comments = { } return { editing, userName, isModerator, model, txt, input, comments, keyDown, startEditing, - formatDate, loading, error, submit, close, removeComment, voteUp, flag, hasVoted, - remainingToAskModel, renderMarkdown } + formatDate, loading, error, submit, close, removeComment, voteUp, flag, hasVoted, + modelLoading, remainingToAskModel } } } @@ -1095,6 +1111,11 @@ async function loadUserReputations(userName) { } } +async function loadMeta(postId) { + meta = await client.get(new GetMeta({ id:`${postId}` })) + pageBus.publish('meta:load') +} + export default { async load() { const { user, hasRole } = useAuth() @@ -1108,11 +1129,7 @@ export default { } if (meta == null) { - client.get(new GetMeta({ id:`${postId}` })) - .then(r => { - meta = r - pageBus.publish('meta:load') - }) + loadMeta(postId) } if (!isNaN(postId)) { From 62d528a5e3b21c78b90608448d3d5e90a870f8bb Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 May 2024 18:04:30 +0800 Subject: [PATCH 29/36] Update AnswerPost.razor --- MyApp/Components/Shared/AnswerPost.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MyApp/Components/Shared/AnswerPost.razor b/MyApp/Components/Shared/AnswerPost.razor index 941031c..2cdc4df 100644 --- a/MyApp/Components/Shared/AnswerPost.razor +++ b/MyApp/Components/Shared/AnswerPost.razor @@ -26,7 +26,7 @@
    -
    +
    @if (Question.Meta?.ModelVotes?.TryGetValue(Answer.CreatedBy!, out var votes) == true && Question.Meta?.ModelReasons?.TryGetValue(Answer.CreatedBy!, out var reason) == true) { From 43c526d53fee484153903b0d3b9f8fa19bc1c4ad Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 May 2024 18:21:02 +0800 Subject: [PATCH 30/36] Update CreateAnswerCommentTaskCommand.cs --- .../AiServer/CreateAnswerCommentTaskCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs b/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs index e4dc6fa..48fd718 100644 --- a/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs +++ b/MyApp.ServiceInterface/AiServer/CreateAnswerCommentTaskCommand.cs @@ -41,7 +41,7 @@ public async Task ExecuteAsync(CreateAnswerCommentTask request) new() { Role = "assistant", Content = answerPrompt }, ], Temperature = 0.2, - MaxTokens = 100, + MaxTokens = 300, }; var modelUser = appConfig.GetModelUser(request.Model); From 1c45b6b3db21e5877163ff9993d08532f611d9ca Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 May 2024 18:34:40 +0800 Subject: [PATCH 31/36] populate js question from embedded post json --- MyApp/Components/Shared/QuestionPost.razor | 2 +- MyApp/wwwroot/mjs/question.mjs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/MyApp/Components/Shared/QuestionPost.razor b/MyApp/Components/Shared/QuestionPost.razor index 7ff5833..7da9b48 100644 --- a/MyApp/Components/Shared/QuestionPost.razor +++ b/MyApp/Components/Shared/QuestionPost.razor @@ -70,7 +70,7 @@
    -
    +
    @BlazorHtml.Raw(Markdown.GenerateHtml(Question.Post.Body))
    diff --git a/MyApp/wwwroot/mjs/question.mjs b/MyApp/wwwroot/mjs/question.mjs index 726f255..1ce7f74 100644 --- a/MyApp/wwwroot/mjs/question.mjs +++ b/MyApp/wwwroot/mjs/question.mjs @@ -841,6 +841,14 @@ const EditQuestion = { debounceApi(request.value.body) } }) + + const postJson = $1(`#Post`)?.innerHTML + if (postJson) { + const post = JSON.parse(postJson) + request.value.title = post.title + request.value.body = post.body + request.value.tags = post.tags + } }) function close() { From cce69df818e44feea3b75eaed21a40cfcb33426e Mon Sep 17 00:00:00 2001 From: Demis Bellot Date: Sun, 5 May 2024 20:36:10 +0800 Subject: [PATCH 32/36] Add more capable highlight js --- MyApp/Components/App.razor | 2 +- MyApp/wwwroot/lib/js/highlight.js | 22702 ++++++++++++++++++++++-- MyApp/wwwroot/lib/js/highlight.min.js | 2049 +++ 3 files changed, 23612 insertions(+), 1141 deletions(-) create mode 100644 MyApp/wwwroot/lib/js/highlight.min.js diff --git a/MyApp/Components/App.razor b/MyApp/Components/App.razor index 27a674d..7b66165 100644 --- a/MyApp/Components/App.razor +++ b/MyApp/Components/App.razor @@ -36,7 +36,7 @@ window.scrollTo({ top: 0, left: 0, behavior: 'instant' }); }) - + diff --git a/MyApp/wwwroot/lib/js/highlight.js b/MyApp/wwwroot/lib/js/highlight.js index 5eb82e3..8c05a99 100644 --- a/MyApp/wwwroot/lib/js/highlight.js +++ b/MyApp/wwwroot/lib/js/highlight.js @@ -1,1143 +1,21565 @@ /*! - Highlight.js v11.8.0 (git: 65687a907b) - (c) 2006-2023 undefined and other contributors + Highlight.js v11.9.0 (git: b7ec4bfafc) + (c) 2006-2024 undefined and other contributors License: BSD-3-Clause */ -var hljs=function(){"use strict";function e(t){ -return t instanceof Map?t.clear=t.delete=t.set=()=>{ -throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{ -throw Error("set is read-only") -}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{ -const i=t[n],s=typeof i;"object"!==s&&"function"!==s||Object.isFrozen(i)||e(i) -})),t}class t{constructor(e){ -void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} -ignoreMatch(){this.isMatchIgnored=!0}}function n(e){ -return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") -}function i(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t] -;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const s=e=>!!e.scope -;class o{constructor(e,t){ -this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){ -this.buffer+=n(e)}openNode(e){if(!s(e))return;const t=((e,{prefix:t})=>{ -if(e.startsWith("language:"))return e.replace("language:","language-") -;if(e.includes(".")){const n=e.split(".") -;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ") -}return`${t}${e}`})(e.scope,{prefix:this.classPrefix});this.span(t)} -closeNode(e){s(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ -this.buffer+=``}}const r=(e={})=>{const t={children:[]} -;return Object.assign(t,e),t};class a{constructor(){ -this.rootNode=r(),this.stack=[this.rootNode]}get top(){ -return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ -this.top.children.push(e)}openNode(e){const t=r({scope:e}) -;this.add(t),this.stack.push(t)}closeNode(){ -if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ -for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} -walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){ -return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t), -t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){ -"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ -a._collapse(e)})))}}class c extends a{constructor(e){super(),this.options=e} -addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){ -this.closeNode()}__addSublanguage(e,t){const n=e.root -;t&&(n.scope="language:"+t),this.add(n)}toHTML(){ -return new o(this,this.options).value()}finalize(){ -return this.closeAllNodes(),!0}}function l(e){ -return e?"string"==typeof e?e:e.source:null}function g(e){return h("(?=",e,")")} -function u(e){return h("(?:",e,")*")}function d(e){return h("(?:",e,")?")} -function h(...e){return e.map((e=>l(e))).join("")}function f(...e){const t=(e=>{ -const t=e[e.length-1] -;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{} -})(e);return"("+(t.capture?"":"?:")+e.map((e=>l(e))).join("|")+")"} -function p(e){return RegExp(e.toString()+"|").exec("").length-1} -const b=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ -;function m(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n -;let i=l(e),s="";for(;i.length>0;){const e=b.exec(i);if(!e){s+=i;break} -s+=i.substring(0,e.index), -i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?s+="\\"+(Number(e[1])+t):(s+=e[0], -"("===e[0]&&n++)}return s})).map((e=>`(${e})`)).join(t)} -const E="[a-zA-Z]\\w*",x="[a-zA-Z_]\\w*",w="\\b\\d+(\\.\\d+)?",y="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",_="\\b(0b[01]+)",O={ -begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'", -illegal:"\\n",contains:[O]},N={scope:"string",begin:'"',end:'"',illegal:"\\n", -contains:[O]},S=(e,t,n={})=>{const s=i({scope:"comment",begin:e,end:t, -contains:[]},n);s.contains.push({scope:"doctag", -begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", -end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) -;const o=f("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) -;return s.contains.push({begin:h(/[ ]+/,"(",o,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s -},v=S("//","$"),M=S("/\\*","\\*/"),R=S("#","$");var j=Object.freeze({ -__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:E,UNDERSCORE_IDENT_RE:x, -NUMBER_RE:w,C_NUMBER_RE:y,BINARY_NUMBER_RE:_, -RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", -SHEBANG:(e={})=>{const t=/^#![ ]*\// -;return e.binary&&(e.begin=h(t,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:t, -end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)}, -BACKSLASH_ESCAPE:O,APOS_STRING_MODE:k,QUOTE_STRING_MODE:N,PHRASAL_WORDS_MODE:{ -begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ -},COMMENT:S,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:M,HASH_COMMENT_MODE:R, -NUMBER_MODE:{scope:"number",begin:w,relevance:0},C_NUMBER_MODE:{scope:"number", -begin:y,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:_,relevance:0}, -REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//, -end:/\/[gimuy]*/,illegal:/\n/,contains:[O,{begin:/\[/,end:/\]/,relevance:0, -contains:[O]}]}]},TITLE_MODE:{scope:"title",begin:E,relevance:0}, -UNDERSCORE_TITLE_MODE:{scope:"title",begin:x,relevance:0},METHOD_GUARD:{ -begin:"\\.\\s*"+x,relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{ -"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{ -t.data._beginMatch!==e[1]&&t.ignoreMatch()}})});function A(e,t){ -"."===e.input[e.index-1]&&t.ignoreMatch()}function I(e,t){ -void 0!==e.className&&(e.scope=e.className,delete e.className)}function T(e,t){ -t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", -e.__beforeBegin=A,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, -void 0===e.relevance&&(e.relevance=0))}function L(e,t){ -Array.isArray(e.illegal)&&(e.illegal=f(...e.illegal))}function B(e,t){ -if(e.match){ -if(e.begin||e.end)throw Error("begin & end are not supported with match") -;e.begin=e.match,delete e.match}}function P(e,t){ -void 0===e.relevance&&(e.relevance=1)}const D=(e,t)=>{if(!e.beforeMatch)return -;if(e.starts)throw Error("beforeMatch cannot be used with starts") -;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t] -})),e.keywords=n.keywords,e.begin=h(n.beforeMatch,g(n.begin)),e.starts={ -relevance:0,contains:[Object.assign(n,{endsParent:!0})] -},e.relevance=0,delete n.beforeMatch -},H=["of","and","for","in","not","or","if","then","parent","list","value"],C="keyword" -;function $(e,t,n=C){const i=Object.create(null) -;return"string"==typeof e?s(n,e.split(" ")):Array.isArray(e)?s(n,e):Object.keys(e).forEach((n=>{ -Object.assign(i,$(e[n],t,n))})),i;function s(e,n){ -t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|") -;i[n[0]]=[e,U(n[0],n[1])]}))}}function U(e,t){ -return t?Number(t):(e=>H.includes(e.toLowerCase()))(e)?0:1}const z={},W=e=>{ -console.error(e)},X=(e,...t)=>{console.log("WARN: "+e,...t)},G=(e,t)=>{ -z[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),z[`${e}/${t}`]=!0) -},K=Error();function F(e,t,{key:n}){let i=0;const s=e[n],o={},r={} -;for(let e=1;e<=t.length;e++)r[e+i]=s[e],o[e+i]=!0,i+=p(t[e-1]) -;e[n]=r,e[n]._emit=o,e[n]._multi=!0}function Z(e){(e=>{ -e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, -delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ -_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope -}),(e=>{if(Array.isArray(e.begin)){ -if(e.skip||e.excludeBegin||e.returnBegin)throw W("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), -K -;if("object"!=typeof e.beginScope||null===e.beginScope)throw W("beginScope must be object"), -K;F(e,e.begin,{key:"beginScope"}),e.begin=m(e.begin,{joinWith:""})}})(e),(e=>{ -if(Array.isArray(e.end)){ -if(e.skip||e.excludeEnd||e.returnEnd)throw W("skip, excludeEnd, returnEnd not compatible with endScope: {}"), -K -;if("object"!=typeof e.endScope||null===e.endScope)throw W("endScope must be object"), -K;F(e,e.end,{key:"endScope"}),e.end=m(e.end,{joinWith:""})}})(e)}function V(e){ -function t(t,n){ -return RegExp(l(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":"")) -}class n{constructor(){ -this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} -addRule(e,t){ -t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]), -this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) -;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(m(e,{joinWith:"|" -}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex -;const t=this.matcherRe.exec(e);if(!t)return null -;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n] -;return t.splice(0,n),Object.assign(t,i)}}class s{constructor(){ -this.rules=[],this.multiRegexes=[], -this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ -if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n -;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))), -t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){ -return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){ -this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){ -const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex -;let n=t.exec(e) -;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{ -const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)} -return n&&(this.regexIndex+=n.position+1, -this.regexIndex===this.count&&this.considerAll()),n}} -if(e.compilerExtensions||(e.compilerExtensions=[]), -e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") -;return e.classNameAliases=i(e.classNameAliases||{}),function n(o,r){const a=o -;if(o.isCompiled)return a -;[I,B,Z,D].forEach((e=>e(o,r))),e.compilerExtensions.forEach((e=>e(o,r))), -o.__beforeBegin=null,[T,L,P].forEach((e=>e(o,r))),o.isCompiled=!0;let c=null -;return"object"==typeof o.keywords&&o.keywords.$pattern&&(o.keywords=Object.assign({},o.keywords), -c=o.keywords.$pattern, -delete o.keywords.$pattern),c=c||/\w+/,o.keywords&&(o.keywords=$(o.keywords,e.case_insensitive)), -a.keywordPatternRe=t(c,!0), -r&&(o.begin||(o.begin=/\B|\b/),a.beginRe=t(a.begin),o.end||o.endsWithParent||(o.end=/\B|\b/), -o.end&&(a.endRe=t(a.end)), -a.terminatorEnd=l(a.end)||"",o.endsWithParent&&r.terminatorEnd&&(a.terminatorEnd+=(o.end?"|":"")+r.terminatorEnd)), -o.illegal&&(a.illegalRe=t(o.illegal)), -o.contains||(o.contains=[]),o.contains=[].concat(...o.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>i(e,{ -variants:null},t)))),e.cachedVariants?e.cachedVariants:q(e)?i(e,{ -starts:e.starts?i(e.starts):null -}):Object.isFrozen(e)?i(e):e))("self"===e?o:e)))),o.contains.forEach((e=>{n(e,a) -})),o.starts&&n(o.starts,r),a.matcher=(e=>{const t=new s -;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin" -}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end" -}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function q(e){ -return!!e&&(e.endsWithParent||q(e.starts))}class J extends Error{ -constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}} -const Y=n,Q=i,ee=Symbol("nomatch"),te=n=>{ -const i=Object.create(null),s=Object.create(null),o=[];let r=!0 -;const a="Could not find the language '{}', did you forget to load/include a language module?",l={ -disableAutodetect:!0,name:"Plain text",contains:[]};let p={ -ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, -languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", -cssSelector:"pre code",languages:null,__emitter:c};function b(e){ -return p.noHighlightRe.test(e)}function m(e,t,n){let i="",s="" -;"object"==typeof t?(i=e, -n=t.ignoreIllegals,s=t.language):(G("10.7.0","highlight(lang, code, ...args) has been deprecated."), -G("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), -s=e,i=t),void 0===n&&(n=!0);const o={code:i,language:s};S("before:highlight",o) -;const r=o.result?o.result:E(o.language,o.code,n) -;return r.code=o.code,S("after:highlight",r),r}function E(e,n,s,o){ -const c=Object.create(null);function l(){if(!S.keywords)return void M.addText(R) -;let e=0;S.keywordPatternRe.lastIndex=0;let t=S.keywordPatternRe.exec(R),n="" -;for(;t;){n+=R.substring(e,t.index) -;const s=_.case_insensitive?t[0].toLowerCase():t[0],o=(i=s,S.keywords[i]);if(o){ -const[e,i]=o -;if(M.addText(n),n="",c[s]=(c[s]||0)+1,c[s]<=7&&(j+=i),e.startsWith("_"))n+=t[0];else{ -const n=_.classNameAliases[e]||e;u(t[0],n)}}else n+=t[0] -;e=S.keywordPatternRe.lastIndex,t=S.keywordPatternRe.exec(R)}var i -;n+=R.substring(e),M.addText(n)}function g(){null!=S.subLanguage?(()=>{ -if(""===R)return;let e=null;if("string"==typeof S.subLanguage){ -if(!i[S.subLanguage])return void M.addText(R) -;e=E(S.subLanguage,R,!0,v[S.subLanguage]),v[S.subLanguage]=e._top -}else e=x(R,S.subLanguage.length?S.subLanguage:null) -;S.relevance>0&&(j+=e.relevance),M.__addSublanguage(e._emitter,e.language) -})():l(),R=""}function u(e,t){ -""!==e&&(M.startScope(t),M.addText(e),M.endScope())}function d(e,t){let n=1 -;const i=t.length-1;for(;n<=i;){if(!e._emit[n]){n++;continue} -const i=_.classNameAliases[e[n]]||e[n],s=t[n];i?u(s,i):(R=s,l(),R=""),n++}} -function h(e,t){ -return e.scope&&"string"==typeof e.scope&&M.openNode(_.classNameAliases[e.scope]||e.scope), -e.beginScope&&(e.beginScope._wrap?(u(R,_.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), -R=""):e.beginScope._multi&&(d(e.beginScope,t),R="")),S=Object.create(e,{parent:{ -value:S}}),S}function f(e,n,i){let s=((e,t)=>{const n=e&&e.exec(t) -;return n&&0===n.index})(e.endRe,i);if(s){if(e["on:end"]){const i=new t(e) -;e["on:end"](n,i),i.isMatchIgnored&&(s=!1)}if(s){ -for(;e.endsParent&&e.parent;)e=e.parent;return e}} -if(e.endsWithParent)return f(e.parent,n,i)}function b(e){ -return 0===S.matcher.regexIndex?(R+=e[0],1):(T=!0,0)}function m(e){ -const t=e[0],i=n.substring(e.index),s=f(S,e,i);if(!s)return ee;const o=S -;S.endScope&&S.endScope._wrap?(g(), -u(t,S.endScope._wrap)):S.endScope&&S.endScope._multi?(g(), -d(S.endScope,e)):o.skip?R+=t:(o.returnEnd||o.excludeEnd||(R+=t), -g(),o.excludeEnd&&(R=t));do{ -S.scope&&M.closeNode(),S.skip||S.subLanguage||(j+=S.relevance),S=S.parent -}while(S!==s.parent);return s.starts&&h(s.starts,e),o.returnEnd?0:t.length} -let w={};function y(i,o){const a=o&&o[0];if(R+=i,null==a)return g(),0 -;if("begin"===w.type&&"end"===o.type&&w.index===o.index&&""===a){ -if(R+=n.slice(o.index,o.index+1),!r){const t=Error(`0 width match regex (${e})`) -;throw t.languageName=e,t.badRule=w.rule,t}return 1} -if(w=o,"begin"===o.type)return(e=>{ -const n=e[0],i=e.rule,s=new t(i),o=[i.__beforeBegin,i["on:begin"]] -;for(const t of o)if(t&&(t(e,s),s.isMatchIgnored))return b(n) -;return i.skip?R+=n:(i.excludeBegin&&(R+=n), -g(),i.returnBegin||i.excludeBegin||(R=n)),h(i,e),i.returnBegin?0:n.length})(o) -;if("illegal"===o.type&&!s){ -const e=Error('Illegal lexeme "'+a+'" for mode "'+(S.scope||"")+'"') -;throw e.mode=S,e}if("end"===o.type){const e=m(o);if(e!==ee)return e} -if("illegal"===o.type&&""===a)return 1 -;if(I>1e5&&I>3*o.index)throw Error("potential infinite loop, way more iterations than matches") -;return R+=a,a.length}const _=O(e) -;if(!_)throw W(a.replace("{}",e)),Error('Unknown language: "'+e+'"') -;const k=V(_);let N="",S=o||k;const v={},M=new p.__emitter(p);(()=>{const e=[] -;for(let t=S;t!==_;t=t.parent)t.scope&&e.unshift(t.scope) -;e.forEach((e=>M.openNode(e)))})();let R="",j=0,A=0,I=0,T=!1;try{ -if(_.__emitTokens)_.__emitTokens(n,M);else{for(S.matcher.considerAll();;){ -I++,T?T=!1:S.matcher.considerAll(),S.matcher.lastIndex=A -;const e=S.matcher.exec(n);if(!e)break;const t=y(n.substring(A,e.index),e) -;A=e.index+t}y(n.substring(A))}return M.finalize(),N=M.toHTML(),{language:e, -value:N,relevance:j,illegal:!1,_emitter:M,_top:S}}catch(t){ -if(t.message&&t.message.includes("Illegal"))return{language:e,value:Y(n), -illegal:!0,relevance:0,_illegalBy:{message:t.message,index:A, -context:n.slice(A-100,A+100),mode:t.mode,resultSoFar:N},_emitter:M};if(r)return{ -language:e,value:Y(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:S} -;throw t}}function x(e,t){t=t||p.languages||Object.keys(i);const n=(e=>{ -const t={value:Y(e),illegal:!1,relevance:0,_top:l,_emitter:new p.__emitter(p)} -;return t._emitter.addText(e),t})(e),s=t.filter(O).filter(N).map((t=>E(t,e,!1))) -;s.unshift(n);const o=s.sort(((e,t)=>{ -if(e.relevance!==t.relevance)return t.relevance-e.relevance -;if(e.language&&t.language){if(O(e.language).supersetOf===t.language)return 1 -;if(O(t.language).supersetOf===e.language)return-1}return 0})),[r,a]=o,c=r -;return c.secondBest=a,c}function w(e){let t=null;const n=(e=>{ -let t=e.className+" ";t+=e.parentNode?e.parentNode.className:"" -;const n=p.languageDetectRe.exec(t);if(n){const t=O(n[1]) -;return t||(X(a.replace("{}",n[1])), -X("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"} -return t.split(/\s+/).find((e=>b(e)||O(e)))})(e);if(b(n))return -;if(S("before:highlightElement",{el:e,language:n -}),e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), -console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), -console.warn("The element with unescaped HTML:"), -console.warn(e)),p.throwUnescapedHTML))throw new J("One of your code blocks includes unescaped HTML.",e.innerHTML) -;t=e;const i=t.textContent,o=n?m(i,{language:n,ignoreIllegals:!0}):x(i) -;e.innerHTML=o.value,((e,t,n)=>{const i=t&&s[t]||n -;e.classList.add("hljs"),e.classList.add("language-"+i) -})(e,n,o.language),e.result={language:o.language,re:o.relevance, -relevance:o.relevance},o.secondBest&&(e.secondBest={ -language:o.secondBest.language,relevance:o.secondBest.relevance -}),S("after:highlightElement",{el:e,result:o,text:i})}let y=!1;function _(){ -"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(w):y=!0 -}function O(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]} -function k(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ -s[e.toLowerCase()]=t}))}function N(e){const t=O(e) -;return t&&!t.disableAutodetect}function S(e,t){const n=e;o.forEach((e=>{ -e[n]&&e[n](t)}))} -"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ -y&&_()}),!1),Object.assign(n,{highlight:m,highlightAuto:x,highlightAll:_, -highlightElement:w, -highlightBlock:e=>(G("10.7.0","highlightBlock will be removed entirely in v12.0"), -G("10.7.0","Please use highlightElement now."),w(e)),configure:e=>{p=Q(p,e)}, -initHighlighting:()=>{ -_(),G("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, -initHighlightingOnLoad:()=>{ -_(),G("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") -},registerLanguage:(e,t)=>{let s=null;try{s=t(n)}catch(t){ -if(W("Language definition for '{}' could not be registered.".replace("{}",e)), -!r)throw t;W(t),s=l} -s.name||(s.name=e),i[e]=s,s.rawDefinition=t.bind(null,n),s.aliases&&k(s.aliases,{ -languageName:e})},unregisterLanguage:e=>{delete i[e] -;for(const t of Object.keys(s))s[t]===e&&delete s[t]}, -listLanguages:()=>Object.keys(i),getLanguage:O,registerAliases:k, -autoDetection:N,inherit:Q,addPlugin:e=>{(e=>{ -e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{ -e["before:highlightBlock"](Object.assign({block:t.el},t)) -}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{ -e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),o.push(e)}, -removePlugin:e=>{const t=o.indexOf(e);-1!==t&&o.splice(t,1)}}),n.debugMode=()=>{ -r=!1},n.safeMode=()=>{r=!0},n.versionString="11.8.0",n.regex={concat:h, -lookahead:g,either:f,optional:d,anyNumberOfTimes:u} -;for(const t in j)"object"==typeof j[t]&&e(j[t]);return Object.assign(n,j),n -},ne=te({});return ne.newInstance=()=>te({}),ne}() -;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);/*! `bash` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{const s=e.regex,t={},n={begin:/\$\{/, -end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]};Object.assign(t,{ -className:"variable",variants:[{ -begin:s.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},n]});const a={ -className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},i={ -begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/, -end:/(\w+)/,className:"string"})]}},c={className:"string",begin:/"/,end:/"/, -contains:[e.BACKSLASH_ESCAPE,t,a]};a.contains.push(c);const o={begin:/\$?\(\(/, -end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t] -},r=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 -}),l={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, -contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ -name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/, -keyword:["if","then","else","elif","fi","for","while","until","in","do","done","case","esac","function","select"], -literal:["true","false"], -built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"] -},contains:[r,e.SHEBANG(),l,o,e.HASH_COMMENT_MODE,i,{match:/(\/[a-z._-]+)+/},c,{ -className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},t]}}})() -;hljs.registerLanguage("bash",e)})();/*! `csharp` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{const n={ -keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]), -built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"], -literal:["default","false","null","true"]},a=e.inherit(e.TITLE_MODE,{ -begin:"[a-zA-Z](\\.?\\w)*"}),i={className:"number",variants:[{ -begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] -},t=e.inherit(s,{illegal:/\n/}),r={className:"subst",begin:/\{/,end:/\}/, -keywords:n},l=e.inherit(r,{illegal:/\n/}),c={className:"string",begin:/\$"/, -end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/ -},e.BACKSLASH_ESCAPE,l]},o={className:"string",begin:/\$@"/,end:'"',contains:[{ -begin:/\{\{/},{begin:/\}\}/},{begin:'""'},r]},d=e.inherit(o,{illegal:/\n/, -contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},l]}) -;r.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,e.C_BLOCK_COMMENT_MODE], -l.contains=[d,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,e.inherit(e.C_BLOCK_COMMENT_MODE,{ -illegal:/\n/})];const g={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] -},E={begin:"<",end:">",contains:[{beginKeywords:"in out"},a] -},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={ -begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], -keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, -contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ -begin:"\x3c!--|--\x3e"},{begin:""}]}] -}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", -end:"$",keywords:{ -keyword:"if else elif endif define undef warning error line region endregion pragma checksum" -}},g,i,{beginKeywords:"class interface",relevance:0,end:/[{;=]/, -illegal:/[^\s:,]/,contains:[{beginKeywords:"where class" -},a,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", -relevance:0,end:/[{;=]/,illegal:/[^\s:]/, -contains:[a,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ -beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/, -contains:[a,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", -begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ -className:"string",begin:/"/,end:/"/}]},{ -beginKeywords:"new return throw await else",relevance:0},{className:"function", -begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, -end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ -beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial", -relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, -contains:[e.TITLE_MODE,E],relevance:0},{match:/\(\)/},{className:"params", -begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, -contains:[g,i,e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}})() -;hljs.registerLanguage("csharp",e)})();/*! `css` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict" -;const e=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],i=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],r=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],t=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],o=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse() -;return n=>{const a=n.regex,l=(e=>({IMPORTANT:{scope:"meta",begin:"!important"}, -BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{scope:"number", -begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/},FUNCTION_DISPATCH:{ -className:"built_in",begin:/[\w-]+(?=\()/},ATTRIBUTE_SELECTOR_MODE:{ -scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", -contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{ -scope:"number", -begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", -relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z][A-Za-z0-9_-]*/} -}))(n),s=[n.APOS_STRING_MODE,n.QUOTE_STRING_MODE];return{name:"CSS", -case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"}, -classNameAliases:{keyframePosition:"selector-tag"},contains:[l.BLOCK_COMMENT,{ -begin:/-(webkit|moz|ms|o)-(?=[a-z])/},l.CSS_NUMBER_MODE,{ -className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0},{ -className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 -},l.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ -begin:":("+r.join("|")+")"},{begin:":(:)?("+t.join("|")+")"}]},l.CSS_VARIABLE,{ -className:"attribute",begin:"\\b("+o.join("|")+")\\b"},{begin:/:/,end:/[;}{]/, -contains:[l.BLOCK_COMMENT,l.HEXCOLOR,l.IMPORTANT,l.CSS_NUMBER_MODE,...s,{ -begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" -},contains:[...s,{className:"string",begin:/[^)]/,endsWithParent:!0, -excludeEnd:!0}]},l.FUNCTION_DISPATCH]},{begin:a.lookahead(/@/),end:"[{;]", -relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/ -},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{ -$pattern:/[a-z-]+/,keyword:"and or not only",attribute:i.join(" ")},contains:[{ -begin:/[a-z-]+(?=:)/,className:"attribute"},...s,l.CSS_NUMBER_MODE]}]},{ -className:"selector-tag",begin:"\\b("+e.join("|")+")\\b"}]}}})() -;hljs.registerLanguage("css",e)})();/*! `dart` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{const n={className:"subst",variants:[{ -begin:"\\$[A-Za-z0-9_]+"}]},a={className:"subst",variants:[{begin:/\$\{/, -end:/\}/}],keywords:"true false null this is new super"},t={className:"string", -variants:[{begin:"r'''",end:"'''"},{begin:'r"""',end:'"""'},{begin:"r'",end:"'", -illegal:"\\n"},{begin:'r"',end:'"',illegal:"\\n"},{begin:"'''",end:"'''", -contains:[e.BACKSLASH_ESCAPE,n,a]},{begin:'"""',end:'"""', -contains:[e.BACKSLASH_ESCAPE,n,a]},{begin:"'",end:"'",illegal:"\\n", -contains:[e.BACKSLASH_ESCAPE,n,a]},{begin:'"',end:'"',illegal:"\\n", -contains:[e.BACKSLASH_ESCAPE,n,a]}]};a.contains=[e.C_NUMBER_MODE,t] -;const i=["Comparable","DateTime","Duration","Function","Iterable","Iterator","List","Map","Match","Object","Pattern","RegExp","Set","Stopwatch","String","StringBuffer","StringSink","Symbol","Type","Uri","bool","double","int","num","Element","ElementList"],r=i.map((e=>e+"?")) -;return{name:"Dart",keywords:{ -keyword:["abstract","as","assert","async","await","base","break","case","catch","class","const","continue","covariant","default","deferred","do","dynamic","else","enum","export","extends","extension","external","factory","false","final","finally","for","Function","get","hide","if","implements","import","in","interface","is","late","library","mixin","new","null","on","operator","part","required","rethrow","return","sealed","set","show","static","super","switch","sync","this","throw","true","try","typedef","var","void","when","while","with","yield"], -built_in:i.concat(r).concat(["Never","Null","dynamic","print","document","querySelector","querySelectorAll","window"]), -$pattern:/[A-Za-z][A-Za-z0-9_]*\??/}, -contains:[t,e.COMMENT(/\/\*\*(?!\/)/,/\*\//,{subLanguage:"markdown",relevance:0 -}),e.COMMENT(/\/{3,} ?/,/$/,{contains:[{subLanguage:"markdown",begin:".", -end:"$",relevance:0}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{ -className:"class",beginKeywords:"class interface",end:/\{/,excludeEnd:!0, -contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE] -},e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"},{begin:"=>"}]}}})() -;hljs.registerLanguage("dart",e)})();/*! `dockerfile` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>({name:"Dockerfile",aliases:["docker"], -case_insensitive:!0, -keywords:["from","maintainer","expose","env","arg","user","onbuild","stopsignal"], -contains:[e.HASH_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{ -beginKeywords:"run cmd entrypoint volume add copy workdir label healthcheck shell", -starts:{end:/[^\\]$/,subLanguage:"bash"}}],illegal:"{var e=(()=>{"use strict";function e(e){ -return RegExp(e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function n(e){ -return e?"string"==typeof e?e:e.source:null}function t(e){return i("(?=",e,")")} -function i(...e){return e.map((e=>n(e))).join("")}function a(...e){const t=(e=>{ -const n=e[e.length-1] -;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} -})(e);return"("+(t.capture?"":"?:")+e.map((e=>n(e))).join("|")+")"}return n=>{ -const r={scope:"keyword",match:/\b(yield|return|let|do|match|use)!/ -},o=["bool","byte","sbyte","int8","int16","int32","uint8","uint16","uint32","int","uint","int64","uint64","nativeint","unativeint","decimal","float","double","float32","single","char","string","unit","bigint","option","voption","list","array","seq","byref","exn","inref","nativeptr","obj","outref","voidptr","Result"],s={ -keyword:["abstract","and","as","assert","base","begin","class","default","delegate","do","done","downcast","downto","elif","else","end","exception","extern","finally","fixed","for","fun","function","global","if","in","inherit","inline","interface","internal","lazy","let","match","member","module","mutable","namespace","new","of","open","or","override","private","public","rec","return","static","struct","then","to","try","type","upcast","use","val","void","when","while","with","yield"], -literal:["true","false","null","Some","None","Ok","Error","infinity","infinityf","nan","nanf"], -built_in:["not","ref","raise","reraise","dict","readOnlyDict","set","get","enum","sizeof","typeof","typedefof","nameof","nullArg","invalidArg","invalidOp","id","fst","snd","ignore","lock","using","box","unbox","tryUnbox","printf","printfn","sprintf","eprintf","eprintfn","fprintf","fprintfn","failwith","failwithf"], -"variable.constant":["__LINE__","__SOURCE_DIRECTORY__","__SOURCE_FILE__"]},c={ -variants:[n.COMMENT(/\(\*(?!\))/,/\*\)/,{contains:["self"] -}),n.C_LINE_COMMENT_MODE]},l={scope:"variable",begin:/``/,end:/``/ -},u=/\B('|\^)/,p={scope:"symbol",variants:[{match:i(u,/``.*?``/)},{ -match:i(u,n.UNDERSCORE_IDENT_RE)}],relevance:0},f=({includeEqual:n})=>{let r -;r=n?"!%&*+-/<=>@^|~?":"!%&*+-/<>@^|~?" -;const o=i("[",...Array.from(r).map(e),"]"),s=a(o,/\./),c=i(s,t(s)),l=a(i(c,s,"*"),i(o,"+")) -;return{scope:"operator",match:a(l,/:\?>/,/:\?/,/:>/,/:=/,/::?/,/\$/), -relevance:0}},d=f({includeEqual:!0}),b=f({includeEqual:!1}),g=(e,r)=>({ -begin:i(e,t(i(/\s*/,a(/\w/,/'/,/\^/,/#/,/``/,/\(/,/{\|/)))),beginScope:r, -end:t(a(/\n/,/=/)),relevance:0,keywords:n.inherit(s,{type:o}), -contains:[c,p,n.inherit(l,{scope:null}),b] -}),m=g(/:/,"operator"),h=g(/\bof\b/,"keyword"),y={ -begin:[/(^|\s+)/,/type/,/\s+/,/[a-zA-Z_](\w|')*/],beginScope:{2:"keyword", -4:"title.class"},end:t(/\(|=|$/),keywords:s,contains:[c,n.inherit(l,{scope:null -}),p,{scope:"operator",match:/<|>/},m]},E={scope:"computation-expression", -match:/\b[_a-z]\w*(?=\s*\{)/},_={ -begin:[/^\s*/,i(/#/,a("if","else","endif","line","nowarn","light","r","i","I","load","time","help","quit")),/\b/], -beginScope:{2:"meta"},end:t(/\s|$/)},v={ -variants:[n.BINARY_NUMBER_MODE,n.C_NUMBER_MODE]},w={scope:"string",begin:/"/, -end:/"/,contains:[n.BACKSLASH_ESCAPE]},A={scope:"string",begin:/@"/,end:/"/, -contains:[{match:/""/},n.BACKSLASH_ESCAPE]},S={scope:"string",begin:/"""/, -end:/"""/,relevance:2},C={scope:"subst",begin:/\{/,end:/\}/,keywords:s},O={ -scope:"string",begin:/\$"/,end:/"/,contains:[{match:/\{\{/},{match:/\}\}/ -},n.BACKSLASH_ESCAPE,C]},R={scope:"string",begin:/(\$@|@\$)"/,end:/"/, -contains:[{match:/\{\{/},{match:/\}\}/},{match:/""/},n.BACKSLASH_ESCAPE,C]},k={ -scope:"string",begin:/\$"""/,end:/"""/,contains:[{match:/\{\{/},{match:/\}\}/ -},C],relevance:2},x={scope:"string", -match:i(/'/,a(/[^\\']/,/\\(?:.|\d{3}|x[a-fA-F\d]{2}|u[a-fA-F\d]{4}|U[a-fA-F\d]{8})/),/'/) -};return C.contains=[R,O,A,w,x,r,c,l,m,E,_,v,p,d],{name:"F#", -aliases:["fs","f#"],keywords:s,illegal:/\/\*/,classNameAliases:{ -"computation-expression":"keyword"},contains:[r,{variants:[k,R,O,S,A,w,x] -},c,l,y,{scope:"meta",begin:/\[\]/,relevance:2,contains:[l,S,A,w,x,v] -},h,m,E,_,v,p,d]}}})();hljs.registerLanguage("fsharp",e)})();/*! `go` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{const n={ -keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"], -type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"], -literal:["true","false","iota","nil"], -built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"] -};return{name:"Go",aliases:["golang"],keywords:n,illegal:"{var e=(()=>{"use strict";return e=>{const n=e.regex,a={className:"number", -relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{begin:e.NUMBER_RE}] -},s=e.COMMENT();s.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];const i={ -className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)\}/ -}]},t={className:"literal",begin:/\bon|off|true|false|yes|no\b/},r={ -className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''", -end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"' -},{begin:"'",end:"'"}]},l={begin:/\[/,end:/\]/,contains:[s,t,i,r,a,"self"], -relevance:0},c=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{ -name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, -contains:[s,{className:"section",begin:/\[+/,end:/\]+/},{ -begin:n.concat(c,"(\\s*\\.\\s*",c,")*",n.lookahead(/\s*=\s*[^#\s]/)), -className:"attr",starts:{end:/$/,contains:[s,l,t,i,r,a]}}]}}})() -;hljs.registerLanguage("ini",e)})();/*! `java` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict" -;var e="[0-9](_*[0-9])*",a=`\\.(${e})`,n="[0-9a-fA-F](_*[0-9a-fA-F])*",s={ -className:"number",variants:[{ -begin:`(\\b(${e})((${a})|\\.)?|(${a}))[eE][+-]?(${e})[fFdD]?\\b`},{ -begin:`\\b(${e})((${a})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${a})[fFdD]?\\b` -},{begin:`\\b(${e})[fFdD]\\b`},{ -begin:`\\b0[xX]((${n})\\.?|(${n})?\\.(${n}))[pP][+-]?(${e})[fFdD]?\\b`},{ -begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${n})[lL]?\\b`},{ -begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], -relevance:0};function t(e,a,n){return-1===n?"":e.replace(a,(s=>t(e,a,n-1)))} -return e=>{ -const a=e.regex,n="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",i=n+t("(?:<"+n+"~~~(?:\\s*,\\s*"+n+"~~~)*>)?",/~~~/g,2),r={ -keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits"], -literal:["false","true","null"], -type:["char","boolean","long","float","int","byte","short","double"], -built_in:["super","this"]},l={className:"meta",begin:"@"+n,contains:[{ -begin:/\(/,end:/\)/,contains:["self"]}]},c={className:"params",begin:/\(/, -end:/\)/,keywords:r,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} -;return{name:"Java",aliases:["jsp"],keywords:r,illegal:/<\/|#/, -contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, -relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ -begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, -className:"string",contains:[e.BACKSLASH_ESCAPE] -},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ -match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,n],className:{ -1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ -begin:[a.concat(/(?!else)/,n),/\s+/,n,/\s+/,/=(?!=)/],className:{1:"type", -3:"variable",5:"operator"}},{begin:[/record/,/\s+/,n],className:{1:"keyword", -3:"title.class"},contains:[c,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ -beginKeywords:"new throw return else",relevance:0},{ -begin:["(?:"+i+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ -2:"title.function"},keywords:r,contains:[{className:"params",begin:/\(/, -end:/\)/,keywords:r,relevance:0, -contains:[l,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,s,e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},s,l]}}})() -;hljs.registerLanguage("java",e)})();/*! `javascript` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict" -;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],t=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],s=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],r=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],c=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],i=[].concat(r,t,s) -;return o=>{const l=o.regex,b=e,d={begin:/<[A-Za-z0-9\\._:-]+/, -end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ -const a=e[0].length+e.index,t=e.input[a] -;if("<"===t||","===t)return void n.ignoreMatch();let s -;">"===t&&(((e,{after:n})=>{const a="",$={ -match:[/const|var|let/,/\s+/,b,/\s*/,/=\s*/,/(async\s*)?/,l.lookahead(B)], -keywords:"async",className:{1:"keyword",3:"title.function"},contains:[R]} -;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:g,exports:{ -PARAMS_CONTAINS:w,CLASS_REFERENCE:k},illegal:/#(?![$_A-z])/, -contains:[o.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ -label:"use_strict",className:"meta",relevance:10, -begin:/^\s*['"]use (strict|asm)['"]/ -},o.APOS_STRING_MODE,o.QUOTE_STRING_MODE,h,N,_,f,v,{match:/\$\d+/},A,k,{ -className:"attr",begin:b+l.lookahead(":"),relevance:0},$,{ -begin:"("+o.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", -keywords:"return throw case",relevance:0,contains:[v,o.REGEXP_MODE,{ -className:"function",begin:B,returnBegin:!0,end:"\\s*=>",contains:[{ -className:"params",variants:[{begin:o.UNDERSCORE_IDENT_RE,relevance:0},{ -className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0, -excludeEnd:!0,keywords:g,contains:w}]}]},{begin:/,/,relevance:0},{match:/\s+/, -relevance:0},{variants:[{begin:"<>",end:""},{ -match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:d.begin, -"on:begin":d.isTrulyOpeningTag,end:d.end}],subLanguage:"xml",contains:[{ -begin:d.begin,end:d.end,skip:!0,contains:["self"]}]}]},I,{ -beginKeywords:"while if switch catch for"},{ -begin:"\\b(?!function)"+o.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", -returnBegin:!0,label:"func.def",contains:[R,o.inherit(o.TITLE_MODE,{begin:b, -className:"title.function"})]},{match:/\.\.\./,relevance:0},C,{match:"\\$"+b, -relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, -contains:[R]},x,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, -className:"variable.constant"},O,M,{match:/\$[(.]/}]}}})() -;hljs.registerLanguage("javascript",e)})();/*! `json` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{const a=["true","false","null"],n={ -scope:"literal",beginKeywords:a.join(" ")};return{name:"JSON",keywords:{ -literal:a},contains:[{className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/, -relevance:1.01},{match:/[{}[\],:]/,className:"punctuation",relevance:0 -},e.QUOTE_STRING_MODE,n,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], -illegal:"\\S"}}})();hljs.registerLanguage("json",e)})();/*! `kotlin` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict" -;var e="[0-9](_*[0-9])*",n=`\\.(${e})`,a="[0-9a-fA-F](_*[0-9a-fA-F])*",i={ -className:"number",variants:[{ -begin:`(\\b(${e})((${n})|\\.)?|(${n}))[eE][+-]?(${e})[fFdD]?\\b`},{ -begin:`\\b(${e})((${n})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${n})[fFdD]?\\b` -},{begin:`\\b(${e})[fFdD]\\b`},{ -begin:`\\b0[xX]((${a})\\.?|(${a})?\\.(${a}))[pP][+-]?(${e})[fFdD]?\\b`},{ -begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${a})[lL]?\\b`},{ -begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], -relevance:0};return e=>{const n={ -keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", -built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", -literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" -},s={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},t={ -className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", -variants:[{begin:'"""',end:'"""(?=[^"])',contains:[t,s]},{begin:"'",end:"'", -illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, -contains:[e.BACKSLASH_ESCAPE,t,s]}]};s.contains.push(r);const l={ -className:"meta", -begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" -},c={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, -end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}] -},o=i,b=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),E={ -variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, -contains:[]}]},d=E;return d.variants[1].contains=[E],E.variants[1].contains=[d], -{name:"Kotlin",aliases:["kt","kts"],keywords:n, -contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", -begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,b,{className:"keyword", -begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", -begin:/@\w+/}]}},a,l,c,{className:"function",beginKeywords:"fun",end:"[(]|$", -returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ -begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, -contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, -keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, -endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, -endsWithParent:!0,contains:[E,e.C_LINE_COMMENT_MODE,b],relevance:0 -},e.C_LINE_COMMENT_MODE,b,l,c,r,e.C_NUMBER_MODE]},b]},{ -begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{ -3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, -illegal:"extends implements",contains:[{ -beginKeywords:"public protected internal private constructor" -},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, -excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/, -excludeBegin:!0,returnEnd:!0},l,c]},r,{className:"meta",begin:"^#!/usr/bin/env", -end:"$",illegal:"\n"},o]}}})();hljs.registerLanguage("kotlin",e)})();/*! `lisp` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{ -const n="[a-zA-Z_\\-+\\*\\/<=>&#][a-zA-Z0-9_\\-+*\\/<=>&#!]*",a="\\|[^]*?\\|",i="(-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s|D|E|F|L|S)(\\+|-)?\\d+)?",s={ -className:"literal",begin:"\\b(t{1}|nil)\\b"},l={className:"number",variants:[{ -begin:i,relevance:0},{begin:"#(b|B)[0-1]+(/[0-1]+)?"},{ -begin:"#(o|O)[0-7]+(/[0-7]+)?"},{begin:"#(x|X)[0-9a-fA-F]+(/[0-9a-fA-F]+)?"},{ -begin:"#(c|C)\\("+i+" +"+i,end:"\\)"}]},b=e.inherit(e.QUOTE_STRING_MODE,{ -illegal:null}),g=e.COMMENT(";","$",{relevance:0}),r={begin:"\\*",end:"\\*"},t={ -className:"symbol",begin:"[:&]"+n},c={begin:n,relevance:0},d={begin:a},o={ -contains:[l,b,r,t,{begin:"\\(",end:"\\)",contains:["self",s,b,l,c]},c], -variants:[{begin:"['`]\\(",end:"\\)"},{begin:"\\(quote ",end:"\\)",keywords:{ -name:"quote"}},{begin:"'"+a}]},v={variants:[{begin:"'"+n},{ -begin:"#'"+n+"(::"+n+")*"}]},m={begin:"\\(\\s*",end:"\\)"},u={endsWithParent:!0, -relevance:0};return m.contains=[{className:"name",variants:[{begin:n,relevance:0 -},{begin:a}]},u],u.contains=[o,v,m,s,l,b,g,r,t,d,c],{name:"Lisp",illegal:/\S/, -contains:[l,e.SHEBANG(),s,b,g,o,v,m,c]}}})();hljs.registerLanguage("lisp",e) -})();/*! `markdown` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{const n={begin:/<\/?[A-Za-z_]/, -end:">",subLanguage:"xml",relevance:0},a={variants:[{begin:/\[.+?\]\[.*?\]/, -relevance:0},{ -begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, -relevance:2},{ -begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), -relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ -begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/ -},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, -returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", -excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", -end:"\\]",excludeBegin:!0,excludeEnd:!0}]},i={className:"strong",contains:[], -variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}] -},s={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{ -begin:/_(?![_\s])/,end:/_/,relevance:0}]},c=e.inherit(i,{contains:[] -}),t=e.inherit(s,{contains:[]});i.contains.push(t),s.contains.push(c) -;let g=[n,a];return[i,s,c,t].forEach((e=>{e.contains=e.contains.concat(g) -})),g=g.concat(i,s),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ -className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:g},{ -begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", -contains:g}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", -end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:g, -end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ -begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ -begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", -contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ -begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ -className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ -className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}})() -;hljs.registerLanguage("markdown",e)})();/*! `php` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{ -const t=e.regex,a=/(?![A-Za-z0-9])(?![$])/,r=t.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,a),n=t.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,a),o={ -scope:"variable",match:"\\$+"+r},c={scope:"subst",variants:[{begin:/\$\w+/},{ -begin:/\{\$/,end:/\}/}]},i=e.inherit(e.APOS_STRING_MODE,{illegal:null -}),s="[ \t\n]",l={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ -illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(c)}),i,{ -begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/, -contains:e.QUOTE_STRING_MODE.contains.concat(c),"on:begin":(e,t)=>{ -t.data._beginMatch=e[1]||e[2]},"on:end":(e,t)=>{ -t.data._beginMatch!==e[1]&&t.ignoreMatch()}},e.END_SAME_AS_BEGIN({ -begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},d={scope:"number",variants:[{ -begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ -begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ -begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" -}],relevance:0 -},_=["false","null","true"],p=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],E={ -keyword:p,literal:(e=>{const t=[];return e.forEach((e=>{ -t.push(e),e.toLowerCase()===e?t.push(e.toUpperCase()):t.push(e.toLowerCase()) -})),t})(_),built_in:b},u=e=>e.map((e=>e.replace(/\|\d+$/,""))),g={variants:[{ -match:[/new/,t.concat(s,"+"),t.concat("(?!",u(b).join("\\b|"),"\\b)"),n],scope:{ -1:"keyword",4:"title.class"}}]},h=t.concat(r,"\\b(?!\\()"),m={variants:[{ -match:[t.concat(/::/,t.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant" -}},{match:[/::/,/class/],scope:{2:"variable.language"}},{ -match:[n,t.concat(/::/,t.lookahead(/(?!class\b)/)),h],scope:{1:"title.class", -3:"variable.constant"}},{match:[n,t.concat("::",t.lookahead(/(?!class\b)/))], -scope:{1:"title.class"}},{match:[n,/::/,/class/],scope:{1:"title.class", -3:"variable.language"}}]},I={scope:"attr", -match:t.concat(r,t.lookahead(":"),t.lookahead(/(?!::)/))},f={relevance:0, -begin:/\(/,end:/\)/,keywords:E,contains:[I,o,m,e.C_BLOCK_COMMENT_MODE,l,d,g] -},O={relevance:0, -match:[/\b/,t.concat("(?!fn\\b|function\\b|",u(p).join("\\b|"),"|",u(b).join("\\b|"),"\\b)"),r,t.concat(s,"*"),t.lookahead(/(?=\()/)], -scope:{3:"title.function.invoke"},contains:[f]};f.contains.push(O) -;const v=[I,m,e.C_BLOCK_COMMENT_MODE,l,d,g];return{case_insensitive:!1, -keywords:E,contains:[{begin:t.concat(/#\[\s*/,n),beginScope:"meta",end:/]/, -endScope:"meta",keywords:{literal:_,keyword:["new","array"]},contains:[{ -begin:/\[/,end:/]/,keywords:{literal:_,keyword:["new","array"]}, -contains:["self",...v]},...v,{scope:"meta",match:n}] -},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{ -scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, -keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, -contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ -begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ -begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},o,O,m,{ -match:[/const/,/\s/,r],scope:{1:"keyword",3:"variable.constant"}},g,{ -scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, -excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" -},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", -begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:E, -contains:["self",o,m,e.C_BLOCK_COMMENT_MODE,l,d]}]},{scope:"class",variants:[{ -beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", -illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ -beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ -beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, -contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ -beginKeywords:"use",relevance:0,end:";",contains:[{ -match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},l,d]} -}})();hljs.registerLanguage("php",e)})();/*! `python` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{ -const n=e.regex,a=/[\p{XID_Start}_]\p{XID_Continue}*/u,i=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],s={ -$pattern:/[A-Za-z]\w+|__\w+__/,keyword:i, -built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"], -literal:["__debug__","Ellipsis","False","None","NotImplemented","True"], -type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"] -},t={className:"meta",begin:/^(>>>|\.\.\.) /},r={className:"subst",begin:/\{/, -end:/\}/,keywords:s,illegal:/#/},l={begin:/\{\{/,relevance:0},b={ -className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ -begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, -contains:[e.BACKSLASH_ESCAPE,t],relevance:10},{ -begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, -contains:[e.BACKSLASH_ESCAPE,t],relevance:10},{ -begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, -contains:[e.BACKSLASH_ESCAPE,t,l,r]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, -end:/"""/,contains:[e.BACKSLASH_ESCAPE,t,l,r]},{begin:/([uU]|[rR])'/,end:/'/, -relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ -begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, -end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, -contains:[e.BACKSLASH_ESCAPE,l,r]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, -contains:[e.BACKSLASH_ESCAPE,l,r]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] -},o="[0-9](_?[0-9])*",c=`(\\b(${o}))?\\.(${o})|\\b(${o})\\.`,d="\\b|"+i.join("|"),g={ -className:"number",relevance:0,variants:[{ -begin:`(\\b(${o})|(${c}))[eE][+-]?(${o})[jJ]?(?=${d})`},{begin:`(${c})[jJ]?`},{ -begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${d})`},{ -begin:`\\b0[bB](_?[01])+[lL]?(?=${d})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${d})` -},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${d})`},{begin:`\\b(${o})[jJ](?=${d})` -}]},p={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:s, -contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={ -className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/, -end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:s, -contains:["self",t,g,b,e.HASH_COMMENT_MODE]}]};return r.contains=[b,g,t],{ -name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:s, -illegal:/(<\/|\?)|=>/,contains:[t,g,{begin:/\bself\b/},{beginKeywords:"if", -relevance:0},b,p,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,a],scope:{ -1:"keyword",3:"title.function"},contains:[m]},{variants:[{ -match:[/\bclass/,/\s+/,a,/\s*/,/\(\s*/,a,/\s*\)/]},{match:[/\bclass/,/\s+/,a]}], -scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{ -className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[g,m,b]}]}}})() -;hljs.registerLanguage("python",e)})();/*! `ruby` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{ -const n=e.regex,a="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",s=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(s,/(::\w+)*/),t={ -"variable.constant":["__FILE__","__LINE__","__ENCODING__"], -"variable.language":["self","super"], -keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield","include","extend","prepend","public","private","protected","raise","throw"], -built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"], -literal:["true","false","nil"]},c={className:"doctag",begin:"@[A-Za-z]+"},r={ -begin:"#<",end:">"},b=[e.COMMENT("#","$",{contains:[c] -}),e.COMMENT("^=begin","^=end",{contains:[c],relevance:10 -}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],l={className:"subst",begin:/#\{/, -end:/\}/,keywords:t},d={className:"string",contains:[e.BACKSLASH_ESCAPE,l], -variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ -begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{ -begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//, -end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{ -begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{ -begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ -begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ -begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ -begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), -contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, -contains:[e.BACKSLASH_ESCAPE,l]})]}]},o="[0-9](_?[0-9])*",g={className:"number", -relevance:0,variants:[{ -begin:`\\b([1-9](_?[0-9])*|0)(\\.(${o}))?([eE][+-]?(${o})|r)?i?\\b`},{ -begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" -},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ -begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ -begin:"\\b0(_?[0-7])+r?i?\\b"}]},_={variants:[{match:/\(\)/},{ -className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0, -keywords:t}]},u=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{ -match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class", -4:"title.class.inherited"},keywords:t},{match:[/(include|extend)\s+/,i],scope:{ -2:"title.class"},keywords:t},{relevance:0,match:[i,/\.new[. (]/],scope:{ -1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, -className:"variable.constant"},{relevance:0,match:s,scope:"title.class"},{ -match:[/def/,/\s+/,a],scope:{1:"keyword",3:"title.function"},contains:[_]},{ -begin:e.IDENT_RE+"::"},{className:"symbol", -begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", -begin:":(?!\\s)",contains:[d,{begin:a}],relevance:0},g,{className:"variable", -begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ -className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0, -relevance:0,keywords:t},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", -keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,l], -illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{ -begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[", -end:"\\][a-z]*"}]}].concat(r,b),relevance:0}].concat(r,b) -;l.contains=u,_.contains=u;const m=[{begin:/^\s*=>/,starts:{end:"$",contains:u} -},{className:"meta.prompt", -begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", -starts:{end:"$",keywords:t,contains:u}}];return b.unshift(r),{name:"Ruby", -aliases:["rb","gemspec","podspec","thor","irb"],keywords:t,illegal:/\/\*/, -contains:[e.SHEBANG({binary:"ruby"})].concat(m).concat(b).concat(u)}}})() -;hljs.registerLanguage("ruby",e)})();/*! `rust` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{const t=e.regex,a={ -className:"title.function.invoke",relevance:0, -begin:t.concat(/\b/,/(?!let\b)/,e.IDENT_RE,t.lookahead(/\s*\(/)) -},n="([ui](8|16|32|64|128|size)|f(32|64))?",s=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],r=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"] -;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:r, -keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"], -literal:["true","false","Some","None","Ok","Err"],built_in:s},illegal:""},a]}}})() -;hljs.registerLanguage("rust",e)})();/*! `shell` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var s=(()=>{"use strict";return s=>({name:"Shell Session", -aliases:["console","shellsession"],contains:[{className:"meta.prompt", -begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/, -subLanguage:"bash"}}]})})();hljs.registerLanguage("shell",s)})();/*! `sql` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{ -const r=e.regex,t=e.COMMENT("--","$"),n=["true","false","unknown"],a=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],i=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=i,c=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!i.includes(e))),l={ -begin:r.concat(/\b/,r.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}} -;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ -$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:r,when:t}={})=>{const n=t -;return r=r||[],e.map((e=>e.match(/\|\d+$/)||r.includes(e)?e:n(e)?e+"|0":e)) -})(c,{when:e=>e.length<3}),literal:n,type:a, -built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] -},contains:[{begin:r.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/, -keyword:c.concat(s),literal:n,type:a}},{className:"type", -begin:r.either("double precision","large object","with timezone","without timezone") -},l,{className:"variable",begin:/@[a-z0-9][a-z0-9_]*/},{className:"string", -variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/, -contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{ -className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, -relevance:0}]}}})();hljs.registerLanguage("sql",e)})();/*! `swift` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";function e(e){ -return e?"string"==typeof e?e:e.source:null}function a(e){return t("(?=",e,")")} -function t(...a){return a.map((a=>e(a))).join("")}function n(...a){const t=(e=>{ -const a=e[e.length-1] -;return"object"==typeof a&&a.constructor===Object?(e.splice(e.length-1,1),a):{} -})(a);return"("+(t.capture?"":"?:")+a.map((a=>e(a))).join("|")+")"} -const i=e=>t(/\b/,e,/\w$/.test(e)?/\b/:/\B/),s=["Protocol","Type"].map(i),u=["init","self"].map(i),c=["Any","Self"],r=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","break","case","catch","class","continue","convenience","default","defer","deinit","didSet","distributed","do","dynamic","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],o=["false","nil","true"],l=["assignment","associativity","higherThan","left","lowerThan","none","right"],m=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warn_unqualified_access","#warning"],p=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],d=n(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),F=n(d,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),b=t(d,F,"*"),h=n(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),f=n(h,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),w=t(h,f,"*"),y=t(/[A-Z]/,f,"*"),g=["autoclosure",t(/convention\(/,n("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",t(/objc\(/,w,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","testable","UIApplicationMain","unknown","usableFromInline"],E=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] -;return e=>{const d={match:/\s+/,relevance:0},h=e.COMMENT("/\\*","\\*/",{ -contains:["self"]}),v=[e.C_LINE_COMMENT_MODE,h],A={match:[/\./,n(...s,...u)], -className:{2:"keyword"}},N={match:t(/\./,n(...r)),relevance:0 -},C=r.filter((e=>"string"==typeof e)).concat(["_|0"]),D={variants:[{ -className:"keyword", -match:n(...r.filter((e=>"string"!=typeof e)).concat(c).map(i),...u)}]},k={ -$pattern:n(/\b\w+/,/#\w+/),keyword:C.concat(m),literal:o},B=[A,N,D],_=[{ -match:t(/\./,n(...p)),relevance:0},{className:"built_in", -match:t(/\b/,n(...p),/(?=\()/)}],S={match:/->/,relevance:0},M=[S,{ -className:"operator",relevance:0,variants:[{match:b},{match:`\\.(\\.|${F})+`}] -}],x="([0-9]_*)+",$="([0-9a-fA-F]_*)+",I={className:"number",relevance:0, -variants:[{match:`\\b(${x})(\\.(${x}))?([eE][+-]?(${x}))?\\b`},{ -match:`\\b0x(${$})(\\.(${$}))?([pP][+-]?(${x}))?\\b`},{match:/\b0o([0-7]_*)+\b/ -},{match:/\b0b([01]_*)+\b/}]},L=(e="")=>({className:"subst",variants:[{ -match:t(/\\/,e,/[0\\tnr"']/)},{match:t(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}] -}),O=(e="")=>({className:"subst",match:t(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/) -}),T=(e="")=>({className:"subst",label:"interpol",begin:t(/\\/,e,/\(/),end:/\)/ -}),j=(e="")=>({begin:t(e,/"""/),end:t(/"""/,e),contains:[L(e),O(e),T(e)] -}),P=(e="")=>({begin:t(e,/"/),end:t(/"/,e),contains:[L(e),T(e)]}),K={ -className:"string", -variants:[j(),j("#"),j("##"),j("###"),P(),P("#"),P("##"),P("###")]},z={ -match:t(/`/,w,/`/)},q=[z,{className:"variable",match:/\$\d+/},{ -className:"variable",match:`\\$${f}+`}],U=[{match:/(@|#(un)?)available/, -className:"keyword",starts:{contains:[{begin:/\(/,end:/\)/,keywords:E, -contains:[...M,I,K]}]}},{className:"keyword",match:t(/@/,n(...g))},{ -className:"meta",match:t(/@/,w)}],Z={match:a(/\b[A-Z]/),relevance:0,contains:[{ -className:"type", -match:t(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,f,"+") -},{className:"type",match:y,relevance:0},{match:/[?!]+/,relevance:0},{ -match:/\.\.\./,relevance:0},{match:t(/\s+&\s+/,a(y)),relevance:0}]},V={ -begin://,keywords:k,contains:[...v,...B,...U,S,Z]};Z.contains.push(V) -;const W={begin:/\(/,end:/\)/,relevance:0,keywords:k,contains:["self",{ -match:t(w,/\s*:/),keywords:"_|0",relevance:0 -},...v,...B,..._,...M,I,K,...q,...U,Z]},G={begin://,contains:[...v,Z] -},R={begin:/\(/,end:/\)/,keywords:k,contains:[{ -begin:n(a(t(w,/\s*:/)),a(t(w,/\s+/,w,/\s*:/))),end:/:/,relevance:0,contains:[{ -className:"keyword",match:/\b_\b/},{className:"params",match:w}] -},...v,...B,...M,I,K,...U,Z,W],endsParent:!0,illegal:/["']/},X={ -match:[/func/,/\s+/,n(z.match,w,b)],className:{1:"keyword",3:"title.function"}, -contains:[G,R,d],illegal:[/\[/,/%/]},H={ -match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, -contains:[G,R,d],illegal:/\[|%/},J={match:[/operator/,/\s+/,b],className:{ -1:"keyword",3:"title"}},Q={begin:[/precedencegroup/,/\s+/,y],className:{ -1:"keyword",3:"title"},contains:[Z],keywords:[...l,...o],end:/}/} -;for(const e of K.variants){const a=e.contains.find((e=>"interpol"===e.label)) -;a.keywords=k;const t=[...B,..._,...M,I,K,...q];a.contains=[...t,{begin:/\(/, -end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:k, -contains:[...v,X,H,{beginKeywords:"struct protocol class extension enum actor", -end:"\\{",excludeEnd:!0,keywords:k,contains:[e.inherit(e.TITLE_MODE,{ -className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...B] -},J,Q,{beginKeywords:"import",end:/$/,contains:[...v],relevance:0 -},...B,..._,...M,I,K,...q,...U,Z,W]}}})();hljs.registerLanguage("swift",e)})();/*! `typescript` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict" -;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],t=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],s=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],r=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],c=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],i=[].concat(r,t,s) -;function o(o){const l=o.regex,d=e,b={begin:/<[A-Za-z0-9\\._:-]+/, -end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ -const a=e[0].length+e.index,t=e.input[a] -;if("<"===t||","===t)return void n.ignoreMatch();let s -;">"===t&&(((e,{after:n})=>{const a="",$={ -match:[/const|var|let/,/\s+/,d,/\s*/,/=\s*/,/(async\s*)?/,l.lookahead(B)], -keywords:"async",className:{1:"keyword",3:"title.function"},contains:[R]} -;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:g,exports:{ -PARAMS_CONTAINS:w,CLASS_REFERENCE:k},illegal:/#(?![$_A-z])/, -contains:[o.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ -label:"use_strict",className:"meta",relevance:10, -begin:/^\s*['"]use (strict|asm)['"]/ -},o.APOS_STRING_MODE,o.QUOTE_STRING_MODE,p,N,f,_,h,{match:/\$\d+/},y,k,{ -className:"attr",begin:d+l.lookahead(":"),relevance:0},$,{ -begin:"("+o.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", -keywords:"return throw case",relevance:0,contains:[h,o.REGEXP_MODE,{ -className:"function",begin:B,returnBegin:!0,end:"\\s*=>",contains:[{ -className:"params",variants:[{begin:o.UNDERSCORE_IDENT_RE,relevance:0},{ -className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0, -excludeEnd:!0,keywords:g,contains:w}]}]},{begin:/,/,relevance:0},{match:/\s+/, -relevance:0},{variants:[{begin:"<>",end:""},{ -match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:b.begin, -"on:begin":b.isTrulyOpeningTag,end:b.end}],subLanguage:"xml",contains:[{ -begin:b.begin,end:b.end,skip:!0,contains:["self"]}]}]},O,{ -beginKeywords:"while if switch catch for"},{ -begin:"\\b(?!function)"+o.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", -returnBegin:!0,label:"func.def",contains:[R,o.inherit(o.TITLE_MODE,{begin:d, -className:"title.function"})]},{match:/\.\.\./,relevance:0},T,{match:"\\$"+d, -relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, -contains:[R]},C,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, -className:"variable.constant"},x,M,{match:/\$[(.]/}]}}return t=>{ -const s=o(t),r=e,l=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],d={ -beginKeywords:"namespace",end:/\{/,excludeEnd:!0, -contains:[s.exports.CLASS_REFERENCE]},b={beginKeywords:"interface",end:/\{/, -excludeEnd:!0,keywords:{keyword:"interface extends",built_in:l}, -contains:[s.exports.CLASS_REFERENCE]},g={$pattern:e, -keyword:n.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]), -literal:a,built_in:i.concat(l),"variable.language":c},u={className:"meta", -begin:"@"+r},m=(e,n,a)=>{const t=e.contains.findIndex((e=>e.label===n)) -;if(-1===t)throw Error("can not find mode to replace");e.contains.splice(t,1,a)} -;return Object.assign(s.keywords,g), -s.exports.PARAMS_CONTAINS.push(u),s.contains=s.contains.concat([u,d,b]), -m(s,"shebang",t.SHEBANG()),m(s,"use_strict",{className:"meta",relevance:10, -begin:/^\s*['"]use strict['"]/ -}),s.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(s,{ -name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),s}})() -;hljs.registerLanguage("typescript",e)})();/*! `vbnet` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{ -const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,s=/\d{1,2}(:\d{1,2}){1,2}/,r={ -className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{ -begin:n.concat(/# */,s,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{ -begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,s),/ *#/)}] -},l=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}] -}),o=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]}) -;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0, -classNameAliases:{label:"symbol"},keywords:{ -keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield", -built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort", -type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort", -literal:"true false nothing"}, -illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{ -className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/, -end:/"/,illegal:/\n/,contains:[{begin:/""/}]},r,{className:"number",relevance:0, -variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ -},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{ -begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{ -className:"label",begin:/^\w+:/},l,o,{className:"meta", -begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, -end:/$/,keywords:{ -keyword:"const disable else elseif enable end externalsource if region then"}, -contains:[o]}]}}})();hljs.registerLanguage("vbnet",e)})();/*! `xml` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{ -const a=e.regex,n=a.concat(/[\p{L}_]/u,a.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),s={ -className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},t={begin:/\s/, -contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] -},i=e.inherit(t,{begin:/\(/,end:/\)/}),c=e.inherit(e.APOS_STRING_MODE,{ -className:"string"}),l=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),r={ -endsWithParent:!0,illegal:/`]+/}]}]}]};return{ -name:"HTML, XML", -aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], -case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[t,l,c,i,{begin:/\[/,end:/\]/,contains:[{ -className:"meta",begin://,contains:[t,i,l,c]}]}] -},e.COMMENT(//,{relevance:10}),{begin://, -relevance:10},s,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, -relevance:10,contains:[l]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"style"},contains:[r],starts:{ -end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"script"},contains:[r],starts:{ -end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ -className:"tag",begin:/<>|<\/>/},{className:"tag", -begin:a.concat(//,/>/,/\s/)))), -end:/\/?>/,contains:[{className:"name",begin:n,relevance:0,starts:r}]},{ -className:"tag",begin:a.concat(/<\//,a.lookahead(a.concat(n,/>/))),contains:[{ -className:"name",begin:n,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}} -})();hljs.registerLanguage("xml",e)})();/*! `yaml` grammar compiled for Highlight.js 11.8.0 */ -(()=>{var e=(()=>{"use strict";return e=>{ -const n="true false yes no null",a="[\\w#;/?:@&=+$,.~*'()[\\]]+",s={ -className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ -},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", -variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(s,{ -variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={ -end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},t={begin:/\{/, -end:/\}/,contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]", -contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{ -begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{ -begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$", -relevance:10},{className:"string", -begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ -begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, -relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type", -begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a -},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", -begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", -relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ -className:"number", -begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" -},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},t,g,s],r=[...b] -;return r.pop(),r.push(i),l.contains=r,{name:"YAML",case_insensitive:!0, -aliases:["yml"],contains:b}}})();hljs.registerLanguage("yaml",e)})(); \ No newline at end of file +var hljs = (function () { + 'use strict'; + + /* eslint-disable no-multi-assign */ + + function deepFreeze(obj) { + if (obj instanceof Map) { + obj.clear = + obj.delete = + obj.set = + function () { + throw new Error('map is read-only'); + }; + } else if (obj instanceof Set) { + obj.add = + obj.clear = + obj.delete = + function () { + throw new Error('set is read-only'); + }; + } + + // Freeze self + Object.freeze(obj); + + Object.getOwnPropertyNames(obj).forEach((name) => { + const prop = obj[name]; + const type = typeof prop; + + // Freeze prop if it is an object or function and also not already frozen + if ((type === 'object' || type === 'function') && !Object.isFrozen(prop)) { + deepFreeze(prop); + } + }); + + return obj; + } + + /** @typedef {import('highlight.js').CallbackResponse} CallbackResponse */ + /** @typedef {import('highlight.js').CompiledMode} CompiledMode */ + /** @implements CallbackResponse */ + + class Response { + /** + * @param {CompiledMode} mode + */ + constructor(mode) { + // eslint-disable-next-line no-undefined + if (mode.data === undefined) mode.data = {}; + + this.data = mode.data; + this.isMatchIgnored = false; + } + + ignoreMatch() { + this.isMatchIgnored = true; + } + } + + /** + * @param {string} value + * @returns {string} + */ + function escapeHTML(value) { + return value + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + + /** + * performs a shallow merge of multiple objects into one + * + * @template T + * @param {T} original + * @param {Record[]} objects + * @returns {T} a single new object + */ + function inherit$1(original, ...objects) { + /** @type Record */ + const result = Object.create(null); + + for (const key in original) { + result[key] = original[key]; + } + objects.forEach(function(obj) { + for (const key in obj) { + result[key] = obj[key]; + } + }); + return /** @type {T} */ (result); + } + + /** + * @typedef {object} Renderer + * @property {(text: string) => void} addText + * @property {(node: Node) => void} openNode + * @property {(node: Node) => void} closeNode + * @property {() => string} value + */ + + /** @typedef {{scope?: string, language?: string, sublanguage?: boolean}} Node */ + /** @typedef {{walk: (r: Renderer) => void}} Tree */ + /** */ + + const SPAN_CLOSE = ''; + + /** + * Determines if a node needs to be wrapped in + * + * @param {Node} node */ + const emitsWrappingTags = (node) => { + // rarely we can have a sublanguage where language is undefined + // TODO: track down why + return !!node.scope; + }; + + /** + * + * @param {string} name + * @param {{prefix:string}} options + */ + const scopeToCSSClass = (name, { prefix }) => { + // sub-language + if (name.startsWith("language:")) { + return name.replace("language:", "language-"); + } + // tiered scope: comment.line + if (name.includes(".")) { + const pieces = name.split("."); + return [ + `${prefix}${pieces.shift()}`, + ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`)) + ].join(" "); + } + // simple scope + return `${prefix}${name}`; + }; + + /** @type {Renderer} */ + class HTMLRenderer { + /** + * Creates a new HTMLRenderer + * + * @param {Tree} parseTree - the parse tree (must support `walk` API) + * @param {{classPrefix: string}} options + */ + constructor(parseTree, options) { + this.buffer = ""; + this.classPrefix = options.classPrefix; + parseTree.walk(this); + } + + /** + * Adds texts to the output stream + * + * @param {string} text */ + addText(text) { + this.buffer += escapeHTML(text); + } + + /** + * Adds a node open to the output stream (if needed) + * + * @param {Node} node */ + openNode(node) { + if (!emitsWrappingTags(node)) return; + + const className = scopeToCSSClass(node.scope, + { prefix: this.classPrefix }); + this.span(className); + } + + /** + * Adds a node close to the output stream (if needed) + * + * @param {Node} node */ + closeNode(node) { + if (!emitsWrappingTags(node)) return; + + this.buffer += SPAN_CLOSE; + } + + /** + * returns the accumulated buffer + */ + value() { + return this.buffer; + } + + // helpers + + /** + * Builds a span element + * + * @param {string} className */ + span(className) { + this.buffer += ``; + } + } + + /** @typedef {{scope?: string, language?: string, children: Node[]} | string} Node */ + /** @typedef {{scope?: string, language?: string, children: Node[]} } DataNode */ + /** @typedef {import('highlight.js').Emitter} Emitter */ + /** */ + + /** @returns {DataNode} */ + const newNode = (opts = {}) => { + /** @type DataNode */ + const result = { children: [] }; + Object.assign(result, opts); + return result; + }; + + class TokenTree { + constructor() { + /** @type DataNode */ + this.rootNode = newNode(); + this.stack = [this.rootNode]; + } + + get top() { + return this.stack[this.stack.length - 1]; + } + + get root() { return this.rootNode; } + + /** @param {Node} node */ + add(node) { + this.top.children.push(node); + } + + /** @param {string} scope */ + openNode(scope) { + /** @type Node */ + const node = newNode({ scope }); + this.add(node); + this.stack.push(node); + } + + closeNode() { + if (this.stack.length > 1) { + return this.stack.pop(); + } + // eslint-disable-next-line no-undefined + return undefined; + } + + closeAllNodes() { + while (this.closeNode()); + } + + toJSON() { + return JSON.stringify(this.rootNode, null, 4); + } + + /** + * @typedef { import("./html_renderer").Renderer } Renderer + * @param {Renderer} builder + */ + walk(builder) { + // this does not + return this.constructor._walk(builder, this.rootNode); + // this works + // return TokenTree._walk(builder, this.rootNode); + } + + /** + * @param {Renderer} builder + * @param {Node} node + */ + static _walk(builder, node) { + if (typeof node === "string") { + builder.addText(node); + } else if (node.children) { + builder.openNode(node); + node.children.forEach((child) => this._walk(builder, child)); + builder.closeNode(node); + } + return builder; + } + + /** + * @param {Node} node + */ + static _collapse(node) { + if (typeof node === "string") return; + if (!node.children) return; + + if (node.children.every(el => typeof el === "string")) { + // node.text = node.children.join(""); + // delete node.children; + node.children = [node.children.join("")]; + } else { + node.children.forEach((child) => { + TokenTree._collapse(child); + }); + } + } + } + + /** + Currently this is all private API, but this is the minimal API necessary + that an Emitter must implement to fully support the parser. + + Minimal interface: + + - addText(text) + - __addSublanguage(emitter, subLanguageName) + - startScope(scope) + - endScope() + - finalize() + - toHTML() + + */ + + /** + * @implements {Emitter} + */ + class TokenTreeEmitter extends TokenTree { + /** + * @param {*} options + */ + constructor(options) { + super(); + this.options = options; + } + + /** + * @param {string} text + */ + addText(text) { + if (text === "") { return; } + + this.add(text); + } + + /** @param {string} scope */ + startScope(scope) { + this.openNode(scope); + } + + endScope() { + this.closeNode(); + } + + /** + * @param {Emitter & {root: DataNode}} emitter + * @param {string} name + */ + __addSublanguage(emitter, name) { + /** @type DataNode */ + const node = emitter.root; + if (name) node.scope = `language:${name}`; + + this.add(node); + } + + toHTML() { + const renderer = new HTMLRenderer(this, this.options); + return renderer.value(); + } + + finalize() { + this.closeAllNodes(); + return true; + } + } + + /** + * @param {string} value + * @returns {RegExp} + * */ + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function source(re) { + if (!re) return null; + if (typeof re === "string") return re; + + return re.source; + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function lookahead(re) { + return concat('(?=', re, ')'); + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function anyNumberOfTimes(re) { + return concat('(?:', re, ')*'); + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function optional(re) { + return concat('(?:', re, ')?'); + } + + /** + * @param {...(RegExp | string) } args + * @returns {string} + */ + function concat(...args) { + const joined = args.map((x) => source(x)).join(""); + return joined; + } + + /** + * @param { Array } args + * @returns {object} + */ + function stripOptionsFromArgs(args) { + const opts = args[args.length - 1]; + + if (typeof opts === 'object' && opts.constructor === Object) { + args.splice(args.length - 1, 1); + return opts; + } else { + return {}; + } + } + + /** @typedef { {capture?: boolean} } RegexEitherOptions */ + + /** + * Any of the passed expresssions may match + * + * Creates a huge this | this | that | that match + * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args + * @returns {string} + */ + function either(...args) { + /** @type { object & {capture?: boolean} } */ + const opts = stripOptionsFromArgs(args); + const joined = '(' + + (opts.capture ? "" : "?:") + + args.map((x) => source(x)).join("|") + ")"; + return joined; + } + + /** + * @param {RegExp | string} re + * @returns {number} + */ + function countMatchGroups(re) { + return (new RegExp(re.toString() + '|')).exec('').length - 1; + } + + /** + * Does lexeme start with a regular expression match at the beginning + * @param {RegExp} re + * @param {string} lexeme + */ + function startsWith(re, lexeme) { + const match = re && re.exec(lexeme); + return match && match.index === 0; + } + + // BACKREF_RE matches an open parenthesis or backreference. To avoid + // an incorrect parse, it additionally matches the following: + // - [...] elements, where the meaning of parentheses and escapes change + // - other escape sequences, so we do not misparse escape sequences as + // interesting elements + // - non-matching or lookahead parentheses, which do not capture. These + // follow the '(' with a '?'. + const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./; + + // **INTERNAL** Not intended for outside usage + // join logically computes regexps.join(separator), but fixes the + // backreferences so they continue to match. + // it also places each individual regular expression into it's own + // match group, keeping track of the sequencing of those match groups + // is currently an exercise for the caller. :-) + /** + * @param {(string | RegExp)[]} regexps + * @param {{joinWith: string}} opts + * @returns {string} + */ + function _rewriteBackreferences(regexps, { joinWith }) { + let numCaptures = 0; + + return regexps.map((regex) => { + numCaptures += 1; + const offset = numCaptures; + let re = source(regex); + let out = ''; + + while (re.length > 0) { + const match = BACKREF_RE.exec(re); + if (!match) { + out += re; + break; + } + out += re.substring(0, match.index); + re = re.substring(match.index + match[0].length); + if (match[0][0] === '\\' && match[1]) { + // Adjust the backreference. + out += '\\' + String(Number(match[1]) + offset); + } else { + out += match[0]; + if (match[0] === '(') { + numCaptures++; + } + } + } + return out; + }).map(re => `(${re})`).join(joinWith); + } + + /** @typedef {import('highlight.js').Mode} Mode */ + /** @typedef {import('highlight.js').ModeCallback} ModeCallback */ + + // Common regexps + const MATCH_NOTHING_RE = /\b\B/; + const IDENT_RE = '[a-zA-Z]\\w*'; + const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; + const NUMBER_RE = '\\b\\d+(\\.\\d+)?'; + const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float + const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... + const RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; + + /** + * @param { Partial & {binary?: string | RegExp} } opts + */ + const SHEBANG = (opts = {}) => { + const beginShebang = /^#![ ]*\//; + if (opts.binary) { + opts.begin = concat( + beginShebang, + /.*\b/, + opts.binary, + /\b.*/); + } + return inherit$1({ + scope: 'meta', + begin: beginShebang, + end: /$/, + relevance: 0, + /** @type {ModeCallback} */ + "on:begin": (m, resp) => { + if (m.index !== 0) resp.ignoreMatch(); + } + }, opts); + }; + + // Common modes + const BACKSLASH_ESCAPE = { + begin: '\\\\[\\s\\S]', relevance: 0 + }; + const APOS_STRING_MODE = { + scope: 'string', + begin: '\'', + end: '\'', + illegal: '\\n', + contains: [BACKSLASH_ESCAPE] + }; + const QUOTE_STRING_MODE = { + scope: 'string', + begin: '"', + end: '"', + illegal: '\\n', + contains: [BACKSLASH_ESCAPE] + }; + const PHRASAL_WORDS_MODE = { + begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ + }; + /** + * Creates a comment mode + * + * @param {string | RegExp} begin + * @param {string | RegExp} end + * @param {Mode | {}} [modeOptions] + * @returns {Partial} + */ + const COMMENT = function(begin, end, modeOptions = {}) { + const mode = inherit$1( + { + scope: 'comment', + begin, + end, + contains: [] + }, + modeOptions + ); + mode.contains.push({ + scope: 'doctag', + // hack to avoid the space from being included. the space is necessary to + // match here to prevent the plain text rule below from gobbling up doctags + begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)', + end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/, + excludeBegin: true, + relevance: 0 + }); + const ENGLISH_WORD = either( + // list of common 1 and 2 letter words in English + "I", + "a", + "is", + "so", + "us", + "to", + "at", + "if", + "in", + "it", + "on", + // note: this is not an exhaustive list of contractions, just popular ones + /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc + /[A-Za-z]+[-][a-z]+/, // `no-way`, etc. + /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences + ); + // looking like plain text, more likely to be a comment + mode.contains.push( + { + // TODO: how to include ", (, ) without breaking grammars that use these for + // comment delimiters? + // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ ]|\))){3}/ + // --- + + // this tries to find sequences of 3 english words in a row (without any + // "programming" type syntax) this gives us a strong signal that we've + // TRULY found a comment - vs perhaps scanning with the wrong language. + // It's possible to find something that LOOKS like the start of the + // comment - but then if there is no readable text - good chance it is a + // false match and not a comment. + // + // for a visual example please see: + // https://github.com/highlightjs/highlight.js/issues/2827 + + begin: concat( + /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */ + '(', + ENGLISH_WORD, + /[.]?[:]?([.][ ]|[ ])/, + '){3}') // look for 3 words in a row + } + ); + return mode; + }; + const C_LINE_COMMENT_MODE = COMMENT('//', '$'); + const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/'); + const HASH_COMMENT_MODE = COMMENT('#', '$'); + const NUMBER_MODE = { + scope: 'number', + begin: NUMBER_RE, + relevance: 0 + }; + const C_NUMBER_MODE = { + scope: 'number', + begin: C_NUMBER_RE, + relevance: 0 + }; + const BINARY_NUMBER_MODE = { + scope: 'number', + begin: BINARY_NUMBER_RE, + relevance: 0 + }; + const REGEXP_MODE = { + scope: "regexp", + begin: /\/(?=[^/\n]*\/)/, + end: /\/[gimuy]*/, + contains: [ + BACKSLASH_ESCAPE, + { + begin: /\[/, + end: /\]/, + relevance: 0, + contains: [BACKSLASH_ESCAPE] + } + ] + }; + const TITLE_MODE = { + scope: 'title', + begin: IDENT_RE, + relevance: 0 + }; + const UNDERSCORE_TITLE_MODE = { + scope: 'title', + begin: UNDERSCORE_IDENT_RE, + relevance: 0 + }; + const METHOD_GUARD = { + // excludes method names from keyword processing + begin: '\\.\\s*' + UNDERSCORE_IDENT_RE, + relevance: 0 + }; + + /** + * Adds end same as begin mechanics to a mode + * + * Your mode must include at least a single () match group as that first match + * group is what is used for comparison + * @param {Partial} mode + */ + const END_SAME_AS_BEGIN = function(mode) { + return Object.assign(mode, + { + /** @type {ModeCallback} */ + 'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; }, + /** @type {ModeCallback} */ + 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); } + }); + }; + + var MODES = /*#__PURE__*/Object.freeze({ + __proto__: null, + APOS_STRING_MODE: APOS_STRING_MODE, + BACKSLASH_ESCAPE: BACKSLASH_ESCAPE, + BINARY_NUMBER_MODE: BINARY_NUMBER_MODE, + BINARY_NUMBER_RE: BINARY_NUMBER_RE, + COMMENT: COMMENT, + C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE, + C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE, + C_NUMBER_MODE: C_NUMBER_MODE, + C_NUMBER_RE: C_NUMBER_RE, + END_SAME_AS_BEGIN: END_SAME_AS_BEGIN, + HASH_COMMENT_MODE: HASH_COMMENT_MODE, + IDENT_RE: IDENT_RE, + MATCH_NOTHING_RE: MATCH_NOTHING_RE, + METHOD_GUARD: METHOD_GUARD, + NUMBER_MODE: NUMBER_MODE, + NUMBER_RE: NUMBER_RE, + PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE, + QUOTE_STRING_MODE: QUOTE_STRING_MODE, + REGEXP_MODE: REGEXP_MODE, + RE_STARTERS_RE: RE_STARTERS_RE, + SHEBANG: SHEBANG, + TITLE_MODE: TITLE_MODE, + UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE, + UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE + }); + + /** + @typedef {import('highlight.js').CallbackResponse} CallbackResponse + @typedef {import('highlight.js').CompilerExt} CompilerExt + */ + + // Grammar extensions / plugins + // See: https://github.com/highlightjs/highlight.js/issues/2833 + + // Grammar extensions allow "syntactic sugar" to be added to the grammar modes + // without requiring any underlying changes to the compiler internals. + + // `compileMatch` being the perfect small example of now allowing a grammar + // author to write `match` when they desire to match a single expression rather + // than being forced to use `begin`. The extension then just moves `match` into + // `begin` when it runs. Ie, no features have been added, but we've just made + // the experience of writing (and reading grammars) a little bit nicer. + + // ------ + + // TODO: We need negative look-behind support to do this properly + /** + * Skip a match if it has a preceding dot + * + * This is used for `beginKeywords` to prevent matching expressions such as + * `bob.keyword.do()`. The mode compiler automatically wires this up as a + * special _internal_ 'on:begin' callback for modes with `beginKeywords` + * @param {RegExpMatchArray} match + * @param {CallbackResponse} response + */ + function skipIfHasPrecedingDot(match, response) { + const before = match.input[match.index - 1]; + if (before === ".") { + response.ignoreMatch(); + } + } + + /** + * + * @type {CompilerExt} + */ + function scopeClassName(mode, _parent) { + // eslint-disable-next-line no-undefined + if (mode.className !== undefined) { + mode.scope = mode.className; + delete mode.className; + } + } + + /** + * `beginKeywords` syntactic sugar + * @type {CompilerExt} + */ + function beginKeywords(mode, parent) { + if (!parent) return; + if (!mode.beginKeywords) return; + + // for languages with keywords that include non-word characters checking for + // a word boundary is not sufficient, so instead we check for a word boundary + // or whitespace - this does no harm in any case since our keyword engine + // doesn't allow spaces in keywords anyways and we still check for the boundary + // first + mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)'; + mode.__beforeBegin = skipIfHasPrecedingDot; + mode.keywords = mode.keywords || mode.beginKeywords; + delete mode.beginKeywords; + + // prevents double relevance, the keywords themselves provide + // relevance, the mode doesn't need to double it + // eslint-disable-next-line no-undefined + if (mode.relevance === undefined) mode.relevance = 0; + } + + /** + * Allow `illegal` to contain an array of illegal values + * @type {CompilerExt} + */ + function compileIllegal(mode, _parent) { + if (!Array.isArray(mode.illegal)) return; + + mode.illegal = either(...mode.illegal); + } + + /** + * `match` to match a single expression for readability + * @type {CompilerExt} + */ + function compileMatch(mode, _parent) { + if (!mode.match) return; + if (mode.begin || mode.end) throw new Error("begin & end are not supported with match"); + + mode.begin = mode.match; + delete mode.match; + } + + /** + * provides the default 1 relevance to all modes + * @type {CompilerExt} + */ + function compileRelevance(mode, _parent) { + // eslint-disable-next-line no-undefined + if (mode.relevance === undefined) mode.relevance = 1; + } + + // allow beforeMatch to act as a "qualifier" for the match + // the full match begin must be [beforeMatch][begin] + const beforeMatchExt = (mode, parent) => { + if (!mode.beforeMatch) return; + // starts conflicts with endsParent which we need to make sure the child + // rule is not matched multiple times + if (mode.starts) throw new Error("beforeMatch cannot be used with starts"); + + const originalMode = Object.assign({}, mode); + Object.keys(mode).forEach((key) => { delete mode[key]; }); + + mode.keywords = originalMode.keywords; + mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin)); + mode.starts = { + relevance: 0, + contains: [ + Object.assign(originalMode, { endsParent: true }) + ] + }; + mode.relevance = 0; + + delete originalMode.beforeMatch; + }; + + // keywords that should have no default relevance value + const COMMON_KEYWORDS = [ + 'of', + 'and', + 'for', + 'in', + 'not', + 'or', + 'if', + 'then', + 'parent', // common variable name + 'list', // common variable name + 'value' // common variable name + ]; + + const DEFAULT_KEYWORD_SCOPE = "keyword"; + + /** + * Given raw keywords from a language definition, compile them. + * + * @param {string | Record | Array} rawKeywords + * @param {boolean} caseInsensitive + */ + function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) { + /** @type {import("highlight.js/private").KeywordDict} */ + const compiledKeywords = Object.create(null); + + // input can be a string of keywords, an array of keywords, or a object with + // named keys representing scopeName (which can then point to a string or array) + if (typeof rawKeywords === 'string') { + compileList(scopeName, rawKeywords.split(" ")); + } else if (Array.isArray(rawKeywords)) { + compileList(scopeName, rawKeywords); + } else { + Object.keys(rawKeywords).forEach(function(scopeName) { + // collapse all our objects back into the parent object + Object.assign( + compiledKeywords, + compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName) + ); + }); + } + return compiledKeywords; + + // --- + + /** + * Compiles an individual list of keywords + * + * Ex: "for if when while|5" + * + * @param {string} scopeName + * @param {Array} keywordList + */ + function compileList(scopeName, keywordList) { + if (caseInsensitive) { + keywordList = keywordList.map(x => x.toLowerCase()); + } + keywordList.forEach(function(keyword) { + const pair = keyword.split('|'); + compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])]; + }); + } + } + + /** + * Returns the proper score for a given keyword + * + * Also takes into account comment keywords, which will be scored 0 UNLESS + * another score has been manually assigned. + * @param {string} keyword + * @param {string} [providedScore] + */ + function scoreForKeyword(keyword, providedScore) { + // manual scores always win over common keywords + // so you can force a score of 1 if you really insist + if (providedScore) { + return Number(providedScore); + } + + return commonKeyword(keyword) ? 0 : 1; + } + + /** + * Determines if a given keyword is common or not + * + * @param {string} keyword */ + function commonKeyword(keyword) { + return COMMON_KEYWORDS.includes(keyword.toLowerCase()); + } + + /* + + For the reasoning behind this please see: + https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419 + + */ + + /** + * @type {Record} + */ + const seenDeprecations = {}; + + /** + * @param {string} message + */ + const error = (message) => { + console.error(message); + }; + + /** + * @param {string} message + * @param {any} args + */ + const warn = (message, ...args) => { + console.log(`WARN: ${message}`, ...args); + }; + + /** + * @param {string} version + * @param {string} message + */ + const deprecated = (version, message) => { + if (seenDeprecations[`${version}/${message}`]) return; + + console.log(`Deprecated as of ${version}. ${message}`); + seenDeprecations[`${version}/${message}`] = true; + }; + + /* eslint-disable no-throw-literal */ + + /** + @typedef {import('highlight.js').CompiledMode} CompiledMode + */ + + const MultiClassError = new Error(); + + /** + * Renumbers labeled scope names to account for additional inner match + * groups that otherwise would break everything. + * + * Lets say we 3 match scopes: + * + * { 1 => ..., 2 => ..., 3 => ... } + * + * So what we need is a clean match like this: + * + * (a)(b)(c) => [ "a", "b", "c" ] + * + * But this falls apart with inner match groups: + * + * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ] + * + * Our scopes are now "out of alignment" and we're repeating `b` 3 times. + * What needs to happen is the numbers are remapped: + * + * { 1 => ..., 2 => ..., 5 => ... } + * + * We also need to know that the ONLY groups that should be output + * are 1, 2, and 5. This function handles this behavior. + * + * @param {CompiledMode} mode + * @param {Array} regexes + * @param {{key: "beginScope"|"endScope"}} opts + */ + function remapScopeNames(mode, regexes, { key }) { + let offset = 0; + const scopeNames = mode[key]; + /** @type Record */ + const emit = {}; + /** @type Record */ + const positions = {}; + + for (let i = 1; i <= regexes.length; i++) { + positions[i + offset] = scopeNames[i]; + emit[i + offset] = true; + offset += countMatchGroups(regexes[i - 1]); + } + // we use _emit to keep track of which match groups are "top-level" to avoid double + // output from inside match groups + mode[key] = positions; + mode[key]._emit = emit; + mode[key]._multi = true; + } + + /** + * @param {CompiledMode} mode + */ + function beginMultiClass(mode) { + if (!Array.isArray(mode.begin)) return; + + if (mode.skip || mode.excludeBegin || mode.returnBegin) { + error("skip, excludeBegin, returnBegin not compatible with beginScope: {}"); + throw MultiClassError; + } + + if (typeof mode.beginScope !== "object" || mode.beginScope === null) { + error("beginScope must be object"); + throw MultiClassError; + } + + remapScopeNames(mode, mode.begin, { key: "beginScope" }); + mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" }); + } + + /** + * @param {CompiledMode} mode + */ + function endMultiClass(mode) { + if (!Array.isArray(mode.end)) return; + + if (mode.skip || mode.excludeEnd || mode.returnEnd) { + error("skip, excludeEnd, returnEnd not compatible with endScope: {}"); + throw MultiClassError; + } + + if (typeof mode.endScope !== "object" || mode.endScope === null) { + error("endScope must be object"); + throw MultiClassError; + } + + remapScopeNames(mode, mode.end, { key: "endScope" }); + mode.end = _rewriteBackreferences(mode.end, { joinWith: "" }); + } + + /** + * this exists only to allow `scope: {}` to be used beside `match:` + * Otherwise `beginScope` would necessary and that would look weird + + { + match: [ /def/, /\w+/ ] + scope: { 1: "keyword" , 2: "title" } + } + + * @param {CompiledMode} mode + */ + function scopeSugar(mode) { + if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) { + mode.beginScope = mode.scope; + delete mode.scope; + } + } + + /** + * @param {CompiledMode} mode + */ + function MultiClass(mode) { + scopeSugar(mode); + + if (typeof mode.beginScope === "string") { + mode.beginScope = { _wrap: mode.beginScope }; + } + if (typeof mode.endScope === "string") { + mode.endScope = { _wrap: mode.endScope }; + } + + beginMultiClass(mode); + endMultiClass(mode); + } + + /** + @typedef {import('highlight.js').Mode} Mode + @typedef {import('highlight.js').CompiledMode} CompiledMode + @typedef {import('highlight.js').Language} Language + @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin + @typedef {import('highlight.js').CompiledLanguage} CompiledLanguage + */ + + // compilation + + /** + * Compiles a language definition result + * + * Given the raw result of a language definition (Language), compiles this so + * that it is ready for highlighting code. + * @param {Language} language + * @returns {CompiledLanguage} + */ + function compileLanguage(language) { + /** + * Builds a regex with the case sensitivity of the current language + * + * @param {RegExp | string} value + * @param {boolean} [global] + */ + function langRe(value, global) { + return new RegExp( + source(value), + 'm' + + (language.case_insensitive ? 'i' : '') + + (language.unicodeRegex ? 'u' : '') + + (global ? 'g' : '') + ); + } + + /** + Stores multiple regular expressions and allows you to quickly search for + them all in a string simultaneously - returning the first match. It does + this by creating a huge (a|b|c) regex - each individual item wrapped with () + and joined by `|` - using match groups to track position. When a match is + found checking which position in the array has content allows us to figure + out which of the original regexes / match groups triggered the match. + + The match object itself (the result of `Regex.exec`) is returned but also + enhanced by merging in any meta-data that was registered with the regex. + This is how we keep track of which mode matched, and what type of rule + (`illegal`, `begin`, end, etc). + */ + class MultiRegex { + constructor() { + this.matchIndexes = {}; + // @ts-ignore + this.regexes = []; + this.matchAt = 1; + this.position = 0; + } + + // @ts-ignore + addRule(re, opts) { + opts.position = this.position++; + // @ts-ignore + this.matchIndexes[this.matchAt] = opts; + this.regexes.push([opts, re]); + this.matchAt += countMatchGroups(re) + 1; + } + + compile() { + if (this.regexes.length === 0) { + // avoids the need to check length every time exec is called + // @ts-ignore + this.exec = () => null; + } + const terminators = this.regexes.map(el => el[1]); + this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true); + this.lastIndex = 0; + } + + /** @param {string} s */ + exec(s) { + this.matcherRe.lastIndex = this.lastIndex; + const match = this.matcherRe.exec(s); + if (!match) { return null; } + + // eslint-disable-next-line no-undefined + const i = match.findIndex((el, i) => i > 0 && el !== undefined); + // @ts-ignore + const matchData = this.matchIndexes[i]; + // trim off any earlier non-relevant match groups (ie, the other regex + // match groups that make up the multi-matcher) + match.splice(0, i); + + return Object.assign(match, matchData); + } + } + + /* + Created to solve the key deficiently with MultiRegex - there is no way to + test for multiple matches at a single location. Why would we need to do + that? In the future a more dynamic engine will allow certain matches to be + ignored. An example: if we matched say the 3rd regex in a large group but + decided to ignore it - we'd need to started testing again at the 4th + regex... but MultiRegex itself gives us no real way to do that. + + So what this class creates MultiRegexs on the fly for whatever search + position they are needed. + + NOTE: These additional MultiRegex objects are created dynamically. For most + grammars most of the time we will never actually need anything more than the + first MultiRegex - so this shouldn't have too much overhead. + + Say this is our search group, and we match regex3, but wish to ignore it. + + regex1 | regex2 | regex3 | regex4 | regex5 ' ie, startAt = 0 + + What we need is a new MultiRegex that only includes the remaining + possibilities: + + regex4 | regex5 ' ie, startAt = 3 + + This class wraps all that complexity up in a simple API... `startAt` decides + where in the array of expressions to start doing the matching. It + auto-increments, so if a match is found at position 2, then startAt will be + set to 3. If the end is reached startAt will return to 0. + + MOST of the time the parser will be setting startAt manually to 0. + */ + class ResumableMultiRegex { + constructor() { + // @ts-ignore + this.rules = []; + // @ts-ignore + this.multiRegexes = []; + this.count = 0; + + this.lastIndex = 0; + this.regexIndex = 0; + } + + // @ts-ignore + getMatcher(index) { + if (this.multiRegexes[index]) return this.multiRegexes[index]; + + const matcher = new MultiRegex(); + this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts)); + matcher.compile(); + this.multiRegexes[index] = matcher; + return matcher; + } + + resumingScanAtSamePosition() { + return this.regexIndex !== 0; + } + + considerAll() { + this.regexIndex = 0; + } + + // @ts-ignore + addRule(re, opts) { + this.rules.push([re, opts]); + if (opts.type === "begin") this.count++; + } + + /** @param {string} s */ + exec(s) { + const m = this.getMatcher(this.regexIndex); + m.lastIndex = this.lastIndex; + let result = m.exec(s); + + // The following is because we have no easy way to say "resume scanning at the + // existing position but also skip the current rule ONLY". What happens is + // all prior rules are also skipped which can result in matching the wrong + // thing. Example of matching "booger": + + // our matcher is [string, "booger", number] + // + // ....booger.... + + // if "booger" is ignored then we'd really need a regex to scan from the + // SAME position for only: [string, number] but ignoring "booger" (if it + // was the first match), a simple resume would scan ahead who knows how + // far looking only for "number", ignoring potential string matches (or + // future "booger" matches that might be valid.) + + // So what we do: We execute two matchers, one resuming at the same + // position, but the second full matcher starting at the position after: + + // /--- resume first regex match here (for [number]) + // |/---- full match here for [string, "booger", number] + // vv + // ....booger.... + + // Which ever results in a match first is then used. So this 3-4 step + // process essentially allows us to say "match at this position, excluding + // a prior rule that was ignored". + // + // 1. Match "booger" first, ignore. Also proves that [string] does non match. + // 2. Resume matching for [number] + // 3. Match at index + 1 for [string, "booger", number] + // 4. If #2 and #3 result in matches, which came first? + if (this.resumingScanAtSamePosition()) { + if (result && result.index === this.lastIndex) ; else { // use the second matcher result + const m2 = this.getMatcher(0); + m2.lastIndex = this.lastIndex + 1; + result = m2.exec(s); + } + } + + if (result) { + this.regexIndex += result.position + 1; + if (this.regexIndex === this.count) { + // wrap-around to considering all matches again + this.considerAll(); + } + } + + return result; + } + } + + /** + * Given a mode, builds a huge ResumableMultiRegex that can be used to walk + * the content and find matches. + * + * @param {CompiledMode} mode + * @returns {ResumableMultiRegex} + */ + function buildModeRegex(mode) { + const mm = new ResumableMultiRegex(); + + mode.contains.forEach(term => mm.addRule(term.begin, { rule: term, type: "begin" })); + + if (mode.terminatorEnd) { + mm.addRule(mode.terminatorEnd, { type: "end" }); + } + if (mode.illegal) { + mm.addRule(mode.illegal, { type: "illegal" }); + } + + return mm; + } + + /** skip vs abort vs ignore + * + * @skip - The mode is still entered and exited normally (and contains rules apply), + * but all content is held and added to the parent buffer rather than being + * output when the mode ends. Mostly used with `sublanguage` to build up + * a single large buffer than can be parsed by sublanguage. + * + * - The mode begin ands ends normally. + * - Content matched is added to the parent mode buffer. + * - The parser cursor is moved forward normally. + * + * @abort - A hack placeholder until we have ignore. Aborts the mode (as if it + * never matched) but DOES NOT continue to match subsequent `contains` + * modes. Abort is bad/suboptimal because it can result in modes + * farther down not getting applied because an earlier rule eats the + * content but then aborts. + * + * - The mode does not begin. + * - Content matched by `begin` is added to the mode buffer. + * - The parser cursor is moved forward accordingly. + * + * @ignore - Ignores the mode (as if it never matched) and continues to match any + * subsequent `contains` modes. Ignore isn't technically possible with + * the current parser implementation. + * + * - The mode does not begin. + * - Content matched by `begin` is ignored. + * - The parser cursor is not moved forward. + */ + + /** + * Compiles an individual mode + * + * This can raise an error if the mode contains certain detectable known logic + * issues. + * @param {Mode} mode + * @param {CompiledMode | null} [parent] + * @returns {CompiledMode | never} + */ + function compileMode(mode, parent) { + const cmode = /** @type CompiledMode */ (mode); + if (mode.isCompiled) return cmode; + + [ + scopeClassName, + // do this early so compiler extensions generally don't have to worry about + // the distinction between match/begin + compileMatch, + MultiClass, + beforeMatchExt + ].forEach(ext => ext(mode, parent)); + + language.compilerExtensions.forEach(ext => ext(mode, parent)); + + // __beforeBegin is considered private API, internal use only + mode.__beforeBegin = null; + + [ + beginKeywords, + // do this later so compiler extensions that come earlier have access to the + // raw array if they wanted to perhaps manipulate it, etc. + compileIllegal, + // default to 1 relevance if not specified + compileRelevance + ].forEach(ext => ext(mode, parent)); + + mode.isCompiled = true; + + let keywordPattern = null; + if (typeof mode.keywords === "object" && mode.keywords.$pattern) { + // we need a copy because keywords might be compiled multiple times + // so we can't go deleting $pattern from the original on the first + // pass + mode.keywords = Object.assign({}, mode.keywords); + keywordPattern = mode.keywords.$pattern; + delete mode.keywords.$pattern; + } + keywordPattern = keywordPattern || /\w+/; + + if (mode.keywords) { + mode.keywords = compileKeywords(mode.keywords, language.case_insensitive); + } + + cmode.keywordPatternRe = langRe(keywordPattern, true); + + if (parent) { + if (!mode.begin) mode.begin = /\B|\b/; + cmode.beginRe = langRe(cmode.begin); + if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/; + if (mode.end) cmode.endRe = langRe(cmode.end); + cmode.terminatorEnd = source(cmode.end) || ''; + if (mode.endsWithParent && parent.terminatorEnd) { + cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd; + } + } + if (mode.illegal) cmode.illegalRe = langRe(/** @type {RegExp | string} */ (mode.illegal)); + if (!mode.contains) mode.contains = []; + + mode.contains = [].concat(...mode.contains.map(function(c) { + return expandOrCloneMode(c === 'self' ? mode : c); + })); + mode.contains.forEach(function(c) { compileMode(/** @type Mode */ (c), cmode); }); + + if (mode.starts) { + compileMode(mode.starts, parent); + } + + cmode.matcher = buildModeRegex(cmode); + return cmode; + } + + if (!language.compilerExtensions) language.compilerExtensions = []; + + // self is not valid at the top-level + if (language.contains && language.contains.includes('self')) { + throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation."); + } + + // we need a null object, which inherit will guarantee + language.classNameAliases = inherit$1(language.classNameAliases || {}); + + return compileMode(/** @type Mode */ (language)); + } + + /** + * Determines if a mode has a dependency on it's parent or not + * + * If a mode does have a parent dependency then often we need to clone it if + * it's used in multiple places so that each copy points to the correct parent, + * where-as modes without a parent can often safely be re-used at the bottom of + * a mode chain. + * + * @param {Mode | null} mode + * @returns {boolean} - is there a dependency on the parent? + * */ + function dependencyOnParent(mode) { + if (!mode) return false; + + return mode.endsWithParent || dependencyOnParent(mode.starts); + } + + /** + * Expands a mode or clones it if necessary + * + * This is necessary for modes with parental dependenceis (see notes on + * `dependencyOnParent`) and for nodes that have `variants` - which must then be + * exploded into their own individual modes at compile time. + * + * @param {Mode} mode + * @returns {Mode | Mode[]} + * */ + function expandOrCloneMode(mode) { + if (mode.variants && !mode.cachedVariants) { + mode.cachedVariants = mode.variants.map(function(variant) { + return inherit$1(mode, { variants: null }, variant); + }); + } + + // EXPAND + // if we have variants then essentially "replace" the mode with the variants + // this happens in compileMode, where this function is called from + if (mode.cachedVariants) { + return mode.cachedVariants; + } + + // CLONE + // if we have dependencies on parents then we need a unique + // instance of ourselves, so we can be reused with many + // different parents without issue + if (dependencyOnParent(mode)) { + return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null }); + } + + if (Object.isFrozen(mode)) { + return inherit$1(mode); + } + + // no special dependency issues, just return ourselves + return mode; + } + + var version = "11.9.0"; + + class HTMLInjectionError extends Error { + constructor(reason, html) { + super(reason); + this.name = "HTMLInjectionError"; + this.html = html; + } + } + + /* + Syntax highlighting with language autodetection. + https://highlightjs.org/ + */ + + + + /** + @typedef {import('highlight.js').Mode} Mode + @typedef {import('highlight.js').CompiledMode} CompiledMode + @typedef {import('highlight.js').CompiledScope} CompiledScope + @typedef {import('highlight.js').Language} Language + @typedef {import('highlight.js').HLJSApi} HLJSApi + @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin + @typedef {import('highlight.js').PluginEvent} PluginEvent + @typedef {import('highlight.js').HLJSOptions} HLJSOptions + @typedef {import('highlight.js').LanguageFn} LanguageFn + @typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement + @typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext + @typedef {import('highlight.js/private').MatchType} MatchType + @typedef {import('highlight.js/private').KeywordData} KeywordData + @typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch + @typedef {import('highlight.js/private').AnnotatedError} AnnotatedError + @typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult + @typedef {import('highlight.js').HighlightOptions} HighlightOptions + @typedef {import('highlight.js').HighlightResult} HighlightResult + */ + + + const escape = escapeHTML; + const inherit = inherit$1; + const NO_MATCH = Symbol("nomatch"); + const MAX_KEYWORD_HITS = 7; + + /** + * @param {any} hljs - object that is extended (legacy) + * @returns {HLJSApi} + */ + const HLJS = function(hljs) { + // Global internal variables used within the highlight.js library. + /** @type {Record} */ + const languages = Object.create(null); + /** @type {Record} */ + const aliases = Object.create(null); + /** @type {HLJSPlugin[]} */ + const plugins = []; + + // safe/production mode - swallows more errors, tries to keep running + // even if a single syntax or parse hits a fatal error + let SAFE_MODE = true; + const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?"; + /** @type {Language} */ + const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] }; + + // Global options used when within external APIs. This is modified when + // calling the `hljs.configure` function. + /** @type HLJSOptions */ + let options = { + ignoreUnescapedHTML: false, + throwUnescapedHTML: false, + noHighlightRe: /^(no-?highlight)$/i, + languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i, + classPrefix: 'hljs-', + cssSelector: 'pre code', + languages: null, + // beta configuration options, subject to change, welcome to discuss + // https://github.com/highlightjs/highlight.js/issues/1086 + __emitter: TokenTreeEmitter + }; + + /* Utility functions */ + + /** + * Tests a language name to see if highlighting should be skipped + * @param {string} languageName + */ + function shouldNotHighlight(languageName) { + return options.noHighlightRe.test(languageName); + } + + /** + * @param {HighlightedHTMLElement} block - the HTML element to determine language for + */ + function blockLanguage(block) { + let classes = block.className + ' '; + + classes += block.parentNode ? block.parentNode.className : ''; + + // language-* takes precedence over non-prefixed class names. + const match = options.languageDetectRe.exec(classes); + if (match) { + const language = getLanguage(match[1]); + if (!language) { + warn(LANGUAGE_NOT_FOUND.replace("{}", match[1])); + warn("Falling back to no-highlight mode for this block.", block); + } + return language ? match[1] : 'no-highlight'; + } + + return classes + .split(/\s+/) + .find((_class) => shouldNotHighlight(_class) || getLanguage(_class)); + } + + /** + * Core highlighting function. + * + * OLD API + * highlight(lang, code, ignoreIllegals, continuation) + * + * NEW API + * highlight(code, {lang, ignoreIllegals}) + * + * @param {string} codeOrLanguageName - the language to use for highlighting + * @param {string | HighlightOptions} optionsOrCode - the code to highlight + * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail + * + * @returns {HighlightResult} Result - an object that represents the result + * @property {string} language - the language name + * @property {number} relevance - the relevance score + * @property {string} value - the highlighted HTML code + * @property {string} code - the original raw code + * @property {CompiledMode} top - top of the current mode stack + * @property {boolean} illegal - indicates whether any illegal matches were found + */ + function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals) { + let code = ""; + let languageName = ""; + if (typeof optionsOrCode === "object") { + code = codeOrLanguageName; + ignoreIllegals = optionsOrCode.ignoreIllegals; + languageName = optionsOrCode.language; + } else { + // old API + deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated."); + deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"); + languageName = codeOrLanguageName; + code = optionsOrCode; + } + + // https://github.com/highlightjs/highlight.js/issues/3149 + // eslint-disable-next-line no-undefined + if (ignoreIllegals === undefined) { ignoreIllegals = true; } + + /** @type {BeforeHighlightContext} */ + const context = { + code, + language: languageName + }; + // the plugin can change the desired language or the code to be highlighted + // just be changing the object it was passed + fire("before:highlight", context); + + // a before plugin can usurp the result completely by providing it's own + // in which case we don't even need to call highlight + const result = context.result + ? context.result + : _highlight(context.language, context.code, ignoreIllegals); + + result.code = context.code; + // the plugin can change anything in result to suite it + fire("after:highlight", result); + + return result; + } + + /** + * private highlight that's used internally and does not fire callbacks + * + * @param {string} languageName - the language to use for highlighting + * @param {string} codeToHighlight - the code to highlight + * @param {boolean?} [ignoreIllegals] - whether to ignore illegal matches, default is to bail + * @param {CompiledMode?} [continuation] - current continuation mode, if any + * @returns {HighlightResult} - result of the highlight operation + */ + function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) { + const keywordHits = Object.create(null); + + /** + * Return keyword data if a match is a keyword + * @param {CompiledMode} mode - current mode + * @param {string} matchText - the textual match + * @returns {KeywordData | false} + */ + function keywordData(mode, matchText) { + return mode.keywords[matchText]; + } + + function processKeywords() { + if (!top.keywords) { + emitter.addText(modeBuffer); + return; + } + + let lastIndex = 0; + top.keywordPatternRe.lastIndex = 0; + let match = top.keywordPatternRe.exec(modeBuffer); + let buf = ""; + + while (match) { + buf += modeBuffer.substring(lastIndex, match.index); + const word = language.case_insensitive ? match[0].toLowerCase() : match[0]; + const data = keywordData(top, word); + if (data) { + const [kind, keywordRelevance] = data; + emitter.addText(buf); + buf = ""; + + keywordHits[word] = (keywordHits[word] || 0) + 1; + if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance; + if (kind.startsWith("_")) { + // _ implied for relevance only, do not highlight + // by applying a class name + buf += match[0]; + } else { + const cssClass = language.classNameAliases[kind] || kind; + emitKeyword(match[0], cssClass); + } + } else { + buf += match[0]; + } + lastIndex = top.keywordPatternRe.lastIndex; + match = top.keywordPatternRe.exec(modeBuffer); + } + buf += modeBuffer.substring(lastIndex); + emitter.addText(buf); + } + + function processSubLanguage() { + if (modeBuffer === "") return; + /** @type HighlightResult */ + let result = null; + + if (typeof top.subLanguage === 'string') { + if (!languages[top.subLanguage]) { + emitter.addText(modeBuffer); + return; + } + result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]); + continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top); + } else { + result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null); + } + + // Counting embedded language score towards the host language may be disabled + // with zeroing the containing mode relevance. Use case in point is Markdown that + // allows XML everywhere and makes every XML snippet to have a much larger Markdown + // score. + if (top.relevance > 0) { + relevance += result.relevance; + } + emitter.__addSublanguage(result._emitter, result.language); + } + + function processBuffer() { + if (top.subLanguage != null) { + processSubLanguage(); + } else { + processKeywords(); + } + modeBuffer = ''; + } + + /** + * @param {string} text + * @param {string} scope + */ + function emitKeyword(keyword, scope) { + if (keyword === "") return; + + emitter.startScope(scope); + emitter.addText(keyword); + emitter.endScope(); + } + + /** + * @param {CompiledScope} scope + * @param {RegExpMatchArray} match + */ + function emitMultiClass(scope, match) { + let i = 1; + const max = match.length - 1; + while (i <= max) { + if (!scope._emit[i]) { i++; continue; } + const klass = language.classNameAliases[scope[i]] || scope[i]; + const text = match[i]; + if (klass) { + emitKeyword(text, klass); + } else { + modeBuffer = text; + processKeywords(); + modeBuffer = ""; + } + i++; + } + } + + /** + * @param {CompiledMode} mode - new mode to start + * @param {RegExpMatchArray} match + */ + function startNewMode(mode, match) { + if (mode.scope && typeof mode.scope === "string") { + emitter.openNode(language.classNameAliases[mode.scope] || mode.scope); + } + if (mode.beginScope) { + // beginScope just wraps the begin match itself in a scope + if (mode.beginScope._wrap) { + emitKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap); + modeBuffer = ""; + } else if (mode.beginScope._multi) { + // at this point modeBuffer should just be the match + emitMultiClass(mode.beginScope, match); + modeBuffer = ""; + } + } + + top = Object.create(mode, { parent: { value: top } }); + return top; + } + + /** + * @param {CompiledMode } mode - the mode to potentially end + * @param {RegExpMatchArray} match - the latest match + * @param {string} matchPlusRemainder - match plus remainder of content + * @returns {CompiledMode | void} - the next mode, or if void continue on in current mode + */ + function endOfMode(mode, match, matchPlusRemainder) { + let matched = startsWith(mode.endRe, matchPlusRemainder); + + if (matched) { + if (mode["on:end"]) { + const resp = new Response(mode); + mode["on:end"](match, resp); + if (resp.isMatchIgnored) matched = false; + } + + if (matched) { + while (mode.endsParent && mode.parent) { + mode = mode.parent; + } + return mode; + } + } + // even if on:end fires an `ignore` it's still possible + // that we might trigger the end node because of a parent mode + if (mode.endsWithParent) { + return endOfMode(mode.parent, match, matchPlusRemainder); + } + } + + /** + * Handle matching but then ignoring a sequence of text + * + * @param {string} lexeme - string containing full match text + */ + function doIgnore(lexeme) { + if (top.matcher.regexIndex === 0) { + // no more regexes to potentially match here, so we move the cursor forward one + // space + modeBuffer += lexeme[0]; + return 1; + } else { + // no need to move the cursor, we still have additional regexes to try and + // match at this very spot + resumeScanAtSamePosition = true; + return 0; + } + } + + /** + * Handle the start of a new potential mode match + * + * @param {EnhancedMatch} match - the current match + * @returns {number} how far to advance the parse cursor + */ + function doBeginMatch(match) { + const lexeme = match[0]; + const newMode = match.rule; + + const resp = new Response(newMode); + // first internal before callbacks, then the public ones + const beforeCallbacks = [newMode.__beforeBegin, newMode["on:begin"]]; + for (const cb of beforeCallbacks) { + if (!cb) continue; + cb(match, resp); + if (resp.isMatchIgnored) return doIgnore(lexeme); + } + + if (newMode.skip) { + modeBuffer += lexeme; + } else { + if (newMode.excludeBegin) { + modeBuffer += lexeme; + } + processBuffer(); + if (!newMode.returnBegin && !newMode.excludeBegin) { + modeBuffer = lexeme; + } + } + startNewMode(newMode, match); + return newMode.returnBegin ? 0 : lexeme.length; + } + + /** + * Handle the potential end of mode + * + * @param {RegExpMatchArray} match - the current match + */ + function doEndMatch(match) { + const lexeme = match[0]; + const matchPlusRemainder = codeToHighlight.substring(match.index); + + const endMode = endOfMode(top, match, matchPlusRemainder); + if (!endMode) { return NO_MATCH; } + + const origin = top; + if (top.endScope && top.endScope._wrap) { + processBuffer(); + emitKeyword(lexeme, top.endScope._wrap); + } else if (top.endScope && top.endScope._multi) { + processBuffer(); + emitMultiClass(top.endScope, match); + } else if (origin.skip) { + modeBuffer += lexeme; + } else { + if (!(origin.returnEnd || origin.excludeEnd)) { + modeBuffer += lexeme; + } + processBuffer(); + if (origin.excludeEnd) { + modeBuffer = lexeme; + } + } + do { + if (top.scope) { + emitter.closeNode(); + } + if (!top.skip && !top.subLanguage) { + relevance += top.relevance; + } + top = top.parent; + } while (top !== endMode.parent); + if (endMode.starts) { + startNewMode(endMode.starts, match); + } + return origin.returnEnd ? 0 : lexeme.length; + } + + function processContinuations() { + const list = []; + for (let current = top; current !== language; current = current.parent) { + if (current.scope) { + list.unshift(current.scope); + } + } + list.forEach(item => emitter.openNode(item)); + } + + /** @type {{type?: MatchType, index?: number, rule?: Mode}}} */ + let lastMatch = {}; + + /** + * Process an individual match + * + * @param {string} textBeforeMatch - text preceding the match (since the last match) + * @param {EnhancedMatch} [match] - the match itself + */ + function processLexeme(textBeforeMatch, match) { + const lexeme = match && match[0]; + + // add non-matched text to the current mode buffer + modeBuffer += textBeforeMatch; + + if (lexeme == null) { + processBuffer(); + return 0; + } + + // we've found a 0 width match and we're stuck, so we need to advance + // this happens when we have badly behaved rules that have optional matchers to the degree that + // sometimes they can end up matching nothing at all + // Ref: https://github.com/highlightjs/highlight.js/issues/2140 + if (lastMatch.type === "begin" && match.type === "end" && lastMatch.index === match.index && lexeme === "") { + // spit the "skipped" character that our regex choked on back into the output sequence + modeBuffer += codeToHighlight.slice(match.index, match.index + 1); + if (!SAFE_MODE) { + /** @type {AnnotatedError} */ + const err = new Error(`0 width match regex (${languageName})`); + err.languageName = languageName; + err.badRule = lastMatch.rule; + throw err; + } + return 1; + } + lastMatch = match; + + if (match.type === "begin") { + return doBeginMatch(match); + } else if (match.type === "illegal" && !ignoreIllegals) { + // illegal match, we do not continue processing + /** @type {AnnotatedError} */ + const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '') + '"'); + err.mode = top; + throw err; + } else if (match.type === "end") { + const processed = doEndMatch(match); + if (processed !== NO_MATCH) { + return processed; + } + } + + // edge case for when illegal matches $ (end of line) which is technically + // a 0 width match but not a begin/end match so it's not caught by the + // first handler (when ignoreIllegals is true) + if (match.type === "illegal" && lexeme === "") { + // advance so we aren't stuck in an infinite loop + return 1; + } + + // infinite loops are BAD, this is a last ditch catch all. if we have a + // decent number of iterations yet our index (cursor position in our + // parsing) still 3x behind our index then something is very wrong + // so we bail + if (iterations > 100000 && iterations > match.index * 3) { + const err = new Error('potential infinite loop, way more iterations than matches'); + throw err; + } + + /* + Why might be find ourselves here? An potential end match that was + triggered but could not be completed. IE, `doEndMatch` returned NO_MATCH. + (this could be because a callback requests the match be ignored, etc) + + This causes no real harm other than stopping a few times too many. + */ + + modeBuffer += lexeme; + return lexeme.length; + } + + const language = getLanguage(languageName); + if (!language) { + error(LANGUAGE_NOT_FOUND.replace("{}", languageName)); + throw new Error('Unknown language: "' + languageName + '"'); + } + + const md = compileLanguage(language); + let result = ''; + /** @type {CompiledMode} */ + let top = continuation || md; + /** @type Record */ + const continuations = {}; // keep continuations for sub-languages + const emitter = new options.__emitter(options); + processContinuations(); + let modeBuffer = ''; + let relevance = 0; + let index = 0; + let iterations = 0; + let resumeScanAtSamePosition = false; + + try { + if (!language.__emitTokens) { + top.matcher.considerAll(); + + for (;;) { + iterations++; + if (resumeScanAtSamePosition) { + // only regexes not matched previously will now be + // considered for a potential match + resumeScanAtSamePosition = false; + } else { + top.matcher.considerAll(); + } + top.matcher.lastIndex = index; + + const match = top.matcher.exec(codeToHighlight); + // console.log("match", match[0], match.rule && match.rule.begin) + + if (!match) break; + + const beforeMatch = codeToHighlight.substring(index, match.index); + const processedCount = processLexeme(beforeMatch, match); + index = match.index + processedCount; + } + processLexeme(codeToHighlight.substring(index)); + } else { + language.__emitTokens(codeToHighlight, emitter); + } + + emitter.finalize(); + result = emitter.toHTML(); + + return { + language: languageName, + value: result, + relevance, + illegal: false, + _emitter: emitter, + _top: top + }; + } catch (err) { + if (err.message && err.message.includes('Illegal')) { + return { + language: languageName, + value: escape(codeToHighlight), + illegal: true, + relevance: 0, + _illegalBy: { + message: err.message, + index, + context: codeToHighlight.slice(index - 100, index + 100), + mode: err.mode, + resultSoFar: result + }, + _emitter: emitter + }; + } else if (SAFE_MODE) { + return { + language: languageName, + value: escape(codeToHighlight), + illegal: false, + relevance: 0, + errorRaised: err, + _emitter: emitter, + _top: top + }; + } else { + throw err; + } + } + } + + /** + * returns a valid highlight result, without actually doing any actual work, + * auto highlight starts with this and it's possible for small snippets that + * auto-detection may not find a better match + * @param {string} code + * @returns {HighlightResult} + */ + function justTextHighlightResult(code) { + const result = { + value: escape(code), + illegal: false, + relevance: 0, + _top: PLAINTEXT_LANGUAGE, + _emitter: new options.__emitter(options) + }; + result._emitter.addText(code); + return result; + } + + /** + Highlighting with language detection. Accepts a string with the code to + highlight. Returns an object with the following properties: + + - language (detected language) + - relevance (int) + - value (an HTML string with highlighting markup) + - secondBest (object with the same structure for second-best heuristically + detected language, may be absent) + + @param {string} code + @param {Array} [languageSubset] + @returns {AutoHighlightResult} + */ + function highlightAuto(code, languageSubset) { + languageSubset = languageSubset || options.languages || Object.keys(languages); + const plaintext = justTextHighlightResult(code); + + const results = languageSubset.filter(getLanguage).filter(autoDetection).map(name => + _highlight(name, code, false) + ); + results.unshift(plaintext); // plaintext is always an option + + const sorted = results.sort((a, b) => { + // sort base on relevance + if (a.relevance !== b.relevance) return b.relevance - a.relevance; + + // always award the tie to the base language + // ie if C++ and Arduino are tied, it's more likely to be C++ + if (a.language && b.language) { + if (getLanguage(a.language).supersetOf === b.language) { + return 1; + } else if (getLanguage(b.language).supersetOf === a.language) { + return -1; + } + } + + // otherwise say they are equal, which has the effect of sorting on + // relevance while preserving the original ordering - which is how ties + // have historically been settled, ie the language that comes first always + // wins in the case of a tie + return 0; + }); + + const [best, secondBest] = sorted; + + /** @type {AutoHighlightResult} */ + const result = best; + result.secondBest = secondBest; + + return result; + } + + /** + * Builds new class name for block given the language name + * + * @param {HTMLElement} element + * @param {string} [currentLang] + * @param {string} [resultLang] + */ + function updateClassName(element, currentLang, resultLang) { + const language = (currentLang && aliases[currentLang]) || resultLang; + + element.classList.add("hljs"); + element.classList.add(`language-${language}`); + } + + /** + * Applies highlighting to a DOM node containing code. + * + * @param {HighlightedHTMLElement} element - the HTML element to highlight + */ + function highlightElement(element) { + /** @type HTMLElement */ + let node = null; + const language = blockLanguage(element); + + if (shouldNotHighlight(language)) return; + + fire("before:highlightElement", + { el: element, language }); + + if (element.dataset.highlighted) { + console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.", element); + return; + } + + // we should be all text, no child nodes (unescaped HTML) - this is possibly + // an HTML injection attack - it's likely too late if this is already in + // production (the code has likely already done its damage by the time + // we're seeing it)... but we yell loudly about this so that hopefully it's + // more likely to be caught in development before making it to production + if (element.children.length > 0) { + if (!options.ignoreUnescapedHTML) { + console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."); + console.warn("https://github.com/highlightjs/highlight.js/wiki/security"); + console.warn("The element with unescaped HTML:"); + console.warn(element); + } + if (options.throwUnescapedHTML) { + const err = new HTMLInjectionError( + "One of your code blocks includes unescaped HTML.", + element.innerHTML + ); + throw err; + } + } + + node = element; + const text = node.textContent; + const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text); + + element.innerHTML = result.value; + element.dataset.highlighted = "yes"; + updateClassName(element, language, result.language); + element.result = { + language: result.language, + // TODO: remove with version 11.0 + re: result.relevance, + relevance: result.relevance + }; + if (result.secondBest) { + element.secondBest = { + language: result.secondBest.language, + relevance: result.secondBest.relevance + }; + } + + fire("after:highlightElement", { el: element, result, text }); + } + + /** + * Updates highlight.js global options with the passed options + * + * @param {Partial} userOptions + */ + function configure(userOptions) { + options = inherit(options, userOptions); + } + + // TODO: remove v12, deprecated + const initHighlighting = () => { + highlightAll(); + deprecated("10.6.0", "initHighlighting() deprecated. Use highlightAll() now."); + }; + + // TODO: remove v12, deprecated + function initHighlightingOnLoad() { + highlightAll(); + deprecated("10.6.0", "initHighlightingOnLoad() deprecated. Use highlightAll() now."); + } + + let wantsHighlight = false; + + /** + * auto-highlights all pre>code elements on the page + */ + function highlightAll() { + // if we are called too early in the loading process + if (document.readyState === "loading") { + wantsHighlight = true; + return; + } + + const blocks = document.querySelectorAll(options.cssSelector); + blocks.forEach(highlightElement); + } + + function boot() { + // if a highlight was requested before DOM was loaded, do now + if (wantsHighlight) highlightAll(); + } + + // make sure we are in the browser environment + if (typeof window !== 'undefined' && window.addEventListener) { + window.addEventListener('DOMContentLoaded', boot, false); + } + + /** + * Register a language grammar module + * + * @param {string} languageName + * @param {LanguageFn} languageDefinition + */ + function registerLanguage(languageName, languageDefinition) { + let lang = null; + try { + lang = languageDefinition(hljs); + } catch (error$1) { + error("Language definition for '{}' could not be registered.".replace("{}", languageName)); + // hard or soft error + if (!SAFE_MODE) { throw error$1; } else { error(error$1); } + // languages that have serious errors are replaced with essentially a + // "plaintext" stand-in so that the code blocks will still get normal + // css classes applied to them - and one bad language won't break the + // entire highlighter + lang = PLAINTEXT_LANGUAGE; + } + // give it a temporary name if it doesn't have one in the meta-data + if (!lang.name) lang.name = languageName; + languages[languageName] = lang; + lang.rawDefinition = languageDefinition.bind(null, hljs); + + if (lang.aliases) { + registerAliases(lang.aliases, { languageName }); + } + } + + /** + * Remove a language grammar module + * + * @param {string} languageName + */ + function unregisterLanguage(languageName) { + delete languages[languageName]; + for (const alias of Object.keys(aliases)) { + if (aliases[alias] === languageName) { + delete aliases[alias]; + } + } + } + + /** + * @returns {string[]} List of language internal names + */ + function listLanguages() { + return Object.keys(languages); + } + + /** + * @param {string} name - name of the language to retrieve + * @returns {Language | undefined} + */ + function getLanguage(name) { + name = (name || '').toLowerCase(); + return languages[name] || languages[aliases[name]]; + } + + /** + * + * @param {string|string[]} aliasList - single alias or list of aliases + * @param {{languageName: string}} opts + */ + function registerAliases(aliasList, { languageName }) { + if (typeof aliasList === 'string') { + aliasList = [aliasList]; + } + aliasList.forEach(alias => { aliases[alias.toLowerCase()] = languageName; }); + } + + /** + * Determines if a given language has auto-detection enabled + * @param {string} name - name of the language + */ + function autoDetection(name) { + const lang = getLanguage(name); + return lang && !lang.disableAutodetect; + } + + /** + * Upgrades the old highlightBlock plugins to the new + * highlightElement API + * @param {HLJSPlugin} plugin + */ + function upgradePluginAPI(plugin) { + // TODO: remove with v12 + if (plugin["before:highlightBlock"] && !plugin["before:highlightElement"]) { + plugin["before:highlightElement"] = (data) => { + plugin["before:highlightBlock"]( + Object.assign({ block: data.el }, data) + ); + }; + } + if (plugin["after:highlightBlock"] && !plugin["after:highlightElement"]) { + plugin["after:highlightElement"] = (data) => { + plugin["after:highlightBlock"]( + Object.assign({ block: data.el }, data) + ); + }; + } + } + + /** + * @param {HLJSPlugin} plugin + */ + function addPlugin(plugin) { + upgradePluginAPI(plugin); + plugins.push(plugin); + } + + /** + * @param {HLJSPlugin} plugin + */ + function removePlugin(plugin) { + const index = plugins.indexOf(plugin); + if (index !== -1) { + plugins.splice(index, 1); + } + } + + /** + * + * @param {PluginEvent} event + * @param {any} args + */ + function fire(event, args) { + const cb = event; + plugins.forEach(function(plugin) { + if (plugin[cb]) { + plugin[cb](args); + } + }); + } + + /** + * DEPRECATED + * @param {HighlightedHTMLElement} el + */ + function deprecateHighlightBlock(el) { + deprecated("10.7.0", "highlightBlock will be removed entirely in v12.0"); + deprecated("10.7.0", "Please use highlightElement now."); + + return highlightElement(el); + } + + /* Interface definition */ + Object.assign(hljs, { + highlight, + highlightAuto, + highlightAll, + highlightElement, + // TODO: Remove with v12 API + highlightBlock: deprecateHighlightBlock, + configure, + initHighlighting, + initHighlightingOnLoad, + registerLanguage, + unregisterLanguage, + listLanguages, + getLanguage, + registerAliases, + autoDetection, + inherit, + addPlugin, + removePlugin + }); + + hljs.debugMode = function() { SAFE_MODE = false; }; + hljs.safeMode = function() { SAFE_MODE = true; }; + hljs.versionString = version; + + hljs.regex = { + concat: concat, + lookahead: lookahead, + either: either, + optional: optional, + anyNumberOfTimes: anyNumberOfTimes + }; + + for (const key in MODES) { + // @ts-ignore + if (typeof MODES[key] === "object") { + // @ts-ignore + deepFreeze(MODES[key]); + } + } + + // merge all the modes/regexes into our main object + Object.assign(hljs, MODES); + + return hljs; + }; + + // Other names for the variable may break build script + const highlight = HLJS({}); + + // returns a new instance of the highlighter to be used for extensions + // check https://github.com/wooorm/lowlight/issues/47 + highlight.newInstance = () => HLJS({}); + + return highlight; + +})(); +if (typeof exports === 'object' && typeof module !== 'undefined') { module.exports = hljs; } +/*! `apache` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Apache config + Author: Ruslan Keba + Contributors: Ivan Sagalaev + Website: https://httpd.apache.org + Description: language definition for Apache configuration files (httpd.conf & .htaccess) + Category: config, web + Audit: 2020 + */ + + /** @type LanguageFn */ + function apache(hljs) { + const NUMBER_REF = { + className: 'number', + begin: /[$%]\d+/ + }; + const NUMBER = { + className: 'number', + begin: /\b\d+/ + }; + const IP_ADDRESS = { + className: "number", + begin: /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(:\d{1,5})?/ + }; + const PORT_NUMBER = { + className: "number", + begin: /:\d{1,5}/ + }; + return { + name: 'Apache config', + aliases: [ 'apacheconf' ], + case_insensitive: true, + contains: [ + hljs.HASH_COMMENT_MODE, + { + className: 'section', + begin: /<\/?/, + end: />/, + contains: [ + IP_ADDRESS, + PORT_NUMBER, + // low relevance prevents us from claming XML/HTML where this rule would + // match strings inside of XML tags + hljs.inherit(hljs.QUOTE_STRING_MODE, { relevance: 0 }) + ] + }, + { + className: 'attribute', + begin: /\w+/, + relevance: 0, + // keywords aren’t needed for highlighting per se, they only boost relevance + // for a very generally defined mode (starts with a word, ends with line-end + keywords: { _: [ + "order", + "deny", + "allow", + "setenv", + "rewriterule", + "rewriteengine", + "rewritecond", + "documentroot", + "sethandler", + "errordocument", + "loadmodule", + "options", + "header", + "listen", + "serverroot", + "servername" + ] }, + starts: { + end: /$/, + relevance: 0, + keywords: { literal: 'on off all deny allow' }, + contains: [ + { + className: 'meta', + begin: /\s\[/, + end: /\]$/ + }, + { + className: 'variable', + begin: /[\$%]\{/, + end: /\}/, + contains: [ + 'self', + NUMBER_REF + ] + }, + IP_ADDRESS, + NUMBER, + hljs.QUOTE_STRING_MODE + ] + } + } + ], + illegal: /\S/ + }; + } + + return apache; + +})(); + + hljs.registerLanguage('apache', hljsGrammar); + })();/*! `awk` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Awk + Author: Matthew Daly + Website: https://www.gnu.org/software/gawk/manual/gawk.html + Description: language definition for Awk scripts + Category: scripting + */ + + /** @type LanguageFn */ + function awk(hljs) { + const VARIABLE = { + className: 'variable', + variants: [ + { begin: /\$[\w\d#@][\w\d_]*/ }, + { begin: /\$\{(.*?)\}/ } + ] + }; + const KEYWORDS = 'BEGIN END if else while do for in break continue delete next nextfile function func exit|10'; + const STRING = { + className: 'string', + contains: [ hljs.BACKSLASH_ESCAPE ], + variants: [ + { + begin: /(u|b)?r?'''/, + end: /'''/, + relevance: 10 + }, + { + begin: /(u|b)?r?"""/, + end: /"""/, + relevance: 10 + }, + { + begin: /(u|r|ur)'/, + end: /'/, + relevance: 10 + }, + { + begin: /(u|r|ur)"/, + end: /"/, + relevance: 10 + }, + { + begin: /(b|br)'/, + end: /'/ + }, + { + begin: /(b|br)"/, + end: /"/ + }, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE + ] + }; + return { + name: 'Awk', + keywords: { keyword: KEYWORDS }, + contains: [ + VARIABLE, + STRING, + hljs.REGEXP_MODE, + hljs.HASH_COMMENT_MODE, + hljs.NUMBER_MODE + ] + }; + } + + return awk; + +})(); + + hljs.registerLanguage('awk', hljsGrammar); + })();/*! `bash` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Bash + Author: vah + Contributrors: Benjamin Pannell + Website: https://www.gnu.org/software/bash/ + Category: common, scripting + */ + + /** @type LanguageFn */ + function bash(hljs) { + const regex = hljs.regex; + const VAR = {}; + const BRACED_VAR = { + begin: /\$\{/, + end: /\}/, + contains: [ + "self", + { + begin: /:-/, + contains: [ VAR ] + } // default values + ] + }; + Object.assign(VAR, { + className: 'variable', + variants: [ + { begin: regex.concat(/\$[\w\d#@][\w\d_]*/, + // negative look-ahead tries to avoid matching patterns that are not + // Perl at all like $ident$, @ident@, etc. + `(?![\\w\\d])(?![$])`) }, + BRACED_VAR + ] + }); + + const SUBST = { + className: 'subst', + begin: /\$\(/, + end: /\)/, + contains: [ hljs.BACKSLASH_ESCAPE ] + }; + const COMMENT = hljs.inherit( + hljs.COMMENT(), + { + match: [ + /(^|\s)/, + /#.*$/ + ], + scope: { + 2: 'comment' + } + } + ); + const HERE_DOC = { + begin: /<<-?\s*(?=\w+)/, + starts: { contains: [ + hljs.END_SAME_AS_BEGIN({ + begin: /(\w+)/, + end: /(\w+)/, + className: 'string' + }) + ] } + }; + const QUOTE_STRING = { + className: 'string', + begin: /"/, + end: /"/, + contains: [ + hljs.BACKSLASH_ESCAPE, + VAR, + SUBST + ] + }; + SUBST.contains.push(QUOTE_STRING); + const ESCAPED_QUOTE = { + match: /\\"/ + }; + const APOS_STRING = { + className: 'string', + begin: /'/, + end: /'/ + }; + const ESCAPED_APOS = { + match: /\\'/ + }; + const ARITHMETIC = { + begin: /\$?\(\(/, + end: /\)\)/, + contains: [ + { + begin: /\d+#[0-9a-f]+/, + className: "number" + }, + hljs.NUMBER_MODE, + VAR + ] + }; + const SH_LIKE_SHELLS = [ + "fish", + "bash", + "zsh", + "sh", + "csh", + "ksh", + "tcsh", + "dash", + "scsh", + ]; + const KNOWN_SHEBANG = hljs.SHEBANG({ + binary: `(${SH_LIKE_SHELLS.join("|")})`, + relevance: 10 + }); + const FUNCTION = { + className: 'function', + begin: /\w[\w\d_]*\s*\(\s*\)\s*\{/, + returnBegin: true, + contains: [ hljs.inherit(hljs.TITLE_MODE, { begin: /\w[\w\d_]*/ }) ], + relevance: 0 + }; + + const KEYWORDS = [ + "if", + "then", + "else", + "elif", + "fi", + "for", + "while", + "until", + "in", + "do", + "done", + "case", + "esac", + "function", + "select" + ]; + + const LITERALS = [ + "true", + "false" + ]; + + // to consume paths to prevent keyword matches inside them + const PATH_MODE = { match: /(\/[a-z._-]+)+/ }; + + // http://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html + const SHELL_BUILT_INS = [ + "break", + "cd", + "continue", + "eval", + "exec", + "exit", + "export", + "getopts", + "hash", + "pwd", + "readonly", + "return", + "shift", + "test", + "times", + "trap", + "umask", + "unset" + ]; + + const BASH_BUILT_INS = [ + "alias", + "bind", + "builtin", + "caller", + "command", + "declare", + "echo", + "enable", + "help", + "let", + "local", + "logout", + "mapfile", + "printf", + "read", + "readarray", + "source", + "type", + "typeset", + "ulimit", + "unalias" + ]; + + const ZSH_BUILT_INS = [ + "autoload", + "bg", + "bindkey", + "bye", + "cap", + "chdir", + "clone", + "comparguments", + "compcall", + "compctl", + "compdescribe", + "compfiles", + "compgroups", + "compquote", + "comptags", + "comptry", + "compvalues", + "dirs", + "disable", + "disown", + "echotc", + "echoti", + "emulate", + "fc", + "fg", + "float", + "functions", + "getcap", + "getln", + "history", + "integer", + "jobs", + "kill", + "limit", + "log", + "noglob", + "popd", + "print", + "pushd", + "pushln", + "rehash", + "sched", + "setcap", + "setopt", + "stat", + "suspend", + "ttyctl", + "unfunction", + "unhash", + "unlimit", + "unsetopt", + "vared", + "wait", + "whence", + "where", + "which", + "zcompile", + "zformat", + "zftp", + "zle", + "zmodload", + "zparseopts", + "zprof", + "zpty", + "zregexparse", + "zsocket", + "zstyle", + "ztcp" + ]; + + const GNU_CORE_UTILS = [ + "chcon", + "chgrp", + "chown", + "chmod", + "cp", + "dd", + "df", + "dir", + "dircolors", + "ln", + "ls", + "mkdir", + "mkfifo", + "mknod", + "mktemp", + "mv", + "realpath", + "rm", + "rmdir", + "shred", + "sync", + "touch", + "truncate", + "vdir", + "b2sum", + "base32", + "base64", + "cat", + "cksum", + "comm", + "csplit", + "cut", + "expand", + "fmt", + "fold", + "head", + "join", + "md5sum", + "nl", + "numfmt", + "od", + "paste", + "ptx", + "pr", + "sha1sum", + "sha224sum", + "sha256sum", + "sha384sum", + "sha512sum", + "shuf", + "sort", + "split", + "sum", + "tac", + "tail", + "tr", + "tsort", + "unexpand", + "uniq", + "wc", + "arch", + "basename", + "chroot", + "date", + "dirname", + "du", + "echo", + "env", + "expr", + "factor", + // "false", // keyword literal already + "groups", + "hostid", + "id", + "link", + "logname", + "nice", + "nohup", + "nproc", + "pathchk", + "pinky", + "printenv", + "printf", + "pwd", + "readlink", + "runcon", + "seq", + "sleep", + "stat", + "stdbuf", + "stty", + "tee", + "test", + "timeout", + // "true", // keyword literal already + "tty", + "uname", + "unlink", + "uptime", + "users", + "who", + "whoami", + "yes" + ]; + + return { + name: 'Bash', + aliases: [ 'sh' ], + keywords: { + $pattern: /\b[a-z][a-z0-9._-]+\b/, + keyword: KEYWORDS, + literal: LITERALS, + built_in: [ + ...SHELL_BUILT_INS, + ...BASH_BUILT_INS, + // Shell modifiers + "set", + "shopt", + ...ZSH_BUILT_INS, + ...GNU_CORE_UTILS + ] + }, + contains: [ + KNOWN_SHEBANG, // to catch known shells and boost relevancy + hljs.SHEBANG(), // to catch unknown shells but still highlight the shebang + FUNCTION, + ARITHMETIC, + COMMENT, + HERE_DOC, + PATH_MODE, + QUOTE_STRING, + ESCAPED_QUOTE, + APOS_STRING, + ESCAPED_APOS, + VAR + ] + }; + } + + return bash; + +})(); + + hljs.registerLanguage('bash', hljsGrammar); + })();/*! `basic` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: BASIC + Author: Raphaël Assénat + Description: Based on the BASIC reference from the Tandy 1000 guide + Website: https://en.wikipedia.org/wiki/Tandy_1000 + Category: system + */ + + /** @type LanguageFn */ + function basic(hljs) { + const KEYWORDS = [ + "ABS", + "ASC", + "AND", + "ATN", + "AUTO|0", + "BEEP", + "BLOAD|10", + "BSAVE|10", + "CALL", + "CALLS", + "CDBL", + "CHAIN", + "CHDIR", + "CHR$|10", + "CINT", + "CIRCLE", + "CLEAR", + "CLOSE", + "CLS", + "COLOR", + "COM", + "COMMON", + "CONT", + "COS", + "CSNG", + "CSRLIN", + "CVD", + "CVI", + "CVS", + "DATA", + "DATE$", + "DEFDBL", + "DEFINT", + "DEFSNG", + "DEFSTR", + "DEF|0", + "SEG", + "USR", + "DELETE", + "DIM", + "DRAW", + "EDIT", + "END", + "ENVIRON", + "ENVIRON$", + "EOF", + "EQV", + "ERASE", + "ERDEV", + "ERDEV$", + "ERL", + "ERR", + "ERROR", + "EXP", + "FIELD", + "FILES", + "FIX", + "FOR|0", + "FRE", + "GET", + "GOSUB|10", + "GOTO", + "HEX$", + "IF", + "THEN", + "ELSE|0", + "INKEY$", + "INP", + "INPUT", + "INPUT#", + "INPUT$", + "INSTR", + "IMP", + "INT", + "IOCTL", + "IOCTL$", + "KEY", + "ON", + "OFF", + "LIST", + "KILL", + "LEFT$", + "LEN", + "LET", + "LINE", + "LLIST", + "LOAD", + "LOC", + "LOCATE", + "LOF", + "LOG", + "LPRINT", + "USING", + "LSET", + "MERGE", + "MID$", + "MKDIR", + "MKD$", + "MKI$", + "MKS$", + "MOD", + "NAME", + "NEW", + "NEXT", + "NOISE", + "NOT", + "OCT$", + "ON", + "OR", + "PEN", + "PLAY", + "STRIG", + "OPEN", + "OPTION", + "BASE", + "OUT", + "PAINT", + "PALETTE", + "PCOPY", + "PEEK", + "PMAP", + "POINT", + "POKE", + "POS", + "PRINT", + "PRINT]", + "PSET", + "PRESET", + "PUT", + "RANDOMIZE", + "READ", + "REM", + "RENUM", + "RESET|0", + "RESTORE", + "RESUME", + "RETURN|0", + "RIGHT$", + "RMDIR", + "RND", + "RSET", + "RUN", + "SAVE", + "SCREEN", + "SGN", + "SHELL", + "SIN", + "SOUND", + "SPACE$", + "SPC", + "SQR", + "STEP", + "STICK", + "STOP", + "STR$", + "STRING$", + "SWAP", + "SYSTEM", + "TAB", + "TAN", + "TIME$", + "TIMER", + "TROFF", + "TRON", + "TO", + "USR", + "VAL", + "VARPTR", + "VARPTR$", + "VIEW", + "WAIT", + "WHILE", + "WEND", + "WIDTH", + "WINDOW", + "WRITE", + "XOR" + ]; + + return { + name: 'BASIC', + case_insensitive: true, + illegal: '^\.', + // Support explicitly typed variables that end with $%! or #. + keywords: { + $pattern: '[a-zA-Z][a-zA-Z0-9_$%!#]*', + keyword: KEYWORDS + }, + contains: [ + hljs.QUOTE_STRING_MODE, + hljs.COMMENT('REM', '$', { relevance: 10 }), + hljs.COMMENT('\'', '$', { relevance: 0 }), + { + // Match line numbers + className: 'symbol', + begin: '^[0-9]+ ', + relevance: 10 + }, + { + // Match typed numeric constants (1000, 12.34!, 1.2e5, 1.5#, 1.2D2) + className: 'number', + begin: '\\b\\d+(\\.\\d+)?([edED]\\d+)?[#\!]?', + relevance: 0 + }, + { + // Match hexadecimal numbers (&Hxxxx) + className: 'number', + begin: '(&[hH][0-9a-fA-F]{1,4})' + }, + { + // Match octal numbers (&Oxxxxxx) + className: 'number', + begin: '(&[oO][0-7]{1,6})' + } + ] + }; + } + + return basic; + +})(); + + hljs.registerLanguage('basic', hljsGrammar); + })();/*! `c` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: C + Category: common, system + Website: https://en.wikipedia.org/wiki/C_(programming_language) + */ + + /** @type LanguageFn */ + function c(hljs) { + const regex = hljs.regex; + // added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does + // not include such support nor can we be sure all the grammars depending + // on it would desire this behavior + const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] }); + const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)'; + const NAMESPACE_RE = '[a-zA-Z_]\\w*::'; + const TEMPLATE_ARGUMENT_RE = '<[^<>]+>'; + const FUNCTION_TYPE_RE = '(' + + DECLTYPE_AUTO_RE + '|' + + regex.optional(NAMESPACE_RE) + + '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE) + + ')'; + + + const TYPES = { + className: 'type', + variants: [ + { begin: '\\b[a-z\\d_]*_t\\b' }, + { match: /\batomic_[a-z]{3,6}\b/ } + ] + + }; + + // https://en.cppreference.com/w/cpp/language/escape + // \\ \x \xFF \u2837 \u00323747 \374 + const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)'; + const STRINGS = { + className: 'string', + variants: [ + { + begin: '(u8?|U|L)?"', + end: '"', + illegal: '\\n', + contains: [ hljs.BACKSLASH_ESCAPE ] + }, + { + begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + "|.)", + end: '\'', + illegal: '.' + }, + hljs.END_SAME_AS_BEGIN({ + begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/, + end: /\)([^()\\ ]{0,16})"/ + }) + ] + }; + + const NUMBERS = { + className: 'number', + variants: [ + { begin: '\\b(0b[01\']+)' }, + { begin: '(-?)\\b([\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)' }, + { begin: '(-?)(\\b0[xX][a-fA-F0-9\']+|(\\b[\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)([eE][-+]?[\\d\']+)?)' } + ], + relevance: 0 + }; + + const PREPROCESSOR = { + className: 'meta', + begin: /#\s*[a-z]+\b/, + end: /$/, + keywords: { keyword: + 'if else elif endif define undef warning error line ' + + 'pragma _Pragma ifdef ifndef include' }, + contains: [ + { + begin: /\\\n/, + relevance: 0 + }, + hljs.inherit(STRINGS, { className: 'string' }), + { + className: 'string', + begin: /<.*?>/ + }, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }; + + const TITLE_MODE = { + className: 'title', + begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE, + relevance: 0 + }; + + const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\('; + + const C_KEYWORDS = [ + "asm", + "auto", + "break", + "case", + "continue", + "default", + "do", + "else", + "enum", + "extern", + "for", + "fortran", + "goto", + "if", + "inline", + "register", + "restrict", + "return", + "sizeof", + "struct", + "switch", + "typedef", + "union", + "volatile", + "while", + "_Alignas", + "_Alignof", + "_Atomic", + "_Generic", + "_Noreturn", + "_Static_assert", + "_Thread_local", + // aliases + "alignas", + "alignof", + "noreturn", + "static_assert", + "thread_local", + // not a C keyword but is, for all intents and purposes, treated exactly like one. + "_Pragma" + ]; + + const C_TYPES = [ + "float", + "double", + "signed", + "unsigned", + "int", + "short", + "long", + "char", + "void", + "_Bool", + "_Complex", + "_Imaginary", + "_Decimal32", + "_Decimal64", + "_Decimal128", + // modifiers + "const", + "static", + // aliases + "complex", + "bool", + "imaginary" + ]; + + const KEYWORDS = { + keyword: C_KEYWORDS, + type: C_TYPES, + literal: 'true false NULL', + // TODO: apply hinting work similar to what was done in cpp.js + built_in: 'std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream ' + + 'auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set ' + + 'unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos ' + + 'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp ' + + 'fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper ' + + 'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow ' + + 'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp ' + + 'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan ' + + 'vfprintf vprintf vsprintf endl initializer_list unique_ptr', + }; + + const EXPRESSION_CONTAINS = [ + PREPROCESSOR, + TYPES, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + NUMBERS, + STRINGS + ]; + + const EXPRESSION_CONTEXT = { + // This mode covers expression context where we can't expect a function + // definition and shouldn't highlight anything that looks like one: + // `return some()`, `else if()`, `(x*sum(1, 2))` + variants: [ + { + begin: /=/, + end: /;/ + }, + { + begin: /\(/, + end: /\)/ + }, + { + beginKeywords: 'new throw return else', + end: /;/ + } + ], + keywords: KEYWORDS, + contains: EXPRESSION_CONTAINS.concat([ + { + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + contains: EXPRESSION_CONTAINS.concat([ 'self' ]), + relevance: 0 + } + ]), + relevance: 0 + }; + + const FUNCTION_DECLARATION = { + begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE, + returnBegin: true, + end: /[{;=]/, + excludeEnd: true, + keywords: KEYWORDS, + illegal: /[^\w\s\*&:<>.]/, + contains: [ + { // to prevent it from being confused as the function title + begin: DECLTYPE_AUTO_RE, + keywords: KEYWORDS, + relevance: 0 + }, + { + begin: FUNCTION_TITLE, + returnBegin: true, + contains: [ hljs.inherit(TITLE_MODE, { className: "title.function" }) ], + relevance: 0 + }, + // allow for multiple declarations, e.g.: + // extern void f(int), g(char); + { + relevance: 0, + match: /,/ + }, + { + className: 'params', + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + relevance: 0, + contains: [ + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRINGS, + NUMBERS, + TYPES, + // Count matching parentheses. + { + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + relevance: 0, + contains: [ + 'self', + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRINGS, + NUMBERS, + TYPES + ] + } + ] + }, + TYPES, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + PREPROCESSOR + ] + }; + + return { + name: "C", + aliases: [ 'h' ], + keywords: KEYWORDS, + // Until differentiations are added between `c` and `cpp`, `c` will + // not be auto-detected to avoid auto-detect conflicts between C and C++ + disableAutodetect: true, + illegal: '=]/, + contains: [ + { beginKeywords: "final class struct" }, + hljs.TITLE_MODE + ] + } + ]), + exports: { + preprocessor: PREPROCESSOR, + strings: STRINGS, + keywords: KEYWORDS + } + }; + } + + return c; + +})(); + + hljs.registerLanguage('c', hljsGrammar); + })();/*! `clojure` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Clojure + Description: Clojure syntax (based on lisp.js) + Author: mfornos + Website: https://clojure.org + Category: lisp + */ + + /** @type LanguageFn */ + function clojure(hljs) { + const SYMBOLSTART = 'a-zA-Z_\\-!.?+*=<>&\''; + const SYMBOL_RE = '[#]?[' + SYMBOLSTART + '][' + SYMBOLSTART + '0-9/;:$#]*'; + const globals = 'def defonce defprotocol defstruct defmulti defmethod defn- defn defmacro deftype defrecord'; + const keywords = { + $pattern: SYMBOL_RE, + built_in: + // Clojure keywords + globals + ' ' + + 'cond apply if-not if-let if not not= =|0 <|0 >|0 <=|0 >=|0 ==|0 +|0 /|0 *|0 -|0 rem ' + + 'quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? ' + + 'set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? ' + + 'class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? ' + + 'string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . ' + + 'inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last ' + + 'drop-while while intern condp case reduced cycle split-at split-with repeat replicate ' + + 'iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext ' + + 'nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends ' + + 'add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler ' + + 'set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter ' + + 'monitor-exit macroexpand macroexpand-1 for dosync and or ' + + 'when when-not when-let comp juxt partial sequence memoize constantly complement identity assert ' + + 'peek pop doto proxy first rest cons cast coll last butlast ' + + 'sigs reify second ffirst fnext nfirst nnext meta with-meta ns in-ns create-ns import ' + + 'refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! ' + + 'assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger ' + + 'bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline ' + + 'flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking ' + + 'assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! ' + + 'reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! ' + + 'new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty ' + + 'hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list ' + + 'disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer ' + + 'chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate ' + + 'unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta ' + + 'lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize' + }; + + const SYMBOL = { + begin: SYMBOL_RE, + relevance: 0 + }; + const NUMBER = { + scope: 'number', + relevance: 0, + variants: [ + { match: /[-+]?0[xX][0-9a-fA-F]+N?/ }, // hexadecimal // 0x2a + { match: /[-+]?0[0-7]+N?/ }, // octal // 052 + { match: /[-+]?[1-9][0-9]?[rR][0-9a-zA-Z]+N?/ }, // variable radix from 2 to 36 // 2r101010, 8r52, 36r16 + { match: /[-+]?[0-9]+\/[0-9]+N?/ }, // ratio // 1/2 + { match: /[-+]?[0-9]+((\.[0-9]*([eE][+-]?[0-9]+)?M?)|([eE][+-]?[0-9]+M?|M))/ }, // float // 0.42 4.2E-1M 42E1 42M + { match: /[-+]?([1-9][0-9]*|0)N?/ }, // int (don't match leading 0) // 42 42N + ] + }; + const CHARACTER = { + scope: 'character', + variants: [ + { match: /\\o[0-3]?[0-7]{1,2}/ }, // Unicode Octal 0 - 377 + { match: /\\u[0-9a-fA-F]{4}/ }, // Unicode Hex 0000 - FFFF + { match: /\\(newline|space|tab|formfeed|backspace|return)/ }, // special characters + { + match: /\\\S/, + relevance: 0 + } // any non-whitespace char + ] + }; + const REGEX = { + scope: 'regex', + begin: /#"/, + end: /"/, + contains: [ hljs.BACKSLASH_ESCAPE ] + }; + const STRING = hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }); + const COMMA = { + scope: 'punctuation', + match: /,/, + relevance: 0 + }; + const COMMENT = hljs.COMMENT( + ';', + '$', + { relevance: 0 } + ); + const LITERAL = { + className: 'literal', + begin: /\b(true|false|nil)\b/ + }; + const COLLECTION = { + begin: "\\[|(#::?" + SYMBOL_RE + ")?\\{", + end: '[\\]\\}]', + relevance: 0 + }; + const KEY = { + className: 'symbol', + begin: '[:]{1,2}' + SYMBOL_RE + }; + const LIST = { + begin: '\\(', + end: '\\)' + }; + const BODY = { + endsWithParent: true, + relevance: 0 + }; + const NAME = { + keywords: keywords, + className: 'name', + begin: SYMBOL_RE, + relevance: 0, + starts: BODY + }; + const DEFAULT_CONTAINS = [ + COMMA, + LIST, + CHARACTER, + REGEX, + STRING, + COMMENT, + KEY, + COLLECTION, + NUMBER, + LITERAL, + SYMBOL + ]; + + const GLOBAL = { + beginKeywords: globals, + keywords: { + $pattern: SYMBOL_RE, + keyword: globals + }, + end: '(\\[|#|\\d|"|:|\\{|\\)|\\(|$)', + contains: [ + { + className: 'title', + begin: SYMBOL_RE, + relevance: 0, + excludeEnd: true, + // we can only have a single title + endsParent: true + } + ].concat(DEFAULT_CONTAINS) + }; + + LIST.contains = [ + GLOBAL, + NAME, + BODY + ]; + BODY.contains = DEFAULT_CONTAINS; + COLLECTION.contains = DEFAULT_CONTAINS; + + return { + name: 'Clojure', + aliases: [ + 'clj', + 'edn' + ], + illegal: /\S/, + contains: [ + COMMA, + LIST, + CHARACTER, + REGEX, + STRING, + COMMENT, + KEY, + COLLECTION, + NUMBER, + LITERAL + ] + }; + } + + return clojure; + +})(); + + hljs.registerLanguage('clojure', hljsGrammar); + })();/*! `cmake` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: CMake + Description: CMake is an open-source cross-platform system for build automation. + Author: Igor Kalnitsky + Website: https://cmake.org + Category: build-system + */ + + /** @type LanguageFn */ + function cmake(hljs) { + return { + name: 'CMake', + aliases: [ 'cmake.in' ], + case_insensitive: true, + keywords: { keyword: + // scripting commands + 'break cmake_host_system_information cmake_minimum_required cmake_parse_arguments ' + + 'cmake_policy configure_file continue elseif else endforeach endfunction endif endmacro ' + + 'endwhile execute_process file find_file find_library find_package find_path ' + + 'find_program foreach function get_cmake_property get_directory_property ' + + 'get_filename_component get_property if include include_guard list macro ' + + 'mark_as_advanced math message option return separate_arguments ' + + 'set_directory_properties set_property set site_name string unset variable_watch while ' + // project commands + + 'add_compile_definitions add_compile_options add_custom_command add_custom_target ' + + 'add_definitions add_dependencies add_executable add_library add_link_options ' + + 'add_subdirectory add_test aux_source_directory build_command create_test_sourcelist ' + + 'define_property enable_language enable_testing export fltk_wrap_ui ' + + 'get_source_file_property get_target_property get_test_property include_directories ' + + 'include_external_msproject include_regular_expression install link_directories ' + + 'link_libraries load_cache project qt_wrap_cpp qt_wrap_ui remove_definitions ' + + 'set_source_files_properties set_target_properties set_tests_properties source_group ' + + 'target_compile_definitions target_compile_features target_compile_options ' + + 'target_include_directories target_link_directories target_link_libraries ' + + 'target_link_options target_sources try_compile try_run ' + // CTest commands + + 'ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ' + + 'ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ' + + 'ctest_test ctest_update ctest_upload ' + // deprecated commands + + 'build_name exec_program export_library_dependencies install_files install_programs ' + + 'install_targets load_command make_directory output_required_files remove ' + + 'subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file ' + + 'qt5_use_modules qt5_use_package qt5_wrap_cpp ' + // core keywords + + 'on off true false and or not command policy target test exists is_newer_than ' + + 'is_directory is_symlink is_absolute matches less greater equal less_equal ' + + 'greater_equal strless strgreater strequal strless_equal strgreater_equal version_less ' + + 'version_greater version_equal version_less_equal version_greater_equal in_list defined' }, + contains: [ + { + className: 'variable', + begin: /\$\{/, + end: /\}/ + }, + hljs.COMMENT(/#\[\[/, /]]/), + hljs.HASH_COMMENT_MODE, + hljs.QUOTE_STRING_MODE, + hljs.NUMBER_MODE + ] + }; + } + + return cmake; + +})(); + + hljs.registerLanguage('cmake', hljsGrammar); + })();/*! `cpp` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: C++ + Category: common, system + Website: https://isocpp.org + */ + + /** @type LanguageFn */ + function cpp(hljs) { + const regex = hljs.regex; + // added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does + // not include such support nor can we be sure all the grammars depending + // on it would desire this behavior + const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] }); + const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)'; + const NAMESPACE_RE = '[a-zA-Z_]\\w*::'; + const TEMPLATE_ARGUMENT_RE = '<[^<>]+>'; + const FUNCTION_TYPE_RE = '(?!struct)(' + + DECLTYPE_AUTO_RE + '|' + + regex.optional(NAMESPACE_RE) + + '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE) + + ')'; + + const CPP_PRIMITIVE_TYPES = { + className: 'type', + begin: '\\b[a-z\\d_]*_t\\b' + }; + + // https://en.cppreference.com/w/cpp/language/escape + // \\ \x \xFF \u2837 \u00323747 \374 + const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)'; + const STRINGS = { + className: 'string', + variants: [ + { + begin: '(u8?|U|L)?"', + end: '"', + illegal: '\\n', + contains: [ hljs.BACKSLASH_ESCAPE ] + }, + { + begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + '|.)', + end: '\'', + illegal: '.' + }, + hljs.END_SAME_AS_BEGIN({ + begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/, + end: /\)([^()\\ ]{0,16})"/ + }) + ] + }; + + const NUMBERS = { + className: 'number', + variants: [ + // Floating-point literal. + { begin: + "[+-]?(?:" // Leading sign. + // Decimal. + + "(?:" + +"[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?" + + "|\\.[0-9](?:'?[0-9])*" + + ")(?:[Ee][+-]?[0-9](?:'?[0-9])*)?" + + "|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*" + // Hexadecimal. + + "|0[Xx](?:" + +"[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?" + + "|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*" + + ")[Pp][+-]?[0-9](?:'?[0-9])*" + + ")(?:" // Literal suffixes. + + "[Ff](?:16|32|64|128)?" + + "|(BF|bf)16" + + "|[Ll]" + + "|" // Literal suffix is optional. + + ")" + }, + // Integer literal. + { begin: + "[+-]?\\b(?:" // Leading sign. + + "0[Bb][01](?:'?[01])*" // Binary. + + "|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*" // Hexadecimal. + + "|0(?:'?[0-7])*" // Octal or just a lone zero. + + "|[1-9](?:'?[0-9])*" // Decimal. + + ")(?:" // Literal suffixes. + + "[Uu](?:LL?|ll?)" + + "|[Uu][Zz]?" + + "|(?:LL?|ll?)[Uu]?" + + "|[Zz][Uu]" + + "|" // Literal suffix is optional. + + ")" + // Note: there are user-defined literal suffixes too, but perhaps having the custom suffix not part of the + // literal highlight actually makes it stand out more. + } + ], + relevance: 0 + }; + + const PREPROCESSOR = { + className: 'meta', + begin: /#\s*[a-z]+\b/, + end: /$/, + keywords: { keyword: + 'if else elif endif define undef warning error line ' + + 'pragma _Pragma ifdef ifndef include' }, + contains: [ + { + begin: /\\\n/, + relevance: 0 + }, + hljs.inherit(STRINGS, { className: 'string' }), + { + className: 'string', + begin: /<.*?>/ + }, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }; + + const TITLE_MODE = { + className: 'title', + begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE, + relevance: 0 + }; + + const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\('; + + // https://en.cppreference.com/w/cpp/keyword + const RESERVED_KEYWORDS = [ + 'alignas', + 'alignof', + 'and', + 'and_eq', + 'asm', + 'atomic_cancel', + 'atomic_commit', + 'atomic_noexcept', + 'auto', + 'bitand', + 'bitor', + 'break', + 'case', + 'catch', + 'class', + 'co_await', + 'co_return', + 'co_yield', + 'compl', + 'concept', + 'const_cast|10', + 'consteval', + 'constexpr', + 'constinit', + 'continue', + 'decltype', + 'default', + 'delete', + 'do', + 'dynamic_cast|10', + 'else', + 'enum', + 'explicit', + 'export', + 'extern', + 'false', + 'final', + 'for', + 'friend', + 'goto', + 'if', + 'import', + 'inline', + 'module', + 'mutable', + 'namespace', + 'new', + 'noexcept', + 'not', + 'not_eq', + 'nullptr', + 'operator', + 'or', + 'or_eq', + 'override', + 'private', + 'protected', + 'public', + 'reflexpr', + 'register', + 'reinterpret_cast|10', + 'requires', + 'return', + 'sizeof', + 'static_assert', + 'static_cast|10', + 'struct', + 'switch', + 'synchronized', + 'template', + 'this', + 'thread_local', + 'throw', + 'transaction_safe', + 'transaction_safe_dynamic', + 'true', + 'try', + 'typedef', + 'typeid', + 'typename', + 'union', + 'using', + 'virtual', + 'volatile', + 'while', + 'xor', + 'xor_eq' + ]; + + // https://en.cppreference.com/w/cpp/keyword + const RESERVED_TYPES = [ + 'bool', + 'char', + 'char16_t', + 'char32_t', + 'char8_t', + 'double', + 'float', + 'int', + 'long', + 'short', + 'void', + 'wchar_t', + 'unsigned', + 'signed', + 'const', + 'static' + ]; + + const TYPE_HINTS = [ + 'any', + 'auto_ptr', + 'barrier', + 'binary_semaphore', + 'bitset', + 'complex', + 'condition_variable', + 'condition_variable_any', + 'counting_semaphore', + 'deque', + 'false_type', + 'future', + 'imaginary', + 'initializer_list', + 'istringstream', + 'jthread', + 'latch', + 'lock_guard', + 'multimap', + 'multiset', + 'mutex', + 'optional', + 'ostringstream', + 'packaged_task', + 'pair', + 'promise', + 'priority_queue', + 'queue', + 'recursive_mutex', + 'recursive_timed_mutex', + 'scoped_lock', + 'set', + 'shared_future', + 'shared_lock', + 'shared_mutex', + 'shared_timed_mutex', + 'shared_ptr', + 'stack', + 'string_view', + 'stringstream', + 'timed_mutex', + 'thread', + 'true_type', + 'tuple', + 'unique_lock', + 'unique_ptr', + 'unordered_map', + 'unordered_multimap', + 'unordered_multiset', + 'unordered_set', + 'variant', + 'vector', + 'weak_ptr', + 'wstring', + 'wstring_view' + ]; + + const FUNCTION_HINTS = [ + 'abort', + 'abs', + 'acos', + 'apply', + 'as_const', + 'asin', + 'atan', + 'atan2', + 'calloc', + 'ceil', + 'cerr', + 'cin', + 'clog', + 'cos', + 'cosh', + 'cout', + 'declval', + 'endl', + 'exchange', + 'exit', + 'exp', + 'fabs', + 'floor', + 'fmod', + 'forward', + 'fprintf', + 'fputs', + 'free', + 'frexp', + 'fscanf', + 'future', + 'invoke', + 'isalnum', + 'isalpha', + 'iscntrl', + 'isdigit', + 'isgraph', + 'islower', + 'isprint', + 'ispunct', + 'isspace', + 'isupper', + 'isxdigit', + 'labs', + 'launder', + 'ldexp', + 'log', + 'log10', + 'make_pair', + 'make_shared', + 'make_shared_for_overwrite', + 'make_tuple', + 'make_unique', + 'malloc', + 'memchr', + 'memcmp', + 'memcpy', + 'memset', + 'modf', + 'move', + 'pow', + 'printf', + 'putchar', + 'puts', + 'realloc', + 'scanf', + 'sin', + 'sinh', + 'snprintf', + 'sprintf', + 'sqrt', + 'sscanf', + 'std', + 'stderr', + 'stdin', + 'stdout', + 'strcat', + 'strchr', + 'strcmp', + 'strcpy', + 'strcspn', + 'strlen', + 'strncat', + 'strncmp', + 'strncpy', + 'strpbrk', + 'strrchr', + 'strspn', + 'strstr', + 'swap', + 'tan', + 'tanh', + 'terminate', + 'to_underlying', + 'tolower', + 'toupper', + 'vfprintf', + 'visit', + 'vprintf', + 'vsprintf' + ]; + + const LITERALS = [ + 'NULL', + 'false', + 'nullopt', + 'nullptr', + 'true' + ]; + + // https://en.cppreference.com/w/cpp/keyword + const BUILT_IN = [ '_Pragma' ]; + + const CPP_KEYWORDS = { + type: RESERVED_TYPES, + keyword: RESERVED_KEYWORDS, + literal: LITERALS, + built_in: BUILT_IN, + _type_hints: TYPE_HINTS + }; + + const FUNCTION_DISPATCH = { + className: 'function.dispatch', + relevance: 0, + keywords: { + // Only for relevance, not highlighting. + _hint: FUNCTION_HINTS }, + begin: regex.concat( + /\b/, + /(?!decltype)/, + /(?!if)/, + /(?!for)/, + /(?!switch)/, + /(?!while)/, + hljs.IDENT_RE, + regex.lookahead(/(<[^<>]+>|)\s*\(/)) + }; + + const EXPRESSION_CONTAINS = [ + FUNCTION_DISPATCH, + PREPROCESSOR, + CPP_PRIMITIVE_TYPES, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + NUMBERS, + STRINGS + ]; + + const EXPRESSION_CONTEXT = { + // This mode covers expression context where we can't expect a function + // definition and shouldn't highlight anything that looks like one: + // `return some()`, `else if()`, `(x*sum(1, 2))` + variants: [ + { + begin: /=/, + end: /;/ + }, + { + begin: /\(/, + end: /\)/ + }, + { + beginKeywords: 'new throw return else', + end: /;/ + } + ], + keywords: CPP_KEYWORDS, + contains: EXPRESSION_CONTAINS.concat([ + { + begin: /\(/, + end: /\)/, + keywords: CPP_KEYWORDS, + contains: EXPRESSION_CONTAINS.concat([ 'self' ]), + relevance: 0 + } + ]), + relevance: 0 + }; + + const FUNCTION_DECLARATION = { + className: 'function', + begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE, + returnBegin: true, + end: /[{;=]/, + excludeEnd: true, + keywords: CPP_KEYWORDS, + illegal: /[^\w\s\*&:<>.]/, + contains: [ + { // to prevent it from being confused as the function title + begin: DECLTYPE_AUTO_RE, + keywords: CPP_KEYWORDS, + relevance: 0 + }, + { + begin: FUNCTION_TITLE, + returnBegin: true, + contains: [ TITLE_MODE ], + relevance: 0 + }, + // needed because we do not have look-behind on the below rule + // to prevent it from grabbing the final : in a :: pair + { + begin: /::/, + relevance: 0 + }, + // initializers + { + begin: /:/, + endsWithParent: true, + contains: [ + STRINGS, + NUMBERS + ] + }, + // allow for multiple declarations, e.g.: + // extern void f(int), g(char); + { + relevance: 0, + match: /,/ + }, + { + className: 'params', + begin: /\(/, + end: /\)/, + keywords: CPP_KEYWORDS, + relevance: 0, + contains: [ + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRINGS, + NUMBERS, + CPP_PRIMITIVE_TYPES, + // Count matching parentheses. + { + begin: /\(/, + end: /\)/, + keywords: CPP_KEYWORDS, + relevance: 0, + contains: [ + 'self', + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRINGS, + NUMBERS, + CPP_PRIMITIVE_TYPES + ] + } + ] + }, + CPP_PRIMITIVE_TYPES, + C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + PREPROCESSOR + ] + }; + + return { + name: 'C++', + aliases: [ + 'cc', + 'c++', + 'h++', + 'hpp', + 'hh', + 'hxx', + 'cxx' + ], + keywords: CPP_KEYWORDS, + illegal: ' rooms (9);` + begin: '\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function)\\s*<(?!<)', + end: '>', + keywords: CPP_KEYWORDS, + contains: [ + 'self', + CPP_PRIMITIVE_TYPES + ] + }, + { + begin: hljs.IDENT_RE + '::', + keywords: CPP_KEYWORDS + }, + { + match: [ + // extra complexity to deal with `enum class` and `enum struct` + /\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/, + /\s+/, + /\w+/ + ], + className: { + 1: 'keyword', + 3: 'title.class' + } + } + ]) + }; + } + + return cpp; + +})(); + + hljs.registerLanguage('cpp', hljsGrammar); + })();/*! `crystal` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Crystal + Author: TSUYUSATO Kitsune + Website: https://crystal-lang.org + Category: system + */ + + /** @type LanguageFn */ + function crystal(hljs) { + const INT_SUFFIX = '(_?[ui](8|16|32|64|128))?'; + const FLOAT_SUFFIX = '(_?f(32|64))?'; + const CRYSTAL_IDENT_RE = '[a-zA-Z_]\\w*[!?=]?'; + const CRYSTAL_METHOD_RE = '[a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|[=!]~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~|]|//|//=|&[-+*]=?|&\\*\\*|\\[\\][=?]?'; + const CRYSTAL_PATH_RE = '[A-Za-z_]\\w*(::\\w+)*(\\?|!)?'; + const CRYSTAL_KEYWORDS = { + $pattern: CRYSTAL_IDENT_RE, + keyword: + 'abstract alias annotation as as? asm begin break case class def do else elsif end ensure enum extend for fun if ' + + 'include instance_sizeof is_a? lib macro module next nil? of out pointerof private protected rescue responds_to? ' + + 'return require select self sizeof struct super then type typeof union uninitialized unless until verbatim when while with yield ' + + '__DIR__ __END_LINE__ __FILE__ __LINE__', + literal: 'false nil true' + }; + const SUBST = { + className: 'subst', + begin: /#\{/, + end: /\}/, + keywords: CRYSTAL_KEYWORDS + }; + // borrowed from Ruby + const VARIABLE = { + // negative-look forward attemps to prevent false matches like: + // @ident@ or $ident$ that might indicate this is not ruby at all + className: "variable", + begin: '(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])' + `(?![A-Za-z])(?![@$?'])` + }; + const EXPANSION = { + className: 'template-variable', + variants: [ + { + begin: '\\{\\{', + end: '\\}\\}' + }, + { + begin: '\\{%', + end: '%\\}' + } + ], + keywords: CRYSTAL_KEYWORDS + }; + + function recursiveParen(begin, end) { + const + contains = [ + { + begin: begin, + end: end + } + ]; + contains[0].contains = contains; + return contains; + } + const STRING = { + className: 'string', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + variants: [ + { + begin: /'/, + end: /'/ + }, + { + begin: /"/, + end: /"/ + }, + { + begin: /`/, + end: /`/ + }, + { + begin: '%[Qwi]?\\(', + end: '\\)', + contains: recursiveParen('\\(', '\\)') + }, + { + begin: '%[Qwi]?\\[', + end: '\\]', + contains: recursiveParen('\\[', '\\]') + }, + { + begin: '%[Qwi]?\\{', + end: /\}/, + contains: recursiveParen(/\{/, /\}/) + }, + { + begin: '%[Qwi]?<', + end: '>', + contains: recursiveParen('<', '>') + }, + { + begin: '%[Qwi]?\\|', + end: '\\|' + }, + { + begin: /<<-\w+$/, + end: /^\s*\w+$/ + } + ], + relevance: 0 + }; + const Q_STRING = { + className: 'string', + variants: [ + { + begin: '%q\\(', + end: '\\)', + contains: recursiveParen('\\(', '\\)') + }, + { + begin: '%q\\[', + end: '\\]', + contains: recursiveParen('\\[', '\\]') + }, + { + begin: '%q\\{', + end: /\}/, + contains: recursiveParen(/\{/, /\}/) + }, + { + begin: '%q<', + end: '>', + contains: recursiveParen('<', '>') + }, + { + begin: '%q\\|', + end: '\\|' + }, + { + begin: /<<-'\w+'$/, + end: /^\s*\w+$/ + } + ], + relevance: 0 + }; + const REGEXP = { + begin: '(?!%\\})(' + hljs.RE_STARTERS_RE + '|\\n|\\b(case|if|select|unless|until|when|while)\\b)\\s*', + keywords: 'case if select unless until when while', + contains: [ + { + className: 'regexp', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + variants: [ + { + begin: '//[a-z]*', + relevance: 0 + }, + { + begin: '/(?!\\/)', + end: '/[a-z]*' + } + ] + } + ], + relevance: 0 + }; + const REGEXP2 = { + className: 'regexp', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + variants: [ + { + begin: '%r\\(', + end: '\\)', + contains: recursiveParen('\\(', '\\)') + }, + { + begin: '%r\\[', + end: '\\]', + contains: recursiveParen('\\[', '\\]') + }, + { + begin: '%r\\{', + end: /\}/, + contains: recursiveParen(/\{/, /\}/) + }, + { + begin: '%r<', + end: '>', + contains: recursiveParen('<', '>') + }, + { + begin: '%r\\|', + end: '\\|' + } + ], + relevance: 0 + }; + const ATTRIBUTE = { + className: 'meta', + begin: '@\\[', + end: '\\]', + contains: [ hljs.inherit(hljs.QUOTE_STRING_MODE, { className: 'string' }) ] + }; + const CRYSTAL_DEFAULT_CONTAINS = [ + EXPANSION, + STRING, + Q_STRING, + REGEXP2, + REGEXP, + ATTRIBUTE, + VARIABLE, + hljs.HASH_COMMENT_MODE, + { + className: 'class', + beginKeywords: 'class module struct', + end: '$|;', + illegal: /=/, + contains: [ + hljs.HASH_COMMENT_MODE, + hljs.inherit(hljs.TITLE_MODE, { begin: CRYSTAL_PATH_RE }), + { // relevance booster for inheritance + begin: '<' } + ] + }, + { + className: 'class', + beginKeywords: 'lib enum union', + end: '$|;', + illegal: /=/, + contains: [ + hljs.HASH_COMMENT_MODE, + hljs.inherit(hljs.TITLE_MODE, { begin: CRYSTAL_PATH_RE }) + ] + }, + { + beginKeywords: 'annotation', + end: '$|;', + illegal: /=/, + contains: [ + hljs.HASH_COMMENT_MODE, + hljs.inherit(hljs.TITLE_MODE, { begin: CRYSTAL_PATH_RE }) + ], + relevance: 2 + }, + { + className: 'function', + beginKeywords: 'def', + end: /\B\b/, + contains: [ + hljs.inherit(hljs.TITLE_MODE, { + begin: CRYSTAL_METHOD_RE, + endsParent: true + }) + ] + }, + { + className: 'function', + beginKeywords: 'fun macro', + end: /\B\b/, + contains: [ + hljs.inherit(hljs.TITLE_MODE, { + begin: CRYSTAL_METHOD_RE, + endsParent: true + }) + ], + relevance: 2 + }, + { + className: 'symbol', + begin: hljs.UNDERSCORE_IDENT_RE + '(!|\\?)?:', + relevance: 0 + }, + { + className: 'symbol', + begin: ':', + contains: [ + STRING, + { begin: CRYSTAL_METHOD_RE } + ], + relevance: 0 + }, + { + className: 'number', + variants: [ + { begin: '\\b0b([01_]+)' + INT_SUFFIX }, + { begin: '\\b0o([0-7_]+)' + INT_SUFFIX }, + { begin: '\\b0x([A-Fa-f0-9_]+)' + INT_SUFFIX }, + { begin: '\\b([1-9][0-9_]*[0-9]|[0-9])(\\.[0-9][0-9_]*)?([eE]_?[-+]?[0-9_]*)?' + FLOAT_SUFFIX + '(?!_)' }, + { begin: '\\b([1-9][0-9_]*|0)' + INT_SUFFIX } + ], + relevance: 0 + } + ]; + SUBST.contains = CRYSTAL_DEFAULT_CONTAINS; + EXPANSION.contains = CRYSTAL_DEFAULT_CONTAINS.slice(1); // without EXPANSION + + return { + name: 'Crystal', + aliases: [ 'cr' ], + keywords: CRYSTAL_KEYWORDS, + contains: CRYSTAL_DEFAULT_CONTAINS + }; + } + + return crystal; + +})(); + + hljs.registerLanguage('crystal', hljsGrammar); + })();/*! `csharp` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: C# + Author: Jason Diamond + Contributor: Nicolas LLOBERA , Pieter Vantorre , David Pine + Website: https://docs.microsoft.com/dotnet/csharp/ + Category: common + */ + + /** @type LanguageFn */ + function csharp(hljs) { + const BUILT_IN_KEYWORDS = [ + 'bool', + 'byte', + 'char', + 'decimal', + 'delegate', + 'double', + 'dynamic', + 'enum', + 'float', + 'int', + 'long', + 'nint', + 'nuint', + 'object', + 'sbyte', + 'short', + 'string', + 'ulong', + 'uint', + 'ushort' + ]; + const FUNCTION_MODIFIERS = [ + 'public', + 'private', + 'protected', + 'static', + 'internal', + 'protected', + 'abstract', + 'async', + 'extern', + 'override', + 'unsafe', + 'virtual', + 'new', + 'sealed', + 'partial' + ]; + const LITERAL_KEYWORDS = [ + 'default', + 'false', + 'null', + 'true' + ]; + const NORMAL_KEYWORDS = [ + 'abstract', + 'as', + 'base', + 'break', + 'case', + 'catch', + 'class', + 'const', + 'continue', + 'do', + 'else', + 'event', + 'explicit', + 'extern', + 'finally', + 'fixed', + 'for', + 'foreach', + 'goto', + 'if', + 'implicit', + 'in', + 'interface', + 'internal', + 'is', + 'lock', + 'namespace', + 'new', + 'operator', + 'out', + 'override', + 'params', + 'private', + 'protected', + 'public', + 'readonly', + 'record', + 'ref', + 'return', + 'scoped', + 'sealed', + 'sizeof', + 'stackalloc', + 'static', + 'struct', + 'switch', + 'this', + 'throw', + 'try', + 'typeof', + 'unchecked', + 'unsafe', + 'using', + 'virtual', + 'void', + 'volatile', + 'while' + ]; + const CONTEXTUAL_KEYWORDS = [ + 'add', + 'alias', + 'and', + 'ascending', + 'async', + 'await', + 'by', + 'descending', + 'equals', + 'from', + 'get', + 'global', + 'group', + 'init', + 'into', + 'join', + 'let', + 'nameof', + 'not', + 'notnull', + 'on', + 'or', + 'orderby', + 'partial', + 'remove', + 'select', + 'set', + 'unmanaged', + 'value|0', + 'var', + 'when', + 'where', + 'with', + 'yield' + ]; + + const KEYWORDS = { + keyword: NORMAL_KEYWORDS.concat(CONTEXTUAL_KEYWORDS), + built_in: BUILT_IN_KEYWORDS, + literal: LITERAL_KEYWORDS + }; + const TITLE_MODE = hljs.inherit(hljs.TITLE_MODE, { begin: '[a-zA-Z](\\.?\\w)*' }); + const NUMBERS = { + className: 'number', + variants: [ + { begin: '\\b(0b[01\']+)' }, + { begin: '(-?)\\b([\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)(u|U|l|L|ul|UL|f|F|b|B)' }, + { begin: '(-?)(\\b0[xX][a-fA-F0-9\']+|(\\b[\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)([eE][-+]?[\\d\']+)?)' } + ], + relevance: 0 + }; + const VERBATIM_STRING = { + className: 'string', + begin: '@"', + end: '"', + contains: [ { begin: '""' } ] + }; + const VERBATIM_STRING_NO_LF = hljs.inherit(VERBATIM_STRING, { illegal: /\n/ }); + const SUBST = { + className: 'subst', + begin: /\{/, + end: /\}/, + keywords: KEYWORDS + }; + const SUBST_NO_LF = hljs.inherit(SUBST, { illegal: /\n/ }); + const INTERPOLATED_STRING = { + className: 'string', + begin: /\$"/, + end: '"', + illegal: /\n/, + contains: [ + { begin: /\{\{/ }, + { begin: /\}\}/ }, + hljs.BACKSLASH_ESCAPE, + SUBST_NO_LF + ] + }; + const INTERPOLATED_VERBATIM_STRING = { + className: 'string', + begin: /\$@"/, + end: '"', + contains: [ + { begin: /\{\{/ }, + { begin: /\}\}/ }, + { begin: '""' }, + SUBST + ] + }; + const INTERPOLATED_VERBATIM_STRING_NO_LF = hljs.inherit(INTERPOLATED_VERBATIM_STRING, { + illegal: /\n/, + contains: [ + { begin: /\{\{/ }, + { begin: /\}\}/ }, + { begin: '""' }, + SUBST_NO_LF + ] + }); + SUBST.contains = [ + INTERPOLATED_VERBATIM_STRING, + INTERPOLATED_STRING, + VERBATIM_STRING, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + NUMBERS, + hljs.C_BLOCK_COMMENT_MODE + ]; + SUBST_NO_LF.contains = [ + INTERPOLATED_VERBATIM_STRING_NO_LF, + INTERPOLATED_STRING, + VERBATIM_STRING_NO_LF, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + NUMBERS, + hljs.inherit(hljs.C_BLOCK_COMMENT_MODE, { illegal: /\n/ }) + ]; + const STRING = { variants: [ + INTERPOLATED_VERBATIM_STRING, + INTERPOLATED_STRING, + VERBATIM_STRING, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE + ] }; + + const GENERIC_MODIFIER = { + begin: "<", + end: ">", + contains: [ + { beginKeywords: "in out" }, + TITLE_MODE + ] + }; + const TYPE_IDENT_RE = hljs.IDENT_RE + '(<' + hljs.IDENT_RE + '(\\s*,\\s*' + hljs.IDENT_RE + ')*>)?(\\[\\])?'; + const AT_IDENTIFIER = { + // prevents expressions like `@class` from incorrect flagging + // `class` as a keyword + begin: "@" + hljs.IDENT_RE, + relevance: 0 + }; + + return { + name: 'C#', + aliases: [ + 'cs', + 'c#' + ], + keywords: KEYWORDS, + illegal: /::/, + contains: [ + hljs.COMMENT( + '///', + '$', + { + returnBegin: true, + contains: [ + { + className: 'doctag', + variants: [ + { + begin: '///', + relevance: 0 + }, + { begin: '' }, + { + begin: '' + } + ] + } + ] + } + ), + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + { + className: 'meta', + begin: '#', + end: '$', + keywords: { keyword: 'if else elif endif define undef warning error line region endregion pragma checksum' } + }, + STRING, + NUMBERS, + { + beginKeywords: 'class interface', + relevance: 0, + end: /[{;=]/, + illegal: /[^\s:,]/, + contains: [ + { beginKeywords: "where class" }, + TITLE_MODE, + GENERIC_MODIFIER, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + { + beginKeywords: 'namespace', + relevance: 0, + end: /[{;=]/, + illegal: /[^\s:]/, + contains: [ + TITLE_MODE, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + { + beginKeywords: 'record', + relevance: 0, + end: /[{;=]/, + illegal: /[^\s:]/, + contains: [ + TITLE_MODE, + GENERIC_MODIFIER, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + { + // [Attributes("")] + className: 'meta', + begin: '^\\s*\\[(?=[\\w])', + excludeBegin: true, + end: '\\]', + excludeEnd: true, + contains: [ + { + className: 'string', + begin: /"/, + end: /"/ + } + ] + }, + { + // Expression keywords prevent 'keyword Name(...)' from being + // recognized as a function definition + beginKeywords: 'new return throw await else', + relevance: 0 + }, + { + className: 'function', + begin: '(' + TYPE_IDENT_RE + '\\s+)+' + hljs.IDENT_RE + '\\s*(<[^=]+>\\s*)?\\(', + returnBegin: true, + end: /\s*[{;=]/, + excludeEnd: true, + keywords: KEYWORDS, + contains: [ + // prevents these from being highlighted `title` + { + beginKeywords: FUNCTION_MODIFIERS.join(" "), + relevance: 0 + }, + { + begin: hljs.IDENT_RE + '\\s*(<[^=]+>\\s*)?\\(', + returnBegin: true, + contains: [ + hljs.TITLE_MODE, + GENERIC_MODIFIER + ], + relevance: 0 + }, + { match: /\(\)/ }, + { + className: 'params', + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, + keywords: KEYWORDS, + relevance: 0, + contains: [ + STRING, + NUMBERS, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + AT_IDENTIFIER + ] + }; + } + + return csharp; + +})(); + + hljs.registerLanguage('csharp', hljsGrammar); + })();/*! `css` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + const MODES = (hljs) => { + return { + IMPORTANT: { + scope: 'meta', + begin: '!important' + }, + BLOCK_COMMENT: hljs.C_BLOCK_COMMENT_MODE, + HEXCOLOR: { + scope: 'number', + begin: /#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/ + }, + FUNCTION_DISPATCH: { + className: "built_in", + begin: /[\w-]+(?=\()/ + }, + ATTRIBUTE_SELECTOR_MODE: { + scope: 'selector-attr', + begin: /\[/, + end: /\]/, + illegal: '$', + contains: [ + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE + ] + }, + CSS_NUMBER_MODE: { + scope: 'number', + begin: hljs.NUMBER_RE + '(' + + '%|em|ex|ch|rem' + + '|vw|vh|vmin|vmax' + + '|cm|mm|in|pt|pc|px' + + '|deg|grad|rad|turn' + + '|s|ms' + + '|Hz|kHz' + + '|dpi|dpcm|dppx' + + ')?', + relevance: 0 + }, + CSS_VARIABLE: { + className: "attr", + begin: /--[A-Za-z_][A-Za-z0-9_-]*/ + } + }; + }; + + const HTML_TAGS = [ + 'a', + 'abbr', + 'address', + 'article', + 'aside', + 'audio', + 'b', + 'blockquote', + 'body', + 'button', + 'canvas', + 'caption', + 'cite', + 'code', + 'dd', + 'del', + 'details', + 'dfn', + 'div', + 'dl', + 'dt', + 'em', + 'fieldset', + 'figcaption', + 'figure', + 'footer', + 'form', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'header', + 'hgroup', + 'html', + 'i', + 'iframe', + 'img', + 'input', + 'ins', + 'kbd', + 'label', + 'legend', + 'li', + 'main', + 'mark', + 'menu', + 'nav', + 'object', + 'ol', + 'p', + 'q', + 'quote', + 'samp', + 'section', + 'span', + 'strong', + 'summary', + 'sup', + 'table', + 'tbody', + 'td', + 'textarea', + 'tfoot', + 'th', + 'thead', + 'time', + 'tr', + 'ul', + 'var', + 'video' + ]; + + const SVG_TAGS = [ + 'defs', + 'g', + 'marker', + 'mask', + 'pattern', + 'svg', + 'switch', + 'symbol', + 'feBlend', + 'feColorMatrix', + 'feComponentTransfer', + 'feComposite', + 'feConvolveMatrix', + 'feDiffuseLighting', + 'feDisplacementMap', + 'feFlood', + 'feGaussianBlur', + 'feImage', + 'feMerge', + 'feMorphology', + 'feOffset', + 'feSpecularLighting', + 'feTile', + 'feTurbulence', + 'linearGradient', + 'radialGradient', + 'stop', + 'circle', + 'ellipse', + 'image', + 'line', + 'path', + 'polygon', + 'polyline', + 'rect', + 'text', + 'use', + 'textPath', + 'tspan', + 'foreignObject', + 'clipPath' + ]; + + const TAGS = [ + ...HTML_TAGS, + ...SVG_TAGS, + ]; + + // Sorting, then reversing makes sure longer attributes/elements like + // `font-weight` are matched fully instead of getting false positives on say `font` + + const MEDIA_FEATURES = [ + 'any-hover', + 'any-pointer', + 'aspect-ratio', + 'color', + 'color-gamut', + 'color-index', + 'device-aspect-ratio', + 'device-height', + 'device-width', + 'display-mode', + 'forced-colors', + 'grid', + 'height', + 'hover', + 'inverted-colors', + 'monochrome', + 'orientation', + 'overflow-block', + 'overflow-inline', + 'pointer', + 'prefers-color-scheme', + 'prefers-contrast', + 'prefers-reduced-motion', + 'prefers-reduced-transparency', + 'resolution', + 'scan', + 'scripting', + 'update', + 'width', + // TODO: find a better solution? + 'min-width', + 'max-width', + 'min-height', + 'max-height' + ].sort().reverse(); + + // https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes + const PSEUDO_CLASSES = [ + 'active', + 'any-link', + 'blank', + 'checked', + 'current', + 'default', + 'defined', + 'dir', // dir() + 'disabled', + 'drop', + 'empty', + 'enabled', + 'first', + 'first-child', + 'first-of-type', + 'fullscreen', + 'future', + 'focus', + 'focus-visible', + 'focus-within', + 'has', // has() + 'host', // host or host() + 'host-context', // host-context() + 'hover', + 'indeterminate', + 'in-range', + 'invalid', + 'is', // is() + 'lang', // lang() + 'last-child', + 'last-of-type', + 'left', + 'link', + 'local-link', + 'not', // not() + 'nth-child', // nth-child() + 'nth-col', // nth-col() + 'nth-last-child', // nth-last-child() + 'nth-last-col', // nth-last-col() + 'nth-last-of-type', //nth-last-of-type() + 'nth-of-type', //nth-of-type() + 'only-child', + 'only-of-type', + 'optional', + 'out-of-range', + 'past', + 'placeholder-shown', + 'read-only', + 'read-write', + 'required', + 'right', + 'root', + 'scope', + 'target', + 'target-within', + 'user-invalid', + 'valid', + 'visited', + 'where' // where() + ].sort().reverse(); + + // https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements + const PSEUDO_ELEMENTS = [ + 'after', + 'backdrop', + 'before', + 'cue', + 'cue-region', + 'first-letter', + 'first-line', + 'grammar-error', + 'marker', + 'part', + 'placeholder', + 'selection', + 'slotted', + 'spelling-error' + ].sort().reverse(); + + const ATTRIBUTES = [ + 'align-content', + 'align-items', + 'align-self', + 'alignment-baseline', + 'all', + 'animation', + 'animation-delay', + 'animation-direction', + 'animation-duration', + 'animation-fill-mode', + 'animation-iteration-count', + 'animation-name', + 'animation-play-state', + 'animation-timing-function', + 'backface-visibility', + 'background', + 'background-attachment', + 'background-blend-mode', + 'background-clip', + 'background-color', + 'background-image', + 'background-origin', + 'background-position', + 'background-repeat', + 'background-size', + 'baseline-shift', + 'block-size', + 'border', + 'border-block', + 'border-block-color', + 'border-block-end', + 'border-block-end-color', + 'border-block-end-style', + 'border-block-end-width', + 'border-block-start', + 'border-block-start-color', + 'border-block-start-style', + 'border-block-start-width', + 'border-block-style', + 'border-block-width', + 'border-bottom', + 'border-bottom-color', + 'border-bottom-left-radius', + 'border-bottom-right-radius', + 'border-bottom-style', + 'border-bottom-width', + 'border-collapse', + 'border-color', + 'border-image', + 'border-image-outset', + 'border-image-repeat', + 'border-image-slice', + 'border-image-source', + 'border-image-width', + 'border-inline', + 'border-inline-color', + 'border-inline-end', + 'border-inline-end-color', + 'border-inline-end-style', + 'border-inline-end-width', + 'border-inline-start', + 'border-inline-start-color', + 'border-inline-start-style', + 'border-inline-start-width', + 'border-inline-style', + 'border-inline-width', + 'border-left', + 'border-left-color', + 'border-left-style', + 'border-left-width', + 'border-radius', + 'border-right', + 'border-right-color', + 'border-right-style', + 'border-right-width', + 'border-spacing', + 'border-style', + 'border-top', + 'border-top-color', + 'border-top-left-radius', + 'border-top-right-radius', + 'border-top-style', + 'border-top-width', + 'border-width', + 'bottom', + 'box-decoration-break', + 'box-shadow', + 'box-sizing', + 'break-after', + 'break-before', + 'break-inside', + 'cx', + 'cy', + 'caption-side', + 'caret-color', + 'clear', + 'clip', + 'clip-path', + 'clip-rule', + 'color', + 'color-interpolation', + 'color-interpolation-filters', + 'color-profile', + 'color-rendering', + 'column-count', + 'column-fill', + 'column-gap', + 'column-rule', + 'column-rule-color', + 'column-rule-style', + 'column-rule-width', + 'column-span', + 'column-width', + 'columns', + 'contain', + 'content', + 'content-visibility', + 'counter-increment', + 'counter-reset', + 'cue', + 'cue-after', + 'cue-before', + 'cursor', + 'direction', + 'display', + 'dominant-baseline', + 'empty-cells', + 'enable-background', + 'fill', + 'fill-opacity', + 'fill-rule', + 'filter', + 'flex', + 'flex-basis', + 'flex-direction', + 'flex-flow', + 'flex-grow', + 'flex-shrink', + 'flex-wrap', + 'float', + 'flow', + 'flood-color', + 'flood-opacity', + 'font', + 'font-display', + 'font-family', + 'font-feature-settings', + 'font-kerning', + 'font-language-override', + 'font-size', + 'font-size-adjust', + 'font-smoothing', + 'font-stretch', + 'font-style', + 'font-synthesis', + 'font-variant', + 'font-variant-caps', + 'font-variant-east-asian', + 'font-variant-ligatures', + 'font-variant-numeric', + 'font-variant-position', + 'font-variation-settings', + 'font-weight', + 'gap', + 'glyph-orientation-horizontal', + 'glyph-orientation-vertical', + 'grid', + 'grid-area', + 'grid-auto-columns', + 'grid-auto-flow', + 'grid-auto-rows', + 'grid-column', + 'grid-column-end', + 'grid-column-start', + 'grid-gap', + 'grid-row', + 'grid-row-end', + 'grid-row-start', + 'grid-template', + 'grid-template-areas', + 'grid-template-columns', + 'grid-template-rows', + 'hanging-punctuation', + 'height', + 'hyphens', + 'icon', + 'image-orientation', + 'image-rendering', + 'image-resolution', + 'ime-mode', + 'inline-size', + 'isolation', + 'kerning', + 'justify-content', + 'left', + 'letter-spacing', + 'lighting-color', + 'line-break', + 'line-height', + 'list-style', + 'list-style-image', + 'list-style-position', + 'list-style-type', + 'marker', + 'marker-end', + 'marker-mid', + 'marker-start', + 'mask', + 'margin', + 'margin-block', + 'margin-block-end', + 'margin-block-start', + 'margin-bottom', + 'margin-inline', + 'margin-inline-end', + 'margin-inline-start', + 'margin-left', + 'margin-right', + 'margin-top', + 'marks', + 'mask', + 'mask-border', + 'mask-border-mode', + 'mask-border-outset', + 'mask-border-repeat', + 'mask-border-slice', + 'mask-border-source', + 'mask-border-width', + 'mask-clip', + 'mask-composite', + 'mask-image', + 'mask-mode', + 'mask-origin', + 'mask-position', + 'mask-repeat', + 'mask-size', + 'mask-type', + 'max-block-size', + 'max-height', + 'max-inline-size', + 'max-width', + 'min-block-size', + 'min-height', + 'min-inline-size', + 'min-width', + 'mix-blend-mode', + 'nav-down', + 'nav-index', + 'nav-left', + 'nav-right', + 'nav-up', + 'none', + 'normal', + 'object-fit', + 'object-position', + 'opacity', + 'order', + 'orphans', + 'outline', + 'outline-color', + 'outline-offset', + 'outline-style', + 'outline-width', + 'overflow', + 'overflow-wrap', + 'overflow-x', + 'overflow-y', + 'padding', + 'padding-block', + 'padding-block-end', + 'padding-block-start', + 'padding-bottom', + 'padding-inline', + 'padding-inline-end', + 'padding-inline-start', + 'padding-left', + 'padding-right', + 'padding-top', + 'page-break-after', + 'page-break-before', + 'page-break-inside', + 'pause', + 'pause-after', + 'pause-before', + 'perspective', + 'perspective-origin', + 'pointer-events', + 'position', + 'quotes', + 'r', + 'resize', + 'rest', + 'rest-after', + 'rest-before', + 'right', + 'row-gap', + 'scroll-margin', + 'scroll-margin-block', + 'scroll-margin-block-end', + 'scroll-margin-block-start', + 'scroll-margin-bottom', + 'scroll-margin-inline', + 'scroll-margin-inline-end', + 'scroll-margin-inline-start', + 'scroll-margin-left', + 'scroll-margin-right', + 'scroll-margin-top', + 'scroll-padding', + 'scroll-padding-block', + 'scroll-padding-block-end', + 'scroll-padding-block-start', + 'scroll-padding-bottom', + 'scroll-padding-inline', + 'scroll-padding-inline-end', + 'scroll-padding-inline-start', + 'scroll-padding-left', + 'scroll-padding-right', + 'scroll-padding-top', + 'scroll-snap-align', + 'scroll-snap-stop', + 'scroll-snap-type', + 'scrollbar-color', + 'scrollbar-gutter', + 'scrollbar-width', + 'shape-image-threshold', + 'shape-margin', + 'shape-outside', + 'shape-rendering', + 'stop-color', + 'stop-opacity', + 'stroke', + 'stroke-dasharray', + 'stroke-dashoffset', + 'stroke-linecap', + 'stroke-linejoin', + 'stroke-miterlimit', + 'stroke-opacity', + 'stroke-width', + 'speak', + 'speak-as', + 'src', // @font-face + 'tab-size', + 'table-layout', + 'text-anchor', + 'text-align', + 'text-align-all', + 'text-align-last', + 'text-combine-upright', + 'text-decoration', + 'text-decoration-color', + 'text-decoration-line', + 'text-decoration-style', + 'text-emphasis', + 'text-emphasis-color', + 'text-emphasis-position', + 'text-emphasis-style', + 'text-indent', + 'text-justify', + 'text-orientation', + 'text-overflow', + 'text-rendering', + 'text-shadow', + 'text-transform', + 'text-underline-position', + 'top', + 'transform', + 'transform-box', + 'transform-origin', + 'transform-style', + 'transition', + 'transition-delay', + 'transition-duration', + 'transition-property', + 'transition-timing-function', + 'unicode-bidi', + 'vector-effect', + 'vertical-align', + 'visibility', + 'voice-balance', + 'voice-duration', + 'voice-family', + 'voice-pitch', + 'voice-range', + 'voice-rate', + 'voice-stress', + 'voice-volume', + 'white-space', + 'widows', + 'width', + 'will-change', + 'word-break', + 'word-spacing', + 'word-wrap', + 'writing-mode', + 'x', + 'y', + 'z-index' + ].sort().reverse(); + + /* + Language: CSS + Category: common, css, web + Website: https://developer.mozilla.org/en-US/docs/Web/CSS + */ + + + /** @type LanguageFn */ + function css(hljs) { + const regex = hljs.regex; + const modes = MODES(hljs); + const VENDOR_PREFIX = { begin: /-(webkit|moz|ms|o)-(?=[a-z])/ }; + const AT_MODIFIERS = "and or not only"; + const AT_PROPERTY_RE = /@-?\w[\w]*(-\w+)*/; // @-webkit-keyframes + const IDENT_RE = '[a-zA-Z-][a-zA-Z0-9_-]*'; + const STRINGS = [ + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE + ]; + + return { + name: 'CSS', + case_insensitive: true, + illegal: /[=|'\$]/, + keywords: { keyframePosition: "from to" }, + classNameAliases: { + // for visual continuity with `tag {}` and because we + // don't have a great class for this? + keyframePosition: "selector-tag" }, + contains: [ + modes.BLOCK_COMMENT, + VENDOR_PREFIX, + // to recognize keyframe 40% etc which are outside the scope of our + // attribute value mode + modes.CSS_NUMBER_MODE, + { + className: 'selector-id', + begin: /#[A-Za-z0-9_-]+/, + relevance: 0 + }, + { + className: 'selector-class', + begin: '\\.' + IDENT_RE, + relevance: 0 + }, + modes.ATTRIBUTE_SELECTOR_MODE, + { + className: 'selector-pseudo', + variants: [ + { begin: ':(' + PSEUDO_CLASSES.join('|') + ')' }, + { begin: ':(:)?(' + PSEUDO_ELEMENTS.join('|') + ')' } + ] + }, + // we may actually need this (12/2020) + // { // pseudo-selector params + // begin: /\(/, + // end: /\)/, + // contains: [ hljs.CSS_NUMBER_MODE ] + // }, + modes.CSS_VARIABLE, + { + className: 'attribute', + begin: '\\b(' + ATTRIBUTES.join('|') + ')\\b' + }, + // attribute values + { + begin: /:/, + end: /[;}{]/, + contains: [ + modes.BLOCK_COMMENT, + modes.HEXCOLOR, + modes.IMPORTANT, + modes.CSS_NUMBER_MODE, + ...STRINGS, + // needed to highlight these as strings and to avoid issues with + // illegal characters that might be inside urls that would tigger the + // languages illegal stack + { + begin: /(url|data-uri)\(/, + end: /\)/, + relevance: 0, // from keywords + keywords: { built_in: "url data-uri" }, + contains: [ + ...STRINGS, + { + className: "string", + // any character other than `)` as in `url()` will be the start + // of a string, which ends with `)` (from the parent mode) + begin: /[^)]/, + endsWithParent: true, + excludeEnd: true + } + ] + }, + modes.FUNCTION_DISPATCH + ] + }, + { + begin: regex.lookahead(/@/), + end: '[{;]', + relevance: 0, + illegal: /:/, // break on Less variables @var: ... + contains: [ + { + className: 'keyword', + begin: AT_PROPERTY_RE + }, + { + begin: /\s/, + endsWithParent: true, + excludeEnd: true, + relevance: 0, + keywords: { + $pattern: /[a-z-]+/, + keyword: AT_MODIFIERS, + attribute: MEDIA_FEATURES.join(" ") + }, + contains: [ + { + begin: /[a-z-]+(?=:)/, + className: "attribute" + }, + ...STRINGS, + modes.CSS_NUMBER_MODE + ] + } + ] + }, + { + className: 'selector-tag', + begin: '\\b(' + TAGS.join('|') + ')\\b' + } + ] + }; + } + + return css; + +})(); + + hljs.registerLanguage('css', hljsGrammar); + })();/*! `dart` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Dart + Requires: markdown.js + Author: Maxim Dikun + Description: Dart a modern, object-oriented language developed by Google. For more information see https://www.dartlang.org/ + Website: https://dart.dev + Category: scripting + */ + + /** @type LanguageFn */ + function dart(hljs) { + const SUBST = { + className: 'subst', + variants: [ { begin: '\\$[A-Za-z0-9_]+' } ] + }; + + const BRACED_SUBST = { + className: 'subst', + variants: [ + { + begin: /\$\{/, + end: /\}/ + } + ], + keywords: 'true false null this is new super' + }; + + const STRING = { + className: 'string', + variants: [ + { + begin: 'r\'\'\'', + end: '\'\'\'' + }, + { + begin: 'r"""', + end: '"""' + }, + { + begin: 'r\'', + end: '\'', + illegal: '\\n' + }, + { + begin: 'r"', + end: '"', + illegal: '\\n' + }, + { + begin: '\'\'\'', + end: '\'\'\'', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST, + BRACED_SUBST + ] + }, + { + begin: '"""', + end: '"""', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST, + BRACED_SUBST + ] + }, + { + begin: '\'', + end: '\'', + illegal: '\\n', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST, + BRACED_SUBST + ] + }, + { + begin: '"', + end: '"', + illegal: '\\n', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST, + BRACED_SUBST + ] + } + ] + }; + BRACED_SUBST.contains = [ + hljs.C_NUMBER_MODE, + STRING + ]; + + const BUILT_IN_TYPES = [ + // dart:core + 'Comparable', + 'DateTime', + 'Duration', + 'Function', + 'Iterable', + 'Iterator', + 'List', + 'Map', + 'Match', + 'Object', + 'Pattern', + 'RegExp', + 'Set', + 'Stopwatch', + 'String', + 'StringBuffer', + 'StringSink', + 'Symbol', + 'Type', + 'Uri', + 'bool', + 'double', + 'int', + 'num', + // dart:html + 'Element', + 'ElementList' + ]; + const NULLABLE_BUILT_IN_TYPES = BUILT_IN_TYPES.map((e) => `${e}?`); + + const BASIC_KEYWORDS = [ + "abstract", + "as", + "assert", + "async", + "await", + "base", + "break", + "case", + "catch", + "class", + "const", + "continue", + "covariant", + "default", + "deferred", + "do", + "dynamic", + "else", + "enum", + "export", + "extends", + "extension", + "external", + "factory", + "false", + "final", + "finally", + "for", + "Function", + "get", + "hide", + "if", + "implements", + "import", + "in", + "interface", + "is", + "late", + "library", + "mixin", + "new", + "null", + "on", + "operator", + "part", + "required", + "rethrow", + "return", + "sealed", + "set", + "show", + "static", + "super", + "switch", + "sync", + "this", + "throw", + "true", + "try", + "typedef", + "var", + "void", + "when", + "while", + "with", + "yield" + ]; + + const KEYWORDS = { + keyword: BASIC_KEYWORDS, + built_in: + BUILT_IN_TYPES + .concat(NULLABLE_BUILT_IN_TYPES) + .concat([ + // dart:core + 'Never', + 'Null', + 'dynamic', + 'print', + // dart:html + 'document', + 'querySelector', + 'querySelectorAll', + 'window' + ]), + $pattern: /[A-Za-z][A-Za-z0-9_]*\??/ + }; + + return { + name: 'Dart', + keywords: KEYWORDS, + contains: [ + STRING, + hljs.COMMENT( + /\/\*\*(?!\/)/, + /\*\//, + { + subLanguage: 'markdown', + relevance: 0 + } + ), + hljs.COMMENT( + /\/{3,} ?/, + /$/, { contains: [ + { + subLanguage: 'markdown', + begin: '.', + end: '$', + relevance: 0 + } + ] } + ), + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + { + className: 'class', + beginKeywords: 'class interface', + end: /\{/, + excludeEnd: true, + contains: [ + { beginKeywords: 'extends implements' }, + hljs.UNDERSCORE_TITLE_MODE + ] + }, + hljs.C_NUMBER_MODE, + { + className: 'meta', + begin: '@[A-Za-z]+' + }, + { begin: '=>' // No markup, just a relevance booster + } + ] + }; + } + + return dart; + +})(); + + hljs.registerLanguage('dart', hljsGrammar); + })();/*! `delphi` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Delphi + Website: https://www.embarcadero.com/products/delphi + Category: system + */ + + /** @type LanguageFn */ + function delphi(hljs) { + const KEYWORDS = [ + "exports", + "register", + "file", + "shl", + "array", + "record", + "property", + "for", + "mod", + "while", + "set", + "ally", + "label", + "uses", + "raise", + "not", + "stored", + "class", + "safecall", + "var", + "interface", + "or", + "private", + "static", + "exit", + "index", + "inherited", + "to", + "else", + "stdcall", + "override", + "shr", + "asm", + "far", + "resourcestring", + "finalization", + "packed", + "virtual", + "out", + "and", + "protected", + "library", + "do", + "xorwrite", + "goto", + "near", + "function", + "end", + "div", + "overload", + "object", + "unit", + "begin", + "string", + "on", + "inline", + "repeat", + "until", + "destructor", + "write", + "message", + "program", + "with", + "read", + "initialization", + "except", + "default", + "nil", + "if", + "case", + "cdecl", + "in", + "downto", + "threadvar", + "of", + "try", + "pascal", + "const", + "external", + "constructor", + "type", + "public", + "then", + "implementation", + "finally", + "published", + "procedure", + "absolute", + "reintroduce", + "operator", + "as", + "is", + "abstract", + "alias", + "assembler", + "bitpacked", + "break", + "continue", + "cppdecl", + "cvar", + "enumerator", + "experimental", + "platform", + "deprecated", + "unimplemented", + "dynamic", + "export", + "far16", + "forward", + "generic", + "helper", + "implements", + "interrupt", + "iochecks", + "local", + "name", + "nodefault", + "noreturn", + "nostackframe", + "oldfpccall", + "otherwise", + "saveregisters", + "softfloat", + "specialize", + "strict", + "unaligned", + "varargs" + ]; + const COMMENT_MODES = [ + hljs.C_LINE_COMMENT_MODE, + hljs.COMMENT(/\{/, /\}/, { relevance: 0 }), + hljs.COMMENT(/\(\*/, /\*\)/, { relevance: 10 }) + ]; + const DIRECTIVE = { + className: 'meta', + variants: [ + { + begin: /\{\$/, + end: /\}/ + }, + { + begin: /\(\*\$/, + end: /\*\)/ + } + ] + }; + const STRING = { + className: 'string', + begin: /'/, + end: /'/, + contains: [ { begin: /''/ } ] + }; + const NUMBER = { + className: 'number', + relevance: 0, + // Source: https://www.freepascal.org/docs-html/ref/refse6.html + variants: [ + { + // Hexadecimal notation, e.g., $7F. + begin: '\\$[0-9A-Fa-f]+' }, + { + // Octal notation, e.g., &42. + begin: '&[0-7]+' }, + { + // Binary notation, e.g., %1010. + begin: '%[01]+' } + ] + }; + const CHAR_STRING = { + className: 'string', + begin: /(#\d+)+/ + }; + const CLASS = { + begin: hljs.IDENT_RE + '\\s*=\\s*class\\s*\\(', + returnBegin: true, + contains: [ hljs.TITLE_MODE ] + }; + const FUNCTION = { + className: 'function', + beginKeywords: 'function constructor destructor procedure', + end: /[:;]/, + keywords: 'function constructor|10 destructor|10 procedure|10', + contains: [ + hljs.TITLE_MODE, + { + className: 'params', + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + contains: [ + STRING, + CHAR_STRING, + DIRECTIVE + ].concat(COMMENT_MODES) + }, + DIRECTIVE + ].concat(COMMENT_MODES) + }; + return { + name: 'Delphi', + aliases: [ + 'dpr', + 'dfm', + 'pas', + 'pascal' + ], + case_insensitive: true, + keywords: KEYWORDS, + illegal: /"|\$[G-Zg-z]|\/\*|<\/|\|/, + contains: [ + STRING, + CHAR_STRING, + hljs.NUMBER_MODE, + NUMBER, + CLASS, + FUNCTION, + DIRECTIVE + ].concat(COMMENT_MODES) + }; + } + + return delphi; + +})(); + + hljs.registerLanguage('delphi', hljsGrammar); + })();/*! `diff` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Diff + Description: Unified and context diff + Author: Vasily Polovnyov + Website: https://www.gnu.org/software/diffutils/ + Category: common + */ + + /** @type LanguageFn */ + function diff(hljs) { + const regex = hljs.regex; + return { + name: 'Diff', + aliases: [ 'patch' ], + contains: [ + { + className: 'meta', + relevance: 10, + match: regex.either( + /^@@ +-\d+,\d+ +\+\d+,\d+ +@@/, + /^\*\*\* +\d+,\d+ +\*\*\*\*$/, + /^--- +\d+,\d+ +----$/ + ) + }, + { + className: 'comment', + variants: [ + { + begin: regex.either( + /Index: /, + /^index/, + /={3,}/, + /^-{3}/, + /^\*{3} /, + /^\+{3}/, + /^diff --git/ + ), + end: /$/ + }, + { match: /^\*{15}$/ } + ] + }, + { + className: 'addition', + begin: /^\+/, + end: /$/ + }, + { + className: 'deletion', + begin: /^-/, + end: /$/ + }, + { + className: 'addition', + begin: /^!/, + end: /$/ + } + ] + }; + } + + return diff; + +})(); + + hljs.registerLanguage('diff', hljsGrammar); + })();/*! `django` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Django + Description: Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. + Requires: xml.js + Author: Ivan Sagalaev + Contributors: Ilya Baryshev + Website: https://www.djangoproject.com + Category: template + */ + + /** @type LanguageFn */ + function django(hljs) { + const FILTER = { + begin: /\|[A-Za-z]+:?/, + keywords: { name: + 'truncatewords removetags linebreaksbr yesno get_digit timesince random striptags ' + + 'filesizeformat escape linebreaks length_is ljust rjust cut urlize fix_ampersands ' + + 'title floatformat capfirst pprint divisibleby add make_list unordered_list urlencode ' + + 'timeuntil urlizetrunc wordcount stringformat linenumbers slice date dictsort ' + + 'dictsortreversed default_if_none pluralize lower join center default ' + + 'truncatewords_html upper length phone2numeric wordwrap time addslashes slugify first ' + + 'escapejs force_escape iriencode last safe safeseq truncatechars localize unlocalize ' + + 'localtime utc timezone' }, + contains: [ + hljs.QUOTE_STRING_MODE, + hljs.APOS_STRING_MODE + ] + }; + + return { + name: 'Django', + aliases: [ 'jinja' ], + case_insensitive: true, + subLanguage: 'xml', + contains: [ + hljs.COMMENT(/\{%\s*comment\s*%\}/, /\{%\s*endcomment\s*%\}/), + hljs.COMMENT(/\{#/, /#\}/), + { + className: 'template-tag', + begin: /\{%/, + end: /%\}/, + contains: [ + { + className: 'name', + begin: /\w+/, + keywords: { name: + 'comment endcomment load templatetag ifchanged endifchanged if endif firstof for ' + + 'endfor ifnotequal endifnotequal widthratio extends include spaceless ' + + 'endspaceless regroup ifequal endifequal ssi now with cycle url filter ' + + 'endfilter debug block endblock else autoescape endautoescape csrf_token empty elif ' + + 'endwith static trans blocktrans endblocktrans get_static_prefix get_media_prefix ' + + 'plural get_current_language language get_available_languages ' + + 'get_current_language_bidi get_language_info get_language_info_list localize ' + + 'endlocalize localtime endlocaltime timezone endtimezone get_current_timezone ' + + 'verbatim' }, + starts: { + endsWithParent: true, + keywords: 'in by as', + contains: [ FILTER ], + relevance: 0 + } + } + ] + }, + { + className: 'template-variable', + begin: /\{\{/, + end: /\}\}/, + contains: [ FILTER ] + } + ] + }; + } + + return django; + +})(); + + hljs.registerLanguage('django', hljsGrammar); + })();/*! `dockerfile` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Dockerfile + Requires: bash.js + Author: Alexis Hénaut + Description: language definition for Dockerfile files + Website: https://docs.docker.com/engine/reference/builder/ + Category: config + */ + + /** @type LanguageFn */ + function dockerfile(hljs) { + const KEYWORDS = [ + "from", + "maintainer", + "expose", + "env", + "arg", + "user", + "onbuild", + "stopsignal" + ]; + return { + name: 'Dockerfile', + aliases: [ 'docker' ], + case_insensitive: true, + keywords: KEYWORDS, + contains: [ + hljs.HASH_COMMENT_MODE, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + hljs.NUMBER_MODE, + { + beginKeywords: 'run cmd entrypoint volume add copy workdir label healthcheck shell', + starts: { + end: /[^\\]$/, + subLanguage: 'bash' + } + } + ], + illegal: ' + Contributors: Anton Kochkov + Website: https://en.wikipedia.org/wiki/Batch_file + Category: scripting + */ + + /** @type LanguageFn */ + function dos(hljs) { + const COMMENT = hljs.COMMENT( + /^\s*@?rem\b/, /$/, + { relevance: 10 } + ); + const LABEL = { + className: 'symbol', + begin: '^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)', + relevance: 0 + }; + const KEYWORDS = [ + "if", + "else", + "goto", + "for", + "in", + "do", + "call", + "exit", + "not", + "exist", + "errorlevel", + "defined", + "equ", + "neq", + "lss", + "leq", + "gtr", + "geq" + ]; + const BUILT_INS = [ + "prn", + "nul", + "lpt3", + "lpt2", + "lpt1", + "con", + "com4", + "com3", + "com2", + "com1", + "aux", + "shift", + "cd", + "dir", + "echo", + "setlocal", + "endlocal", + "set", + "pause", + "copy", + "append", + "assoc", + "at", + "attrib", + "break", + "cacls", + "cd", + "chcp", + "chdir", + "chkdsk", + "chkntfs", + "cls", + "cmd", + "color", + "comp", + "compact", + "convert", + "date", + "dir", + "diskcomp", + "diskcopy", + "doskey", + "erase", + "fs", + "find", + "findstr", + "format", + "ftype", + "graftabl", + "help", + "keyb", + "label", + "md", + "mkdir", + "mode", + "more", + "move", + "path", + "pause", + "print", + "popd", + "pushd", + "promt", + "rd", + "recover", + "rem", + "rename", + "replace", + "restore", + "rmdir", + "shift", + "sort", + "start", + "subst", + "time", + "title", + "tree", + "type", + "ver", + "verify", + "vol", + // winutils + "ping", + "net", + "ipconfig", + "taskkill", + "xcopy", + "ren", + "del" + ]; + return { + name: 'Batch file (DOS)', + aliases: [ + 'bat', + 'cmd' + ], + case_insensitive: true, + illegal: /\/\*/, + keywords: { + keyword: KEYWORDS, + built_in: BUILT_INS + }, + contains: [ + { + className: 'variable', + begin: /%%[^ ]|%[^ ]+?%|![^ ]+?!/ + }, + { + className: 'function', + begin: LABEL.begin, + end: 'goto:eof', + contains: [ + hljs.inherit(hljs.TITLE_MODE, { begin: '([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*' }), + COMMENT + ] + }, + { + className: 'number', + begin: '\\b\\d+', + relevance: 0 + }, + COMMENT + ] + }; + } + + return dos; + +})(); + + hljs.registerLanguage('dos', hljsGrammar); + })();/*! `elixir` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Elixir + Author: Josh Adams + Description: language definition for Elixir source code files (.ex and .exs). Based on ruby language support. + Category: functional + Website: https://elixir-lang.org + */ + + /** @type LanguageFn */ + function elixir(hljs) { + const regex = hljs.regex; + const ELIXIR_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_.]*(!|\\?)?'; + const ELIXIR_METHOD_RE = '[a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?'; + const KEYWORDS = [ + "after", + "alias", + "and", + "case", + "catch", + "cond", + "defstruct", + "defguard", + "do", + "else", + "end", + "fn", + "for", + "if", + "import", + "in", + "not", + "or", + "quote", + "raise", + "receive", + "require", + "reraise", + "rescue", + "try", + "unless", + "unquote", + "unquote_splicing", + "use", + "when", + "with|0" + ]; + const LITERALS = [ + "false", + "nil", + "true" + ]; + const KWS = { + $pattern: ELIXIR_IDENT_RE, + keyword: KEYWORDS, + literal: LITERALS + }; + const SUBST = { + className: 'subst', + begin: /#\{/, + end: /\}/, + keywords: KWS + }; + const NUMBER = { + className: 'number', + begin: '(\\b0o[0-7_]+)|(\\b0b[01_]+)|(\\b0x[0-9a-fA-F_]+)|(-?\\b[0-9][0-9_]*(\\.[0-9_]+([eE][-+]?[0-9]+)?)?)', + relevance: 0 + }; + // TODO: could be tightened + // https://elixir-lang.readthedocs.io/en/latest/intro/18.html + // but you also need to include closing delemeters in the escape list per + // individual sigil mode from what I can tell, + // ie: \} might or might not be an escape depending on the sigil used + const ESCAPES_RE = /\\[\s\S]/; + // const ESCAPES_RE = /\\["'\\abdefnrstv0]/; + const BACKSLASH_ESCAPE = { + match: ESCAPES_RE, + scope: "char.escape", + relevance: 0 + }; + const SIGIL_DELIMITERS = '[/|([{<"\']'; + const SIGIL_DELIMITER_MODES = [ + { + begin: /"/, + end: /"/ + }, + { + begin: /'/, + end: /'/ + }, + { + begin: /\//, + end: /\// + }, + { + begin: /\|/, + end: /\|/ + }, + { + begin: /\(/, + end: /\)/ + }, + { + begin: /\[/, + end: /\]/ + }, + { + begin: /\{/, + end: /\}/ + }, + { + begin: // + } + ]; + const escapeSigilEnd = (end) => { + return { + scope: "char.escape", + begin: regex.concat(/\\/, end), + relevance: 0 + }; + }; + const LOWERCASE_SIGIL = { + className: 'string', + begin: '~[a-z]' + '(?=' + SIGIL_DELIMITERS + ')', + contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x, + { contains: [ + escapeSigilEnd(x.end), + BACKSLASH_ESCAPE, + SUBST + ] } + )) + }; + + const UPCASE_SIGIL = { + className: 'string', + begin: '~[A-Z]' + '(?=' + SIGIL_DELIMITERS + ')', + contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x, + { contains: [ escapeSigilEnd(x.end) ] } + )) + }; + + const REGEX_SIGIL = { + className: 'regex', + variants: [ + { + begin: '~r' + '(?=' + SIGIL_DELIMITERS + ')', + contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x, + { + end: regex.concat(x.end, /[uismxfU]{0,7}/), + contains: [ + escapeSigilEnd(x.end), + BACKSLASH_ESCAPE, + SUBST + ] + } + )) + }, + { + begin: '~R' + '(?=' + SIGIL_DELIMITERS + ')', + contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x, + { + end: regex.concat(x.end, /[uismxfU]{0,7}/), + contains: [ escapeSigilEnd(x.end) ] + }) + ) + } + ] + }; + + const STRING = { + className: 'string', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + variants: [ + { + begin: /"""/, + end: /"""/ + }, + { + begin: /'''/, + end: /'''/ + }, + { + begin: /~S"""/, + end: /"""/, + contains: [] // override default + }, + { + begin: /~S"/, + end: /"/, + contains: [] // override default + }, + { + begin: /~S'''/, + end: /'''/, + contains: [] // override default + }, + { + begin: /~S'/, + end: /'/, + contains: [] // override default + }, + { + begin: /'/, + end: /'/ + }, + { + begin: /"/, + end: /"/ + } + ] + }; + const FUNCTION = { + className: 'function', + beginKeywords: 'def defp defmacro defmacrop', + end: /\B\b/, // the mode is ended by the title + contains: [ + hljs.inherit(hljs.TITLE_MODE, { + begin: ELIXIR_IDENT_RE, + endsParent: true + }) + ] + }; + const CLASS = hljs.inherit(FUNCTION, { + className: 'class', + beginKeywords: 'defimpl defmodule defprotocol defrecord', + end: /\bdo\b|$|;/ + }); + const ELIXIR_DEFAULT_CONTAINS = [ + STRING, + REGEX_SIGIL, + UPCASE_SIGIL, + LOWERCASE_SIGIL, + hljs.HASH_COMMENT_MODE, + CLASS, + FUNCTION, + { begin: '::' }, + { + className: 'symbol', + begin: ':(?![\\s:])', + contains: [ + STRING, + { begin: ELIXIR_METHOD_RE } + ], + relevance: 0 + }, + { + className: 'symbol', + begin: ELIXIR_IDENT_RE + ':(?!:)', + relevance: 0 + }, + { // Usage of a module, struct, etc. + className: 'title.class', + begin: /(\b[A-Z][a-zA-Z0-9_]+)/, + relevance: 0 + }, + NUMBER, + { + className: 'variable', + begin: '(\\$\\W)|((\\$|@@?)(\\w+))' + } + // -> has been removed, capnproto always uses this grammar construct + ]; + SUBST.contains = ELIXIR_DEFAULT_CONTAINS; + + return { + name: 'Elixir', + aliases: [ + 'ex', + 'exs' + ], + keywords: KWS, + contains: ELIXIR_DEFAULT_CONTAINS + }; + } + + return elixir; + +})(); + + hljs.registerLanguage('elixir', hljsGrammar); + })();/*! `elm` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Elm + Author: Janis Voigtlaender + Website: https://elm-lang.org + Category: functional + */ + + /** @type LanguageFn */ + function elm(hljs) { + const COMMENT = { variants: [ + hljs.COMMENT('--', '$'), + hljs.COMMENT( + /\{-/, + /-\}/, + { contains: [ 'self' ] } + ) + ] }; + + const CONSTRUCTOR = { + className: 'type', + begin: '\\b[A-Z][\\w\']*', // TODO: other constructors (built-in, infix). + relevance: 0 + }; + + const LIST = { + begin: '\\(', + end: '\\)', + illegal: '"', + contains: [ + { + className: 'type', + begin: '\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?' + }, + COMMENT + ] + }; + + const RECORD = { + begin: /\{/, + end: /\}/, + contains: LIST.contains + }; + + const CHARACTER = { + className: 'string', + begin: '\'\\\\?.', + end: '\'', + illegal: '.' + }; + + const KEYWORDS = [ + "let", + "in", + "if", + "then", + "else", + "case", + "of", + "where", + "module", + "import", + "exposing", + "type", + "alias", + "as", + "infix", + "infixl", + "infixr", + "port", + "effect", + "command", + "subscription" + ]; + + return { + name: 'Elm', + keywords: KEYWORDS, + contains: [ + + // Top-level constructions. + + { + beginKeywords: 'port effect module', + end: 'exposing', + keywords: 'port effect module where command subscription exposing', + contains: [ + LIST, + COMMENT + ], + illegal: '\\W\\.|;' + }, + { + begin: 'import', + end: '$', + keywords: 'import as exposing', + contains: [ + LIST, + COMMENT + ], + illegal: '\\W\\.|;' + }, + { + begin: 'type', + end: '$', + keywords: 'type alias', + contains: [ + CONSTRUCTOR, + LIST, + RECORD, + COMMENT + ] + }, + { + beginKeywords: 'infix infixl infixr', + end: '$', + contains: [ + hljs.C_NUMBER_MODE, + COMMENT + ] + }, + { + begin: 'port', + end: '$', + keywords: 'port', + contains: [ COMMENT ] + }, + + // Literals and names. + CHARACTER, + hljs.QUOTE_STRING_MODE, + hljs.C_NUMBER_MODE, + CONSTRUCTOR, + hljs.inherit(hljs.TITLE_MODE, { begin: '^[_a-z][\\w\']*' }), + COMMENT, + + { // No markup, relevance booster + begin: '->|<-' } + ], + illegal: /;/ + }; + } + + return elm; + +})(); + + hljs.registerLanguage('elm', hljsGrammar); + })();/*! `erb` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: ERB (Embedded Ruby) + Requires: xml.js, ruby.js + Author: Lucas Mazza + Contributors: Kassio Borges + Description: "Bridge" language defining fragments of Ruby in HTML within <% .. %> + Website: https://ruby-doc.org/stdlib-2.6.5/libdoc/erb/rdoc/ERB.html + Category: template + */ + + /** @type LanguageFn */ + function erb(hljs) { + return { + name: 'ERB', + subLanguage: 'xml', + contains: [ + hljs.COMMENT('<%#', '%>'), + { + begin: '<%[%=-]?', + end: '[%-]?%>', + subLanguage: 'ruby', + excludeBegin: true, + excludeEnd: true + } + ] + }; + } + + return erb; + +})(); + + hljs.registerLanguage('erb', hljsGrammar); + })();/*! `erlang` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Erlang + Description: Erlang is a general-purpose functional language, with strict evaluation, single assignment, and dynamic typing. + Author: Nikolay Zakharov , Dmitry Kovega + Website: https://www.erlang.org + Category: functional + */ + + /** @type LanguageFn */ + function erlang(hljs) { + const BASIC_ATOM_RE = '[a-z\'][a-zA-Z0-9_\']*'; + const FUNCTION_NAME_RE = '(' + BASIC_ATOM_RE + ':' + BASIC_ATOM_RE + '|' + BASIC_ATOM_RE + ')'; + const ERLANG_RESERVED = { + keyword: + 'after and andalso|10 band begin bnot bor bsl bzr bxor case catch cond div end fun if ' + + 'let not of orelse|10 query receive rem try when xor', + literal: + 'false true' + }; + + const COMMENT = hljs.COMMENT('%', '$'); + const NUMBER = { + className: 'number', + begin: '\\b(\\d+(_\\d+)*#[a-fA-F0-9]+(_[a-fA-F0-9]+)*|\\d+(_\\d+)*(\\.\\d+(_\\d+)*)?([eE][-+]?\\d+)?)', + relevance: 0 + }; + const NAMED_FUN = { begin: 'fun\\s+' + BASIC_ATOM_RE + '/\\d+' }; + const FUNCTION_CALL = { + begin: FUNCTION_NAME_RE + '\\(', + end: '\\)', + returnBegin: true, + relevance: 0, + contains: [ + { + begin: FUNCTION_NAME_RE, + relevance: 0 + }, + { + begin: '\\(', + end: '\\)', + endsWithParent: true, + returnEnd: true, + relevance: 0 + // "contains" defined later + } + ] + }; + const TUPLE = { + begin: /\{/, + end: /\}/, + relevance: 0 + // "contains" defined later + }; + const VAR1 = { + begin: '\\b_([A-Z][A-Za-z0-9_]*)?', + relevance: 0 + }; + const VAR2 = { + begin: '[A-Z][a-zA-Z0-9_]*', + relevance: 0 + }; + const RECORD_ACCESS = { + begin: '#' + hljs.UNDERSCORE_IDENT_RE, + relevance: 0, + returnBegin: true, + contains: [ + { + begin: '#' + hljs.UNDERSCORE_IDENT_RE, + relevance: 0 + }, + { + begin: /\{/, + end: /\}/, + relevance: 0 + // "contains" defined later + } + ] + }; + + const BLOCK_STATEMENTS = { + beginKeywords: 'fun receive if try case', + end: 'end', + keywords: ERLANG_RESERVED + }; + BLOCK_STATEMENTS.contains = [ + COMMENT, + NAMED_FUN, + hljs.inherit(hljs.APOS_STRING_MODE, { className: '' }), + BLOCK_STATEMENTS, + FUNCTION_CALL, + hljs.QUOTE_STRING_MODE, + NUMBER, + TUPLE, + VAR1, + VAR2, + RECORD_ACCESS + ]; + + const BASIC_MODES = [ + COMMENT, + NAMED_FUN, + BLOCK_STATEMENTS, + FUNCTION_CALL, + hljs.QUOTE_STRING_MODE, + NUMBER, + TUPLE, + VAR1, + VAR2, + RECORD_ACCESS + ]; + FUNCTION_CALL.contains[1].contains = BASIC_MODES; + TUPLE.contains = BASIC_MODES; + RECORD_ACCESS.contains[1].contains = BASIC_MODES; + + const DIRECTIVES = [ + "-module", + "-record", + "-undef", + "-export", + "-ifdef", + "-ifndef", + "-author", + "-copyright", + "-doc", + "-vsn", + "-import", + "-include", + "-include_lib", + "-compile", + "-define", + "-else", + "-endif", + "-file", + "-behaviour", + "-behavior", + "-spec" + ]; + + const PARAMS = { + className: 'params', + begin: '\\(', + end: '\\)', + contains: BASIC_MODES + }; + return { + name: 'Erlang', + aliases: [ 'erl' ], + keywords: ERLANG_RESERVED, + illegal: '(', + returnBegin: true, + illegal: '\\(|#|//|/\\*|\\\\|:|;', + contains: [ + PARAMS, + hljs.inherit(hljs.TITLE_MODE, { begin: BASIC_ATOM_RE }) + ], + starts: { + end: ';|\\.', + keywords: ERLANG_RESERVED, + contains: BASIC_MODES + } + }, + COMMENT, + { + begin: '^-', + end: '\\.', + relevance: 0, + excludeEnd: true, + returnBegin: true, + keywords: { + $pattern: '-' + hljs.IDENT_RE, + keyword: DIRECTIVES.map(x => `${x}|1.5`).join(" ") + }, + contains: [ PARAMS ] + }, + NUMBER, + hljs.QUOTE_STRING_MODE, + RECORD_ACCESS, + VAR1, + VAR2, + TUPLE, + { begin: /\.$/ } // relevance booster + ] + }; + } + + return erlang; + +})(); + + hljs.registerLanguage('erlang', hljsGrammar); + })();/*! `fortran` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Fortran + Author: Anthony Scemama + Website: https://en.wikipedia.org/wiki/Fortran + Category: scientific + */ + + /** @type LanguageFn */ + function fortran(hljs) { + const regex = hljs.regex; + const PARAMS = { + className: 'params', + begin: '\\(', + end: '\\)' + }; + + const COMMENT = { variants: [ + hljs.COMMENT('!', '$', { relevance: 0 }), + // allow FORTRAN 77 style comments + hljs.COMMENT('^C[ ]', '$', { relevance: 0 }), + hljs.COMMENT('^C$', '$', { relevance: 0 }) + ] }; + + // regex in both fortran and irpf90 should match + const OPTIONAL_NUMBER_SUFFIX = /(_[a-z_\d]+)?/; + const OPTIONAL_NUMBER_EXP = /([de][+-]?\d+)?/; + const NUMBER = { + className: 'number', + variants: [ + { begin: regex.concat(/\b\d+/, /\.(\d*)/, OPTIONAL_NUMBER_EXP, OPTIONAL_NUMBER_SUFFIX) }, + { begin: regex.concat(/\b\d+/, OPTIONAL_NUMBER_EXP, OPTIONAL_NUMBER_SUFFIX) }, + { begin: regex.concat(/\.\d+/, OPTIONAL_NUMBER_EXP, OPTIONAL_NUMBER_SUFFIX) } + ], + relevance: 0 + }; + + const FUNCTION_DEF = { + className: 'function', + beginKeywords: 'subroutine function program', + illegal: '[${=\\n]', + contains: [ + hljs.UNDERSCORE_TITLE_MODE, + PARAMS + ] + }; + + const STRING = { + className: 'string', + relevance: 0, + variants: [ + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE + ] + }; + + const KEYWORDS = [ + "kind", + "do", + "concurrent", + "local", + "shared", + "while", + "private", + "call", + "intrinsic", + "where", + "elsewhere", + "type", + "endtype", + "endmodule", + "endselect", + "endinterface", + "end", + "enddo", + "endif", + "if", + "forall", + "endforall", + "only", + "contains", + "default", + "return", + "stop", + "then", + "block", + "endblock", + "endassociate", + "public", + "subroutine|10", + "function", + "program", + ".and.", + ".or.", + ".not.", + ".le.", + ".eq.", + ".ge.", + ".gt.", + ".lt.", + "goto", + "save", + "else", + "use", + "module", + "select", + "case", + "access", + "blank", + "direct", + "exist", + "file", + "fmt", + "form", + "formatted", + "iostat", + "name", + "named", + "nextrec", + "number", + "opened", + "rec", + "recl", + "sequential", + "status", + "unformatted", + "unit", + "continue", + "format", + "pause", + "cycle", + "exit", + "c_null_char", + "c_alert", + "c_backspace", + "c_form_feed", + "flush", + "wait", + "decimal", + "round", + "iomsg", + "synchronous", + "nopass", + "non_overridable", + "pass", + "protected", + "volatile", + "abstract", + "extends", + "import", + "non_intrinsic", + "value", + "deferred", + "generic", + "final", + "enumerator", + "class", + "associate", + "bind", + "enum", + "c_int", + "c_short", + "c_long", + "c_long_long", + "c_signed_char", + "c_size_t", + "c_int8_t", + "c_int16_t", + "c_int32_t", + "c_int64_t", + "c_int_least8_t", + "c_int_least16_t", + "c_int_least32_t", + "c_int_least64_t", + "c_int_fast8_t", + "c_int_fast16_t", + "c_int_fast32_t", + "c_int_fast64_t", + "c_intmax_t", + "C_intptr_t", + "c_float", + "c_double", + "c_long_double", + "c_float_complex", + "c_double_complex", + "c_long_double_complex", + "c_bool", + "c_char", + "c_null_ptr", + "c_null_funptr", + "c_new_line", + "c_carriage_return", + "c_horizontal_tab", + "c_vertical_tab", + "iso_c_binding", + "c_loc", + "c_funloc", + "c_associated", + "c_f_pointer", + "c_ptr", + "c_funptr", + "iso_fortran_env", + "character_storage_size", + "error_unit", + "file_storage_size", + "input_unit", + "iostat_end", + "iostat_eor", + "numeric_storage_size", + "output_unit", + "c_f_procpointer", + "ieee_arithmetic", + "ieee_support_underflow_control", + "ieee_get_underflow_mode", + "ieee_set_underflow_mode", + "newunit", + "contiguous", + "recursive", + "pad", + "position", + "action", + "delim", + "readwrite", + "eor", + "advance", + "nml", + "interface", + "procedure", + "namelist", + "include", + "sequence", + "elemental", + "pure", + "impure", + "integer", + "real", + "character", + "complex", + "logical", + "codimension", + "dimension", + "allocatable|10", + "parameter", + "external", + "implicit|10", + "none", + "double", + "precision", + "assign", + "intent", + "optional", + "pointer", + "target", + "in", + "out", + "common", + "equivalence", + "data" + ]; + const LITERALS = [ + ".False.", + ".True." + ]; + const BUILT_INS = [ + "alog", + "alog10", + "amax0", + "amax1", + "amin0", + "amin1", + "amod", + "cabs", + "ccos", + "cexp", + "clog", + "csin", + "csqrt", + "dabs", + "dacos", + "dasin", + "datan", + "datan2", + "dcos", + "dcosh", + "ddim", + "dexp", + "dint", + "dlog", + "dlog10", + "dmax1", + "dmin1", + "dmod", + "dnint", + "dsign", + "dsin", + "dsinh", + "dsqrt", + "dtan", + "dtanh", + "float", + "iabs", + "idim", + "idint", + "idnint", + "ifix", + "isign", + "max0", + "max1", + "min0", + "min1", + "sngl", + "algama", + "cdabs", + "cdcos", + "cdexp", + "cdlog", + "cdsin", + "cdsqrt", + "cqabs", + "cqcos", + "cqexp", + "cqlog", + "cqsin", + "cqsqrt", + "dcmplx", + "dconjg", + "derf", + "derfc", + "dfloat", + "dgamma", + "dimag", + "dlgama", + "iqint", + "qabs", + "qacos", + "qasin", + "qatan", + "qatan2", + "qcmplx", + "qconjg", + "qcos", + "qcosh", + "qdim", + "qerf", + "qerfc", + "qexp", + "qgamma", + "qimag", + "qlgama", + "qlog", + "qlog10", + "qmax1", + "qmin1", + "qmod", + "qnint", + "qsign", + "qsin", + "qsinh", + "qsqrt", + "qtan", + "qtanh", + "abs", + "acos", + "aimag", + "aint", + "anint", + "asin", + "atan", + "atan2", + "char", + "cmplx", + "conjg", + "cos", + "cosh", + "exp", + "ichar", + "index", + "int", + "log", + "log10", + "max", + "min", + "nint", + "sign", + "sin", + "sinh", + "sqrt", + "tan", + "tanh", + "print", + "write", + "dim", + "lge", + "lgt", + "lle", + "llt", + "mod", + "nullify", + "allocate", + "deallocate", + "adjustl", + "adjustr", + "all", + "allocated", + "any", + "associated", + "bit_size", + "btest", + "ceiling", + "count", + "cshift", + "date_and_time", + "digits", + "dot_product", + "eoshift", + "epsilon", + "exponent", + "floor", + "fraction", + "huge", + "iand", + "ibclr", + "ibits", + "ibset", + "ieor", + "ior", + "ishft", + "ishftc", + "lbound", + "len_trim", + "matmul", + "maxexponent", + "maxloc", + "maxval", + "merge", + "minexponent", + "minloc", + "minval", + "modulo", + "mvbits", + "nearest", + "pack", + "present", + "product", + "radix", + "random_number", + "random_seed", + "range", + "repeat", + "reshape", + "rrspacing", + "scale", + "scan", + "selected_int_kind", + "selected_real_kind", + "set_exponent", + "shape", + "size", + "spacing", + "spread", + "sum", + "system_clock", + "tiny", + "transpose", + "trim", + "ubound", + "unpack", + "verify", + "achar", + "iachar", + "transfer", + "dble", + "entry", + "dprod", + "cpu_time", + "command_argument_count", + "get_command", + "get_command_argument", + "get_environment_variable", + "is_iostat_end", + "ieee_arithmetic", + "ieee_support_underflow_control", + "ieee_get_underflow_mode", + "ieee_set_underflow_mode", + "is_iostat_eor", + "move_alloc", + "new_line", + "selected_char_kind", + "same_type_as", + "extends_type_of", + "acosh", + "asinh", + "atanh", + "bessel_j0", + "bessel_j1", + "bessel_jn", + "bessel_y0", + "bessel_y1", + "bessel_yn", + "erf", + "erfc", + "erfc_scaled", + "gamma", + "log_gamma", + "hypot", + "norm2", + "atomic_define", + "atomic_ref", + "execute_command_line", + "leadz", + "trailz", + "storage_size", + "merge_bits", + "bge", + "bgt", + "ble", + "blt", + "dshiftl", + "dshiftr", + "findloc", + "iall", + "iany", + "iparity", + "image_index", + "lcobound", + "ucobound", + "maskl", + "maskr", + "num_images", + "parity", + "popcnt", + "poppar", + "shifta", + "shiftl", + "shiftr", + "this_image", + "sync", + "change", + "team", + "co_broadcast", + "co_max", + "co_min", + "co_sum", + "co_reduce" + ]; + return { + name: 'Fortran', + case_insensitive: true, + aliases: [ + 'f90', + 'f95' + ], + keywords: { + keyword: KEYWORDS, + literal: LITERALS, + built_in: BUILT_INS + }, + illegal: /\/\*/, + contains: [ + STRING, + FUNCTION_DEF, + // allow `C = value` for assignments so they aren't misdetected + // as Fortran 77 style comments + { + begin: /^C\s*=(?!=)/, + relevance: 0 + }, + COMMENT, + NUMBER + ] + }; + } + + return fortran; + +})(); + + hljs.registerLanguage('fortran', hljsGrammar); + })();/*! `fsharp` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /** + * @param {string} value + * @returns {RegExp} + * */ + function escape(value) { + return new RegExp(value.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'), 'm'); + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function source(re) { + if (!re) return null; + if (typeof re === "string") return re; + + return re.source; + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function lookahead(re) { + return concat('(?=', re, ')'); + } + + /** + * @param {...(RegExp | string) } args + * @returns {string} + */ + function concat(...args) { + const joined = args.map((x) => source(x)).join(""); + return joined; + } + + /** + * @param { Array } args + * @returns {object} + */ + function stripOptionsFromArgs(args) { + const opts = args[args.length - 1]; + + if (typeof opts === 'object' && opts.constructor === Object) { + args.splice(args.length - 1, 1); + return opts; + } else { + return {}; + } + } + + /** @typedef { {capture?: boolean} } RegexEitherOptions */ + + /** + * Any of the passed expresssions may match + * + * Creates a huge this | this | that | that match + * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args + * @returns {string} + */ + function either(...args) { + /** @type { object & {capture?: boolean} } */ + const opts = stripOptionsFromArgs(args); + const joined = '(' + + (opts.capture ? "" : "?:") + + args.map((x) => source(x)).join("|") + ")"; + return joined; + } + + /* + Language: F# + Author: Jonas Follesø + Contributors: Troy Kershaw , Henrik Feldt , Melvyn Laïly + Website: https://docs.microsoft.com/en-us/dotnet/fsharp/ + Category: functional + */ + + + /** @type LanguageFn */ + function fsharp(hljs) { + const KEYWORDS = [ + "abstract", + "and", + "as", + "assert", + "base", + "begin", + "class", + "default", + "delegate", + "do", + "done", + "downcast", + "downto", + "elif", + "else", + "end", + "exception", + "extern", + // "false", // literal + "finally", + "fixed", + "for", + "fun", + "function", + "global", + "if", + "in", + "inherit", + "inline", + "interface", + "internal", + "lazy", + "let", + "match", + "member", + "module", + "mutable", + "namespace", + "new", + // "not", // built_in + // "null", // literal + "of", + "open", + "or", + "override", + "private", + "public", + "rec", + "return", + "static", + "struct", + "then", + "to", + // "true", // literal + "try", + "type", + "upcast", + "use", + "val", + "void", + "when", + "while", + "with", + "yield" + ]; + + const BANG_KEYWORD_MODE = { + // monad builder keywords (matches before non-bang keywords) + scope: 'keyword', + match: /\b(yield|return|let|do|match|use)!/ + }; + + const PREPROCESSOR_KEYWORDS = [ + "if", + "else", + "endif", + "line", + "nowarn", + "light", + "r", + "i", + "I", + "load", + "time", + "help", + "quit" + ]; + + const LITERALS = [ + "true", + "false", + "null", + "Some", + "None", + "Ok", + "Error", + "infinity", + "infinityf", + "nan", + "nanf" + ]; + + const SPECIAL_IDENTIFIERS = [ + "__LINE__", + "__SOURCE_DIRECTORY__", + "__SOURCE_FILE__" + ]; + + // Since it's possible to re-bind/shadow names (e.g. let char = 'c'), + // these builtin types should only be matched when a type name is expected. + const KNOWN_TYPES = [ + // basic types + "bool", + "byte", + "sbyte", + "int8", + "int16", + "int32", + "uint8", + "uint16", + "uint32", + "int", + "uint", + "int64", + "uint64", + "nativeint", + "unativeint", + "decimal", + "float", + "double", + "float32", + "single", + "char", + "string", + "unit", + "bigint", + // other native types or lowercase aliases + "option", + "voption", + "list", + "array", + "seq", + "byref", + "exn", + "inref", + "nativeptr", + "obj", + "outref", + "voidptr", + // other important FSharp types + "Result" + ]; + + const BUILTINS = [ + // Somewhat arbitrary list of builtin functions and values. + // Most of them are declared in Microsoft.FSharp.Core + // I tried to stay relevant by adding only the most idiomatic + // and most used symbols that are not already declared as types. + "not", + "ref", + "raise", + "reraise", + "dict", + "readOnlyDict", + "set", + "get", + "enum", + "sizeof", + "typeof", + "typedefof", + "nameof", + "nullArg", + "invalidArg", + "invalidOp", + "id", + "fst", + "snd", + "ignore", + "lock", + "using", + "box", + "unbox", + "tryUnbox", + "printf", + "printfn", + "sprintf", + "eprintf", + "eprintfn", + "fprintf", + "fprintfn", + "failwith", + "failwithf" + ]; + + const ALL_KEYWORDS = { + keyword: KEYWORDS, + literal: LITERALS, + built_in: BUILTINS, + 'variable.constant': SPECIAL_IDENTIFIERS + }; + + // (* potentially multi-line Meta Language style comment *) + const ML_COMMENT = + hljs.COMMENT(/\(\*(?!\))/, /\*\)/, { + contains: ["self"] + }); + // Either a multi-line (* Meta Language style comment *) or a single line // C style comment. + const COMMENT = { + variants: [ + ML_COMMENT, + hljs.C_LINE_COMMENT_MODE, + ] + }; + + // Most identifiers can contain apostrophes + const IDENTIFIER_RE = /[a-zA-Z_](\w|')*/; + + const QUOTED_IDENTIFIER = { + scope: 'variable', + begin: /``/, + end: /``/ + }; + + // 'a or ^a where a can be a ``quoted identifier`` + const BEGIN_GENERIC_TYPE_SYMBOL_RE = /\B('|\^)/; + const GENERIC_TYPE_SYMBOL = { + scope: 'symbol', + variants: [ + // the type name is a quoted identifier: + { match: concat(BEGIN_GENERIC_TYPE_SYMBOL_RE, /``.*?``/) }, + // the type name is a normal identifier (we don't use IDENTIFIER_RE because there cannot be another apostrophe here): + { match: concat(BEGIN_GENERIC_TYPE_SYMBOL_RE, hljs.UNDERSCORE_IDENT_RE) } + ], + relevance: 0 + }; + + const makeOperatorMode = function({ includeEqual }) { + // List or symbolic operator characters from the FSharp Spec 4.1, minus the dot, and with `?` added, used for nullable operators. + let allOperatorChars; + if (includeEqual) + allOperatorChars = "!%&*+-/<=>@^|~?"; + else + allOperatorChars = "!%&*+-/<>@^|~?"; + const OPERATOR_CHARS = Array.from(allOperatorChars); + const OPERATOR_CHAR_RE = concat('[', ...OPERATOR_CHARS.map(escape), ']'); + // The lone dot operator is special. It cannot be redefined, and we don't want to highlight it. It can be used as part of a multi-chars operator though. + const OPERATOR_CHAR_OR_DOT_RE = either(OPERATOR_CHAR_RE, /\./); + // When a dot is present, it must be followed by another operator char: + const OPERATOR_FIRST_CHAR_OF_MULTIPLE_RE = concat(OPERATOR_CHAR_OR_DOT_RE, lookahead(OPERATOR_CHAR_OR_DOT_RE)); + const SYMBOLIC_OPERATOR_RE = either( + concat(OPERATOR_FIRST_CHAR_OF_MULTIPLE_RE, OPERATOR_CHAR_OR_DOT_RE, '*'), // Matches at least 2 chars operators + concat(OPERATOR_CHAR_RE, '+'), // Matches at least one char operators + ); + return { + scope: 'operator', + match: either( + // symbolic operators: + SYMBOLIC_OPERATOR_RE, + // other symbolic keywords: + // Type casting and conversion operators: + /:\?>/, + /:\?/, + /:>/, + /:=/, // Reference cell assignment + /::?/, // : or :: + /\$/), // A single $ can be used as an operator + relevance: 0 + }; + }; + + const OPERATOR = makeOperatorMode({ includeEqual: true }); + // This variant is used when matching '=' should end a parent mode: + const OPERATOR_WITHOUT_EQUAL = makeOperatorMode({ includeEqual: false }); + + const makeTypeAnnotationMode = function(prefix, prefixScope) { + return { + begin: concat( // a type annotation is a + prefix, // should be a colon or the 'of' keyword + lookahead( // that has to be followed by + concat( + /\s*/, // optional space + either( // then either of: + /\w/, // word + /'/, // generic type name + /\^/, // generic type name + /#/, // flexible type name + /``/, // quoted type name + /\(/, // parens type expression + /{\|/, // anonymous type annotation + )))), + beginScope: prefixScope, + // BUG: because ending with \n is necessary for some cases, multi-line type annotations are not properly supported. + // Examples where \n is required at the end: + // - abstract member definitions in classes: abstract Property : int * string + // - return type annotations: let f f' = f' () : returnTypeAnnotation + // - record fields definitions: { A : int \n B : string } + end: lookahead( + either( + /\n/, + /=/)), + relevance: 0, + // we need the known types, and we need the type constraint keywords and literals. e.g.: when 'a : null + keywords: hljs.inherit(ALL_KEYWORDS, { type: KNOWN_TYPES }), + contains: [ + COMMENT, + GENERIC_TYPE_SYMBOL, + hljs.inherit(QUOTED_IDENTIFIER, { scope: null }), // match to avoid strange patterns inside that may break the parsing + OPERATOR_WITHOUT_EQUAL + ] + }; + }; + + const TYPE_ANNOTATION = makeTypeAnnotationMode(/:/, 'operator'); + const DISCRIMINATED_UNION_TYPE_ANNOTATION = makeTypeAnnotationMode(/\bof\b/, 'keyword'); + + // type MyType<'a> = ... + const TYPE_DECLARATION = { + begin: [ + /(^|\s+)/, // prevents matching the following: `match s.stype with` + /type/, + /\s+/, + IDENTIFIER_RE + ], + beginScope: { + 2: 'keyword', + 4: 'title.class' + }, + end: lookahead(/\(|=|$/), + keywords: ALL_KEYWORDS, // match keywords in type constraints. e.g.: when 'a : null + contains: [ + COMMENT, + hljs.inherit(QUOTED_IDENTIFIER, { scope: null }), // match to avoid strange patterns inside that may break the parsing + GENERIC_TYPE_SYMBOL, + { + // For visual consistency, highlight type brackets as operators. + scope: 'operator', + match: /<|>/ + }, + TYPE_ANNOTATION // generic types can have constraints, which are type annotations. e.g. type MyType<'T when 'T : delegate> = + ] + }; + + const COMPUTATION_EXPRESSION = { + // computation expressions: + scope: 'computation-expression', + // BUG: might conflict with record deconstruction. e.g. let f { Name = name } = name // will highlight f + match: /\b[_a-z]\w*(?=\s*\{)/ + }; + + const PREPROCESSOR = { + // preprocessor directives and fsi commands: + begin: [ + /^\s*/, + concat(/#/, either(...PREPROCESSOR_KEYWORDS)), + /\b/ + ], + beginScope: { 2: 'meta' }, + end: lookahead(/\s|$/) + }; + + // TODO: this definition is missing support for type suffixes and octal notation. + // BUG: range operator without any space is wrongly interpreted as a single number (e.g. 1..10 ) + const NUMBER = { + variants: [ + hljs.BINARY_NUMBER_MODE, + hljs.C_NUMBER_MODE + ] + }; + + // All the following string definitions are potentially multi-line. + // BUG: these definitions are missing support for byte strings (suffixed with B) + + // "..." + const QUOTED_STRING = { + scope: 'string', + begin: /"/, + end: /"/, + contains: [ + hljs.BACKSLASH_ESCAPE + ] + }; + // @"..." + const VERBATIM_STRING = { + scope: 'string', + begin: /@"/, + end: /"/, + contains: [ + { + match: /""/ // escaped " + }, + hljs.BACKSLASH_ESCAPE + ] + }; + // """...""" + const TRIPLE_QUOTED_STRING = { + scope: 'string', + begin: /"""/, + end: /"""/, + relevance: 2 + }; + const SUBST = { + scope: 'subst', + begin: /\{/, + end: /\}/, + keywords: ALL_KEYWORDS + }; + // $"...{1+1}..." + const INTERPOLATED_STRING = { + scope: 'string', + begin: /\$"/, + end: /"/, + contains: [ + { + match: /\{\{/ // escaped { + }, + { + match: /\}\}/ // escaped } + }, + hljs.BACKSLASH_ESCAPE, + SUBST + ] + }; + // $@"...{1+1}..." + const INTERPOLATED_VERBATIM_STRING = { + scope: 'string', + begin: /(\$@|@\$)"/, + end: /"/, + contains: [ + { + match: /\{\{/ // escaped { + }, + { + match: /\}\}/ // escaped } + }, + { + match: /""/ + }, + hljs.BACKSLASH_ESCAPE, + SUBST + ] + }; + // $"""...{1+1}...""" + const INTERPOLATED_TRIPLE_QUOTED_STRING = { + scope: 'string', + begin: /\$"""/, + end: /"""/, + contains: [ + { + match: /\{\{/ // escaped { + }, + { + match: /\}\}/ // escaped } + }, + SUBST + ], + relevance: 2 + }; + // '.' + const CHAR_LITERAL = { + scope: 'string', + match: concat( + /'/, + either( + /[^\\']/, // either a single non escaped char... + /\\(?:.|\d{3}|x[a-fA-F\d]{2}|u[a-fA-F\d]{4}|U[a-fA-F\d]{8})/ // ...or an escape sequence + ), + /'/ + ) + }; + // F# allows a lot of things inside string placeholders. + // Things that don't currently seem allowed by the compiler: types definition, attributes usage. + // (Strictly speaking, some of the followings are only allowed inside triple quoted interpolated strings...) + SUBST.contains = [ + INTERPOLATED_VERBATIM_STRING, + INTERPOLATED_STRING, + VERBATIM_STRING, + QUOTED_STRING, + CHAR_LITERAL, + BANG_KEYWORD_MODE, + COMMENT, + QUOTED_IDENTIFIER, + TYPE_ANNOTATION, + COMPUTATION_EXPRESSION, + PREPROCESSOR, + NUMBER, + GENERIC_TYPE_SYMBOL, + OPERATOR + ]; + const STRING = { + variants: [ + INTERPOLATED_TRIPLE_QUOTED_STRING, + INTERPOLATED_VERBATIM_STRING, + INTERPOLATED_STRING, + TRIPLE_QUOTED_STRING, + VERBATIM_STRING, + QUOTED_STRING, + CHAR_LITERAL + ] + }; + + return { + name: 'F#', + aliases: [ + 'fs', + 'f#' + ], + keywords: ALL_KEYWORDS, + illegal: /\/\*/, + classNameAliases: { + 'computation-expression': 'keyword' + }, + contains: [ + BANG_KEYWORD_MODE, + STRING, + COMMENT, + QUOTED_IDENTIFIER, + TYPE_DECLARATION, + { + // e.g. [] or [<``module``: MyCustomAttributeThatWorksOnModules>] + // or [] + scope: 'meta', + begin: /\[\]/, + relevance: 2, + contains: [ + QUOTED_IDENTIFIER, + // can contain any constant value + TRIPLE_QUOTED_STRING, + VERBATIM_STRING, + QUOTED_STRING, + CHAR_LITERAL, + NUMBER + ] + }, + DISCRIMINATED_UNION_TYPE_ANNOTATION, + TYPE_ANNOTATION, + COMPUTATION_EXPRESSION, + PREPROCESSOR, + NUMBER, + GENERIC_TYPE_SYMBOL, + OPERATOR + ] + }; + } + + return fsharp; + +})(); + + hljs.registerLanguage('fsharp', hljsGrammar); + })();/*! `go` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Go + Author: Stephan Kountso aka StepLg + Contributors: Evgeny Stepanischev + Description: Google go language (golang). For info about language + Website: http://golang.org/ + Category: common, system + */ + + function go(hljs) { + const LITERALS = [ + "true", + "false", + "iota", + "nil" + ]; + const BUILT_INS = [ + "append", + "cap", + "close", + "complex", + "copy", + "imag", + "len", + "make", + "new", + "panic", + "print", + "println", + "real", + "recover", + "delete" + ]; + const TYPES = [ + "bool", + "byte", + "complex64", + "complex128", + "error", + "float32", + "float64", + "int8", + "int16", + "int32", + "int64", + "string", + "uint8", + "uint16", + "uint32", + "uint64", + "int", + "uint", + "uintptr", + "rune" + ]; + const KWS = [ + "break", + "case", + "chan", + "const", + "continue", + "default", + "defer", + "else", + "fallthrough", + "for", + "func", + "go", + "goto", + "if", + "import", + "interface", + "map", + "package", + "range", + "return", + "select", + "struct", + "switch", + "type", + "var", + ]; + const KEYWORDS = { + keyword: KWS, + type: TYPES, + literal: LITERALS, + built_in: BUILT_INS + }; + return { + name: 'Go', + aliases: [ 'golang' ], + keywords: KEYWORDS, + illegal: ' + Category: build-system + */ + + function gradle(hljs) { + const KEYWORDS = [ + "task", + "project", + "allprojects", + "subprojects", + "artifacts", + "buildscript", + "configurations", + "dependencies", + "repositories", + "sourceSets", + "description", + "delete", + "from", + "into", + "include", + "exclude", + "source", + "classpath", + "destinationDir", + "includes", + "options", + "sourceCompatibility", + "targetCompatibility", + "group", + "flatDir", + "doLast", + "doFirst", + "flatten", + "todir", + "fromdir", + "ant", + "def", + "abstract", + "break", + "case", + "catch", + "continue", + "default", + "do", + "else", + "extends", + "final", + "finally", + "for", + "if", + "implements", + "instanceof", + "native", + "new", + "private", + "protected", + "public", + "return", + "static", + "switch", + "synchronized", + "throw", + "throws", + "transient", + "try", + "volatile", + "while", + "strictfp", + "package", + "import", + "false", + "null", + "super", + "this", + "true", + "antlrtask", + "checkstyle", + "codenarc", + "copy", + "boolean", + "byte", + "char", + "class", + "double", + "float", + "int", + "interface", + "long", + "short", + "void", + "compile", + "runTime", + "file", + "fileTree", + "abs", + "any", + "append", + "asList", + "asWritable", + "call", + "collect", + "compareTo", + "count", + "div", + "dump", + "each", + "eachByte", + "eachFile", + "eachLine", + "every", + "find", + "findAll", + "flatten", + "getAt", + "getErr", + "getIn", + "getOut", + "getText", + "grep", + "immutable", + "inject", + "inspect", + "intersect", + "invokeMethods", + "isCase", + "join", + "leftShift", + "minus", + "multiply", + "newInputStream", + "newOutputStream", + "newPrintWriter", + "newReader", + "newWriter", + "next", + "plus", + "pop", + "power", + "previous", + "print", + "println", + "push", + "putAt", + "read", + "readBytes", + "readLines", + "reverse", + "reverseEach", + "round", + "size", + "sort", + "splitEachLine", + "step", + "subMap", + "times", + "toInteger", + "toList", + "tokenize", + "upto", + "waitForOrKill", + "withPrintWriter", + "withReader", + "withStream", + "withWriter", + "withWriterAppend", + "write", + "writeLine" + ]; + return { + name: 'Gradle', + case_insensitive: true, + keywords: KEYWORDS, + contains: [ + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + hljs.NUMBER_MODE, + hljs.REGEXP_MODE + + ] + }; + } + + return gradle; + +})(); + + hljs.registerLanguage('gradle', hljsGrammar); + })();/*! `groovy` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Groovy + Author: Guillaume Laforge + Description: Groovy programming language implementation inspired from Vsevolod's Java mode + Website: https://groovy-lang.org + Category: system + */ + + function variants(variants, obj = {}) { + obj.variants = variants; + return obj; + } + + function groovy(hljs) { + const regex = hljs.regex; + const IDENT_RE = '[A-Za-z0-9_$]+'; + const COMMENT = variants([ + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + hljs.COMMENT( + '/\\*\\*', + '\\*/', + { + relevance: 0, + contains: [ + { + // eat up @'s in emails to prevent them to be recognized as doctags + begin: /\w+@/, + relevance: 0 + }, + { + className: 'doctag', + begin: '@[A-Za-z]+' + } + ] + } + ) + ]); + const REGEXP = { + className: 'regexp', + begin: /~?\/[^\/\n]+\//, + contains: [ hljs.BACKSLASH_ESCAPE ] + }; + const NUMBER = variants([ + hljs.BINARY_NUMBER_MODE, + hljs.C_NUMBER_MODE + ]); + const STRING = variants([ + { + begin: /"""/, + end: /"""/ + }, + { + begin: /'''/, + end: /'''/ + }, + { + begin: "\\$/", + end: "/\\$", + relevance: 10 + }, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE + ], + { className: "string" } + ); + + const CLASS_DEFINITION = { + match: [ + /(class|interface|trait|enum|record|extends|implements)/, + /\s+/, + hljs.UNDERSCORE_IDENT_RE + ], + scope: { + 1: "keyword", + 3: "title.class", + } + }; + const TYPES = [ + "byte", + "short", + "char", + "int", + "long", + "boolean", + "float", + "double", + "void" + ]; + const KEYWORDS = [ + // groovy specific keywords + "def", + "as", + "in", + "assert", + "trait", + // common keywords with Java + "abstract", + "static", + "volatile", + "transient", + "public", + "private", + "protected", + "synchronized", + "final", + "class", + "interface", + "enum", + "if", + "else", + "for", + "while", + "switch", + "case", + "break", + "default", + "continue", + "throw", + "throws", + "try", + "catch", + "finally", + "implements", + "extends", + "new", + "import", + "package", + "return", + "instanceof", + "var" + ]; + + return { + name: 'Groovy', + keywords: { + "variable.language": 'this super', + literal: 'true false null', + type: TYPES, + keyword: KEYWORDS + }, + contains: [ + hljs.SHEBANG({ + binary: "groovy", + relevance: 10 + }), + COMMENT, + STRING, + REGEXP, + NUMBER, + CLASS_DEFINITION, + { + className: 'meta', + begin: '@[A-Za-z]+', + relevance: 0 + }, + { + // highlight map keys and named parameters as attrs + className: 'attr', + begin: IDENT_RE + '[ \t]*:', + relevance: 0 + }, + { + // catch middle element of the ternary operator + // to avoid highlight it as a label, named parameter, or map key + begin: /\?/, + end: /:/, + relevance: 0, + contains: [ + COMMENT, + STRING, + REGEXP, + NUMBER, + 'self' + ] + }, + { + // highlight labeled statements + className: 'symbol', + begin: '^[ \t]*' + regex.lookahead(IDENT_RE + ':'), + excludeBegin: true, + end: IDENT_RE + ':', + relevance: 0 + } + ], + illegal: /#|<\// + }; + } + + return groovy; + +})(); + + hljs.registerLanguage('groovy', hljsGrammar); + })();/*! `haml` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: HAML + Requires: ruby.js + Author: Dan Allen + Website: http://haml.info + Category: template + */ + + // TODO support filter tags like :javascript, support inline HTML + function haml(hljs) { + return { + name: 'HAML', + case_insensitive: true, + contains: [ + { + className: 'meta', + begin: '^!!!( (5|1\\.1|Strict|Frameset|Basic|Mobile|RDFa|XML\\b.*))?$', + relevance: 10 + }, + // FIXME these comments should be allowed to span indented lines + hljs.COMMENT( + '^\\s*(!=#|=#|-#|/).*$', + null, + { relevance: 0 } + ), + { + begin: '^\\s*(-|=|!=)(?!#)', + end: /$/, + subLanguage: 'ruby', + excludeBegin: true, + excludeEnd: true + }, + { + className: 'tag', + begin: '^\\s*%', + contains: [ + { + className: 'selector-tag', + begin: '\\w+' + }, + { + className: 'selector-id', + begin: '#[\\w-]+' + }, + { + className: 'selector-class', + begin: '\\.[\\w-]+' + }, + { + begin: /\{\s*/, + end: /\s*\}/, + contains: [ + { + begin: ':\\w+\\s*=>', + end: ',\\s+', + returnBegin: true, + endsWithParent: true, + contains: [ + { + className: 'attr', + begin: ':\\w+' + }, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + { + begin: '\\w+', + relevance: 0 + } + ] + } + ] + }, + { + begin: '\\(\\s*', + end: '\\s*\\)', + excludeEnd: true, + contains: [ + { + begin: '\\w+\\s*=', + end: '\\s+', + returnBegin: true, + endsWithParent: true, + contains: [ + { + className: 'attr', + begin: '\\w+', + relevance: 0 + }, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + { + begin: '\\w+', + relevance: 0 + } + ] + } + ] + } + ] + }, + { begin: '^\\s*[=~]\\s*' }, + { + begin: /#\{/, + end: /\}/, + subLanguage: 'ruby', + excludeBegin: true, + excludeEnd: true + } + ] + }; + } + + return haml; + +})(); + + hljs.registerLanguage('haml', hljsGrammar); + })();/*! `handlebars` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Handlebars + Requires: xml.js + Author: Robin Ward + Description: Matcher for Handlebars as well as EmberJS additions. + Website: https://handlebarsjs.com + Category: template + */ + + function handlebars(hljs) { + const regex = hljs.regex; + const BUILT_INS = { + $pattern: /[\w.\/]+/, + built_in: [ + 'action', + 'bindattr', + 'collection', + 'component', + 'concat', + 'debugger', + 'each', + 'each-in', + 'get', + 'hash', + 'if', + 'in', + 'input', + 'link-to', + 'loc', + 'log', + 'lookup', + 'mut', + 'outlet', + 'partial', + 'query-params', + 'render', + 'template', + 'textarea', + 'unbound', + 'unless', + 'view', + 'with', + 'yield' + ] + }; + + const LITERALS = { + $pattern: /[\w.\/]+/, + literal: [ + 'true', + 'false', + 'undefined', + 'null' + ] + }; + + // as defined in https://handlebarsjs.com/guide/expressions.html#literal-segments + // this regex matches literal segments like ' abc ' or [ abc ] as well as helpers and paths + // like a/b, ./abc/cde, and abc.bcd + + const DOUBLE_QUOTED_ID_REGEX = /""|"[^"]+"/; + const SINGLE_QUOTED_ID_REGEX = /''|'[^']+'/; + const BRACKET_QUOTED_ID_REGEX = /\[\]|\[[^\]]+\]/; + const PLAIN_ID_REGEX = /[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/; + const PATH_DELIMITER_REGEX = /(\.|\/)/; + const ANY_ID = regex.either( + DOUBLE_QUOTED_ID_REGEX, + SINGLE_QUOTED_ID_REGEX, + BRACKET_QUOTED_ID_REGEX, + PLAIN_ID_REGEX + ); + + const IDENTIFIER_REGEX = regex.concat( + regex.optional(/\.|\.\/|\//), // relative or absolute path + ANY_ID, + regex.anyNumberOfTimes(regex.concat( + PATH_DELIMITER_REGEX, + ANY_ID + )) + ); + + // identifier followed by a equal-sign (without the equal sign) + const HASH_PARAM_REGEX = regex.concat( + '(', + BRACKET_QUOTED_ID_REGEX, '|', + PLAIN_ID_REGEX, + ')(?==)' + ); + + const HELPER_NAME_OR_PATH_EXPRESSION = { begin: IDENTIFIER_REGEX }; + + const HELPER_PARAMETER = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, { keywords: LITERALS }); + + const SUB_EXPRESSION = { + begin: /\(/, + end: /\)/ + // the "contains" is added below when all necessary sub-modes are defined + }; + + const HASH = { + // fka "attribute-assignment", parameters of the form 'key=value' + className: 'attr', + begin: HASH_PARAM_REGEX, + relevance: 0, + starts: { + begin: /=/, + end: /=/, + starts: { contains: [ + hljs.NUMBER_MODE, + hljs.QUOTE_STRING_MODE, + hljs.APOS_STRING_MODE, + HELPER_PARAMETER, + SUB_EXPRESSION + ] } + } + }; + + const BLOCK_PARAMS = { + // parameters of the form '{{#with x as | y |}}...{{/with}}' + begin: /as\s+\|/, + keywords: { keyword: 'as' }, + end: /\|/, + contains: [ + { + // define sub-mode in order to prevent highlighting of block-parameter named "as" + begin: /\w+/ } + ] + }; + + const HELPER_PARAMETERS = { + contains: [ + hljs.NUMBER_MODE, + hljs.QUOTE_STRING_MODE, + hljs.APOS_STRING_MODE, + BLOCK_PARAMS, + HASH, + HELPER_PARAMETER, + SUB_EXPRESSION + ], + returnEnd: true + // the property "end" is defined through inheritance when the mode is used. If depends + // on the surrounding mode, but "endsWithParent" does not work here (i.e. it includes the + // end-token of the surrounding mode) + }; + + const SUB_EXPRESSION_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, { + className: 'name', + keywords: BUILT_INS, + starts: hljs.inherit(HELPER_PARAMETERS, { end: /\)/ }) + }); + + SUB_EXPRESSION.contains = [ SUB_EXPRESSION_CONTENTS ]; + + const OPENING_BLOCK_MUSTACHE_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, { + keywords: BUILT_INS, + className: 'name', + starts: hljs.inherit(HELPER_PARAMETERS, { end: /\}\}/ }) + }); + + const CLOSING_BLOCK_MUSTACHE_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, { + keywords: BUILT_INS, + className: 'name' + }); + + const BASIC_MUSTACHE_CONTENTS = hljs.inherit(HELPER_NAME_OR_PATH_EXPRESSION, { + className: 'name', + keywords: BUILT_INS, + starts: hljs.inherit(HELPER_PARAMETERS, { end: /\}\}/ }) + }); + + const ESCAPE_MUSTACHE_WITH_PRECEEDING_BACKSLASH = { + begin: /\\\{\{/, + skip: true + }; + const PREVENT_ESCAPE_WITH_ANOTHER_PRECEEDING_BACKSLASH = { + begin: /\\\\(?=\{\{)/, + skip: true + }; + + return { + name: 'Handlebars', + aliases: [ + 'hbs', + 'html.hbs', + 'html.handlebars', + 'htmlbars' + ], + case_insensitive: true, + subLanguage: 'xml', + contains: [ + ESCAPE_MUSTACHE_WITH_PRECEEDING_BACKSLASH, + PREVENT_ESCAPE_WITH_ANOTHER_PRECEEDING_BACKSLASH, + hljs.COMMENT(/\{\{!--/, /--\}\}/), + hljs.COMMENT(/\{\{!/, /\}\}/), + { + // open raw block "{{{{raw}}}} content not evaluated {{{{/raw}}}}" + className: 'template-tag', + begin: /\{\{\{\{(?!\/)/, + end: /\}\}\}\}/, + contains: [ OPENING_BLOCK_MUSTACHE_CONTENTS ], + starts: { + end: /\{\{\{\{\//, + returnEnd: true, + subLanguage: 'xml' + } + }, + { + // close raw block + className: 'template-tag', + begin: /\{\{\{\{\//, + end: /\}\}\}\}/, + contains: [ CLOSING_BLOCK_MUSTACHE_CONTENTS ] + }, + { + // open block statement + className: 'template-tag', + begin: /\{\{#/, + end: /\}\}/, + contains: [ OPENING_BLOCK_MUSTACHE_CONTENTS ] + }, + { + className: 'template-tag', + begin: /\{\{(?=else\}\})/, + end: /\}\}/, + keywords: 'else' + }, + { + className: 'template-tag', + begin: /\{\{(?=else if)/, + end: /\}\}/, + keywords: 'else if' + }, + { + // closing block statement + className: 'template-tag', + begin: /\{\{\//, + end: /\}\}/, + contains: [ CLOSING_BLOCK_MUSTACHE_CONTENTS ] + }, + { + // template variable or helper-call that is NOT html-escaped + className: 'template-variable', + begin: /\{\{\{/, + end: /\}\}\}/, + contains: [ BASIC_MUSTACHE_CONTENTS ] + }, + { + // template variable or helper-call that is html-escaped + className: 'template-variable', + begin: /\{\{/, + end: /\}\}/, + contains: [ BASIC_MUSTACHE_CONTENTS ] + } + ] + }; + } + + return handlebars; + +})(); + + hljs.registerLanguage('handlebars', hljsGrammar); + })();/*! `haskell` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Haskell + Author: Jeremy Hull + Contributors: Zena Treep + Website: https://www.haskell.org + Category: functional + */ + + function haskell(hljs) { + + /* See: + - https://www.haskell.org/onlinereport/lexemes.html + - https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/binary_literals.html + - https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/numeric_underscores.html + - https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/hex_float_literals.html + */ + const decimalDigits = '([0-9]_*)+'; + const hexDigits = '([0-9a-fA-F]_*)+'; + const binaryDigits = '([01]_*)+'; + const octalDigits = '([0-7]_*)+'; + const ascSymbol = '[!#$%&*+.\\/<=>?@\\\\^~-]'; + const uniSymbol = '(\\p{S}|\\p{P})'; // Symbol or Punctuation + const special = '[(),;\\[\\]`|{}]'; + const symbol = `(${ascSymbol}|(?!(${special}|[_:"']))${uniSymbol})`; + + const COMMENT = { variants: [ + // Double dash forms a valid comment only if it's not part of legal lexeme. + // See: Haskell 98 report: https://www.haskell.org/onlinereport/lexemes.html + // + // The commented code does the job, but we can't use negative lookbehind, + // due to poor support by Safari browser. + // > hljs.COMMENT(`(?|<-' } + ] + }; + } + + return haskell; + +})(); + + hljs.registerLanguage('haskell', hljsGrammar); + })();/*! `haxe` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Haxe + Description: Haxe is an open source toolkit based on a modern, high level, strictly typed programming language. + Author: Christopher Kaster (Based on the actionscript.js language file by Alexander Myadzel) + Contributors: Kenton Hamaluik + Website: https://haxe.org + Category: system + */ + + function haxe(hljs) { + const IDENT_RE = '[a-zA-Z_$][a-zA-Z0-9_$]*'; + + // C_NUMBER_RE with underscores and literal suffixes + const HAXE_NUMBER_RE = /(-?)(\b0[xX][a-fA-F0-9_]+|(\b\d+(\.[\d_]*)?|\.[\d_]+)(([eE][-+]?\d+)|i32|u32|i64|f64)?)/; + + const HAXE_BASIC_TYPES = 'Int Float String Bool Dynamic Void Array '; + + return { + name: 'Haxe', + aliases: [ 'hx' ], + keywords: { + keyword: 'abstract break case cast catch continue default do dynamic else enum extern ' + + 'final for function here if import in inline is macro never new override package private get set ' + + 'public return static super switch this throw trace try typedef untyped using var while ' + + HAXE_BASIC_TYPES, + built_in: + 'trace this', + literal: + 'true false null _' + }, + contains: [ + { + className: 'string', // interpolate-able strings + begin: '\'', + end: '\'', + contains: [ + hljs.BACKSLASH_ESCAPE, + { + className: 'subst', // interpolation + begin: /\$\{/, + end: /\}/ + }, + { + className: 'subst', // interpolation + begin: /\$/, + end: /\W\}/ + } + ] + }, + hljs.QUOTE_STRING_MODE, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + { + className: 'number', + begin: HAXE_NUMBER_RE, + relevance: 0 + }, + { + className: 'variable', + begin: "\\$" + IDENT_RE, + }, + { + className: 'meta', // compiler meta + begin: /@:?/, + end: /\(|$/, + excludeEnd: true, + }, + { + className: 'meta', // compiler conditionals + begin: '#', + end: '$', + keywords: { keyword: 'if else elseif end error' } + }, + { + className: 'type', // function types + begin: /:[ \t]*/, + end: /[^A-Za-z0-9_ \t\->]/, + excludeBegin: true, + excludeEnd: true, + relevance: 0 + }, + { + className: 'type', // types + begin: /:[ \t]*/, + end: /\W/, + excludeBegin: true, + excludeEnd: true + }, + { + className: 'type', // instantiation + begin: /new */, + end: /\W/, + excludeBegin: true, + excludeEnd: true + }, + { + className: 'title.class', // enums + beginKeywords: 'enum', + end: /\{/, + contains: [ hljs.TITLE_MODE ] + }, + { + className: 'title.class', // abstracts + begin: '\\babstract\\b(?=\\s*' + hljs.IDENT_RE + '\\s*\\()', + end: /[\{$]/, + contains: [ + { + className: 'type', + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true + }, + { + className: 'type', + begin: /from +/, + end: /\W/, + excludeBegin: true, + excludeEnd: true + }, + { + className: 'type', + begin: /to +/, + end: /\W/, + excludeBegin: true, + excludeEnd: true + }, + hljs.TITLE_MODE + ], + keywords: { keyword: 'abstract from to' } + }, + { + className: 'title.class', // classes + begin: /\b(class|interface) +/, + end: /[\{$]/, + excludeEnd: true, + keywords: 'class interface', + contains: [ + { + className: 'keyword', + begin: /\b(extends|implements) +/, + keywords: 'extends implements', + contains: [ + { + className: 'type', + begin: hljs.IDENT_RE, + relevance: 0 + } + ] + }, + hljs.TITLE_MODE + ] + }, + { + className: 'title.function', + beginKeywords: 'function', + end: /\(/, + excludeEnd: true, + illegal: /\S/, + contains: [ hljs.TITLE_MODE ] + } + ], + illegal: /<\// + }; + } + + return haxe; + +})(); + + hljs.registerLanguage('haxe', hljsGrammar); + })();/*! `http` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: HTTP + Description: HTTP request and response headers with automatic body highlighting + Author: Ivan Sagalaev + Category: protocols, web + Website: https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview + */ + + function http(hljs) { + const regex = hljs.regex; + const VERSION = 'HTTP/([32]|1\\.[01])'; + const HEADER_NAME = /[A-Za-z][A-Za-z0-9-]*/; + const HEADER = { + className: 'attribute', + begin: regex.concat('^', HEADER_NAME, '(?=\\:\\s)'), + starts: { contains: [ + { + className: "punctuation", + begin: /: /, + relevance: 0, + starts: { + end: '$', + relevance: 0 + } + } + ] } + }; + const HEADERS_AND_BODY = [ + HEADER, + { + begin: '\\n\\n', + starts: { + subLanguage: [], + endsWithParent: true + } + } + ]; + + return { + name: 'HTTP', + aliases: [ 'https' ], + illegal: /\S/, + contains: [ + // response + { + begin: '^(?=' + VERSION + " \\d{3})", + end: /$/, + contains: [ + { + className: "meta", + begin: VERSION + }, + { + className: 'number', + begin: '\\b\\d{3}\\b' + } + ], + starts: { + end: /\b\B/, + illegal: /\S/, + contains: HEADERS_AND_BODY + } + }, + // request + { + begin: '(?=^[A-Z]+ (.*?) ' + VERSION + '$)', + end: /$/, + contains: [ + { + className: 'string', + begin: ' ', + end: ' ', + excludeBegin: true, + excludeEnd: true + }, + { + className: "meta", + begin: VERSION + }, + { + className: 'keyword', + begin: '[A-Z]+' + } + ], + starts: { + end: /\b\B/, + illegal: /\S/, + contains: HEADERS_AND_BODY + } + }, + // to allow headers to work even without a preamble + hljs.inherit(HEADER, { relevance: 0 }) + ] + }; + } + + return http; + +})(); + + hljs.registerLanguage('http', hljsGrammar); + })();/*! `ini` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: TOML, also INI + Description: TOML aims to be a minimal configuration file format that's easy to read due to obvious semantics. + Contributors: Guillaume Gomez + Category: common, config + Website: https://github.com/toml-lang/toml + */ + + function ini(hljs) { + const regex = hljs.regex; + const NUMBERS = { + className: 'number', + relevance: 0, + variants: [ + { begin: /([+-]+)?[\d]+_[\d_]+/ }, + { begin: hljs.NUMBER_RE } + ] + }; + const COMMENTS = hljs.COMMENT(); + COMMENTS.variants = [ + { + begin: /;/, + end: /$/ + }, + { + begin: /#/, + end: /$/ + } + ]; + const VARIABLES = { + className: 'variable', + variants: [ + { begin: /\$[\w\d"][\w\d_]*/ }, + { begin: /\$\{(.*?)\}/ } + ] + }; + const LITERALS = { + className: 'literal', + begin: /\bon|off|true|false|yes|no\b/ + }; + const STRINGS = { + className: "string", + contains: [ hljs.BACKSLASH_ESCAPE ], + variants: [ + { + begin: "'''", + end: "'''", + relevance: 10 + }, + { + begin: '"""', + end: '"""', + relevance: 10 + }, + { + begin: '"', + end: '"' + }, + { + begin: "'", + end: "'" + } + ] + }; + const ARRAY = { + begin: /\[/, + end: /\]/, + contains: [ + COMMENTS, + LITERALS, + VARIABLES, + STRINGS, + NUMBERS, + 'self' + ], + relevance: 0 + }; + + const BARE_KEY = /[A-Za-z0-9_-]+/; + const QUOTED_KEY_DOUBLE_QUOTE = /"(\\"|[^"])*"/; + const QUOTED_KEY_SINGLE_QUOTE = /'[^']*'/; + const ANY_KEY = regex.either( + BARE_KEY, QUOTED_KEY_DOUBLE_QUOTE, QUOTED_KEY_SINGLE_QUOTE + ); + const DOTTED_KEY = regex.concat( + ANY_KEY, '(\\s*\\.\\s*', ANY_KEY, ')*', + regex.lookahead(/\s*=\s*[^#\s]/) + ); + + return { + name: 'TOML, also INI', + aliases: [ 'toml' ], + case_insensitive: true, + illegal: /\S/, + contains: [ + COMMENTS, + { + className: 'section', + begin: /\[+/, + end: /\]+/ + }, + { + begin: DOTTED_KEY, + className: 'attr', + starts: { + end: /$/, + contains: [ + COMMENTS, + ARRAY, + LITERALS, + VARIABLES, + STRINGS, + NUMBERS + ] + } + } + ] + }; + } + + return ini; + +})(); + + hljs.registerLanguage('ini', hljsGrammar); + })();/*! `java` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + // https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.10 + var decimalDigits = '[0-9](_*[0-9])*'; + var frac = `\\.(${decimalDigits})`; + var hexDigits = '[0-9a-fA-F](_*[0-9a-fA-F])*'; + var NUMERIC = { + className: 'number', + variants: [ + // DecimalFloatingPointLiteral + // including ExponentPart + { begin: `(\\b(${decimalDigits})((${frac})|\\.)?|(${frac}))` + + `[eE][+-]?(${decimalDigits})[fFdD]?\\b` }, + // excluding ExponentPart + { begin: `\\b(${decimalDigits})((${frac})[fFdD]?\\b|\\.([fFdD]\\b)?)` }, + { begin: `(${frac})[fFdD]?\\b` }, + { begin: `\\b(${decimalDigits})[fFdD]\\b` }, + + // HexadecimalFloatingPointLiteral + { begin: `\\b0[xX]((${hexDigits})\\.?|(${hexDigits})?\\.(${hexDigits}))` + + `[pP][+-]?(${decimalDigits})[fFdD]?\\b` }, + + // DecimalIntegerLiteral + { begin: '\\b(0|[1-9](_*[0-9])*)[lL]?\\b' }, + + // HexIntegerLiteral + { begin: `\\b0[xX](${hexDigits})[lL]?\\b` }, + + // OctalIntegerLiteral + { begin: '\\b0(_*[0-7])*[lL]?\\b' }, + + // BinaryIntegerLiteral + { begin: '\\b0[bB][01](_*[01])*[lL]?\\b' }, + ], + relevance: 0 + }; + + /* + Language: Java + Author: Vsevolod Solovyov + Category: common, enterprise + Website: https://www.java.com/ + */ + + + /** + * Allows recursive regex expressions to a given depth + * + * ie: recurRegex("(abc~~~)", /~~~/g, 2) becomes: + * (abc(abc(abc))) + * + * @param {string} re + * @param {RegExp} substitution (should be a g mode regex) + * @param {number} depth + * @returns {string}`` + */ + function recurRegex(re, substitution, depth) { + if (depth === -1) return ""; + + return re.replace(substitution, _ => { + return recurRegex(re, substitution, depth - 1); + }); + } + + /** @type LanguageFn */ + function java(hljs) { + const regex = hljs.regex; + const JAVA_IDENT_RE = '[\u00C0-\u02B8a-zA-Z_$][\u00C0-\u02B8a-zA-Z_$0-9]*'; + const GENERIC_IDENT_RE = JAVA_IDENT_RE + + recurRegex('(?:<' + JAVA_IDENT_RE + '~~~(?:\\s*,\\s*' + JAVA_IDENT_RE + '~~~)*>)?', /~~~/g, 2); + const MAIN_KEYWORDS = [ + 'synchronized', + 'abstract', + 'private', + 'var', + 'static', + 'if', + 'const ', + 'for', + 'while', + 'strictfp', + 'finally', + 'protected', + 'import', + 'native', + 'final', + 'void', + 'enum', + 'else', + 'break', + 'transient', + 'catch', + 'instanceof', + 'volatile', + 'case', + 'assert', + 'package', + 'default', + 'public', + 'try', + 'switch', + 'continue', + 'throws', + 'protected', + 'public', + 'private', + 'module', + 'requires', + 'exports', + 'do', + 'sealed', + 'yield', + 'permits' + ]; + + const BUILT_INS = [ + 'super', + 'this' + ]; + + const LITERALS = [ + 'false', + 'true', + 'null' + ]; + + const TYPES = [ + 'char', + 'boolean', + 'long', + 'float', + 'int', + 'byte', + 'short', + 'double' + ]; + + const KEYWORDS = { + keyword: MAIN_KEYWORDS, + literal: LITERALS, + type: TYPES, + built_in: BUILT_INS + }; + + const ANNOTATION = { + className: 'meta', + begin: '@' + JAVA_IDENT_RE, + contains: [ + { + begin: /\(/, + end: /\)/, + contains: [ "self" ] // allow nested () inside our annotation + } + ] + }; + const PARAMS = { + className: 'params', + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + relevance: 0, + contains: [ hljs.C_BLOCK_COMMENT_MODE ], + endsParent: true + }; + + return { + name: 'Java', + aliases: [ 'jsp' ], + keywords: KEYWORDS, + illegal: /<\/|#/, + contains: [ + hljs.COMMENT( + '/\\*\\*', + '\\*/', + { + relevance: 0, + contains: [ + { + // eat up @'s in emails to prevent them to be recognized as doctags + begin: /\w+@/, + relevance: 0 + }, + { + className: 'doctag', + begin: '@[A-Za-z]+' + } + ] + } + ), + // relevance boost + { + begin: /import java\.[a-z]+\./, + keywords: "import", + relevance: 2 + }, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + { + begin: /"""/, + end: /"""/, + className: "string", + contains: [ hljs.BACKSLASH_ESCAPE ] + }, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + { + match: [ + /\b(?:class|interface|enum|extends|implements|new)/, + /\s+/, + JAVA_IDENT_RE + ], + className: { + 1: "keyword", + 3: "title.class" + } + }, + { + // Exceptions for hyphenated keywords + match: /non-sealed/, + scope: "keyword" + }, + { + begin: [ + regex.concat(/(?!else)/, JAVA_IDENT_RE), + /\s+/, + JAVA_IDENT_RE, + /\s+/, + /=(?!=)/ + ], + className: { + 1: "type", + 3: "variable", + 5: "operator" + } + }, + { + begin: [ + /record/, + /\s+/, + JAVA_IDENT_RE + ], + className: { + 1: "keyword", + 3: "title.class" + }, + contains: [ + PARAMS, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + { + // Expression keywords prevent 'keyword Name(...)' from being + // recognized as a function definition + beginKeywords: 'new throw return else', + relevance: 0 + }, + { + begin: [ + '(?:' + GENERIC_IDENT_RE + '\\s+)', + hljs.UNDERSCORE_IDENT_RE, + /\s*(?=\()/ + ], + className: { 2: "title.function" }, + keywords: KEYWORDS, + contains: [ + { + className: 'params', + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + relevance: 0, + contains: [ + ANNOTATION, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + NUMERIC, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + NUMERIC, + ANNOTATION + ] + }; + } + + return java; + +})(); + + hljs.registerLanguage('java', hljsGrammar); + })();/*! `javascript` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + const IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*'; + const KEYWORDS = [ + "as", // for exports + "in", + "of", + "if", + "for", + "while", + "finally", + "var", + "new", + "function", + "do", + "return", + "void", + "else", + "break", + "catch", + "instanceof", + "with", + "throw", + "case", + "default", + "try", + "switch", + "continue", + "typeof", + "delete", + "let", + "yield", + "const", + "class", + // JS handles these with a special rule + // "get", + // "set", + "debugger", + "async", + "await", + "static", + "import", + "from", + "export", + "extends" + ]; + const LITERALS = [ + "true", + "false", + "null", + "undefined", + "NaN", + "Infinity" + ]; + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects + const TYPES = [ + // Fundamental objects + "Object", + "Function", + "Boolean", + "Symbol", + // numbers and dates + "Math", + "Date", + "Number", + "BigInt", + // text + "String", + "RegExp", + // Indexed collections + "Array", + "Float32Array", + "Float64Array", + "Int8Array", + "Uint8Array", + "Uint8ClampedArray", + "Int16Array", + "Int32Array", + "Uint16Array", + "Uint32Array", + "BigInt64Array", + "BigUint64Array", + // Keyed collections + "Set", + "Map", + "WeakSet", + "WeakMap", + // Structured data + "ArrayBuffer", + "SharedArrayBuffer", + "Atomics", + "DataView", + "JSON", + // Control abstraction objects + "Promise", + "Generator", + "GeneratorFunction", + "AsyncFunction", + // Reflection + "Reflect", + "Proxy", + // Internationalization + "Intl", + // WebAssembly + "WebAssembly" + ]; + + const ERROR_TYPES = [ + "Error", + "EvalError", + "InternalError", + "RangeError", + "ReferenceError", + "SyntaxError", + "TypeError", + "URIError" + ]; + + const BUILT_IN_GLOBALS = [ + "setInterval", + "setTimeout", + "clearInterval", + "clearTimeout", + + "require", + "exports", + + "eval", + "isFinite", + "isNaN", + "parseFloat", + "parseInt", + "decodeURI", + "decodeURIComponent", + "encodeURI", + "encodeURIComponent", + "escape", + "unescape" + ]; + + const BUILT_IN_VARIABLES = [ + "arguments", + "this", + "super", + "console", + "window", + "document", + "localStorage", + "sessionStorage", + "module", + "global" // Node.js + ]; + + const BUILT_INS = [].concat( + BUILT_IN_GLOBALS, + TYPES, + ERROR_TYPES + ); + + /* + Language: JavaScript + Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. + Category: common, scripting, web + Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript + */ + + + /** @type LanguageFn */ + function javascript(hljs) { + const regex = hljs.regex; + /** + * Takes a string like " { + const tag = "', + end: '' + }; + // to avoid some special cases inside isTrulyOpeningTag + const XML_SELF_CLOSING = /<[A-Za-z0-9\\._:-]+\s*\/>/; + const XML_TAG = { + begin: /<[A-Za-z0-9\\._:-]+/, + end: /\/[A-Za-z0-9\\._:-]+>|\/>/, + /** + * @param {RegExpMatchArray} match + * @param {CallbackResponse} response + */ + isTrulyOpeningTag: (match, response) => { + const afterMatchIndex = match[0].length + match.index; + const nextChar = match.input[afterMatchIndex]; + if ( + // HTML should not include another raw `<` inside a tag + // nested type? + // `>`, etc. + nextChar === "<" || + // the , gives away that this is not HTML + // `` + nextChar === "," + ) { + response.ignoreMatch(); + return; + } + + // `` + // Quite possibly a tag, lets look for a matching closing tag... + if (nextChar === ">") { + // if we cannot find a matching closing tag, then we + // will ignore it + if (!hasClosingTag(match, { after: afterMatchIndex })) { + response.ignoreMatch(); + } + } + + // `` (self-closing) + // handled by simpleSelfClosing rule + + let m; + const afterMatch = match.input.substring(afterMatchIndex); + + // some more template typing stuff + // (key?: string) => Modify< + if ((m = afterMatch.match(/^\s*=/))) { + response.ignoreMatch(); + return; + } + + // `` + // technically this could be HTML, but it smells like a type + // NOTE: This is ugh, but added specifically for https://github.com/highlightjs/highlight.js/issues/3276 + if ((m = afterMatch.match(/^\s+extends\s+/))) { + if (m.index === 0) { + response.ignoreMatch(); + // eslint-disable-next-line no-useless-return + return; + } + } + } + }; + const KEYWORDS$1 = { + $pattern: IDENT_RE, + keyword: KEYWORDS, + literal: LITERALS, + built_in: BUILT_INS, + "variable.language": BUILT_IN_VARIABLES + }; + + // https://tc39.es/ecma262/#sec-literals-numeric-literals + const decimalDigits = '[0-9](_?[0-9])*'; + const frac = `\\.(${decimalDigits})`; + // DecimalIntegerLiteral, including Annex B NonOctalDecimalIntegerLiteral + // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals + const decimalInteger = `0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*`; + const NUMBER = { + className: 'number', + variants: [ + // DecimalLiteral + { begin: `(\\b(${decimalInteger})((${frac})|\\.)?|(${frac}))` + + `[eE][+-]?(${decimalDigits})\\b` }, + { begin: `\\b(${decimalInteger})\\b((${frac})\\b|\\.)?|(${frac})\\b` }, + + // DecimalBigIntegerLiteral + { begin: `\\b(0|[1-9](_?[0-9])*)n\\b` }, + + // NonDecimalIntegerLiteral + { begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b" }, + { begin: "\\b0[bB][0-1](_?[0-1])*n?\\b" }, + { begin: "\\b0[oO][0-7](_?[0-7])*n?\\b" }, + + // LegacyOctalIntegerLiteral (does not include underscore separators) + // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals + { begin: "\\b0[0-7]+n?\\b" }, + ], + relevance: 0 + }; + + const SUBST = { + className: 'subst', + begin: '\\$\\{', + end: '\\}', + keywords: KEYWORDS$1, + contains: [] // defined later + }; + const HTML_TEMPLATE = { + begin: 'html`', + end: '', + starts: { + end: '`', + returnEnd: false, + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + subLanguage: 'xml' + } + }; + const CSS_TEMPLATE = { + begin: 'css`', + end: '', + starts: { + end: '`', + returnEnd: false, + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + subLanguage: 'css' + } + }; + const GRAPHQL_TEMPLATE = { + begin: 'gql`', + end: '', + starts: { + end: '`', + returnEnd: false, + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + subLanguage: 'graphql' + } + }; + const TEMPLATE_STRING = { + className: 'string', + begin: '`', + end: '`', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ] + }; + const JSDOC_COMMENT = hljs.COMMENT( + /\/\*\*(?!\/)/, + '\\*/', + { + relevance: 0, + contains: [ + { + begin: '(?=@[A-Za-z]+)', + relevance: 0, + contains: [ + { + className: 'doctag', + begin: '@[A-Za-z]+' + }, + { + className: 'type', + begin: '\\{', + end: '\\}', + excludeEnd: true, + excludeBegin: true, + relevance: 0 + }, + { + className: 'variable', + begin: IDENT_RE$1 + '(?=\\s*(-)|$)', + endsParent: true, + relevance: 0 + }, + // eat spaces (not newlines) so we can find + // types or variables + { + begin: /(?=[^\n])\s/, + relevance: 0 + } + ] + } + ] + } + ); + const COMMENT = { + className: "comment", + variants: [ + JSDOC_COMMENT, + hljs.C_BLOCK_COMMENT_MODE, + hljs.C_LINE_COMMENT_MODE + ] + }; + const SUBST_INTERNALS = [ + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + HTML_TEMPLATE, + CSS_TEMPLATE, + GRAPHQL_TEMPLATE, + TEMPLATE_STRING, + // Skip numbers when they are part of a variable name + { match: /\$\d+/ }, + NUMBER, + // This is intentional: + // See https://github.com/highlightjs/highlight.js/issues/3288 + // hljs.REGEXP_MODE + ]; + SUBST.contains = SUBST_INTERNALS + .concat({ + // we need to pair up {} inside our subst to prevent + // it from ending too early by matching another } + begin: /\{/, + end: /\}/, + keywords: KEYWORDS$1, + contains: [ + "self" + ].concat(SUBST_INTERNALS) + }); + const SUBST_AND_COMMENTS = [].concat(COMMENT, SUBST.contains); + const PARAMS_CONTAINS = SUBST_AND_COMMENTS.concat([ + // eat recursive parens in sub expressions + { + begin: /\(/, + end: /\)/, + keywords: KEYWORDS$1, + contains: ["self"].concat(SUBST_AND_COMMENTS) + } + ]); + const PARAMS = { + className: 'params', + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, + keywords: KEYWORDS$1, + contains: PARAMS_CONTAINS + }; + + // ES6 classes + const CLASS_OR_EXTENDS = { + variants: [ + // class Car extends vehicle + { + match: [ + /class/, + /\s+/, + IDENT_RE$1, + /\s+/, + /extends/, + /\s+/, + regex.concat(IDENT_RE$1, "(", regex.concat(/\./, IDENT_RE$1), ")*") + ], + scope: { + 1: "keyword", + 3: "title.class", + 5: "keyword", + 7: "title.class.inherited" + } + }, + // class Car + { + match: [ + /class/, + /\s+/, + IDENT_RE$1 + ], + scope: { + 1: "keyword", + 3: "title.class" + } + }, + + ] + }; + + const CLASS_REFERENCE = { + relevance: 0, + match: + regex.either( + // Hard coded exceptions + /\bJSON/, + // Float32Array, OutT + /\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/, + // CSSFactory, CSSFactoryT + /\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/, + // FPs, FPsT + /\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/, + // P + // single letters are not highlighted + // BLAH + // this will be flagged as a UPPER_CASE_CONSTANT instead + ), + className: "title.class", + keywords: { + _: [ + // se we still get relevance credit for JS library classes + ...TYPES, + ...ERROR_TYPES + ] + } + }; + + const USE_STRICT = { + label: "use_strict", + className: 'meta', + relevance: 10, + begin: /^\s*['"]use (strict|asm)['"]/ + }; + + const FUNCTION_DEFINITION = { + variants: [ + { + match: [ + /function/, + /\s+/, + IDENT_RE$1, + /(?=\s*\()/ + ] + }, + // anonymous function + { + match: [ + /function/, + /\s*(?=\()/ + ] + } + ], + className: { + 1: "keyword", + 3: "title.function" + }, + label: "func.def", + contains: [ PARAMS ], + illegal: /%/ + }; + + const UPPER_CASE_CONSTANT = { + relevance: 0, + match: /\b[A-Z][A-Z_0-9]+\b/, + className: "variable.constant" + }; + + function noneOf(list) { + return regex.concat("(?!", list.join("|"), ")"); + } + + const FUNCTION_CALL = { + match: regex.concat( + /\b/, + noneOf([ + ...BUILT_IN_GLOBALS, + "super", + "import" + ]), + IDENT_RE$1, regex.lookahead(/\(/)), + className: "title.function", + relevance: 0 + }; + + const PROPERTY_ACCESS = { + begin: regex.concat(/\./, regex.lookahead( + regex.concat(IDENT_RE$1, /(?![0-9A-Za-z$_(])/) + )), + end: IDENT_RE$1, + excludeBegin: true, + keywords: "prototype", + className: "property", + relevance: 0 + }; + + const GETTER_OR_SETTER = { + match: [ + /get|set/, + /\s+/, + IDENT_RE$1, + /(?=\()/ + ], + className: { + 1: "keyword", + 3: "title.function" + }, + contains: [ + { // eat to avoid empty params + begin: /\(\)/ + }, + PARAMS + ] + }; + + const FUNC_LEAD_IN_RE = '(\\(' + + '[^()]*(\\(' + + '[^()]*(\\(' + + '[^()]*' + + '\\)[^()]*)*' + + '\\)[^()]*)*' + + '\\)|' + hljs.UNDERSCORE_IDENT_RE + ')\\s*=>'; + + const FUNCTION_VARIABLE = { + match: [ + /const|var|let/, /\s+/, + IDENT_RE$1, /\s*/, + /=\s*/, + /(async\s*)?/, // async is optional + regex.lookahead(FUNC_LEAD_IN_RE) + ], + keywords: "async", + className: { + 1: "keyword", + 3: "title.function" + }, + contains: [ + PARAMS + ] + }; + + return { + name: 'JavaScript', + aliases: ['js', 'jsx', 'mjs', 'cjs'], + keywords: KEYWORDS$1, + // this will be extended by TypeScript + exports: { PARAMS_CONTAINS, CLASS_REFERENCE }, + illegal: /#(?![$_A-z])/, + contains: [ + hljs.SHEBANG({ + label: "shebang", + binary: "node", + relevance: 5 + }), + USE_STRICT, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + HTML_TEMPLATE, + CSS_TEMPLATE, + GRAPHQL_TEMPLATE, + TEMPLATE_STRING, + COMMENT, + // Skip numbers when they are part of a variable name + { match: /\$\d+/ }, + NUMBER, + CLASS_REFERENCE, + { + className: 'attr', + begin: IDENT_RE$1 + regex.lookahead(':'), + relevance: 0 + }, + FUNCTION_VARIABLE, + { // "value" container + begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*', + keywords: 'return throw case', + relevance: 0, + contains: [ + COMMENT, + hljs.REGEXP_MODE, + { + className: 'function', + // we have to count the parens to make sure we actually have the + // correct bounding ( ) before the =>. There could be any number of + // sub-expressions inside also surrounded by parens. + begin: FUNC_LEAD_IN_RE, + returnBegin: true, + end: '\\s*=>', + contains: [ + { + className: 'params', + variants: [ + { + begin: hljs.UNDERSCORE_IDENT_RE, + relevance: 0 + }, + { + className: null, + begin: /\(\s*\)/, + skip: true + }, + { + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, + keywords: KEYWORDS$1, + contains: PARAMS_CONTAINS + } + ] + } + ] + }, + { // could be a comma delimited list of params to a function call + begin: /,/, + relevance: 0 + }, + { + match: /\s+/, + relevance: 0 + }, + { // JSX + variants: [ + { begin: FRAGMENT.begin, end: FRAGMENT.end }, + { match: XML_SELF_CLOSING }, + { + begin: XML_TAG.begin, + // we carefully check the opening tag to see if it truly + // is a tag and not a false positive + 'on:begin': XML_TAG.isTrulyOpeningTag, + end: XML_TAG.end + } + ], + subLanguage: 'xml', + contains: [ + { + begin: XML_TAG.begin, + end: XML_TAG.end, + skip: true, + contains: ['self'] + } + ] + } + ], + }, + FUNCTION_DEFINITION, + { + // prevent this from getting swallowed up by function + // since they appear "function like" + beginKeywords: "while if switch catch for" + }, + { + // we have to count the parens to make sure we actually have the correct + // bounding ( ). There could be any number of sub-expressions inside + // also surrounded by parens. + begin: '\\b(?!function)' + hljs.UNDERSCORE_IDENT_RE + + '\\(' + // first parens + '[^()]*(\\(' + + '[^()]*(\\(' + + '[^()]*' + + '\\)[^()]*)*' + + '\\)[^()]*)*' + + '\\)\\s*\\{', // end parens + returnBegin:true, + label: "func.def", + contains: [ + PARAMS, + hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1, className: "title.function" }) + ] + }, + // catch ... so it won't trigger the property rule below + { + match: /\.\.\./, + relevance: 0 + }, + PROPERTY_ACCESS, + // hack: prevents detection of keywords in some circumstances + // .keyword() + // $keyword = x + { + match: '\\$' + IDENT_RE$1, + relevance: 0 + }, + { + match: [ /\bconstructor(?=\s*\()/ ], + className: { 1: "title.function" }, + contains: [ PARAMS ] + }, + FUNCTION_CALL, + UPPER_CASE_CONSTANT, + CLASS_OR_EXTENDS, + GETTER_OR_SETTER, + { + match: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something` + } + ] + }; + } + + return javascript; + +})(); + + hljs.registerLanguage('javascript', hljsGrammar); + })();/*! `json` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: JSON + Description: JSON (JavaScript Object Notation) is a lightweight data-interchange format. + Author: Ivan Sagalaev + Website: http://www.json.org + Category: common, protocols, web + */ + + function json(hljs) { + const ATTRIBUTE = { + className: 'attr', + begin: /"(\\.|[^\\"\r\n])*"(?=\s*:)/, + relevance: 1.01 + }; + const PUNCTUATION = { + match: /[{}[\],:]/, + className: "punctuation", + relevance: 0 + }; + const LITERALS = [ + "true", + "false", + "null" + ]; + // NOTE: normally we would rely on `keywords` for this but using a mode here allows us + // - to use the very tight `illegal: \S` rule later to flag any other character + // - as illegal indicating that despite looking like JSON we do not truly have + // - JSON and thus improve false-positively greatly since JSON will try and claim + // - all sorts of JSON looking stuff + const LITERALS_MODE = { + scope: "literal", + beginKeywords: LITERALS.join(" "), + }; + + return { + name: 'JSON', + keywords:{ + literal: LITERALS, + }, + contains: [ + ATTRIBUTE, + PUNCTUATION, + hljs.QUOTE_STRING_MODE, + LITERALS_MODE, + hljs.C_NUMBER_MODE, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ], + illegal: '\\S' + }; + } + + return json; + +})(); + + hljs.registerLanguage('json', hljsGrammar); + })();/*! `julia` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Julia + Description: Julia is a high-level, high-performance, dynamic programming language. + Author: Kenta Sato + Contributors: Alex Arslan , Fredrik Ekre + Website: https://julialang.org + Category: scientific + */ + + function julia(hljs) { + // Since there are numerous special names in Julia, it is too much trouble + // to maintain them by hand. Hence these names (i.e. keywords, literals and + // built-ins) are automatically generated from Julia 1.5.2 itself through + // the following scripts for each. + + // ref: https://docs.julialang.org/en/v1/manual/variables/#Allowed-Variable-Names + const VARIABLE_NAME_RE = '[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*'; + + // # keyword generator, multi-word keywords handled manually below (Julia 1.5.2) + // import REPL.REPLCompletions + // res = String["in", "isa", "where"] + // for kw in collect(x.keyword for x in REPLCompletions.complete_keyword("")) + // if !(contains(kw, " ") || kw == "struct") + // push!(res, kw) + // end + // end + // sort!(unique!(res)) + // foreach(x -> println("\'", x, "\',"), res) + const KEYWORD_LIST = [ + 'baremodule', + 'begin', + 'break', + 'catch', + 'ccall', + 'const', + 'continue', + 'do', + 'else', + 'elseif', + 'end', + 'export', + 'false', + 'finally', + 'for', + 'function', + 'global', + 'if', + 'import', + 'in', + 'isa', + 'let', + 'local', + 'macro', + 'module', + 'quote', + 'return', + 'true', + 'try', + 'using', + 'where', + 'while', + ]; + + // # literal generator (Julia 1.5.2) + // import REPL.REPLCompletions + // res = String["true", "false"] + // for compl in filter!(x -> isa(x, REPLCompletions.ModuleCompletion) && (x.parent === Base || x.parent === Core), + // REPLCompletions.completions("", 0)[1]) + // try + // v = eval(Symbol(compl.mod)) + // if !(v isa Function || v isa Type || v isa TypeVar || v isa Module || v isa Colon) + // push!(res, compl.mod) + // end + // catch e + // end + // end + // sort!(unique!(res)) + // foreach(x -> println("\'", x, "\',"), res) + const LITERAL_LIST = [ + 'ARGS', + 'C_NULL', + 'DEPOT_PATH', + 'ENDIAN_BOM', + 'ENV', + 'Inf', + 'Inf16', + 'Inf32', + 'Inf64', + 'InsertionSort', + 'LOAD_PATH', + 'MergeSort', + 'NaN', + 'NaN16', + 'NaN32', + 'NaN64', + 'PROGRAM_FILE', + 'QuickSort', + 'RoundDown', + 'RoundFromZero', + 'RoundNearest', + 'RoundNearestTiesAway', + 'RoundNearestTiesUp', + 'RoundToZero', + 'RoundUp', + 'VERSION|0', + 'devnull', + 'false', + 'im', + 'missing', + 'nothing', + 'pi', + 'stderr', + 'stdin', + 'stdout', + 'true', + 'undef', + 'π', + 'ℯ', + ]; + + // # built_in generator (Julia 1.5.2) + // import REPL.REPLCompletions + // res = String[] + // for compl in filter!(x -> isa(x, REPLCompletions.ModuleCompletion) && (x.parent === Base || x.parent === Core), + // REPLCompletions.completions("", 0)[1]) + // try + // v = eval(Symbol(compl.mod)) + // if (v isa Type || v isa TypeVar) && (compl.mod != "=>") + // push!(res, compl.mod) + // end + // catch e + // end + // end + // sort!(unique!(res)) + // foreach(x -> println("\'", x, "\',"), res) + const BUILT_IN_LIST = [ + 'AbstractArray', + 'AbstractChannel', + 'AbstractChar', + 'AbstractDict', + 'AbstractDisplay', + 'AbstractFloat', + 'AbstractIrrational', + 'AbstractMatrix', + 'AbstractRange', + 'AbstractSet', + 'AbstractString', + 'AbstractUnitRange', + 'AbstractVecOrMat', + 'AbstractVector', + 'Any', + 'ArgumentError', + 'Array', + 'AssertionError', + 'BigFloat', + 'BigInt', + 'BitArray', + 'BitMatrix', + 'BitSet', + 'BitVector', + 'Bool', + 'BoundsError', + 'CapturedException', + 'CartesianIndex', + 'CartesianIndices', + 'Cchar', + 'Cdouble', + 'Cfloat', + 'Channel', + 'Char', + 'Cint', + 'Cintmax_t', + 'Clong', + 'Clonglong', + 'Cmd', + 'Colon', + 'Complex', + 'ComplexF16', + 'ComplexF32', + 'ComplexF64', + 'CompositeException', + 'Condition', + 'Cptrdiff_t', + 'Cshort', + 'Csize_t', + 'Cssize_t', + 'Cstring', + 'Cuchar', + 'Cuint', + 'Cuintmax_t', + 'Culong', + 'Culonglong', + 'Cushort', + 'Cvoid', + 'Cwchar_t', + 'Cwstring', + 'DataType', + 'DenseArray', + 'DenseMatrix', + 'DenseVecOrMat', + 'DenseVector', + 'Dict', + 'DimensionMismatch', + 'Dims', + 'DivideError', + 'DomainError', + 'EOFError', + 'Enum', + 'ErrorException', + 'Exception', + 'ExponentialBackOff', + 'Expr', + 'Float16', + 'Float32', + 'Float64', + 'Function', + 'GlobalRef', + 'HTML', + 'IO', + 'IOBuffer', + 'IOContext', + 'IOStream', + 'IdDict', + 'IndexCartesian', + 'IndexLinear', + 'IndexStyle', + 'InexactError', + 'InitError', + 'Int', + 'Int128', + 'Int16', + 'Int32', + 'Int64', + 'Int8', + 'Integer', + 'InterruptException', + 'InvalidStateException', + 'Irrational', + 'KeyError', + 'LinRange', + 'LineNumberNode', + 'LinearIndices', + 'LoadError', + 'MIME', + 'Matrix', + 'Method', + 'MethodError', + 'Missing', + 'MissingException', + 'Module', + 'NTuple', + 'NamedTuple', + 'Nothing', + 'Number', + 'OrdinalRange', + 'OutOfMemoryError', + 'OverflowError', + 'Pair', + 'PartialQuickSort', + 'PermutedDimsArray', + 'Pipe', + 'ProcessFailedException', + 'Ptr', + 'QuoteNode', + 'Rational', + 'RawFD', + 'ReadOnlyMemoryError', + 'Real', + 'ReentrantLock', + 'Ref', + 'Regex', + 'RegexMatch', + 'RoundingMode', + 'SegmentationFault', + 'Set', + 'Signed', + 'Some', + 'StackOverflowError', + 'StepRange', + 'StepRangeLen', + 'StridedArray', + 'StridedMatrix', + 'StridedVecOrMat', + 'StridedVector', + 'String', + 'StringIndexError', + 'SubArray', + 'SubString', + 'SubstitutionString', + 'Symbol', + 'SystemError', + 'Task', + 'TaskFailedException', + 'Text', + 'TextDisplay', + 'Timer', + 'Tuple', + 'Type', + 'TypeError', + 'TypeVar', + 'UInt', + 'UInt128', + 'UInt16', + 'UInt32', + 'UInt64', + 'UInt8', + 'UndefInitializer', + 'UndefKeywordError', + 'UndefRefError', + 'UndefVarError', + 'Union', + 'UnionAll', + 'UnitRange', + 'Unsigned', + 'Val', + 'Vararg', + 'VecElement', + 'VecOrMat', + 'Vector', + 'VersionNumber', + 'WeakKeyDict', + 'WeakRef', + ]; + + const KEYWORDS = { + $pattern: VARIABLE_NAME_RE, + keyword: KEYWORD_LIST, + literal: LITERAL_LIST, + built_in: BUILT_IN_LIST, + }; + + // placeholder for recursive self-reference + const DEFAULT = { + keywords: KEYWORDS, + illegal: /<\// + }; + + // ref: https://docs.julialang.org/en/v1/manual/integers-and-floating-point-numbers/ + const NUMBER = { + className: 'number', + // supported numeric literals: + // * binary literal (e.g. 0x10) + // * octal literal (e.g. 0o76543210) + // * hexadecimal literal (e.g. 0xfedcba876543210) + // * hexadecimal floating point literal (e.g. 0x1p0, 0x1.2p2) + // * decimal literal (e.g. 9876543210, 100_000_000) + // * floating pointe literal (e.g. 1.2, 1.2f, .2, 1., 1.2e10, 1.2e-10) + begin: /(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/, + relevance: 0 + }; + + const CHAR = { + className: 'string', + begin: /'(.|\\[xXuU][a-zA-Z0-9]+)'/ + }; + + const INTERPOLATION = { + className: 'subst', + begin: /\$\(/, + end: /\)/, + keywords: KEYWORDS + }; + + const INTERPOLATED_VARIABLE = { + className: 'variable', + begin: '\\$' + VARIABLE_NAME_RE + }; + + // TODO: neatly escape normal code in string literal + const STRING = { + className: 'string', + contains: [ + hljs.BACKSLASH_ESCAPE, + INTERPOLATION, + INTERPOLATED_VARIABLE + ], + variants: [ + { + begin: /\w*"""/, + end: /"""\w*/, + relevance: 10 + }, + { + begin: /\w*"/, + end: /"\w*/ + } + ] + }; + + const COMMAND = { + className: 'string', + contains: [ + hljs.BACKSLASH_ESCAPE, + INTERPOLATION, + INTERPOLATED_VARIABLE + ], + begin: '`', + end: '`' + }; + + const MACROCALL = { + className: 'meta', + begin: '@' + VARIABLE_NAME_RE + }; + + const COMMENT = { + className: 'comment', + variants: [ + { + begin: '#=', + end: '=#', + relevance: 10 + }, + { + begin: '#', + end: '$' + } + ] + }; + + DEFAULT.name = 'Julia'; + DEFAULT.contains = [ + NUMBER, + CHAR, + STRING, + COMMAND, + MACROCALL, + COMMENT, + hljs.HASH_COMMENT_MODE, + { + className: 'keyword', + begin: + '\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b' + }, + { begin: /<:/ } // relevance booster + ]; + INTERPOLATION.contains = DEFAULT.contains; + + return DEFAULT; + } + + return julia; + +})(); + + hljs.registerLanguage('julia', hljsGrammar); + })();/*! `kotlin` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + // https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.10 + var decimalDigits = '[0-9](_*[0-9])*'; + var frac = `\\.(${decimalDigits})`; + var hexDigits = '[0-9a-fA-F](_*[0-9a-fA-F])*'; + var NUMERIC = { + className: 'number', + variants: [ + // DecimalFloatingPointLiteral + // including ExponentPart + { begin: `(\\b(${decimalDigits})((${frac})|\\.)?|(${frac}))` + + `[eE][+-]?(${decimalDigits})[fFdD]?\\b` }, + // excluding ExponentPart + { begin: `\\b(${decimalDigits})((${frac})[fFdD]?\\b|\\.([fFdD]\\b)?)` }, + { begin: `(${frac})[fFdD]?\\b` }, + { begin: `\\b(${decimalDigits})[fFdD]\\b` }, + + // HexadecimalFloatingPointLiteral + { begin: `\\b0[xX]((${hexDigits})\\.?|(${hexDigits})?\\.(${hexDigits}))` + + `[pP][+-]?(${decimalDigits})[fFdD]?\\b` }, + + // DecimalIntegerLiteral + { begin: '\\b(0|[1-9](_*[0-9])*)[lL]?\\b' }, + + // HexIntegerLiteral + { begin: `\\b0[xX](${hexDigits})[lL]?\\b` }, + + // OctalIntegerLiteral + { begin: '\\b0(_*[0-7])*[lL]?\\b' }, + + // BinaryIntegerLiteral + { begin: '\\b0[bB][01](_*[01])*[lL]?\\b' }, + ], + relevance: 0 + }; + + /* + Language: Kotlin + Description: Kotlin is an OSS statically typed programming language that targets the JVM, Android, JavaScript and Native. + Author: Sergey Mashkov + Website: https://kotlinlang.org + Category: common + */ + + + function kotlin(hljs) { + const KEYWORDS = { + keyword: + 'abstract as val var vararg get set class object open private protected public noinline ' + + 'crossinline dynamic final enum if else do while for when throw try catch finally ' + + 'import package is in fun override companion reified inline lateinit init ' + + 'interface annotation data sealed internal infix operator out by constructor super ' + + 'tailrec where const inner suspend typealias external expect actual', + built_in: + 'Byte Short Char Int Long Boolean Float Double Void Unit Nothing', + literal: + 'true false null' + }; + const KEYWORDS_WITH_LABEL = { + className: 'keyword', + begin: /\b(break|continue|return|this)\b/, + starts: { contains: [ + { + className: 'symbol', + begin: /@\w+/ + } + ] } + }; + const LABEL = { + className: 'symbol', + begin: hljs.UNDERSCORE_IDENT_RE + '@' + }; + + // for string templates + const SUBST = { + className: 'subst', + begin: /\$\{/, + end: /\}/, + contains: [ hljs.C_NUMBER_MODE ] + }; + const VARIABLE = { + className: 'variable', + begin: '\\$' + hljs.UNDERSCORE_IDENT_RE + }; + const STRING = { + className: 'string', + variants: [ + { + begin: '"""', + end: '"""(?=[^"])', + contains: [ + VARIABLE, + SUBST + ] + }, + // Can't use built-in modes easily, as we want to use STRING in the meta + // context as 'meta-string' and there's no syntax to remove explicitly set + // classNames in built-in modes. + { + begin: '\'', + end: '\'', + illegal: /\n/, + contains: [ hljs.BACKSLASH_ESCAPE ] + }, + { + begin: '"', + end: '"', + illegal: /\n/, + contains: [ + hljs.BACKSLASH_ESCAPE, + VARIABLE, + SUBST + ] + } + ] + }; + SUBST.contains.push(STRING); + + const ANNOTATION_USE_SITE = { + className: 'meta', + begin: '@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*' + hljs.UNDERSCORE_IDENT_RE + ')?' + }; + const ANNOTATION = { + className: 'meta', + begin: '@' + hljs.UNDERSCORE_IDENT_RE, + contains: [ + { + begin: /\(/, + end: /\)/, + contains: [ + hljs.inherit(STRING, { className: 'string' }), + "self" + ] + } + ] + }; + + // https://kotlinlang.org/docs/reference/whatsnew11.html#underscores-in-numeric-literals + // According to the doc above, the number mode of kotlin is the same as java 8, + // so the code below is copied from java.js + const KOTLIN_NUMBER_MODE = NUMERIC; + const KOTLIN_NESTED_COMMENT = hljs.COMMENT( + '/\\*', '\\*/', + { contains: [ hljs.C_BLOCK_COMMENT_MODE ] } + ); + const KOTLIN_PAREN_TYPE = { variants: [ + { + className: 'type', + begin: hljs.UNDERSCORE_IDENT_RE + }, + { + begin: /\(/, + end: /\)/, + contains: [] // defined later + } + ] }; + const KOTLIN_PAREN_TYPE2 = KOTLIN_PAREN_TYPE; + KOTLIN_PAREN_TYPE2.variants[1].contains = [ KOTLIN_PAREN_TYPE ]; + KOTLIN_PAREN_TYPE.variants[1].contains = [ KOTLIN_PAREN_TYPE2 ]; + + return { + name: 'Kotlin', + aliases: [ + 'kt', + 'kts' + ], + keywords: KEYWORDS, + contains: [ + hljs.COMMENT( + '/\\*\\*', + '\\*/', + { + relevance: 0, + contains: [ + { + className: 'doctag', + begin: '@[A-Za-z]+' + } + ] + } + ), + hljs.C_LINE_COMMENT_MODE, + KOTLIN_NESTED_COMMENT, + KEYWORDS_WITH_LABEL, + LABEL, + ANNOTATION_USE_SITE, + ANNOTATION, + { + className: 'function', + beginKeywords: 'fun', + end: '[(]|$', + returnBegin: true, + excludeEnd: true, + keywords: KEYWORDS, + relevance: 5, + contains: [ + { + begin: hljs.UNDERSCORE_IDENT_RE + '\\s*\\(', + returnBegin: true, + relevance: 0, + contains: [ hljs.UNDERSCORE_TITLE_MODE ] + }, + { + className: 'type', + begin: //, + keywords: 'reified', + relevance: 0 + }, + { + className: 'params', + begin: /\(/, + end: /\)/, + endsParent: true, + keywords: KEYWORDS, + relevance: 0, + contains: [ + { + begin: /:/, + end: /[=,\/]/, + endsWithParent: true, + contains: [ + KOTLIN_PAREN_TYPE, + hljs.C_LINE_COMMENT_MODE, + KOTLIN_NESTED_COMMENT + ], + relevance: 0 + }, + hljs.C_LINE_COMMENT_MODE, + KOTLIN_NESTED_COMMENT, + ANNOTATION_USE_SITE, + ANNOTATION, + STRING, + hljs.C_NUMBER_MODE + ] + }, + KOTLIN_NESTED_COMMENT + ] + }, + { + begin: [ + /class|interface|trait/, + /\s+/, + hljs.UNDERSCORE_IDENT_RE + ], + beginScope: { + 3: "title.class" + }, + keywords: 'class interface trait', + end: /[:\{(]|$/, + excludeEnd: true, + illegal: 'extends implements', + contains: [ + { beginKeywords: 'public protected internal private constructor' }, + hljs.UNDERSCORE_TITLE_MODE, + { + className: 'type', + begin: //, + excludeBegin: true, + excludeEnd: true, + relevance: 0 + }, + { + className: 'type', + begin: /[,:]\s*/, + end: /[<\(,){\s]|$/, + excludeBegin: true, + returnEnd: true + }, + ANNOTATION_USE_SITE, + ANNOTATION + ] + }, + STRING, + { + className: 'meta', + begin: "^#!/usr/bin/env", + end: '$', + illegal: '\n' + }, + KOTLIN_NUMBER_MODE + ] + }; + } + + return kotlin; + +})(); + + hljs.registerLanguage('kotlin', hljsGrammar); + })();/*! `latex` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: LaTeX + Author: Benedikt Wilde + Website: https://www.latex-project.org + Category: markup + */ + + /** @type LanguageFn */ + function latex(hljs) { + const regex = hljs.regex; + const KNOWN_CONTROL_WORDS = regex.either(...[ + '(?:NeedsTeXFormat|RequirePackage|GetIdInfo)', + 'Provides(?:Expl)?(?:Package|Class|File)', + '(?:DeclareOption|ProcessOptions)', + '(?:documentclass|usepackage|input|include)', + 'makeat(?:letter|other)', + 'ExplSyntax(?:On|Off)', + '(?:new|renew|provide)?command', + '(?:re)newenvironment', + '(?:New|Renew|Provide|Declare)(?:Expandable)?DocumentCommand', + '(?:New|Renew|Provide|Declare)DocumentEnvironment', + '(?:(?:e|g|x)?def|let)', + '(?:begin|end)', + '(?:part|chapter|(?:sub){0,2}section|(?:sub)?paragraph)', + 'caption', + '(?:label|(?:eq|page|name)?ref|(?:paren|foot|super)?cite)', + '(?:alpha|beta|[Gg]amma|[Dd]elta|(?:var)?epsilon|zeta|eta|[Tt]heta|vartheta)', + '(?:iota|(?:var)?kappa|[Ll]ambda|mu|nu|[Xx]i|[Pp]i|varpi|(?:var)rho)', + '(?:[Ss]igma|varsigma|tau|[Uu]psilon|[Pp]hi|varphi|chi|[Pp]si|[Oo]mega)', + '(?:frac|sum|prod|lim|infty|times|sqrt|leq|geq|left|right|middle|[bB]igg?)', + '(?:[lr]angle|q?quad|[lcvdi]?dots|d?dot|hat|tilde|bar)' + ].map(word => word + '(?![a-zA-Z@:_])')); + const L3_REGEX = new RegExp([ + // A function \module_function_name:signature or \__module_function_name:signature, + // where both module and function_name need at least two characters and + // function_name may contain single underscores. + '(?:__)?[a-zA-Z]{2,}_[a-zA-Z](?:_?[a-zA-Z])+:[a-zA-Z]*', + // A variable \scope_module_and_name_type or \scope__module_ane_name_type, + // where scope is one of l, g or c, type needs at least two characters + // and module_and_name may contain single underscores. + '[lgc]__?[a-zA-Z](?:_?[a-zA-Z])*_[a-zA-Z]{2,}', + // A quark \q_the_name or \q__the_name or + // scan mark \s_the_name or \s__vthe_name, + // where variable_name needs at least two characters and + // may contain single underscores. + '[qs]__?[a-zA-Z](?:_?[a-zA-Z])+', + // Other LaTeX3 macro names that are not covered by the three rules above. + 'use(?:_i)?:[a-zA-Z]*', + '(?:else|fi|or):', + '(?:if|cs|exp):w', + '(?:hbox|vbox):n', + '::[a-zA-Z]_unbraced', + '::[a-zA-Z:]' + ].map(pattern => pattern + '(?![a-zA-Z:_])').join('|')); + const L2_VARIANTS = [ + { begin: /[a-zA-Z@]+/ }, // control word + { begin: /[^a-zA-Z@]?/ } // control symbol + ]; + const DOUBLE_CARET_VARIANTS = [ + { begin: /\^{6}[0-9a-f]{6}/ }, + { begin: /\^{5}[0-9a-f]{5}/ }, + { begin: /\^{4}[0-9a-f]{4}/ }, + { begin: /\^{3}[0-9a-f]{3}/ }, + { begin: /\^{2}[0-9a-f]{2}/ }, + { begin: /\^{2}[\u0000-\u007f]/ } + ]; + const CONTROL_SEQUENCE = { + className: 'keyword', + begin: /\\/, + relevance: 0, + contains: [ + { + endsParent: true, + begin: KNOWN_CONTROL_WORDS + }, + { + endsParent: true, + begin: L3_REGEX + }, + { + endsParent: true, + variants: DOUBLE_CARET_VARIANTS + }, + { + endsParent: true, + relevance: 0, + variants: L2_VARIANTS + } + ] + }; + const MACRO_PARAM = { + className: 'params', + relevance: 0, + begin: /#+\d?/ + }; + const DOUBLE_CARET_CHAR = { + // relevance: 1 + variants: DOUBLE_CARET_VARIANTS }; + const SPECIAL_CATCODE = { + className: 'built_in', + relevance: 0, + begin: /[$&^_]/ + }; + const MAGIC_COMMENT = { + className: 'meta', + begin: /% ?!(T[eE]X|tex|BIB|bib)/, + end: '$', + relevance: 10 + }; + const COMMENT = hljs.COMMENT( + '%', + '$', + { relevance: 0 } + ); + const EVERYTHING_BUT_VERBATIM = [ + CONTROL_SEQUENCE, + MACRO_PARAM, + DOUBLE_CARET_CHAR, + SPECIAL_CATCODE, + MAGIC_COMMENT, + COMMENT + ]; + const BRACE_GROUP_NO_VERBATIM = { + begin: /\{/, + end: /\}/, + relevance: 0, + contains: [ + 'self', + ...EVERYTHING_BUT_VERBATIM + ] + }; + const ARGUMENT_BRACES = hljs.inherit( + BRACE_GROUP_NO_VERBATIM, + { + relevance: 0, + endsParent: true, + contains: [ + BRACE_GROUP_NO_VERBATIM, + ...EVERYTHING_BUT_VERBATIM + ] + } + ); + const ARGUMENT_BRACKETS = { + begin: /\[/, + end: /\]/, + endsParent: true, + relevance: 0, + contains: [ + BRACE_GROUP_NO_VERBATIM, + ...EVERYTHING_BUT_VERBATIM + ] + }; + const SPACE_GOBBLER = { + begin: /\s+/, + relevance: 0 + }; + const ARGUMENT_M = [ ARGUMENT_BRACES ]; + const ARGUMENT_O = [ ARGUMENT_BRACKETS ]; + const ARGUMENT_AND_THEN = function(arg, starts_mode) { + return { + contains: [ SPACE_GOBBLER ], + starts: { + relevance: 0, + contains: arg, + starts: starts_mode + } + }; + }; + const CSNAME = function(csname, starts_mode) { + return { + begin: '\\\\' + csname + '(?![a-zA-Z@:_])', + keywords: { + $pattern: /\\[a-zA-Z]+/, + keyword: '\\' + csname + }, + relevance: 0, + contains: [ SPACE_GOBBLER ], + starts: starts_mode + }; + }; + const BEGIN_ENV = function(envname, starts_mode) { + return hljs.inherit( + { + begin: '\\\\begin(?=[ \t]*(\\r?\\n[ \t]*)?\\{' + envname + '\\})', + keywords: { + $pattern: /\\[a-zA-Z]+/, + keyword: '\\begin' + }, + relevance: 0, + }, + ARGUMENT_AND_THEN(ARGUMENT_M, starts_mode) + ); + }; + const VERBATIM_DELIMITED_EQUAL = (innerName = "string") => { + return hljs.END_SAME_AS_BEGIN({ + className: innerName, + begin: /(.|\r?\n)/, + end: /(.|\r?\n)/, + excludeBegin: true, + excludeEnd: true, + endsParent: true + }); + }; + const VERBATIM_DELIMITED_ENV = function(envname) { + return { + className: 'string', + end: '(?=\\\\end\\{' + envname + '\\})' + }; + }; + + const VERBATIM_DELIMITED_BRACES = (innerName = "string") => { + return { + relevance: 0, + begin: /\{/, + starts: { + endsParent: true, + contains: [ + { + className: innerName, + end: /(?=\})/, + endsParent: true, + contains: [ + { + begin: /\{/, + end: /\}/, + relevance: 0, + contains: [ "self" ] + } + ], + } + ] + } + }; + }; + const VERBATIM = [ + ...[ + 'verb', + 'lstinline' + ].map(csname => CSNAME(csname, { contains: [ VERBATIM_DELIMITED_EQUAL() ] })), + CSNAME('mint', ARGUMENT_AND_THEN(ARGUMENT_M, { contains: [ VERBATIM_DELIMITED_EQUAL() ] })), + CSNAME('mintinline', ARGUMENT_AND_THEN(ARGUMENT_M, { contains: [ + VERBATIM_DELIMITED_BRACES(), + VERBATIM_DELIMITED_EQUAL() + ] })), + CSNAME('url', { contains: [ + VERBATIM_DELIMITED_BRACES("link"), + VERBATIM_DELIMITED_BRACES("link") + ] }), + CSNAME('hyperref', { contains: [ VERBATIM_DELIMITED_BRACES("link") ] }), + CSNAME('href', ARGUMENT_AND_THEN(ARGUMENT_O, { contains: [ VERBATIM_DELIMITED_BRACES("link") ] })), + ...[].concat(...[ + '', + '\\*' + ].map(suffix => [ + BEGIN_ENV('verbatim' + suffix, VERBATIM_DELIMITED_ENV('verbatim' + suffix)), + BEGIN_ENV('filecontents' + suffix, ARGUMENT_AND_THEN(ARGUMENT_M, VERBATIM_DELIMITED_ENV('filecontents' + suffix))), + ...[ + '', + 'B', + 'L' + ].map(prefix => + BEGIN_ENV(prefix + 'Verbatim' + suffix, ARGUMENT_AND_THEN(ARGUMENT_O, VERBATIM_DELIMITED_ENV(prefix + 'Verbatim' + suffix))) + ) + ])), + BEGIN_ENV('minted', ARGUMENT_AND_THEN(ARGUMENT_O, ARGUMENT_AND_THEN(ARGUMENT_M, VERBATIM_DELIMITED_ENV('minted')))), + ]; + + return { + name: 'LaTeX', + aliases: [ 'tex' ], + contains: [ + ...VERBATIM, + ...EVERYTHING_BUT_VERBATIM + ] + }; + } + + return latex; + +})(); + + hljs.registerLanguage('latex', hljsGrammar); + })();/*! `lisp` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Lisp + Description: Generic lisp syntax + Author: Vasily Polovnyov + Category: lisp + */ + + function lisp(hljs) { + const LISP_IDENT_RE = '[a-zA-Z_\\-+\\*\\/<=>&#][a-zA-Z0-9_\\-+*\\/<=>&#!]*'; + const MEC_RE = '\\|[^]*?\\|'; + const LISP_SIMPLE_NUMBER_RE = '(-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s|D|E|F|L|S)(\\+|-)?\\d+)?'; + const LITERAL = { + className: 'literal', + begin: '\\b(t{1}|nil)\\b' + }; + const NUMBER = { + className: 'number', + variants: [ + { + begin: LISP_SIMPLE_NUMBER_RE, + relevance: 0 + }, + { begin: '#(b|B)[0-1]+(/[0-1]+)?' }, + { begin: '#(o|O)[0-7]+(/[0-7]+)?' }, + { begin: '#(x|X)[0-9a-fA-F]+(/[0-9a-fA-F]+)?' }, + { + begin: '#(c|C)\\(' + LISP_SIMPLE_NUMBER_RE + ' +' + LISP_SIMPLE_NUMBER_RE, + end: '\\)' + } + ] + }; + const STRING = hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }); + const COMMENT = hljs.COMMENT( + ';', '$', + { relevance: 0 } + ); + const VARIABLE = { + begin: '\\*', + end: '\\*' + }; + const KEYWORD = { + className: 'symbol', + begin: '[:&]' + LISP_IDENT_RE + }; + const IDENT = { + begin: LISP_IDENT_RE, + relevance: 0 + }; + const MEC = { begin: MEC_RE }; + const QUOTED_LIST = { + begin: '\\(', + end: '\\)', + contains: [ + 'self', + LITERAL, + STRING, + NUMBER, + IDENT + ] + }; + const QUOTED = { + contains: [ + NUMBER, + STRING, + VARIABLE, + KEYWORD, + QUOTED_LIST, + IDENT + ], + variants: [ + { + begin: '[\'`]\\(', + end: '\\)' + }, + { + begin: '\\(quote ', + end: '\\)', + keywords: { name: 'quote' } + }, + { begin: '\'' + MEC_RE } + ] + }; + const QUOTED_ATOM = { variants: [ + { begin: '\'' + LISP_IDENT_RE }, + { begin: '#\'' + LISP_IDENT_RE + '(::' + LISP_IDENT_RE + ')*' } + ] }; + const LIST = { + begin: '\\(\\s*', + end: '\\)' + }; + const BODY = { + endsWithParent: true, + relevance: 0 + }; + LIST.contains = [ + { + className: 'name', + variants: [ + { + begin: LISP_IDENT_RE, + relevance: 0, + }, + { begin: MEC_RE } + ] + }, + BODY + ]; + BODY.contains = [ + QUOTED, + QUOTED_ATOM, + LIST, + LITERAL, + NUMBER, + STRING, + COMMENT, + VARIABLE, + KEYWORD, + MEC, + IDENT + ]; + + return { + name: 'Lisp', + illegal: /\S/, + contains: [ + NUMBER, + hljs.SHEBANG(), + LITERAL, + STRING, + COMMENT, + QUOTED, + QUOTED_ATOM, + LIST, + IDENT + ] + }; + } + + return lisp; + +})(); + + hljs.registerLanguage('lisp', hljsGrammar); + })();/*! `llvm` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: LLVM IR + Author: Michael Rodler + Description: language used as intermediate representation in the LLVM compiler framework + Website: https://llvm.org/docs/LangRef.html + Category: assembler + Audit: 2020 + */ + + /** @type LanguageFn */ + function llvm(hljs) { + const regex = hljs.regex; + const IDENT_RE = /([-a-zA-Z$._][\w$.-]*)/; + const TYPE = { + className: 'type', + begin: /\bi\d+(?=\s|\b)/ + }; + const OPERATOR = { + className: 'operator', + relevance: 0, + begin: /=/ + }; + const PUNCTUATION = { + className: 'punctuation', + relevance: 0, + begin: /,/ + }; + const NUMBER = { + className: 'number', + variants: [ + { begin: /[su]?0[xX][KMLHR]?[a-fA-F0-9]+/ }, + { begin: /[-+]?\d+(?:[.]\d+)?(?:[eE][-+]?\d+(?:[.]\d+)?)?/ } + ], + relevance: 0 + }; + const LABEL = { + className: 'symbol', + variants: [ { begin: /^\s*[a-z]+:/ }, // labels + ], + relevance: 0 + }; + const VARIABLE = { + className: 'variable', + variants: [ + { begin: regex.concat(/%/, IDENT_RE) }, + { begin: /%\d+/ }, + { begin: /#\d+/ }, + ] + }; + const FUNCTION = { + className: 'title', + variants: [ + { begin: regex.concat(/@/, IDENT_RE) }, + { begin: /@\d+/ }, + { begin: regex.concat(/!/, IDENT_RE) }, + { begin: regex.concat(/!\d+/, IDENT_RE) }, + // https://llvm.org/docs/LangRef.html#namedmetadatastructure + // obviously a single digit can also be used in this fashion + { begin: /!\d+/ } + ] + }; + + return { + name: 'LLVM IR', + // TODO: split into different categories of keywords + keywords: + 'begin end true false declare define global ' + + 'constant private linker_private internal ' + + 'available_externally linkonce linkonce_odr weak ' + + 'weak_odr appending dllimport dllexport common ' + + 'default hidden protected extern_weak external ' + + 'thread_local zeroinitializer undef null to tail ' + + 'target triple datalayout volatile nuw nsw nnan ' + + 'ninf nsz arcp fast exact inbounds align ' + + 'addrspace section alias module asm sideeffect ' + + 'gc dbg linker_private_weak attributes blockaddress ' + + 'initialexec localdynamic localexec prefix unnamed_addr ' + + 'ccc fastcc coldcc x86_stdcallcc x86_fastcallcc ' + + 'arm_apcscc arm_aapcscc arm_aapcs_vfpcc ptx_device ' + + 'ptx_kernel intel_ocl_bicc msp430_intrcc spir_func ' + + 'spir_kernel x86_64_sysvcc x86_64_win64cc x86_thiscallcc ' + + 'cc c signext zeroext inreg sret nounwind ' + + 'noreturn noalias nocapture byval nest readnone ' + + 'readonly inlinehint noinline alwaysinline optsize ssp ' + + 'sspreq noredzone noimplicitfloat naked builtin cold ' + + 'nobuiltin noduplicate nonlazybind optnone returns_twice ' + + 'sanitize_address sanitize_memory sanitize_thread sspstrong ' + + 'uwtable returned type opaque eq ne slt sgt ' + + 'sle sge ult ugt ule uge oeq one olt ogt ' + + 'ole oge ord uno ueq une x acq_rel acquire ' + + 'alignstack atomic catch cleanup filter inteldialect ' + + 'max min monotonic nand personality release seq_cst ' + + 'singlethread umax umin unordered xchg add fadd ' + + 'sub fsub mul fmul udiv sdiv fdiv urem srem ' + + 'frem shl lshr ashr and or xor icmp fcmp ' + + 'phi call trunc zext sext fptrunc fpext uitofp ' + + 'sitofp fptoui fptosi inttoptr ptrtoint bitcast ' + + 'addrspacecast select va_arg ret br switch invoke ' + + 'unwind unreachable indirectbr landingpad resume ' + + 'malloc alloca free load store getelementptr ' + + 'extractelement insertelement shufflevector getresult ' + + 'extractvalue insertvalue atomicrmw cmpxchg fence ' + + 'argmemonly double', + contains: [ + TYPE, + // this matches "empty comments"... + // ...because it's far more likely this is a statement terminator in + // another language than an actual comment + hljs.COMMENT(/;\s*$/, null, { relevance: 0 }), + hljs.COMMENT(/;/, /$/), + { + className: 'string', + begin: /"/, + end: /"/, + contains: [ + { + className: 'char.escape', + match: /\\\d\d/ + } + ] + }, + FUNCTION, + PUNCTUATION, + OPERATOR, + VARIABLE, + LABEL, + NUMBER + ] + }; + } + + return llvm; + +})(); + + hljs.registerLanguage('llvm', hljsGrammar); + })();/*! `lua` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Lua + Description: Lua is a powerful, efficient, lightweight, embeddable scripting language. + Author: Andrew Fedorov + Category: common, gaming, scripting + Website: https://www.lua.org + */ + + function lua(hljs) { + const OPENING_LONG_BRACKET = '\\[=*\\['; + const CLOSING_LONG_BRACKET = '\\]=*\\]'; + const LONG_BRACKETS = { + begin: OPENING_LONG_BRACKET, + end: CLOSING_LONG_BRACKET, + contains: [ 'self' ] + }; + const COMMENTS = [ + hljs.COMMENT('--(?!' + OPENING_LONG_BRACKET + ')', '$'), + hljs.COMMENT( + '--' + OPENING_LONG_BRACKET, + CLOSING_LONG_BRACKET, + { + contains: [ LONG_BRACKETS ], + relevance: 10 + } + ) + ]; + return { + name: 'Lua', + keywords: { + $pattern: hljs.UNDERSCORE_IDENT_RE, + literal: "true false nil", + keyword: "and break do else elseif end for goto if in local not or repeat return then until while", + built_in: + // Metatags and globals: + '_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len ' + + '__gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert ' + // Standard methods and properties: + + 'collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring ' + + 'module next pairs pcall print rawequal rawget rawset require select setfenv ' + + 'setmetatable tonumber tostring type unpack xpcall arg self ' + // Library methods and properties (one line per library): + + 'coroutine resume yield status wrap create running debug getupvalue ' + + 'debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv ' + + 'io lines write close flush open output type read stderr stdin input stdout popen tmpfile ' + + 'math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan ' + + 'os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall ' + + 'string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower ' + + 'table setn insert getn foreachi maxn foreach concat sort remove' + }, + contains: COMMENTS.concat([ + { + className: 'function', + beginKeywords: 'function', + end: '\\)', + contains: [ + hljs.inherit(hljs.TITLE_MODE, { begin: '([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*' }), + { + className: 'params', + begin: '\\(', + endsWithParent: true, + contains: COMMENTS + } + ].concat(COMMENTS) + }, + hljs.C_NUMBER_MODE, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + { + className: 'string', + begin: OPENING_LONG_BRACKET, + end: CLOSING_LONG_BRACKET, + contains: [ LONG_BRACKETS ], + relevance: 5 + } + ]) + }; + } + + return lua; + +})(); + + hljs.registerLanguage('lua', hljsGrammar); + })();/*! `makefile` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Makefile + Author: Ivan Sagalaev + Contributors: Joël Porquet + Website: https://www.gnu.org/software/make/manual/html_node/Introduction.html + Category: common, build-system + */ + + function makefile(hljs) { + /* Variables: simple (eg $(var)) and special (eg $@) */ + const VARIABLE = { + className: 'variable', + variants: [ + { + begin: '\\$\\(' + hljs.UNDERSCORE_IDENT_RE + '\\)', + contains: [ hljs.BACKSLASH_ESCAPE ] + }, + { begin: /\$[@% + Website: https://daringfireball.net/projects/markdown/ + Category: common, markup + */ + + function markdown(hljs) { + const regex = hljs.regex; + const INLINE_HTML = { + begin: /<\/?[A-Za-z_]/, + end: '>', + subLanguage: 'xml', + relevance: 0 + }; + const HORIZONTAL_RULE = { + begin: '^[-\\*]{3,}', + end: '$' + }; + const CODE = { + className: 'code', + variants: [ + // TODO: fix to allow these to work with sublanguage also + { begin: '(`{3,})[^`](.|\\n)*?\\1`*[ ]*' }, + { begin: '(~{3,})[^~](.|\\n)*?\\1~*[ ]*' }, + // needed to allow markdown as a sublanguage to work + { + begin: '```', + end: '```+[ ]*$' + }, + { + begin: '~~~', + end: '~~~+[ ]*$' + }, + { begin: '`.+?`' }, + { + begin: '(?=^( {4}|\\t))', + // use contains to gobble up multiple lines to allow the block to be whatever size + // but only have a single open/close tag vs one per line + contains: [ + { + begin: '^( {4}|\\t)', + end: '(\\n)$' + } + ], + relevance: 0 + } + ] + }; + const LIST = { + className: 'bullet', + begin: '^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)', + end: '\\s+', + excludeEnd: true + }; + const LINK_REFERENCE = { + begin: /^\[[^\n]+\]:/, + returnBegin: true, + contains: [ + { + className: 'symbol', + begin: /\[/, + end: /\]/, + excludeBegin: true, + excludeEnd: true + }, + { + className: 'link', + begin: /:\s*/, + end: /$/, + excludeBegin: true + } + ] + }; + const URL_SCHEME = /[A-Za-z][A-Za-z0-9+.-]*/; + const LINK = { + variants: [ + // too much like nested array access in so many languages + // to have any real relevance + { + begin: /\[.+?\]\[.*?\]/, + relevance: 0 + }, + // popular internet URLs + { + begin: /\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, + relevance: 2 + }, + { + begin: regex.concat(/\[.+?\]\(/, URL_SCHEME, /:\/\/.*?\)/), + relevance: 2 + }, + // relative urls + { + begin: /\[.+?\]\([./?&#].*?\)/, + relevance: 1 + }, + // whatever else, lower relevance (might not be a link at all) + { + begin: /\[.*?\]\(.*?\)/, + relevance: 0 + } + ], + returnBegin: true, + contains: [ + { + // empty strings for alt or link text + match: /\[(?=\])/ }, + { + className: 'string', + relevance: 0, + begin: '\\[', + end: '\\]', + excludeBegin: true, + returnEnd: true + }, + { + className: 'link', + relevance: 0, + begin: '\\]\\(', + end: '\\)', + excludeBegin: true, + excludeEnd: true + }, + { + className: 'symbol', + relevance: 0, + begin: '\\]\\[', + end: '\\]', + excludeBegin: true, + excludeEnd: true + } + ] + }; + const BOLD = { + className: 'strong', + contains: [], // defined later + variants: [ + { + begin: /_{2}(?!\s)/, + end: /_{2}/ + }, + { + begin: /\*{2}(?!\s)/, + end: /\*{2}/ + } + ] + }; + const ITALIC = { + className: 'emphasis', + contains: [], // defined later + variants: [ + { + begin: /\*(?![*\s])/, + end: /\*/ + }, + { + begin: /_(?![_\s])/, + end: /_/, + relevance: 0 + } + ] + }; + + // 3 level deep nesting is not allowed because it would create confusion + // in cases like `***testing***` because where we don't know if the last + // `***` is starting a new bold/italic or finishing the last one + const BOLD_WITHOUT_ITALIC = hljs.inherit(BOLD, { contains: [] }); + const ITALIC_WITHOUT_BOLD = hljs.inherit(ITALIC, { contains: [] }); + BOLD.contains.push(ITALIC_WITHOUT_BOLD); + ITALIC.contains.push(BOLD_WITHOUT_ITALIC); + + let CONTAINABLE = [ + INLINE_HTML, + LINK + ]; + + [ + BOLD, + ITALIC, + BOLD_WITHOUT_ITALIC, + ITALIC_WITHOUT_BOLD + ].forEach(m => { + m.contains = m.contains.concat(CONTAINABLE); + }); + + CONTAINABLE = CONTAINABLE.concat(BOLD, ITALIC); + + const HEADER = { + className: 'section', + variants: [ + { + begin: '^#{1,6}', + end: '$', + contains: CONTAINABLE + }, + { + begin: '(?=^.+?\\n[=-]{2,}$)', + contains: [ + { begin: '^[=-]*$' }, + { + begin: '^', + end: "\\n", + contains: CONTAINABLE + } + ] + } + ] + }; + + const BLOCKQUOTE = { + className: 'quote', + begin: '^>\\s+', + contains: CONTAINABLE, + end: '$' + }; + + return { + name: 'Markdown', + aliases: [ + 'md', + 'mkdown', + 'mkd' + ], + contains: [ + HEADER, + INLINE_HTML, + LIST, + BOLD, + ITALIC, + BLOCKQUOTE, + CODE, + HORIZONTAL_RULE, + LINK, + LINK_REFERENCE + ] + }; + } + + return markdown; + +})(); + + hljs.registerLanguage('markdown', hljsGrammar); + })();/*! `matlab` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Matlab + Author: Denis Bardadym + Contributors: Eugene Nizhibitsky , Egor Rogov + Website: https://www.mathworks.com/products/matlab.html + Category: scientific + */ + + /* + Formal syntax is not published, helpful link: + https://github.com/kornilova-l/matlab-IntelliJ-plugin/blob/master/src/main/grammar/Matlab.bnf + */ + function matlab(hljs) { + const TRANSPOSE_RE = '(\'|\\.\')+'; + const TRANSPOSE = { + relevance: 0, + contains: [ { begin: TRANSPOSE_RE } ] + }; + + return { + name: 'Matlab', + keywords: { + keyword: + 'arguments break case catch classdef continue else elseif end enumeration events for function ' + + 'global if methods otherwise parfor persistent properties return spmd switch try while', + built_in: + 'sin sind sinh asin asind asinh cos cosd cosh acos acosd acosh tan tand tanh atan ' + + 'atand atan2 atanh sec secd sech asec asecd asech csc cscd csch acsc acscd acsch cot ' + + 'cotd coth acot acotd acoth hypot exp expm1 log log1p log10 log2 pow2 realpow reallog ' + + 'realsqrt sqrt nthroot nextpow2 abs angle complex conj imag real unwrap isreal ' + + 'cplxpair fix floor ceil round mod rem sign airy besselj bessely besselh besseli ' + + 'besselk beta betainc betaln ellipj ellipke erf erfc erfcx erfinv expint gamma ' + + 'gammainc gammaln psi legendre cross dot factor isprime primes gcd lcm rat rats perms ' + + 'nchoosek factorial cart2sph cart2pol pol2cart sph2cart hsv2rgb rgb2hsv zeros ones ' + + 'eye repmat rand randn linspace logspace freqspace meshgrid accumarray size length ' + + 'ndims numel disp isempty isequal isequalwithequalnans cat reshape diag blkdiag tril ' + + 'triu fliplr flipud flipdim rot90 find sub2ind ind2sub bsxfun ndgrid permute ipermute ' + + 'shiftdim circshift squeeze isscalar isvector ans eps realmax realmin pi i|0 inf nan ' + + 'isnan isinf isfinite j|0 why compan gallery hadamard hankel hilb invhilb magic pascal ' + + 'rosser toeplitz vander wilkinson max min nanmax nanmin mean nanmean type table ' + + 'readtable writetable sortrows sort figure plot plot3 scatter scatter3 cellfun ' + + 'legend intersect ismember procrustes hold num2cell ' + }, + illegal: '(//|"|#|/\\*|\\s+/\\w+)', + contains: [ + { + className: 'function', + beginKeywords: 'function', + end: '$', + contains: [ + hljs.UNDERSCORE_TITLE_MODE, + { + className: 'params', + variants: [ + { + begin: '\\(', + end: '\\)' + }, + { + begin: '\\[', + end: '\\]' + } + ] + } + ] + }, + { + className: 'built_in', + begin: /true|false/, + relevance: 0, + starts: TRANSPOSE + }, + { + begin: '[a-zA-Z][a-zA-Z_0-9]*' + TRANSPOSE_RE, + relevance: 0 + }, + { + className: 'number', + begin: hljs.C_NUMBER_RE, + relevance: 0, + starts: TRANSPOSE + }, + { + className: 'string', + begin: '\'', + end: '\'', + contains: [ { begin: '\'\'' } ] + }, + { + begin: /\]|\}|\)/, + relevance: 0, + starts: TRANSPOSE + }, + { + className: 'string', + begin: '"', + end: '"', + contains: [ { begin: '""' } ], + starts: TRANSPOSE + }, + hljs.COMMENT('^\\s*%\\{\\s*$', '^\\s*%\\}\\s*$'), + hljs.COMMENT('%', '$') + ] + }; + } + + return matlab; + +})(); + + hljs.registerLanguage('matlab', hljsGrammar); + })();/*! `nginx` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Nginx config + Author: Peter Leonov + Contributors: Ivan Sagalaev + Category: config, web + Website: https://www.nginx.com + */ + + /** @type LanguageFn */ + function nginx(hljs) { + const regex = hljs.regex; + const VAR = { + className: 'variable', + variants: [ + { begin: /\$\d+/ }, + { begin: /\$\{\w+\}/ }, + { begin: regex.concat(/[$@]/, hljs.UNDERSCORE_IDENT_RE) } + ] + }; + const LITERALS = [ + "on", + "off", + "yes", + "no", + "true", + "false", + "none", + "blocked", + "debug", + "info", + "notice", + "warn", + "error", + "crit", + "select", + "break", + "last", + "permanent", + "redirect", + "kqueue", + "rtsig", + "epoll", + "poll", + "/dev/poll" + ]; + const DEFAULT = { + endsWithParent: true, + keywords: { + $pattern: /[a-z_]{2,}|\/dev\/poll/, + literal: LITERALS + }, + relevance: 0, + illegal: '=>', + contains: [ + hljs.HASH_COMMENT_MODE, + { + className: 'string', + contains: [ + hljs.BACKSLASH_ESCAPE, + VAR + ], + variants: [ + { + begin: /"/, + end: /"/ + }, + { + begin: /'/, + end: /'/ + } + ] + }, + // this swallows entire URLs to avoid detecting numbers within + { + begin: '([a-z]+):/', + end: '\\s', + endsWithParent: true, + excludeEnd: true, + contains: [ VAR ] + }, + { + className: 'regexp', + contains: [ + hljs.BACKSLASH_ESCAPE, + VAR + ], + variants: [ + { + begin: "\\s\\^", + end: "\\s|\\{|;", + returnEnd: true + }, + // regexp locations (~, ~*) + { + begin: "~\\*?\\s+", + end: "\\s|\\{|;", + returnEnd: true + }, + // *.example.com + { begin: "\\*(\\.[a-z\\-]+)+" }, + // sub.example.* + { begin: "([a-z\\-]+\\.)+\\*" } + ] + }, + // IP + { + className: 'number', + begin: '\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b' + }, + // units + { + className: 'number', + begin: '\\b\\d+[kKmMgGdshdwy]?\\b', + relevance: 0 + }, + VAR + ] + }; + + return { + name: 'Nginx config', + aliases: [ 'nginxconf' ], + contains: [ + hljs.HASH_COMMENT_MODE, + { + beginKeywords: "upstream location", + end: /;|\{/, + contains: DEFAULT.contains, + keywords: { section: "upstream location" } + }, + { + className: 'section', + begin: regex.concat(hljs.UNDERSCORE_IDENT_RE + regex.lookahead(/\s+\{/)), + relevance: 0 + }, + { + begin: regex.lookahead(hljs.UNDERSCORE_IDENT_RE + '\\s'), + end: ';|\\{', + contains: [ + { + className: 'attribute', + begin: hljs.UNDERSCORE_IDENT_RE, + starts: DEFAULT + } + ], + relevance: 0 + } + ], + illegal: '[^\\s\\}\\{]' + }; + } + + return nginx; + +})(); + + hljs.registerLanguage('nginx', hljsGrammar); + })();/*! `nim` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Nim + Description: Nim is a statically typed compiled systems programming language. + Website: https://nim-lang.org + Category: system + */ + + function nim(hljs) { + const TYPES = [ + "int", + "int8", + "int16", + "int32", + "int64", + "uint", + "uint8", + "uint16", + "uint32", + "uint64", + "float", + "float32", + "float64", + "bool", + "char", + "string", + "cstring", + "pointer", + "expr", + "stmt", + "void", + "auto", + "any", + "range", + "array", + "openarray", + "varargs", + "seq", + "set", + "clong", + "culong", + "cchar", + "cschar", + "cshort", + "cint", + "csize", + "clonglong", + "cfloat", + "cdouble", + "clongdouble", + "cuchar", + "cushort", + "cuint", + "culonglong", + "cstringarray", + "semistatic" + ]; + const KEYWORDS = [ + "addr", + "and", + "as", + "asm", + "bind", + "block", + "break", + "case", + "cast", + "const", + "continue", + "converter", + "discard", + "distinct", + "div", + "do", + "elif", + "else", + "end", + "enum", + "except", + "export", + "finally", + "for", + "from", + "func", + "generic", + "guarded", + "if", + "import", + "in", + "include", + "interface", + "is", + "isnot", + "iterator", + "let", + "macro", + "method", + "mixin", + "mod", + "nil", + "not", + "notin", + "object", + "of", + "or", + "out", + "proc", + "ptr", + "raise", + "ref", + "return", + "shared", + "shl", + "shr", + "static", + "template", + "try", + "tuple", + "type", + "using", + "var", + "when", + "while", + "with", + "without", + "xor", + "yield" + ]; + const BUILT_INS = [ + "stdin", + "stdout", + "stderr", + "result" + ]; + const LITERALS = [ + "true", + "false" + ]; + return { + name: 'Nim', + keywords: { + keyword: KEYWORDS, + literal: LITERALS, + type: TYPES, + built_in: BUILT_INS + }, + contains: [ + { + className: 'meta', // Actually pragma + begin: /\{\./, + end: /\.\}/, + relevance: 10 + }, + { + className: 'string', + begin: /[a-zA-Z]\w*"/, + end: /"/, + contains: [ { begin: /""/ } ] + }, + { + className: 'string', + begin: /([a-zA-Z]\w*)?"""/, + end: /"""/ + }, + hljs.QUOTE_STRING_MODE, + { + className: 'type', + begin: /\b[A-Z]\w+\b/, + relevance: 0 + }, + { + className: 'number', + relevance: 0, + variants: [ + { begin: /\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)('?[iIuU](8|16|32|64))?/ }, + { begin: /\b(0o[0-7][_0-7]*)('?[iIuUfF](8|16|32|64))?/ }, + { begin: /\b(0(b|B)[01][_01]*)('?[iIuUfF](8|16|32|64))?/ }, + { begin: /\b(\d[_\d]*)('?[iIuUfF](8|16|32|64))?/ } + ] + }, + hljs.HASH_COMMENT_MODE + ] + }; + } + + return nim; + +})(); + + hljs.registerLanguage('nim', hljsGrammar); + })();/*! `objectivec` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Objective-C + Author: Valerii Hiora + Contributors: Angel G. Olloqui , Matt Diephouse , Andrew Farmer , Minh Nguyễn + Website: https://developer.apple.com/documentation/objectivec + Category: common + */ + + function objectivec(hljs) { + const API_CLASS = { + className: 'built_in', + begin: '\\b(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)\\w+' + }; + const IDENTIFIER_RE = /[a-zA-Z@][a-zA-Z0-9_]*/; + const TYPES = [ + "int", + "float", + "char", + "unsigned", + "signed", + "short", + "long", + "double", + "wchar_t", + "unichar", + "void", + "bool", + "BOOL", + "id|0", + "_Bool" + ]; + const KWS = [ + "while", + "export", + "sizeof", + "typedef", + "const", + "struct", + "for", + "union", + "volatile", + "static", + "mutable", + "if", + "do", + "return", + "goto", + "enum", + "else", + "break", + "extern", + "asm", + "case", + "default", + "register", + "explicit", + "typename", + "switch", + "continue", + "inline", + "readonly", + "assign", + "readwrite", + "self", + "@synchronized", + "id", + "typeof", + "nonatomic", + "IBOutlet", + "IBAction", + "strong", + "weak", + "copy", + "in", + "out", + "inout", + "bycopy", + "byref", + "oneway", + "__strong", + "__weak", + "__block", + "__autoreleasing", + "@private", + "@protected", + "@public", + "@try", + "@property", + "@end", + "@throw", + "@catch", + "@finally", + "@autoreleasepool", + "@synthesize", + "@dynamic", + "@selector", + "@optional", + "@required", + "@encode", + "@package", + "@import", + "@defs", + "@compatibility_alias", + "__bridge", + "__bridge_transfer", + "__bridge_retained", + "__bridge_retain", + "__covariant", + "__contravariant", + "__kindof", + "_Nonnull", + "_Nullable", + "_Null_unspecified", + "__FUNCTION__", + "__PRETTY_FUNCTION__", + "__attribute__", + "getter", + "setter", + "retain", + "unsafe_unretained", + "nonnull", + "nullable", + "null_unspecified", + "null_resettable", + "class", + "instancetype", + "NS_DESIGNATED_INITIALIZER", + "NS_UNAVAILABLE", + "NS_REQUIRES_SUPER", + "NS_RETURNS_INNER_POINTER", + "NS_INLINE", + "NS_AVAILABLE", + "NS_DEPRECATED", + "NS_ENUM", + "NS_OPTIONS", + "NS_SWIFT_UNAVAILABLE", + "NS_ASSUME_NONNULL_BEGIN", + "NS_ASSUME_NONNULL_END", + "NS_REFINED_FOR_SWIFT", + "NS_SWIFT_NAME", + "NS_SWIFT_NOTHROW", + "NS_DURING", + "NS_HANDLER", + "NS_ENDHANDLER", + "NS_VALUERETURN", + "NS_VOIDRETURN" + ]; + const LITERALS = [ + "false", + "true", + "FALSE", + "TRUE", + "nil", + "YES", + "NO", + "NULL" + ]; + const BUILT_INS = [ + "dispatch_once_t", + "dispatch_queue_t", + "dispatch_sync", + "dispatch_async", + "dispatch_once" + ]; + const KEYWORDS = { + "variable.language": [ + "this", + "super" + ], + $pattern: IDENTIFIER_RE, + keyword: KWS, + literal: LITERALS, + built_in: BUILT_INS, + type: TYPES + }; + const CLASS_KEYWORDS = { + $pattern: IDENTIFIER_RE, + keyword: [ + "@interface", + "@class", + "@protocol", + "@implementation" + ] + }; + return { + name: 'Objective-C', + aliases: [ + 'mm', + 'objc', + 'obj-c', + 'obj-c++', + 'objective-c++' + ], + keywords: KEYWORDS, + illegal: '/, + end: /$/, + illegal: '\\n' + }, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE + ] + }, + { + className: 'class', + begin: '(' + CLASS_KEYWORDS.keyword.join('|') + ')\\b', + end: /(\{|$)/, + excludeEnd: true, + keywords: CLASS_KEYWORDS, + contains: [ hljs.UNDERSCORE_TITLE_MODE ] + }, + { + begin: '\\.' + hljs.UNDERSCORE_IDENT_RE, + relevance: 0 + } + ] + }; + } + + return objectivec; + +})(); + + hljs.registerLanguage('objectivec', hljsGrammar); + })();/*! `ocaml` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: OCaml + Author: Mehdi Dogguy + Contributors: Nicolas Braud-Santoni , Mickael Delahaye + Description: OCaml language definition. + Website: https://ocaml.org + Category: functional + */ + + function ocaml(hljs) { + /* missing support for heredoc-like string (OCaml 4.0.2+) */ + return { + name: 'OCaml', + aliases: [ 'ml' ], + keywords: { + $pattern: '[a-z_]\\w*!?', + keyword: + 'and as assert asr begin class constraint do done downto else end ' + + 'exception external for fun function functor if in include ' + + 'inherit! inherit initializer land lazy let lor lsl lsr lxor match method!|10 method ' + + 'mod module mutable new object of open! open or private rec sig struct ' + + 'then to try type val! val virtual when while with ' + /* camlp4 */ + + 'parser value', + built_in: + /* built-in types */ + 'array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 string unit ' + /* (some) types in Pervasives */ + + 'in_channel out_channel ref', + literal: + 'true false' + }, + illegal: /\/\/|>>/, + contains: [ + { + className: 'literal', + begin: '\\[(\\|\\|)?\\]|\\(\\)', + relevance: 0 + }, + hljs.COMMENT( + '\\(\\*', + '\\*\\)', + { contains: [ 'self' ] } + ), + { /* type variable */ + className: 'symbol', + begin: '\'[A-Za-z_](?!\')[\\w\']*' + /* the grammar is ambiguous on how 'a'b should be interpreted but not the compiler */ + }, + { /* polymorphic variant */ + className: 'type', + begin: '`[A-Z][\\w\']*' + }, + { /* module or constructor */ + className: 'type', + begin: '\\b[A-Z][\\w\']*', + relevance: 0 + }, + { /* don't color identifiers, but safely catch all identifiers with ' */ + begin: '[a-z_]\\w*\'[\\w\']*', + relevance: 0 + }, + hljs.inherit(hljs.APOS_STRING_MODE, { + className: 'string', + relevance: 0 + }), + hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }), + { + className: 'number', + begin: + '\\b(0[xX][a-fA-F0-9_]+[Lln]?|' + + '0[oO][0-7_]+[Lln]?|' + + '0[bB][01_]+[Lln]?|' + + '[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)', + relevance: 0 + }, + { begin: /->/ // relevance booster + } + ] + }; + } + + return ocaml; + +})(); + + hljs.registerLanguage('ocaml', hljsGrammar); + })();/*! `pgsql` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: PostgreSQL and PL/pgSQL + Author: Egor Rogov (e.rogov@postgrespro.ru) + Website: https://www.postgresql.org/docs/11/sql.html + Description: + This language incorporates both PostgreSQL SQL dialect and PL/pgSQL language. + It is based on PostgreSQL version 11. Some notes: + - Text in double-dollar-strings is _always_ interpreted as some programming code. Text + in ordinary quotes is _never_ interpreted that way and highlighted just as a string. + - There are quite a bit "special cases". That's because many keywords are not strictly + they are keywords in some contexts and ordinary identifiers in others. Only some + of such cases are handled; you still can get some of your identifiers highlighted + wrong way. + - Function names deliberately are not highlighted. There is no way to tell function + call from other constructs, hence we can't highlight _all_ function names. And + some names highlighted while others not looks ugly. + Category: database + */ + + function pgsql(hljs) { + const COMMENT_MODE = hljs.COMMENT('--', '$'); + const UNQUOTED_IDENT = '[a-zA-Z_][a-zA-Z_0-9$]*'; + const DOLLAR_STRING = '\\$([a-zA-Z_]?|[a-zA-Z_][a-zA-Z_0-9]*)\\$'; + const LABEL = '<<\\s*' + UNQUOTED_IDENT + '\\s*>>'; + + const SQL_KW = + // https://www.postgresql.org/docs/11/static/sql-keywords-appendix.html + // https://www.postgresql.org/docs/11/static/sql-commands.html + // SQL commands (starting words) + 'ABORT ALTER ANALYZE BEGIN CALL CHECKPOINT|10 CLOSE CLUSTER COMMENT COMMIT COPY CREATE DEALLOCATE DECLARE ' + + 'DELETE DISCARD DO DROP END EXECUTE EXPLAIN FETCH GRANT IMPORT INSERT LISTEN LOAD LOCK MOVE NOTIFY ' + + 'PREPARE REASSIGN|10 REFRESH REINDEX RELEASE RESET REVOKE ROLLBACK SAVEPOINT SECURITY SELECT SET SHOW ' + + 'START TRUNCATE UNLISTEN|10 UPDATE VACUUM|10 VALUES ' + // SQL commands (others) + + 'AGGREGATE COLLATION CONVERSION|10 DATABASE DEFAULT PRIVILEGES DOMAIN TRIGGER EXTENSION FOREIGN ' + + 'WRAPPER|10 TABLE FUNCTION GROUP LANGUAGE LARGE OBJECT MATERIALIZED VIEW OPERATOR CLASS ' + + 'FAMILY POLICY PUBLICATION|10 ROLE RULE SCHEMA SEQUENCE SERVER STATISTICS SUBSCRIPTION SYSTEM ' + + 'TABLESPACE CONFIGURATION DICTIONARY PARSER TEMPLATE TYPE USER MAPPING PREPARED ACCESS ' + + 'METHOD CAST AS TRANSFORM TRANSACTION OWNED TO INTO SESSION AUTHORIZATION ' + + 'INDEX PROCEDURE ASSERTION ' + // additional reserved key words + + 'ALL ANALYSE AND ANY ARRAY ASC ASYMMETRIC|10 BOTH CASE CHECK ' + + 'COLLATE COLUMN CONCURRENTLY|10 CONSTRAINT CROSS ' + + 'DEFERRABLE RANGE ' + + 'DESC DISTINCT ELSE EXCEPT FOR FREEZE|10 FROM FULL HAVING ' + + 'ILIKE IN INITIALLY INNER INTERSECT IS ISNULL JOIN LATERAL LEADING LIKE LIMIT ' + + 'NATURAL NOT NOTNULL NULL OFFSET ON ONLY OR ORDER OUTER OVERLAPS PLACING PRIMARY ' + + 'REFERENCES RETURNING SIMILAR SOME SYMMETRIC TABLESAMPLE THEN ' + + 'TRAILING UNION UNIQUE USING VARIADIC|10 VERBOSE WHEN WHERE WINDOW WITH ' + // some of non-reserved (which are used in clauses or as PL/pgSQL keyword) + + 'BY RETURNS INOUT OUT SETOF|10 IF STRICT CURRENT CONTINUE OWNER LOCATION OVER PARTITION WITHIN ' + + 'BETWEEN ESCAPE EXTERNAL INVOKER DEFINER WORK RENAME VERSION CONNECTION CONNECT ' + + 'TABLES TEMP TEMPORARY FUNCTIONS SEQUENCES TYPES SCHEMAS OPTION CASCADE RESTRICT ADD ADMIN ' + + 'EXISTS VALID VALIDATE ENABLE DISABLE REPLICA|10 ALWAYS PASSING COLUMNS PATH ' + + 'REF VALUE OVERRIDING IMMUTABLE STABLE VOLATILE BEFORE AFTER EACH ROW PROCEDURAL ' + + 'ROUTINE NO HANDLER VALIDATOR OPTIONS STORAGE OIDS|10 WITHOUT INHERIT DEPENDS CALLED ' + + 'INPUT LEAKPROOF|10 COST ROWS NOWAIT SEARCH UNTIL ENCRYPTED|10 PASSWORD CONFLICT|10 ' + + 'INSTEAD INHERITS CHARACTERISTICS WRITE CURSOR ALSO STATEMENT SHARE EXCLUSIVE INLINE ' + + 'ISOLATION REPEATABLE READ COMMITTED SERIALIZABLE UNCOMMITTED LOCAL GLOBAL SQL PROCEDURES ' + + 'RECURSIVE SNAPSHOT ROLLUP CUBE TRUSTED|10 INCLUDE FOLLOWING PRECEDING UNBOUNDED RANGE GROUPS ' + + 'UNENCRYPTED|10 SYSID FORMAT DELIMITER HEADER QUOTE ENCODING FILTER OFF ' + // some parameters of VACUUM/ANALYZE/EXPLAIN + + 'FORCE_QUOTE FORCE_NOT_NULL FORCE_NULL COSTS BUFFERS TIMING SUMMARY DISABLE_PAGE_SKIPPING ' + // + + 'RESTART CYCLE GENERATED IDENTITY DEFERRED IMMEDIATE LEVEL LOGGED UNLOGGED ' + + 'OF NOTHING NONE EXCLUDE ATTRIBUTE ' + // from GRANT (not keywords actually) + + 'USAGE ROUTINES ' + // actually literals, but look better this way (due to IS TRUE, IS FALSE, ISNULL etc) + + 'TRUE FALSE NAN INFINITY '; + + const ROLE_ATTRS = // only those not in keywrods already + 'SUPERUSER NOSUPERUSER CREATEDB NOCREATEDB CREATEROLE NOCREATEROLE INHERIT NOINHERIT ' + + 'LOGIN NOLOGIN REPLICATION NOREPLICATION BYPASSRLS NOBYPASSRLS '; + + const PLPGSQL_KW = + 'ALIAS BEGIN CONSTANT DECLARE END EXCEPTION RETURN PERFORM|10 RAISE GET DIAGNOSTICS ' + + 'STACKED|10 FOREACH LOOP ELSIF EXIT WHILE REVERSE SLICE DEBUG LOG INFO NOTICE WARNING ASSERT ' + + 'OPEN '; + + const TYPES = + // https://www.postgresql.org/docs/11/static/datatype.html + 'BIGINT INT8 BIGSERIAL SERIAL8 BIT VARYING VARBIT BOOLEAN BOOL BOX BYTEA CHARACTER CHAR VARCHAR ' + + 'CIDR CIRCLE DATE DOUBLE PRECISION FLOAT8 FLOAT INET INTEGER INT INT4 INTERVAL JSON JSONB LINE LSEG|10 ' + + 'MACADDR MACADDR8 MONEY NUMERIC DEC DECIMAL PATH POINT POLYGON REAL FLOAT4 SMALLINT INT2 ' + + 'SMALLSERIAL|10 SERIAL2|10 SERIAL|10 SERIAL4|10 TEXT TIME ZONE TIMETZ|10 TIMESTAMP TIMESTAMPTZ|10 TSQUERY|10 TSVECTOR|10 ' + + 'TXID_SNAPSHOT|10 UUID XML NATIONAL NCHAR ' + + 'INT4RANGE|10 INT8RANGE|10 NUMRANGE|10 TSRANGE|10 TSTZRANGE|10 DATERANGE|10 ' + // pseudotypes + + 'ANYELEMENT ANYARRAY ANYNONARRAY ANYENUM ANYRANGE CSTRING INTERNAL ' + + 'RECORD PG_DDL_COMMAND VOID UNKNOWN OPAQUE REFCURSOR ' + // spec. type + + 'NAME ' + // OID-types + + 'OID REGPROC|10 REGPROCEDURE|10 REGOPER|10 REGOPERATOR|10 REGCLASS|10 REGTYPE|10 REGROLE|10 ' + + 'REGNAMESPACE|10 REGCONFIG|10 REGDICTIONARY|10 ';// + + + const TYPES_RE = + TYPES.trim() + .split(' ') + .map(function(val) { return val.split('|')[0]; }) + .join('|'); + + const SQL_BI = + 'CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURRENT_CATALOG|10 CURRENT_DATE LOCALTIME LOCALTIMESTAMP ' + + 'CURRENT_ROLE|10 CURRENT_SCHEMA|10 SESSION_USER PUBLIC '; + + const PLPGSQL_BI = + 'FOUND NEW OLD TG_NAME|10 TG_WHEN|10 TG_LEVEL|10 TG_OP|10 TG_RELID|10 TG_RELNAME|10 ' + + 'TG_TABLE_NAME|10 TG_TABLE_SCHEMA|10 TG_NARGS|10 TG_ARGV|10 TG_EVENT|10 TG_TAG|10 ' + // get diagnostics + + 'ROW_COUNT RESULT_OID|10 PG_CONTEXT|10 RETURNED_SQLSTATE COLUMN_NAME CONSTRAINT_NAME ' + + 'PG_DATATYPE_NAME|10 MESSAGE_TEXT TABLE_NAME SCHEMA_NAME PG_EXCEPTION_DETAIL|10 ' + + 'PG_EXCEPTION_HINT|10 PG_EXCEPTION_CONTEXT|10 '; + + const PLPGSQL_EXCEPTIONS = + // exceptions https://www.postgresql.org/docs/current/static/errcodes-appendix.html + 'SQLSTATE SQLERRM|10 ' + + 'SUCCESSFUL_COMPLETION WARNING DYNAMIC_RESULT_SETS_RETURNED IMPLICIT_ZERO_BIT_PADDING ' + + 'NULL_VALUE_ELIMINATED_IN_SET_FUNCTION PRIVILEGE_NOT_GRANTED PRIVILEGE_NOT_REVOKED ' + + 'STRING_DATA_RIGHT_TRUNCATION DEPRECATED_FEATURE NO_DATA NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED ' + + 'SQL_STATEMENT_NOT_YET_COMPLETE CONNECTION_EXCEPTION CONNECTION_DOES_NOT_EXIST CONNECTION_FAILURE ' + + 'SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION ' + + 'TRANSACTION_RESOLUTION_UNKNOWN PROTOCOL_VIOLATION TRIGGERED_ACTION_EXCEPTION FEATURE_NOT_SUPPORTED ' + + 'INVALID_TRANSACTION_INITIATION LOCATOR_EXCEPTION INVALID_LOCATOR_SPECIFICATION INVALID_GRANTOR ' + + 'INVALID_GRANT_OPERATION INVALID_ROLE_SPECIFICATION DIAGNOSTICS_EXCEPTION ' + + 'STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER CASE_NOT_FOUND CARDINALITY_VIOLATION ' + + 'DATA_EXCEPTION ARRAY_SUBSCRIPT_ERROR CHARACTER_NOT_IN_REPERTOIRE DATETIME_FIELD_OVERFLOW ' + + 'DIVISION_BY_ZERO ERROR_IN_ASSIGNMENT ESCAPE_CHARACTER_CONFLICT INDICATOR_OVERFLOW ' + + 'INTERVAL_FIELD_OVERFLOW INVALID_ARGUMENT_FOR_LOGARITHM INVALID_ARGUMENT_FOR_NTILE_FUNCTION ' + + 'INVALID_ARGUMENT_FOR_NTH_VALUE_FUNCTION INVALID_ARGUMENT_FOR_POWER_FUNCTION ' + + 'INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION INVALID_CHARACTER_VALUE_FOR_CAST ' + + 'INVALID_DATETIME_FORMAT INVALID_ESCAPE_CHARACTER INVALID_ESCAPE_OCTET INVALID_ESCAPE_SEQUENCE ' + + 'NONSTANDARD_USE_OF_ESCAPE_CHARACTER INVALID_INDICATOR_PARAMETER_VALUE INVALID_PARAMETER_VALUE ' + + 'INVALID_REGULAR_EXPRESSION INVALID_ROW_COUNT_IN_LIMIT_CLAUSE ' + + 'INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE INVALID_TABLESAMPLE_ARGUMENT INVALID_TABLESAMPLE_REPEAT ' + + 'INVALID_TIME_ZONE_DISPLACEMENT_VALUE INVALID_USE_OF_ESCAPE_CHARACTER MOST_SPECIFIC_TYPE_MISMATCH ' + + 'NULL_VALUE_NOT_ALLOWED NULL_VALUE_NO_INDICATOR_PARAMETER NUMERIC_VALUE_OUT_OF_RANGE ' + + 'SEQUENCE_GENERATOR_LIMIT_EXCEEDED STRING_DATA_LENGTH_MISMATCH STRING_DATA_RIGHT_TRUNCATION ' + + 'SUBSTRING_ERROR TRIM_ERROR UNTERMINATED_C_STRING ZERO_LENGTH_CHARACTER_STRING ' + + 'FLOATING_POINT_EXCEPTION INVALID_TEXT_REPRESENTATION INVALID_BINARY_REPRESENTATION ' + + 'BAD_COPY_FILE_FORMAT UNTRANSLATABLE_CHARACTER NOT_AN_XML_DOCUMENT INVALID_XML_DOCUMENT ' + + 'INVALID_XML_CONTENT INVALID_XML_COMMENT INVALID_XML_PROCESSING_INSTRUCTION ' + + 'INTEGRITY_CONSTRAINT_VIOLATION RESTRICT_VIOLATION NOT_NULL_VIOLATION FOREIGN_KEY_VIOLATION ' + + 'UNIQUE_VIOLATION CHECK_VIOLATION EXCLUSION_VIOLATION INVALID_CURSOR_STATE ' + + 'INVALID_TRANSACTION_STATE ACTIVE_SQL_TRANSACTION BRANCH_TRANSACTION_ALREADY_ACTIVE ' + + 'HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION ' + + 'INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION ' + + 'NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION READ_ONLY_SQL_TRANSACTION ' + + 'SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED NO_ACTIVE_SQL_TRANSACTION ' + + 'IN_FAILED_SQL_TRANSACTION IDLE_IN_TRANSACTION_SESSION_TIMEOUT INVALID_SQL_STATEMENT_NAME ' + + 'TRIGGERED_DATA_CHANGE_VIOLATION INVALID_AUTHORIZATION_SPECIFICATION INVALID_PASSWORD ' + + 'DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST DEPENDENT_OBJECTS_STILL_EXIST ' + + 'INVALID_TRANSACTION_TERMINATION SQL_ROUTINE_EXCEPTION FUNCTION_EXECUTED_NO_RETURN_STATEMENT ' + + 'MODIFYING_SQL_DATA_NOT_PERMITTED PROHIBITED_SQL_STATEMENT_ATTEMPTED ' + + 'READING_SQL_DATA_NOT_PERMITTED INVALID_CURSOR_NAME EXTERNAL_ROUTINE_EXCEPTION ' + + 'CONTAINING_SQL_NOT_PERMITTED MODIFYING_SQL_DATA_NOT_PERMITTED ' + + 'PROHIBITED_SQL_STATEMENT_ATTEMPTED READING_SQL_DATA_NOT_PERMITTED ' + + 'EXTERNAL_ROUTINE_INVOCATION_EXCEPTION INVALID_SQLSTATE_RETURNED NULL_VALUE_NOT_ALLOWED ' + + 'TRIGGER_PROTOCOL_VIOLATED SRF_PROTOCOL_VIOLATED EVENT_TRIGGER_PROTOCOL_VIOLATED ' + + 'SAVEPOINT_EXCEPTION INVALID_SAVEPOINT_SPECIFICATION INVALID_CATALOG_NAME ' + + 'INVALID_SCHEMA_NAME TRANSACTION_ROLLBACK TRANSACTION_INTEGRITY_CONSTRAINT_VIOLATION ' + + 'SERIALIZATION_FAILURE STATEMENT_COMPLETION_UNKNOWN DEADLOCK_DETECTED ' + + 'SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION SYNTAX_ERROR INSUFFICIENT_PRIVILEGE CANNOT_COERCE ' + + 'GROUPING_ERROR WINDOWING_ERROR INVALID_RECURSION INVALID_FOREIGN_KEY INVALID_NAME ' + + 'NAME_TOO_LONG RESERVED_NAME DATATYPE_MISMATCH INDETERMINATE_DATATYPE COLLATION_MISMATCH ' + + 'INDETERMINATE_COLLATION WRONG_OBJECT_TYPE GENERATED_ALWAYS UNDEFINED_COLUMN ' + + 'UNDEFINED_FUNCTION UNDEFINED_TABLE UNDEFINED_PARAMETER UNDEFINED_OBJECT ' + + 'DUPLICATE_COLUMN DUPLICATE_CURSOR DUPLICATE_DATABASE DUPLICATE_FUNCTION ' + + 'DUPLICATE_PREPARED_STATEMENT DUPLICATE_SCHEMA DUPLICATE_TABLE DUPLICATE_ALIAS ' + + 'DUPLICATE_OBJECT AMBIGUOUS_COLUMN AMBIGUOUS_FUNCTION AMBIGUOUS_PARAMETER AMBIGUOUS_ALIAS ' + + 'INVALID_COLUMN_REFERENCE INVALID_COLUMN_DEFINITION INVALID_CURSOR_DEFINITION ' + + 'INVALID_DATABASE_DEFINITION INVALID_FUNCTION_DEFINITION ' + + 'INVALID_PREPARED_STATEMENT_DEFINITION INVALID_SCHEMA_DEFINITION INVALID_TABLE_DEFINITION ' + + 'INVALID_OBJECT_DEFINITION WITH_CHECK_OPTION_VIOLATION INSUFFICIENT_RESOURCES DISK_FULL ' + + 'OUT_OF_MEMORY TOO_MANY_CONNECTIONS CONFIGURATION_LIMIT_EXCEEDED PROGRAM_LIMIT_EXCEEDED ' + + 'STATEMENT_TOO_COMPLEX TOO_MANY_COLUMNS TOO_MANY_ARGUMENTS OBJECT_NOT_IN_PREREQUISITE_STATE ' + + 'OBJECT_IN_USE CANT_CHANGE_RUNTIME_PARAM LOCK_NOT_AVAILABLE OPERATOR_INTERVENTION ' + + 'QUERY_CANCELED ADMIN_SHUTDOWN CRASH_SHUTDOWN CANNOT_CONNECT_NOW DATABASE_DROPPED ' + + 'SYSTEM_ERROR IO_ERROR UNDEFINED_FILE DUPLICATE_FILE SNAPSHOT_TOO_OLD CONFIG_FILE_ERROR ' + + 'LOCK_FILE_EXISTS FDW_ERROR FDW_COLUMN_NAME_NOT_FOUND FDW_DYNAMIC_PARAMETER_VALUE_NEEDED ' + + 'FDW_FUNCTION_SEQUENCE_ERROR FDW_INCONSISTENT_DESCRIPTOR_INFORMATION ' + + 'FDW_INVALID_ATTRIBUTE_VALUE FDW_INVALID_COLUMN_NAME FDW_INVALID_COLUMN_NUMBER ' + + 'FDW_INVALID_DATA_TYPE FDW_INVALID_DATA_TYPE_DESCRIPTORS ' + + 'FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER FDW_INVALID_HANDLE FDW_INVALID_OPTION_INDEX ' + + 'FDW_INVALID_OPTION_NAME FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH ' + + 'FDW_INVALID_STRING_FORMAT FDW_INVALID_USE_OF_NULL_POINTER FDW_TOO_MANY_HANDLES ' + + 'FDW_OUT_OF_MEMORY FDW_NO_SCHEMAS FDW_OPTION_NAME_NOT_FOUND FDW_REPLY_HANDLE ' + + 'FDW_SCHEMA_NOT_FOUND FDW_TABLE_NOT_FOUND FDW_UNABLE_TO_CREATE_EXECUTION ' + + 'FDW_UNABLE_TO_CREATE_REPLY FDW_UNABLE_TO_ESTABLISH_CONNECTION PLPGSQL_ERROR ' + + 'RAISE_EXCEPTION NO_DATA_FOUND TOO_MANY_ROWS ASSERT_FAILURE INTERNAL_ERROR DATA_CORRUPTED ' + + 'INDEX_CORRUPTED '; + + const FUNCTIONS = + // https://www.postgresql.org/docs/11/static/functions-aggregate.html + 'ARRAY_AGG AVG BIT_AND BIT_OR BOOL_AND BOOL_OR COUNT EVERY JSON_AGG JSONB_AGG JSON_OBJECT_AGG ' + + 'JSONB_OBJECT_AGG MAX MIN MODE STRING_AGG SUM XMLAGG ' + + 'CORR COVAR_POP COVAR_SAMP REGR_AVGX REGR_AVGY REGR_COUNT REGR_INTERCEPT REGR_R2 REGR_SLOPE ' + + 'REGR_SXX REGR_SXY REGR_SYY STDDEV STDDEV_POP STDDEV_SAMP VARIANCE VAR_POP VAR_SAMP ' + + 'PERCENTILE_CONT PERCENTILE_DISC ' + // https://www.postgresql.org/docs/11/static/functions-window.html + + 'ROW_NUMBER RANK DENSE_RANK PERCENT_RANK CUME_DIST NTILE LAG LEAD FIRST_VALUE LAST_VALUE NTH_VALUE ' + // https://www.postgresql.org/docs/11/static/functions-comparison.html + + 'NUM_NONNULLS NUM_NULLS ' + // https://www.postgresql.org/docs/11/static/functions-math.html + + 'ABS CBRT CEIL CEILING DEGREES DIV EXP FLOOR LN LOG MOD PI POWER RADIANS ROUND SCALE SIGN SQRT ' + + 'TRUNC WIDTH_BUCKET ' + + 'RANDOM SETSEED ' + + 'ACOS ACOSD ASIN ASIND ATAN ATAND ATAN2 ATAN2D COS COSD COT COTD SIN SIND TAN TAND ' + // https://www.postgresql.org/docs/11/static/functions-string.html + + 'BIT_LENGTH CHAR_LENGTH CHARACTER_LENGTH LOWER OCTET_LENGTH OVERLAY POSITION SUBSTRING TREAT TRIM UPPER ' + + 'ASCII BTRIM CHR CONCAT CONCAT_WS CONVERT CONVERT_FROM CONVERT_TO DECODE ENCODE INITCAP ' + + 'LEFT LENGTH LPAD LTRIM MD5 PARSE_IDENT PG_CLIENT_ENCODING QUOTE_IDENT|10 QUOTE_LITERAL|10 ' + + 'QUOTE_NULLABLE|10 REGEXP_MATCH REGEXP_MATCHES REGEXP_REPLACE REGEXP_SPLIT_TO_ARRAY ' + + 'REGEXP_SPLIT_TO_TABLE REPEAT REPLACE REVERSE RIGHT RPAD RTRIM SPLIT_PART STRPOS SUBSTR ' + + 'TO_ASCII TO_HEX TRANSLATE ' + // https://www.postgresql.org/docs/11/static/functions-binarystring.html + + 'OCTET_LENGTH GET_BIT GET_BYTE SET_BIT SET_BYTE ' + // https://www.postgresql.org/docs/11/static/functions-formatting.html + + 'TO_CHAR TO_DATE TO_NUMBER TO_TIMESTAMP ' + // https://www.postgresql.org/docs/11/static/functions-datetime.html + + 'AGE CLOCK_TIMESTAMP|10 DATE_PART DATE_TRUNC ISFINITE JUSTIFY_DAYS JUSTIFY_HOURS JUSTIFY_INTERVAL ' + + 'MAKE_DATE MAKE_INTERVAL|10 MAKE_TIME MAKE_TIMESTAMP|10 MAKE_TIMESTAMPTZ|10 NOW STATEMENT_TIMESTAMP|10 ' + + 'TIMEOFDAY TRANSACTION_TIMESTAMP|10 ' + // https://www.postgresql.org/docs/11/static/functions-enum.html + + 'ENUM_FIRST ENUM_LAST ENUM_RANGE ' + // https://www.postgresql.org/docs/11/static/functions-geometry.html + + 'AREA CENTER DIAMETER HEIGHT ISCLOSED ISOPEN NPOINTS PCLOSE POPEN RADIUS WIDTH ' + + 'BOX BOUND_BOX CIRCLE LINE LSEG PATH POLYGON ' + // https://www.postgresql.org/docs/11/static/functions-net.html + + 'ABBREV BROADCAST HOST HOSTMASK MASKLEN NETMASK NETWORK SET_MASKLEN TEXT INET_SAME_FAMILY ' + + 'INET_MERGE MACADDR8_SET7BIT ' + // https://www.postgresql.org/docs/11/static/functions-textsearch.html + + 'ARRAY_TO_TSVECTOR GET_CURRENT_TS_CONFIG NUMNODE PLAINTO_TSQUERY PHRASETO_TSQUERY WEBSEARCH_TO_TSQUERY ' + + 'QUERYTREE SETWEIGHT STRIP TO_TSQUERY TO_TSVECTOR JSON_TO_TSVECTOR JSONB_TO_TSVECTOR TS_DELETE ' + + 'TS_FILTER TS_HEADLINE TS_RANK TS_RANK_CD TS_REWRITE TSQUERY_PHRASE TSVECTOR_TO_ARRAY ' + + 'TSVECTOR_UPDATE_TRIGGER TSVECTOR_UPDATE_TRIGGER_COLUMN ' + // https://www.postgresql.org/docs/11/static/functions-xml.html + + 'XMLCOMMENT XMLCONCAT XMLELEMENT XMLFOREST XMLPI XMLROOT ' + + 'XMLEXISTS XML_IS_WELL_FORMED XML_IS_WELL_FORMED_DOCUMENT XML_IS_WELL_FORMED_CONTENT ' + + 'XPATH XPATH_EXISTS XMLTABLE XMLNAMESPACES ' + + 'TABLE_TO_XML TABLE_TO_XMLSCHEMA TABLE_TO_XML_AND_XMLSCHEMA ' + + 'QUERY_TO_XML QUERY_TO_XMLSCHEMA QUERY_TO_XML_AND_XMLSCHEMA ' + + 'CURSOR_TO_XML CURSOR_TO_XMLSCHEMA ' + + 'SCHEMA_TO_XML SCHEMA_TO_XMLSCHEMA SCHEMA_TO_XML_AND_XMLSCHEMA ' + + 'DATABASE_TO_XML DATABASE_TO_XMLSCHEMA DATABASE_TO_XML_AND_XMLSCHEMA ' + + 'XMLATTRIBUTES ' + // https://www.postgresql.org/docs/11/static/functions-json.html + + 'TO_JSON TO_JSONB ARRAY_TO_JSON ROW_TO_JSON JSON_BUILD_ARRAY JSONB_BUILD_ARRAY JSON_BUILD_OBJECT ' + + 'JSONB_BUILD_OBJECT JSON_OBJECT JSONB_OBJECT JSON_ARRAY_LENGTH JSONB_ARRAY_LENGTH JSON_EACH ' + + 'JSONB_EACH JSON_EACH_TEXT JSONB_EACH_TEXT JSON_EXTRACT_PATH JSONB_EXTRACT_PATH ' + + 'JSON_OBJECT_KEYS JSONB_OBJECT_KEYS JSON_POPULATE_RECORD JSONB_POPULATE_RECORD JSON_POPULATE_RECORDSET ' + + 'JSONB_POPULATE_RECORDSET JSON_ARRAY_ELEMENTS JSONB_ARRAY_ELEMENTS JSON_ARRAY_ELEMENTS_TEXT ' + + 'JSONB_ARRAY_ELEMENTS_TEXT JSON_TYPEOF JSONB_TYPEOF JSON_TO_RECORD JSONB_TO_RECORD JSON_TO_RECORDSET ' + + 'JSONB_TO_RECORDSET JSON_STRIP_NULLS JSONB_STRIP_NULLS JSONB_SET JSONB_INSERT JSONB_PRETTY ' + // https://www.postgresql.org/docs/11/static/functions-sequence.html + + 'CURRVAL LASTVAL NEXTVAL SETVAL ' + // https://www.postgresql.org/docs/11/static/functions-conditional.html + + 'COALESCE NULLIF GREATEST LEAST ' + // https://www.postgresql.org/docs/11/static/functions-array.html + + 'ARRAY_APPEND ARRAY_CAT ARRAY_NDIMS ARRAY_DIMS ARRAY_FILL ARRAY_LENGTH ARRAY_LOWER ARRAY_POSITION ' + + 'ARRAY_POSITIONS ARRAY_PREPEND ARRAY_REMOVE ARRAY_REPLACE ARRAY_TO_STRING ARRAY_UPPER CARDINALITY ' + + 'STRING_TO_ARRAY UNNEST ' + // https://www.postgresql.org/docs/11/static/functions-range.html + + 'ISEMPTY LOWER_INC UPPER_INC LOWER_INF UPPER_INF RANGE_MERGE ' + // https://www.postgresql.org/docs/11/static/functions-srf.html + + 'GENERATE_SERIES GENERATE_SUBSCRIPTS ' + // https://www.postgresql.org/docs/11/static/functions-info.html + + 'CURRENT_DATABASE CURRENT_QUERY CURRENT_SCHEMA|10 CURRENT_SCHEMAS|10 INET_CLIENT_ADDR INET_CLIENT_PORT ' + + 'INET_SERVER_ADDR INET_SERVER_PORT ROW_SECURITY_ACTIVE FORMAT_TYPE ' + + 'TO_REGCLASS TO_REGPROC TO_REGPROCEDURE TO_REGOPER TO_REGOPERATOR TO_REGTYPE TO_REGNAMESPACE TO_REGROLE ' + + 'COL_DESCRIPTION OBJ_DESCRIPTION SHOBJ_DESCRIPTION ' + + 'TXID_CURRENT TXID_CURRENT_IF_ASSIGNED TXID_CURRENT_SNAPSHOT TXID_SNAPSHOT_XIP TXID_SNAPSHOT_XMAX ' + + 'TXID_SNAPSHOT_XMIN TXID_VISIBLE_IN_SNAPSHOT TXID_STATUS ' + // https://www.postgresql.org/docs/11/static/functions-admin.html + + 'CURRENT_SETTING SET_CONFIG BRIN_SUMMARIZE_NEW_VALUES BRIN_SUMMARIZE_RANGE BRIN_DESUMMARIZE_RANGE ' + + 'GIN_CLEAN_PENDING_LIST ' + // https://www.postgresql.org/docs/11/static/functions-trigger.html + + 'SUPPRESS_REDUNDANT_UPDATES_TRIGGER ' + // ihttps://www.postgresql.org/docs/devel/static/lo-funcs.html + + 'LO_FROM_BYTEA LO_PUT LO_GET LO_CREAT LO_CREATE LO_UNLINK LO_IMPORT LO_EXPORT LOREAD LOWRITE ' + // + + 'GROUPING CAST '; + + const FUNCTIONS_RE = + FUNCTIONS.trim() + .split(' ') + .map(function(val) { return val.split('|')[0]; }) + .join('|'); + + return { + name: 'PostgreSQL', + aliases: [ + 'postgres', + 'postgresql' + ], + supersetOf: "sql", + case_insensitive: true, + keywords: { + keyword: + SQL_KW + PLPGSQL_KW + ROLE_ATTRS, + built_in: + SQL_BI + PLPGSQL_BI + PLPGSQL_EXCEPTIONS + }, + // Forbid some cunstructs from other languages to improve autodetect. In fact + // "[a-z]:" is legal (as part of array slice), but improbabal. + illegal: /:==|\W\s*\(\*|(^|\s)\$[a-z]|\{\{|[a-z]:\s*$|\.\.\.|TO:|DO:/, + contains: [ + // special handling of some words, which are reserved only in some contexts + { + className: 'keyword', + variants: [ + { begin: /\bTEXT\s*SEARCH\b/ }, + { begin: /\b(PRIMARY|FOREIGN|FOR(\s+NO)?)\s+KEY\b/ }, + { begin: /\bPARALLEL\s+(UNSAFE|RESTRICTED|SAFE)\b/ }, + { begin: /\bSTORAGE\s+(PLAIN|EXTERNAL|EXTENDED|MAIN)\b/ }, + { begin: /\bMATCH\s+(FULL|PARTIAL|SIMPLE)\b/ }, + { begin: /\bNULLS\s+(FIRST|LAST)\b/ }, + { begin: /\bEVENT\s+TRIGGER\b/ }, + { begin: /\b(MAPPING|OR)\s+REPLACE\b/ }, + { begin: /\b(FROM|TO)\s+(PROGRAM|STDIN|STDOUT)\b/ }, + { begin: /\b(SHARE|EXCLUSIVE)\s+MODE\b/ }, + { begin: /\b(LEFT|RIGHT)\s+(OUTER\s+)?JOIN\b/ }, + { begin: /\b(FETCH|MOVE)\s+(NEXT|PRIOR|FIRST|LAST|ABSOLUTE|RELATIVE|FORWARD|BACKWARD)\b/ }, + { begin: /\bPRESERVE\s+ROWS\b/ }, + { begin: /\bDISCARD\s+PLANS\b/ }, + { begin: /\bREFERENCING\s+(OLD|NEW)\b/ }, + { begin: /\bSKIP\s+LOCKED\b/ }, + { begin: /\bGROUPING\s+SETS\b/ }, + { begin: /\b(BINARY|INSENSITIVE|SCROLL|NO\s+SCROLL)\s+(CURSOR|FOR)\b/ }, + { begin: /\b(WITH|WITHOUT)\s+HOLD\b/ }, + { begin: /\bWITH\s+(CASCADED|LOCAL)\s+CHECK\s+OPTION\b/ }, + { begin: /\bEXCLUDE\s+(TIES|NO\s+OTHERS)\b/ }, + { begin: /\bFORMAT\s+(TEXT|XML|JSON|YAML)\b/ }, + { begin: /\bSET\s+((SESSION|LOCAL)\s+)?NAMES\b/ }, + { begin: /\bIS\s+(NOT\s+)?UNKNOWN\b/ }, + { begin: /\bSECURITY\s+LABEL\b/ }, + { begin: /\bSTANDALONE\s+(YES|NO|NO\s+VALUE)\b/ }, + { begin: /\bWITH\s+(NO\s+)?DATA\b/ }, + { begin: /\b(FOREIGN|SET)\s+DATA\b/ }, + { begin: /\bSET\s+(CATALOG|CONSTRAINTS)\b/ }, + { begin: /\b(WITH|FOR)\s+ORDINALITY\b/ }, + { begin: /\bIS\s+(NOT\s+)?DOCUMENT\b/ }, + { begin: /\bXML\s+OPTION\s+(DOCUMENT|CONTENT)\b/ }, + { begin: /\b(STRIP|PRESERVE)\s+WHITESPACE\b/ }, + { begin: /\bNO\s+(ACTION|MAXVALUE|MINVALUE)\b/ }, + { begin: /\bPARTITION\s+BY\s+(RANGE|LIST|HASH)\b/ }, + { begin: /\bAT\s+TIME\s+ZONE\b/ }, + { begin: /\bGRANTED\s+BY\b/ }, + { begin: /\bRETURN\s+(QUERY|NEXT)\b/ }, + { begin: /\b(ATTACH|DETACH)\s+PARTITION\b/ }, + { begin: /\bFORCE\s+ROW\s+LEVEL\s+SECURITY\b/ }, + { begin: /\b(INCLUDING|EXCLUDING)\s+(COMMENTS|CONSTRAINTS|DEFAULTS|IDENTITY|INDEXES|STATISTICS|STORAGE|ALL)\b/ }, + { begin: /\bAS\s+(ASSIGNMENT|IMPLICIT|PERMISSIVE|RESTRICTIVE|ENUM|RANGE)\b/ } + ] + }, + // functions named as keywords, followed by '(' + { begin: /\b(FORMAT|FAMILY|VERSION)\s*\(/ + // keywords: { built_in: 'FORMAT FAMILY VERSION' } + }, + // INCLUDE ( ... ) in index_parameters in CREATE TABLE + { + begin: /\bINCLUDE\s*\(/, + keywords: 'INCLUDE' + }, + // not highlight RANGE if not in frame_clause (not 100% correct, but seems satisfactory) + { begin: /\bRANGE(?!\s*(BETWEEN|UNBOUNDED|CURRENT|[-0-9]+))/ }, + // disable highlighting in commands CREATE AGGREGATE/COLLATION/DATABASE/OPERTOR/TEXT SEARCH .../TYPE + // and in PL/pgSQL RAISE ... USING + { begin: /\b(VERSION|OWNER|TEMPLATE|TABLESPACE|CONNECTION\s+LIMIT|PROCEDURE|RESTRICT|JOIN|PARSER|COPY|START|END|COLLATION|INPUT|ANALYZE|STORAGE|LIKE|DEFAULT|DELIMITER|ENCODING|COLUMN|CONSTRAINT|TABLE|SCHEMA)\s*=/ }, + // PG_smth; HAS_some_PRIVILEGE + { + // className: 'built_in', + begin: /\b(PG_\w+?|HAS_[A-Z_]+_PRIVILEGE)\b/, + relevance: 10 + }, + // extract + { + begin: /\bEXTRACT\s*\(/, + end: /\bFROM\b/, + returnEnd: true, + keywords: { + // built_in: 'EXTRACT', + type: 'CENTURY DAY DECADE DOW DOY EPOCH HOUR ISODOW ISOYEAR MICROSECONDS ' + + 'MILLENNIUM MILLISECONDS MINUTE MONTH QUARTER SECOND TIMEZONE TIMEZONE_HOUR ' + + 'TIMEZONE_MINUTE WEEK YEAR' } + }, + // xmlelement, xmlpi - special NAME + { + begin: /\b(XMLELEMENT|XMLPI)\s*\(\s*NAME/, + keywords: { + // built_in: 'XMLELEMENT XMLPI', + keyword: 'NAME' } + }, + // xmlparse, xmlserialize + { + begin: /\b(XMLPARSE|XMLSERIALIZE)\s*\(\s*(DOCUMENT|CONTENT)/, + keywords: { + // built_in: 'XMLPARSE XMLSERIALIZE', + keyword: 'DOCUMENT CONTENT' } + }, + // Sequences. We actually skip everything between CACHE|INCREMENT|MAXVALUE|MINVALUE and + // nearest following numeric constant. Without with trick we find a lot of "keywords" + // in 'avrasm' autodetection test... + { + beginKeywords: 'CACHE INCREMENT MAXVALUE MINVALUE', + end: hljs.C_NUMBER_RE, + returnEnd: true, + keywords: 'BY CACHE INCREMENT MAXVALUE MINVALUE' + }, + // WITH|WITHOUT TIME ZONE as part of datatype + { + className: 'type', + begin: /\b(WITH|WITHOUT)\s+TIME\s+ZONE\b/ + }, + // INTERVAL optional fields + { + className: 'type', + begin: /\bINTERVAL\s+(YEAR|MONTH|DAY|HOUR|MINUTE|SECOND)(\s+TO\s+(MONTH|HOUR|MINUTE|SECOND))?\b/ + }, + // Pseudo-types which allowed only as return type + { + begin: /\bRETURNS\s+(LANGUAGE_HANDLER|TRIGGER|EVENT_TRIGGER|FDW_HANDLER|INDEX_AM_HANDLER|TSM_HANDLER)\b/, + keywords: { + keyword: 'RETURNS', + type: 'LANGUAGE_HANDLER TRIGGER EVENT_TRIGGER FDW_HANDLER INDEX_AM_HANDLER TSM_HANDLER' + } + }, + // Known functions - only when followed by '(' + { begin: '\\b(' + FUNCTIONS_RE + ')\\s*\\(' + // keywords: { built_in: FUNCTIONS } + }, + // Types + { begin: '\\.(' + TYPES_RE + ')\\b' // prevent highlight as type, say, 'oid' in 'pgclass.oid' + }, + { + begin: '\\b(' + TYPES_RE + ')\\s+PATH\\b', // in XMLTABLE + keywords: { + keyword: 'PATH', // hopefully no one would use PATH type in XMLTABLE... + type: TYPES.replace('PATH ', '') + } + }, + { + className: 'type', + begin: '\\b(' + TYPES_RE + ')\\b' + }, + // Strings, see https://www.postgresql.org/docs/11/static/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS + { + className: 'string', + begin: '\'', + end: '\'', + contains: [ { begin: '\'\'' } ] + }, + { + className: 'string', + begin: '(e|E|u&|U&)\'', + end: '\'', + contains: [ { begin: '\\\\.' } ], + relevance: 10 + }, + hljs.END_SAME_AS_BEGIN({ + begin: DOLLAR_STRING, + end: DOLLAR_STRING, + contains: [ + { + // actually we want them all except SQL; listed are those with known implementations + // and XML + JSON just in case + subLanguage: [ + 'pgsql', + 'perl', + 'python', + 'tcl', + 'r', + 'lua', + 'java', + 'php', + 'ruby', + 'bash', + 'scheme', + 'xml', + 'json' + ], + endsWithParent: true + } + ] + }), + // identifiers in quotes + { + begin: '"', + end: '"', + contains: [ { begin: '""' } ] + }, + // numbers + hljs.C_NUMBER_MODE, + // comments + hljs.C_BLOCK_COMMENT_MODE, + COMMENT_MODE, + // PL/pgSQL staff + // %ROWTYPE, %TYPE, $n + { + className: 'meta', + variants: [ + { // %TYPE, %ROWTYPE + begin: '%(ROW)?TYPE', + relevance: 10 + }, + { // $n + begin: '\\$\\d+' }, + { // #compiler option + begin: '^#\\w', + end: '$' + } + ] + }, + // <> + { + className: 'symbol', + begin: LABEL, + relevance: 10 + } + ] + }; + } + + return pgsql; + +})(); + + hljs.registerLanguage('pgsql', hljsGrammar); + })();/*! `php` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: PHP + Author: Victor Karamzin + Contributors: Evgeny Stepanischev , Ivan Sagalaev + Website: https://www.php.net + Category: common + */ + + /** + * @param {HLJSApi} hljs + * @returns {LanguageDetail} + * */ + function php(hljs) { + const regex = hljs.regex; + // negative look-ahead tries to avoid matching patterns that are not + // Perl at all like $ident$, @ident@, etc. + const NOT_PERL_ETC = /(?![A-Za-z0-9])(?![$])/; + const IDENT_RE = regex.concat( + /[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/, + NOT_PERL_ETC); + // Will not detect camelCase classes + const PASCAL_CASE_CLASS_NAME_RE = regex.concat( + /(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/, + NOT_PERL_ETC); + const VARIABLE = { + scope: 'variable', + match: '\\$+' + IDENT_RE, + }; + const PREPROCESSOR = { + scope: 'meta', + variants: [ + { begin: /<\?php/, relevance: 10 }, // boost for obvious PHP + { begin: /<\?=/ }, + // less relevant per PSR-1 which says not to use short-tags + { begin: /<\?/, relevance: 0.1 }, + { begin: /\?>/ } // end php tag + ] + }; + const SUBST = { + scope: 'subst', + variants: [ + { begin: /\$\w+/ }, + { + begin: /\{\$/, + end: /\}/ + } + ] + }; + const SINGLE_QUOTED = hljs.inherit(hljs.APOS_STRING_MODE, { illegal: null, }); + const DOUBLE_QUOTED = hljs.inherit(hljs.QUOTE_STRING_MODE, { + illegal: null, + contains: hljs.QUOTE_STRING_MODE.contains.concat(SUBST), + }); + + const HEREDOC = { + begin: /<<<[ \t]*(?:(\w+)|"(\w+)")\n/, + end: /[ \t]*(\w+)\b/, + contains: hljs.QUOTE_STRING_MODE.contains.concat(SUBST), + 'on:begin': (m, resp) => { resp.data._beginMatch = m[1] || m[2]; }, + 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); }, + }; + + const NOWDOC = hljs.END_SAME_AS_BEGIN({ + begin: /<<<[ \t]*'(\w+)'\n/, + end: /[ \t]*(\w+)\b/, + }); + // list of valid whitespaces because non-breaking space might be part of a IDENT_RE + const WHITESPACE = '[ \t\n]'; + const STRING = { + scope: 'string', + variants: [ + DOUBLE_QUOTED, + SINGLE_QUOTED, + HEREDOC, + NOWDOC + ] + }; + const NUMBER = { + scope: 'number', + variants: [ + { begin: `\\b0[bB][01]+(?:_[01]+)*\\b` }, // Binary w/ underscore support + { begin: `\\b0[oO][0-7]+(?:_[0-7]+)*\\b` }, // Octals w/ underscore support + { begin: `\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b` }, // Hex w/ underscore support + // Decimals w/ underscore support, with optional fragments and scientific exponent (e) suffix. + { begin: `(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?` } + ], + relevance: 0 + }; + const LITERALS = [ + "false", + "null", + "true" + ]; + const KWS = [ + // Magic constants: + // + "__CLASS__", + "__DIR__", + "__FILE__", + "__FUNCTION__", + "__COMPILER_HALT_OFFSET__", + "__LINE__", + "__METHOD__", + "__NAMESPACE__", + "__TRAIT__", + // Function that look like language construct or language construct that look like function: + // List of keywords that may not require parenthesis + "die", + "echo", + "exit", + "include", + "include_once", + "print", + "require", + "require_once", + // These are not language construct (function) but operate on the currently-executing function and can access the current symbol table + // 'compact extract func_get_arg func_get_args func_num_args get_called_class get_parent_class ' + + // Other keywords: + // + // + "array", + "abstract", + "and", + "as", + "binary", + "bool", + "boolean", + "break", + "callable", + "case", + "catch", + "class", + "clone", + "const", + "continue", + "declare", + "default", + "do", + "double", + "else", + "elseif", + "empty", + "enddeclare", + "endfor", + "endforeach", + "endif", + "endswitch", + "endwhile", + "enum", + "eval", + "extends", + "final", + "finally", + "float", + "for", + "foreach", + "from", + "global", + "goto", + "if", + "implements", + "instanceof", + "insteadof", + "int", + "integer", + "interface", + "isset", + "iterable", + "list", + "match|0", + "mixed", + "new", + "never", + "object", + "or", + "private", + "protected", + "public", + "readonly", + "real", + "return", + "string", + "switch", + "throw", + "trait", + "try", + "unset", + "use", + "var", + "void", + "while", + "xor", + "yield" + ]; + + const BUILT_INS = [ + // Standard PHP library: + // + "Error|0", + "AppendIterator", + "ArgumentCountError", + "ArithmeticError", + "ArrayIterator", + "ArrayObject", + "AssertionError", + "BadFunctionCallException", + "BadMethodCallException", + "CachingIterator", + "CallbackFilterIterator", + "CompileError", + "Countable", + "DirectoryIterator", + "DivisionByZeroError", + "DomainException", + "EmptyIterator", + "ErrorException", + "Exception", + "FilesystemIterator", + "FilterIterator", + "GlobIterator", + "InfiniteIterator", + "InvalidArgumentException", + "IteratorIterator", + "LengthException", + "LimitIterator", + "LogicException", + "MultipleIterator", + "NoRewindIterator", + "OutOfBoundsException", + "OutOfRangeException", + "OuterIterator", + "OverflowException", + "ParentIterator", + "ParseError", + "RangeException", + "RecursiveArrayIterator", + "RecursiveCachingIterator", + "RecursiveCallbackFilterIterator", + "RecursiveDirectoryIterator", + "RecursiveFilterIterator", + "RecursiveIterator", + "RecursiveIteratorIterator", + "RecursiveRegexIterator", + "RecursiveTreeIterator", + "RegexIterator", + "RuntimeException", + "SeekableIterator", + "SplDoublyLinkedList", + "SplFileInfo", + "SplFileObject", + "SplFixedArray", + "SplHeap", + "SplMaxHeap", + "SplMinHeap", + "SplObjectStorage", + "SplObserver", + "SplPriorityQueue", + "SplQueue", + "SplStack", + "SplSubject", + "SplTempFileObject", + "TypeError", + "UnderflowException", + "UnexpectedValueException", + "UnhandledMatchError", + // Reserved interfaces: + // + "ArrayAccess", + "BackedEnum", + "Closure", + "Fiber", + "Generator", + "Iterator", + "IteratorAggregate", + "Serializable", + "Stringable", + "Throwable", + "Traversable", + "UnitEnum", + "WeakReference", + "WeakMap", + // Reserved classes: + // + "Directory", + "__PHP_Incomplete_Class", + "parent", + "php_user_filter", + "self", + "static", + "stdClass" + ]; + + /** Dual-case keywords + * + * ["then","FILE"] => + * ["then", "THEN", "FILE", "file"] + * + * @param {string[]} items */ + const dualCase = (items) => { + /** @type string[] */ + const result = []; + items.forEach(item => { + result.push(item); + if (item.toLowerCase() === item) { + result.push(item.toUpperCase()); + } else { + result.push(item.toLowerCase()); + } + }); + return result; + }; + + const KEYWORDS = { + keyword: KWS, + literal: dualCase(LITERALS), + built_in: BUILT_INS, + }; + + /** + * @param {string[]} items */ + const normalizeKeywords = (items) => { + return items.map(item => { + return item.replace(/\|\d+$/, ""); + }); + }; + + const CONSTRUCTOR_CALL = { variants: [ + { + match: [ + /new/, + regex.concat(WHITESPACE, "+"), + // to prevent built ins from being confused as the class constructor call + regex.concat("(?!", normalizeKeywords(BUILT_INS).join("\\b|"), "\\b)"), + PASCAL_CASE_CLASS_NAME_RE, + ], + scope: { + 1: "keyword", + 4: "title.class", + }, + } + ] }; + + const CONSTANT_REFERENCE = regex.concat(IDENT_RE, "\\b(?!\\()"); + + const LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON = { variants: [ + { + match: [ + regex.concat( + /::/, + regex.lookahead(/(?!class\b)/) + ), + CONSTANT_REFERENCE, + ], + scope: { 2: "variable.constant", }, + }, + { + match: [ + /::/, + /class/, + ], + scope: { 2: "variable.language", }, + }, + { + match: [ + PASCAL_CASE_CLASS_NAME_RE, + regex.concat( + /::/, + regex.lookahead(/(?!class\b)/) + ), + CONSTANT_REFERENCE, + ], + scope: { + 1: "title.class", + 3: "variable.constant", + }, + }, + { + match: [ + PASCAL_CASE_CLASS_NAME_RE, + regex.concat( + "::", + regex.lookahead(/(?!class\b)/) + ), + ], + scope: { 1: "title.class", }, + }, + { + match: [ + PASCAL_CASE_CLASS_NAME_RE, + /::/, + /class/, + ], + scope: { + 1: "title.class", + 3: "variable.language", + }, + } + ] }; + + const NAMED_ARGUMENT = { + scope: 'attr', + match: regex.concat(IDENT_RE, regex.lookahead(':'), regex.lookahead(/(?!::)/)), + }; + const PARAMS_MODE = { + relevance: 0, + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + contains: [ + NAMED_ARGUMENT, + VARIABLE, + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, + hljs.C_BLOCK_COMMENT_MODE, + STRING, + NUMBER, + CONSTRUCTOR_CALL, + ], + }; + const FUNCTION_INVOKE = { + relevance: 0, + match: [ + /\b/, + // to prevent keywords from being confused as the function title + regex.concat("(?!fn\\b|function\\b|", normalizeKeywords(KWS).join("\\b|"), "|", normalizeKeywords(BUILT_INS).join("\\b|"), "\\b)"), + IDENT_RE, + regex.concat(WHITESPACE, "*"), + regex.lookahead(/(?=\()/) + ], + scope: { 3: "title.function.invoke", }, + contains: [ PARAMS_MODE ] + }; + PARAMS_MODE.contains.push(FUNCTION_INVOKE); + + const ATTRIBUTE_CONTAINS = [ + NAMED_ARGUMENT, + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, + hljs.C_BLOCK_COMMENT_MODE, + STRING, + NUMBER, + CONSTRUCTOR_CALL, + ]; + + const ATTRIBUTES = { + begin: regex.concat(/#\[\s*/, PASCAL_CASE_CLASS_NAME_RE), + beginScope: "meta", + end: /]/, + endScope: "meta", + keywords: { + literal: LITERALS, + keyword: [ + 'new', + 'array', + ] + }, + contains: [ + { + begin: /\[/, + end: /]/, + keywords: { + literal: LITERALS, + keyword: [ + 'new', + 'array', + ] + }, + contains: [ + 'self', + ...ATTRIBUTE_CONTAINS, + ] + }, + ...ATTRIBUTE_CONTAINS, + { + scope: 'meta', + match: PASCAL_CASE_CLASS_NAME_RE + } + ] + }; + + return { + case_insensitive: false, + keywords: KEYWORDS, + contains: [ + ATTRIBUTES, + hljs.HASH_COMMENT_MODE, + hljs.COMMENT('//', '$'), + hljs.COMMENT( + '/\\*', + '\\*/', + { contains: [ + { + scope: 'doctag', + match: '@[A-Za-z]+' + } + ] } + ), + { + match: /__halt_compiler\(\);/, + keywords: '__halt_compiler', + starts: { + scope: "comment", + end: hljs.MATCH_NOTHING_RE, + contains: [ + { + match: /\?>/, + scope: "meta", + endsParent: true + } + ] + } + }, + PREPROCESSOR, + { + scope: 'variable.language', + match: /\$this\b/ + }, + VARIABLE, + FUNCTION_INVOKE, + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, + { + match: [ + /const/, + /\s/, + IDENT_RE, + ], + scope: { + 1: "keyword", + 3: "variable.constant", + }, + }, + CONSTRUCTOR_CALL, + { + scope: 'function', + relevance: 0, + beginKeywords: 'fn function', + end: /[;{]/, + excludeEnd: true, + illegal: '[$%\\[]', + contains: [ + { beginKeywords: 'use', }, + hljs.UNDERSCORE_TITLE_MODE, + { + begin: '=>', // No markup, just a relevance booster + endsParent: true + }, + { + scope: 'params', + begin: '\\(', + end: '\\)', + excludeBegin: true, + excludeEnd: true, + keywords: KEYWORDS, + contains: [ + 'self', + VARIABLE, + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, + hljs.C_BLOCK_COMMENT_MODE, + STRING, + NUMBER + ] + }, + ] + }, + { + scope: 'class', + variants: [ + { + beginKeywords: "enum", + illegal: /[($"]/ + }, + { + beginKeywords: "class interface trait", + illegal: /[:($"]/ + } + ], + relevance: 0, + end: /\{/, + excludeEnd: true, + contains: [ + { beginKeywords: 'extends implements' }, + hljs.UNDERSCORE_TITLE_MODE + ] + }, + // both use and namespace still use "old style" rules (vs multi-match) + // because the namespace name can include `\` and we still want each + // element to be treated as its own *individual* title + { + beginKeywords: 'namespace', + relevance: 0, + end: ';', + illegal: /[.']/, + contains: [ hljs.inherit(hljs.UNDERSCORE_TITLE_MODE, { scope: "title.class" }) ] + }, + { + beginKeywords: 'use', + relevance: 0, + end: ';', + contains: [ + // TODO: title.function vs title.class + { + match: /\b(as|const|function)\b/, + scope: "keyword" + }, + // TODO: could be title.class or title.function + hljs.UNDERSCORE_TITLE_MODE + ] + }, + STRING, + NUMBER, + ] + }; + } + + return php; + +})(); + + hljs.registerLanguage('php', hljsGrammar); + })();/*! `plaintext` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Plain text + Author: Egor Rogov (e.rogov@postgrespro.ru) + Description: Plain text without any highlighting. + Category: common + */ + + function plaintext(hljs) { + return { + name: 'Plain text', + aliases: [ + 'text', + 'txt' + ], + disableAutodetect: true + }; + } + + return plaintext; + +})(); + + hljs.registerLanguage('plaintext', hljsGrammar); + })();/*! `powershell` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: PowerShell + Description: PowerShell is a task-based command-line shell and scripting language built on .NET. + Author: David Mohundro + Contributors: Nicholas Blumhardt , Victor Zhou , Nicolas Le Gall + Website: https://docs.microsoft.com/en-us/powershell/ + Category: scripting + */ + + function powershell(hljs) { + const TYPES = [ + "string", + "char", + "byte", + "int", + "long", + "bool", + "decimal", + "single", + "double", + "DateTime", + "xml", + "array", + "hashtable", + "void" + ]; + + // https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands + const VALID_VERBS = + 'Add|Clear|Close|Copy|Enter|Exit|Find|Format|Get|Hide|Join|Lock|' + + 'Move|New|Open|Optimize|Pop|Push|Redo|Remove|Rename|Reset|Resize|' + + 'Search|Select|Set|Show|Skip|Split|Step|Switch|Undo|Unlock|' + + 'Watch|Backup|Checkpoint|Compare|Compress|Convert|ConvertFrom|' + + 'ConvertTo|Dismount|Edit|Expand|Export|Group|Import|Initialize|' + + 'Limit|Merge|Mount|Out|Publish|Restore|Save|Sync|Unpublish|Update|' + + 'Approve|Assert|Build|Complete|Confirm|Deny|Deploy|Disable|Enable|Install|Invoke|' + + 'Register|Request|Restart|Resume|Start|Stop|Submit|Suspend|Uninstall|' + + 'Unregister|Wait|Debug|Measure|Ping|Repair|Resolve|Test|Trace|Connect|' + + 'Disconnect|Read|Receive|Send|Write|Block|Grant|Protect|Revoke|Unblock|' + + 'Unprotect|Use|ForEach|Sort|Tee|Where'; + + const COMPARISON_OPERATORS = + '-and|-as|-band|-bnot|-bor|-bxor|-casesensitive|-ccontains|-ceq|-cge|-cgt|' + + '-cle|-clike|-clt|-cmatch|-cne|-cnotcontains|-cnotlike|-cnotmatch|-contains|' + + '-creplace|-csplit|-eq|-exact|-f|-file|-ge|-gt|-icontains|-ieq|-ige|-igt|' + + '-ile|-ilike|-ilt|-imatch|-in|-ine|-inotcontains|-inotlike|-inotmatch|' + + '-ireplace|-is|-isnot|-isplit|-join|-le|-like|-lt|-match|-ne|-not|' + + '-notcontains|-notin|-notlike|-notmatch|-or|-regex|-replace|-shl|-shr|' + + '-split|-wildcard|-xor'; + + const KEYWORDS = { + $pattern: /-?[A-z\.\-]+\b/, + keyword: + 'if else foreach return do while until elseif begin for trap data dynamicparam ' + + 'end break throw param continue finally in switch exit filter try process catch ' + + 'hidden static parameter', + // "echo" relevance has been set to 0 to avoid auto-detect conflicts with shell transcripts + built_in: + 'ac asnp cat cd CFS chdir clc clear clhy cli clp cls clv cnsn compare copy cp ' + + 'cpi cpp curl cvpa dbp del diff dir dnsn ebp echo|0 epal epcsv epsn erase etsn exsn fc fhx ' + + 'fl ft fw gal gbp gc gcb gci gcm gcs gdr gerr ghy gi gin gjb gl gm gmo gp gps gpv group ' + + 'gsn gsnp gsv gtz gu gv gwmi h history icm iex ihy ii ipal ipcsv ipmo ipsn irm ise iwmi ' + + 'iwr kill lp ls man md measure mi mount move mp mv nal ndr ni nmo npssc nsn nv ogv oh ' + + 'popd ps pushd pwd r rbp rcjb rcsn rd rdr ren ri rjb rm rmdir rmo rni rnp rp rsn rsnp ' + + 'rujb rv rvpa rwmi sajb sal saps sasv sbp sc scb select set shcm si sl sleep sls sort sp ' + + 'spjb spps spsv start stz sujb sv swmi tee trcm type wget where wjb write' + // TODO: 'validate[A-Z]+' can't work in keywords + }; + + const TITLE_NAME_RE = /\w[\w\d]*((-)[\w\d]+)*/; + + const BACKTICK_ESCAPE = { + begin: '`[\\s\\S]', + relevance: 0 + }; + + const VAR = { + className: 'variable', + variants: [ + { begin: /\$\B/ }, + { + className: 'keyword', + begin: /\$this/ + }, + { begin: /\$[\w\d][\w\d_:]*/ } + ] + }; + + const LITERAL = { + className: 'literal', + begin: /\$(null|true|false)\b/ + }; + + const QUOTE_STRING = { + className: "string", + variants: [ + { + begin: /"/, + end: /"/ + }, + { + begin: /@"/, + end: /^"@/ + } + ], + contains: [ + BACKTICK_ESCAPE, + VAR, + { + className: 'variable', + begin: /\$[A-z]/, + end: /[^A-z]/ + } + ] + }; + + const APOS_STRING = { + className: 'string', + variants: [ + { + begin: /'/, + end: /'/ + }, + { + begin: /@'/, + end: /^'@/ + } + ] + }; + + const PS_HELPTAGS = { + className: "doctag", + variants: [ + /* no paramater help tags */ + { begin: /\.(synopsis|description|example|inputs|outputs|notes|link|component|role|functionality)/ }, + /* one parameter help tags */ + { begin: /\.(parameter|forwardhelptargetname|forwardhelpcategory|remotehelprunspace|externalhelp)\s+\S+/ } + ] + }; + + const PS_COMMENT = hljs.inherit( + hljs.COMMENT(null, null), + { + variants: [ + /* single-line comment */ + { + begin: /#/, + end: /$/ + }, + /* multi-line comment */ + { + begin: /<#/, + end: /#>/ + } + ], + contains: [ PS_HELPTAGS ] + } + ); + + const CMDLETS = { + className: 'built_in', + variants: [ { begin: '('.concat(VALID_VERBS, ')+(-)[\\w\\d]+') } ] + }; + + const PS_CLASS = { + className: 'class', + beginKeywords: 'class enum', + end: /\s*[{]/, + excludeEnd: true, + relevance: 0, + contains: [ hljs.TITLE_MODE ] + }; + + const PS_FUNCTION = { + className: 'function', + begin: /function\s+/, + end: /\s*\{|$/, + excludeEnd: true, + returnBegin: true, + relevance: 0, + contains: [ + { + begin: "function", + relevance: 0, + className: "keyword" + }, + { + className: "title", + begin: TITLE_NAME_RE, + relevance: 0 + }, + { + begin: /\(/, + end: /\)/, + className: "params", + relevance: 0, + contains: [ VAR ] + } + // CMDLETS + ] + }; + + // Using statment, plus type, plus assembly name. + const PS_USING = { + begin: /using\s/, + end: /$/, + returnBegin: true, + contains: [ + QUOTE_STRING, + APOS_STRING, + { + className: 'keyword', + begin: /(using|assembly|command|module|namespace|type)/ + } + ] + }; + + // Comperison operators & function named parameters. + const PS_ARGUMENTS = { variants: [ + // PS literals are pretty verbose so it's a good idea to accent them a bit. + { + className: 'operator', + begin: '('.concat(COMPARISON_OPERATORS, ')\\b') + }, + { + className: 'literal', + begin: /(-){1,2}[\w\d-]+/, + relevance: 0 + } + ] }; + + const HASH_SIGNS = { + className: 'selector-tag', + begin: /@\B/, + relevance: 0 + }; + + // It's a very general rule so I'll narrow it a bit with some strict boundaries + // to avoid any possible false-positive collisions! + const PS_METHODS = { + className: 'function', + begin: /\[.*\]\s*[\w]+[ ]??\(/, + end: /$/, + returnBegin: true, + relevance: 0, + contains: [ + { + className: 'keyword', + begin: '('.concat( + KEYWORDS.keyword.toString().replace(/\s/g, '|' + ), ')\\b'), + endsParent: true, + relevance: 0 + }, + hljs.inherit(hljs.TITLE_MODE, { endsParent: true }) + ] + }; + + const GENTLEMANS_SET = [ + // STATIC_MEMBER, + PS_METHODS, + PS_COMMENT, + BACKTICK_ESCAPE, + hljs.NUMBER_MODE, + QUOTE_STRING, + APOS_STRING, + // PS_NEW_OBJECT_TYPE, + CMDLETS, + VAR, + LITERAL, + HASH_SIGNS + ]; + + const PS_TYPE = { + begin: /\[/, + end: /\]/, + excludeBegin: true, + excludeEnd: true, + relevance: 0, + contains: [].concat( + 'self', + GENTLEMANS_SET, + { + begin: "(" + TYPES.join("|") + ")", + className: "built_in", + relevance: 0 + }, + { + className: 'type', + begin: /[\.\w\d]+/, + relevance: 0 + } + ) + }; + + PS_METHODS.contains.unshift(PS_TYPE); + + return { + name: 'PowerShell', + aliases: [ + "pwsh", + "ps", + "ps1" + ], + case_insensitive: true, + keywords: KEYWORDS, + contains: GENTLEMANS_SET.concat( + PS_CLASS, + PS_FUNCTION, + PS_USING, + PS_ARGUMENTS, + PS_TYPE + ) + }; + } + + return powershell; + +})(); + + hljs.registerLanguage('powershell', hljsGrammar); + })();/*! `properties` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: .properties + Contributors: Valentin Aitken , Egor Rogov + Website: https://en.wikipedia.org/wiki/.properties + Category: config + */ + + /** @type LanguageFn */ + function properties(hljs) { + // whitespaces: space, tab, formfeed + const WS0 = '[ \\t\\f]*'; + const WS1 = '[ \\t\\f]+'; + // delimiter + const EQUAL_DELIM = WS0 + '[:=]' + WS0; + const WS_DELIM = WS1; + const DELIM = '(' + EQUAL_DELIM + '|' + WS_DELIM + ')'; + const KEY = '([^\\\\:= \\t\\f\\n]|\\\\.)+'; + + const DELIM_AND_VALUE = { + // skip DELIM + end: DELIM, + relevance: 0, + starts: { + // value: everything until end of line (again, taking into account backslashes) + className: 'string', + end: /$/, + relevance: 0, + contains: [ + { begin: '\\\\\\\\' }, + { begin: '\\\\\\n' } + ] + } + }; + + return { + name: '.properties', + disableAutodetect: true, + case_insensitive: true, + illegal: /\S/, + contains: [ + hljs.COMMENT('^\\s*[!#]', '$'), + // key: everything until whitespace or = or : (taking into account backslashes) + // case of a key-value pair + { + returnBegin: true, + variants: [ + { begin: KEY + EQUAL_DELIM }, + { begin: KEY + WS_DELIM } + ], + contains: [ + { + className: 'attr', + begin: KEY, + endsParent: true + } + ], + starts: DELIM_AND_VALUE + }, + // case of an empty key + { + className: 'attr', + begin: KEY + WS0 + '$' + } + ] + }; + } + + return properties; + +})(); + + hljs.registerLanguage('properties', hljsGrammar); + })();/*! `python` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Python + Description: Python is an interpreted, object-oriented, high-level programming language with dynamic semantics. + Website: https://www.python.org + Category: common + */ + + function python(hljs) { + const regex = hljs.regex; + const IDENT_RE = /[\p{XID_Start}_]\p{XID_Continue}*/u; + const RESERVED_WORDS = [ + 'and', + 'as', + 'assert', + 'async', + 'await', + 'break', + 'case', + 'class', + 'continue', + 'def', + 'del', + 'elif', + 'else', + 'except', + 'finally', + 'for', + 'from', + 'global', + 'if', + 'import', + 'in', + 'is', + 'lambda', + 'match', + 'nonlocal|10', + 'not', + 'or', + 'pass', + 'raise', + 'return', + 'try', + 'while', + 'with', + 'yield' + ]; + + const BUILT_INS = [ + '__import__', + 'abs', + 'all', + 'any', + 'ascii', + 'bin', + 'bool', + 'breakpoint', + 'bytearray', + 'bytes', + 'callable', + 'chr', + 'classmethod', + 'compile', + 'complex', + 'delattr', + 'dict', + 'dir', + 'divmod', + 'enumerate', + 'eval', + 'exec', + 'filter', + 'float', + 'format', + 'frozenset', + 'getattr', + 'globals', + 'hasattr', + 'hash', + 'help', + 'hex', + 'id', + 'input', + 'int', + 'isinstance', + 'issubclass', + 'iter', + 'len', + 'list', + 'locals', + 'map', + 'max', + 'memoryview', + 'min', + 'next', + 'object', + 'oct', + 'open', + 'ord', + 'pow', + 'print', + 'property', + 'range', + 'repr', + 'reversed', + 'round', + 'set', + 'setattr', + 'slice', + 'sorted', + 'staticmethod', + 'str', + 'sum', + 'super', + 'tuple', + 'type', + 'vars', + 'zip' + ]; + + const LITERALS = [ + '__debug__', + 'Ellipsis', + 'False', + 'None', + 'NotImplemented', + 'True' + ]; + + // https://docs.python.org/3/library/typing.html + // TODO: Could these be supplemented by a CamelCase matcher in certain + // contexts, leaving these remaining only for relevance hinting? + const TYPES = [ + "Any", + "Callable", + "Coroutine", + "Dict", + "List", + "Literal", + "Generic", + "Optional", + "Sequence", + "Set", + "Tuple", + "Type", + "Union" + ]; + + const KEYWORDS = { + $pattern: /[A-Za-z]\w+|__\w+__/, + keyword: RESERVED_WORDS, + built_in: BUILT_INS, + literal: LITERALS, + type: TYPES + }; + + const PROMPT = { + className: 'meta', + begin: /^(>>>|\.\.\.) / + }; + + const SUBST = { + className: 'subst', + begin: /\{/, + end: /\}/, + keywords: KEYWORDS, + illegal: /#/ + }; + + const LITERAL_BRACKET = { + begin: /\{\{/, + relevance: 0 + }; + + const STRING = { + className: 'string', + contains: [ hljs.BACKSLASH_ESCAPE ], + variants: [ + { + begin: /([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/, + end: /'''/, + contains: [ + hljs.BACKSLASH_ESCAPE, + PROMPT + ], + relevance: 10 + }, + { + begin: /([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/, + end: /"""/, + contains: [ + hljs.BACKSLASH_ESCAPE, + PROMPT + ], + relevance: 10 + }, + { + begin: /([fF][rR]|[rR][fF]|[fF])'''/, + end: /'''/, + contains: [ + hljs.BACKSLASH_ESCAPE, + PROMPT, + LITERAL_BRACKET, + SUBST + ] + }, + { + begin: /([fF][rR]|[rR][fF]|[fF])"""/, + end: /"""/, + contains: [ + hljs.BACKSLASH_ESCAPE, + PROMPT, + LITERAL_BRACKET, + SUBST + ] + }, + { + begin: /([uU]|[rR])'/, + end: /'/, + relevance: 10 + }, + { + begin: /([uU]|[rR])"/, + end: /"/, + relevance: 10 + }, + { + begin: /([bB]|[bB][rR]|[rR][bB])'/, + end: /'/ + }, + { + begin: /([bB]|[bB][rR]|[rR][bB])"/, + end: /"/ + }, + { + begin: /([fF][rR]|[rR][fF]|[fF])'/, + end: /'/, + contains: [ + hljs.BACKSLASH_ESCAPE, + LITERAL_BRACKET, + SUBST + ] + }, + { + begin: /([fF][rR]|[rR][fF]|[fF])"/, + end: /"/, + contains: [ + hljs.BACKSLASH_ESCAPE, + LITERAL_BRACKET, + SUBST + ] + }, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE + ] + }; + + // https://docs.python.org/3.9/reference/lexical_analysis.html#numeric-literals + const digitpart = '[0-9](_?[0-9])*'; + const pointfloat = `(\\b(${digitpart}))?\\.(${digitpart})|\\b(${digitpart})\\.`; + // Whitespace after a number (or any lexical token) is needed only if its absence + // would change the tokenization + // https://docs.python.org/3.9/reference/lexical_analysis.html#whitespace-between-tokens + // We deviate slightly, requiring a word boundary or a keyword + // to avoid accidentally recognizing *prefixes* (e.g., `0` in `0x41` or `08` or `0__1`) + const lookahead = `\\b|${RESERVED_WORDS.join('|')}`; + const NUMBER = { + className: 'number', + relevance: 0, + variants: [ + // exponentfloat, pointfloat + // https://docs.python.org/3.9/reference/lexical_analysis.html#floating-point-literals + // optionally imaginary + // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals + // Note: no leading \b because floats can start with a decimal point + // and we don't want to mishandle e.g. `fn(.5)`, + // no trailing \b for pointfloat because it can end with a decimal point + // and we don't want to mishandle e.g. `0..hex()`; this should be safe + // because both MUST contain a decimal point and so cannot be confused with + // the interior part of an identifier + { + begin: `(\\b(${digitpart})|(${pointfloat}))[eE][+-]?(${digitpart})[jJ]?(?=${lookahead})` + }, + { + begin: `(${pointfloat})[jJ]?` + }, + + // decinteger, bininteger, octinteger, hexinteger + // https://docs.python.org/3.9/reference/lexical_analysis.html#integer-literals + // optionally "long" in Python 2 + // https://docs.python.org/2.7/reference/lexical_analysis.html#integer-and-long-integer-literals + // decinteger is optionally imaginary + // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals + { + begin: `\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${lookahead})` + }, + { + begin: `\\b0[bB](_?[01])+[lL]?(?=${lookahead})` + }, + { + begin: `\\b0[oO](_?[0-7])+[lL]?(?=${lookahead})` + }, + { + begin: `\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${lookahead})` + }, + + // imagnumber (digitpart-based) + // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals + { + begin: `\\b(${digitpart})[jJ](?=${lookahead})` + } + ] + }; + const COMMENT_TYPE = { + className: "comment", + begin: regex.lookahead(/# type:/), + end: /$/, + keywords: KEYWORDS, + contains: [ + { // prevent keywords from coloring `type` + begin: /# type:/ + }, + // comment within a datatype comment includes no keywords + { + begin: /#/, + end: /\b\B/, + endsWithParent: true + } + ] + }; + const PARAMS = { + className: 'params', + variants: [ + // Exclude params in functions without params + { + className: "", + begin: /\(\s*\)/, + skip: true + }, + { + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, + keywords: KEYWORDS, + contains: [ + 'self', + PROMPT, + NUMBER, + STRING, + hljs.HASH_COMMENT_MODE + ] + } + ] + }; + SUBST.contains = [ + STRING, + NUMBER, + PROMPT + ]; + + return { + name: 'Python', + aliases: [ + 'py', + 'gyp', + 'ipython' + ], + unicodeRegex: true, + keywords: KEYWORDS, + illegal: /(<\/|\?)|=>/, + contains: [ + PROMPT, + NUMBER, + { + // very common convention + begin: /\bself\b/ + }, + { + // eat "if" prior to string so that it won't accidentally be + // labeled as an f-string + beginKeywords: "if", + relevance: 0 + }, + { match: /\bor\b/, scope: "keyword" }, + STRING, + COMMENT_TYPE, + hljs.HASH_COMMENT_MODE, + { + match: [ + /\bdef/, /\s+/, + IDENT_RE, + ], + scope: { + 1: "keyword", + 3: "title.function" + }, + contains: [ PARAMS ] + }, + { + variants: [ + { + match: [ + /\bclass/, /\s+/, + IDENT_RE, /\s*/, + /\(\s*/, IDENT_RE,/\s*\)/ + ], + }, + { + match: [ + /\bclass/, /\s+/, + IDENT_RE + ], + } + ], + scope: { + 1: "keyword", + 3: "title.class", + 6: "title.class.inherited", + } + }, + { + className: 'meta', + begin: /^[\t ]*@/, + end: /(?=#)|$/, + contains: [ + NUMBER, + PARAMS, + STRING + ] + } + ] + }; + } + + return python; + +})(); + + hljs.registerLanguage('python', hljsGrammar); + })();/*! `r` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: R + Description: R is a free software environment for statistical computing and graphics. + Author: Joe Cheng + Contributors: Konrad Rudolph + Website: https://www.r-project.org + Category: common,scientific + */ + + /** @type LanguageFn */ + function r(hljs) { + const regex = hljs.regex; + // Identifiers in R cannot start with `_`, but they can start with `.` if it + // is not immediately followed by a digit. + // R also supports quoted identifiers, which are near-arbitrary sequences + // delimited by backticks (`…`), which may contain escape sequences. These are + // handled in a separate mode. See `test/markup/r/names.txt` for examples. + // FIXME: Support Unicode identifiers. + const IDENT_RE = /(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/; + const NUMBER_TYPES_RE = regex.either( + // Special case: only hexadecimal binary powers can contain fractions + /0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/, + // Hexadecimal numbers without fraction and optional binary power + /0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/, + // Decimal numbers + /(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/ + ); + const OPERATORS_RE = /[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/; + const PUNCTUATION_RE = regex.either( + /[()]/, + /[{}]/, + /\[\[/, + /[[\]]/, + /\\/, + /,/ + ); + + return { + name: 'R', + + keywords: { + $pattern: IDENT_RE, + keyword: + 'function if in break next repeat else for while', + literal: + 'NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 ' + + 'NA_character_|10 NA_complex_|10', + built_in: + // Builtin constants + 'LETTERS letters month.abb month.name pi T F ' + // Primitive functions + // These are all the functions in `base` that are implemented as a + // `.Primitive`, minus those functions that are also keywords. + + 'abs acos acosh all any anyNA Arg as.call as.character ' + + 'as.complex as.double as.environment as.integer as.logical ' + + 'as.null.default as.numeric as.raw asin asinh atan atanh attr ' + + 'attributes baseenv browser c call ceiling class Conj cos cosh ' + + 'cospi cummax cummin cumprod cumsum digamma dim dimnames ' + + 'emptyenv exp expression floor forceAndCall gamma gc.time ' + + 'globalenv Im interactive invisible is.array is.atomic is.call ' + + 'is.character is.complex is.double is.environment is.expression ' + + 'is.finite is.function is.infinite is.integer is.language ' + + 'is.list is.logical is.matrix is.na is.name is.nan is.null ' + + 'is.numeric is.object is.pairlist is.raw is.recursive is.single ' + + 'is.symbol lazyLoadDBfetch length lgamma list log max min ' + + 'missing Mod names nargs nzchar oldClass on.exit pos.to.env ' + + 'proc.time prod quote range Re rep retracemem return round ' + + 'seq_along seq_len seq.int sign signif sin sinh sinpi sqrt ' + + 'standardGeneric substitute sum switch tan tanh tanpi tracemem ' + + 'trigamma trunc unclass untracemem UseMethod xtfrm', + }, + + contains: [ + // Roxygen comments + hljs.COMMENT( + /#'/, + /$/, + { contains: [ + { + // Handle `@examples` separately to cause all subsequent code + // until the next `@`-tag on its own line to be kept as-is, + // preventing highlighting. This code is example R code, so nested + // doctags shouldn’t be treated as such. See + // `test/markup/r/roxygen.txt` for an example. + scope: 'doctag', + match: /@examples/, + starts: { + end: regex.lookahead(regex.either( + // end if another doc comment + /\n^#'\s*(?=@[a-zA-Z]+)/, + // or a line with no comment + /\n^(?!#')/ + )), + endsParent: true + } + }, + { + // Handle `@param` to highlight the parameter name following + // after. + scope: 'doctag', + begin: '@param', + end: /$/, + contains: [ + { + scope: 'variable', + variants: [ + { match: IDENT_RE }, + { match: /`(?:\\.|[^`\\])+`/ } + ], + endsParent: true + } + ] + }, + { + scope: 'doctag', + match: /@[a-zA-Z]+/ + }, + { + scope: 'keyword', + match: /\\[a-zA-Z]+/ + } + ] } + ), + + hljs.HASH_COMMENT_MODE, + + { + scope: 'string', + contains: [ hljs.BACKSLASH_ESCAPE ], + variants: [ + hljs.END_SAME_AS_BEGIN({ + begin: /[rR]"(-*)\(/, + end: /\)(-*)"/ + }), + hljs.END_SAME_AS_BEGIN({ + begin: /[rR]"(-*)\{/, + end: /\}(-*)"/ + }), + hljs.END_SAME_AS_BEGIN({ + begin: /[rR]"(-*)\[/, + end: /\](-*)"/ + }), + hljs.END_SAME_AS_BEGIN({ + begin: /[rR]'(-*)\(/, + end: /\)(-*)'/ + }), + hljs.END_SAME_AS_BEGIN({ + begin: /[rR]'(-*)\{/, + end: /\}(-*)'/ + }), + hljs.END_SAME_AS_BEGIN({ + begin: /[rR]'(-*)\[/, + end: /\](-*)'/ + }), + { + begin: '"', + end: '"', + relevance: 0 + }, + { + begin: "'", + end: "'", + relevance: 0 + } + ], + }, + + // Matching numbers immediately following punctuation and operators is + // tricky since we need to look at the character ahead of a number to + // ensure the number is not part of an identifier, and we cannot use + // negative look-behind assertions. So instead we explicitly handle all + // possible combinations of (operator|punctuation), number. + // TODO: replace with negative look-behind when available + // { begin: /(? + Contributors: Peter Leonov , Vasily Polovnyov , Loren Segal , Pascal Hurni , Cedric Sohrauer + Category: common, scripting + */ + + function ruby(hljs) { + const regex = hljs.regex; + const RUBY_METHOD_RE = '([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)'; + // TODO: move concepts like CAMEL_CASE into `modes.js` + const CLASS_NAME_RE = regex.either( + /\b([A-Z]+[a-z0-9]+)+/, + // ends in caps + /\b([A-Z]+[a-z0-9]+)+[A-Z]+/, + ) + ; + const CLASS_NAME_WITH_NAMESPACE_RE = regex.concat(CLASS_NAME_RE, /(::\w+)*/); + // very popular ruby built-ins that one might even assume + // are actual keywords (despite that not being the case) + const PSEUDO_KWS = [ + "include", + "extend", + "prepend", + "public", + "private", + "protected", + "raise", + "throw" + ]; + const RUBY_KEYWORDS = { + "variable.constant": [ + "__FILE__", + "__LINE__", + "__ENCODING__" + ], + "variable.language": [ + "self", + "super", + ], + keyword: [ + "alias", + "and", + "begin", + "BEGIN", + "break", + "case", + "class", + "defined", + "do", + "else", + "elsif", + "end", + "END", + "ensure", + "for", + "if", + "in", + "module", + "next", + "not", + "or", + "redo", + "require", + "rescue", + "retry", + "return", + "then", + "undef", + "unless", + "until", + "when", + "while", + "yield", + ...PSEUDO_KWS + ], + built_in: [ + "proc", + "lambda", + "attr_accessor", + "attr_reader", + "attr_writer", + "define_method", + "private_constant", + "module_function" + ], + literal: [ + "true", + "false", + "nil" + ] + }; + const YARDOCTAG = { + className: 'doctag', + begin: '@[A-Za-z]+' + }; + const IRB_OBJECT = { + begin: '#<', + end: '>' + }; + const COMMENT_MODES = [ + hljs.COMMENT( + '#', + '$', + { contains: [ YARDOCTAG ] } + ), + hljs.COMMENT( + '^=begin', + '^=end', + { + contains: [ YARDOCTAG ], + relevance: 10 + } + ), + hljs.COMMENT('^__END__', hljs.MATCH_NOTHING_RE) + ]; + const SUBST = { + className: 'subst', + begin: /#\{/, + end: /\}/, + keywords: RUBY_KEYWORDS + }; + const STRING = { + className: 'string', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + variants: [ + { + begin: /'/, + end: /'/ + }, + { + begin: /"/, + end: /"/ + }, + { + begin: /`/, + end: /`/ + }, + { + begin: /%[qQwWx]?\(/, + end: /\)/ + }, + { + begin: /%[qQwWx]?\[/, + end: /\]/ + }, + { + begin: /%[qQwWx]?\{/, + end: /\}/ + }, + { + begin: /%[qQwWx]?/ + }, + { + begin: /%[qQwWx]?\//, + end: /\// + }, + { + begin: /%[qQwWx]?%/, + end: /%/ + }, + { + begin: /%[qQwWx]?-/, + end: /-/ + }, + { + begin: /%[qQwWx]?\|/, + end: /\|/ + }, + // in the following expressions, \B in the beginning suppresses recognition of ?-sequences + // where ? is the last character of a preceding identifier, as in: `func?4` + { begin: /\B\?(\\\d{1,3})/ }, + { begin: /\B\?(\\x[A-Fa-f0-9]{1,2})/ }, + { begin: /\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/ }, + { begin: /\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/ }, + { begin: /\B\?\\(c|C-)[\x20-\x7e]/ }, + { begin: /\B\?\\?\S/ }, + // heredocs + { + // this guard makes sure that we have an entire heredoc and not a false + // positive (auto-detect, etc.) + begin: regex.concat( + /<<[-~]?'?/, + regex.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/) + ), + contains: [ + hljs.END_SAME_AS_BEGIN({ + begin: /(\w+)/, + end: /(\w+)/, + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ] + }) + ] + } + ] + }; + + // Ruby syntax is underdocumented, but this grammar seems to be accurate + // as of version 2.7.2 (confirmed with (irb and `Ripper.sexp(...)`) + // https://docs.ruby-lang.org/en/2.7.0/doc/syntax/literals_rdoc.html#label-Numbers + const decimal = '[1-9](_?[0-9])*|0'; + const digits = '[0-9](_?[0-9])*'; + const NUMBER = { + className: 'number', + relevance: 0, + variants: [ + // decimal integer/float, optionally exponential or rational, optionally imaginary + { begin: `\\b(${decimal})(\\.(${digits}))?([eE][+-]?(${digits})|r)?i?\\b` }, + + // explicit decimal/binary/octal/hexadecimal integer, + // optionally rational and/or imaginary + { begin: "\\b0[dD][0-9](_?[0-9])*r?i?\\b" }, + { begin: "\\b0[bB][0-1](_?[0-1])*r?i?\\b" }, + { begin: "\\b0[oO][0-7](_?[0-7])*r?i?\\b" }, + { begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b" }, + + // 0-prefixed implicit octal integer, optionally rational and/or imaginary + { begin: "\\b0(_?[0-7])+r?i?\\b" } + ] + }; + + const PARAMS = { + variants: [ + { + match: /\(\)/, + }, + { + className: 'params', + begin: /\(/, + end: /(?=\))/, + excludeBegin: true, + endsParent: true, + keywords: RUBY_KEYWORDS, + } + ] + }; + + const INCLUDE_EXTEND = { + match: [ + /(include|extend)\s+/, + CLASS_NAME_WITH_NAMESPACE_RE + ], + scope: { + 2: "title.class" + }, + keywords: RUBY_KEYWORDS + }; + + const CLASS_DEFINITION = { + variants: [ + { + match: [ + /class\s+/, + CLASS_NAME_WITH_NAMESPACE_RE, + /\s+<\s+/, + CLASS_NAME_WITH_NAMESPACE_RE + ] + }, + { + match: [ + /\b(class|module)\s+/, + CLASS_NAME_WITH_NAMESPACE_RE + ] + } + ], + scope: { + 2: "title.class", + 4: "title.class.inherited" + }, + keywords: RUBY_KEYWORDS + }; + + const UPPER_CASE_CONSTANT = { + relevance: 0, + match: /\b[A-Z][A-Z_0-9]+\b/, + className: "variable.constant" + }; + + const METHOD_DEFINITION = { + match: [ + /def/, /\s+/, + RUBY_METHOD_RE + ], + scope: { + 1: "keyword", + 3: "title.function" + }, + contains: [ + PARAMS + ] + }; + + const OBJECT_CREATION = { + relevance: 0, + match: [ + CLASS_NAME_WITH_NAMESPACE_RE, + /\.new[. (]/ + ], + scope: { + 1: "title.class" + } + }; + + // CamelCase + const CLASS_REFERENCE = { + relevance: 0, + match: CLASS_NAME_RE, + scope: "title.class" + }; + + const RUBY_DEFAULT_CONTAINS = [ + STRING, + CLASS_DEFINITION, + INCLUDE_EXTEND, + OBJECT_CREATION, + UPPER_CASE_CONSTANT, + CLASS_REFERENCE, + METHOD_DEFINITION, + { + // swallow namespace qualifiers before symbols + begin: hljs.IDENT_RE + '::' }, + { + className: 'symbol', + begin: hljs.UNDERSCORE_IDENT_RE + '(!|\\?)?:', + relevance: 0 + }, + { + className: 'symbol', + begin: ':(?!\\s)', + contains: [ + STRING, + { begin: RUBY_METHOD_RE } + ], + relevance: 0 + }, + NUMBER, + { + // negative-look forward attempts to prevent false matches like: + // @ident@ or $ident$ that might indicate this is not ruby at all + className: "variable", + begin: '(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])' + `(?![A-Za-z])(?![@$?'])` + }, + { + className: 'params', + begin: /\|/, + end: /\|/, + excludeBegin: true, + excludeEnd: true, + relevance: 0, // this could be a lot of things (in other languages) other than params + keywords: RUBY_KEYWORDS + }, + { // regexp container + begin: '(' + hljs.RE_STARTERS_RE + '|unless)\\s*', + keywords: 'unless', + contains: [ + { + className: 'regexp', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + illegal: /\n/, + variants: [ + { + begin: '/', + end: '/[a-z]*' + }, + { + begin: /%r\{/, + end: /\}[a-z]*/ + }, + { + begin: '%r\\(', + end: '\\)[a-z]*' + }, + { + begin: '%r!', + end: '![a-z]*' + }, + { + begin: '%r\\[', + end: '\\][a-z]*' + } + ] + } + ].concat(IRB_OBJECT, COMMENT_MODES), + relevance: 0 + } + ].concat(IRB_OBJECT, COMMENT_MODES); + + SUBST.contains = RUBY_DEFAULT_CONTAINS; + PARAMS.contains = RUBY_DEFAULT_CONTAINS; + + // >> + // ?> + const SIMPLE_PROMPT = "[>?]>"; + // irb(main):001:0> + const DEFAULT_PROMPT = "[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]"; + const RVM_PROMPT = "(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>"; + + const IRB_DEFAULT = [ + { + begin: /^\s*=>/, + starts: { + end: '$', + contains: RUBY_DEFAULT_CONTAINS + } + }, + { + className: 'meta.prompt', + begin: '^(' + SIMPLE_PROMPT + "|" + DEFAULT_PROMPT + '|' + RVM_PROMPT + ')(?=[ ])', + starts: { + end: '$', + keywords: RUBY_KEYWORDS, + contains: RUBY_DEFAULT_CONTAINS + } + } + ]; + + COMMENT_MODES.unshift(IRB_OBJECT); + + return { + name: 'Ruby', + aliases: [ + 'rb', + 'gemspec', + 'podspec', + 'thor', + 'irb' + ], + keywords: RUBY_KEYWORDS, + illegal: /\/\*/, + contains: [ hljs.SHEBANG({ binary: "ruby" }) ] + .concat(IRB_DEFAULT) + .concat(COMMENT_MODES) + .concat(RUBY_DEFAULT_CONTAINS) + }; + } + + return ruby; + +})(); + + hljs.registerLanguage('ruby', hljsGrammar); + })();/*! `rust` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Rust + Author: Andrey Vlasovskikh + Contributors: Roman Shmatov , Kasper Andersen + Website: https://www.rust-lang.org + Category: common, system + */ + + /** @type LanguageFn */ + function rust(hljs) { + const regex = hljs.regex; + const FUNCTION_INVOKE = { + className: "title.function.invoke", + relevance: 0, + begin: regex.concat( + /\b/, + /(?!let|for|while|if|else|match\b)/, + hljs.IDENT_RE, + regex.lookahead(/\s*\(/)) + }; + const NUMBER_SUFFIX = '([ui](8|16|32|64|128|size)|f(32|64))\?'; + const KEYWORDS = [ + "abstract", + "as", + "async", + "await", + "become", + "box", + "break", + "const", + "continue", + "crate", + "do", + "dyn", + "else", + "enum", + "extern", + "false", + "final", + "fn", + "for", + "if", + "impl", + "in", + "let", + "loop", + "macro", + "match", + "mod", + "move", + "mut", + "override", + "priv", + "pub", + "ref", + "return", + "self", + "Self", + "static", + "struct", + "super", + "trait", + "true", + "try", + "type", + "typeof", + "unsafe", + "unsized", + "use", + "virtual", + "where", + "while", + "yield" + ]; + const LITERALS = [ + "true", + "false", + "Some", + "None", + "Ok", + "Err" + ]; + const BUILTINS = [ + // functions + 'drop ', + // traits + "Copy", + "Send", + "Sized", + "Sync", + "Drop", + "Fn", + "FnMut", + "FnOnce", + "ToOwned", + "Clone", + "Debug", + "PartialEq", + "PartialOrd", + "Eq", + "Ord", + "AsRef", + "AsMut", + "Into", + "From", + "Default", + "Iterator", + "Extend", + "IntoIterator", + "DoubleEndedIterator", + "ExactSizeIterator", + "SliceConcatExt", + "ToString", + // macros + "assert!", + "assert_eq!", + "bitflags!", + "bytes!", + "cfg!", + "col!", + "concat!", + "concat_idents!", + "debug_assert!", + "debug_assert_eq!", + "env!", + "eprintln!", + "panic!", + "file!", + "format!", + "format_args!", + "include_bytes!", + "include_str!", + "line!", + "local_data_key!", + "module_path!", + "option_env!", + "print!", + "println!", + "select!", + "stringify!", + "try!", + "unimplemented!", + "unreachable!", + "vec!", + "write!", + "writeln!", + "macro_rules!", + "assert_ne!", + "debug_assert_ne!" + ]; + const TYPES = [ + "i8", + "i16", + "i32", + "i64", + "i128", + "isize", + "u8", + "u16", + "u32", + "u64", + "u128", + "usize", + "f32", + "f64", + "str", + "char", + "bool", + "Box", + "Option", + "Result", + "String", + "Vec" + ]; + return { + name: 'Rust', + aliases: [ 'rs' ], + keywords: { + $pattern: hljs.IDENT_RE + '!?', + type: TYPES, + keyword: KEYWORDS, + literal: LITERALS, + built_in: BUILTINS + }, + illegal: '' + }, + FUNCTION_INVOKE + ] + }; + } + + return rust; + +})(); + + hljs.registerLanguage('rust', hljsGrammar); + })();/*! `scala` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Scala + Category: functional + Author: Jan Berkel + Contributors: Erik Osheim + Website: https://www.scala-lang.org + */ + + function scala(hljs) { + const regex = hljs.regex; + const ANNOTATION = { + className: 'meta', + begin: '@[A-Za-z]+' + }; + + // used in strings for escaping/interpolation/substitution + const SUBST = { + className: 'subst', + variants: [ + { begin: '\\$[A-Za-z0-9_]+' }, + { + begin: /\$\{/, + end: /\}/ + } + ] + }; + + const STRING = { + className: 'string', + variants: [ + { + begin: '"""', + end: '"""' + }, + { + begin: '"', + end: '"', + illegal: '\\n', + contains: [ hljs.BACKSLASH_ESCAPE ] + }, + { + begin: '[a-z]+"', + end: '"', + illegal: '\\n', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ] + }, + { + className: 'string', + begin: '[a-z]+"""', + end: '"""', + contains: [ SUBST ], + relevance: 10 + } + ] + + }; + + const TYPE = { + className: 'type', + begin: '\\b[A-Z][A-Za-z0-9_]*', + relevance: 0 + }; + + const NAME = { + className: 'title', + begin: /[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/, + relevance: 0 + }; + + const CLASS = { + className: 'class', + beginKeywords: 'class object trait type', + end: /[:={\[\n;]/, + excludeEnd: true, + contains: [ + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + { + beginKeywords: 'extends with', + relevance: 10 + }, + { + begin: /\[/, + end: /\]/, + excludeBegin: true, + excludeEnd: true, + relevance: 0, + contains: [ + TYPE, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + ] + }, + { + className: 'params', + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, + relevance: 0, + contains: [ + TYPE, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + ] + }, + NAME + ] + }; + + const METHOD = { + className: 'function', + beginKeywords: 'def', + end: regex.lookahead(/[:={\[(\n;]/), + contains: [ NAME ] + }; + + const EXTENSION = { + begin: [ + /^\s*/, // Is first token on the line + 'extension', + /\s+(?=[[(])/, // followed by at least one space and `[` or `(` + ], + beginScope: { 2: "keyword", } + }; + + const END = { + begin: [ + /^\s*/, // Is first token on the line + /end/, + /\s+/, + /(extension\b)?/, // `extension` is the only marker that follows an `end` that cannot be captured by another rule. + ], + beginScope: { + 2: "keyword", + 4: "keyword", + } + }; + + // TODO: use negative look-behind in future + // /(?', + /\s+/, + /using/, + /\s+/, + /\S+/ + ], + beginScope: { + 1: "comment", + 3: "keyword", + 5: "type" + }, + end: /$/, + contains: [ + DIRECTIVE_VALUE, + ] + }; + + return { + name: 'Scala', + keywords: { + literal: 'true false null', + keyword: 'type yield lazy override def with val var sealed abstract private trait object if then forSome for while do throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit export enum given transparent' + }, + contains: [ + USING_DIRECTIVE, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + STRING, + TYPE, + METHOD, + CLASS, + hljs.C_NUMBER_MODE, + EXTENSION, + END, + ...INLINE_MODES, + USING_PARAM_CLAUSE, + ANNOTATION + ] + }; + } + + return scala; + +})(); + + hljs.registerLanguage('scala', hljsGrammar); + })();/*! `scheme` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Scheme + Description: Scheme is a programming language in the Lisp family. + (keywords based on http://community.schemewiki.org/?scheme-keywords) + Author: JP Verkamp + Contributors: Ivan Sagalaev + Origin: clojure.js + Website: http://community.schemewiki.org/?what-is-scheme + Category: lisp + */ + + function scheme(hljs) { + const SCHEME_IDENT_RE = '[^\\(\\)\\[\\]\\{\\}",\'`;#|\\\\\\s]+'; + const SCHEME_SIMPLE_NUMBER_RE = '(-|\\+)?\\d+([./]\\d+)?'; + const SCHEME_COMPLEX_NUMBER_RE = SCHEME_SIMPLE_NUMBER_RE + '[+\\-]' + SCHEME_SIMPLE_NUMBER_RE + 'i'; + const KEYWORDS = { + $pattern: SCHEME_IDENT_RE, + built_in: + 'case-lambda call/cc class define-class exit-handler field import ' + + 'inherit init-field interface let*-values let-values let/ec mixin ' + + 'opt-lambda override protect provide public rename require ' + + 'require-for-syntax syntax syntax-case syntax-error unit/sig unless ' + + 'when with-syntax and begin call-with-current-continuation ' + + 'call-with-input-file call-with-output-file case cond define ' + + 'define-syntax delay do dynamic-wind else for-each if lambda let let* ' + + 'let-syntax letrec letrec-syntax map or syntax-rules \' * + , ,@ - ... / ' + + '; < <= = => > >= ` abs acos angle append apply asin assoc assq assv atan ' + + 'boolean? caar cadr call-with-input-file call-with-output-file ' + + 'call-with-values car cdddar cddddr cdr ceiling char->integer ' + + 'char-alphabetic? char-ci<=? char-ci=? char-ci>? ' + + 'char-downcase char-lower-case? char-numeric? char-ready? char-upcase ' + + 'char-upper-case? char-whitespace? char<=? char=? char>? ' + + 'char? close-input-port close-output-port complex? cons cos ' + + 'current-input-port current-output-port denominator display eof-object? ' + + 'eq? equal? eqv? eval even? exact->inexact exact? exp expt floor ' + + 'force gcd imag-part inexact->exact inexact? input-port? integer->char ' + + 'integer? interaction-environment lcm length list list->string ' + + 'list->vector list-ref list-tail list? load log magnitude make-polar ' + + 'make-rectangular make-string make-vector max member memq memv min ' + + 'modulo negative? newline not null-environment null? number->string ' + + 'number? numerator odd? open-input-file open-output-file output-port? ' + + 'pair? peek-char port? positive? procedure? quasiquote quote quotient ' + + 'rational? rationalize read read-char real-part real? remainder reverse ' + + 'round scheme-report-environment set! set-car! set-cdr! sin sqrt string ' + + 'string->list string->number string->symbol string-append string-ci<=? ' + + 'string-ci=? string-ci>? string-copy ' + + 'string-fill! string-length string-ref string-set! string<=? string=? string>? string? substring symbol->string symbol? ' + + 'tan transcript-off transcript-on truncate values vector ' + + 'vector->list vector-fill! vector-length vector-ref vector-set! ' + + 'with-input-from-file with-output-to-file write write-char zero?' + }; + + const LITERAL = { + className: 'literal', + begin: '(#t|#f|#\\\\' + SCHEME_IDENT_RE + '|#\\\\.)' + }; + + const NUMBER = { + className: 'number', + variants: [ + { + begin: SCHEME_SIMPLE_NUMBER_RE, + relevance: 0 + }, + { + begin: SCHEME_COMPLEX_NUMBER_RE, + relevance: 0 + }, + { begin: '#b[0-1]+(/[0-1]+)?' }, + { begin: '#o[0-7]+(/[0-7]+)?' }, + { begin: '#x[0-9a-f]+(/[0-9a-f]+)?' } + ] + }; + + const STRING = hljs.QUOTE_STRING_MODE; + + const COMMENT_MODES = [ + hljs.COMMENT( + ';', + '$', + { relevance: 0 } + ), + hljs.COMMENT('#\\|', '\\|#') + ]; + + const IDENT = { + begin: SCHEME_IDENT_RE, + relevance: 0 + }; + + const QUOTED_IDENT = { + className: 'symbol', + begin: '\'' + SCHEME_IDENT_RE + }; + + const BODY = { + endsWithParent: true, + relevance: 0 + }; + + const QUOTED_LIST = { + variants: [ + { begin: /'/ }, + { begin: '`' } + ], + contains: [ + { + begin: '\\(', + end: '\\)', + contains: [ + 'self', + LITERAL, + STRING, + NUMBER, + IDENT, + QUOTED_IDENT + ] + } + ] + }; + + const NAME = { + className: 'name', + relevance: 0, + begin: SCHEME_IDENT_RE, + keywords: KEYWORDS + }; + + const LAMBDA = { + begin: /lambda/, + endsWithParent: true, + returnBegin: true, + contains: [ + NAME, + { + endsParent: true, + variants: [ + { + begin: /\(/, + end: /\)/ + }, + { + begin: /\[/, + end: /\]/ + } + ], + contains: [ IDENT ] + } + ] + }; + + const LIST = { + variants: [ + { + begin: '\\(', + end: '\\)' + }, + { + begin: '\\[', + end: '\\]' + } + ], + contains: [ + LAMBDA, + NAME, + BODY + ] + }; + + BODY.contains = [ + LITERAL, + NUMBER, + STRING, + IDENT, + QUOTED_IDENT, + QUOTED_LIST, + LIST + ].concat(COMMENT_MODES); + + return { + name: 'Scheme', + aliases: ['scm'], + illegal: /\S/, + contains: [ + hljs.SHEBANG(), + NUMBER, + STRING, + QUOTED_IDENT, + QUOTED_LIST, + LIST + ].concat(COMMENT_MODES) + }; + } + + return scheme; + +})(); + + hljs.registerLanguage('scheme', hljsGrammar); + })();/*! `shell` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Shell Session + Requires: bash.js + Author: TSUYUSATO Kitsune + Category: common + Audit: 2020 + */ + + /** @type LanguageFn */ + function shell(hljs) { + return { + name: 'Shell Session', + aliases: [ + 'console', + 'shellsession' + ], + contains: [ + { + className: 'meta.prompt', + // We cannot add \s (spaces) in the regular expression otherwise it will be too broad and produce unexpected result. + // For instance, in the following example, it would match "echo /path/to/home >" as a prompt: + // echo /path/to/home > t.exe + begin: /^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/, + starts: { + end: /[^\\](?=\s*$)/, + subLanguage: 'bash' + } + } + ] + }; + } + + return shell; + +})(); + + hljs.registerLanguage('shell', hljsGrammar); + })();/*! `smalltalk` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Smalltalk + Description: Smalltalk is an object-oriented, dynamically typed reflective programming language. + Author: Vladimir Gubarkov + Website: https://en.wikipedia.org/wiki/Smalltalk + Category: system + */ + + function smalltalk(hljs) { + const VAR_IDENT_RE = '[a-z][a-zA-Z0-9_]*'; + const CHAR = { + className: 'string', + begin: '\\$.{1}' + }; + const SYMBOL = { + className: 'symbol', + begin: '#' + hljs.UNDERSCORE_IDENT_RE + }; + return { + name: 'Smalltalk', + aliases: [ 'st' ], + keywords: [ + "self", + "super", + "nil", + "true", + "false", + "thisContext" + ], + contains: [ + hljs.COMMENT('"', '"'), + hljs.APOS_STRING_MODE, + { + className: 'type', + begin: '\\b[A-Z][A-Za-z0-9_]*', + relevance: 0 + }, + { + begin: VAR_IDENT_RE + ':', + relevance: 0 + }, + hljs.C_NUMBER_MODE, + SYMBOL, + CHAR, + { + // This looks more complicated than needed to avoid combinatorial + // explosion under V8. It effectively means `| var1 var2 ... |` with + // whitespace adjacent to `|` being optional. + begin: '\\|[ ]*' + VAR_IDENT_RE + '([ ]+' + VAR_IDENT_RE + ')*[ ]*\\|', + returnBegin: true, + end: /\|/, + illegal: /\S/, + contains: [ { begin: '(\\|[ ]*)?' + VAR_IDENT_RE } ] + }, + { + begin: '#\\(', + end: '\\)', + contains: [ + hljs.APOS_STRING_MODE, + CHAR, + hljs.C_NUMBER_MODE, + SYMBOL + ] + } + ] + }; + } + + return smalltalk; + +})(); + + hljs.registerLanguage('smalltalk', hljsGrammar); + })();/*! `sql` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: SQL + Website: https://en.wikipedia.org/wiki/SQL + Category: common, database + */ + + /* + + Goals: + + SQL is intended to highlight basic/common SQL keywords and expressions + + - If pretty much every single SQL server includes supports, then it's a canidate. + - It is NOT intended to include tons of vendor specific keywords (Oracle, MySQL, + PostgreSQL) although the list of data types is purposely a bit more expansive. + - For more specific SQL grammars please see: + - PostgreSQL and PL/pgSQL - core + - T-SQL - https://github.com/highlightjs/highlightjs-tsql + - sql_more (core) + + */ + + function sql(hljs) { + const regex = hljs.regex; + const COMMENT_MODE = hljs.COMMENT('--', '$'); + const STRING = { + className: 'string', + variants: [ + { + begin: /'/, + end: /'/, + contains: [ { begin: /''/ } ] + } + ] + }; + const QUOTED_IDENTIFIER = { + begin: /"/, + end: /"/, + contains: [ { begin: /""/ } ] + }; + + const LITERALS = [ + "true", + "false", + // Not sure it's correct to call NULL literal, and clauses like IS [NOT] NULL look strange that way. + // "null", + "unknown" + ]; + + const MULTI_WORD_TYPES = [ + "double precision", + "large object", + "with timezone", + "without timezone" + ]; + + const TYPES = [ + 'bigint', + 'binary', + 'blob', + 'boolean', + 'char', + 'character', + 'clob', + 'date', + 'dec', + 'decfloat', + 'decimal', + 'float', + 'int', + 'integer', + 'interval', + 'nchar', + 'nclob', + 'national', + 'numeric', + 'real', + 'row', + 'smallint', + 'time', + 'timestamp', + 'varchar', + 'varying', // modifier (character varying) + 'varbinary' + ]; + + const NON_RESERVED_WORDS = [ + "add", + "asc", + "collation", + "desc", + "final", + "first", + "last", + "view" + ]; + + // https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#reserved-word + const RESERVED_WORDS = [ + "abs", + "acos", + "all", + "allocate", + "alter", + "and", + "any", + "are", + "array", + "array_agg", + "array_max_cardinality", + "as", + "asensitive", + "asin", + "asymmetric", + "at", + "atan", + "atomic", + "authorization", + "avg", + "begin", + "begin_frame", + "begin_partition", + "between", + "bigint", + "binary", + "blob", + "boolean", + "both", + "by", + "call", + "called", + "cardinality", + "cascaded", + "case", + "cast", + "ceil", + "ceiling", + "char", + "char_length", + "character", + "character_length", + "check", + "classifier", + "clob", + "close", + "coalesce", + "collate", + "collect", + "column", + "commit", + "condition", + "connect", + "constraint", + "contains", + "convert", + "copy", + "corr", + "corresponding", + "cos", + "cosh", + "count", + "covar_pop", + "covar_samp", + "create", + "cross", + "cube", + "cume_dist", + "current", + "current_catalog", + "current_date", + "current_default_transform_group", + "current_path", + "current_role", + "current_row", + "current_schema", + "current_time", + "current_timestamp", + "current_path", + "current_role", + "current_transform_group_for_type", + "current_user", + "cursor", + "cycle", + "date", + "day", + "deallocate", + "dec", + "decimal", + "decfloat", + "declare", + "default", + "define", + "delete", + "dense_rank", + "deref", + "describe", + "deterministic", + "disconnect", + "distinct", + "double", + "drop", + "dynamic", + "each", + "element", + "else", + "empty", + "end", + "end_frame", + "end_partition", + "end-exec", + "equals", + "escape", + "every", + "except", + "exec", + "execute", + "exists", + "exp", + "external", + "extract", + "false", + "fetch", + "filter", + "first_value", + "float", + "floor", + "for", + "foreign", + "frame_row", + "free", + "from", + "full", + "function", + "fusion", + "get", + "global", + "grant", + "group", + "grouping", + "groups", + "having", + "hold", + "hour", + "identity", + "in", + "indicator", + "initial", + "inner", + "inout", + "insensitive", + "insert", + "int", + "integer", + "intersect", + "intersection", + "interval", + "into", + "is", + "join", + "json_array", + "json_arrayagg", + "json_exists", + "json_object", + "json_objectagg", + "json_query", + "json_table", + "json_table_primitive", + "json_value", + "lag", + "language", + "large", + "last_value", + "lateral", + "lead", + "leading", + "left", + "like", + "like_regex", + "listagg", + "ln", + "local", + "localtime", + "localtimestamp", + "log", + "log10", + "lower", + "match", + "match_number", + "match_recognize", + "matches", + "max", + "member", + "merge", + "method", + "min", + "minute", + "mod", + "modifies", + "module", + "month", + "multiset", + "national", + "natural", + "nchar", + "nclob", + "new", + "no", + "none", + "normalize", + "not", + "nth_value", + "ntile", + "null", + "nullif", + "numeric", + "octet_length", + "occurrences_regex", + "of", + "offset", + "old", + "omit", + "on", + "one", + "only", + "open", + "or", + "order", + "out", + "outer", + "over", + "overlaps", + "overlay", + "parameter", + "partition", + "pattern", + "per", + "percent", + "percent_rank", + "percentile_cont", + "percentile_disc", + "period", + "portion", + "position", + "position_regex", + "power", + "precedes", + "precision", + "prepare", + "primary", + "procedure", + "ptf", + "range", + "rank", + "reads", + "real", + "recursive", + "ref", + "references", + "referencing", + "regr_avgx", + "regr_avgy", + "regr_count", + "regr_intercept", + "regr_r2", + "regr_slope", + "regr_sxx", + "regr_sxy", + "regr_syy", + "release", + "result", + "return", + "returns", + "revoke", + "right", + "rollback", + "rollup", + "row", + "row_number", + "rows", + "running", + "savepoint", + "scope", + "scroll", + "search", + "second", + "seek", + "select", + "sensitive", + "session_user", + "set", + "show", + "similar", + "sin", + "sinh", + "skip", + "smallint", + "some", + "specific", + "specifictype", + "sql", + "sqlexception", + "sqlstate", + "sqlwarning", + "sqrt", + "start", + "static", + "stddev_pop", + "stddev_samp", + "submultiset", + "subset", + "substring", + "substring_regex", + "succeeds", + "sum", + "symmetric", + "system", + "system_time", + "system_user", + "table", + "tablesample", + "tan", + "tanh", + "then", + "time", + "timestamp", + "timezone_hour", + "timezone_minute", + "to", + "trailing", + "translate", + "translate_regex", + "translation", + "treat", + "trigger", + "trim", + "trim_array", + "true", + "truncate", + "uescape", + "union", + "unique", + "unknown", + "unnest", + "update", + "upper", + "user", + "using", + "value", + "values", + "value_of", + "var_pop", + "var_samp", + "varbinary", + "varchar", + "varying", + "versioning", + "when", + "whenever", + "where", + "width_bucket", + "window", + "with", + "within", + "without", + "year", + ]; + + // these are reserved words we have identified to be functions + // and should only be highlighted in a dispatch-like context + // ie, array_agg(...), etc. + const RESERVED_FUNCTIONS = [ + "abs", + "acos", + "array_agg", + "asin", + "atan", + "avg", + "cast", + "ceil", + "ceiling", + "coalesce", + "corr", + "cos", + "cosh", + "count", + "covar_pop", + "covar_samp", + "cume_dist", + "dense_rank", + "deref", + "element", + "exp", + "extract", + "first_value", + "floor", + "json_array", + "json_arrayagg", + "json_exists", + "json_object", + "json_objectagg", + "json_query", + "json_table", + "json_table_primitive", + "json_value", + "lag", + "last_value", + "lead", + "listagg", + "ln", + "log", + "log10", + "lower", + "max", + "min", + "mod", + "nth_value", + "ntile", + "nullif", + "percent_rank", + "percentile_cont", + "percentile_disc", + "position", + "position_regex", + "power", + "rank", + "regr_avgx", + "regr_avgy", + "regr_count", + "regr_intercept", + "regr_r2", + "regr_slope", + "regr_sxx", + "regr_sxy", + "regr_syy", + "row_number", + "sin", + "sinh", + "sqrt", + "stddev_pop", + "stddev_samp", + "substring", + "substring_regex", + "sum", + "tan", + "tanh", + "translate", + "translate_regex", + "treat", + "trim", + "trim_array", + "unnest", + "upper", + "value_of", + "var_pop", + "var_samp", + "width_bucket", + ]; + + // these functions can + const POSSIBLE_WITHOUT_PARENS = [ + "current_catalog", + "current_date", + "current_default_transform_group", + "current_path", + "current_role", + "current_schema", + "current_transform_group_for_type", + "current_user", + "session_user", + "system_time", + "system_user", + "current_time", + "localtime", + "current_timestamp", + "localtimestamp" + ]; + + // those exist to boost relevance making these very + // "SQL like" keyword combos worth +1 extra relevance + const COMBOS = [ + "create table", + "insert into", + "primary key", + "foreign key", + "not null", + "alter table", + "add constraint", + "grouping sets", + "on overflow", + "character set", + "respect nulls", + "ignore nulls", + "nulls first", + "nulls last", + "depth first", + "breadth first" + ]; + + const FUNCTIONS = RESERVED_FUNCTIONS; + + const KEYWORDS = [ + ...RESERVED_WORDS, + ...NON_RESERVED_WORDS + ].filter((keyword) => { + return !RESERVED_FUNCTIONS.includes(keyword); + }); + + const VARIABLE = { + className: "variable", + begin: /@[a-z0-9][a-z0-9_]*/, + }; + + const OPERATOR = { + className: "operator", + begin: /[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, + relevance: 0, + }; + + const FUNCTION_CALL = { + begin: regex.concat(/\b/, regex.either(...FUNCTIONS), /\s*\(/), + relevance: 0, + keywords: { built_in: FUNCTIONS } + }; + + // keywords with less than 3 letters are reduced in relevancy + function reduceRelevancy(list, { + exceptions, when + } = {}) { + const qualifyFn = when; + exceptions = exceptions || []; + return list.map((item) => { + if (item.match(/\|\d+$/) || exceptions.includes(item)) { + return item; + } else if (qualifyFn(item)) { + return `${item}|0`; + } else { + return item; + } + }); + } + + return { + name: 'SQL', + case_insensitive: true, + // does not include {} or HTML tags ` x.length < 3 }), + literal: LITERALS, + type: TYPES, + built_in: POSSIBLE_WITHOUT_PARENS + }, + contains: [ + { + begin: regex.either(...COMBOS), + relevance: 0, + keywords: { + $pattern: /[\w\.]+/, + keyword: KEYWORDS.concat(COMBOS), + literal: LITERALS, + type: TYPES + }, + }, + { + className: "type", + begin: regex.either(...MULTI_WORD_TYPES) + }, + FUNCTION_CALL, + VARIABLE, + STRING, + QUOTED_IDENTIFIER, + hljs.C_NUMBER_MODE, + hljs.C_BLOCK_COMMENT_MODE, + COMMENT_MODE, + OPERATOR + ] + }; + } + + return sql; + +})(); + + hljs.registerLanguage('sql', hljsGrammar); + })();/*! `swift` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /** + * @param {string} value + * @returns {RegExp} + * */ + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function source(re) { + if (!re) return null; + if (typeof re === "string") return re; + + return re.source; + } + + /** + * @param {RegExp | string } re + * @returns {string} + */ + function lookahead(re) { + return concat('(?=', re, ')'); + } + + /** + * @param {...(RegExp | string) } args + * @returns {string} + */ + function concat(...args) { + const joined = args.map((x) => source(x)).join(""); + return joined; + } + + /** + * @param { Array } args + * @returns {object} + */ + function stripOptionsFromArgs(args) { + const opts = args[args.length - 1]; + + if (typeof opts === 'object' && opts.constructor === Object) { + args.splice(args.length - 1, 1); + return opts; + } else { + return {}; + } + } + + /** @typedef { {capture?: boolean} } RegexEitherOptions */ + + /** + * Any of the passed expresssions may match + * + * Creates a huge this | this | that | that match + * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args + * @returns {string} + */ + function either(...args) { + /** @type { object & {capture?: boolean} } */ + const opts = stripOptionsFromArgs(args); + const joined = '(' + + (opts.capture ? "" : "?:") + + args.map((x) => source(x)).join("|") + ")"; + return joined; + } + + const keywordWrapper = keyword => concat( + /\b/, + keyword, + /\w$/.test(keyword) ? /\b/ : /\B/ + ); + + // Keywords that require a leading dot. + const dotKeywords = [ + 'Protocol', // contextual + 'Type' // contextual + ].map(keywordWrapper); + + // Keywords that may have a leading dot. + const optionalDotKeywords = [ + 'init', + 'self' + ].map(keywordWrapper); + + // should register as keyword, not type + const keywordTypes = [ + 'Any', + 'Self' + ]; + + // Regular keywords and literals. + const keywords = [ + // strings below will be fed into the regular `keywords` engine while regex + // will result in additional modes being created to scan for those keywords to + // avoid conflicts with other rules + 'actor', + 'any', // contextual + 'associatedtype', + 'async', + 'await', + /as\?/, // operator + /as!/, // operator + 'as', // operator + 'borrowing', // contextual + 'break', + 'case', + 'catch', + 'class', + 'consume', // contextual + 'consuming', // contextual + 'continue', + 'convenience', // contextual + 'copy', // contextual + 'default', + 'defer', + 'deinit', + 'didSet', // contextual + 'distributed', + 'do', + 'dynamic', // contextual + 'each', + 'else', + 'enum', + 'extension', + 'fallthrough', + /fileprivate\(set\)/, + 'fileprivate', + 'final', // contextual + 'for', + 'func', + 'get', // contextual + 'guard', + 'if', + 'import', + 'indirect', // contextual + 'infix', // contextual + /init\?/, + /init!/, + 'inout', + /internal\(set\)/, + 'internal', + 'in', + 'is', // operator + 'isolated', // contextual + 'nonisolated', // contextual + 'lazy', // contextual + 'let', + 'macro', + 'mutating', // contextual + 'nonmutating', // contextual + /open\(set\)/, // contextual + 'open', // contextual + 'operator', + 'optional', // contextual + 'override', // contextual + 'postfix', // contextual + 'precedencegroup', + 'prefix', // contextual + /private\(set\)/, + 'private', + 'protocol', + /public\(set\)/, + 'public', + 'repeat', + 'required', // contextual + 'rethrows', + 'return', + 'set', // contextual + 'some', // contextual + 'static', + 'struct', + 'subscript', + 'super', + 'switch', + 'throws', + 'throw', + /try\?/, // operator + /try!/, // operator + 'try', // operator + 'typealias', + /unowned\(safe\)/, // contextual + /unowned\(unsafe\)/, // contextual + 'unowned', // contextual + 'var', + 'weak', // contextual + 'where', + 'while', + 'willSet' // contextual + ]; + + // NOTE: Contextual keywords are reserved only in specific contexts. + // Ideally, these should be matched using modes to avoid false positives. + + // Literals. + const literals = [ + 'false', + 'nil', + 'true' + ]; + + // Keywords used in precedence groups. + const precedencegroupKeywords = [ + 'assignment', + 'associativity', + 'higherThan', + 'left', + 'lowerThan', + 'none', + 'right' + ]; + + // Keywords that start with a number sign (#). + // #(un)available is handled separately. + const numberSignKeywords = [ + '#colorLiteral', + '#column', + '#dsohandle', + '#else', + '#elseif', + '#endif', + '#error', + '#file', + '#fileID', + '#fileLiteral', + '#filePath', + '#function', + '#if', + '#imageLiteral', + '#keyPath', + '#line', + '#selector', + '#sourceLocation', + '#warning' + ]; + + // Global functions in the Standard Library. + const builtIns = [ + 'abs', + 'all', + 'any', + 'assert', + 'assertionFailure', + 'debugPrint', + 'dump', + 'fatalError', + 'getVaList', + 'isKnownUniquelyReferenced', + 'max', + 'min', + 'numericCast', + 'pointwiseMax', + 'pointwiseMin', + 'precondition', + 'preconditionFailure', + 'print', + 'readLine', + 'repeatElement', + 'sequence', + 'stride', + 'swap', + 'swift_unboxFromSwiftValueWithType', + 'transcode', + 'type', + 'unsafeBitCast', + 'unsafeDowncast', + 'withExtendedLifetime', + 'withUnsafeMutablePointer', + 'withUnsafePointer', + 'withVaList', + 'withoutActuallyEscaping', + 'zip' + ]; + + // Valid first characters for operators. + const operatorHead = either( + /[/=\-+!*%<>&|^~?]/, + /[\u00A1-\u00A7]/, + /[\u00A9\u00AB]/, + /[\u00AC\u00AE]/, + /[\u00B0\u00B1]/, + /[\u00B6\u00BB\u00BF\u00D7\u00F7]/, + /[\u2016-\u2017]/, + /[\u2020-\u2027]/, + /[\u2030-\u203E]/, + /[\u2041-\u2053]/, + /[\u2055-\u205E]/, + /[\u2190-\u23FF]/, + /[\u2500-\u2775]/, + /[\u2794-\u2BFF]/, + /[\u2E00-\u2E7F]/, + /[\u3001-\u3003]/, + /[\u3008-\u3020]/, + /[\u3030]/ + ); + + // Valid characters for operators. + const operatorCharacter = either( + operatorHead, + /[\u0300-\u036F]/, + /[\u1DC0-\u1DFF]/, + /[\u20D0-\u20FF]/, + /[\uFE00-\uFE0F]/, + /[\uFE20-\uFE2F]/ + // TODO: The following characters are also allowed, but the regex isn't supported yet. + // /[\u{E0100}-\u{E01EF}]/u + ); + + // Valid operator. + const operator = concat(operatorHead, operatorCharacter, '*'); + + // Valid first characters for identifiers. + const identifierHead = either( + /[a-zA-Z_]/, + /[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/, + /[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/, + /[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/, + /[\u1E00-\u1FFF]/, + /[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/, + /[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/, + /[\u2C00-\u2DFF\u2E80-\u2FFF]/, + /[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/, + /[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/, + /[\uFE47-\uFEFE\uFF00-\uFFFD]/ // Should be /[\uFE47-\uFFFD]/, but we have to exclude FEFF. + // The following characters are also allowed, but the regexes aren't supported yet. + // /[\u{10000}-\u{1FFFD}\u{20000-\u{2FFFD}\u{30000}-\u{3FFFD}\u{40000}-\u{4FFFD}]/u, + // /[\u{50000}-\u{5FFFD}\u{60000-\u{6FFFD}\u{70000}-\u{7FFFD}\u{80000}-\u{8FFFD}]/u, + // /[\u{90000}-\u{9FFFD}\u{A0000-\u{AFFFD}\u{B0000}-\u{BFFFD}\u{C0000}-\u{CFFFD}]/u, + // /[\u{D0000}-\u{DFFFD}\u{E0000-\u{EFFFD}]/u + ); + + // Valid characters for identifiers. + const identifierCharacter = either( + identifierHead, + /\d/, + /[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/ + ); + + // Valid identifier. + const identifier = concat(identifierHead, identifierCharacter, '*'); + + // Valid type identifier. + const typeIdentifier = concat(/[A-Z]/, identifierCharacter, '*'); + + // Built-in attributes, which are highlighted as keywords. + // @available is handled separately. + // https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes + const keywordAttributes = [ + 'attached', + 'autoclosure', + concat(/convention\(/, either('swift', 'block', 'c'), /\)/), + 'discardableResult', + 'dynamicCallable', + 'dynamicMemberLookup', + 'escaping', + 'freestanding', + 'frozen', + 'GKInspectable', + 'IBAction', + 'IBDesignable', + 'IBInspectable', + 'IBOutlet', + 'IBSegueAction', + 'inlinable', + 'main', + 'nonobjc', + 'NSApplicationMain', + 'NSCopying', + 'NSManaged', + concat(/objc\(/, identifier, /\)/), + 'objc', + 'objcMembers', + 'propertyWrapper', + 'requires_stored_property_inits', + 'resultBuilder', + 'Sendable', + 'testable', + 'UIApplicationMain', + 'unchecked', + 'unknown', + 'usableFromInline', + 'warn_unqualified_access' + ]; + + // Contextual keywords used in @available and #(un)available. + const availabilityKeywords = [ + 'iOS', + 'iOSApplicationExtension', + 'macOS', + 'macOSApplicationExtension', + 'macCatalyst', + 'macCatalystApplicationExtension', + 'watchOS', + 'watchOSApplicationExtension', + 'tvOS', + 'tvOSApplicationExtension', + 'swift' + ]; + + /* + Language: Swift + Description: Swift is a general-purpose programming language built using a modern approach to safety, performance, and software design patterns. + Author: Steven Van Impe + Contributors: Chris Eidhof , Nate Cook , Alexander Lichter , Richard Gibson + Website: https://swift.org + Category: common, system + */ + + + /** @type LanguageFn */ + function swift(hljs) { + const WHITESPACE = { + match: /\s+/, + relevance: 0 + }; + // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID411 + const BLOCK_COMMENT = hljs.COMMENT( + '/\\*', + '\\*/', + { contains: [ 'self' ] } + ); + const COMMENTS = [ + hljs.C_LINE_COMMENT_MODE, + BLOCK_COMMENT + ]; + + // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID413 + // https://docs.swift.org/swift-book/ReferenceManual/zzSummaryOfTheGrammar.html + const DOT_KEYWORD = { + match: [ + /\./, + either(...dotKeywords, ...optionalDotKeywords) + ], + className: { 2: "keyword" } + }; + const KEYWORD_GUARD = { + // Consume .keyword to prevent highlighting properties and methods as keywords. + match: concat(/\./, either(...keywords)), + relevance: 0 + }; + const PLAIN_KEYWORDS = keywords + .filter(kw => typeof kw === 'string') + .concat([ "_|0" ]); // seems common, so 0 relevance + const REGEX_KEYWORDS = keywords + .filter(kw => typeof kw !== 'string') // find regex + .concat(keywordTypes) + .map(keywordWrapper); + const KEYWORD = { variants: [ + { + className: 'keyword', + match: either(...REGEX_KEYWORDS, ...optionalDotKeywords) + } + ] }; + // find all the regular keywords + const KEYWORDS = { + $pattern: either( + /\b\w+/, // regular keywords + /#\w+/ // number keywords + ), + keyword: PLAIN_KEYWORDS + .concat(numberSignKeywords), + literal: literals + }; + const KEYWORD_MODES = [ + DOT_KEYWORD, + KEYWORD_GUARD, + KEYWORD + ]; + + // https://github.com/apple/swift/tree/main/stdlib/public/core + const BUILT_IN_GUARD = { + // Consume .built_in to prevent highlighting properties and methods. + match: concat(/\./, either(...builtIns)), + relevance: 0 + }; + const BUILT_IN = { + className: 'built_in', + match: concat(/\b/, either(...builtIns), /(?=\()/) + }; + const BUILT_INS = [ + BUILT_IN_GUARD, + BUILT_IN + ]; + + // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418 + const OPERATOR_GUARD = { + // Prevent -> from being highlighting as an operator. + match: /->/, + relevance: 0 + }; + const OPERATOR = { + className: 'operator', + relevance: 0, + variants: [ + { match: operator }, + { + // dot-operator: only operators that start with a dot are allowed to use dots as + // characters (..., ...<, .*, etc). So there rule here is: a dot followed by one or more + // characters that may also include dots. + match: `\\.(\\.|${operatorCharacter})+` } + ] + }; + const OPERATORS = [ + OPERATOR_GUARD, + OPERATOR + ]; + + // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#grammar_numeric-literal + // TODO: Update for leading `-` after lookbehind is supported everywhere + const decimalDigits = '([0-9]_*)+'; + const hexDigits = '([0-9a-fA-F]_*)+'; + const NUMBER = { + className: 'number', + relevance: 0, + variants: [ + // decimal floating-point-literal (subsumes decimal-literal) + { match: `\\b(${decimalDigits})(\\.(${decimalDigits}))?` + `([eE][+-]?(${decimalDigits}))?\\b` }, + // hexadecimal floating-point-literal (subsumes hexadecimal-literal) + { match: `\\b0x(${hexDigits})(\\.(${hexDigits}))?` + `([pP][+-]?(${decimalDigits}))?\\b` }, + // octal-literal + { match: /\b0o([0-7]_*)+\b/ }, + // binary-literal + { match: /\b0b([01]_*)+\b/ } + ] + }; + + // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#grammar_string-literal + const ESCAPED_CHARACTER = (rawDelimiter = "") => ({ + className: 'subst', + variants: [ + { match: concat(/\\/, rawDelimiter, /[0\\tnr"']/) }, + { match: concat(/\\/, rawDelimiter, /u\{[0-9a-fA-F]{1,8}\}/) } + ] + }); + const ESCAPED_NEWLINE = (rawDelimiter = "") => ({ + className: 'subst', + match: concat(/\\/, rawDelimiter, /[\t ]*(?:[\r\n]|\r\n)/) + }); + const INTERPOLATION = (rawDelimiter = "") => ({ + className: 'subst', + label: "interpol", + begin: concat(/\\/, rawDelimiter, /\(/), + end: /\)/ + }); + const MULTILINE_STRING = (rawDelimiter = "") => ({ + begin: concat(rawDelimiter, /"""/), + end: concat(/"""/, rawDelimiter), + contains: [ + ESCAPED_CHARACTER(rawDelimiter), + ESCAPED_NEWLINE(rawDelimiter), + INTERPOLATION(rawDelimiter) + ] + }); + const SINGLE_LINE_STRING = (rawDelimiter = "") => ({ + begin: concat(rawDelimiter, /"/), + end: concat(/"/, rawDelimiter), + contains: [ + ESCAPED_CHARACTER(rawDelimiter), + INTERPOLATION(rawDelimiter) + ] + }); + const STRING = { + className: 'string', + variants: [ + MULTILINE_STRING(), + MULTILINE_STRING("#"), + MULTILINE_STRING("##"), + MULTILINE_STRING("###"), + SINGLE_LINE_STRING(), + SINGLE_LINE_STRING("#"), + SINGLE_LINE_STRING("##"), + SINGLE_LINE_STRING("###") + ] + }; + + const REGEXP_CONTENTS = [ + hljs.BACKSLASH_ESCAPE, + { + begin: /\[/, + end: /\]/, + relevance: 0, + contains: [ hljs.BACKSLASH_ESCAPE ] + } + ]; + + const BARE_REGEXP_LITERAL = { + begin: /\/[^\s](?=[^/\n]*\/)/, + end: /\//, + contains: REGEXP_CONTENTS + }; + + const EXTENDED_REGEXP_LITERAL = (rawDelimiter) => { + const begin = concat(rawDelimiter, /\//); + const end = concat(/\//, rawDelimiter); + return { + begin, + end, + contains: [ + ...REGEXP_CONTENTS, + { + scope: "comment", + begin: `#(?!.*${end})`, + end: /$/, + }, + ], + }; + }; + + // https://docs.swift.org/swift-book/documentation/the-swift-programming-language/lexicalstructure/#Regular-Expression-Literals + const REGEXP = { + scope: "regexp", + variants: [ + EXTENDED_REGEXP_LITERAL('###'), + EXTENDED_REGEXP_LITERAL('##'), + EXTENDED_REGEXP_LITERAL('#'), + BARE_REGEXP_LITERAL + ] + }; + + // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID412 + const QUOTED_IDENTIFIER = { match: concat(/`/, identifier, /`/) }; + const IMPLICIT_PARAMETER = { + className: 'variable', + match: /\$\d+/ + }; + const PROPERTY_WRAPPER_PROJECTION = { + className: 'variable', + match: `\\$${identifierCharacter}+` + }; + const IDENTIFIERS = [ + QUOTED_IDENTIFIER, + IMPLICIT_PARAMETER, + PROPERTY_WRAPPER_PROJECTION + ]; + + // https://docs.swift.org/swift-book/ReferenceManual/Attributes.html + const AVAILABLE_ATTRIBUTE = { + match: /(@|#(un)?)available/, + scope: 'keyword', + starts: { contains: [ + { + begin: /\(/, + end: /\)/, + keywords: availabilityKeywords, + contains: [ + ...OPERATORS, + NUMBER, + STRING + ] + } + ] } + }; + const KEYWORD_ATTRIBUTE = { + scope: 'keyword', + match: concat(/@/, either(...keywordAttributes)) + }; + const USER_DEFINED_ATTRIBUTE = { + scope: 'meta', + match: concat(/@/, identifier) + }; + const ATTRIBUTES = [ + AVAILABLE_ATTRIBUTE, + KEYWORD_ATTRIBUTE, + USER_DEFINED_ATTRIBUTE + ]; + + // https://docs.swift.org/swift-book/ReferenceManual/Types.html + const TYPE = { + match: lookahead(/\b[A-Z]/), + relevance: 0, + contains: [ + { // Common Apple frameworks, for relevance boost + className: 'type', + match: concat(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/, identifierCharacter, '+') + }, + { // Type identifier + className: 'type', + match: typeIdentifier, + relevance: 0 + }, + { // Optional type + match: /[?!]+/, + relevance: 0 + }, + { // Variadic parameter + match: /\.\.\./, + relevance: 0 + }, + { // Protocol composition + match: concat(/\s+&\s+/, lookahead(typeIdentifier)), + relevance: 0 + } + ] + }; + const GENERIC_ARGUMENTS = { + begin: //, + keywords: KEYWORDS, + contains: [ + ...COMMENTS, + ...KEYWORD_MODES, + ...ATTRIBUTES, + OPERATOR_GUARD, + TYPE + ] + }; + TYPE.contains.push(GENERIC_ARGUMENTS); + + // https://docs.swift.org/swift-book/ReferenceManual/Expressions.html#ID552 + // Prevents element names from being highlighted as keywords. + const TUPLE_ELEMENT_NAME = { + match: concat(identifier, /\s*:/), + keywords: "_|0", + relevance: 0 + }; + // Matches tuples as well as the parameter list of a function type. + const TUPLE = { + begin: /\(/, + end: /\)/, + relevance: 0, + keywords: KEYWORDS, + contains: [ + 'self', + TUPLE_ELEMENT_NAME, + ...COMMENTS, + REGEXP, + ...KEYWORD_MODES, + ...BUILT_INS, + ...OPERATORS, + NUMBER, + STRING, + ...IDENTIFIERS, + ...ATTRIBUTES, + TYPE + ] + }; + + const GENERIC_PARAMETERS = { + begin: //, + keywords: 'repeat each', + contains: [ + ...COMMENTS, + TYPE + ] + }; + const FUNCTION_PARAMETER_NAME = { + begin: either( + lookahead(concat(identifier, /\s*:/)), + lookahead(concat(identifier, /\s+/, identifier, /\s*:/)) + ), + end: /:/, + relevance: 0, + contains: [ + { + className: 'keyword', + match: /\b_\b/ + }, + { + className: 'params', + match: identifier + } + ] + }; + const FUNCTION_PARAMETERS = { + begin: /\(/, + end: /\)/, + keywords: KEYWORDS, + contains: [ + FUNCTION_PARAMETER_NAME, + ...COMMENTS, + ...KEYWORD_MODES, + ...OPERATORS, + NUMBER, + STRING, + ...ATTRIBUTES, + TYPE, + TUPLE + ], + endsParent: true, + illegal: /["']/ + }; + // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID362 + // https://docs.swift.org/swift-book/documentation/the-swift-programming-language/declarations/#Macro-Declaration + const FUNCTION_OR_MACRO = { + match: [ + /(func|macro)/, + /\s+/, + either(QUOTED_IDENTIFIER.match, identifier, operator) + ], + className: { + 1: "keyword", + 3: "title.function" + }, + contains: [ + GENERIC_PARAMETERS, + FUNCTION_PARAMETERS, + WHITESPACE + ], + illegal: [ + /\[/, + /%/ + ] + }; + + // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID375 + // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID379 + const INIT_SUBSCRIPT = { + match: [ + /\b(?:subscript|init[?!]?)/, + /\s*(?=[<(])/, + ], + className: { 1: "keyword" }, + contains: [ + GENERIC_PARAMETERS, + FUNCTION_PARAMETERS, + WHITESPACE + ], + illegal: /\[|%/ + }; + // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID380 + const OPERATOR_DECLARATION = { + match: [ + /operator/, + /\s+/, + operator + ], + className: { + 1: "keyword", + 3: "title" + } + }; + + // https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#ID550 + const PRECEDENCEGROUP = { + begin: [ + /precedencegroup/, + /\s+/, + typeIdentifier + ], + className: { + 1: "keyword", + 3: "title" + }, + contains: [ TYPE ], + keywords: [ + ...precedencegroupKeywords, + ...literals + ], + end: /}/ + }; + + // Add supported submodes to string interpolation. + for (const variant of STRING.variants) { + const interpolation = variant.contains.find(mode => mode.label === "interpol"); + // TODO: Interpolation can contain any expression, so there's room for improvement here. + interpolation.keywords = KEYWORDS; + const submodes = [ + ...KEYWORD_MODES, + ...BUILT_INS, + ...OPERATORS, + NUMBER, + STRING, + ...IDENTIFIERS + ]; + interpolation.contains = [ + ...submodes, + { + begin: /\(/, + end: /\)/, + contains: [ + 'self', + ...submodes + ] + } + ]; + } + + return { + name: 'Swift', + keywords: KEYWORDS, + contains: [ + ...COMMENTS, + FUNCTION_OR_MACRO, + INIT_SUBSCRIPT, + { + beginKeywords: 'struct protocol class extension enum actor', + end: '\\{', + excludeEnd: true, + keywords: KEYWORDS, + contains: [ + hljs.inherit(hljs.TITLE_MODE, { + className: "title.class", + begin: /[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/ + }), + ...KEYWORD_MODES + ] + }, + OPERATOR_DECLARATION, + PRECEDENCEGROUP, + { + beginKeywords: 'import', + end: /$/, + contains: [ ...COMMENTS ], + relevance: 0 + }, + REGEXP, + ...KEYWORD_MODES, + ...BUILT_INS, + ...OPERATORS, + NUMBER, + STRING, + ...IDENTIFIERS, + ...ATTRIBUTES, + TYPE, + TUPLE + ] + }; + } + + return swift; + +})(); + + hljs.registerLanguage('swift', hljsGrammar); + })();/*! `typescript` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + const IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*'; + const KEYWORDS = [ + "as", // for exports + "in", + "of", + "if", + "for", + "while", + "finally", + "var", + "new", + "function", + "do", + "return", + "void", + "else", + "break", + "catch", + "instanceof", + "with", + "throw", + "case", + "default", + "try", + "switch", + "continue", + "typeof", + "delete", + "let", + "yield", + "const", + "class", + // JS handles these with a special rule + // "get", + // "set", + "debugger", + "async", + "await", + "static", + "import", + "from", + "export", + "extends" + ]; + const LITERALS = [ + "true", + "false", + "null", + "undefined", + "NaN", + "Infinity" + ]; + + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects + const TYPES = [ + // Fundamental objects + "Object", + "Function", + "Boolean", + "Symbol", + // numbers and dates + "Math", + "Date", + "Number", + "BigInt", + // text + "String", + "RegExp", + // Indexed collections + "Array", + "Float32Array", + "Float64Array", + "Int8Array", + "Uint8Array", + "Uint8ClampedArray", + "Int16Array", + "Int32Array", + "Uint16Array", + "Uint32Array", + "BigInt64Array", + "BigUint64Array", + // Keyed collections + "Set", + "Map", + "WeakSet", + "WeakMap", + // Structured data + "ArrayBuffer", + "SharedArrayBuffer", + "Atomics", + "DataView", + "JSON", + // Control abstraction objects + "Promise", + "Generator", + "GeneratorFunction", + "AsyncFunction", + // Reflection + "Reflect", + "Proxy", + // Internationalization + "Intl", + // WebAssembly + "WebAssembly" + ]; + + const ERROR_TYPES = [ + "Error", + "EvalError", + "InternalError", + "RangeError", + "ReferenceError", + "SyntaxError", + "TypeError", + "URIError" + ]; + + const BUILT_IN_GLOBALS = [ + "setInterval", + "setTimeout", + "clearInterval", + "clearTimeout", + + "require", + "exports", + + "eval", + "isFinite", + "isNaN", + "parseFloat", + "parseInt", + "decodeURI", + "decodeURIComponent", + "encodeURI", + "encodeURIComponent", + "escape", + "unescape" + ]; + + const BUILT_IN_VARIABLES = [ + "arguments", + "this", + "super", + "console", + "window", + "document", + "localStorage", + "sessionStorage", + "module", + "global" // Node.js + ]; + + const BUILT_INS = [].concat( + BUILT_IN_GLOBALS, + TYPES, + ERROR_TYPES + ); + + /* + Language: JavaScript + Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. + Category: common, scripting, web + Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript + */ + + + /** @type LanguageFn */ + function javascript(hljs) { + const regex = hljs.regex; + /** + * Takes a string like " { + const tag = "', + end: '' + }; + // to avoid some special cases inside isTrulyOpeningTag + const XML_SELF_CLOSING = /<[A-Za-z0-9\\._:-]+\s*\/>/; + const XML_TAG = { + begin: /<[A-Za-z0-9\\._:-]+/, + end: /\/[A-Za-z0-9\\._:-]+>|\/>/, + /** + * @param {RegExpMatchArray} match + * @param {CallbackResponse} response + */ + isTrulyOpeningTag: (match, response) => { + const afterMatchIndex = match[0].length + match.index; + const nextChar = match.input[afterMatchIndex]; + if ( + // HTML should not include another raw `<` inside a tag + // nested type? + // `>`, etc. + nextChar === "<" || + // the , gives away that this is not HTML + // `` + nextChar === "," + ) { + response.ignoreMatch(); + return; + } + + // `` + // Quite possibly a tag, lets look for a matching closing tag... + if (nextChar === ">") { + // if we cannot find a matching closing tag, then we + // will ignore it + if (!hasClosingTag(match, { after: afterMatchIndex })) { + response.ignoreMatch(); + } + } + + // `` (self-closing) + // handled by simpleSelfClosing rule + + let m; + const afterMatch = match.input.substring(afterMatchIndex); + + // some more template typing stuff + // (key?: string) => Modify< + if ((m = afterMatch.match(/^\s*=/))) { + response.ignoreMatch(); + return; + } + + // `` + // technically this could be HTML, but it smells like a type + // NOTE: This is ugh, but added specifically for https://github.com/highlightjs/highlight.js/issues/3276 + if ((m = afterMatch.match(/^\s+extends\s+/))) { + if (m.index === 0) { + response.ignoreMatch(); + // eslint-disable-next-line no-useless-return + return; + } + } + } + }; + const KEYWORDS$1 = { + $pattern: IDENT_RE, + keyword: KEYWORDS, + literal: LITERALS, + built_in: BUILT_INS, + "variable.language": BUILT_IN_VARIABLES + }; + + // https://tc39.es/ecma262/#sec-literals-numeric-literals + const decimalDigits = '[0-9](_?[0-9])*'; + const frac = `\\.(${decimalDigits})`; + // DecimalIntegerLiteral, including Annex B NonOctalDecimalIntegerLiteral + // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals + const decimalInteger = `0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*`; + const NUMBER = { + className: 'number', + variants: [ + // DecimalLiteral + { begin: `(\\b(${decimalInteger})((${frac})|\\.)?|(${frac}))` + + `[eE][+-]?(${decimalDigits})\\b` }, + { begin: `\\b(${decimalInteger})\\b((${frac})\\b|\\.)?|(${frac})\\b` }, + + // DecimalBigIntegerLiteral + { begin: `\\b(0|[1-9](_?[0-9])*)n\\b` }, + + // NonDecimalIntegerLiteral + { begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b" }, + { begin: "\\b0[bB][0-1](_?[0-1])*n?\\b" }, + { begin: "\\b0[oO][0-7](_?[0-7])*n?\\b" }, + + // LegacyOctalIntegerLiteral (does not include underscore separators) + // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals + { begin: "\\b0[0-7]+n?\\b" }, + ], + relevance: 0 + }; + + const SUBST = { + className: 'subst', + begin: '\\$\\{', + end: '\\}', + keywords: KEYWORDS$1, + contains: [] // defined later + }; + const HTML_TEMPLATE = { + begin: 'html`', + end: '', + starts: { + end: '`', + returnEnd: false, + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + subLanguage: 'xml' + } + }; + const CSS_TEMPLATE = { + begin: 'css`', + end: '', + starts: { + end: '`', + returnEnd: false, + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + subLanguage: 'css' + } + }; + const GRAPHQL_TEMPLATE = { + begin: 'gql`', + end: '', + starts: { + end: '`', + returnEnd: false, + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ], + subLanguage: 'graphql' + } + }; + const TEMPLATE_STRING = { + className: 'string', + begin: '`', + end: '`', + contains: [ + hljs.BACKSLASH_ESCAPE, + SUBST + ] + }; + const JSDOC_COMMENT = hljs.COMMENT( + /\/\*\*(?!\/)/, + '\\*/', + { + relevance: 0, + contains: [ + { + begin: '(?=@[A-Za-z]+)', + relevance: 0, + contains: [ + { + className: 'doctag', + begin: '@[A-Za-z]+' + }, + { + className: 'type', + begin: '\\{', + end: '\\}', + excludeEnd: true, + excludeBegin: true, + relevance: 0 + }, + { + className: 'variable', + begin: IDENT_RE$1 + '(?=\\s*(-)|$)', + endsParent: true, + relevance: 0 + }, + // eat spaces (not newlines) so we can find + // types or variables + { + begin: /(?=[^\n])\s/, + relevance: 0 + } + ] + } + ] + } + ); + const COMMENT = { + className: "comment", + variants: [ + JSDOC_COMMENT, + hljs.C_BLOCK_COMMENT_MODE, + hljs.C_LINE_COMMENT_MODE + ] + }; + const SUBST_INTERNALS = [ + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + HTML_TEMPLATE, + CSS_TEMPLATE, + GRAPHQL_TEMPLATE, + TEMPLATE_STRING, + // Skip numbers when they are part of a variable name + { match: /\$\d+/ }, + NUMBER, + // This is intentional: + // See https://github.com/highlightjs/highlight.js/issues/3288 + // hljs.REGEXP_MODE + ]; + SUBST.contains = SUBST_INTERNALS + .concat({ + // we need to pair up {} inside our subst to prevent + // it from ending too early by matching another } + begin: /\{/, + end: /\}/, + keywords: KEYWORDS$1, + contains: [ + "self" + ].concat(SUBST_INTERNALS) + }); + const SUBST_AND_COMMENTS = [].concat(COMMENT, SUBST.contains); + const PARAMS_CONTAINS = SUBST_AND_COMMENTS.concat([ + // eat recursive parens in sub expressions + { + begin: /\(/, + end: /\)/, + keywords: KEYWORDS$1, + contains: ["self"].concat(SUBST_AND_COMMENTS) + } + ]); + const PARAMS = { + className: 'params', + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, + keywords: KEYWORDS$1, + contains: PARAMS_CONTAINS + }; + + // ES6 classes + const CLASS_OR_EXTENDS = { + variants: [ + // class Car extends vehicle + { + match: [ + /class/, + /\s+/, + IDENT_RE$1, + /\s+/, + /extends/, + /\s+/, + regex.concat(IDENT_RE$1, "(", regex.concat(/\./, IDENT_RE$1), ")*") + ], + scope: { + 1: "keyword", + 3: "title.class", + 5: "keyword", + 7: "title.class.inherited" + } + }, + // class Car + { + match: [ + /class/, + /\s+/, + IDENT_RE$1 + ], + scope: { + 1: "keyword", + 3: "title.class" + } + }, + + ] + }; + + const CLASS_REFERENCE = { + relevance: 0, + match: + regex.either( + // Hard coded exceptions + /\bJSON/, + // Float32Array, OutT + /\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/, + // CSSFactory, CSSFactoryT + /\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/, + // FPs, FPsT + /\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/, + // P + // single letters are not highlighted + // BLAH + // this will be flagged as a UPPER_CASE_CONSTANT instead + ), + className: "title.class", + keywords: { + _: [ + // se we still get relevance credit for JS library classes + ...TYPES, + ...ERROR_TYPES + ] + } + }; + + const USE_STRICT = { + label: "use_strict", + className: 'meta', + relevance: 10, + begin: /^\s*['"]use (strict|asm)['"]/ + }; + + const FUNCTION_DEFINITION = { + variants: [ + { + match: [ + /function/, + /\s+/, + IDENT_RE$1, + /(?=\s*\()/ + ] + }, + // anonymous function + { + match: [ + /function/, + /\s*(?=\()/ + ] + } + ], + className: { + 1: "keyword", + 3: "title.function" + }, + label: "func.def", + contains: [ PARAMS ], + illegal: /%/ + }; + + const UPPER_CASE_CONSTANT = { + relevance: 0, + match: /\b[A-Z][A-Z_0-9]+\b/, + className: "variable.constant" + }; + + function noneOf(list) { + return regex.concat("(?!", list.join("|"), ")"); + } + + const FUNCTION_CALL = { + match: regex.concat( + /\b/, + noneOf([ + ...BUILT_IN_GLOBALS, + "super", + "import" + ]), + IDENT_RE$1, regex.lookahead(/\(/)), + className: "title.function", + relevance: 0 + }; + + const PROPERTY_ACCESS = { + begin: regex.concat(/\./, regex.lookahead( + regex.concat(IDENT_RE$1, /(?![0-9A-Za-z$_(])/) + )), + end: IDENT_RE$1, + excludeBegin: true, + keywords: "prototype", + className: "property", + relevance: 0 + }; + + const GETTER_OR_SETTER = { + match: [ + /get|set/, + /\s+/, + IDENT_RE$1, + /(?=\()/ + ], + className: { + 1: "keyword", + 3: "title.function" + }, + contains: [ + { // eat to avoid empty params + begin: /\(\)/ + }, + PARAMS + ] + }; + + const FUNC_LEAD_IN_RE = '(\\(' + + '[^()]*(\\(' + + '[^()]*(\\(' + + '[^()]*' + + '\\)[^()]*)*' + + '\\)[^()]*)*' + + '\\)|' + hljs.UNDERSCORE_IDENT_RE + ')\\s*=>'; + + const FUNCTION_VARIABLE = { + match: [ + /const|var|let/, /\s+/, + IDENT_RE$1, /\s*/, + /=\s*/, + /(async\s*)?/, // async is optional + regex.lookahead(FUNC_LEAD_IN_RE) + ], + keywords: "async", + className: { + 1: "keyword", + 3: "title.function" + }, + contains: [ + PARAMS + ] + }; + + return { + name: 'JavaScript', + aliases: ['js', 'jsx', 'mjs', 'cjs'], + keywords: KEYWORDS$1, + // this will be extended by TypeScript + exports: { PARAMS_CONTAINS, CLASS_REFERENCE }, + illegal: /#(?![$_A-z])/, + contains: [ + hljs.SHEBANG({ + label: "shebang", + binary: "node", + relevance: 5 + }), + USE_STRICT, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + HTML_TEMPLATE, + CSS_TEMPLATE, + GRAPHQL_TEMPLATE, + TEMPLATE_STRING, + COMMENT, + // Skip numbers when they are part of a variable name + { match: /\$\d+/ }, + NUMBER, + CLASS_REFERENCE, + { + className: 'attr', + begin: IDENT_RE$1 + regex.lookahead(':'), + relevance: 0 + }, + FUNCTION_VARIABLE, + { // "value" container + begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*', + keywords: 'return throw case', + relevance: 0, + contains: [ + COMMENT, + hljs.REGEXP_MODE, + { + className: 'function', + // we have to count the parens to make sure we actually have the + // correct bounding ( ) before the =>. There could be any number of + // sub-expressions inside also surrounded by parens. + begin: FUNC_LEAD_IN_RE, + returnBegin: true, + end: '\\s*=>', + contains: [ + { + className: 'params', + variants: [ + { + begin: hljs.UNDERSCORE_IDENT_RE, + relevance: 0 + }, + { + className: null, + begin: /\(\s*\)/, + skip: true + }, + { + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, + keywords: KEYWORDS$1, + contains: PARAMS_CONTAINS + } + ] + } + ] + }, + { // could be a comma delimited list of params to a function call + begin: /,/, + relevance: 0 + }, + { + match: /\s+/, + relevance: 0 + }, + { // JSX + variants: [ + { begin: FRAGMENT.begin, end: FRAGMENT.end }, + { match: XML_SELF_CLOSING }, + { + begin: XML_TAG.begin, + // we carefully check the opening tag to see if it truly + // is a tag and not a false positive + 'on:begin': XML_TAG.isTrulyOpeningTag, + end: XML_TAG.end + } + ], + subLanguage: 'xml', + contains: [ + { + begin: XML_TAG.begin, + end: XML_TAG.end, + skip: true, + contains: ['self'] + } + ] + } + ], + }, + FUNCTION_DEFINITION, + { + // prevent this from getting swallowed up by function + // since they appear "function like" + beginKeywords: "while if switch catch for" + }, + { + // we have to count the parens to make sure we actually have the correct + // bounding ( ). There could be any number of sub-expressions inside + // also surrounded by parens. + begin: '\\b(?!function)' + hljs.UNDERSCORE_IDENT_RE + + '\\(' + // first parens + '[^()]*(\\(' + + '[^()]*(\\(' + + '[^()]*' + + '\\)[^()]*)*' + + '\\)[^()]*)*' + + '\\)\\s*\\{', // end parens + returnBegin:true, + label: "func.def", + contains: [ + PARAMS, + hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1, className: "title.function" }) + ] + }, + // catch ... so it won't trigger the property rule below + { + match: /\.\.\./, + relevance: 0 + }, + PROPERTY_ACCESS, + // hack: prevents detection of keywords in some circumstances + // .keyword() + // $keyword = x + { + match: '\\$' + IDENT_RE$1, + relevance: 0 + }, + { + match: [ /\bconstructor(?=\s*\()/ ], + className: { 1: "title.function" }, + contains: [ PARAMS ] + }, + FUNCTION_CALL, + UPPER_CASE_CONSTANT, + CLASS_OR_EXTENDS, + GETTER_OR_SETTER, + { + match: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something` + } + ] + }; + } + + /* + Language: TypeScript + Author: Panu Horsmalahti + Contributors: Ike Ku + Description: TypeScript is a strict superset of JavaScript + Website: https://www.typescriptlang.org + Category: common, scripting + */ + + + /** @type LanguageFn */ + function typescript(hljs) { + const tsLanguage = javascript(hljs); + + const IDENT_RE$1 = IDENT_RE; + const TYPES = [ + "any", + "void", + "number", + "boolean", + "string", + "object", + "never", + "symbol", + "bigint", + "unknown" + ]; + const NAMESPACE = { + beginKeywords: 'namespace', + end: /\{/, + excludeEnd: true, + contains: [ tsLanguage.exports.CLASS_REFERENCE ] + }; + const INTERFACE = { + beginKeywords: 'interface', + end: /\{/, + excludeEnd: true, + keywords: { + keyword: 'interface extends', + built_in: TYPES + }, + contains: [ tsLanguage.exports.CLASS_REFERENCE ] + }; + const USE_STRICT = { + className: 'meta', + relevance: 10, + begin: /^\s*['"]use strict['"]/ + }; + const TS_SPECIFIC_KEYWORDS = [ + "type", + "namespace", + "interface", + "public", + "private", + "protected", + "implements", + "declare", + "abstract", + "readonly", + "enum", + "override" + ]; + const KEYWORDS$1 = { + $pattern: IDENT_RE, + keyword: KEYWORDS.concat(TS_SPECIFIC_KEYWORDS), + literal: LITERALS, + built_in: BUILT_INS.concat(TYPES), + "variable.language": BUILT_IN_VARIABLES + }; + const DECORATOR = { + className: 'meta', + begin: '@' + IDENT_RE$1, + }; + + const swapMode = (mode, label, replacement) => { + const indx = mode.contains.findIndex(m => m.label === label); + if (indx === -1) { throw new Error("can not find mode to replace"); } + + mode.contains.splice(indx, 1, replacement); + }; + + + // this should update anywhere keywords is used since + // it will be the same actual JS object + Object.assign(tsLanguage.keywords, KEYWORDS$1); + + tsLanguage.exports.PARAMS_CONTAINS.push(DECORATOR); + tsLanguage.contains = tsLanguage.contains.concat([ + DECORATOR, + NAMESPACE, + INTERFACE, + ]); + + // TS gets a simpler shebang rule than JS + swapMode(tsLanguage, "shebang", hljs.SHEBANG()); + // JS use strict rule purposely excludes `asm` which makes no sense + swapMode(tsLanguage, "use_strict", USE_STRICT); + + const functionDeclaration = tsLanguage.contains.find(m => m.label === "func.def"); + functionDeclaration.relevance = 0; // () => {} is more typical in TypeScript + + Object.assign(tsLanguage, { + name: 'TypeScript', + aliases: [ + 'ts', + 'tsx', + 'mts', + 'cts' + ] + }); + + return tsLanguage; + } + + return typescript; + +})(); + + hljs.registerLanguage('typescript', hljsGrammar); + })();/*! `vala` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Vala + Author: Antono Vasiljev + Description: Vala is a new programming language that aims to bring modern programming language features to GNOME developers without imposing any additional runtime requirements and without using a different ABI compared to applications and libraries written in C. + Website: https://wiki.gnome.org/Projects/Vala + Category: system + */ + + function vala(hljs) { + return { + name: 'Vala', + keywords: { + keyword: + // Value types + 'char uchar unichar int uint long ulong short ushort int8 int16 int32 int64 uint8 ' + + 'uint16 uint32 uint64 float double bool struct enum string void ' + // Reference types + + 'weak unowned owned ' + // Modifiers + + 'async signal static abstract interface override virtual delegate ' + // Control Structures + + 'if while do for foreach else switch case break default return try catch ' + // Visibility + + 'public private protected internal ' + // Other + + 'using new this get set const stdout stdin stderr var', + built_in: + 'DBus GLib CCode Gee Object Gtk Posix', + literal: + 'false true null' + }, + contains: [ + { + className: 'class', + beginKeywords: 'class interface namespace', + end: /\{/, + excludeEnd: true, + illegal: '[^,:\\n\\s\\.]', + contains: [ hljs.UNDERSCORE_TITLE_MODE ] + }, + hljs.C_LINE_COMMENT_MODE, + hljs.C_BLOCK_COMMENT_MODE, + { + className: 'string', + begin: '"""', + end: '"""', + relevance: 5 + }, + hljs.APOS_STRING_MODE, + hljs.QUOTE_STRING_MODE, + hljs.C_NUMBER_MODE, + { + className: 'meta', + begin: '^#', + end: '$', + } + ] + }; + } + + return vala; + +})(); + + hljs.registerLanguage('vala', hljsGrammar); + })();/*! `vbnet` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Visual Basic .NET + Description: Visual Basic .NET (VB.NET) is a multi-paradigm, object-oriented programming language, implemented on the .NET Framework. + Authors: Poren Chiang , Jan Pilzer + Website: https://docs.microsoft.com/dotnet/visual-basic/getting-started + Category: common + */ + + /** @type LanguageFn */ + function vbnet(hljs) { + const regex = hljs.regex; + /** + * Character Literal + * Either a single character ("a"C) or an escaped double quote (""""C). + */ + const CHARACTER = { + className: 'string', + begin: /"(""|[^/n])"C\b/ + }; + + const STRING = { + className: 'string', + begin: /"/, + end: /"/, + illegal: /\n/, + contains: [ + { + // double quote escape + begin: /""/ } + ] + }; + + /** Date Literals consist of a date, a time, or both separated by whitespace, surrounded by # */ + const MM_DD_YYYY = /\d{1,2}\/\d{1,2}\/\d{4}/; + const YYYY_MM_DD = /\d{4}-\d{1,2}-\d{1,2}/; + const TIME_12H = /(\d|1[012])(:\d+){0,2} *(AM|PM)/; + const TIME_24H = /\d{1,2}(:\d{1,2}){1,2}/; + const DATE = { + className: 'literal', + variants: [ + { + // #YYYY-MM-DD# (ISO-Date) or #M/D/YYYY# (US-Date) + begin: regex.concat(/# */, regex.either(YYYY_MM_DD, MM_DD_YYYY), / *#/) }, + { + // #H:mm[:ss]# (24h Time) + begin: regex.concat(/# */, TIME_24H, / *#/) }, + { + // #h[:mm[:ss]] A# (12h Time) + begin: regex.concat(/# */, TIME_12H, / *#/) }, + { + // date plus time + begin: regex.concat( + /# */, + regex.either(YYYY_MM_DD, MM_DD_YYYY), + / +/, + regex.either(TIME_12H, TIME_24H), + / *#/ + ) } + ] + }; + + const NUMBER = { + className: 'number', + relevance: 0, + variants: [ + { + // Float + begin: /\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ }, + { + // Integer (base 10) + begin: /\b\d[\d_]*((U?[SIL])|[%&])?/ }, + { + // Integer (base 16) + begin: /&H[\dA-F_]+((U?[SIL])|[%&])?/ }, + { + // Integer (base 8) + begin: /&O[0-7_]+((U?[SIL])|[%&])?/ }, + { + // Integer (base 2) + begin: /&B[01_]+((U?[SIL])|[%&])?/ } + ] + }; + + const LABEL = { + className: 'label', + begin: /^\w+:/ + }; + + const DOC_COMMENT = hljs.COMMENT(/'''/, /$/, { contains: [ + { + className: 'doctag', + begin: /<\/?/, + end: />/ + } + ] }); + + const COMMENT = hljs.COMMENT(null, /$/, { variants: [ + { begin: /'/ }, + { + // TODO: Use multi-class for leading spaces + begin: /([\t ]|^)REM(?=\s)/ } + ] }); + + const DIRECTIVES = { + className: 'meta', + // TODO: Use multi-class for indentation once available + begin: /[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, + end: /$/, + keywords: { keyword: + 'const disable else elseif enable end externalsource if region then' }, + contains: [ COMMENT ] + }; + + return { + name: 'Visual Basic .NET', + aliases: [ 'vb' ], + case_insensitive: true, + classNameAliases: { label: 'symbol' }, + keywords: { + keyword: + 'addhandler alias aggregate ansi as async assembly auto binary by byref byval ' /* a-b */ + + 'call case catch class compare const continue custom declare default delegate dim distinct do ' /* c-d */ + + 'each equals else elseif end enum erase error event exit explicit finally for friend from function ' /* e-f */ + + 'get global goto group handles if implements imports in inherits interface into iterator ' /* g-i */ + + 'join key let lib loop me mid module mustinherit mustoverride mybase myclass ' /* j-m */ + + 'namespace narrowing new next notinheritable notoverridable ' /* n */ + + 'of off on operator option optional order overloads overridable overrides ' /* o */ + + 'paramarray partial preserve private property protected public ' /* p */ + + 'raiseevent readonly redim removehandler resume return ' /* r */ + + 'select set shadows shared skip static step stop structure strict sub synclock ' /* s */ + + 'take text then throw to try unicode until using when where while widening with withevents writeonly yield' /* t-y */, + built_in: + // Operators https://docs.microsoft.com/dotnet/visual-basic/language-reference/operators + 'addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor ' + // Type Conversion Functions https://docs.microsoft.com/dotnet/visual-basic/language-reference/functions/type-conversion-functions + + 'cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort', + type: + // Data types https://docs.microsoft.com/dotnet/visual-basic/language-reference/data-types + 'boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort', + literal: 'true false nothing' + }, + illegal: + '//|\\{|\\}|endif|gosub|variant|wend|^\\$ ' /* reserved deprecated keywords */, + contains: [ + CHARACTER, + STRING, + DATE, + NUMBER, + LABEL, + DOC_COMMENT, + COMMENT, + DIRECTIVES + ] + }; + } + + return vbnet; + +})(); + + hljs.registerLanguage('vbnet', hljsGrammar); + })();/*! `vim` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Vim Script + Author: Jun Yang + Description: full keyword and built-in from http://vimdoc.sourceforge.net/htmldoc/ + Website: https://www.vim.org + Category: scripting + */ + + function vim(hljs) { + return { + name: 'Vim Script', + keywords: { + $pattern: /[!#@\w]+/, + keyword: + // express version except: ! & * < = > !! # @ @@ + 'N|0 P|0 X|0 a|0 ab abc abo al am an|0 ar arga argd arge argdo argg argl argu as au aug aun b|0 bN ba bad bd be bel bf bl bm bn bo bp br brea breaka breakd breakl bro bufdo buffers bun bw c|0 cN cNf ca cabc caddb cad caddf cal cat cb cc ccl cd ce cex cf cfir cgetb cgete cg changes chd che checkt cl cla clo cm cmapc cme cn cnew cnf cno cnorea cnoreme co col colo com comc comp con conf cope ' + + 'cp cpf cq cr cs cst cu cuna cunme cw delm deb debugg delc delf dif diffg diffo diffp diffpu diffs diffthis dig di dl dell dj dli do doautoa dp dr ds dsp e|0 ea ec echoe echoh echom echon el elsei em en endfo endf endt endw ene ex exe exi exu f|0 files filet fin fina fini fir fix fo foldc foldd folddoc foldo for fu go gr grepa gu gv ha helpf helpg helpt hi hid his ia iabc if ij il im imapc ' + + 'ime ino inorea inoreme int is isp iu iuna iunme j|0 ju k|0 keepa kee keepj lN lNf l|0 lad laddb laddf la lan lat lb lc lch lcl lcs le lefta let lex lf lfir lgetb lgete lg lgr lgrepa lh ll lla lli lmak lm lmapc lne lnew lnf ln loadk lo loc lockv lol lope lp lpf lr ls lt lu lua luad luaf lv lvimgrepa lw m|0 ma mak map mapc marks mat me menut mes mk mks mksp mkv mkvie mod mz mzf nbc nb nbs new nm nmapc nme nn nnoreme noa no noh norea noreme norm nu nun nunme ol o|0 om omapc ome on ono onoreme opt ou ounme ow p|0 ' + + 'profd prof pro promptr pc ped pe perld po popu pp pre prev ps pt ptN ptf ptj ptl ptn ptp ptr pts pu pw py3 python3 py3d py3f py pyd pyf quita qa rec red redi redr redraws reg res ret retu rew ri rightb rub rubyd rubyf rund ru rv sN san sa sal sav sb sbN sba sbf sbl sbm sbn sbp sbr scrip scripte scs se setf setg setl sf sfir sh sim sig sil sl sla sm smap smapc sme sn sni sno snor snoreme sor ' + + 'so spelld spe spelli spellr spellu spellw sp spr sre st sta startg startr star stopi stj sts sun sunm sunme sus sv sw sy synti sync tN tabN tabc tabdo tabe tabf tabfir tabl tabm tabnew ' + + 'tabn tabo tabp tabr tabs tab ta tags tc tcld tclf te tf th tj tl tm tn to tp tr try ts tu u|0 undoj undol una unh unl unlo unm unme uns up ve verb vert vim vimgrepa vi viu vie vm vmapc vme vne vn vnoreme vs vu vunme windo w|0 wN wa wh wi winc winp wn wp wq wqa ws wu wv x|0 xa xmapc xm xme xn xnoreme xu xunme y|0 z|0 ~ ' + // full version + + 'Next Print append abbreviate abclear aboveleft all amenu anoremenu args argadd argdelete argedit argglobal arglocal argument ascii autocmd augroup aunmenu buffer bNext ball badd bdelete behave belowright bfirst blast bmodified bnext botright bprevious brewind break breakadd breakdel breaklist browse bunload ' + + 'bwipeout change cNext cNfile cabbrev cabclear caddbuffer caddexpr caddfile call catch cbuffer cclose center cexpr cfile cfirst cgetbuffer cgetexpr cgetfile chdir checkpath checktime clist clast close cmap cmapclear cmenu cnext cnewer cnfile cnoremap cnoreabbrev cnoremenu copy colder colorscheme command comclear compiler continue confirm copen cprevious cpfile cquit crewind cscope cstag cunmap ' + + 'cunabbrev cunmenu cwindow delete delmarks debug debuggreedy delcommand delfunction diffupdate diffget diffoff diffpatch diffput diffsplit digraphs display deletel djump dlist doautocmd doautoall deletep drop dsearch dsplit edit earlier echo echoerr echohl echomsg else elseif emenu endif endfor ' + + 'endfunction endtry endwhile enew execute exit exusage file filetype find finally finish first fixdel fold foldclose folddoopen folddoclosed foldopen function global goto grep grepadd gui gvim hardcopy help helpfind helpgrep helptags highlight hide history insert iabbrev iabclear ijump ilist imap ' + + 'imapclear imenu inoremap inoreabbrev inoremenu intro isearch isplit iunmap iunabbrev iunmenu join jumps keepalt keepmarks keepjumps lNext lNfile list laddexpr laddbuffer laddfile last language later lbuffer lcd lchdir lclose lcscope left leftabove lexpr lfile lfirst lgetbuffer lgetexpr lgetfile lgrep lgrepadd lhelpgrep llast llist lmake lmap lmapclear lnext lnewer lnfile lnoremap loadkeymap loadview ' + + 'lockmarks lockvar lolder lopen lprevious lpfile lrewind ltag lunmap luado luafile lvimgrep lvimgrepadd lwindow move mark make mapclear match menu menutranslate messages mkexrc mksession mkspell mkvimrc mkview mode mzscheme mzfile nbclose nbkey nbsart next nmap nmapclear nmenu nnoremap ' + + 'nnoremenu noautocmd noremap nohlsearch noreabbrev noremenu normal number nunmap nunmenu oldfiles open omap omapclear omenu only onoremap onoremenu options ounmap ounmenu ownsyntax print profdel profile promptfind promptrepl pclose pedit perl perldo pop popup ppop preserve previous psearch ptag ptNext ' + + 'ptfirst ptjump ptlast ptnext ptprevious ptrewind ptselect put pwd py3do py3file python pydo pyfile quit quitall qall read recover redo redir redraw redrawstatus registers resize retab return rewind right rightbelow ruby rubydo rubyfile rundo runtime rviminfo substitute sNext sandbox sargument sall saveas sbuffer sbNext sball sbfirst sblast sbmodified sbnext sbprevious sbrewind scriptnames scriptencoding ' + + 'scscope set setfiletype setglobal setlocal sfind sfirst shell simalt sign silent sleep slast smagic smapclear smenu snext sniff snomagic snoremap snoremenu sort source spelldump spellgood spellinfo spellrepall spellundo spellwrong split sprevious srewind stop stag startgreplace startreplace ' + + 'startinsert stopinsert stjump stselect sunhide sunmap sunmenu suspend sview swapname syntax syntime syncbind tNext tabNext tabclose tabedit tabfind tabfirst tablast tabmove tabnext tabonly tabprevious tabrewind tag tcl tcldo tclfile tearoff tfirst throw tjump tlast tmenu tnext topleft tprevious ' + 'trewind tselect tunmenu undo undojoin undolist unabbreviate unhide unlet unlockvar unmap unmenu unsilent update vglobal version verbose vertical vimgrep vimgrepadd visual viusage view vmap vmapclear vmenu vnew ' + + 'vnoremap vnoremenu vsplit vunmap vunmenu write wNext wall while winsize wincmd winpos wnext wprevious wqall wsverb wundo wviminfo xit xall xmapclear xmap xmenu xnoremap xnoremenu xunmap xunmenu yank', + built_in: // built in func + 'synIDtrans atan2 range matcharg did_filetype asin feedkeys xor argv ' + + 'complete_check add getwinposx getqflist getwinposy screencol ' + + 'clearmatches empty extend getcmdpos mzeval garbagecollect setreg ' + + 'ceil sqrt diff_hlID inputsecret get getfperm getpid filewritable ' + + 'shiftwidth max sinh isdirectory synID system inputrestore winline ' + + 'atan visualmode inputlist tabpagewinnr round getregtype mapcheck ' + + 'hasmapto histdel argidx findfile sha256 exists toupper getcmdline ' + + 'taglist string getmatches bufnr strftime winwidth bufexists ' + + 'strtrans tabpagebuflist setcmdpos remote_read printf setloclist ' + + 'getpos getline bufwinnr float2nr len getcmdtype diff_filler luaeval ' + + 'resolve libcallnr foldclosedend reverse filter has_key bufname ' + + 'str2float strlen setline getcharmod setbufvar index searchpos ' + + 'shellescape undofile foldclosed setqflist buflisted strchars str2nr ' + + 'virtcol floor remove undotree remote_expr winheight gettabwinvar ' + + 'reltime cursor tabpagenr finddir localtime acos getloclist search ' + + 'tanh matchend rename gettabvar strdisplaywidth type abs py3eval ' + + 'setwinvar tolower wildmenumode log10 spellsuggest bufloaded ' + + 'synconcealed nextnonblank server2client complete settabwinvar ' + + 'executable input wincol setmatches getftype hlID inputsave ' + + 'searchpair or screenrow line settabvar histadd deepcopy strpart ' + + 'remote_peek and eval getftime submatch screenchar winsaveview ' + + 'matchadd mkdir screenattr getfontname libcall reltimestr getfsize ' + + 'winnr invert pow getbufline byte2line soundfold repeat fnameescape ' + + 'tagfiles sin strwidth spellbadword trunc maparg log lispindent ' + + 'hostname setpos globpath remote_foreground getchar synIDattr ' + + 'fnamemodify cscope_connection stridx winbufnr indent min ' + + 'complete_add nr2char searchpairpos inputdialog values matchlist ' + + 'items hlexists strridx browsedir expand fmod pathshorten line2byte ' + + 'argc count getwinvar glob foldtextresult getreg foreground cosh ' + + 'matchdelete has char2nr simplify histget searchdecl iconv ' + + 'winrestcmd pumvisible writefile foldlevel haslocaldir keys cos ' + + 'matchstr foldtext histnr tan tempname getcwd byteidx getbufvar ' + + 'islocked escape eventhandler remote_send serverlist winrestview ' + + 'synstack pyeval prevnonblank readfile cindent filereadable changenr ' + + 'exp' + }, + illegal: /;/, + contains: [ + hljs.NUMBER_MODE, + { + className: 'string', + begin: '\'', + end: '\'', + illegal: '\\n' + }, + + /* + A double quote can start either a string or a line comment. Strings are + ended before the end of a line by another double quote and can contain + escaped double-quotes and post-escaped line breaks. + + Also, any double quote at the beginning of a line is a comment but we + don't handle that properly at the moment: any double quote inside will + turn them into a string. Handling it properly will require a smarter + parser. + */ + { + className: 'string', + begin: /"(\\"|\n\\|[^"\n])*"/ + }, + hljs.COMMENT('"', '$'), + + { + className: 'variable', + begin: /[bwtglsav]:[\w\d_]+/ + }, + { + begin: [ + /\b(?:function|function!)/, + /\s+/, + hljs.IDENT_RE + ], + className: { + 1: "keyword", + 3: "title" + }, + end: '$', + relevance: 0, + contains: [ + { + className: 'params', + begin: '\\(', + end: '\\)' + } + ] + }, + { + className: 'symbol', + begin: /<[\w-]+>/ + } + ] + }; + } + + return vim; + +})(); + + hljs.registerLanguage('vim', hljsGrammar); + })();/*! `wasm` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: WebAssembly + Website: https://webassembly.org + Description: Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications. + Category: web, common + Audit: 2020 + */ + + /** @type LanguageFn */ + function wasm(hljs) { + hljs.regex; + const BLOCK_COMMENT = hljs.COMMENT(/\(;/, /;\)/); + BLOCK_COMMENT.contains.push("self"); + const LINE_COMMENT = hljs.COMMENT(/;;/, /$/); + + const KWS = [ + "anyfunc", + "block", + "br", + "br_if", + "br_table", + "call", + "call_indirect", + "data", + "drop", + "elem", + "else", + "end", + "export", + "func", + "global.get", + "global.set", + "local.get", + "local.set", + "local.tee", + "get_global", + "get_local", + "global", + "if", + "import", + "local", + "loop", + "memory", + "memory.grow", + "memory.size", + "module", + "mut", + "nop", + "offset", + "param", + "result", + "return", + "select", + "set_global", + "set_local", + "start", + "table", + "tee_local", + "then", + "type", + "unreachable" + ]; + + const FUNCTION_REFERENCE = { + begin: [ + /(?:func|call|call_indirect)/, + /\s+/, + /\$[^\s)]+/ + ], + className: { + 1: "keyword", + 3: "title.function" + } + }; + + const ARGUMENT = { + className: "variable", + begin: /\$[\w_]+/ + }; + + const PARENS = { + match: /(\((?!;)|\))+/, + className: "punctuation", + relevance: 0 + }; + + const NUMBER = { + className: "number", + relevance: 0, + // borrowed from Prism, TODO: split out into variants + match: /[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/ + }; + + const TYPE = { + // look-ahead prevents us from gobbling up opcodes + match: /(i32|i64|f32|f64)(?!\.)/, + className: "type" + }; + + const MATH_OPERATIONS = { + className: "keyword", + // borrowed from Prism, TODO: split out into variants + match: /\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/ + }; + + const OFFSET_ALIGN = { + match: [ + /(?:offset|align)/, + /\s*/, + /=/ + ], + className: { + 1: "keyword", + 3: "operator" + } + }; + + return { + name: 'WebAssembly', + keywords: { + $pattern: /[\w.]+/, + keyword: KWS + }, + contains: [ + LINE_COMMENT, + BLOCK_COMMENT, + OFFSET_ALIGN, + ARGUMENT, + PARENS, + FUNCTION_REFERENCE, + hljs.QUOTE_STRING_MODE, + TYPE, + MATH_OPERATIONS, + NUMBER + ] + }; + } + + return wasm; + +})(); + + hljs.registerLanguage('wasm', hljsGrammar); + })();/*! `x86asm` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Intel x86 Assembly + Author: innocenat + Description: x86 assembly language using Intel's mnemonic and NASM syntax + Website: https://en.wikipedia.org/wiki/X86_assembly_language + Category: assembler + */ + + function x86asm(hljs) { + return { + name: 'Intel x86 Assembly', + case_insensitive: true, + keywords: { + $pattern: '[.%]?' + hljs.IDENT_RE, + keyword: + 'lock rep repe repz repne repnz xaquire xrelease bnd nobnd ' + + 'aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63', + built_in: + // Instruction pointer + 'ip eip rip ' + // 8-bit registers + + 'al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ' + // 16-bit registers + + 'ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w ' + // 32-bit registers + + 'eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d ' + // 64-bit registers + + 'rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 ' + // Segment registers + + 'cs ds es fs gs ss ' + // Floating point stack registers + + 'st st0 st1 st2 st3 st4 st5 st6 st7 ' + // MMX Registers + + 'mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 ' + // SSE registers + + 'xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 ' + + 'xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ' + // AVX registers + + 'ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ' + + 'ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 ' + // AVX-512F registers + + 'zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 ' + + 'zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 ' + // AVX-512F mask registers + + 'k0 k1 k2 k3 k4 k5 k6 k7 ' + // Bound (MPX) register + + 'bnd0 bnd1 bnd2 bnd3 ' + // Special register + + 'cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 ' + // NASM altreg package + + 'r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b ' + + 'r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d ' + + 'r0h r1h r2h r3h ' + + 'r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l ' + + + 'db dw dd dq dt ddq do dy dz ' + + 'resb resw resd resq rest resdq reso resy resz ' + + 'incbin equ times ' + + 'byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr', + + meta: + '%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif ' + + '%if %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep ' + + '%endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment ' + + '.nolist ' + + '__FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ ' + + '__UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend ' + + 'align alignb sectalign daz nodaz up down zero default option assume public ' + + + 'bits use16 use32 use64 default section segment absolute extern global common cpu float ' + + '__utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ ' + + '__float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ ' + + '__Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e ' + + 'float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__' + }, + contains: [ + hljs.COMMENT( + ';', + '$', + { relevance: 0 } + ), + { + className: 'number', + variants: [ + // Float number and x87 BCD + { + begin: '\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|' + + '(0[Xx])?[0-9][0-9_]*(\\.[0-9_]*)?(?:[pP](?:[+-]?[0-9_]+)?)?)\\b', + relevance: 0 + }, + + // Hex number in $ + { + begin: '\\$[0-9][0-9A-Fa-f]*', + relevance: 0 + }, + + // Number in H,D,T,Q,O,B,Y suffix + { begin: '\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[Hh]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b' }, + + // Number in X,D,T,Q,O,B,Y prefix + { begin: '\\b(?:0[Xx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b' } + ] + }, + // Double quote string + hljs.QUOTE_STRING_MODE, + { + className: 'string', + variants: [ + // Single-quoted string + { + begin: '\'', + end: '[^\\\\]\'' + }, + // Backquoted string + { + begin: '`', + end: '[^\\\\]`' + } + ], + relevance: 0 + }, + { + className: 'symbol', + variants: [ + // Global label and local label + { begin: '^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)' }, + // Macro-local label + { begin: '^\\s*%%[A-Za-z0-9_$#@~.?]*:' } + ], + relevance: 0 + }, + // Macro parameter + { + className: 'subst', + begin: '%[0-9]+', + relevance: 0 + }, + // Macro parameter + { + className: 'subst', + begin: '%!\S+', + relevance: 0 + }, + { + className: 'meta', + begin: /^\s*\.[\w_-]+/ + } + ] + }; + } + + return x86asm; + +})(); + + hljs.registerLanguage('x86asm', hljsGrammar); + })();/*! `xml` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: HTML, XML + Website: https://www.w3.org/XML/ + Category: common, web + Audit: 2020 + */ + + /** @type LanguageFn */ + function xml(hljs) { + const regex = hljs.regex; + // XML names can have the following additional letters: https://www.w3.org/TR/xml/#NT-NameChar + // OTHER_NAME_CHARS = /[:\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]/; + // Element names start with NAME_START_CHAR followed by optional other Unicode letters, ASCII digits, hyphens, underscores, and periods + // const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/);; + // const XML_IDENT_RE = /[A-Z_a-z:\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]+/; + // const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/); + // however, to cater for performance and more Unicode support rely simply on the Unicode letter class + const TAG_NAME_RE = regex.concat(/[\p{L}_]/u, regex.optional(/[\p{L}0-9_.-]*:/u), /[\p{L}0-9_.-]*/u); + const XML_IDENT_RE = /[\p{L}0-9._:-]+/u; + const XML_ENTITIES = { + className: 'symbol', + begin: /&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/ + }; + const XML_META_KEYWORDS = { + begin: /\s/, + contains: [ + { + className: 'keyword', + begin: /#?[a-z_][a-z1-9_-]+/, + illegal: /\n/ + } + ] + }; + const XML_META_PAR_KEYWORDS = hljs.inherit(XML_META_KEYWORDS, { + begin: /\(/, + end: /\)/ + }); + const APOS_META_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, { className: 'string' }); + const QUOTE_META_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, { className: 'string' }); + const TAG_INTERNALS = { + endsWithParent: true, + illegal: /`]+/ } + ] + } + ] + } + ] + }; + return { + name: 'HTML, XML', + aliases: [ + 'html', + 'xhtml', + 'rss', + 'atom', + 'xjb', + 'xsd', + 'xsl', + 'plist', + 'wsf', + 'svg' + ], + case_insensitive: true, + unicodeRegex: true, + contains: [ + { + className: 'meta', + begin: //, + relevance: 10, + contains: [ + XML_META_KEYWORDS, + QUOTE_META_STRING_MODE, + APOS_META_STRING_MODE, + XML_META_PAR_KEYWORDS, + { + begin: /\[/, + end: /\]/, + contains: [ + { + className: 'meta', + begin: //, + contains: [ + XML_META_KEYWORDS, + XML_META_PAR_KEYWORDS, + QUOTE_META_STRING_MODE, + APOS_META_STRING_MODE + ] + } + ] + } + ] + }, + hljs.COMMENT( + //, + { relevance: 10 } + ), + { + begin: //, + relevance: 10 + }, + XML_ENTITIES, + // xml processing instructions + { + className: 'meta', + end: /\?>/, + variants: [ + { + begin: /<\?xml/, + relevance: 10, + contains: [ + QUOTE_META_STRING_MODE + ] + }, + { + begin: /<\?[a-z][a-z0-9]+/, + } + ] + + }, + { + className: 'tag', + /* + The lookahead pattern (?=...) ensures that 'begin' only matches + ')/, + end: />/, + keywords: { name: 'style' }, + contains: [ TAG_INTERNALS ], + starts: { + end: /<\/style>/, + returnEnd: true, + subLanguage: [ + 'css', + 'xml' + ] + } + }, + { + className: 'tag', + // See the comment in the