Showing posts with label Code Snippet. Show all posts
Showing posts with label Code Snippet. Show all posts

Thursday, 22 April 2021

Git Tutorial - Commands from Beginner to Advanced Level

Git Tutorial Beginner to Advanced Level

What is Git?

Git is a world wide populor distributed version control system which keeps track of all files in a cenrtalized location. It is a free and open source created by Linus Torvalds in 2005.

In short there will be a centralized copy (master) available in one location and the copy of the same will be copied into each user machine. All users changes will be pushed/merged into the same centrlized/parent copy (maseter) with the help of git commands (add, commit, push, pull etc.)

Advantages of Git

- Speed
- Simplicity
- Fully Distributed
- Excellent support for parallel development, support for hundreds of parallel branches.
- Integrity

Thinking in Git

Thinking in git is simple and easy by practicing it. This article covers the Git commands for beginner to advanced level. Each and every command will be presented with simple and straight forward explanation.

Git Commands

What is my git version?

Command: git --version

Show git configuration details

Command: git config --list
This command shows detailed git configuration for the branch like below.
- remote.origin.url
- user.name
- user.email
- credential.helper (Type of credential stored)

How to create an empty git repository?

Command: git init
Creates an empty repository (Folder) in the machine with the hidden git configuration files in it.

How to clone an origin branch?

Command: git clone <branch_link> <local_branch_name_optional>
It copies all the files from the specified remote branch into the current local machine folder. This stores the chain with remote branch for pushing and pulling the changes.  

Workflow of pushing changes

Modify Files > Staging > Committing > Pushing

What are my pending/modified changes?

Command: git status
Lists the modified files both staged and unstaged.

How to stage files?

Command: git add .
All the modified files will be shown in the unstaged/changes area. To push the local changes you need to stage, commit and push them. Above command will add all the files to the staging area.
Command: git add filename
If the given file name is existed in the modified list then the file will be staged.

How to commit changes?

Command: git commit -m "Commit Message"
You can only commit the staged changes. All the staged files will be committed with the above command. Make sure the files are available in staged area before running this command. Every commit will be generate with an unique hash id to address the commit. This is unique across the all the branches.

Reverting Commit

Command: git revert <commit_hash>
Every commit assigned with an unique hash id (Ex:f26ef0db7d33b46cccccda4699319ef518fdd3c7) to address or refer the commit. This is unique across the all the branches. The above command will revert the given commit.

Pushing changes to origin branch

Command: git push
Pushes all the local commits to origin branch

What are the available changes in origin and how to fecth them?

Command: git fecth
This will compare the origin branch with local branch and list out the commits or changes which are available in origin branch but not available in the local repository. These changes in origin branch can be pushed by the other users from thier local brach. This command helps in knowing what are all the incoming commits before pulling them.

How to pull the changes from origin branch?

Command: git pull
Gets all the pending commits from origin branch into the working branch.

Lis out commit history

Command: git log
Get all the detailed commits history (Commit hash, message, committed owner, committed date, files changed etc.) of the working branch.

Get names of all local branches

Command: git branch

Get names of all remote branches

Command: git branch -r

Get names of both local and remote branches

Command: git branch -a

Switch from one branch to another branch

Command: git checkout <local_branch_name>

Branching - Create a new branch from working / current branch

Command: git checkout -b <new_branch_name>

Branching - Create a new branch from another local branch

Command: git checkout -b <new_branch_name> <source_branch_name>

Branching - Create a local branch from a remote branch

Command: git checkout -b <new_branch_name> <origin/remote_branch_name>

Branching - Delete local branch

Command: git branch -d <local_branch_name>

Branching - Push local branch to remote

Command: git push origin <branch_name>
This will push the local branch to the remote which can be shared with the others.

Branching - Merge another local branch into current branch

Command: git merge <other_local_branch_name>
This compares the commit history of source branch with current branch and merges the changes from source branch into current.

Stashing - Saving Changes Temporarly

Stashing helps in saving the modified and uncommitted changes temporarly. Each stash will be stored with an index by following LIFO (Last In First Order). You can re-apply the saved stash or changes across all the branches. It supports deleting or dropping. You can create a new branch with the stash as well.

Stash the changes
command: git stash

Stash the changes with message
command: git stash save "<stash_message>"

Show all the saved stashes
command: git stash list

Re-apply most recent stash and keep it in your stack
command: git stash apply

Re-apply stash by index
command: git stash apply <index>

Apply most recent stash and then drop
command: git stash pop

Remove most recent stash
command: git stash drop

Remove stash by index
command: git stash drop <index>

Create a branch from stash
command: git stash branch <branch_name> stash@{index}

Get commit details by commit-hash

Command: git show <commit-hash>
This command gets the details of commit which are commit hash, message, owner, date, files changed along with changes.

Cherry-pick commit

Command: git cherry-pick <commit-hash>
Cherry-pick command copies the commit into the current branch. This we use to copy the commit from one branch to another branch.

What is a HEAD?

HEAD is a reference to the last commit in the currently check-out branch. When you do a new commit then HEAD will be pointed to the newly created commit.

Below command shows where and which commit the HEAD is currently pointing to
Command: git show HEAD

Show nth commit with the HELP of HEAD
Command: git show HEAD~<index>

How to rename local and remote branch?

1. Switch to the branch you want to rename
Command: git checkout <branch_name>

2. Rename the branch
Command: git branch -m <new_branch_name>

3. Push the renamed local branch to the remote and reset the upstream branch. This will create the new branch in remote with the new_branch_name and keep the old branch as it is.
Command: git push origin -u <new_branch_name>

4. Delete remote branch with the old_branch_name
Command: git push origin --delete <old_branch_name>

Thursday, 26 November 2020

C# - Truncate characters from string by keeping right side string with the specific length

 

Challenge

Consider a scenario where you are uploading a file in a website and prcoess the file by appending the date at the end of the file name and saves in a location and then saving the uploaded file name in the database. Post uploading the file you are displaying all the submitted files in a grid like below.

Uploaded filename: Developer_Profile.xlsx
Saved filename appended with date: Developer_Profile_11242020.xlsx
https://dotnetcookie.blogspot.com/
Consider the column length for the filename is 150. If the uploaded file name length is more than 150 and there is no length validation before inserting into database then database will throw the exception. So we need to add a validation before uploading. Assume that the client doesn't want to restrict the upload if the file name length is more than 150 characters. Instead client comes with the below requirement.

- If the file length is greater than 150
- Truncate filename to 150 characters, but keep the right side portion which is date part along with extension.

Example: Uploaded file with file name length more than 150
Filename: Developer_Profile_ dummy text of the printing and typesetting industrya Lorem Ipsum has been the industry's standard dummy text ever sinceweb page editors now use Lorestandard_11242020.xlsx

Keep the date part and remove/trim the additional characters highlighted above.

Truncated filename with 150: Developer_Profile_ dummy text of the printing and typesetting industrya Lorem Ipsum has been the industry's standard dummy text ever sinceweb page edit_11242020.xlsx

Below is the extesion method which will truncate the file name and the respective unit testcacses. Follow the code comments which is self explanatory.

Extension method to truncate string

        /// <summary>
        /// If input length is greater than the truncate length value
        /// Trims the input with length truncate length value.
        /// Keeps the right side of the input value
        /// </summary>
        /// <param name="value">Input value</param>
        /// <param name="truncateLength">Truncates input if the input length is greater than this</param>
        /// <param name="rightLengthToKeep">The right side string length which needs to take while truncating</param>
        /// <returns></returns>
        public static string TruncateRight(this string value, int truncateLength, int rightLengthToKeep)
        {
            var errorMessage = "Negative values are not allowed";

            // Handle empty, null and white spaces 
            if (string.IsNullOrWhiteSpace(value))
            {
                return value;
            }

            // Handle negative values
            if (truncateLength < 0)
            {
                throw new ArgumentOutOfRangeException("truncateLength", truncateLength, errorMessage);
            }

            // Handle negative values
            if (rightLengthToKeep < 0)
            {
                throw new ArgumentOutOfRangeException("rightLengthToKeep", rightLengthToKeep, errorMessage);
            }

            if (rightLengthToKeep > truncateLength)
            {
                errorMessage = $"rightLengthToKeep value ({rightLengthToKeep}) shoud be less than or equal to truncateLength ({truncateLength})";
                throw new ArgumentOutOfRangeException(errorMessage);
            }

            if (value.Length <= truncateLength)
            {
                return value;
            }

            // To skip middle range we need to take the left side end rage and right side start rage.
            int leftStringEndIndex = truncateLength - rightLengthToKeep;
            int rightStringStartIndex = value.Length - rightLengthToKeep;

            var finalResult = "";

            // Get left side value
            for (int i = 0; i < leftStringEndIndex; i++)
            {
                finalResult = finalResult + value[i];
            }

            // Get right side value
            for (int i = rightStringStartIndex; i < value.Length; i++)
            {
                finalResult = finalResult + value[i];
            }

            return finalResult;
        }

Unit tests

        [Fact]
        public void SkipRightThenTrimTest()
        {
            // Test filename: FileNameToTestWithTruncateLogicTruncateMe_11242020_ErroFile.csv
            // Total string length is 63

            // Null check
            string testString = null;
            Assert.Equal(null, testString.TruncateRight(40, 22));

            // Empty check
            testString = ""; 
            Assert.Equal("", testString.TruncateRight(40, 22));

            // Whitespace check
            testString = "  ";
            Assert.Equal("  ", testString.TruncateRight(40, 22));

            // Negative value check 
            testString = "FileNameToTestWithTruncateLogicTruncateMe_11242020_ErroFile.csv";
            Assert.Throws<ArgumentOutOfRangeException>(() => testString.TruncateRight(-22, 40));
            Assert.Throws<ArgumentOutOfRangeException>(() => testString.TruncateRight(22, -40));
            
            // Invalid range check
            Assert.Throws<ArgumentOutOfRangeException>(() => testString.TruncateRight(22, 40));

            // Truncate filename if it more than 22 chars and take right 22 characters
            Assert.Equal("_11242020_ErroFile.csv", testString.TruncateRight(22, 22)); 
           
            // Truncate filename if it is more than 40 chars and keep right 22 characters and left 18 chars
            Assert.Equal("FileNameToTestWith_11242020_ErroFile.csv", testString.TruncateRight(40, 22));
            
            // Take filename directly if the fielname lenth and truncate value length is equal
            Assert.Equal(testString, testString.TruncateRight(63, 22));
            
            // Take filename directly if the truncate value length is greater than the filename length
            Assert.Equal(testString, testString.TruncateRight(70, 22));
        }
    }

Tuesday, 22 September 2020

C# LINQ - Partitioning the List Collection Into Chunks

















Partitioning is the key part while working with the large collections in programming. LINQ helps in dividing the huge collection into chunks. 

Below code snippet takes the list and the chunk size and yields the chunks from the collection.

public static IEnumerable<List<T>> Partition<T>(List<T> source, Int32 size)
{
    for (int i = 0; i < Math.Ceiling(source.Count / (Double)size); i++)
        yield return new List<T>(source.Skip(size * i).Take(size));
}

Test Results:





JavaScript - window.location.origin is not working in Internet Explorer


window.location.origin does not work on Internet Explorer. 

Follow the below code which will set the window.location.origin value by concatenating the portions of the URL. 

 if (!window.location.origin)
    window.location.origin = window.location.protocol + '//' + window.location.hostname + (window.location.port ? (':' + window.location.port) : ''); 
}

window.location properties

window.location.protocol         - Return the protocol of the current URL
window.location.hostname      - Returns the domain name of the web host
window.location.port                  - Number of the internet host port (of the current page)

Wednesday, 18 December 2019

Design Patterns - Singleton Design Pattern

Objective: Ensure a class only has one instance, and provides a global point of access to it.

Characteristics.

  • The class must be sealed.
  • A single constructor, that is private and parameterless.
  • A static variable that holds a reference to the single created instance, if any.
  • A public static means of getting the reference to the single created instance, creating one if necessary.

Non Thread Safe Singleton Design Pattern
namespace DesignPatterns
{
    public sealed class Singleton
    {
        // This static variable holds one instance of a class
        private static Singleton instance;

        // Private constructor will control the instantiation
        private Singleton() { }

        // Property responsible to create the single instace and return
        public static Singleton Instance
        {
            get
            {
                // If the static instance is null which means the instance is not yet created.
                if (instance == null)
                {
                    // Creats the static instance with the private constructor.
                    // This is the lazy object instance creation, 
                    // this will creates the object when the property is been called.
                    instance = new Singleton();
                }

                // The instace is ready, the static instance will return from here.
                return instance;
            }
        }

        // Other class methods.....
    }
}
This will make sure the single instance is created but it is not thread safe.
Thread Safe Singleton Design Pattern
public sealed class Singleton
    {
        private static readonly Singleton instance;

        // a static constructor is guaranteed to be called only once per AppDomain, 
        // and only when it’s needed (a static member is called or an instance of that object is created).
        static Singleton()
        {
            instance = new Singleton();
        }

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                return instance;
            }
        }

        // Other class methods.....
    }
Benefits of Singleton Design Pattern:

1. Instance Controlling: This prevents other objects from instantiating their own copies of the Singleton object, ensures that all objects access with the single instance.

2. Flexibility: Since the class controls the instantiation process, the class has the flexibility to change the instantiation process.
3. Helpful in controls concurrent access to a shared resource like logging, registry settings, file system, windows manager etc.
4. Managing the multi-thread Pool.
5. It can be lazy loaded.
6. It has Static Initialization.
7. It helps to hide dependencies.
8. It provides a single point of access to a particular instance, so it is easy to maintain.

Example:

Consider logging process in an application. The log files are shared globally and bigger in size. Your intention is want to flush, sync and close it properly. This is an example of a single shared resource that has to be managed.

Thursday, 12 December 2019

C#.NET - Working With Files, File and Directory

The following class has the code snippets to perform the below operations.
  • Move all files from one directory to another directory
  • Moves source file to target directory
  • Copies all files from one directory to another directory
  • Copies source file to target directory
  • Creates a Directory if it is not existed
  • Deletes the file from path

using System.IO;
using System.Linq;

public class FileProcessor
{
    /// <summary>
    /// Move all files from one directory to another directory
    /// </summary>
    /// <param name="sourceDir">Source Directory</param>
    /// <param name="targetDir">Target Directory</param>
    /// <param name="overWrite">true| overwrite the file. false|</param>
    public static void MoveFiles(string sourceDir, string targetDir, bool overWrite = false)
    {
        if (!Directory.Exists(sourceDir))
        {
            return;
        }

        CheckDirectory(targetDir);

        string[] filesToMove = Directory.GetFiles(sourceDir);

        if (filesToMove != null && filesToMove.Any())
        {
            string destinationFilePath;
            filesToMove.ToList().ForEach(
                filePath =>
                {
                    destinationFilePath = Path.Combine(targetDir, Path.GetFileName(filePath));
                    if (File.Exists(destinationFilePath))
                    {
                        if (overWrite)
                        {
                            DeleteFile(destinationFilePath);
                            File.Move(filePath, destinationFilePath);
                        }
                    }
                    else
                    {
                        File.Move(filePath, destinationFilePath);
                    }
                });
        }
    }

    /// <summary>
    /// Moves source file to target directory
    /// </summary>
    /// <param name="filepath"></param>
    /// <param name="targetDirectory"></param>
    /// <param name="overWrite"></param>
    public static void MoveFile(string sourceFilePath, string targetDirectory, bool overWrite = false)
    {
        if (!File.Exists(sourceFilePath))
        {
            return;
        }

        CheckDirectory(targetDirectory);

        string destinationFilePath = Path.Combine(targetDirectory, Path.GetFileName(sourceFilePath));

        if (overWrite)
        {
            DeleteFile(destinationFilePath);
        }

        File.Move(sourceFilePath, destinationFilePath);
    }

    /// <summary>
    /// Copies all files from one directory to another directory
    /// </summary>
    /// <param name="sourceDir"></param>
    /// <param name="destDir"></param>
    /// <param name="overWrite"></param>
    public static void CopyFiles(string sourceDir, string destDir, bool overWrite = false)
    {
        if (!Directory.Exists(sourceDir))
        {
            return;
        }

        CheckDirectory(destDir);

        string[] filesToCopy = Directory.GetFiles(sourceDir);

        if (filesToCopy != null && filesToCopy.Any())
        {
            filesToCopy.ToList().ForEach(
                sourceFilePath =>
                {
                    File.Copy(sourceFilePath, Path.Combine(destDir, Path.GetFileName(sourceFilePath)), overWrite);
                });
        }
    }

    /// <summary>
    /// Copies source file to target directory
    /// </summary>
    /// <param name="sourceFilePath"></param>
    /// <param name="directoryToCopy"></param>
    /// <param name="overWrite"></param>
    /// <returns></returns>
    public static void CopyFile(string sourceFilePath, string directoryToCopy, bool overWrite = false)
    {
        if (!File.Exists(sourceFilePath))
        {
            return;
        }

        CheckDirectory(directoryToCopy);

        string destinationFilePath = Path.Combine(directoryToCopy, Path.GetFileName(sourceFilePath));
        File.Copy(sourceFilePath, destinationFilePath, overWrite);
    }

    /// <summary>
    /// Creates a Directory if it is not existed
    /// </summary>
    /// <param name="directoryToCopy"></param>
    public static void CheckDirectory(string directoryToCopy)
    {
        if (!Directory.Exists(directoryToCopy))
        {
            Directory.CreateDirectory(directoryToCopy);
        }
    }

    /// <summary>
    /// Deletes the file from path
    /// </summary>
    /// <param name="filepath"></param>
    public static void DeleteFile(string filepath)
    {
        if (File.Exists(filepath))
        {
            File.Delete(filepath);
        }
    }
}

C#.NET - Get All Files from the Directory with File Types Filter

The below code snippet will load all files from the given directory and filter the files by the given file type filter and returns the files info.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

public class FileProcessor
{
    /// <summary>
    /// Loads files by given filter
    /// </summary>
    /// <param name="directoryPath"></param>
    /// <param name="fileTypes"></param>
    /// <param name="caseSensitive"></param>
    /// <returns></returns>
    public IEnumerable<string> LoadFilesByFilters(string directoryPath, string[] fileTypes, bool caseSensitive = false)
    {
        StringComparer compare = StringComparer.OrdinalIgnoreCase;

        if (caseSensitive)
        {
            compare = StringComparer.Ordinal;
        }

        return Directory.EnumerateFiles(directoryPath, "*.*", SearchOption.TopDirectoryOnly)
                    .Where(file => fileTypes.Contains(Path.GetExtension(file), compare));
    }

    /// <summary>
    ///  How to Use?
    /// </summary>
    public IEnumerable<string> LoadFiles()
    {
        return LoadFilesByFilters(@"C:\Users\sravilla\Desktop\Repository", new[] { "*.xls", "*.xlsx" });
    }

}

C#.NET - How to Create a Zip File using Compression Classes

The following code snippet takes the specified file (sourceFilePath) and creates Zip file.

using System.IO;
using System.IO.Compression;

public class FilesProcess
{
    public bool ConvertFileToZip(string sourceFilePath, string destinationZipFilePath)
    {
        bool isFileZipped = false;

        using (ZipArchive archive = ZipFile.Open(destinationZipFilePath, ZipArchiveMode.Create))
        {
            archive.CreateEntryFromFile(sourceFilePath, Path.GetFileName(sourceFilePath));
        }

        if (File.Exists(destinationZipFilePath))
        {
            isFileZipped = true;
        }
        return isFileZipped;
    }
}

C#.NET - Regular Expressions - Search Text by Group Name

The following code snippet will guide you on how to search a string with Regular Expressions with Grouping mechanism and return the value by the group name?
public string RegExGetValueByGroupName(string input, string regExPattern, string groupName)
{
   IEnumerable<Group> matchedList = new Regex(regExPattern)
.Match(input).Groups.Where(grp => string.Equals(grp.Name, groupName));
            return matchedList.Any() ? matchedList.FirstOrDefault().Value : null;
}

C#.NET - Reflection - Get Enum Description from Enum Value

/// Gets the description of the Enumeration provided.
public string GetEnumDescription(Enum value) { return value .GetType() .GetMember(value.ToString()) .FirstOrDefault() .GetCustomAttribute() ?.Description; }

C#.NET - Reflection - Get Enum Value from Description Attribute

Below snippet will get the Enum value by the Enum description
public T GetEnumValueFromDescription(string description)
{
    Type type = typeof(T);
    if (!type.IsEnum)
    {
        throw new ArgumentException();
    }

    FieldInfo[] fields = type.GetFields();
    var field = fields
                    .SelectMany(f => f.GetCustomAttributes(
                        typeof(DescriptionAttribute), false), (
                            f, a) => new { Field = f, Att = a })
                    .Where(a => ((DescriptionAttribute)a.Att)
                        .Description == description).SingleOrDefault();
    return field == null ? default(T) : (T)field.Field.GetRawConstantValue();
}

C#.NET - Large Files Search Processing with Boyer-Moore Searching Algorithm

The below class searches the given string in the specified file. This algorithm is implemented with Boyer-Moore. 

All you need to copy the below full class and call it as shown below.

long searchCount = FileGrep.GetMatchIndexes(filePath, "Hyderabad").Count;

This program can process huge files in seconds.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;

namespace FileProcessor
{
    public class FileGrep
    {
        #region Public Methods
        /// 
        /// Return all matches of the pattern in specified file using the Boyer-Moore algorithm
        /// 
        /// The file to be searched
        /// The size of the buffer to use when reading the file
        /// IEnumerable which returns the indexes of pattern matches
        public static ReadOnlyCollection GetMatchIndexes(string filePath, string searchFor, int bufferSize = 1024 * 1024)
        {
            List matchIndexes = new List();

            if (string.IsNullOrEmpty(searchFor))
            {
                return new ReadOnlyCollection(matchIndexes);
            }

            FileInfo fileToSearch = new FileInfo(filePath);
            if (!fileToSearch.Exists)
            {
                throw new FileNotFoundException();
            }

            if (bufferSize  (Int32.MaxValue - (searchPattern.Length - 1)))
            {
                throw new ArgumentOutOfRangeException("bufferSize", bufferSize, string.Format("Size of the file buffer ({0}) plus the size of the search pattern minus one ({1}) may not exceed Int32.MaxValue ({2}).", bufferSize, (searchPattern.Length - 1), Int32.MaxValue));
            }

            using (FileStream stream = fileToSearch.OpenRead())
            {
                // Make sure that the file stream is seekable to access the data
                if (!stream.CanSeek)
                {
                    throw new Exception(String.Format("The file '{0}' is not seekable!  Search cannot be performed.", fileToSearch));
                }

                int chunkIndex = 0;
                while (true)
                {
                    byte[] fileData = GetNextChunkForSearch(stream, chunkIndex, bufferSize, searchPattern.Length);

                    if (fileData == null || !fileData.Any())
                    {
                        //EOF, so exit
                        break;
                    }

                    List occuranceIndexes = GetMatchIndexes_Internal(fileData, searchPattern, goodSuffixShift, badCharacterShift);

                    if (occuranceIndexes != null)
                    {
                        // We found one or more matches in our buffer.  Translate the buffer index
                        // back to the file index by adding the buffer size * the chunk index.
                        int bufferOffset = (bufferSize * chunkIndex);
                        matchIndexes.AddRange(occuranceIndexes.Select(bufferMatchIndex => (bufferMatchIndex + bufferOffset)));
                    }
                    chunkIndex++;
                } // end while
            }
            return new ReadOnlyCollection(matchIndexes);
        }

        #endregion Public Methods

        #region Helpers
        /// 
        /// Build the bad byte shift array.
        /// 
        /// Pattern for search
        /// Bad byte shift array
        private static long[] BuildBadCharacterShift(byte[] pattern)
        {
            long[] badCharacterShift = new long[256];
            long patternLength = Convert.ToInt64(pattern.Length);

            for (long c = 0; c 
        /// Find suffixes in the pattern
        /// 
        /// Pattern for search
        /// Suffix array
        private static long[] FindSuffixes(byte[] pattern)
        {
            long f = 0;

            long patternLength = Convert.ToInt64(pattern.Length);
            long[] suffixes = new long[pattern.Length + 1];

            suffixes[patternLength - 1] = patternLength;
            long g = patternLength - 1;
            for (long i = patternLength - 2; i >= 0; --i)
            {
                if (i > g && suffixes[i + patternLength - 1 - f] = 0 && (pattern[g] == pattern[g + patternLength - 1 - f]))
                    {
                        --g;
                    }
                    suffixes[i] = f - g;
                }
            }

            return suffixes;
        }
        /// 
        /// Build the good suffix array.
        /// 
        /// Pattern for search
        /// Suffixes in the pattern
        /// Good suffix shift array
        private static long[] BuildGoodSuffixShift(byte[] pattern, long[] suff)
        {
            long patternLength = Convert.ToInt64(pattern.Length);
            long[] goodSuffixShift = new long[pattern.Length + 1];

            for (long i = 0; i = -1; --i)
            {
                if (i == -1 || suff[i] == i + 1)
                {
                    for (; j 
        /// Gets the next chunk of bytes from the stream to perform the search.
        /// 
        /// The stream containing the file to search
        /// The index of the chunk to read from the file
        /// The size of the data chunk to read from the file
        /// The bytes read out of the stream
        private static byte[] GetNextChunkForSearch(Stream stream, int chunkIndex, int fileSearchBufferSize, int searchPatternLength)
        {
            byte[] chunk = null;

            long fileStartIndex = Convert.ToInt64(chunkIndex) * Convert.ToInt64(fileSearchBufferSize);
            if (fileStartIndex = searchPatternLength)
                {
                    // If we read less than the buffer length (end of file), then return a trimmed byte array.
                    if (numBytesRead 
        /// Return all matches of the pattern in specified data using the Boyer-Moore algorithm
        /// 
        /// The data to be searched
        /// List which returns the indexes of pattern matches
        private static List GetMatchIndexes_Internal(byte[] dataToSearch, byte[] searchPattern, long[] goodSuffixShift, long[] badCharacterShift)
        {
            List matchIndexes = new List();

            long patternLength = Convert.ToInt64(searchPattern.Length);
            long textLength = Convert.ToInt64(dataToSearch.Length);

            /* Searching */
            long index = 0;
            while (index = 0)
                {
                    if (searchPattern[unmatched] != dataToSearch[unmatched + index])
                    {
                        //pattern mismatch
                        index += Math.Max(goodSuffixShift[unmatched], badCharacterShift[dataToSearch[unmatched + index]] - patternLength + 1 + unmatched);
                        break;
                    }
                    unmatched--;
                }

                if (unmatched < 0)
                {
                    //match found
                    matchIndexes.Add(index);
                    index += goodSuffixShift[0];
                }
            }

            return matchIndexes;
        }
        #endregion Helpers
    }

}