diff --git a/.coveralls.yml b/.coveralls.yml
new file mode 100644
index 0000000..4eecff5
--- /dev/null
+++ b/.coveralls.yml
@@ -0,0 +1,3 @@
+service_name: travis-ci
+coverage_clover: clover.xml
+json_path: coveralls-upload.json
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..932c4ba
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,13 @@
+# Enforce Unix newlines
+* text=lf
+
+# Exclude unused files
+# see: https://redd.it/2jzp6k
+/tests export-ignore
+/.github export-ignore
+/.gitattributes export-ignore
+/.gitignore export-ignore
+/.*.yml export-ignore
+/phpcs.xml export-ignore
+/phpunit.xml.dist export-ignore
+/README.md export-ignore
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..9a4b075
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @traderinteractive/opensource
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..69512db
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,24 @@
+# Contribution Guidelines
+We welcome you to report [issues](/../../issues) or submit [pull requests](/../../pulls). While the below guidelines are necessary to get code merged, you can
+submit pull requests that do not adhere to them and we will try to take care of them in our spare time. We are a smallish group of developers,
+though, so if you can make sure the build is passing 100%, that would be very useful.
+
+We recommend including details of your particular usecase(s) with any issues or pull requests. We love to hear how our libraries are being used
+and we can get things merged in quicker when we understand its expected usage.
+
+## Pull Requests
+Code changes should be sent through [GitHub Pull Requests](/../../pulls). Before submitting the pull request, make sure that phpunit reports success
+by running:
+```sh
+./vendor/bin/phpunit
+```
+And there are not coding standard violations by running
+```sh
+./vendor/bin/phpcs
+```
+
+## Builds
+Our [Travis build](https://travis-ci.org/traderinteractive/filter-ints-php) executes [PHPUnit](http://www.phpunit.de) and uses [Coveralls](https://coveralls.io/) to enforce code coverage.
+While the build does not strictly enforce 100% code coverage, it will not allow coverage to drop below its current percentage.
+[Scrutinizer](https://scrutinizer-ci.com/) is used to ensure code quality and enforce the [coding standard](http://www.php-fig.org/psr/psr-2/).
+
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..4eef22e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,6 @@
+## Expected Behavior
+
+## Actual Behavior
+
+## Steps to reproduce the behavior
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..c0d57b0
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,9 @@
+Fixes # .
+
+#### What does this PR do?
+
+#### Checklist
+- [ ] Pull request contains a clear definition of changes
+- [ ] Tests (either unit, integration, or acceptance) written and passing
+- [ ] Relevant documentation produced and/or updated
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3be34b5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+/coverage/
+/vendor/
+/clover.xml
+phpunit.xml
+composer.lock
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
new file mode 100644
index 0000000..ef22543
--- /dev/null
+++ b/.scrutinizer.yml
@@ -0,0 +1,22 @@
+filter:
+ excluded_paths:
+ - 'vendor/*'
+before_commands:
+ - 'composer install'
+tools:
+ php_analyzer: true
+ php_mess_detector: true
+ php_code_sniffer:
+ config:
+ standard: PSR2
+ sensiolabs_security_checker: true
+ php_loc:
+ excluded_dirs:
+ - vendor
+ php_pdepend: true
+ php_sim: true
+build_failure_conditions:
+ - 'elements.rating(< A).exists'
+ - 'issues.label("coding-style").exists'
+ - 'issues.severity(>= MAJOR).exists'
+ - 'project.metric("scrutinizer.quality", < 9)'
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..36bdffb
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+sudo: false
+language: php
+php:
+ - 7.0
+ - 7.1
+ - 7.2
+ - nightly
+env:
+ - PREFER_LOWEST="--prefer-lowest --prefer-stable"
+ - PREFER_LOWEST=""
+matrix:
+ fast_finish: true
+ allow_failures:
+ - php: nightly
+before_script:
+ - composer update $PREFER_LOWEST
+script: ./vendor/bin/phpunit --coverage-clover clover.xml
+after_success: ./vendor/bin/coveralls -v
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a7a5819
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Trader Interactive
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 40f08b0..10fedfa 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,64 @@
# filter-ints-php
-A filtering implementation for verifying correct data and performing typical modifications to integers.
+
+[![Build Status](https://travis-ci.org/traderinteractive/filter-ints-php.svg?branch=master)](https://travis-ci.org/traderinteractive/filter-ints-php)
+[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/traderinteractive/filter-ints-php/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/traderinteractive/filter-ints-php/?branch=master)
+[![Coverage Status](https://coveralls.io/repos/github/traderinteractive/filter-ints-php/badge.svg?branch=master)](https://coveralls.io/github/traderinteractive/filter-ints-php?branch=master)
+
+[![Latest Stable Version](https://poser.pugx.org/traderinteractive/filter-ints/v/stable)](https://packagist.org/packages/traderinteractive/filter-ints)
+[![Latest Unstable Version](https://poser.pugx.org/traderinteractive/filter-ints/v/unstable)](https://packagist.org/packages/traderinteractive/filter-ints)
+[![License](https://poser.pugx.org/traderinteractive/filter-ints/license)](https://packagist.org/packages/traderinteractive/filter-ints)
+
+[![Total Downloads](https://poser.pugx.org/traderinteractive/filter-ints/downloads)](https://packagist.org/packages/traderinteractive/filter-ints)
+[![Daily Downloads](https://poser.pugx.org/traderinteractive/filter-ints/d/daily)](https://packagist.org/packages/traderinteractive/filter-ints)
+[![Monthly Downloads](https://poser.pugx.org/traderinteractive/filter-ints/d/monthly)](https://packagist.org/packages/traderinteractive/filter-ints)
+
+A filtering implementation for verifying correct data and performing typical modifications to data.
+
+## Requirements
+
+Requires PHP 7.0 or newer and uses composer to install further PHP dependencies. See the [composer specification](composer.json) for more details.
+
+## Composer
+
+To add the library as a local, per-project dependency use [Composer](http://getcomposer.org)! Simply add a dependency on
+`traderinteractive/filter-ints` to your project's `composer.json` file such as:
+
+```sh
+composer require traderinteractive/filter-ints
+```
+
+### Functionality
+
+#### Ints/UnsignedInt::filter
+
+These filters verify that the arguments are of the proper numeric type and
+allow for bounds checking. The second parameter to each of them can be set to `true` to allow null values through without an error (they will
+stay null and not get converted to false). The next two parameters are the min and max bounds and can be used to limit the domain of allowed
+numbers.
+
+Non-numeric strings will fail validation, and numeric strings will be cast.
+
+The following checks that `$value` is an integer between 1 and 100 inclusive, and returns the integer (after casting it if it was a string).
+
+```php
+$value = \TraderInteractive\Filter\UnsignedInt::filter($value, false, 1, 100);
+```
+
+## Contact
+
+Developers may be contacted at:
+
+ * [Pull Requests](https://github.com/traderinteractive/filter-ints-php/pulls)
+ * [Issues](https://github.com/traderinteractive/filter-ints-php/issues)
+
+## Project Build
+
+With a checkout of the code get [Composer](http://getcomposer.org) in your PATH and run:
+
+```bash
+composer install
+./vendor/bin/phpcs
+./vendor/bin/phpunit
+```
+
+For more information on our build process, read through out our [Contribution Guidelines](CONTRIBUTING.md).
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..3b5719b
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "traderinteractive/filter-ints",
+ "description": "A filtering implementation for verifying correct data and performing typical modifications to data",
+ "keywords": [
+ "integer",
+ "ints",
+ "int",
+ "unsigned",
+ "uint"
+ ],
+ "config": {
+ "sort-packages": true
+ },
+ "license": "MIT",
+ "require": {
+ "php": "^7.0",
+ "traderinteractive/exceptions": "^1.0"
+ },
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^1.0",
+ "phpunit/phpunit": "^6.0",
+ "squizlabs/php_codesniffer": "^3.2"
+ },
+ "autoload": {
+ "psr-4": { "TraderInteractive\\": "src/" }
+ }
+}
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..449f1e8
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,8 @@
+
+
+ .
+ */vendor/*
+
+
+
+
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..ba76cec
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,10 @@
+
+
+ ./tests
+
+
+
+ src
+
+
+
diff --git a/src/Filter/Ints.php b/src/Filter/Ints.php
new file mode 100644
index 0000000..affdce6
--- /dev/null
+++ b/src/Filter/Ints.php
@@ -0,0 +1,144 @@
+ $maxValue) {
+ throw new FilterException("{$valueInt} is greater than {$maxValue}");
+ }
+ }
+
+ private static function enforcePhpIntMax(string $value, int $casted)
+ {
+ if ($casted === PHP_INT_MAX && $value !== (string)PHP_INT_MAX) {
+ throw new FilterException("{$value} was greater than a max int of " . PHP_INT_MAX);
+ }
+ }
+
+ private static function enforcePhpIntMin(string $value, int $casted, int $phpIntMin)
+ {
+ if ($casted === $phpIntMin && $value !== (string)$phpIntMin) {
+ throw new FilterException("{$value} was less than a min int of {$phpIntMin}");
+ }
+ }
+}
diff --git a/src/Filter/UnsignedInt.php b/src/Filter/UnsignedInt.php
new file mode 100644
index 0000000..a39a3ac
--- /dev/null
+++ b/src/Filter/UnsignedInt.php
@@ -0,0 +1,44 @@
+
+ */
+final class IntsTest extends TestCase
+{
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterAllowNullIsTrueAndNullValue()
+ {
+ $result = Ints::filter(null, true);
+ $this->assertSame(null, $result);
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterPositiveInt()
+ {
+ $this->assertSame(123, Ints::filter(123));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterNegativeInt()
+ {
+ $this->assertSame(-123, Ints::filter(-123));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterZeroInt()
+ {
+ $positiveZero = + 0;
+ $this->assertSame(0, Ints::filter($positiveZero));
+ $this->assertSame(0, Ints::filter(-0));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterPositiveString()
+ {
+ $this->assertSame(123, Ints::filter(' 123 '));
+ $this->assertSame(123, Ints::filter(' +123 '));
+ $this->assertSame(0, Ints::filter(' +0 '));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterNegativeString()
+ {
+ $this->assertSame(-123, Ints::filter(' -123 '));
+ $this->assertSame(0, Ints::filter(' -0 '));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ * @expectedExceptionMessage "true" $value is not a string
+ */
+ public function filterNonStringOrInt()
+ {
+ Ints::filter(true);
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ * @expectedExceptionMessage $value string length is zero
+ */
+ public function filterEmptyString()
+ {
+ Ints::filter('');
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ * @expectedExceptionMessage $value string length is zero
+ */
+ public function filterWhitespaceString()
+ {
+ Ints::filter(' ');
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function nonDigitString()
+ {
+ try {
+ Ints::filter('123.4');
+ $this->fail("No exception thrown");
+ } catch (\Throwable $e) {
+ $this->assertSame(
+ "123.4 does not contain all digits, optionally prepended by a '+' or '-' and optionally surrounded by "
+ . "whitespace",
+ $e->getMessage()
+ );
+ }
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ */
+ public function filterGreaterThanPhpIntMax()
+ {
+ //32, 64 and 128 bit and their +1 's
+ $maxes = [
+ '2147483647' => '2147483648',
+ '9223372036854775807' => '9223372036854775808',
+ '170141183460469231731687303715884105727' => '170141183460469231731687303715884105728',
+ ];
+ $oneOverMax = $maxes[(string)PHP_INT_MAX];
+ Ints::filter($oneOverMax);
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ */
+ public function filterLessThanPhpIntMin()
+ {
+ //32, 64 and 128 bit and their -1 's
+ $mins = [
+ '-2147483648' => '-2147483649',
+ '-9223372036854775808' => '-9223372036854775809',
+ '-170141183460469231731687303715884105728' => '-170141183460469231731687303715884105729',
+ ];
+ $oneUnderMin = $mins[(string)~PHP_INT_MAX];
+ Ints::filter($oneUnderMin);
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ * @expectedExceptionMessage -1 is less than 0
+ */
+ public function filterLessThanMin()
+ {
+ Ints::filter(-1, false, 0);
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterEqualToMin()
+ {
+ $this->assertSame(0, Ints::filter(0, false, 0));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ * @expectedExceptionMessage 1 is greater than 0
+ */
+ public function filterGreaterThanMax()
+ {
+ Ints::filter(1, false, null, 0);
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterEqualToMax()
+ {
+ $this->assertSame(0, Ints::filter(0, false, null, 0));
+ }
+}
diff --git a/tests/Filter/UnsignedIntTest.php b/tests/Filter/UnsignedIntTest.php
new file mode 100644
index 0000000..eee038a
--- /dev/null
+++ b/tests/Filter/UnsignedIntTest.php
@@ -0,0 +1,94 @@
+
+ */
+final class UnsignedIntTest extends TestCase
+{
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage -1 was not greater or equal to zero
+ */
+ public function filterMinValueNegative()
+ {
+ UnsignedInt::filter('1', false, -1);
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterMinValueNullSuccess()
+ {
+ $this->assertSame(1, UnsignedInt::filter('1', false, null));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ * @expectedExceptionMessage -1 is less than 0
+ */
+ public function filterMinValueNullFail()
+ {
+ UnsignedInt::filter('-1', false, null);
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterBasicUse()
+ {
+ $this->assertSame(123, UnsignedInt::filter('123'));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ */
+ public function filterAllowNullSuccess()
+ {
+ $this->assertSame(null, UnsignedInt::filter(null, true));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ * @expectedExceptionMessage Value failed filtering, $allowNull is set to false
+ */
+ public function filterAllowNullFail()
+ {
+ UnsignedInt::filter(null, false);
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ * @expectedExceptionMessage 0 is less than 1
+ */
+ public function filterMinValueFail()
+ {
+ $this->assertSame(1, UnsignedInt::filter('0', false, 1));
+ }
+
+ /**
+ * @test
+ * @covers ::filter
+ * @expectedException \TraderInteractive\Exceptions\FilterException
+ * @expectedExceptionMessage 2 is greater than 1
+ */
+ public function filterMaxValueFail()
+ {
+ UnsignedInt::filter('2', false, 0, 1);
+ }
+}