diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7d37fa4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,176 @@
+# Created by http://www.gitignore.io
+
+### VisualStudio ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+x64/
+build/
+bld/
+[Bb]in/
+[Oo]bj/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+#NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding addin-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+_NCrunch_*
+.*crunch*.local.xml
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+
+# NuGet Packages Directory
+packages/
+!packages/repositories.config
+
+# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
+# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented)
+!packages/build/
+
+# Windows Azure Build Output
+csx/
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
diff --git a/.tfignore b/.tfignore
new file mode 100644
index 0000000..e37a9f1
--- /dev/null
+++ b/.tfignore
@@ -0,0 +1 @@
+\.git
\ No newline at end of file
diff --git a/NCuid.Tests/Base36ConverterTests.cs b/NCuid.Tests/Base36ConverterTests.cs
new file mode 100644
index 0000000..000e26e
--- /dev/null
+++ b/NCuid.Tests/Base36ConverterTests.cs
@@ -0,0 +1,21 @@
+using Xunit;
+
+namespace Cuid.Tests
+{
+ public class Base36ConverterTests
+ {
+ [Fact]
+ public void DecodeTest()
+ {
+ Assert.Equal(0, Base36Converter.Decode(""));
+ Assert.Equal(-1, Base36Converter.Decode("%"));
+ Assert.Equal(1412823931503067241, Base36Converter.Decode("AQF8AA0006EH"));
+ }
+
+ [Fact]
+ public void EncodeTest()
+ {
+ Assert.Equal("AQF8AA0006EH", Base36Converter.Encode(1412823931503067241));
+ }
+ }
+}
diff --git a/NCuid.Tests/CuidTests.cs b/NCuid.Tests/CuidTests.cs
new file mode 100644
index 0000000..4116b66
--- /dev/null
+++ b/NCuid.Tests/CuidTests.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Diagnostics;
+using Xunit;
+
+namespace Cuid.Tests
+{
+ public class CuidTests
+ {
+ [Fact]
+ public void GenerateTest()
+ {
+ Assert.Equal(Cuid.Generate().Length, 25);
+ }
+
+ [Fact]
+ public void CuidsAreShorterThanGuids()
+ {
+ Assert.True(
+ Guid.NewGuid().ToString().Replace("-", string.Empty).Length > Cuid.Generate().Length
+ );
+ }
+
+ [Fact]
+ public void CuidsAreSlowerThanNativeGuids()
+ {
+ var toGen = Math.Pow(36, 4) +1;
+
+ var sw = new Stopwatch();
+
+ sw.Start();
+ for (double i = 0; i < toGen; i++)
+ {
+ Cuid.Generate();
+ }
+ sw.Stop();
+
+ var elapsedCuid = sw.ElapsedTicks;
+
+ sw.Reset();
+
+ sw.Start();
+ for (double i = 0; i < toGen; i++)
+ {
+ Guid.NewGuid();
+ }
+ sw.Stop();
+
+ var elapsedGuid = sw.ElapsedTicks;
+
+ Assert.False(elapsedGuid > elapsedCuid);
+ }
+ }
+}
diff --git a/NCuid.Tests/DateTimeExtensionsTests.cs b/NCuid.Tests/DateTimeExtensionsTests.cs
new file mode 100644
index 0000000..1ddf983
--- /dev/null
+++ b/NCuid.Tests/DateTimeExtensionsTests.cs
@@ -0,0 +1,23 @@
+using System;
+using Xunit;
+namespace Cuid.Tests
+{
+ public class DateTimeExtensionsTests
+ {
+ [Fact]
+ public void FromUnixTimeTest()
+ {
+ var dt = new DateTime(1987, 07, 03, 18, 00, 00);
+ Assert.Equal(dt.ToUnixTime(), 552333600);
+ }
+
+ [Fact]
+ public void ToUnixTimeTest()
+ {
+ var dt = new DateTime(1987, 07, 03, 18, 00, 00);
+
+ Assert.Equal(dt, 552333600.FromUnixTime());
+ Assert.Equal(dt, 552333600L.FromUnixTime());
+ }
+ }
+}
diff --git a/NCuid.Tests/NCuid.Tests.csproj b/NCuid.Tests/NCuid.Tests.csproj
new file mode 100644
index 0000000..21a0b26
--- /dev/null
+++ b/NCuid.Tests/NCuid.Tests.csproj
@@ -0,0 +1,98 @@
+
+
+
+ Debug
+ AnyCPU
+ {1CD3A779-B529-497C-A186-F0637E316D2A}
+ Library
+ Properties
+ NCuid.Tests
+ NCuid.Tests
+ v4.5
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 10.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
+ False
+ UnitTest
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ ..\packages\xunit.1.9.2\lib\net20\xunit.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {C9033C45-5859-4420-8D44-15A43BBC53EA}
+ NCuid
+
+
+
+
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+ False
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NCuid.Tests/Properties/AssemblyInfo.cs b/NCuid.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..543024d
--- /dev/null
+++ b/NCuid.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// Les informations générales relatives à un assembly dépendent de
+// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
+// associées à un assembly.
+[assembly: AssemblyTitle("Cuid.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Cuid.Tests")]
+[assembly: AssemblyCopyright("Copyright © 2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
+// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
+// COM, affectez la valeur true à l'attribut ComVisible sur ce type.
+[assembly: ComVisible(false)]
+
+// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
+[assembly: Guid("d6d097b8-9e8e-4ca0-895f-214931f45a38")]
+
+// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
+//
+// Version principale
+// Version secondaire
+// Numéro de build
+// Révision
+//
+// Vous pouvez spécifier toutes les valeurs ou vous pouvez définir par défaut les numéros de build et de révision
+// en utilisant '*', comme indiqué ci-dessous :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/NCuid.Tests/StringExtensionsTests.cs b/NCuid.Tests/StringExtensionsTests.cs
new file mode 100644
index 0000000..d9d9ee7
--- /dev/null
+++ b/NCuid.Tests/StringExtensionsTests.cs
@@ -0,0 +1,25 @@
+using Xunit;
+namespace Cuid.Tests
+{
+ public class StringExtensionsTests
+ {
+ [Fact]
+ public void SliceTest()
+ {
+ Assert.Equal("eac", "Peaceful".Slice(1, 4));
+ Assert.Equal(" morning is upon u", "The morning is upon us.".Slice(3, -2));
+
+ const string s = "0123456789_";
+ Assert.Equal("0", s.Slice(0, 1));
+ Assert.Equal("01", s.Slice(0, 2));
+ Assert.Equal("1", s.Slice(1, 2));
+ Assert.Equal("89_", s.Slice(8, 11));
+ }
+
+ [Fact]
+ public void ReverseTest()
+ {
+ Assert.Equal("CBA", "ABC".Reverse());
+ }
+ }
+}
diff --git a/NCuid.Tests/packages.config b/NCuid.Tests/packages.config
new file mode 100644
index 0000000..3eb1f07
--- /dev/null
+++ b/NCuid.Tests/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/NCuid.sln b/NCuid.sln
new file mode 100644
index 0000000..b368227
--- /dev/null
+++ b/NCuid.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30110.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NCuid.Tests", "NCuid.Tests\NCuid.Tests.csproj", "{1CD3A779-B529-497C-A186-F0637E316D2A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NCuid", "NCuid\NCuid.csproj", "{C9033C45-5859-4420-8D44-15A43BBC53EA}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1CD3A779-B529-497C-A186-F0637E316D2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1CD3A779-B529-497C-A186-F0637E316D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1CD3A779-B529-497C-A186-F0637E316D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1CD3A779-B529-497C-A186-F0637E316D2A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C9033C45-5859-4420-8D44-15A43BBC53EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C9033C45-5859-4420-8D44-15A43BBC53EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C9033C45-5859-4420-8D44-15A43BBC53EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C9033C45-5859-4420-8D44-15A43BBC53EA}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/NCuid/Base36Converter.cs b/NCuid/Base36Converter.cs
new file mode 100644
index 0000000..016a35f
--- /dev/null
+++ b/NCuid/Base36Converter.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Text;
+
+namespace Cuid
+{
+ public static class Base36Converter
+ {
+ private const string Clist = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private static readonly char[] Clistarr = Clist.ToCharArray();
+
+ public static long Decode(string inputString)
+ {
+ long result = 0;
+ var pow = 0;
+
+ for (var i = inputString.Length - 1; i >= 0; i--)
+ {
+ var c = inputString[i];
+ var pos = Clist.IndexOf(c);
+
+ if (pos > -1)
+ {
+ result += pos*(long)Math.Pow(Clist.Length, pow);
+ }
+ else
+ {
+ return -1;
+ }
+
+ pow++;
+ }
+ return result;
+ }
+
+ public static string Encode(long inputNumber)
+ {
+ return Encode((ulong)inputNumber);
+ }
+
+ public static string Encode(ulong inputNumber)
+ {
+ var sb = new StringBuilder();
+ do
+ {
+ sb.Append(Clistarr[inputNumber % (ulong)Clist.Length]);
+ inputNumber /= (ulong)Clist.Length;
+ } while (inputNumber != 0);
+
+ return sb.ToString().Reverse();
+ }
+ }
+}
\ No newline at end of file
diff --git a/NCuid/Cuid.cs b/NCuid/Cuid.cs
new file mode 100644
index 0000000..f413634
--- /dev/null
+++ b/NCuid/Cuid.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Diagnostics;
+using System.Linq;
+
+namespace Cuid
+{
+ public class Cuid
+ {
+ private static ulong _globalCounter;
+ private const int BlockSize = 4;
+ private const int Base = 36;
+ private static readonly ulong DiscreteValues = (ulong)Math.Pow(Base, BlockSize);
+
+ //private static string Pad(string num, int size)
+ //{
+ // var s = "0000 0 0000" + num;
+ // return s.Substring(s.Length - size);
+ //}
+
+ private static string Pad(string num, int size)
+ {
+ var s = "000000000" + num;
+ return s.Substring(s.Length-size);
+ }
+
+ private static string RandomBlock(Random rnd)
+ {
+ var number = (long)(rnd.NextDouble() * DiscreteValues);
+ number <<= 0;
+
+ var r = Pad(Base36Converter.Encode(number),
+ BlockSize
+ );
+
+ return r;
+ }
+
+ public static string Generate()
+ {
+ var ts = Base36Converter.Encode(DateTime.Now.ToUnixMilliTime());
+ var gen = new Random();
+ var rnd = RandomBlock(gen) + RandomBlock(gen);
+ var fingerprint = FingerPrint();
+
+ _globalCounter = (_globalCounter < DiscreteValues)
+ ? _globalCounter
+ : 0;
+
+ var counter = Pad(Base36Converter.Encode(_globalCounter), BlockSize);
+
+ _globalCounter++;
+
+ return ("c" + ts + counter + fingerprint + rnd).ToLowerInvariant();
+ }
+
+ public static string FingerPrint()
+ {
+ const int padding = 2;
+
+ var pid = Pad(Base36Converter.Encode((Process.GetCurrentProcess().Id)), padding);
+ var hostname = Environment.MachineName;
+ var length = hostname.Length;
+ var inputNumber = hostname.Split().Aggregate(length + 36, (prev, c) => prev + c[0]);
+
+ var hostId = Pad(Base36Converter.Encode(inputNumber), padding);
+ return pid + hostId;
+ }
+ }
+}
diff --git a/NCuid/DateTimeExtensions.cs b/NCuid/DateTimeExtensions.cs
new file mode 100644
index 0000000..f69c496
--- /dev/null
+++ b/NCuid/DateTimeExtensions.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Cuid
+{
+ public static class DateTimeExtensions
+ {
+ private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+ public static DateTime FromUnixTime(this int unixTime)
+ {
+ return Epoch.AddSeconds(unixTime);
+ }
+
+ public static DateTime FromUnixTime(this long unixTime)
+ {
+ return Epoch.AddSeconds(unixTime);
+ }
+
+ public static long ToUnixTime(this DateTime date)
+ {
+ return Convert.ToInt64((date - Epoch).TotalSeconds);
+ }
+
+ public static long ToUnixMilliTime(this DateTime date)
+ {
+ return Convert.ToInt64((date - Epoch).TotalMilliseconds);
+ }
+ }
+}
diff --git a/NCuid/NCuid.csproj b/NCuid/NCuid.csproj
new file mode 100644
index 0000000..4b959fc
--- /dev/null
+++ b/NCuid/NCuid.csproj
@@ -0,0 +1,56 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {C9033C45-5859-4420-8D44-15A43BBC53EA}
+ Library
+ Properties
+ NCuid
+ NCuid
+ v4.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NCuid/Properties/AssemblyInfo.cs b/NCuid/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0b49ef9
--- /dev/null
+++ b/NCuid/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// Les informations générales relatives à un assembly dépendent de
+// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
+// associées à un assembly.
+[assembly: AssemblyTitle("Cuid.NET")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Cuid.NET")]
+[assembly: AssemblyCopyright("Copyright © 2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
+// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
+// COM, affectez la valeur true à l'attribut ComVisible sur ce type.
+[assembly: ComVisible(false)]
+
+// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
+[assembly: Guid("ca82e0f7-976a-4f3c-bb29-1640af785b97")]
+
+// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
+//
+// Version principale
+// Version secondaire
+// Numéro de build
+// Révision
+//
+// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
+// en utilisant '*', comme indiqué ci-dessous :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/NCuid/StringExtensions.cs b/NCuid/StringExtensions.cs
new file mode 100644
index 0000000..de614f7
--- /dev/null
+++ b/NCuid/StringExtensions.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Cuid
+{
+ public static class StringExtensions
+ {
+ ///
+ /// Get the string slice between the two indexes.
+ /// Inclusive for start index, exclusive for end index.
+ ///
+ public static string Slice(this string source, int start, int end)
+ {
+ if (end < 0) // Keep this for negative end support
+ {
+ end += source.Length;
+ }
+ return source.Substring(start, end - start); // Return Substring of length
+ }
+
+ public static string Reverse(this string s)
+ {
+ var charArray = s.ToCharArray();
+ Array.Reverse(charArray);
+ return new string(charArray);
+ }
+ }
+}
\ No newline at end of file