├── AhoCorasick ├── key.snk ├── AhoCorasick.csproj ├── Extensions.cs ├── Trie.cs ├── AhoCorasick.cs └── CharComparer.cs ├── .github └── dependabot.yml ├── .nuget └── packages.config ├── LICENSE ├── AhoCorasick.Tests ├── AhoCorasick.Tests.csproj ├── CharComparerTests.cs └── UnitTests.cs ├── AhoCorasick.SqlClr ├── AhoCorasick.SqlClr.sln ├── AhoCorasick.SqlClr.sqlproj ├── Contains.cs └── dist │ └── AhoCorasick.SqlClr_Create.sql ├── AhoCorasick.sln ├── appveyor.yml ├── .gitignore └── README.md /AhoCorasick/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mganss/AhoCorasick/HEAD/AhoCorasick/key.snk -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: nuget 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.nuget/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Michael Ganss 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /AhoCorasick.Tests/AhoCorasick.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net462;net6.0 4 | Ganss.Text.Tests 5 | true 6 | opencover 7 | ../coverage.xml 8 | [AhoCorasick]* 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | 25 | 26 | -------------------------------------------------------------------------------- /AhoCorasick.SqlClr/AhoCorasick.SqlClr.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "AhoCorasick.SqlClr", "AhoCorasick.SqlClr.sqlproj", "{FBC73EEF-133B-492B-9EBB-77E7484F3485}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {FBC73EEF-133B-492B-9EBB-77E7484F3485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {FBC73EEF-133B-492B-9EBB-77E7484F3485}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {FBC73EEF-133B-492B-9EBB-77E7484F3485}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {FBC73EEF-133B-492B-9EBB-77E7484F3485}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {FBC73EEF-133B-492B-9EBB-77E7484F3485}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {FBC73EEF-133B-492B-9EBB-77E7484F3485}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | EndGlobal 25 | -------------------------------------------------------------------------------- /AhoCorasick.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AhoCorasick", "AhoCorasick\AhoCorasick.csproj", "{A1F19E27-06C8-4DB1-94CE-24B4F10330DF}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AhoCorasick.Tests", "AhoCorasick.Tests\AhoCorasick.Tests.csproj", "{860F4149-D7F3-495A-99BE-8AC3FBAE4176}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {A1F19E27-06C8-4DB1-94CE-24B4F10330DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {A1F19E27-06C8-4DB1-94CE-24B4F10330DF}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {A1F19E27-06C8-4DB1-94CE-24B4F10330DF}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {A1F19E27-06C8-4DB1-94CE-24B4F10330DF}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {860F4149-D7F3-495A-99BE-8AC3FBAE4176}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {860F4149-D7F3-495A-99BE-8AC3FBAE4176}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {860F4149-D7F3-495A-99BE-8AC3FBAE4176}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {860F4149-D7F3-495A-99BE-8AC3FBAE4176}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {12FCD39C-9278-4D4D-8438-9A0FCDCA85F3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 2.0.{build} 2 | skip_tags: true 3 | image: Visual Studio 2022 4 | environment: 5 | access_token: 6 | secure: Eq6BjtZ80BXKLwFMg76IjuQAvbLjbojIF/X/ARouGVhxPneJtgDfCXMPNgJ7KBKq 7 | sonar_token: 8 | secure: W7pHKhuTW6Lh8WlXJNTOIaOzeuxLi+H6Nqmnm4pr28jM6jyIpOZ+1r10lIQi0eCA 9 | JAVA_HOME: C:\Program Files\Java\jdk19 10 | build_script: 11 | - dotnet restore 12 | - dotnet pack --include-symbols --include-source -c Release AhoCorasick 13 | test_script: 14 | - ps: | 15 | if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { 16 | dotnet tool install --global dotnet-sonarscanner 17 | dotnet sonarscanner begin /k:"mganss_AhoCorasick" /v:$env:APPVEYOR_BUILD_VERSION /o:"mganss-github" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.login="$env:sonar_token" /d:sonar.cs.opencover.reportsPaths="$($env:APPVEYOR_BUILD_FOLDER)\coverage.xml" /d:sonar.coverage.exclusions="**/Program.cs" 18 | dotnet build 19 | } 20 | - dotnet test /p:CollectCoverage=true AhoCorasick.Tests\AhoCorasick.Tests.csproj /p:Include="[AhoCorasick]*" -f net6.0 21 | - ps: cp coverage.*.xml ./coverage.xml 22 | - ps: | 23 | if (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { 24 | dotnet sonarscanner end /d:sonar.login="$env:sonar_token" 25 | } 26 | - pip install codecov 27 | - codecov -f "coverage.xml" 28 | artifacts: 29 | - path: 'AhoCorasick\**\*.*nupkg' 30 | deploy: 31 | - provider: GitHub 32 | tag: v$(APPVEYOR_BUILD_VERSION) 33 | release: $(APPVEYOR_BUILD_VERSION) 34 | description: '$(APPVEYOR_REPO_COMMIT_MESSAGE)' 35 | auth_token: 36 | secure: Eq6BjtZ80BXKLwFMg76IjuQAvbLjbojIF/X/ARouGVhxPneJtgDfCXMPNgJ7KBKq 37 | draft: true 38 | on: 39 | branch: master 40 | -------------------------------------------------------------------------------- /AhoCorasick/AhoCorasick.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ganss.Text 4 | AhoCorasick 5 | Implements the Aho-Corasick string search algorithm 6 | Copyright 2013-$([System.DateTime]::Now.Year) Michael Ganss 7 | 1.0.0 8 | 2.0.0.0 9 | $(AppVeyor_Build_Version).0 10 | $(AppVeyor_Build_Version) 11 | Michael Ganss 12 | net40;netstandard2.0 13 | AhoCorasick 14 | AhoCorasick 15 | aho-corasick;aho;corasick;string;search;match;substring 16 | https://github.com/mganss/AhoCorasick 17 | https://github.com/mganss/AhoCorasick/blob/master/LICENSE 18 | README.md 19 | git 20 | git://github.com/mganss/AhoCorasick 21 | Ganss.Text 22 | true 23 | bin\$(Configuration)\$(TargetFramework)\AhoCorasick.xml 24 | true 25 | key.snk 26 | snupkg 27 | true 28 | true 29 | true 30 | snupkg 31 | latest 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /AhoCorasick/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Ganss.Text 4 | { 5 | /// 6 | /// Provides extension methods. 7 | /// 8 | public static class Extensions 9 | { 10 | /// 11 | /// Determines whether this instance contains the specified words. 12 | /// 13 | /// The text. 14 | /// The words. 15 | /// The matched words. 16 | public static IEnumerable Contains(this string text, IEnumerable words) 17 | { 18 | return new AhoCorasick(words).Search(text); 19 | } 20 | 21 | /// 22 | /// Determines whether this instance contains the specified words. 23 | /// 24 | /// The text. 25 | /// The words. 26 | /// The matched words. 27 | public static IEnumerable Contains(this string text, params string[] words) 28 | { 29 | return new AhoCorasick(words).Search(text); 30 | } 31 | 32 | /// 33 | /// Determines whether this instance contains the specified words. 34 | /// 35 | /// The text. 36 | /// The comparer used to compare individual characters. 37 | /// The words. 38 | /// The matched words. 39 | public static IEnumerable Contains(this string text, IEqualityComparer comparer, IEnumerable words) 40 | { 41 | return new AhoCorasick(comparer, words).Search(text); 42 | } 43 | 44 | /// 45 | /// Determines whether this instance contains the specified words. 46 | /// 47 | /// The text. 48 | /// The comparer used to compare individual characters. 49 | /// The words. 50 | /// The matched words. 51 | public static IEnumerable Contains(this string text, IEqualityComparer comparer, params string[] words) 52 | { 53 | return new AhoCorasick(comparer, words).Search(text); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # MSTest test Results 19 | [Tt]est[Rr]esult*/ 20 | [Bb]uild[Ll]og.* 21 | 22 | *_i.c 23 | *_p.c 24 | *.ilk 25 | *.meta 26 | *.obj 27 | *.pch 28 | *.pdb 29 | *.pgc 30 | *.pgd 31 | *.rsp 32 | *.sbr 33 | *.tlb 34 | *.tli 35 | *.tlh 36 | *.tmp 37 | *.tmp_proj 38 | *.log 39 | *.vspscc 40 | *.vssscc 41 | .builds 42 | *.pidb 43 | *.log 44 | *.scc 45 | 46 | # Visual C++ cache files 47 | ipch/ 48 | *.aps 49 | *.ncb 50 | *.opensdf 51 | *.sdf 52 | *.cachefile 53 | 54 | # Visual Studio profiler 55 | *.psess 56 | *.vsp 57 | *.vspx 58 | 59 | # Guidance Automation Toolkit 60 | *.gpState 61 | 62 | # ReSharper is a .NET coding add-in 63 | _ReSharper*/ 64 | *.[Rr]e[Ss]harper 65 | 66 | # TeamCity is a build add-in 67 | _TeamCity* 68 | 69 | # DotCover is a Code Coverage Tool 70 | *.dotCover 71 | 72 | # NCrunch 73 | *.ncrunch* 74 | .*crunch*.local.xml 75 | 76 | # Installshield output folder 77 | [Ee]xpress/ 78 | 79 | # DocProject is a documentation generator add-in 80 | DocProject/buildhelp/ 81 | DocProject/Help/*.HxT 82 | DocProject/Help/*.HxC 83 | DocProject/Help/*.hhc 84 | DocProject/Help/*.hhk 85 | DocProject/Help/*.hhp 86 | DocProject/Help/Html2 87 | DocProject/Help/html 88 | 89 | # Click-Once directory 90 | publish/ 91 | 92 | # Publish Web Output 93 | *.Publish.xml 94 | *.pubxml 95 | 96 | # NuGet Packages Directory 97 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 98 | packages/ 99 | 100 | # Windows Azure Build Output 101 | csx 102 | *.build.csdef 103 | 104 | # Windows Store app package directory 105 | AppPackages/ 106 | 107 | # Others 108 | sql/ 109 | *.Cache 110 | ClientBin/ 111 | [Ss]tyle[Cc]op.* 112 | ~$* 113 | *~ 114 | *.dbmdl 115 | *.[Pp]ublish.xml 116 | *.pfx 117 | *.publishsettings 118 | 119 | # RIA/Silverlight projects 120 | Generated_Code/ 121 | 122 | # Backup & report files from converting an old project file to a newer 123 | # Visual Studio version. Backup files are not needed, because we have git ;-) 124 | _UpgradeReport_Files/ 125 | Backup*/ 126 | UpgradeLog*.XML 127 | UpgradeLog*.htm 128 | 129 | # SQL Server files 130 | App_Data/*.mdf 131 | App_Data/*.ldf 132 | 133 | # ========================= 134 | # Windows detritus 135 | # ========================= 136 | 137 | # Windows image file caches 138 | Thumbs.db 139 | ehthumbs.db 140 | 141 | # Folder config file 142 | Desktop.ini 143 | 144 | # Recycle Bin used on file shares 145 | $RECYCLE.BIN/ 146 | 147 | # Mac crap 148 | .DS_Store 149 | 150 | *.nupkg 151 | TestResult.xml 152 | coverage.xml 153 | .vs/ 154 | /OpenCover 155 | -------------------------------------------------------------------------------- /AhoCorasick.Tests/CharComparerTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace Ganss.Text.Tests 11 | { 12 | public class CharComparerTests 13 | { 14 | const char SmallDotlessI = '\u0131'; 15 | const char CapitalIWithDot = '\u0130'; 16 | const char CapitalSharpS = '\u1e9e'; 17 | const char LatinSmallCapitalR = '\u0280'; 18 | const char LatinLetterYR = '\u01a6'; 19 | 20 | [Test] 21 | public void OrdinalTest() 22 | { 23 | var c = CharComparer.Ordinal; 24 | Assert.That(c.Equals('i', 'i'), Is.True); 25 | Assert.That(c.Equals(SmallDotlessI, 'i'), Is.False); 26 | Assert.That(c.Equals('ß', CapitalSharpS), Is.False); 27 | Assert.That(c.Equals(LatinSmallCapitalR, LatinLetterYR), Is.False); 28 | 29 | c = CharComparer.OrdinalIgnoreCase; 30 | Assert.That(c.Equals('i', 'I'), Is.True); 31 | Assert.That(c.Equals(SmallDotlessI, 'i'), Is.False); 32 | Assert.That(c.Equals(SmallDotlessI, 'I'), Is.False); 33 | Assert.That(c.Equals('ß', CapitalSharpS), Is.False); 34 | Assert.That(c.Equals(LatinSmallCapitalR, LatinLetterYR), Is.True); 35 | } 36 | 37 | [Test] 38 | public void InvariantTest() 39 | { 40 | var c = CharComparer.InvariantCulture; 41 | Assert.That(c.Equals('i', 'i'), Is.True); 42 | Assert.That(c.Equals(SmallDotlessI, 'i'), Is.False); 43 | Assert.That(c.Equals('ß', CapitalSharpS), Is.False); 44 | Assert.That(c.Equals(LatinSmallCapitalR, LatinLetterYR), Is.False); 45 | 46 | c = CharComparer.InvariantCultureIgnoreCase; 47 | Assert.That(c.Equals('i', 'I'), Is.True); 48 | Assert.That(c.Equals(SmallDotlessI, 'i'), Is.False); 49 | Assert.That(c.Equals(SmallDotlessI, 'I'), Is.False); 50 | Assert.That(c.Equals('ß', CapitalSharpS), Is.True); 51 | } 52 | 53 | [Test] 54 | public void CultureTest() 55 | { 56 | CultureInfo.CurrentCulture = new CultureInfo("tr-TR"); 57 | var c = CharComparer.CurrentCulture; 58 | Assert.That(c.Equals('i', 'i'), Is.True); 59 | Assert.That(c.Equals(SmallDotlessI, 'i'), Is.False); 60 | Assert.That(c.Equals('ß', CapitalSharpS), Is.False); 61 | Assert.That(c.Equals(LatinSmallCapitalR, LatinLetterYR), Is.False); 62 | 63 | c = CharComparer.CurrentCultureIgnoreCase; 64 | Assert.That(c.Equals('i', 'I'), Is.False); 65 | Assert.That(c.Equals(SmallDotlessI, 'i'), Is.False); 66 | Assert.That(c.Equals(SmallDotlessI, 'I'), Is.True); 67 | Assert.That(c.Equals('i', CapitalIWithDot), Is.True); 68 | Assert.That(c.Equals('ß', CapitalSharpS), Is.True); 69 | 70 | Assert.That(c.GetHashCode('i'), Is.EqualTo(c.GetHashCode(CapitalIWithDot))); 71 | Assert.That(c.GetHashCode(SmallDotlessI), Is.EqualTo(c.GetHashCode('I'))); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /AhoCorasick/Trie.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Ganss.Text 4 | { 5 | /// 6 | /// A Trie. 7 | /// 8 | public class Trie 9 | { 10 | /// 11 | /// Gets or sets the child nodes. 12 | /// 13 | /// 14 | /// The child nodes. 15 | /// 16 | public Dictionary Next { get; set; } 17 | 18 | /// 19 | /// Gets or sets a value indicating whether this instance represents a word in the dictionary. 20 | /// 21 | /// 22 | /// true if this instance is a word in the dictionary; otherwise, false. 23 | /// 24 | public bool IsWord { get; set; } 25 | 26 | /// 27 | /// Gets or sets the failure node. 28 | /// 29 | /// 30 | /// The failure node. 31 | /// 32 | public Trie Fail { get; set; } 33 | 34 | /// 35 | /// Gets or sets the parent node. 36 | /// 37 | /// 38 | /// The parent node. 39 | /// 40 | public Trie Parent { get; set; } 41 | 42 | /// 43 | /// Gets the word prefix this node represents. 44 | /// 45 | /// 46 | /// The word prefix. 47 | /// 48 | public string Word { get; private set; } 49 | 50 | /// 51 | /// Initializes a new instance of the class. 52 | /// 53 | public Trie() 54 | { 55 | Word = ""; 56 | Next = new Dictionary(); 57 | } 58 | 59 | /// 60 | /// Initializes a new instance of the class. 61 | /// 62 | /// The comparer used to compare individual characters. 63 | public Trie(IEqualityComparer comparer) 64 | { 65 | Word = ""; 66 | Next = new Dictionary(comparer); 67 | } 68 | 69 | /// 70 | /// Adds the specified word to the trie. 71 | /// 72 | /// The word. 73 | /// 74 | public virtual Trie Add(string word) 75 | { 76 | var c = word[0]; 77 | 78 | if (!Next.TryGetValue(c, out Trie node)) 79 | Next[c] = node = new Trie(Next.Comparer) { Parent = this, Word = Word + c }; 80 | 81 | if (word.Length > 1) 82 | return node.Add(word.Substring(1)); 83 | else 84 | node.IsWord = true; 85 | 86 | return node; 87 | } 88 | 89 | /// 90 | /// Finds the failure node for a specified suffix within the given range of indices. 91 | /// 92 | /// The string containing the suffix. 93 | /// The start index of the suffix within the string. 94 | /// The end index (exclusive) of the suffix within the string. 95 | /// The failure node or null if no failure node is found. 96 | 97 | public virtual Trie ExploreFailLink(string word, int startIndex, int endIndex) 98 | { 99 | var node = this; 100 | 101 | for (int i = startIndex; i < endIndex; i++) 102 | { 103 | if (!node.Next.TryGetValue(word[i], out node)) 104 | { 105 | return null; 106 | } 107 | } 108 | 109 | return node; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /AhoCorasick.SqlClr/AhoCorasick.SqlClr.sqlproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | AhoCorasick.SqlClr 8 | 2.0 9 | 4.1 10 | {fbc73eef-133b-492b-9ebb-77e7484f3485} 11 | Microsoft.Data.Tools.Schema.Sql.Sql120DatabaseSchemaProvider 12 | Database 13 | 14 | 15 | AhoCorasick.SqlClr 16 | AhoCorasick.SqlClr 17 | 1033, CI 18 | BySchemaAndSchemaType 19 | True 20 | v4.0 21 | CS 22 | Properties 23 | False 24 | True 25 | True 26 | True 27 | 28 | 29 | bin\Release\ 30 | $(MSBuildProjectName).sql 31 | False 32 | pdbonly 33 | true 34 | false 35 | true 36 | prompt 37 | 4 38 | NET40 39 | 40 | 41 | bin\Debug\ 42 | $(MSBuildProjectName).sql 43 | false 44 | true 45 | full 46 | false 47 | true 48 | true 49 | prompt 50 | 4 51 | NET40 52 | 53 | 54 | 11.0 55 | 56 | True 57 | 11.0 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | AhoCorasick.cs 67 | 68 | 69 | CharComparer.cs 70 | 71 | 72 | Trie.cs 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /AhoCorasick.Tests/UnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Ganss.Text; 4 | using System.Collections.Generic; 5 | using NUnit.Framework; 6 | using System.Globalization; 7 | 8 | namespace Ganss.Text.Tests 9 | { 10 | public class WordMatchList: List 11 | { 12 | public void Add(int index, string word) 13 | { 14 | Add(new WordMatch { Index = index, Word = word }); 15 | } 16 | } 17 | 18 | public class UnitTests 19 | { 20 | [Test] 21 | public void SearchWikipediaTest() 22 | { 23 | // from https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm 24 | var ac = new AhoCorasick("a", "ab", "bab", "bc", "bca", "c", "caa"); 25 | var m = ac.Search("abccab").ToList(); 26 | var expected = new WordMatchList { { 0, "a" }, { 0, "ab" }, { 1, "bc" }, { 2, "c" }, { 3, "c" }, { 4, "a" }, { 4, "ab" } }; 27 | Assert.That(m, Is.EquivalentTo(expected)); 28 | } 29 | 30 | [Test] 31 | public void SimpleTest() 32 | { 33 | var ac = new AhoCorasick("a"); 34 | Assert.That(ac.Search("a").ToList(), Is.EquivalentTo(new WordMatchList { { 0, "a" } })); 35 | Assert.That(ac.Search("b"), Is.Empty); 36 | } 37 | 38 | [Test] 39 | public void SearchNullEmptyTest() 40 | { 41 | var ac = new AhoCorasick("a"); 42 | var m = ac.Search(null).ToList(); 43 | Assert.That(m, Is.Empty); 44 | m = ac.Search("").ToList(); 45 | Assert.That(m, Is.Empty); 46 | } 47 | 48 | [Test] 49 | public void SearchMultipleTest() 50 | { 51 | var ac = new AhoCorasick("her", "their", "eye", "iris", "he", "is", "si"); 52 | var m = ac.Search("theye iris irisis").ToList(); 53 | var expected = new WordMatchList { { 1, "he" }, { 2, "eye" }, { 6, "iris" }, { 8, "is" }, { 11, "iris" }, { 13, "is" }, { 14, "si" }, { 15, "is" } }; 54 | Assert.That(m, Is.EquivalentTo(expected)); 55 | } 56 | 57 | [Test] 58 | public void SearchIvankTest() 59 | { 60 | // from http://blog.ivank.net/aho-corasick-algorithm-in-as3.html 61 | var ac = new AhoCorasick("take", "fast", "sofa"); 62 | var m = ac.Search("takeso fasofast fassofatake sosso sofastake so").ToList(); 63 | var expected = new WordMatchList { { 0, "take" }, { 9, "sofa" }, { 11, "fast" }, { 19, "sofa" }, { 23, "take" }, { 34, "sofa" }, { 36, "fast" }, { 39, "take" } }; 64 | Assert.That(m, Is.EquivalentTo(expected)); 65 | } 66 | 67 | [Test] 68 | public void StringExtensionTest() 69 | { 70 | var m = "abc".Contains("abd", "bc", "ab").ToList(); 71 | Assert.That(m, Is.EquivalentTo(new WordMatchList { { 0, "ab" }, { 1, "bc" } })); 72 | m = "abc".Contains(new List { "abd", "bc", "ab" }).ToList(); 73 | Assert.That(m, Is.EquivalentTo(new WordMatchList { { 0, "ab" }, { 1, "bc" } })); 74 | m = "ABC".Contains(CharComparer.OrdinalIgnoreCase, "abd", "bc", "ab").ToList(); 75 | Assert.That(m, Is.EquivalentTo(new WordMatchList { { 0, "ab" }, { 1, "bc" } })); 76 | m = "ABC".Contains(CharComparer.OrdinalIgnoreCase, new List { "abd", "bc", "ab" }).ToList(); 77 | Assert.That(m, Is.EquivalentTo(new WordMatchList { { 0, "ab" }, { 1, "bc" } })); 78 | } 79 | 80 | [Test] 81 | public void UpperCaseTest() 82 | { 83 | var ac = new AhoCorasick("a", "ab", "bab", "bC", "bca", "c", "caa"); 84 | var m = ac.Search("abCcab").ToList(); 85 | var expected = new WordMatchList { { 0, "a" }, { 0, "ab" }, { 1, "bC" }, { 3, "c" }, { 4, "a" }, { 4, "ab" } }; 86 | Assert.That(m, Is.EquivalentTo(expected)); 87 | } 88 | 89 | [Test] 90 | public void OrdinalIgnoreCaseTest() 91 | { 92 | var ac = new AhoCorasick(CharComparer.OrdinalIgnoreCase, "a", "ab", "bab", "bC", "bca", "c", "caa"); 93 | var m = ac.Search("abCcab").ToList(); 94 | var expected = new WordMatchList { { 0, "a" }, { 0, "ab" }, { 1, "bC" }, { 2, "c" }, { 3, "c" }, { 4, "a" }, { 4, "ab" } }; 95 | Assert.That(m, Is.EquivalentTo(expected)); 96 | } 97 | 98 | [Test] 99 | public void OverloadsTest() 100 | { 101 | var ac = new AhoCorasick(new List { "a" }); 102 | Assert.That(ac.Search("a").ToList(), Is.EquivalentTo(new WordMatchList { { 0, "a" } })); 103 | Assert.That(ac.Search("b"), Is.Empty); 104 | 105 | ac = new AhoCorasick(CharComparer.OrdinalIgnoreCase, new List { "a", "ab", "bab", "bC", "bca", "c", "caa" }); 106 | var m = ac.Search("abCcab").ToList(); 107 | var expected = new WordMatchList { { 0, "a" }, { 0, "ab" }, { 1, "bC" }, { 2, "c" }, { 3, "c" }, { 4, "a" }, { 4, "ab" } }; 108 | Assert.That(m, Is.EquivalentTo(expected)); 109 | 110 | ac = new AhoCorasick(); 111 | ac.Add("a"); 112 | ac.BuildFail(); 113 | Assert.That(ac.Search("a").ToList(), Is.EquivalentTo(new WordMatchList { { 0, "a" } })); 114 | Assert.That(ac.Search("b"), Is.Empty); 115 | 116 | ac = new AhoCorasick(CharComparer.Create(CultureInfo.InvariantCulture, true), "a", "ab", "bab", "bc", "bca", "c", "caa"); 117 | m = ac.Search("abccab").ToList(); 118 | expected = new WordMatchList { { 0, "a" }, { 0, "ab" }, { 1, "bc" }, { 2, "c" }, { 3, "c" }, { 4, "a" }, { 4, "ab" } }; 119 | Assert.That(m, Is.EquivalentTo(expected)); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /AhoCorasick.SqlClr/Contains.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Data.SqlClient; 4 | using System.Data.SqlTypes; 5 | using Microsoft.SqlServer.Server; 6 | using System.Xml.Linq; 7 | using System.Linq; 8 | using Ganss.Text; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using System.Security.Cryptography; 12 | using System.Text; 13 | using System.Globalization; 14 | 15 | public partial class UserDefinedFunctions 16 | { 17 | private static AhoCorasick BuildAhoCorasick(SqlXml xml, SqlString culture) 18 | { 19 | var xe = XElement.Load(xml.CreateReader()); 20 | var words = xe.Elements().Select(e => e.FirstAttribute.Value); 21 | var c = culture.Value.Split(':'); 22 | var ignoreCase = c.Length > 1 && c[1] == "i"; 23 | CharComparer cc; 24 | switch (c[0]) 25 | { 26 | case "c": 27 | cc = CharComparer.Create(CultureInfo.CurrentCulture, ignoreCase); 28 | break; 29 | case "n": 30 | cc = CharComparer.Create(CultureInfo.InvariantCulture, ignoreCase); 31 | break; 32 | case "o": 33 | case "": 34 | cc = ignoreCase ? CharComparer.OrdinalIgnoreCase : CharComparer.Ordinal; 35 | break; 36 | default: 37 | cc = CharComparer.Create(CultureInfo.GetCultureInfo(c[0]), ignoreCase); 38 | break; 39 | } 40 | var ac = new AhoCorasick(cc, words); 41 | return ac; 42 | } 43 | 44 | [SqlFunction(FillRowMethodName = "FillRow", TableDefinition = @"""Index"" int, Word nvarchar(MAX)", 45 | IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 46 | public static IEnumerable ContainsWordsTable(SqlXml xml, SqlString text, SqlString culture) 47 | { 48 | var ac = BuildAhoCorasick(xml, culture); 49 | var matches = ac.Search(text.Value); 50 | 51 | return matches; 52 | } 53 | 54 | [SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 55 | public static bool ContainsWords(SqlXml xml, SqlString text, SqlString culture) 56 | { 57 | return ContainsWordsTable(xml, text, culture).Cast().Any(); 58 | } 59 | 60 | public static void FillRow(object obj, out int index, out SqlString word) 61 | { 62 | var match = (WordMatch)obj; 63 | index = match.Index; 64 | word = match.Word; 65 | } 66 | 67 | [SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 68 | public static string CreateAhoCorasick(SqlXml xml, SqlString culture) 69 | { 70 | var ac = BuildAhoCorasick(xml, culture); 71 | var hash = Hash(xml.Value + culture.Value); 72 | Objects[hash] = ac; 73 | return hash; 74 | } 75 | 76 | [SqlFunction(IsPrecise = true, DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 77 | public static bool DeleteAhoCorasick(SqlString obj) 78 | { 79 | Objects.Remove(obj.Value); 80 | return true; 81 | } 82 | 83 | [SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 84 | public static bool ClearAhoCorasick() 85 | { 86 | Objects.Clear(); 87 | return true; 88 | } 89 | 90 | [SqlFunction(FillRowMethodName = "FillRow", TableDefinition = @"""Index"" int, Word nvarchar(MAX)", IsDeterministic = true, IsPrecise = true, 91 | DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 92 | public static IEnumerable ContainsWordsTableByObject(SqlString text, SqlString obj) 93 | { 94 | var ac = Objects[obj.Value]; 95 | var matches = ac.Search(text.Value); 96 | 97 | return matches; 98 | } 99 | 100 | [SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 101 | public static bool ContainsWordsByObject(SqlString text, SqlString obj) 102 | { 103 | return ContainsWordsTableByObject(text, obj).Cast().Any(); 104 | } 105 | 106 | [SqlFunction(FillRowMethodName = "FillRow", TableDefinition = @"""Index"" int, Word nvarchar(MAX)", IsDeterministic = true, IsPrecise = true, 107 | DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 108 | public static IEnumerable ContainsWordsBoundedTableByObject(SqlString text, SqlString obj) 109 | { 110 | var ac = Objects[obj.Value]; 111 | var t = text.Value; 112 | var matches = ac.Search(t).Cast().Where(m => 113 | { 114 | var start = m.Index == 0 || !char.IsLetterOrDigit(t[m.Index - 1]); 115 | var end = (m.Index + m.Word.Length) == t.Length || !char.IsLetterOrDigit(t[m.Index + m.Word.Length]); 116 | return start && end; 117 | }); 118 | 119 | return matches; 120 | } 121 | 122 | [SqlFunction(IsDeterministic = true, IsPrecise = true, DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 123 | public static bool ContainsWordsBoundedByObject(SqlString text, SqlString obj) 124 | { 125 | return ContainsWordsBoundedTableByObject(text, obj).Cast().Any(); 126 | } 127 | 128 | [SqlFunction(FillRowMethodName = "FillRowList", TableDefinition = @"Hash nvarchar(MAX)", IsDeterministic = true, IsPrecise = true, 129 | DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None)] 130 | public static IEnumerable ListAhoCorasick() 131 | { 132 | return Objects.Keys; 133 | } 134 | 135 | public static void FillRowList(object obj, out SqlString word) 136 | { 137 | word = (string)obj; 138 | } 139 | 140 | private static string Hash(string s) 141 | { 142 | return string.Concat(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(s)).Select(b => b.ToString("X2"))); 143 | } 144 | 145 | private static readonly Dictionary Objects = new Dictionary(); 146 | } 147 | -------------------------------------------------------------------------------- /AhoCorasick/AhoCorasick.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Ganss.Text 4 | { 5 | /// 6 | /// Represents a word match. 7 | /// 8 | public struct WordMatch 9 | { 10 | /// 11 | /// Gets or sets the index of the matched word in the searched text string. 12 | /// 13 | /// 14 | /// The index. 15 | /// 16 | public int Index { get; set; } 17 | 18 | /// 19 | /// Gets or sets the matched word. 20 | /// 21 | /// 22 | /// The matched word. 23 | /// 24 | public string Word { get; set; } 25 | } 26 | 27 | /// 28 | /// Implements the Aho-Corasick algorithm. 29 | /// 30 | public class AhoCorasick 31 | { 32 | /// 33 | /// Gets or sets the trie. 34 | /// 35 | /// 36 | /// The trie. 37 | /// 38 | protected Trie Trie { get; set; } 39 | 40 | /// 41 | /// Initializes a new instance of the class. 42 | /// Does not build the failure nodes. Call after adding words before calling . 43 | /// 44 | public AhoCorasick() 45 | { 46 | Trie = new Trie(); 47 | } 48 | 49 | /// 50 | /// Initializes a new instance of the class. 51 | /// 52 | /// Does not build the failure nodes. Call after adding words before calling . 53 | /// The comparer used to compare individual characters. 54 | public AhoCorasick(IEqualityComparer comparer) 55 | { 56 | Trie = new Trie(comparer); 57 | } 58 | 59 | /// 60 | /// Initializes a new instance of the class. 61 | /// 62 | /// The words to find. 63 | public AhoCorasick(params string[] words) 64 | : this() 65 | { 66 | Add(words); 67 | } 68 | 69 | /// 70 | /// Initializes a new instance of the class. 71 | /// 72 | /// The words to find. 73 | public AhoCorasick(IEnumerable words) 74 | : this() 75 | { 76 | Add(words); 77 | } 78 | 79 | /// 80 | /// Initializes a new instance of the class. 81 | /// 82 | /// The comparer used to compare individual characters. 83 | /// The words to find. 84 | public AhoCorasick(IEqualityComparer comparer, params string[] words) 85 | : this(comparer) 86 | { 87 | Add(words); 88 | } 89 | 90 | /// 91 | /// Initializes a new instance of the class. 92 | /// 93 | /// The comparer used to compare individual characters. 94 | /// The words to find. 95 | public AhoCorasick(IEqualityComparer comparer, IEnumerable words) 96 | : this(comparer) 97 | { 98 | Add(words); 99 | } 100 | 101 | /// 102 | /// Adds the specified word. 103 | /// 104 | /// Does not build the failure nodes. Call after adding words before calling . 105 | /// The word. 106 | public void Add(string word) 107 | { 108 | Trie.Add(word); 109 | } 110 | 111 | /// 112 | /// Adds the specified words. 113 | /// 114 | /// The words. 115 | public void Add(IEnumerable words) 116 | { 117 | foreach (var word in words) 118 | { 119 | Trie.Add(word); 120 | } 121 | 122 | BuildFail(); 123 | } 124 | 125 | /// 126 | /// Builds the failure nodes necessary to perform search. 127 | /// 128 | /// The start node. 129 | public void BuildFail(Trie node = null) 130 | { 131 | node ??= Trie; 132 | 133 | var word = node.Word; 134 | for (int i = 1; i < word.Length && node.Fail == null; i++) 135 | node.Fail = Trie.ExploreFailLink(word, i, word.Length); 136 | 137 | foreach (var subNode in node.Next.Values) 138 | BuildFail(subNode); 139 | } 140 | 141 | /// 142 | /// Searches for words in the specified text. 143 | /// 144 | /// The text. 145 | /// The matched words. 146 | public virtual IEnumerable Search(string text) 147 | { 148 | if (text == null) yield break; 149 | 150 | var current = Trie; 151 | 152 | for (int i = 0; i < text.Length; i++) 153 | { 154 | var c = text[i]; 155 | 156 | while (current != null && !current.Next.ContainsKey(c)) 157 | current = current.Fail; 158 | 159 | current ??= Trie; 160 | 161 | if (current.Next.TryGetValue(c, out current)) 162 | { 163 | var node = current; 164 | 165 | while (node != null) 166 | { 167 | if (node.IsWord) 168 | { 169 | var word = node.Word; 170 | var offset = i + 1 - word.Length; 171 | yield return new WordMatch { Index = offset, Word = word }; 172 | } 173 | 174 | node = node.Fail; 175 | } 176 | } 177 | } 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /AhoCorasick/CharComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Ganss.Text 8 | { 9 | class OrdinalCharComparer : CharComparer 10 | { 11 | private readonly bool _ignoreCase; 12 | 13 | public OrdinalCharComparer(bool ignoreCase = false) 14 | { 15 | _ignoreCase = ignoreCase; 16 | } 17 | 18 | public override bool Equals(char x, char y) 19 | { 20 | return _ignoreCase ? ((uint)char.ToUpperInvariant(x)).Equals(((uint)char.ToUpperInvariant(y))) 21 | : ((uint)x).Equals((uint)y); 22 | } 23 | 24 | public override int GetHashCode(char obj) 25 | { 26 | return _ignoreCase ? (int)char.ToUpperInvariant(obj) : (int)obj; 27 | } 28 | } 29 | 30 | #if NET40 31 | class CultureCharComparer : CharComparer 32 | { 33 | private readonly StringComparer _stringComparer; 34 | 35 | public CultureCharComparer(CultureInfo cultureInfo, bool ignoreCase = false) 36 | { 37 | _stringComparer = StringComparer.Create(cultureInfo, ignoreCase); 38 | } 39 | 40 | public override bool Equals(char x, char y) 41 | { 42 | return _stringComparer.Equals(x.ToString(), y.ToString()); 43 | } 44 | 45 | public override int GetHashCode(char obj) 46 | { 47 | return _stringComparer.GetHashCode(obj.ToString()); 48 | } 49 | } 50 | #else 51 | class CultureCharComparer: CharComparer 52 | { 53 | private readonly CompareInfo _compareInfo; 54 | private readonly bool _ignoreCase; 55 | 56 | public CultureCharComparer(CultureInfo cultureInfo, bool ignoreCase = false) 57 | { 58 | _compareInfo = cultureInfo.CompareInfo; 59 | _ignoreCase = ignoreCase; 60 | } 61 | 62 | public override bool Equals(char x, char y) 63 | { 64 | return _compareInfo.Compare(x.ToString(), y.ToString(), _ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None) == 0; 65 | } 66 | 67 | public override int GetHashCode(char obj) 68 | { 69 | return _compareInfo.GetHashCode(obj.ToString(), _ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); 70 | } 71 | } 72 | #endif 73 | 74 | /// 75 | /// Represents a char comparison operation that uses specific case and culture-based or ordinal comparison rules. 76 | /// 77 | public abstract class CharComparer: EqualityComparer 78 | { 79 | private static readonly CharComparer _ordinalIgnoreCase = new OrdinalCharComparer(ignoreCase: true); 80 | 81 | /// 82 | /// Gets a object that performs a case-insensitive ordinal comparison. 83 | /// 84 | /// 85 | /// A object. 86 | /// 87 | public static CharComparer OrdinalIgnoreCase 88 | { 89 | get 90 | { 91 | return _ordinalIgnoreCase; 92 | } 93 | } 94 | 95 | private static readonly CharComparer _ordinal = new OrdinalCharComparer(ignoreCase: false); 96 | 97 | /// 98 | /// Gets a object that performs a case-sensitive ordinal comparison. 99 | /// 100 | /// 101 | /// A object. 102 | /// 103 | public static CharComparer Ordinal 104 | { 105 | get 106 | { 107 | return _ordinal; 108 | } 109 | } 110 | 111 | private static readonly CharComparer _invariantCultureIgnoreCase = new CultureCharComparer(CultureInfo.InvariantCulture, ignoreCase: true); 112 | 113 | /// 114 | /// Gets a object that performs a case-insensitive comparison using the comparison rules of the invariant culture. 115 | /// 116 | /// 117 | /// A object. 118 | /// 119 | public static CharComparer InvariantCultureIgnoreCase 120 | { 121 | get 122 | { 123 | return _invariantCultureIgnoreCase; 124 | } 125 | } 126 | 127 | private static readonly CharComparer _invariantCulture = new CultureCharComparer(CultureInfo.InvariantCulture, ignoreCase: false); 128 | 129 | /// 130 | /// Gets a object that performs a case-sensitive comparison using the comparison rules of the invariant culture. 131 | /// 132 | /// 133 | /// A object. 134 | /// 135 | public static CharComparer InvariantCulture 136 | { 137 | get 138 | { 139 | return _invariantCulture; 140 | } 141 | } 142 | 143 | /// 144 | /// Gets a object that performs a case-sensitive comparison using the comparison rules of the current culture. 145 | /// 146 | /// 147 | /// A object. 148 | /// 149 | public static CharComparer CurrentCulture 150 | { 151 | get 152 | { 153 | return new CultureCharComparer(CultureInfo.CurrentCulture, ignoreCase: false); 154 | } 155 | } 156 | 157 | /// 158 | /// Gets a object that performs a case-insensitive comparison using the comparison rules of the current culture. 159 | /// 160 | /// 161 | /// A object. 162 | /// 163 | public static CharComparer CurrentCultureIgnoreCase 164 | { 165 | get 166 | { 167 | return new CultureCharComparer(CultureInfo.CurrentCulture, ignoreCase: true); 168 | } 169 | } 170 | 171 | /// 172 | /// Creates a object that compares characters according to the rules of a specified culture. 173 | /// 174 | /// A culture whose linguistic rules are used to perform a string comparison. 175 | /// true to specify that comparison operations be case-insensitive; false to specify that comparison operations be case-sensitive. 176 | /// A new object that performs character comparisons according to the comparison rules used by the parameter and the case rule specified by the parameter. 177 | public static CharComparer Create(CultureInfo cultureInfo, bool ignoreCase) 178 | { 179 | return new CultureCharComparer(cultureInfo, ignoreCase); 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AhoCorasick 2 | 3 | [![Version](https://img.shields.io/nuget/v/AhoCorasick.svg)](https://www.nuget.org/packages/AhoCorasick) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/b8lxercfn9spio95/branch/master?svg=true)](https://ci.appveyor.com/project/mganss/ahocorasick/branch/master) 5 | [![Coverage Status](https://coveralls.io/repos/mganss/AhoCorasick/badge.svg?branch=master&service=github)](https://coveralls.io/github/mganss/AhoCorasick?branch=master) 6 | [![netstandard2.0](https://img.shields.io/badge/netstandard-2.0-brightgreen.svg)](https://img.shields.io/badge/netstandard-2.0-brightgreen.svg) 7 | [![net40](https://img.shields.io/badge/net-40-brightgreen.svg)](https://img.shields.io/badge/net-40-brightgreen.svg) 8 | 9 | This is an implementation of the [Aho-Corasick](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm) string matching algorithm for .NET (netstandard2.0 and net40) and SQL Server (SQL CLR). Mostly ported from [xudejian/aho-corasick](https://github.com/xudejian/aho-corasick) in CoffeeScript. 10 | 11 | ## Usage 12 | 13 | ```C# 14 | var ac = new AhoCorasick("a", "ab", "bab", "bc", "bca", "c", "caa"); 15 | var results = ac.Search("abccab").ToList(); 16 | 17 | Assert.AreEqual(0, results[0].Index); // index into the searched text 18 | Assert.AreEqual("a", results[0].Word); // matched word 19 | // ... 20 | ``` 21 | 22 | or 23 | 24 | ```C# 25 | var results = "abccab".Contains("a", "ab", "bab", "bc", "bca", "c", "caa").ToList(); 26 | ``` 27 | 28 | ### Custom char comparison 29 | 30 | You can optionally supply an `IEqualityComparer` to perform custom char comparisons when searching for substrings. Several implementations with comparers that mirror `StringComparer` are included. 31 | 32 | ```C# 33 | var results = "AbCcab".Contains(CharComparer.OrdinalIgnoreCase, "a", "ab", "c").ToList(); 34 | ``` 35 | 36 | ## SQL CLR Functions 37 | 38 | There are also several SQL CLR user defined functions that can be used to perform fast substring matching 39 | in Microsoft SQL Server. To use this: 40 | 41 | 1. Make sure you have [enabled CLR integration](https://msdn.microsoft.com/en-us/library/ms131048.aspx) 42 | 2. Execute [AhoCorasick.SqlClr_Create.sql](AhoCorasick.SqlClr/dist/AhoCorasick.SqlClr_Create.sql) 43 | 44 | For one-off queries, you can use the functions that rebuild the trie on each query, e.g. 45 | 46 | ```SQL 47 | select top(100) * from Posts P 48 | where dbo.ContainsWords((select Word from Words for xml raw, root('root')), P.Body, 'o') = 1 49 | ``` 50 | 51 | The words to match are always supplied as XML where the values are taken from the first attribute of all elements directly beneath the root node. Be careful to select the word column as the only or first column otherwise you'll end up matching the wrong words. The XML in the example above looks like this: 52 | 53 | ```XML 54 | 55 | 56 | 57 | 58 | ... 59 | 60 | ``` 61 | 62 | [Here's more](https://www.simple-talk.com/sql/learn-sql-server/using-the-for-xml-clause-to-return-query-results-as-xml/) about FOR XML. 63 | 64 | The last parameter in the function indicates the culture to use since there is no way to use SQL Server collations in SQL CLR code. Values can be: 65 | 66 | |Value|Character comparison| 67 | |-----|--------------------| 68 | |c|Current Culture| 69 | |n|Invariant Culture| 70 | |o or Empty|Ordinal| 71 | |Culture name, e.g. "de-de"|Specific [.NET Culture](https://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.name.aspx)| 72 | 73 | The culture identifier can be suffixed by `:i` indicating case-insensitive matching. 74 | 75 | ### Static objects 76 | 77 | The function in the example above has the problem that the trie is rebuilt for each query even though the input always stays the same. To overcome this problem, there are a number of functions to manage the creation and destruction of static objects whose handles can be saved in SQL variables. Example: 78 | 79 | ```SQL 80 | declare @ac nvarchar(32); 81 | set @ac = dbo.CreateAhoCorasick((select Word from Words for xml raw, root('root')), 'en-us:i'); 82 | select * from Posts P 83 | where dbo.ContainsWordsByObject(P.Body, @ac) = 1; 84 | ``` 85 | 86 | This is a lot faster than the first example because the trie is created only once and then reused for each row in the query. The handle (@ac) is a hash value generated from the words to match and the culture. The corresponding object is saved in a static dictionary. You can list the currently active objects using `dbo.ListAhoCorasick()`, remove all objects using `dbo.ClearAhoCorasick()` or remove only one object using `dbo.DeleteAhoCorasick(@ac)`. 87 | 88 | ### Getting all matches 89 | 90 | The examples above only checked if the words occurred in the queried texts. If you want to get the matched words and the indexes where they occur in the queried texts you can use the supplied table-valued functions. For example: 91 | 92 | ```SQL 93 | declare @ac nvarchar(32); 94 | set @ac = dbo.CreateAhoCorasick((select Word from Words for xml raw, root('root')), 'o'); 95 | select top(100) * from Posts P 96 | cross apply dbo.ContainsWordsTableByObject(P.Body, @ac) W 97 | ``` 98 | 99 | This will return a table such as this: 100 | 101 | |ID |Body |Index |Word | 102 | |---|---|---|---| 103 | |1 |What factors related...|5|factor| 104 | |1 |What factors related...|6|actor| 105 | |1 |What factors related...|5|factors| 106 | |...| 107 | 108 | ### Word boundaries 109 | 110 | There are also functions that return only matches occuring at word boundaries: `dbo.ContainsWordsBoundedByObject()` and `dbo.ContainsWordsBoundedTableByObject()`. Word boundaries here are the same as [`\b` in regexes](http://www.regular-expressions.info/wordboundaries.html), i.e. matches will occur as if words were specified as `\bword\b`. 111 | 112 | ### Forcing parallelism 113 | 114 | Although these kinds of queries lend themselves very well to parallel execution, SQL Server tends to overestimate the cost of parallel queries and builds non-parallel plans most of the time where user defined functions are involved. You can force a parallel plan by using a trace flag (more about this [here](http://sqlblog.com/blogs/paul_white/archive/2011/12/23/forcing-a-parallel-query-execution-plan.aspx)): 115 | 116 | ```SQL 117 | declare @ac nvarchar(32); 118 | set @ac = dbo.CreateAhoCorasick((select Word from Words for xml raw, root('root')), 'en-us:i'); 119 | select * from Posts P 120 | where dbo.ContainsWordsBoundedByObject(P.Body, @ac) = 1 121 | OPTION (RECOMPILE, QUERYTRACEON 8649) 122 | ``` 123 | 124 | Parallel operators are identified by a yellow badge with two arrows in the query plan. 125 | 126 | ### Performance 127 | 128 | Here's a benchmark searching for ~5000 words (average length 7) in ~250,000 texts (average length ~900): 129 | 130 | |SQL|AhoCorasick| 131 | |---|-----------| 132 | |560s|7s| 133 | 134 | The SQL query used was this: 135 | 136 | ```SQL 137 | select * from Posts P 138 | where exists (select * from Words W where CHARINDEX(W.Word, P.Text) > 0) 139 | ``` 140 | 141 | #### But I can simply use full-text search 142 | 143 | No. The [CONTAINS](https://msdn.microsoft.com/en-us/library/ms187787.aspx) predicate can only search for a single literal or variable at a time. You can't use it in a join or subquery to search for a column value of a table in the query, i.e. this won't work: 144 | 145 | ```SQL 146 | select * from Posts P 147 | where exists (select * from Words W where CONTAINS(P.Text, W.Word)) 148 | ``` 149 | 150 | If you know of a way to make this work using FTS (perhaps using a cursor?) let me know. 151 | -------------------------------------------------------------------------------- /AhoCorasick.SqlClr/dist/AhoCorasick.SqlClr_Create.sql: -------------------------------------------------------------------------------- 1 | PRINT N'Creating [AhoCorasick.SqlClr]...'; 2 | 3 | 4 | GO 5 | CREATE ASSEMBLY [AhoCorasick.SqlClr] 6 | AUTHORIZATION [dbo] 7 | FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300F0CEA95D0000000000000000E00022200B013000002E00000006000000000000F64D000000200000006000000000001000200000000200000400000000000000040000000000000000A000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000A44D00004F00000000600000D002000000000000000000000000000000000000008000000C0000006C4C00001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000FC2D000000200000002E000000020000000000000000000000000000200000602E72737263000000D0020000006000000004000000300000000000000000000000000000400000402E72656C6F6300000C0000000080000000020000003400000000000000000000000000004000004200000000000000000000000000000000D84D0000000000004800000002000500C8290000A4220000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013300500EB00000001000011026F0F00000A281000000A6F1100000A7E11000004252D17267E10000004FE0640000006731200000A258011000004280100002B0A0F01281400000A178D2000000125161F3A9D6F1500000A0B078E6917310F07179A7201000070281600000A2B01160C07169A130411042C6711047205000070281600000A2D2B11047209000070281600000A2D2B1104720D000070281600000A2D2B11042C391104281700000A2C1E2B2E281800000A08282D0000060D2B2F281900000A08282D0000060D2B21082D0728280000062B0528270000060D2B0F07169A281A00000A08282D0000060D0906731C0000062A52020428010000060F01281400000A6F200000062A4E0203042802000006280200002B280300002B2A13300200230000000200001102A5030000020A0312002811000006540412002813000006281D00000A81080000012A00133003002E00000003000011020328010000060A026F1E00000A0F01281400000A281F00000A280E0000060B7E0100000407066F2000000A072A527E010000040F00281400000A6F2100000A26172A327E010000046F2200000A172A7A7E010000040F01281400000A6F2300000A0F00281400000A6F200000062A4A02032808000006280200002B280300002B2A000013300300460000000400001173420000060A7E010000040F01281400000A6F2300000A060F00281400000A7D13000004067B130000046F20000006280200002B06FE0643000006732400000A280400002B2A4A0203280A000006280200002B280300002B2A2E7E010000046F2600000A2A4A03027421000001281D00000A81080000012AFE282700000A282800000A026F2900000A6F2A00000A7E12000004252D17267E10000004FE0641000006732B00000A258012000004280500002B282C00000A2A1E02282D00000A2A2E732E00000A80010000042A1E027B020000042A2202037D020000042A1E027B030000042A2202037D030000042A1E027B040000042A2202037D040000042A4A02282D00000A02733A00000628160000062A4E02282D00000A0203733B00000628160000062A3A0228170000060203281E0000062A3E020328180000060204281E0000062A3A022815000006036F3C000006262A1B3002003900000005000011036F2F00000A0A2B14066F3000000A0B022815000006076F3C00000626066F0800000A2DE4DE0A062C06066F0700000ADC0214281F0000062A00000001100000020007002027000A000000001B300400810000000600001103252D07260228150000061001036F380000060A170B2B1C0302281500000606076F3100000A6F3D0000066F350000060717580B07066F1700000A2F08036F340000062CD3036F300000066F3200000A6F3300000A0C2B0F1202283400000A0D0209281F0000061202283500000A2DE8DE0E1202FE160C00001B6F0700000ADC2A00000001100000020056001C72000E000000005A1FFE734400000625027D1900000425037D180000042A3A02282E00000602037D050000042A0000133002002800000007000011027B050000042D0B030A120004283600000A2A03283700000A0A120004283700000A283600000A2A46027B050000042D02032A03283700000A2A5202282E000006020304283800000A7D060000042A6A027B060000040F01283900000A0F02283900000A6F3A00000A2A4E027B060000040F01283900000A6F3B00000A2A1A7E070000042A1A7E080000042A1A7E090000042A1A7E0A0000042A32281800000A1673240000062A32281800000A1773240000062A22020373240000062A1E02283C00000A2ADE17732100000680070000041673210000068008000004281900000A1773240000068009000004281900000A167324000006800A0000042A1E027B0B0000042A2202037D0B0000042A1E027B0C0000042A2202037D0C0000042A1E027B0D0000042A2202037D0D0000042A1E027B0E0000042A2202037D0E0000042A1E027B0F0000042A2202037D0F0000042A7602282D00000A027211000070283900000602733D00000A28310000062A7A02282D00000A02721100007028390000060203733E00000A28310000062A0013300600750000000800001103166F3F00000A0A0228300000060612016F4000000A2D3D022830000006060228300000066F4100000A733B00000625026F37000006250228380000061200283900000A281F00000A6F39000006250B6F4200000A036F1700000A17310E0703176F3100000A6F3C0000062A07176F33000006072A000000133003003300000009000011020A030B160C2B2007086F3F00000A0D066F300000060912006F4000000A26062D02142A0817580C08076F1700000A32D7062A2E733F00000680100000042A32036F4300000A6F4400000A2A360F017213000070284500000A2A000013300400770000000A0000110F0128110000062C1E027B130000040F01281100000617596F3F00000A284600000A16FE012B01170F0128110000060F0128130000066F1700000A58027B130000046F1700000A2E29027B130000040F0128110000060F0128130000066F1700000A586F3F00000A284600000A16FE012B01170A065F2A7A02282D00000A02037D1400000402284700000A6F4800000A7D160000042A062A13300300660100000B000011027B140000040A027B190000040B062C0906173BFD000000162A02157D14000004027B170000042D02162A020728150000067D1A00000402167D1B000004380B010000027B17000004027B1B0000046F3F00000A0C2B1102027B1A0000046F340000067D1A000004027B1A0000042C13027B1A0000046F30000006086F4900000A2CD4027B1A0000042D0C020728150000067D1A000004027B1A0000046F3000000608027C1A0000046F4000000A398900000002027B1A0000047D1C0000042B6C027B1C0000046F320000062C4E027B1C0000046F380000060D027B1B0000041758096F1700000A591304021205FE1503000002120511042812000006120509281400000611057D1500000402177D14000004172A02157D1400000402027B1C0000046F340000067D1C000004027B1C0000042D8C02147D1C000004027B1B000004130602110617587D1B000004027B1B000004027B170000046F1700000A3FDFFEFFFF162A1E027B150000042A1A734A00000A7A32027B150000048C030000022A000013300200480000000C000011027B140000041FFE331D027B16000004284700000A6F4800000A330B02167D14000004020A2B131673440000060A06027B190000047D1900000406027B180000047D17000004062A1E02284A0000062A42534A4201000100000000000C00000076342E302E33303331390000000005006C000000400D0000237E0000AC0D00003C0B000023537472696E677300000000E81800001C0000002355530004190000100000002347554944000000141900009009000023426C6F620000000000000002000001571FA20B090A000000FA013300160000010000002A0000000B0000001C0000004B0000003E000000050000004A00000003000000310000000C000000050000001000000018000000070000000C000000010000000500000003000000050000000000B90501000000000006003204FD0706007904FD070600F103D6070F001D08000006002209F8050600C40025010A00DB052C080A00D9042C080600780025010A001D0417070A00290217070A002302170706009B0266080600D603FD070600BD00F8050E00880971060600B302F80506008600250106006504F80506009A0025011B00220600005700BE0700000600A702F80506004507660806000504D6070600C706F805060059060D060600870025011200A506D0050E00AF06710616009C02810606009306F8050600E504F8051B00320600000600F2000F0B0600D004C00A0600FF050F0B0600A800F8050E00CB03710606009704F80506007401BF0406004006F8050000000003010000000001000100010010007908000015000100010009011000FD04CC0A450002001100010010006C05CC0A15000400150000001000FA06CC0A1C000500210000001000E606CC0A1C0006002400810010000107CC0A0E0007002700010010008302CC0A15000B0030000321100021010000150010003E00030110003B00000015001300420003011000D100000015001400440031009808420201000C024B02010084014E020100B20151022100920355022100D606580231007F035C02310094055C02310030035C023100E4025C020100F601600201009A0155020100C80151020100DE015102010084014E023600FF006902160001006D021600230076020600DF0A4E020100C0034B020100870A7E02010054014B020100DC0A4E020600D70A4E020600550882020100AF0051020100DF004B020100E70051025020000000009100220586020100472100000000960088028F0203005C21000000009600E9079A0206007021000000009600E10AA4020900A0210000000096003305AE020C00DA210000000096004505B6020E00EF210000000096005705BC020F00FC21000000009600F808C0020F001B220000000096001309C90211003022000000009600D608C00213008222000000009600B908C902150095220000000096006805D1021700A122000000009600990AD6021700B4220000000091000E05DE021900F422000000008618C90706001A00FC22000000009118CF07E3021A000823000000008608E90A9F001A001023000000008608F30A01001A00192300000000860838028E001B0021230000000086084102E7021B002A230000000084087602EC021C0032230000000084087F02F1021C003B23000000008618C90706001D004E23000000008618C907F7021D006223000000008618C90700031E006223000000008618C90706031F007123000000008618C9070F0320007123000000008618C9071A03220081230000000086008001E70224009023000000008600800106032500E823000000008600AF05F1022600882400000000C601F604280327009F24000000008618C90732032800B02400000000C6005F0837032900E42400000000C60065023D032B00F624000000008618C90742032C000B2500000000C6005F0837032E00262500000000C60065023D0330003A25000000009608690349033100412500000000960888054903310048250000000096081103490331004F25000000009608CF02490331005625000000009608F6024903310063250000000096084C03490331007025000000009600B9034E0331007925000000008418C907060033008125000000009118CF07E3023300B925000000008608A50A56033300C125000000008608AE0A60033300CA250000000086084A0210003400D225000000008608550232033400DB250000000086089D05EC023500E325000000008608A605F1023500EC250000000086089109EC023600F4250000000086089C09F1023600FD2500000000860838028E00370005260000000081084102E70237000E26000000008618C907060038002C26000000008618C907F70238004C2600000000C60180016B033900D02600000000C60178056B033A000F27000000009118CF07E3023B00F422000000008618C90706003B001B270000000083000A0071033B0028270000000083002D0077033C00F422000000008618C90706003D00382700000000830050007C033D00BB27000000008618C90701003E00DA2700000000E1019E0306003F00DC2700000000E101B70A10003F004E2900000000E109130A82033F00562900000000E101300906003F005D2900000000E1095C0A20003F006C2900000000E101510787033F00C02900000000E1019C0734003F0000000100E20500000200090300000100E20500000200DC0A00000300090300000100E20500000200DC0A000003000903000001001E0502000200FD0A02000300600200000100E205000002000903000001001E0500000100DC0A000002001E0500000100DC0A000002001E0500000100DC0A000002001E0500000100DC0A000002001E05000001001E0502000200600200000100B00800000100B20400000100B20400000100B204000001000E0700000100F70700000100F707000001000E0700000200F707000001000E0700000200F70700000100600200000100F70710100100710200000100DC0A10100100930300000100010B000002003A0B000001001E0500000100650610100200930300000100010B000002003A0B000001001E0500000100650600000200930300000100B20400000100B20400000100B20400000100B20400000100B204000001000E0700000100600200000100600200000100BD04000001001F01000001000B0600000100C0030B000A000B0035000B0006000B005D000B0061000900C90701001100C90706001900C9070A005100C90706007100C90706009900C9070600B900B1030600C100B70A10000C007B0A1B00C1004F090600C1007B0A20001400BB072B006900BB073400C900C9070600390098064D0081007B015200F100A00859002400C9076A00F9002909700041009C048E000901710992000901300B9900090113059F00D900F602A300D900CF02A300D9005606A800F900940AAE00F9002C0BBF0041005509CF0039009C048E000901B208DB002C00EF05E9002C00B804F1002C008D0606002C00E605F7003400C9076A00F900BD020B012C00A90822011901B9032E012101F6003401210141083A012901070540013C00C9076A000901B20853012900C90706002C00C90706004400BB072B004C007B0A1B000901EC047F0154004A088C015C00BB079F0164007B0AB2016400B70A100031015F08BB0101017709C001D100B903C5010101E3048E00D1005F08CD01D1006502D3011C00C90706005400C90706005400C907D80109018E08E8015400A604ED015400BA06F6015400EF05E90081005204070239019C048E004101E3040D02010161091602490169011B02490140019F005400030BF1005101C9070600120099003B020200A10040020200B50040022E000B00B9032E001300C2032E001B00E10340002300EA0341002B008A0960002300800561002B008A0981002B008A09A00023008005C0002300C806E0002300800500012300EA0320012300800523012B008A0940012300EA0343012B008A0960012300800561012B008A0963012B008A0980012300FD0781012B008A09A1012B008A09C1012B008A09E1012B008A0920022B008A0940022B008A0960022B008A0980022B008A09A0022B008A09C0022B008A09C40333008A09240433008A0900062B008A0920062B008A0940062B008A0960062B008A0980062B008A09A0062B008A09C0062B008A09E0062B008A0900072B008A0920072B008A09800873008A09A00873008A09E00873008A09000973008A09200973008A09400973008A09600973008A093F00CA00D500FE005C017101B701E201FF01120221022D0203000100040003000700040008000A000B000F000000F70A900300005B02940300008302980300006D039D0300008C059D03000015039D030000D3029D030000FA029D03000050039D030000BB0AA20300005902AC030000B40598030000A009980300005B0294030000A709B0030000EC09B503020011000300010012000300020013000500010014000500020015000700010016000700020027000900020028000B00020029000D0002002A000F0002002B00110002002C001300020030001500010031001500020032001700010033001700020034001900010035001900020036001B00010037001B00020038001D00010039001D00020047001F000200490021000B008A000F000B008C0011000B008E0013000B00900015000B00920017000B00940019000B0096001B001400240039006200E1000301470165016B0184019701AA0104800000000000000000000000000000000032070000040000000000000000000000320218010000000004000000000000000000000032020C010000000004000000000000000000000032027106000000000400000000000000000000003202D005000000000400000000000000000000003202C30200000000090002000A0002000B000400270088003700BA003900BA004B00BA0027004E010000003C3E395F5F305F30003C4275696C6441686F436F72617369636B3E625F5F305F30003C3E395F5F31335F30003C486173683E625F5F31335F30003C3E635F5F446973706C6179436C617373395F30003C436F6E7461696E73576F726473426F756E6465645461626C6542794F626A6563743E625F5F300049456E756D657261626C6560310049457175616C697479436F6D706172657260310049456E756D657261746F7260310055496E743332003C63757272656E743E355F5F320046756E6360320044696374696F6E6172796032003C5365617263683E645F5F3133003C693E355F5F33003C6E6F64653E355F5F34004D4435006765745F55544638003C3E39003C4D6F64756C653E0053797374656D2E44617461006D73636F726C6962003C3E630053797374656D2E436F6C6C656374696F6E732E47656E65726963006765745F4D616E616765645468726561644964003C3E6C5F5F696E697469616C5468726561644964006765745F43757272656E74546872656164004C6F616400416464003C576F72643E6B5F5F4261636B696E674669656C64003C4973576F72643E6B5F5F4261636B696E674669656C64003C547269653E6B5F5F4261636B696E674669656C64003C4661696C3E6B5F5F4261636B696E674669656C64003C506172656E743E6B5F5F4261636B696E674669656C64003C4E6578743E6B5F5F4261636B696E674669656C64003C496E6465783E6B5F5F4261636B696E674669656C640053797374656D446174614163636573734B696E64006765745F576F7264007365745F576F7264006765745F4973576F7264007365745F4973576F726400776F72640047657448617368436F6465006E6F6465006765745F54726965007365745F5472696500436F6E7461696E73576F7264735461626C650049456E756D657261626C650049446973706F7361626C650056616C7565547970650057686572650053797374656D2E436F7265006765745F496E76617269616E7443756C74757265005F696E76617269616E7443756C74757265006765745F43757272656E7443756C747572650063756C74757265006765745F496E76617269616E7443756C7475726549676E6F726543617365005F696E76617269616E7443756C7475726549676E6F726543617365006765745F43757272656E7443756C7475726549676E6F726543617365006765745F4F7264696E616C49676E6F726543617365005F6F7264696E616C49676E6F726543617365005F69676E6F7265436173650053797374656D2E49446973706F7361626C652E446973706F736500437265617465003C3E315F5F7374617465005841747472696275746500436F6D70696C657247656E6572617465644174747269627574650044656275676761626C6541747472696275746500446562756767657248696464656E4174747269627574650053716C46756E6374696F6E41747472696275746500436F6D70696C6174696F6E52656C61786174696F6E73417474726962757465006765745F466972737441747472696275746500506172616D41727261794174747269627574650052756E74696D65436F6D7061746962696C6974794174747269627574650042797465006765745F56616C75650054727947657456616C75650076616C75650052656D6F76650053797374656D2E546872656164696E6700456E636F64696E670053716C537472696E6700546F537472696E6700537562737472696E670053656172636800576F72644D6174636800436F6D7075746548617368006765745F4C656E677468006F626A004275696C6441686F436F72617369636B0043726561746541686F436F72617369636B0044656C65746541686F436F72617369636B00436C65617241686F436F72617369636B004C69737441686F436F72617369636B004578706C6F72654661696C4C696E6B006765745F4F7264696E616C005F6F7264696E616C006765745F4661696C007365745F4661696C004275696C644661696C0041686F436F72617369636B2E53716C436C722E646C6C0053797374656D2E586D6C0053716C586D6C00786D6C006765745F4974656D007365745F4974656D0053797374656D0048617368416C676F726974686D0053797374656D2E476C6F62616C697A6174696F6E0056616C7565436F6C6C656374696F6E004B6579436F6C6C656374696F6E004E6F74537570706F72746564457863657074696F6E0047657443756C74757265496E666F0063756C74757265496E666F0053797374656D2E586D6C2E4C696E710053797374656D2E4C696E7100436C65617200436861720043726561746552656164657200586D6C5265616465720058436F6E7461696E6572006765745F436F6D706172657200537472696E67436F6D7061726572005F737472696E67436F6D70617265720043756C7475726543686172436F6D7061726572004F7264696E616C43686172436F6D706172657200636F6D7061726572004D6963726F736F66742E53716C5365727665722E5365727665720041686F436F72617369636B2E53716C436C720049456E756D657261746F720053797374656D2E436F6C6C656374696F6E732E47656E657269632E49456E756D657261626C653C47616E73732E546578742E576F72644D617463683E2E476574456E756D657261746F720053797374656D2E436F6C6C656374696F6E732E49456E756D657261626C652E476574456E756D657261746F72002E63746F72002E6363746F720053797374656D2E446961676E6F737469637300436F6E7461696E73576F72647300776F7264730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F6465730053797374656D2E446174612E53716C5479706573004765744279746573006765745F56616C756573003C3E345F5F7468697300457175616C730053797374656D2E436F6C6C656374696F6E730055736572446566696E656446756E6374696F6E73006765745F4368617273004F626A6563747300456C656D656E7473006765745F4B65797300436F6E63617400436F6E7461696E73576F726473426F756E64656442794F626A65637400436F6E7461696E73576F726473426F756E6465645461626C6542794F626A65637400436F6E7461696E73576F7264735461626C6542794F626A65637400436F6E7461696E73576F72647342794F626A6563740053656C6563740053797374656D2E436F6C6C656374696F6E732E49456E756D657261746F722E5265736574006F705F496D706C696369740049734C65747465724F7244696769740053706C697400546F5570706572496E76617269616E740058456C656D656E74006765745F506172656E74007365745F506172656E740053797374656D2E436F6C6C656374696F6E732E47656E657269632E49456E756D657261746F723C47616E73732E546578742E576F72644D617463683E2E43757272656E740053797374656D2E436F6C6C656374696F6E732E49456E756D657261746F722E43757272656E740053797374656D2E436F6C6C656374696F6E732E47656E657269632E49456E756D657261746F723C47616E73732E546578742E576F72644D617463683E2E6765745F43757272656E740053797374656D2E436F6C6C656374696F6E732E49456E756D657261746F722E6765745F43757272656E74003C3E325F5F63757272656E7400436173740046696C6C526F774C697374006765745F4E657874007365745F4E657874004D6F76654E6578740053797374656D2E546578740047616E73732E54657874003C3E335F5F746578740046696C6C526F77006765745F496E646578007365745F496E64657800696E64657800436F6E7461696E734B65790053797374656D2E53656375726974792E43727970746F67726170687900416E79006F705F457175616C69747900000369000003630000036E0000036F000001000558003200000000002E94443AC555AD49A39E1204C637A3F600042001010803200001052001011111032000020615125101110C04200013000320001C0615122501110C08200015125101130004200012610515127101030D0705151225010E1D0E02121C0E0420001275060001124112750820001512250112410715123D0212410E052002011C1817100202151225011E01151225011E0015123D021E001E01050A0212410E0320000E0620011D0E1D03050002020E0E03200008040000126D050001126D0E0B100101151225011E001235040A01110C0A10010102151225011E00040701110C05000111210E05070212100E0500020E0E0E07151219020E121007200201130013010520010213000620011301130004070112280715123D02110C0216100102151225011E00151225011E0015123D021E00020B200015128089021300130105000012808D0500001280910520011D050E0620011D051D050615123D02050E040A02050E0800010E151225010E080702151251010E0E05151225010E05151251010E0D07040E081511590203122012200420010E0807151219020312200A2000151255021300130107151255020312200A200015115902130013010715115902031220042000130103070109042001020904000103030700021269126D02052002020E0E042001080E09200101151249011300050702031220042001030808200202130010130108200015124901130007070412200E080305200012809D0420010E0E0307010204000102030500001280A50B0707081210030E08110C08040701122C08B77A5C561934E089040000000001000806151219020E121002060802060E03061220020602030612690306121C08061512190203122003061224080615123D0212410E070615123D02050E0306110C030612100800021210121D11210A00031235121D1121112109000302121D11211121090003011C10081011210700020E121D11210500010211210300000208000212351121112107000202112111210400001235070002011C1011210400010E0E03000001042001010E0420001220052001011220082001011512490103052001011D0E08200101151225010E0A20020115124901031D0E0D2002011512490103151225010E09200115122501110C0E0420010102052002020303042001080306200201126D02040000121C070002121C126D02092000151219020312200A2001011512190203122005200112200E0520010E12410420010E0505200102110C042000110C08200015125101110C032800080328000E0428001220040800121C0928001512190203122003280002042800110C0328001C0801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F777301080100020000000000819401000600540E1146696C6C526F774D6574686F644E616D650746696C6C526F77540E0F5461626C65446566696E6974696F6E1F22496E6465782220696E742C20576F7264206E76617263686172284D41582954020F497344657465726D696E697374696301540209497350726563697365015455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730000000054557F4D6963726F736F66742E53716C5365727665722E5365727665722E53797374656D446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038391053797374656D446174614163636573730000000081460100040054020F497344657465726D696E697374696301540209497350726563697365015455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730000000054557F4D6963726F736F66742E53716C5365727665722E5365727665722E53797374656D446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038391053797374656D4461746141636365737300000000813301000300540209497350726563697365015455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730000000054557F4D6963726F736F66742E53716C5365727665722E5365727665722E53797374656D446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038391053797374656D4461746141636365737300000000818B01000600540E1146696C6C526F774D6574686F644E616D650B46696C6C526F774C697374540E0F5461626C65446566696E6974696F6E1248617368206E76617263686172284D41582954020F497344657465726D696E697374696301540209497350726563697365015455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730000000054557F4D6963726F736F66742E53716C5365727665722E5365727665722E53797374656D446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038391053797374656D446174614163636573730000000004010000000000000000F0CEA95D00000000020000001C010000884C0000882E000052534453F008FDC110632F41A346158C5BAC73A901000000463A5C50726F6A656374735C41686F436F72617369636B5C41686F436F72617369636B2E53716C436C725C6F626A5C52656C656173655C41686F436F72617369636B2E53716C436C722E706462000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000CC4D00000000000000000000E64D0000002000000000000000000000000000000000000000000000D84D0000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF25002000100000000000000000000000000000000000000100100000001800008000000000000000000000000000000100010000003000008000000000000000000000000000000100000000004800000058600000740200000000000000000000740234000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE00000100000000000000000000000000000000003F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B004D4010000010053007400720069006E006700460069006C00650049006E0066006F000000B001000001003000300030003000300034006200300000002C0002000100460069006C0065004400650073006300720069007000740069006F006E000000000020000000300008000100460069006C006500560065007200730069006F006E000000000030002E0030002E0030002E00300000004E001700010049006E007400650072006E0061006C004E0061006D0065000000410068006F0043006F00720061007300690063006B002E00530071006C0043006C0072002E0064006C006C00000000002800020001004C006500670061006C0043006F0070007900720069006700680074000000200000005600170001004F0072006900670069006E0061006C00460069006C0065006E0061006D0065000000410068006F0043006F00720061007300690063006B002E00530071006C0043006C0072002E0064006C006C0000000000340008000100500072006F006400750063007400560065007200730069006F006E00000030002E0030002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000030002E0030002E0030002E00300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000C000000F83D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; 8 | 9 | 10 | GO 11 | ALTER ASSEMBLY [AhoCorasick.SqlClr] 12 | DROP FILE ALL 13 | ADD FILE FROM 0x4D6963726F736F667420432F432B2B204D534620372E30300D0A1A4453000000000200000200000043000000580100000000000041000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3800000000000000FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0BCA3101380000000010000000100000000000001A00FFFF04000000FFFF03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BCA3101380000000010000000100000000000001B00FFFF04000000FFFF0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000942E3101F0CEA95D01000000F008FDC110632F41A346158C5BAC73A900000000000000000100000001000000000000000000000000000000DC51330100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BCA310138000000001000000010000000000000FFFFFFFF04000000FFFF030000000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BCA310138000000001000000010000000000000FFFFFFFF04000000FFFF030000000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F862513FC607D311905300C04FA302A1C4454B99E9E6D211903F00C04FA302A10B9D865A1166D311BD2A0000F80849BD0FD02988B8111342878B770E8597AC1620000000000000005831DA5DBC0BD7E636AD6E1CFF79421BA9941E32825FA5F80D54EC566D272D10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F862513FC607D311905300C04FA302A1C4454B99E9E6D211903F00C04FA302A10B9D865A1166D311BD2A0000F80849BD0FD02988B8111342878B770E8597AC162000000000000000C866E29C886E5B99E7829DEC965F77118969E3894E48C739AF2F28EC856B4F19000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F862513FC607D311905300C04FA302A1C4454B99E9E6D211903F00C04FA302A10B9D865A1166D311BD2A0000F80849BD0FD02988B8111342878B770E8597AC162000000000000000FF5852C579171CBF6783F30C8547AE939CD8C8E26E78E2E3DCAF7D2B53EA3A29000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F862513FC607D311905300C04FA302A1C4454B99E9E6D211903F00C04FA302A10B9D865A1166D311BD2A0000F80849BD0FD02988B8111342878B770E8597AC162000000000000000568D54EA04119982A63B8019D731A4FEFE35FB0DF9A8316D14A517E94910BF840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F707000000000000F7070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FEEFFEEF010000009601000000463A5C50726F6A656374735C41686F436F72617369636B5C41686F436F72617369636B2E53716C436C725C436F6E7461696E732E63730000663A5C70726F6A656374735C61686F636F72617369636B5C61686F636F72617369636B2E73716C636C725C636F6E7461696E732E637300463A5C50726F6A656374735C41686F436F72617369636B5C41686F436F72617369636B5C41686F436F72617369636B2E637300663A5C70726F6A656374735C61686F636F72617369636B5C61686F636F72617369636B5C61686F636F72617369636B2E637300463A5C50726F6A656374735C41686F436F72617369636B5C41686F436F72617369636B5C43686172436F6D70617265722E637300663A5C70726F6A656374735C61686F636F72617369636B5C61686F636F72617369636B5C63686172636F6D70617265722E637300463A5C50726F6A656374735C41686F436F72617369636B5C41686F436F72617369636B5C547269652E637300663A5C70726F6A656374735C61686F636F72617369636B5C61686F636F72617369636B5C747269652E63730011000000000000000A0100000100000039000000380000003E0100006A010000D600000000000000000000000000000000000000A300000070000000000000000000000000000000090000000000000000000000000000000000000000001BE2300104010000FD5F0D08C285D5010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000006000000010000001E00000000000000A3000000280000001BE230016964F98D680000007000000038000000A30000006500000000000000000000000A010000280000001BE23001F6CD6D9E68000000D6000000380000000A01000065000000000000000000000039000000280000001BE23001A30435EC680000000100000038000000390000006500000000000000000000006A010000280000001BE23001A388BC5A680000003E010000380000006A010000650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000003A002A11000000003802000000000000EB0000000000000000000000010000060000000001000000004275696C6441686F436F72617369636B000000160003110400000004020000EB00000000000000010000000A0024115553797374656D00120024115553797374656D2E44617461000000001A0024115553797374656D2E446174612E53716C436C69656E7400001A0024115553797374656D2E446174612E53716C54797065730000001E002411554D6963726F736F66742E53716C5365727665722E53657276657200160024115553797374656D2E586D6C2E4C696E7100000000120024115553797374656D2E4C696E71000000000E0024115547616E73732E5465787400160024115553797374656D2E436F6C6C656374696F6E73001E0024115553797374656D2E436F6C6C656374696F6E732E47656E6572696300220024115553797374656D2E53656375726974792E43727970746F677261706879000000120024115553797374656D2E54657874000000001A0024115553797374656D2E476C6F62616C697A6174696F6E0000001A00201100000000010000110000000000000000776F7264730000001600201101000000010000110000000000000000630000001E0020110200000001000011000000000000000069676E6F7265436173650000160020110300000001000011000000000000000063630000020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040000000C00000001000D00020006003A002A1100000000A80200000000000014000000000000000000000002000006EB0000000100000000436F6E7461696E73576F7264735461626C65002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000010000060200060036002A1100000000140300000000000013000000000000000000000003000006FF0000000100000000436F6E7461696E73576F72647300002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000010000060200060032002A1100000000B4030000000000002300000000000000000000000400000612010000010000000046696C6C526F77000000001600031118030000800300002300000012010000010000001A002011000000000200001100000000000000006D61746368000000020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000001000006020006003A002A110000000074040000000000002E00000000000000000000000500000635010000010000000043726561746541686F436F72617369636B000016000311B8030000400400002E00000035010000010000001600201100000000030000110000000000000000616300001A002011010000000300001100000000000000006861736800000000020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000001000006020006003A002A1100000000E4040000000000001400000000000000000000000600000663010000010000000044656C65746541686F436F72617369636B00002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000001000006020006003A002A110000000054050000000000000C000000000000000000000007000006770100000100000000436C65617241686F436F72617369636B0000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000010000060200060042002A1100000000CC050000000000001E000000000000000000000008000006830100000100000000436F6E7461696E73576F7264735461626C6542794F626A656374002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000001000006020006003E002A1100000000400600000000000012000000000000000000000009000006A10100000100000000436F6E7461696E73576F72647342794F626A65637400002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000001000006020006004A002A110000000000070000000000004600000000000000000000000A000006B30100000100000000436F6E7461696E73576F726473426F756E6465645461626C6542794F626A65637400001600031144060000CC06000046000000B30100000100000022002011000000000400001100000000000000004353243C3E385F5F6C6F63616C733000020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000010000060200060046002A11000000007C070000000000001200000000000000000000000B000006F90100000100000000436F6E7461696E73576F726473426F756E64656442794F626A6563740000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000001000006020006003A002A1100000000EC070000000000000B00000000000000000000000C0000060B02000001000000004C69737441686F436F72617369636B000000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000010000060200060036002A110000000058080000000000001200000000000000000000000D00000616020000010000000046696C6C526F774C697374000000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000001000006020006002E002A1100000000BC080000000000003F00000000000000000000000E000006280200000100000000486173680000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000001000006020006002E002A110000000020090000000000000B0000000000000000000000100000066702000001000000002E6363746F72002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C0000000100000602000600F2000000CC0000000000000001000100EB000000000000000F000000C000000000000000130000800B0000001400008035000000150000804D00000016000080640000001800008069000000EEEFFE80A60000001B000080B20000001C000080B40000001E000080C00000001F000080C200000022000080D200000023000080D400000025000080E300000028000080EA00000029000080090034000900470009002A000900360009001600000000001100520011001700110054001100170011005900110017001100580009002D0009001300F20000003C000000EB00000001000100140000000000000003000000300000000000000030000080070000003100008013000000330000800900310009002D0009001800F200000024000000FF0000000100010013000000000000000100000018000000000000003900008009004F00F20000004800000012010000010001002300000000000000040000003C000000000000003E000080070000003F000080100000004000008022000000410000800900240009001D0009001B0005000600F20000004800000035010000010001002E00000000000000040000003C0000000000000046000080080000004700008020000000480000802C00000049000080090031000900340009001C0009001500F200000030000000630100000100010014000000000000000200000024000000000000004F00008012000000500000800900230009001500F20000003000000077010000010001000C00000000000000020000002400000000000000560000800A000000570000800900190009001500F20000003C00000083010000010001001E000000000000000300000030000000000000005E000080110000005F0000801D000000610000800900250009002D0009001800F200000024000000A10100000100010012000000000000000100000018000000000000006700008009004E00F200000054000000B3010000010001004600000000000000050000004800000000000000EEEFFE80060000006E000080170000006F00008024000000700000854500000077000080000000000900250009001C0009000C0009001800F200000024000000F90100000100010012000000000000000100000018000000000000007D00008009005500F2000000240000000B020000010001000B000000000000000100000018000000000000008400008009001D00F2000000300000001602000001000100120000000000000002000000240000000000000089000080110000008A00008009001C0005000600F20000002400000028020000010001003F000000000000000100000018000000000000008E00008009007100F20000002400000067020000010001000B000000000000000100000018000000000000009100008005006D00F4000000080000000100000000000000780000000000000020000000380000005C0000007400000090000000A8000000C0000000D8000000F80000001001000030010000480100006801000080010000AC010000C4010000E8010000000200003002000048020000740200008C020000AC020000C4020000E0020000F80200000C030000240300003C0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000032002A11000000003800000000000000070000000000000000000000150000069002000001000000006765745F547269650000000200060032002A11000000007000000000000000080000000000000000000000160000069702000001000000007365745F54726965000000020006002E002A11000000001401000000000000120000000000000000000000170000069F02000001000000002E63746F7200001600031174000000DC000000120000009F020000010000001E0024115553797374656D2E436F6C6C656374696F6E732E47656E65726963000200060032000404C93FEAC6B359D649BC250902BBABB460000000004D004400320000000401000004000000100000000300000000000100020006002E002A1100000000780100000000000013000000000000000000000018000006B102000001000000002E63746F7200002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000017000006020006002E002A1100000000DC010000000000000E000000000000000000000019000006C402000001000000002E63746F7200002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000017000006020006002E002A110000000040020000000000000E00000000000000000000001A000006D202000001000000002E63746F7200002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000017000006020006002E002A1100000000A4020000000000000F00000000000000000000001B000006E002000001000000002E63746F7200002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000017000006020006002E002A110000000008030000000000000F00000000000000000000001C000006EF02000001000000002E63746F7200002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000017000006020006002E002A11000000006C030000000000000E00000000000000000000001D000006FE0200000100000000416464000000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000017000006020006002E002A110000000024040000000000003900000000000000000000001E0000060C0300000100000000416464000000001600031170030000F0030000390000000C0300000100000016000311A0030000EC0300001400000015030000010000001A00201101000000050000110000000000000000776F72640000000002000600020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000170000060200060032002A110000000030050000000000008100000000000000000000001F0000064503000001000000004275696C644661696C00001600031128040000FC0400008100000045030000010000001A00201100000000060000110000000000000000776F726400000000160003115C040000C004000031000000590300000100000016002011010000000600001100000000000000006900000002000600160003115C040000F80400000F0000009D030000010000001A002011030000000600001100000000000000007375624E6F64650002000600020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000017000006020006002E002A1100000000AC0500000000000016000000000000000000000020000006C603000001000000005365617263680046000404C93FEAC6B359D649BC250902BBABB460000000004D004400320000000401000004040000240000003C005300650061007200630068003E0064005F005F0031003300000002000600F20000002400000090020000010001000700000000000000010000001800000000000000260000801F002300F200000024000000970200000100010008000000000000000100000018000000000000002600008024002800F20000003C0000009F0200000100010012000000000000000300000030000000000000002C000080060000002E000080110000002F00008009001D000D001F0009000A00F20000003C000000B1020000010001001300000000000000030000003000000000000000360000800600000038000080120000003900008009003D000D00270009000A00F20000003C000000C4020000010001000E000000000000000300000030000000000000004000008006000000420000800D000000430000800F0015000D00180009000A00F20000003C000000D2020000010001000E000000000000000300000030000000000000004A000080060000004C0000800D0000004D0000800F0015000D00180009000A00F20000003C000000E0020000010001000F000000000000000300000030000000000000005500008007000000570000800E000000580000800F001D000D00180009000A00F20000003C000000EF020000010001000F000000000000000300000030000000000000006000008007000000620000800E000000630000800F001D000D00180009000A00F200000030000000FE020000010001000E000000000000000200000024000000000000006C0000800D0000006D0000800D001C0009000A00F2000000840000000C0300000100010039000000000000000900000078000000000000007500008007000000EEEFFE80090000007500008010000000770000801D0000007500008027000000EEEFFE8030000000EEEFFE80310000007A000080380000007B000080220027000000000016001E00110020001F00210000000000000000000D00190009000A00F2000000C0000000450300000100010081000000000000000E000000B400000000000000830000800D00000085000080140000008600008016000000EEEFFE80180000008700008030000000860000803400000086000080450000008900008056000000EEEFFE805800000089000080600000008A000080670000008900008072000000EEEFFE80800000008B0000800D0021000D00220012001B000000000011004500430046001D00410025003500000000001600210011002400220024000000000009000A00F400000008000000700000000000000060000000540300006C030000840300009C030000B4030000C8030000E0030000F40300000C04000020040000380400004C040000640400007804000090040000A4040000BC040000D0040000E8040000FC040000140500002C050000440500005C050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000003E002A11000000007400000000000000060000000000000000000000270000066404000001000000006765745F4F7264696E616C49676E6F72654361736500002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000210000060200060036002A1100000000E000000000000000060000000000000000000000280000066A04000001000000006765745F4F7264696E616C000000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000210000060200060046002A11000000005C01000000000000060000000000000000000000290000067004000001000000006765745F496E76617269616E7443756C7475726549676E6F726543617365002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000021000006020006003E002A1100000000D0010000000000000600000000000000000000002A0000067604000001000000006765745F496E76617269616E7443756C747572650000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000021000006020006003A002A110000000040020000000000000C00000000000000000000002B0000067C04000001000000006765745F43757272656E7443756C74757265002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000210000060200060046002A1100000000BC020000000000000C00000000000000000000002C0000068804000001000000006765745F43757272656E7443756C7475726549676E6F7265436173650000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000021000006020006002E002A110000000020030000000000000800000000000000000000002D000006940400000100000000437265617465002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000021000006020006002E002A110000000084030000000000003700000000000000000000002F0000069C04000001000000002E6363746F72002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C0000002100000602000600F200000024000000640400000100010006000000000000000100000018000000000000005B00008011002B00F2000000240000006A0400000100010006000000000000000100000018000000000000006B00008011002100F200000024000000700400000100010006000000000000000100000018000000000000007B00008011003400F200000024000000760400000100010006000000000000000100000018000000000000008B00008011002A00F2000000240000007C040000010001000C000000000000000100000018000000000000009900008011005F00F20000002400000088040000010001000C00000000000000010000001800000000000000A700008011005E00F20000002400000094040000010001000800000000000000010000001800000000000000B30000800D004500F2000000480000009C040000010001003700000000000000040000003C000000000000004F0000800B0000005F000080160000006F000080260000007F00008009006D00090064000900940009008B00F400000008000000D600000000000000400000007405000098050000B0050000CC050000E4050000140600002C06000050060000680600008C060000A4060000D0060000E8060000000700001807000030070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000032002A11000000005C01000000000000660100000000000000000000460000069106000001000000004D6F76654E6578740000001600031104000000F80000006601000091060000010000001E0024115553797374656D2E436F6C6C656374696F6E732E47656E65726963001600031138000000F4000000F9000000D40600000100000016002011020000000B0000110000000000000000630000001600031170000000F00000004E0000005F070000010000001A002011030000000B0000110000000000000000776F7264000000001A002011040000000B00001100000000000000006F666673657400000200060002000600020006005E000404C93FEAC6B359D649BC250902BBABB460000000004D004400320000000402000004000000100000000300000000000100040300002C00000004000000000000000000000021000000650100003700000063010000B30000003B01000002000600F200000050010000910600000100010066010000000000001A0000004401000000000000EEEFFE80210000009400008029000000940000802B0000009600008037000000980000803E000000EEEFFE80430000009A00008055000000EEEFFE80570000009D000080680000009C000080830000009F0000808B0000009F00008097000000A1000080B3000000A3000080BF000000EEEFFE80C1000000A7000080CE000000A9000080DA000000AA000080EB000000AB00008015010000EEEFFE801C010000AE0000802D010000A500008035010000B00000803C010000980000804E0100009800008064010000B2000080000000000D001E001F002B000D00200012001B0000000000110021000000000015002C0011004800110025002600350011003E001500280000000000190029001D0032001D003E001D0058000000000019002A0015002900110012002E0031001D002C0009000A00F40000000800000070000000000000000800000048070000600700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000042002A1100000000D4010000000000000C0000000000000000000000400000060106000001000000003C4275696C6441686F436F72617369636B3E625F5F305F300000001600031104000000A00100000C00000001060000010000000A0024115553797374656D00120024115553797374656D2E44617461000000001A0024115553797374656D2E446174612E53716C436C69656E7400001A0024115553797374656D2E446174612E53716C54797065730000001E002411554D6963726F736F66742E53716C5365727665722E53657276657200160024115553797374656D2E586D6C2E4C696E7100000000120024115553797374656D2E4C696E71000000000E0024115547616E73732E5465787400160024115553797374656D2E436F6C6C656374696F6E73001E0024115553797374656D2E436F6C6C656374696F6E732E47656E6572696300220024115553797374656D2E53656375726974792E43727970746F677261706879000000120024115553797374656D2E54657874000000001A0024115553797374656D2E476C6F62616C697A6174696F6E000000020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040000000C00000001000D000200060036002A110000000040020000000000000D0000000000000000000000410000060D06000001000000003C486173683E625F5F31335F3000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C0000004000000602000600F20000002400000001060000010001000C00000000000000010000001800000000000000140000802F004500F2000000240000000D060000010001000D000000000000000100000018000000000000008E0000805E006E00F40000000800000001000000000000001000000078070000A0070000B8070000D407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000052002A1100000000BC00000000000000770000000000000000000000430000061A06000001000000003C436F6E7461696E73576F726473426F756E6465645461626C6542794F626A6563743E625F5F3000000000160003110400000088000000770000001A0600000100000016002011000000000A0000110000000000000000656E6400020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C0000004000000602000600F20000003C0000001A06000001000100770000000000000003000000300000000000000072000080280000007300008074000000740000800D004F000D0072000D002100F400000008000000010000000000000008000000EC070000240800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000002E002A1100000000F4000000000000000E000000000000000000000021000006DC03000001000000002E63746F7200001600031104000000BC0000000E000000DC030000010000000A0024115553797374656D001E0024115553797374656D2E436F6C6C656374696F6E732E47656E65726963001A0024115553797374656D2E476C6F62616C697A6174696F6E000000120024115553797374656D2E4C696E7100000000120024115553797374656D2E54657874000000000200060032000404C93FEAC6B359D649BC250902BBABB460000000004D004400320000000401000004000000100000000300000000000500020006002E002A1100000000580100000000000028000000000000000000000022000006EA0300000100000000457175616C73002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000210000060200060036002A1100000000C4010000000000001100000000000000000000002300000612040000010000000047657448617368436F6465000000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C0000002100000602000600F20000003C000000DC030000010001000E000000000000000300000030000000000000000D000080060000000F0000800D0000001000008009003C000D00260009000A00F200000024000000EA030000010001002800000000000000010000001800000000000000140000810D002D00F200000024000000120400000100010011000000000000000100000018000000000000001A0000800D004D00F400000008000000D600000000000000180000003C08000050080000680800008008000098080000B408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000032002A11000000003800000000000000070000000000000000000000110000067202000001000000006765745F496E64657800000200060032002A11000000007000000000000000080000000000000000000000120000067902000001000000007365745F496E64657800000200060032002A1100000000A800000000000000070000000000000000000000130000068102000001000000006765745F576F72640000000200060032002A1100000000E000000000000000080000000000000000000000140000068802000001000000007365745F576F726400000002000600F20000002400000072020000010001000700000000000000010000001800000000000000100000801C002000F200000024000000790200000100010008000000000000000100000018000000000000001000008021002500F20000002400000081020000010001000700000000000000010000001800000000000000180000801E002200F200000024000000880200000100010008000000000000000100000018000000000000001800008023002700F400000008000000700000000000000020000000CC080000E4080000FC080000140900002C090000440900005C0900007409000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000032002A1100000000380000000000000007000000000000000000000030000006D304000001000000006765745F4E6578740000000200060032002A1100000000700000000000000008000000000000000000000031000006DA04000001000000007365745F4E6578740000000200060032002A1100000000A80000000000000007000000000000000000000032000006E204000001000000006765745F4973576F7264000200060032002A1100000000E00000000000000008000000000000000000000033000006E904000001000000007365745F4973576F7264000200060032002A1100000000180100000000000007000000000000000000000034000006F104000001000000006765745F4661696C0000000200060032002A1100000000500100000000000008000000000000000000000035000006F804000001000000007365745F4661696C0000000200060032002A11000000008801000000000000070000000000000000000000360000060005000001000000006765745F506172656E74000200060032002A1100000000C001000000000000080000000000000000000000370000060705000001000000007365745F506172656E74000200060032002A1100000000F801000000000000070000000000000000000000380000060F05000001000000006765745F576F72640000000200060032002A11000000003002000000000000080000000000000000000000390000061605000001000000007365745F576F7264000000020006002E002A1100000000D4020000000000001D00000000000000000000003A0000061E05000001000000002E63746F72000016000311340200009C0200001D0000001E050000010000001E0024115553797374656D2E436F6C6C656374696F6E732E47656E65726963000200060032000404C93FEAC6B359D649BC250902BBABB460000000004D004400320000000401000004000000100000000300000000000100020006002E002A110000000038030000000000001E00000000000000000000003B0000063B05000001000000002E63746F7200002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C0000003A000006020006002E002A1100000000EC030000000000007500000000000000000000003C00000659050000010000000041646400000000160003113C030000B80300007500000059050000010000001600201100000000080000110000000000000000630000001A002011010000000800001100000000000000006E6F646500000000020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C0000003A000006020006003A002A1100000000C8040000000000003300000000000000000000003D000006CE05000001000000004578706C6F72654661696C4C696E6B0000000016000311F00300009404000033000000CE050000010000001A002011000000000900001100000000000000006E6F646500000000160003112C040000900400001C000000D60500000100000016002011030000000900001100000000000000006300000002000600020006002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C0000003A00000602000600F200000024000000D3040000010001000700000000000000010000001800000000000000100000802E003200F200000024000000DA0400000100010008000000000000000100000018000000000000001000008033003700F200000024000000E2040000010001000700000000000000010000001800000000000000180000801E002200F200000024000000E90400000100010008000000000000000100000018000000000000001800008023002700F200000024000000F1040000010001000700000000000000010000001800000000000000200000801C002000F200000024000000F80400000100010008000000000000000100000018000000000000002000008021002500F20000002400000000050000010001000700000000000000010000001800000000000000280000801E002200F200000024000000070500000100010008000000000000000100000018000000000000002800008023002700F2000000240000000F050000010001000700000000000000010000001800000000000000300000801E002200F200000024000000160500000100010008000000000000000100000018000000000000003000008023002F00F2000000480000001E050000010001001D00000000000000040000003C0000000000000035000080060000003700008011000000380000801C00000039000080090016000D0017000D00310009000A00F2000000480000003B050000010001001E00000000000000040000003C000000000000003F000080060000004100008011000000420000801D00000043000080090036000D0017000D00390009000A00F20000006C000000590500000100010075000000000000000700000060000000000000004C000080080000004E000080180000004F00008055000000510000805E000000520000806C0000005400008073000000560000800D001D000D00350011005D000D00210011003400110024000D001900F200000090000000CE0500000100010033000000000000000A000000840000000000000060000080020000006200008006000000EEEFFE80080000006200008010000000640000801F00000065000080220000006500008024000000EEEFFE80280000006200008031000000680000800D001D001F0023000000000016001B00110034001100220023002F00000000001C001E000D001900F4000000080000003E01000000000000700000008C090000A4090000BC090000D4090000EC090000080A0000200A00003C0A0000540A00006C0A0000840A00009C0A0000B40A0000D00A0000E80A0000040B00001C0B0000340B00004C0B0000640B00007C0B0000900B0000A80B0000BC0B0000D40B0000E80B0000000C0000200C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000002E002A11000000006400000000000000140000000000000000000000240000062304000001000000002E63746F7200002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C00000021000006020006002E002A1100000000C8000000000000001A000000000000000000000025000006370400000100000000457175616C73002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C000000210000060200060036002A110000000034010000000000001300000000000000000000002600000651040000010000000047657448617368436F6465000000002E000404C93FEAC6B359D649BC250902BBABB460000000004D0044003200000004010000040100000C0000002100000602000600F20000003C000000230400000100010014000000000000000300000030000000000000002300008006000000250000801300000026000080090055000D004E0009000A00F20000002400000037040000010001001A000000000000000100000018000000000000002A0000800D004700F200000024000000510400000100010013000000000000000100000018000000000000002F0000800D004000F400000008000000D60000000000000018000000380C00004C0C0000640C00007C0C0000940C0000B00C0000FFFFFFFF1A092FF1F0030000B80300005D000000010000007502000001000000D50B000001000000E904000001000000BD040000010000001509000001000000790400000100000081080000010000008D06000001000000090A000001000000BD0B0000010000000102000001000000850A000001000000550A0000010000009100000001000000AD020000010000004509000001000000A504000001000000B508000001000000D1060000010000003D0A000001000000E90B00000100000025080000010000002D06000001000000B9070000010000003D030000010000005D05000001000000A509000001000000C502000001000000A107000001000000390C000001000000A90B0000010000007D0B0000010000003D080000010000009104000001000000650400000100000039040000010000000D04000001000000E103000001000000B503000001000000790700000100000021000000010000003102000001000000E5080000010000004D04000001000000150500000100000051080000010000005106000001000000ED07000001000000D509000001000000910B0000010000004505000001000000D507000001000000C501000001000000310100000100000075000000010000009D030000010000002D050000010000008101000001000000010C000001000000B10C0000010000003107000001000000D10A00000100000061070000010000006901000001000000C9030000010000009905000001000000050B0000010000004D0B0000010000005D090000010000001D0B0000010000002D09000001000000C100000001000000E102000001000000B1050000010000007509000001000000210A000001000000D104000001000000ED090000010000004D0C00000100000001070000010000006D0A000001000000210C000001000000F9000000010000000D030000010000006D03000001000000FD040000010000007D0C000001000000CD08000001000000FD080000010000009D0A000001000000F902000001000000A90000000100000069060000010000004901000001000000A506000001000000110100000100000019070000010000002503000001000000E5050000010000004902000001000000AD01000001000000F503000001000000CD05000001000000350B00000100000055030000010000008503000001000000E906000001000000E901000001000000D900000001000000750500000100000021040000010000001506000001000000650B0000010000008D020000010000000100000001000000650C0000010000006908000001000000E90A0000010000008D09000001000000BD09000001000000B50A000001000000950C000001000000990800000100000049070000010000003900000001000000012400000208000004010000080200000008000000040040000000000000000001040000020800000401000008020000100000020000000000000000000000000002000002000000040000000800000110020000002000000000000000000000010400000208000005010800080200041000008000000000000000000000000001002000020880020401000008000000100000000000000000000000000000000100000002000000040000000800000000000000000000000100100000000000010404000A08800004010000080200000000000000000000000000000000000001040000020800001400010008000004400000000000000000000000000000000000000000000000000000000000000000020010000000002000000000000000000000000000008000000000000420000000400000000000000000000000000002000000010000000800000004000000000000000080000800000000000000010200080001000000080000000400000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000014004108000000000040000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000C000000180000003C0000004800000054000000600000006C0000007800000084000000900000009C000000A8000000B4000000C0000000CC000000D8000000E4000000F0000000FC0000000801000014010000200100002C0100003801000044010000500100005C01000068010000E0010000EC010000F801000004020000100200001C0200002802000034020000400200004C0200005802000064020000700200007C0200008802000094020000A0020000AC020000B8020000C4020000D0020000DC020000E8020000F4020000000300000C03000018030000240300003003000048030000600300006C0300007803000084030000900300009C030000A8030000B4030000C0030000CC030000D8030000E4030000F0030000FC0300000804000014040000200400002C0400003804000044040000500400005C0400006804000074040000800400008C040000A4040000B0040000BC040000C8040000D4040000E0040000EC040000F804000004050000100500001C05000034050000400500004C0500005805000064050000700500008805000094050000A0050000AC050000B8050000D0050000DC0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E002511000000000400000001004275696C6441686F436F72617369636B000016002911000000000400000001003036303030303031000022002511000000003C0200000100436F6E7461696E73576F7264735461626C650000000016002911000000003C0200000100303630303030303200001A00251100000000AC0200000100436F6E7461696E73576F726473001600291100000000AC020000010030363030303030330000160025110000000018030000010046696C6C526F770000001600291100000000180300000100303630303030303400001E00251100000000B8030000010043726561746541686F436F72617369636B001600291100000000B80300000100303630303030303500001E0025110000000078040000010044656C65746541686F436F72617369636B001600291100000000780400000100303630303030303600001E00251100000000E80400000100436C65617241686F436F72617369636B00001600291100000000E80400000100303630303030303700002A00251100000000580500000100436F6E7461696E73576F7264735461626C6542794F626A656374000000001600291100000000580500000100303630303030303800002200251100000000D00500000100436F6E7461696E73576F72647342794F626A656374001600291100000000D005000001003036303030303039000010000000000000000000000000000000000000000000000000000000FFFFFFFF1A092FF100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E00251100000000440600000100436F6E7461696E73576F726473426F756E6465645461626C6542794F626A656374001600291100000000440600000100303630303030306100002A00251100000000040700000100436F6E7461696E73576F726473426F756E64656442794F626A65637400001600291100000000040700000100303630303030306200001E002511000000008007000001004C69737441686F436F72617369636B0000001600291100000000800700000100303630303030306300001A00251100000000F0070000010046696C6C526F774C6973740000001600291100000000F007000001003036303030303064000012002511000000005C080000010048617368000016002911000000005C0800000100303630303030306500001600251100000000C008000001002E6363746F72000000001600291100000000C008000001003036303030303130000016002511000000000400000003006765745F54726965000016002911000000000400000003003036303030303135000016002511000000003C00000003007365745F54726965000016002911000000003C00000003003036303030303136000012002511000000007400000003002E63746F720016002911000000007400000003003036303030303137000012002511000000001801000003002E63746F720016002911000000001801000003003036303030303138000012002511000000007C01000003002E63746F720016002911000000007C0100000300303630303030313900001200251100000000E001000003002E63746F72001600291100000000E001000003003036303030303161000012002511000000004402000003002E63746F72001600291100000000440200000300303630303030316200001200251100000000A802000003002E63746F72001600291100000000A802000003003036303030303163000012002511000000000C030000030041646400000016002911000000000C030000030030363030303031640000120025110000000070030000030041646400000016002911000000007003000003003036303030303165000016002511000000002804000003004275696C644661696C0016002911000000002804000003003036303030303166000016002511000000003405000003005365617263680000000016002911000000003405000003003036303030303230000022002511000000000400000006006765745F4F7264696E616C49676E6F726543617365001600291100000000040000000600303630303030323700001A002511000000007800000006006765745F4F7264696E616C0000001600291100000000780000000600303630303030323800002E00251100000000E400000006006765745F496E76617269616E7443756C7475726549676E6F726543617365000000001600291100000000E400000006003036303030303239000022002511000000006001000006006765745F496E76617269616E7443756C7475726500001600291100000000600100000600303630303030326100002200251100000000D401000006006765745F43757272656E7443756C74757265000000001600291100000000D40100000600303630303030326200002A002511000000004402000006006765745F43757272656E7443756C7475726549676E6F72654361736500001600291100000000440200000600303630303030326300001600251100000000C00200000600437265617465000000001600291100000000C002000006003036303030303264000016002511000000002403000006002E6363746F72000000001600291100000000240300000600303630303030326600001600251100000000040000000A004D6F76654E65787400001600291100000000040000000A003036303030303436000026002511000000000400000008003C4275696C6441686F436F72617369636B3E625F5F305F3000001600291100000000040000000800303630303030343000001A00251100000000D801000008003C486173683E625F5F31335F30001600291100000000D801000008003036303030303431000036002511000000000400000009003C436F6E7461696E73576F726473426F756E6465645461626C6542794F626A6563743E625F5F3000000016002911000000000400000009003036303030303433000012002511000000000400000004002E63746F72001600291100000000040000000400303630303030323100001600251100000000F80000000400457175616C73000000001600291100000000F80000000400303630303030323200001A002511000000005C010000040047657448617368436F646500000016002911000000005C01000004003036303030303233000016002511000000000400000002006765745F496E6465780016002911000000000400000002003036303030303131000016002511000000003C00000002007365745F496E6465780016002911000000003C00000002003036303030303132000016002511000000007400000002006765745F576F726400001600291100000000740000000200303630303030313300001600251100000000AC00000002007365745F576F726400001600291100000000AC00000002003036303030303134000016002511000000000400000007006765745F4E657874000016002911000000000400000007003036303030303330000016002511000000003C00000007007365745F4E657874000016002911000000003C0000000700303630303030333100001A002511000000007400000007006765745F4973576F7264000000001600291100000000740000000700303630303030333200001A00251100000000AC00000007007365745F4973576F7264000000001600291100000000AC0000000700303630303030333300001600251100000000E400000007006765745F4661696C00001600291100000000E400000007003036303030303334000016002511000000001C01000007007365745F4661696C000016002911000000001C0100000700303630303030333500001A002511000000005401000007006765745F506172656E74000000001600291100000000540100000700303630303030333600001A002511000000008C01000007007365745F506172656E740000000016002911000000008C0100000700303630303030333700001600251100000000C401000007006765745F576F726400001600291100000000C40100000700303630303030333800001600251100000000FC01000007007365745F576F726400001600291100000000FC01000007003036303030303339000012002511000000003402000007002E63746F72001600291100000000340200000700303630303030336100001200251100000000D802000007002E63746F72001600291100000000D802000007003036303030303362000012002511000000003C030000070041646400000016002911000000003C0300000700303630303030336300001E00251100000000F003000007004578706C6F72654661696C4C696E6B0000001600291100000000F003000007003036303030303364000012002511000000000400000005002E63746F72001600291100000000040000000500303630303030323400001600251100000000680000000500457175616C73000000001600291100000000680000000500303630303030323500001A00251100000000CC000000050047657448617368436F64650000001600291100000000CC000000050030363030303032360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF770931010100000017000C8E1800E66419000200F8030000E80600002C00000020010000000000000000000016000000190000000000EEC00000000000000000FFFF000000000000FFFFFFFF00000000FFFF0000000000000000000000000D002409000000000000180400000100000000000000000000000000000055736572446566696E656446756E6374696F6E7300373141414145453800000000000000FFFF000000000000FFFFFFFF00000000FFFF0000000000000000000000001400E400000000000000C00000000100000000000000000000000000000047616E73732E546578742E576F72644D6174636800363236423346313800000000000000FFFF000000000000FFFFFFFF00000000FFFF0000000000000000000000000E00B0050000000000008C0300000100000000000000000000000000000047616E73732E546578742E41686F436F72617369636B0031434435303842360000000000FFFF000000000000FFFFFFFF00000000FFFF0000000000000000000000001300C801000000000000AC0000000100000000000000000000000000000047616E73732E546578742E4F7264696E616C43686172436F6D70617265720045313736333843390000000000FFFF000000000000FFFFFFFF00000000FFFF00000000000000000000000016003801000000000000AC0000000100000000000000000000000000000047616E73732E546578742E43756C7475726543686172436F6D70617265720037374537384337360000000000FFFF000000000000FFFFFFFF00000000FFFF0000000000000000000000000F008803000000000000940100000100000000000000000000000000000047616E73732E546578742E43686172436F6D70617265720038394531464342340000000000000000FFFF000000000000FFFFFFFF00000000FFFF0000000000000000000000001500CC04000000000000740300000100000000000000000000000000000047616E73732E546578742E547269650034323139303734390000000000000000FFFF000000000000FFFFFFFF00000000FFFF00000000000000000000000011004402000000000000680000000100000000000000000000000000000055736572446566696E656446756E6374696F6E732E3C3E6300464146343644353400000000000000FFFF000000000000FFFFFFFF00000000FFFF0000000000000000000000001200C000000000000000540000000100000000000000000000000000000055736572446566696E656446756E6374696F6E732E3C3E635F5F446973706C6179436C617373395F30003536313438444339000000000000FFFF000000000000FFFFFFFF00000000FFFF00000000000000000000000010006001000000000000680100000100000000000000000000000000000047616E73732E546578742E41686F436F72617369636B2E3C5365617263683E645F5F31330045334336314439430000002DBA2EF10100000000000000EB0000000000000000000000000000000000000001000000EB000000140000000000000000000000000000000000000001000000FF00000013000000000000000000000000000000000000000100000012010000230000000000000000000000000000000000000001000000350100002E000000000000000000000000000000000000000100000063010000140000000000000000000000000000000000000001000000770100000C0000000000000000000000000000000000000001000000830100001E0000000000000000000000000000000000000001000000A1010000120000000000000000000000000000000000000001000000B3010000460000000000000000000000000000000000000001000000F90100001200000000000000000000000000000000000000010000000B0200000B000000000000000000000000000000000000000100000016020000120000000000000000000000000000000000000001000000280200003F0000000000000000000000000000000000000001000000670200000B00000000000000000000000000000000000000010000007202000007000000000000000100000000000000000000000100000079020000080000000000000001000000000000000000000001000000810200000700000000000000010000000000000000000000010000008802000008000000000000000100000000000000000000000100000090020000070000000000000002000000000000000000000001000000970200000800000000000000020000000000000000000000010000009F020000120000000000000002000000000000000000000001000000B1020000130000000000000002000000000000000000000001000000C40200000E0000000000000002000000000000000000000001000000D20200000E0000000000000002000000000000000000000001000000E00200000F0000000000000002000000000000000000000001000000EF0200000F0000000000000002000000000000000000000001000000FE0200000E00000000000000020000000000000000000000010000000C03000039000000000000000200000000000000000000000100000045030000810000000000000002000000000000000000000001000000C6030000160000000000000002000000000000000000000001000000DC0300000E0000000000000003000000000000000000000001000000EA0300002800000000000000030000000000000000000000010000001204000011000000000000000300000000000000000000000100000023040000140000000000000004000000000000000000000001000000370400001A000000000000000400000000000000000000000100000051040000130000000000000004000000000000000000000001000000640400000600000000000000050000000000000000000000010000006A04000006000000000000000500000000000000000000000100000070040000060000000000000005000000000000000000000001000000760400000600000000000000050000000000000000000000010000007C0400000C0000000000000005000000000000000000000001000000880400000C0000000000000005000000000000000000000001000000940400000800000000000000050000000000000000000000010000009C040000370000000000000005000000000000000000000001000000D3040000070000000000000006000000000000000000000001000000DA040000080000000000000006000000000000000000000001000000E2040000070000000000000006000000000000000000000001000000E9040000080000000000000006000000000000000000000001000000F1040000070000000000000006000000000000000000000001000000F804000008000000000000000600000000000000000000000100000000050000070000000000000006000000000000000000000001000000070500000800000000000000060000000000000000000000010000000F050000070000000000000006000000000000000000000001000000160500000800000000000000060000000000000000000000010000001E0500001D00000000000000060000000000000000000000010000003B0500001E000000000000000600000000000000000000000100000059050000750000000000000006000000000000000000000001000000CE050000330000000000000006000000000000000000000001000000010600000C00000000000000070000000000000000000000010000000D0600000D00000000000000070000000000000000000000010000001A060000770000000000000008000000000000000000000001000000910600006601000000000000090000000000000000000000020002000D01000000000100FFFFFFFF00000000F70700000802000000000000FFFFFFFF00000000FFFFFFFF0A000A00000001000200030004000500060007000800090001000100010001000100010001000100010001000000000037000000370000006A0000006A0000006A0000009E000000000000000000000037000000463A5C50726F6A656374735C41686F436F72617369636B5C41686F436F72617369636B2E53716C436C725C436F6E7461696E732E637300463A5C50726F6A656374735C41686F436F72617369636B5C41686F436F72617369636B5C41686F436F72617369636B2E637300463A5C50726F6A656374735C41686F436F72617369636B5C41686F436F72617369636B5C43686172436F6D70617265722E637300463A5C50726F6A656374735C41686F436F72617369636B5C41686F436F72617369636B5C547269652E6373000000FEEFFEEF010000000100000000010000000000000000000000FFFFFFFFFFFFFFFFFFFF0C00FFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000942E3101F0CEA95D01000000F008FDC110632F41A346158C5BAC73A9180100002F4C696E6B496E666F002F6E616D6573002F7372632F686561646572626C6F636B002F7372632F66696C65732F663A5C70726F6A656374735C61686F636F72617369636B5C61686F636F72617369636B2E73716C636C725C636F6E7461696E732E6373002F7372632F66696C65732F663A5C70726F6A656374735C61686F636F72617369636B5C61686F636F72617369636B5C61686F636F72617369636B2E6373002F7372632F66696C65732F663A5C70726F6A656374735C61686F636F72617369636B5C61686F636F72617369636B5C63686172636F6D70617265722E6373002F7372632F66696C65732F663A5C70726F6A656374735C61686F636F72617369636B5C61686F636F72617369636B5C747269652E637300070000000E00000001000000B036000000000000A20000000A0000000A00000006000000000000000500000011000000070000006400000009000000E10000000B000000220000000800000000000000DC51330100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001A000000200000008C010000380000009B0C00003800000000000000EE010000040100006800000068000000680000006800000028000000B80D0000A009000060050000D4020000C00200002001000090020000C8010000B408000000020000B80700002C000000C80C0000030000003F0000000600000038000000390000003A0000003B0000003C0000003D0000003E000000070000000D0000000E00000008000000090000000A0000000B0000000C0000000F000000100000001100000012000000130000001400000015000000160000001700000018000000190000001A0000001B0000001C0000001D0000001E0000001F000000200000002100000022000000230000002400000025000000260000002700000028000000290000002A0000002B0000002C0000002D0000002E0000002F000000310000003000000032000000330000003400000035000000360000003700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 AS N'AhoCorasick.SqlClr.pdb'; 14 | 15 | 16 | GO 17 | PRINT N'Creating [dbo].[ContainsWords]...'; 18 | 19 | 20 | GO 21 | CREATE FUNCTION [dbo].[ContainsWords] 22 | (@xml XML, @text NVARCHAR (MAX), @culture NVARCHAR (MAX)) 23 | RETURNS BIT 24 | AS 25 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[ContainsWords] 26 | 27 | 28 | GO 29 | PRINT N'Creating [dbo].[CreateAhoCorasick]...'; 30 | 31 | 32 | GO 33 | CREATE FUNCTION [dbo].[CreateAhoCorasick] 34 | (@xml XML, @culture NVARCHAR (MAX)) 35 | RETURNS NVARCHAR (MAX) 36 | AS 37 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[CreateAhoCorasick] 38 | 39 | 40 | GO 41 | PRINT N'Creating [dbo].[DeleteAhoCorasick]...'; 42 | 43 | 44 | GO 45 | CREATE FUNCTION [dbo].[DeleteAhoCorasick] 46 | (@obj NVARCHAR (MAX)) 47 | RETURNS BIT 48 | AS 49 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[DeleteAhoCorasick] 50 | 51 | 52 | GO 53 | PRINT N'Creating [dbo].[ClearAhoCorasick]...'; 54 | 55 | 56 | GO 57 | CREATE FUNCTION [dbo].[ClearAhoCorasick] 58 | ( ) 59 | RETURNS BIT 60 | AS 61 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[ClearAhoCorasick] 62 | 63 | 64 | GO 65 | PRINT N'Creating [dbo].[ContainsWordsByObject]...'; 66 | 67 | 68 | GO 69 | CREATE FUNCTION [dbo].[ContainsWordsByObject] 70 | (@text NVARCHAR (MAX), @obj NVARCHAR (MAX)) 71 | RETURNS BIT 72 | AS 73 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[ContainsWordsByObject] 74 | 75 | 76 | GO 77 | PRINT N'Creating [dbo].[ContainsWordsBoundedByObject]...'; 78 | 79 | 80 | GO 81 | CREATE FUNCTION [dbo].[ContainsWordsBoundedByObject] 82 | (@text NVARCHAR (MAX), @obj NVARCHAR (MAX)) 83 | RETURNS BIT 84 | AS 85 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[ContainsWordsBoundedByObject] 86 | 87 | 88 | GO 89 | PRINT N'Creating [dbo].[ContainsWordsTable]...'; 90 | 91 | 92 | GO 93 | CREATE FUNCTION [dbo].[ContainsWordsTable] 94 | (@xml XML, @text NVARCHAR (MAX), @culture NVARCHAR (MAX)) 95 | RETURNS 96 | TABLE ( 97 | [Index] INT NULL, 98 | [Word] NVARCHAR (MAX) NULL) 99 | AS 100 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[ContainsWordsTable] 101 | 102 | 103 | GO 104 | PRINT N'Creating [dbo].[ContainsWordsTableByObject]...'; 105 | 106 | 107 | GO 108 | CREATE FUNCTION [dbo].[ContainsWordsTableByObject] 109 | (@text NVARCHAR (MAX), @obj NVARCHAR (MAX)) 110 | RETURNS 111 | TABLE ( 112 | [Index] INT NULL, 113 | [Word] NVARCHAR (MAX) NULL) 114 | AS 115 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[ContainsWordsTableByObject] 116 | 117 | 118 | GO 119 | PRINT N'Creating [dbo].[ContainsWordsBoundedTableByObject]...'; 120 | 121 | 122 | GO 123 | CREATE FUNCTION [dbo].[ContainsWordsBoundedTableByObject] 124 | (@text NVARCHAR (MAX), @obj NVARCHAR (MAX)) 125 | RETURNS 126 | TABLE ( 127 | [Index] INT NULL, 128 | [Word] NVARCHAR (MAX) NULL) 129 | AS 130 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[ContainsWordsBoundedTableByObject] 131 | 132 | 133 | GO 134 | PRINT N'Creating [dbo].[ListAhoCorasick]...'; 135 | 136 | 137 | GO 138 | CREATE FUNCTION [dbo].[ListAhoCorasick] 139 | ( ) 140 | RETURNS 141 | TABLE ( 142 | [Hash] NVARCHAR (MAX) NULL) 143 | AS 144 | EXTERNAL NAME [AhoCorasick.SqlClr].[UserDefinedFunctions].[ListAhoCorasick] 145 | 146 | 147 | GO 148 | PRINT N'Update complete.'; 149 | 150 | 151 | GO 152 | --------------------------------------------------------------------------------