Skip to content

Commit

Permalink
Updates the readme to describe the algorithms used to validate
Browse files Browse the repository at this point in the history
  • Loading branch information
liamlaverty committed May 1, 2024
1 parent 4bf1356 commit 5100ea2
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 10 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/dotnet-build-and-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net

name: .NET Build & Test

on:
push:
branches: [ "main", "stage", "develop" ]
paths-ignore: ["*.md"] # don't build on markdown file changes
pull_request:
branches: [ "main" ]
paths-ignore: ["*.md"] # don't build on markdown file changes

jobs:
build:

runs-on: ubuntu-latest
env:
working-directory: './'
steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x

- name: Restore dependencies
working-directory: ${{env.working-directory}}
run: dotnet restore

- name: Build
working-directory: ${{env.working-directory}}
run: dotnet build --no-restore

- name: Test
working-directory: ${{env.working-directory}}
run: dotnet test --no-build --verbosity normal
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void ValidateImoNumberReturnsExpectedType(string imoNumber, ImoNumberType
[TestMethod]
public void TestKnownValidCompanyImoNumberReturnsValid(string imoNumber)
{
bool result = ImoNumberValidator.ValidateShippingCompanyRegistrationNumber(imoNumber);
bool result = ImoNumberValidator.ValidateCompanyRegistrationNumber(imoNumber);

Assert.IsTrue(result);
}
Expand All @@ -40,7 +40,7 @@ public void TestKnownValidCompanyImoNumberReturnsValid(string imoNumber)
[TestMethod]
public void TestKnownValidCompanyImoNumberReturnsSameResult(string imoNumber)
{
bool resultValidate = ImoNumberValidator.ValidateShippingCompanyRegistrationNumber(imoNumber);
bool resultValidate = ImoNumberValidator.ValidateCompanyRegistrationNumber(imoNumber);
bool resultIsValid = ImoNumberValidator.IsValidCompanyRegistrationNumber(imoNumber);

Assert.AreEqual(resultValidate, resultIsValid);
Expand Down Expand Up @@ -139,7 +139,7 @@ public void TestValidationAllowsCaseInsensitiveForCompanies(string imoNumber)
{
try
{
bool result = ImoNumberValidator.ValidateShippingCompanyRegistrationNumber(imoNumber);
bool result = ImoNumberValidator.ValidateCompanyRegistrationNumber(imoNumber);
}
catch (ImoNumberValidationException ex)
{
Expand Down Expand Up @@ -193,7 +193,7 @@ public void TestImoNumbersMustBe10CharactersLongForCompanies(string imoNumber)
{
try
{
bool result = ImoNumberValidator.ValidateShippingCompanyRegistrationNumber(imoNumber);
bool result = ImoNumberValidator.ValidateCompanyRegistrationNumber(imoNumber);
}
catch (ImoNumberValidationException ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ public static bool ValidateShipRegistrationNumber(string imoNumber)
/// returns a false, otherwise returns true.
///
/// This method will not throw any exceptions. To get the reason of the invalidity
/// call the method <see cref="ValidateShippingCompanyRegistrationNumber(string)"/> directly
/// call the method <see cref="ValidateCompanyRegistrationNumber(string)"/> directly
/// </summary>
/// <param name="imoNumber">A company's IMO number</param>
/// <returns>true or false, indicating if the IMO number was valid</returns>
public static bool IsValidCompanyRegistrationNumber(string imoNumber)
{
try { ValidateShippingCompanyRegistrationNumber(imoNumber); return true; }
try { ValidateCompanyRegistrationNumber(imoNumber); return true; }
catch { return false; }
}

Expand All @@ -130,7 +130,7 @@ public static bool IsValidCompanyRegistrationNumber(string imoNumber)
/// <param name="imoNumber">A company's IMO number</param>
/// <returns></returns>
/// <exception cref="ImoNumberValidationException"></exception>
public static bool ValidateShippingCompanyRegistrationNumber(string imoNumber)
public static bool ValidateCompanyRegistrationNumber(string imoNumber)
{
// These numbers are defined by the IMO. The first digit in the imo number is
// multipl by 8, the second by 6, the third by 4, the fourth by 2, the fifth by 9, and the sixth by 7
Expand Down
75 changes: 72 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,75 @@ The method validates a **Company**'s registration number. Returns either `true`



# Validation Algorithm


# IMO Number Validation Algorithm

All IMO numbers must be `10` characters in length. The first three characters are uppercase `"IMO"`. The next 6 characters are a set of numbers (unique to each ship). The final (7th) character is a check-digit. Ships and Companies have two different algorithms to calculate the check-digit integrity, outlined below:

## Validating a ship's IMO check-digit

**Weights**: `[7, 6, 5, 4, 3, 2]`

- Take each of the first six numerical digits in the `input-string` (ignore the "IMO" characters)
- Multiply each by its corresponding weight, so
- Digit 1 is multiplied by `7`
- Digit 2 is multiplied by `6`
- Digit 3 is multiplied by `5`
- Digit 4 is multiplied by `4`
- Digit 5 is multiplied by `3`
- Digit 6 is multiplied by `2`
- Sum the results of the multiplication step
- Take the last character from the sum
- Check against the last character for the `input-string`


### **Example**: The ship **Nordic Sola**'s IMO number `"IMO9375989"`

- Multiply each numerical char by its weight:
- $(9 \times 7) + (3 \times 6) + (7 \times 5) + (5 \times 4) + (9 \times 3) + (8 \times 2) = 179$
- Take the last digit of `179` (`9`)
- Take the last digit of `IMO9375989` (9)
- Compare the two:
- If they are the same (`9` in this case) then the number **is** a valid Ship IMO Registration number
- If they are different, the IMO number **is not** a valid Ship IMO Registration number


## Validating a company's IMO check-digit

**Weights**: `[8, 6, 4, 2, 9, 7]`

- Take each of the first six numerical digits in the `input-string` (ignore the "IMO" characters)
- Multiply each by its corresponding weight, so
- Digit 1 is multiplied by `8`
- Digit 2 is multiplied by `6`
- Digit 3 is multiplied by `4`
- Digit 4 is multiplied by `2`
- Digit 5 is multiplied by `9`
- Digit 6 is multiplied by `7`
- Sum the results of the multiplication step
- With the result, apply the `mod11` algorithm
- Subtract the results of the `mod11` step from 11
- With the result, apply the `mod10` algorithm
- Take the last character from the `input-string` and compare to the `mod10` result


### **Example**: The company **EVERGREEN MARINE CORP**'s IMO number `"IMO0344771"`

- Multiply each numerical char by its weight:
- $(8 \times 0) + (6 \times 3) + (4 \times 4) + (2 \times 4) + (9 \times 7) + (7 \times 7) = 154$
- Apply `mod11` to 154
- $(154) \mod{11} = 0$
- Subtract `0` from `11`
- $11 - 0 = 11$
- Apply `mod10` to 11
- $11 \mod{10} = 1$
- Take the last digit of `IMO0344771`: `1`
- Compare the two:
- If they are the same (`1` in this case) then the number **is** a valid Company IMO Registration number
- If they are different, the IMO number **is not** a valid Company IMO Registration number


# References & datasets

- IMO Number Wiki page: https://en.wikipedia.org/wiki/IMO_number
- All ship and company IMO numbers: https://gisis.imo.org/Public/Default.aspx
- IMO Ship Identification Number Schemes: https://www.imo.org/en/OurWork/MSAS/Pages/IMO-identification-number-scheme.aspx

0 comments on commit 5100ea2

Please sign in to comment.