diff --git a/.gitignore b/.gitignore
index f1e3d20..1bb482b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,252 +1,252 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-x64/
-x86/
-bld/
-[Bb]in/
-[Oo]bj/
-[Ll]og/
-
-# Visual Studio 2015 cache/options directory
-.vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
-
-# 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
-
-# DNX
-project.lock.json
-artifacts/
-
-*_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
-*.opendb
-*.opensdf
-*.sdf
-*.cachefile
-*.VC.db
-*.VC.VC.opendb
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-*.sap
-
-# 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 add-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-nCrunchTemp_*
-
-# 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
-# TODO: Comment the next line if you want to checkin your web deploy settings
-# but database connection strings (with potential passwords) will be unencrypted
-*.pubxml
-*.publishproj
-
-# Microsoft Azure Web App publish settings. Comment the next line if you want to
-# checkin your Azure Web App publish settings, but sensitive information contained
-# in these scripts will be unencrypted
-PublishScripts/
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
-*.nuget.props
-*.nuget.targets
-
-# Microsoft Azure Build Output
-csx/
-*.build.csdef
-
-# Microsoft Azure Emulator
-ecf/
-rcf/
-
-# Windows Store app package directories and files
-AppPackages/
-BundleArtifacts/
-Package.StoreAssociation.xml
-_pkginfo.txt
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!*.[Cc]ache/
-
-# Others
-ClientBin/
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.pfx
-*.publishsettings
-node_modules/
-orleans.codegen.cs
-
-# Since there are multiple workflows, uncomment next line to ignore bower_components
-# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
-#bower_components/
-
-# 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/
-
-# GhostDoc plugin setting file
-*.GhostDoc.xml
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Visual Studio LightSwitch build output
-**/*.HTMLClient/GeneratedArtifacts
-**/*.DesktopClient/GeneratedArtifacts
-**/*.DesktopClient/ModelManifest.xml
-**/*.Server/GeneratedArtifacts
-**/*.Server/ModelManifest.xml
-_Pvt_Extensions
-
-# Paket dependency manager
-.paket/paket.exe
-paket-files/
-
-# FAKE - F# Make
-.fake/
-
-# JetBrains Rider
-.idea/
-*.sln.iml
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# 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
+
+# DNX
+project.lock.json
+artifacts/
+
+*_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
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# 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 add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# 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
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# 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/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
diff --git a/CoreSpeed.sln b/CoreSpeed.sln
index 31fc932..a64d10d 100644
--- a/CoreSpeed.sln
+++ b/CoreSpeed.sln
@@ -1,69 +1,69 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26228.4
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8EC1550F-BDE7-441F-808D-04242F2E7358}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{82864B3B-4B60-4C02-BCC8-533FBE478169}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreSpeed", "src\CoreSpeed\CoreSpeed.csproj", "{717FF9B2-9C64-4964-875F-1844B818D1C9}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleClient", "src\ConsoleClient\ConsoleClient.csproj", "{96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}"
- ProjectSection(ProjectDependencies) = postProject
- {717FF9B2-9C64-4964-875F-1844B818D1C9} = {717FF9B2-9C64-4964-875F-1844B818D1C9}
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|ARM = Debug|ARM
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|ARM = Release|ARM
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|ARM.Build.0 = Debug|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|x64.ActiveCfg = Debug|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|x64.Build.0 = Debug|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|x86.ActiveCfg = Debug|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|x86.Build.0 = Debug|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|Any CPU.Build.0 = Release|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|ARM.ActiveCfg = Release|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|ARM.Build.0 = Release|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|x64.ActiveCfg = Release|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|x64.Build.0 = Release|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|x86.ActiveCfg = Release|Any CPU
- {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|x86.Build.0 = Release|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|ARM.Build.0 = Debug|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|x64.ActiveCfg = Debug|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|x64.Build.0 = Debug|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|x86.ActiveCfg = Debug|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|x86.Build.0 = Debug|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|Any CPU.Build.0 = Release|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|ARM.ActiveCfg = Release|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|ARM.Build.0 = Release|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|x64.ActiveCfg = Release|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|x64.Build.0 = Release|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|x86.ActiveCfg = Release|Any CPU
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|x86.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {717FF9B2-9C64-4964-875F-1844B818D1C9} = {8EC1550F-BDE7-441F-808D-04242F2E7358}
- {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF} = {8EC1550F-BDE7-441F-808D-04242F2E7358}
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26228.4
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8EC1550F-BDE7-441F-808D-04242F2E7358}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{82864B3B-4B60-4C02-BCC8-533FBE478169}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreSpeed", "src\CoreSpeed\CoreSpeed.csproj", "{717FF9B2-9C64-4964-875F-1844B818D1C9}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleClient", "src\ConsoleClient\ConsoleClient.csproj", "{96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {717FF9B2-9C64-4964-875F-1844B818D1C9} = {717FF9B2-9C64-4964-875F-1844B818D1C9}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|ARM.Build.0 = Debug|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|x64.Build.0 = Debug|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Debug|x86.Build.0 = Debug|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|ARM.ActiveCfg = Release|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|ARM.Build.0 = Release|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|x64.ActiveCfg = Release|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|x64.Build.0 = Release|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|x86.ActiveCfg = Release|Any CPU
+ {717FF9B2-9C64-4964-875F-1844B818D1C9}.Release|x86.Build.0 = Release|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|ARM.Build.0 = Debug|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|x64.Build.0 = Debug|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Debug|x86.Build.0 = Debug|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|ARM.ActiveCfg = Release|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|ARM.Build.0 = Release|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|x64.ActiveCfg = Release|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|x64.Build.0 = Release|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|x86.ActiveCfg = Release|Any CPU
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {717FF9B2-9C64-4964-875F-1844B818D1C9} = {8EC1550F-BDE7-441F-808D-04242F2E7358}
+ {96AE2E6F-A6E9-4460-95C2-2ACC7EA3E1FF} = {8EC1550F-BDE7-441F-808D-04242F2E7358}
+ EndGlobalSection
+EndGlobal
diff --git a/README.md b/README.md
index ccf3639..c51f331 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,15 @@
-CoreSpeed
+# CoreSpeed
=========
-CoreSpeed is an implementation of SpeedTest.Net using .Net Standard. Included is a test client for both .NET Core (ConsoleClient) and a UWP console app (UWPConsoleClient) for testing.
+CoreSpeed is an implementation of SpeedTest.Net using .Net Standard for the library. Included is a test client for .NET Core (ConsoleClient).
Currently the only CLI cross-platform solution is a Python script, so I wanted to build a robust compiled solution that can run cross-platform and independent of having to have Python and it's various modules installed.
----------------------------------------------------------------------------------------------------------------------------------------------------
-### Build status of branches
+## Build status of branches
| Source | Master Build | Development Build |
|--------:|-----------------:|----------------------:|
-| AppVeyor| [![Build status](https://ci.appveyor.com/api/projects/status/o4ysawi7nqumr03w/branch/master?svg=true)](https://ci.appveyor.com/project/tibmeister/corespeed/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/o4ysawi7nqumr03w/branch/development?svg=true)](https://ci.appveyor.com/project/tibmeister/corespeed/branch/development)|
-
+| AppVeyor| [![Build status](https://ci.appveyor.com/api/projects/status/o4ysawi7nqumr03w/branch/master?svg=true)](https://ci.appveyor.com/project/tibmeister/corespeed/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/o4ysawi7nqumr03w/branch/development?svg=true)](https://ci.appveyor.com/project/tibmeister/corespeed/branch/development)|
\ No newline at end of file
diff --git a/src/ConsoleClient/ConsoleClient.csproj b/src/ConsoleClient/ConsoleClient.csproj
index a3fff79..c0ca58e 100644
--- a/src/ConsoleClient/ConsoleClient.csproj
+++ b/src/ConsoleClient/ConsoleClient.csproj
@@ -1,23 +1,23 @@
-
-
-
- netcoreapp1.1
- ConsoleClient
- Exe
- ConsoleClient
- 1.1.1
- $(PackageTargetFallback);dnxcore50
- false
- false
- false
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ netcoreapp1.1
+ ConsoleClient
+ Exe
+ ConsoleClient
+ 1.1.1
+ $(PackageTargetFallback);dnxcore50
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ConsoleClient/ConsoleSpinner.cs b/src/ConsoleClient/ConsoleSpinner.cs
index 3e76755..037b93b 100644
--- a/src/ConsoleClient/ConsoleSpinner.cs
+++ b/src/ConsoleClient/ConsoleSpinner.cs
@@ -1,55 +1,55 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-
-namespace ConsoleClient
-{
- internal class ConsoleSpinner
- {
- private int _currentAnimationFrame;
- private Timer tmr;
-
- public ConsoleSpinner()
- {
- SpinnerAnimationFrames = new[]
- {
- '|',
- '/',
- '-',
- '\\'
- };
-
- }
-
- private void statusChecker(object state)
- {
- throw new NotImplementedException();
- }
-
- public char[] SpinnerAnimationFrames { get; set; }
-
- public void UpdateProgress()
- {
- //Hide the cursor
- Console.CursorVisible = false;
-
- // Store the current position of the cursor
- var originalX = Console.CursorLeft;
- var originalY = Console.CursorTop;
-
- // Write the next frame (character) in the spinner animation
- Console.Write(SpinnerAnimationFrames[_currentAnimationFrame]);
-
- // Keep looping around all the animation frames
- _currentAnimationFrame++;
- if (_currentAnimationFrame == SpinnerAnimationFrames.Length)
- {
- _currentAnimationFrame = 0;
- }
-
- // Restore cursor to original position
- Console.SetCursorPosition(originalX, originalY);
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+
+namespace ConsoleClient
+{
+ internal class ConsoleSpinner
+ {
+ private int _currentAnimationFrame;
+ private Timer tmr;
+
+ public ConsoleSpinner()
+ {
+ SpinnerAnimationFrames = new[]
+ {
+ '|',
+ '/',
+ '-',
+ '\\'
+ };
+
+ }
+
+ private void statusChecker(object state)
+ {
+ throw new NotImplementedException();
+ }
+
+ public char[] SpinnerAnimationFrames { get; set; }
+
+ public void UpdateProgress()
+ {
+ //Hide the cursor
+ Console.CursorVisible = false;
+
+ // Store the current position of the cursor
+ var originalX = Console.CursorLeft;
+ var originalY = Console.CursorTop;
+
+ // Write the next frame (character) in the spinner animation
+ Console.Write(SpinnerAnimationFrames[_currentAnimationFrame]);
+
+ // Keep looping around all the animation frames
+ _currentAnimationFrame++;
+ if (_currentAnimationFrame == SpinnerAnimationFrames.Length)
+ {
+ _currentAnimationFrame = 0;
+ }
+
+ // Restore cursor to original position
+ Console.SetCursorPosition(originalX, originalY);
+ }
+ }
+}
diff --git a/src/ConsoleClient/Program.cs b/src/ConsoleClient/Program.cs
index 4d616ea..4b92357 100644
--- a/src/ConsoleClient/Program.cs
+++ b/src/ConsoleClient/Program.cs
@@ -1,83 +1,82 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using CoreSpeed;
-using CoreSpeed.Models;
-
-namespace ConsoleClient
-{
- public class Program
- {
- private static Settings settings;
- private static CoreSpeedClient client;
- private const string DefaultCountry = "United States";
-
- public static string DefaultCountry1 => DefaultCountry;
-
- public static void Main(string[] args)
- {
- client = new CoreSpeedClient();
-
- Console.WriteLine("Getting Config...");
- settings = client.GetSettings();
-
- var servers = SelectServers();
- var bestServer = SelectBestServer(servers);
-
- Console.WriteLine("Testing speed...");
-
- var downloadSpeed = client.TestDownloadSpeed(bestServer, settings.Download.ThreadsPerUrl);
- PrintSpeed("Download", downloadSpeed);
-
- var uploadSpeed = client.TestUploadSpeed(bestServer, settings.Upload.ThreadsPerUrl);
- PrintSpeed("Upload", uploadSpeed);
-
- Console.WriteLine("Press a key to exit.");
- Console.ReadKey();
-
- }
-
- private static Server SelectBestServer(IEnumerable servers)
- {
- Console.WriteLine();
- Console.WriteLine("Best server by latency:");
- var bestServer = servers.OrderBy(x => x.Latency).First();
- PrintServerDetails(bestServer);
- Console.WriteLine();
- return bestServer;
- }
-
- private static IEnumerable SelectServers()
- {
- Console.WriteLine();
- Console.WriteLine("Selecting best server by distance...");
- var servers = settings.Servers.Where(s => s.Country.Equals(DefaultCountry1)).Take(10).ToList();
-
- foreach (var server in servers)
- {
- server.Latency = client.TestServerLatency(server);
- PrintServerDetails(server);
- }
- return servers;
- }
-
- private static void PrintServerDetails(Server server)
- {
- Console.WriteLine("Hosted by {0} ({1}/{2}), distance: {3}km, latency: {4}ms", server.Sponsor, server.Name,
- server.Country, (int)server.Distance / 1000, server.Latency);
- }
-
- private static void PrintSpeed(string type, double speed)
- {
- if (speed > 1024)
- {
- Console.WriteLine("{0} speed: {1} Mbps", type, Math.Round(speed / 1024 / 1024, 2));
- }
- else
- {
- Console.WriteLine("{0} speed: {1} Kbps", type, Math.Round(speed / 1024, 2));
- }
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using CoreSpeed;
+using CoreSpeed.Models;
+
+namespace ConsoleClient
+{
+ public class Program
+ {
+ private static Settings settings;
+ private static CoreSpeedClient client;
+ private const string DefaultCountry = "United States";
+
+ public static string DefaultCountry1 => DefaultCountry;
+
+ public static void Main(string[] args)
+ {
+ client = new CoreSpeedClient();
+
+ Console.WriteLine("Getting Config...");
+ settings = client.GetSettings();
+
+ var servers = SelectServers();
+ var bestServer = SelectBestServer(servers);
+
+ Console.WriteLine("Testing speed...");
+
+ var downloadSpeed = client.TestDownloadSpeed(bestServer, settings.Download.ThreadsPerUrl);
+ PrintSpeed("Download", downloadSpeed);
+
+ var uploadSpeed = client.TestUploadSpeed(bestServer, settings.Upload.ThreadsPerUrl);
+ PrintSpeed("Upload", uploadSpeed);
+
+ Console.WriteLine("Press a key to exit.");
+ Console.ReadKey();
+
+ }
+
+ private static Server SelectBestServer(IEnumerable servers)
+ {
+ Console.WriteLine();
+ Console.WriteLine("Best server by latency:");
+ var bestServer = servers.OrderBy(x => x.Latency).First();
+ PrintServerDetails(bestServer);
+ Console.WriteLine();
+ return bestServer;
+ }
+
+ private static IEnumerable SelectServers()
+ {
+ Console.WriteLine();
+ Console.WriteLine("Selecting best server by distance...");
+ var servers = settings.Servers.Where(s => s.Country.Equals(DefaultCountry1)).Take(10).ToList();
+
+ foreach (var server in servers)
+ {
+ server.Latency = client.TestServerLatency(server);
+ PrintServerDetails(server);
+ }
+ return servers;
+ }
+
+ private static void PrintServerDetails(Server server) => Console.WriteLine($"Hosted by {server.Sponsor} ({server.Name}/{server.Country}), " +
+ $"distance: {(int)server.Distance / 1000}km " +
+ $"({Math.Round(ConvertDistance.ConvertKilometersToMiles((int)server.Distance / 1000), 2)}mi), " +
+ $"latency: {server.Latency}ms");
+
+ private static void PrintSpeed(string type, double speed)
+ {
+ if (speed > 1024)
+ {
+ Console.WriteLine($"{type} speed: {Math.Round(speed / 1024 / 1024, 2)} Mbps");
+ }
+ else
+ {
+ Console.WriteLine($"{type} speed: {Math.Round(speed / 1024, 2)} Kbps");
+ }
+ }
+ }
+}
diff --git a/src/ConsoleClient/Properties/AssemblyInfo.cs b/src/ConsoleClient/Properties/AssemblyInfo.cs
index 9122bb1..2a488e6 100644
--- a/src/ConsoleClient/Properties/AssemblyInfo.cs
+++ b/src/ConsoleClient/Properties/AssemblyInfo.cs
@@ -1,19 +1,19 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("ConsoleClient")]
-[assembly: AssemblyTrademark("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("96ae2e6f-a6e9-4460-95c2-2acc7ea3e1ff")]
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ConsoleClient")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("96ae2e6f-a6e9-4460-95c2-2acc7ea3e1ff")]
diff --git a/src/CoreSpeed/CoreSpeed.csproj b/src/CoreSpeed/CoreSpeed.csproj
index a86f7ef..3ac5ea0 100644
--- a/src/CoreSpeed/CoreSpeed.csproj
+++ b/src/CoreSpeed/CoreSpeed.csproj
@@ -1,36 +1,36 @@
-
-
-
- Library
-
-
-
- netstandard1.6
- CoreSpeed
- CoreSpeed
- 1.6.0
- $(PackageTargetFallback);dnxcore50
- false
- false
- false
-
- library
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Library
+
+
+
+ netstandard1.6
+ CoreSpeed
+ CoreSpeed
+ 1.6.0
+ $(PackageTargetFallback);dnxcore50
+ false
+ false
+ false
+
+ library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/CoreSpeed/CoreSpeedClient.cs b/src/CoreSpeed/CoreSpeedClient.cs
index 65abdcc..2208e44 100644
--- a/src/CoreSpeed/CoreSpeedClient.cs
+++ b/src/CoreSpeed/CoreSpeedClient.cs
@@ -1,182 +1,187 @@
-#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Diagnostics;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using CoreSpeed.Models;
-using System.Net.Http;
-
-namespace CoreSpeed
-{
- public class CoreSpeedClient
- {
- private const string ConfigUrl = "http://www.speedtest.net/speedtest-config.php";
- private const string ServersUrl = "http://www.speedtest.net/speedtest-servers.php";
- private readonly int[] downloadSizes = { 350, 500, 750, 1000, 1500, 2000, 2500, 3000, 3500, 4000 };
- private const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- private const int MaxUploadSize = 4;
-
- public Settings GetSettings()
- {
- using (var client = new CoreSpeedWebClient())
- {
- var settings = client.GetConfig(ConfigUrl);
- var serversConfig = client.GetConfig(ServersUrl);
-
- serversConfig.CalculateDistances(settings.Client.GeoCoordinate);
- settings.Servers = serversConfig.Servers.OrderBy(s => s.Distance).ToList();
-
- return settings;
- }
- }
-
- ///
- /// Test latency (ping) to server
- ///
- /// Latency in milliseconds (ms)
- public int TestServerLatency(Server server, int retryCount = 3)
- {
- var latencyUri = CreateTestUrl(server, "latency.txt");
- var timer = new Stopwatch();
-
- using (var client = new CoreSpeedWebClient())
- {
- for (var i = 0; i < retryCount; i++)
- {
- string testString;
- try
- {
- timer.Start();
- testString = client.GetWebRequest(latencyUri).Result;
- }
- catch (WebException)
- {
- continue;
- }
- finally
- {
- timer.Stop();
- }
-
- if (!testString.StartsWith("test=test"))
- {
- throw new InvalidOperationException("Server returned incorrect test string for latency.txt");
- }
- }
- }
-
- return (int)timer.ElapsedMilliseconds / retryCount;
- }
-
- ///
- /// Test download speed to server
- ///
- /// Download speed in Kbps
- public double TestDownloadSpeed(Server server, int simultaniousDownloads = 2, int retryCount = 2)
- {
- var testData = GenerateDownloadUrls(server, retryCount);
-
- return TestSpeed(testData, async (client, url) =>
- {
- var data = await client.GetByteArrayAsync(url);
-
- return data.Length;
- }, simultaniousDownloads);
- }
-
- ///
- /// Test upload speed to server
- ///
- /// Upload speed in Kbps
- public double TestUploadSpeed(Server server, int simultaniousUploads = 2, int retryCount = 2)
- {
- var testData = GenerateUploadData(retryCount);
-
- return TestSpeed(testData, async (client, uploadData) =>
- {
- await client.PostAsync(server.Url, new StringContent(uploadData.ToString()));
-
- return uploadData[0].Length;
- }, simultaniousUploads);
- }
-
-
- private static double TestSpeed(IEnumerable testData, Func> doWork, int concurencyCount = 2)
- {
- var timer = new Stopwatch();
- var throttler = new SemaphoreSlim(concurencyCount);
-
- timer.Start();
-
- var downloadTasks = testData.Select(async data =>
- {
- await throttler.WaitAsync().ConfigureAwait(true);
- var client = new CoreSpeedWebClient();
- try
- {
- var size = await doWork(client, data).ConfigureAwait(true);
- return size;
- }
- finally
- {
- client.Dispose();
- throttler.Release();
- }
- }).ToArray();
-
- Task.Run(() => downloadTasks);
-
- timer.Stop();
-
- //double totalSize = downloadTasks.Sum(task => task.Result);
- double totalSize = downloadTasks.Sum(task => task.Result);
-
- return (totalSize * 8 / 1024) / ((double)timer.ElapsedMilliseconds / 1000);
- }
-
- private static IEnumerable GenerateUploadData(int retryCount)
- {
- var random = new Random();
- var result = new List();
-
- for (var sizeCounter = 1; sizeCounter < MaxUploadSize + 1; sizeCounter++)
- {
- var size = sizeCounter * 200 * 1024;
- var builder = new StringBuilder(size);
-
- for (var i = 0; i < size; ++i)
- builder.Append(Chars[random.Next(Chars.Length)]);
-
- for (var i = 0; i < retryCount; i++)
- {
- result.Add(new NameValueCollection { { string.Format("content{0}", sizeCounter), builder.ToString() } });
- }
- }
-
- return result;
- }
-
- private static string CreateTestUrl(Server server, string file)
- {
- return new Uri(new Uri(server.Url), ".").OriginalString + file;
- }
-
- private IEnumerable GenerateDownloadUrls(Server server, int retryCount)
- {
- var downloadUriBase = CreateTestUrl(server, "random{0}x{0}.jpg?r={1}");
- foreach (var downloadSize in downloadSizes)
- {
- for (var i = 0; i < retryCount; i++)
- {
- yield return string.Format(downloadUriBase, downloadSize, i);
- }
- }
- }
- }
-}
-#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
\ No newline at end of file
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using CoreSpeed.Models;
+using System.Net.Http;
+
+namespace CoreSpeed
+{
+ public static class ConvertDistance
+ {
+ public static double ConvertMilesToKilometers(double miles) => miles * 1.609344;
+
+ public static double ConvertKilometersToMiles(double kilometers) => kilometers * 0.621371192;
+ }
+
+ public class CoreSpeedClient
+ {
+ private const string ConfigUrl = "http://www.speedtest.net/speedtest-config.php";
+ private const string ServersUrl = "http://www.speedtest.net/speedtest-servers.php";
+ private readonly int[] downloadSizes = { 350, 500, 750, 1000, 1500, 2000 };//, 2500, 3000, 3500, 4000 };
+ private const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private const int MaxUploadSize = 4;
+
+ public Settings GetSettings()
+ {
+ using (var client = new CoreSpeedWebClient())
+ {
+ var settings = client.GetConfig(ConfigUrl);
+ var serversConfig = client.GetConfig(ServersUrl);
+
+ serversConfig.CalculateDistances(settings.Client.GeoCoordinate);
+ settings.Servers = serversConfig.Servers.OrderBy(s => s.Distance).ToList();
+
+ return settings;
+ }
+ }
+
+ ///
+ /// Test latency (ping) to server
+ ///
+ /// Latency in milliseconds (ms)
+ public int TestServerLatency(Server server, int retryCount = 3)
+ {
+ var latencyUri = CreateTestUrl(server, "latency.txt");
+ var timer = new Stopwatch();
+
+ using (var client = new CoreSpeedWebClient())
+ {
+ for (var i = 0; i < retryCount; i++)
+ {
+ string testString;
+ try
+ {
+ timer.Start();
+ testString = client.GetWebRequest(latencyUri).Result;
+ }
+ catch (WebException)
+ {
+ continue;
+ }
+ finally
+ {
+ timer.Stop();
+ }
+
+ if (!testString.StartsWith("test=test"))
+ {
+ throw new InvalidOperationException("Server returned incorrect test string for latency.txt");
+ }
+ }
+ }
+
+ return (int)timer.ElapsedMilliseconds / retryCount;
+ }
+
+ ///
+ /// Test download speed to server
+ ///
+ /// Download speed in Kbps
+ public double TestDownloadSpeed(Server server, int simultaniousDownloads = 2, int retryCount = 2)
+ {
+ var testData = GenerateDownloadUrls(server, retryCount);
+
+ return TestSpeed(testData, async (client, url) =>
+ {
+ var data = await client.GetByteArrayAsync(url);
+
+ return data.Length;
+ }, simultaniousDownloads);
+ }
+
+ ///
+ /// Test upload speed to server
+ ///
+ /// Upload speed in Kbps
+ public double TestUploadSpeed(Server server, int simultaniousUploads = 2, int retryCount = 2)
+ {
+ var testData = GenerateUploadData(retryCount);
+
+ return TestSpeed(testData, async (client, uploadData) =>
+ {
+ await client.PostAsync(server.Url, new StringContent(uploadData.ToString()));
+
+ return uploadData[0].Length;
+ }, simultaniousUploads);
+ }
+
+
+ private static double TestSpeed(IEnumerable testData, Func> doWork, int concurencyCount = 2)
+ {
+ var timer = new Stopwatch();
+ var throttler = new SemaphoreSlim(concurencyCount);
+
+ timer.Start();
+
+ var downloadTasks = testData.Select(async data =>
+ {
+ await throttler.WaitAsync().ConfigureAwait(true);
+ var client = new CoreSpeedWebClient();
+ try
+ {
+ var size = await doWork(client, data).ConfigureAwait(true);
+ return size;
+ }
+ finally
+ {
+ client.Dispose();
+ throttler.Release();
+ }
+ }).ToArray();
+
+ Task.Run(() => downloadTasks);
+
+ timer.Stop();
+
+ //double totalSize = downloadTasks.Sum(task => task.Result);
+ double totalSize = downloadTasks.Sum(task => task.Result);
+
+ return (totalSize * 8 / 1024) / ((double)timer.ElapsedMilliseconds / 1000);
+ }
+
+ private static IEnumerable GenerateUploadData(int retryCount)
+ {
+ var random = new Random();
+ var result = new List();
+
+ for (var sizeCounter = 1; sizeCounter < MaxUploadSize + 1; sizeCounter++)
+ {
+ var size = sizeCounter * 200 * 1024;
+ var builder = new StringBuilder(size);
+
+ for (var i = 0; i < size; ++i)
+ builder.Append(Chars[random.Next(Chars.Length)]);
+
+ for (var i = 0; i < retryCount; i++)
+ {
+ result.Add(new NameValueCollection { { string.Format("content{0}", sizeCounter), builder.ToString() } });
+ }
+ }
+
+ return result;
+ }
+
+ private static string CreateTestUrl(Server server, string file)
+ {
+ return new Uri(new Uri(server.Url), ".").OriginalString + file;
+ }
+
+ private IEnumerable GenerateDownloadUrls(Server server, int retryCount)
+ {
+ var downloadUriBase = CreateTestUrl(server, "random{0}x{0}.jpg?r={1}");
+ foreach (var downloadSize in downloadSizes)
+ {
+ for (var i = 0; i < retryCount; i++)
+ {
+ yield return string.Format(downloadUriBase, downloadSize, i);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CoreSpeed/CoreSpeedWebClient.cs b/src/CoreSpeed/CoreSpeedWebClient.cs
index 7b97f75..4195222 100644
--- a/src/CoreSpeed/CoreSpeedWebClient.cs
+++ b/src/CoreSpeed/CoreSpeedWebClient.cs
@@ -1,86 +1,86 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.Net;
-using System.Net.Http;
-using System.Xml;
-using System.Xml.Serialization;
-using System.Threading.Tasks;
-using System.Net.Http.Headers;
-
-namespace CoreSpeed
-{
- internal class CoreSpeedWebClient : HttpClient
- {
- public int ConnectionLimit { get; set; } = 10;
- public new int Timeout {
- get
- {
- return this.Timeout;
- }
-
- set
- {
- base.Timeout = new TimeSpan(0, 0, value);
- }
- }
-
- public CoreSpeedWebClient()
- {
- this.Timeout = 60;
- DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0");
- CacheControlHeaderValue cc = new CacheControlHeaderValue();
- }
-
- public CoreSpeedWebClient(int TimeOutSeconds)
- {
- this.Timeout = TimeOutSeconds;
- }
-
- public T GetConfig(string Url)
- {
- var data = GetWebRequest(Url).Result;
-
- var xmlSerializer = new XmlSerializer(typeof(T));
-
- if (data != null && data.Length > 0)
- {
-
- using (var reader = new StringReader(data.ToString()))
- {
- return (T)xmlSerializer.Deserialize(reader);
- }
- }
- else
- {
- throw new Exception("The data is blank");
- }
- }
-
- public async Task GetWebRequest(string Url)
- {
- string content = "";
-
- Uri uri = AddTimeStampToUrl(new Uri(Url));
- HttpResponseMessage response = await GetAsync(uri);
-
- if (response.IsSuccessStatusCode)
- {
- content = await response.Content.ReadAsStringAsync();
- }
-
- return content;
- }
-
- private static Uri AddTimeStampToUrl(Uri address)
- {
- var uriBuilder = new UriBuilder(address);
- var query = uriBuilder.Query;
-
- query = "x=";
- query += DateTime.Now.ToFileTime().ToString(CultureInfo.InvariantCulture);
- uriBuilder.Query = query.ToString();
- return uriBuilder.Uri;
- }
- }
-}
+using System;
+using System.Globalization;
+using System.IO;
+using System.Net;
+using System.Net.Http;
+using System.Xml;
+using System.Xml.Serialization;
+using System.Threading.Tasks;
+using System.Net.Http.Headers;
+
+namespace CoreSpeed
+{
+ internal class CoreSpeedWebClient : HttpClient
+ {
+ public int ConnectionLimit { get; set; } = 10;
+ public new int Timeout {
+ get
+ {
+ return this.Timeout;
+ }
+
+ set
+ {
+ base.Timeout = new TimeSpan(0, 0, value);
+ }
+ }
+
+ public CoreSpeedWebClient()
+ {
+ this.Timeout = 60;
+ DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0");
+ CacheControlHeaderValue cc = new CacheControlHeaderValue();
+ }
+
+ public CoreSpeedWebClient(int TimeOutSeconds)
+ {
+ this.Timeout = TimeOutSeconds;
+ }
+
+ public T GetConfig(string Url)
+ {
+ var data = GetWebRequest(Url).Result;
+
+ var xmlSerializer = new XmlSerializer(typeof(T));
+
+ if (data != null && data.Length > 0)
+ {
+
+ using (var reader = new StringReader(data.ToString()))
+ {
+ return (T)xmlSerializer.Deserialize(reader);
+ }
+ }
+ else
+ {
+ throw new Exception("The data is blank");
+ }
+ }
+
+ public async Task GetWebRequest(string Url)
+ {
+ string content = "";
+
+ Uri uri = AddTimeStampToUrl(new Uri(Url));
+ HttpResponseMessage response = await GetAsync(uri);
+
+ if (response.IsSuccessStatusCode)
+ {
+ content = await response.Content.ReadAsStringAsync();
+ }
+
+ return content;
+ }
+
+ private static Uri AddTimeStampToUrl(Uri address)
+ {
+ var uriBuilder = new UriBuilder(address);
+ var query = uriBuilder.Query;
+
+ query = "x=";
+ query += DateTime.Now.ToFileTime().ToString(CultureInfo.InvariantCulture);
+ uriBuilder.Query = query.ToString();
+ return uriBuilder.Uri;
+ }
+ }
+}
diff --git a/src/CoreSpeed/ICoreSpeedClient.cs b/src/CoreSpeed/ICoreSpeedClient.cs
index d3d458c..68c7448 100644
--- a/src/CoreSpeed/ICoreSpeedClient.cs
+++ b/src/CoreSpeed/ICoreSpeedClient.cs
@@ -1,35 +1,35 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using CoreSpeed.Models;
-
-namespace CoreSpeed
-{
- interface ICoreSpeedClient
- {
- ///
- /// Download speedtest.net settings
- ///
- /// speedtest.net settings
- Settings GetSettings();
-
- ///
- /// Test latency (ping) to server
- ///
- /// Latency in milliseconds (ms)
- int TestServerLatency(Server server, int retryCount = 3);
-
- ///
- /// Test download speed to server
- ///
- /// Download speed in Kbps
- double TestDownloadSpeed(Server server, int simultaniousDownloads = 2, int retryCount = 2);
-
- ///
- /// Test upload speed to server
- ///
- /// Upload speed in Kbps
- double TestUploadSpeed(Server server, int simultaniousUploads = 2, int retryCount = 2);
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using CoreSpeed.Models;
+
+namespace CoreSpeed
+{
+ interface ICoreSpeedClient
+ {
+ ///
+ /// Download speedtest.net settings
+ ///
+ /// speedtest.net settings
+ Settings GetSettings();
+
+ ///
+ /// Test latency (ping) to server
+ ///
+ /// Latency in milliseconds (ms)
+ int TestServerLatency(Server server, int retryCount = 3);
+
+ ///
+ /// Test download speed to server
+ ///
+ /// Download speed in Kbps
+ double TestDownloadSpeed(Server server, int simultaniousDownloads = 2, int retryCount = 2);
+
+ ///
+ /// Test upload speed to server
+ ///
+ /// Upload speed in Kbps
+ double TestUploadSpeed(Server server, int simultaniousUploads = 2, int retryCount = 2);
+ }
+}
diff --git a/src/CoreSpeed/Models/Client.cs b/src/CoreSpeed/Models/Client.cs
index f357a8d..2a0613f 100644
--- a/src/CoreSpeed/Models/Client.cs
+++ b/src/CoreSpeed/Models/Client.cs
@@ -1,46 +1,46 @@
-using System;
-using System.Xml.Serialization;
-
-namespace CoreSpeed.Models
-{
- [XmlRoot("client")]
- public class Client
- {
- [XmlAttribute("ip")]
- public string Ip { get; set; }
-
- [XmlAttribute("lat")]
- public double Latitude { get; set; }
-
- [XmlAttribute("lon")]
- public double Longitude { get; set; }
-
- [XmlAttribute("isp")]
- public string Isp { get; set; }
-
- [XmlAttribute("isprating")]
- public double IspRating { get; set; }
-
- [XmlAttribute("rating")]
- public double Rating { get; set; }
-
- [XmlAttribute("ispdlavg")]
- public int IspAvarageDownloadSpeed { get; set; }
-
- [XmlAttribute("ispulavg")]
- public int IspAvarageUploadSpeed { get; set; }
-
- private readonly Lazy geoCoordinate;
-
- public Coordinate GeoCoordinate
- {
- get { return geoCoordinate.Value; }
- }
-
- public Client()
- {
- // note: geo coordinate will not be recalculated on Latitude or Longitude change
- geoCoordinate = new Lazy(() => new Coordinate(Latitude, Longitude));
- }
- }
+using System;
+using System.Xml.Serialization;
+
+namespace CoreSpeed.Models
+{
+ [XmlRoot("client")]
+ public class Client
+ {
+ [XmlAttribute("ip")]
+ public string Ip { get; set; }
+
+ [XmlAttribute("lat")]
+ public double Latitude { get; set; }
+
+ [XmlAttribute("lon")]
+ public double Longitude { get; set; }
+
+ [XmlAttribute("isp")]
+ public string Isp { get; set; }
+
+ [XmlAttribute("isprating")]
+ public double IspRating { get; set; }
+
+ [XmlAttribute("rating")]
+ public double Rating { get; set; }
+
+ [XmlAttribute("ispdlavg")]
+ public int IspAvarageDownloadSpeed { get; set; }
+
+ [XmlAttribute("ispulavg")]
+ public int IspAvarageUploadSpeed { get; set; }
+
+ private readonly Lazy geoCoordinate;
+
+ public Coordinate GeoCoordinate
+ {
+ get { return geoCoordinate.Value; }
+ }
+
+ public Client()
+ {
+ // note: geo coordinate will not be recalculated on Latitude or Longitude change
+ geoCoordinate = new Lazy(() => new Coordinate(Latitude, Longitude));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/CoreSpeed/Models/Coordinate.cs b/src/CoreSpeed/Models/Coordinate.cs
index f3d483b..d13964a 100644
--- a/src/CoreSpeed/Models/Coordinate.cs
+++ b/src/CoreSpeed/Models/Coordinate.cs
@@ -1,34 +1,34 @@
-using System;
-
-namespace CoreSpeed.Models
-{
- public class Coordinate
- {
- public double Latitude { get; private set; }
- public double Longitude { get; private set; }
-
- public Coordinate(double latitude, double longitude)
- {
- Latitude = latitude;
- Longitude = longitude;
- }
-
- public double GetDistanceTo(Coordinate other)
- {
- if (double.IsNaN(Latitude) || double.IsNaN(Longitude) || double.IsNaN(other.Latitude) ||
- double.IsNaN(other.Longitude))
- {
- throw new ArgumentException("Argument latitude or longitude is not a number");
- }
-
- var d1 = Latitude * (Math.PI / 180.0);
- var num1 = Longitude * (Math.PI / 180.0);
- var d2 = other.Latitude * (Math.PI / 180.0);
- var num2 = other.Longitude * (Math.PI / 180.0) - num1;
- var d3 = Math.Pow(Math.Sin((d2 - d1) / 2.0), 2.0) +
- Math.Cos(d1) * Math.Cos(d2) * Math.Pow(Math.Sin(num2 / 2.0), 2.0);
-
- return 6376500.0 * (2.0 * Math.Atan2(Math.Sqrt(d3), Math.Sqrt(1.0 - d3)));
- }
- }
-}
+using System;
+
+namespace CoreSpeed.Models
+{
+ public class Coordinate
+ {
+ public double Latitude { get; private set; }
+ public double Longitude { get; private set; }
+
+ public Coordinate(double latitude, double longitude)
+ {
+ Latitude = latitude;
+ Longitude = longitude;
+ }
+
+ public double GetDistanceTo(Coordinate other)
+ {
+ if (double.IsNaN(Latitude) || double.IsNaN(Longitude) || double.IsNaN(other.Latitude) ||
+ double.IsNaN(other.Longitude))
+ {
+ throw new ArgumentException("Argument latitude or longitude is not a number");
+ }
+
+ var d1 = Latitude * (Math.PI / 180.0);
+ var num1 = Longitude * (Math.PI / 180.0);
+ var d2 = other.Latitude * (Math.PI / 180.0);
+ var num2 = other.Longitude * (Math.PI / 180.0) - num1;
+ var d3 = Math.Pow(Math.Sin((d2 - d1) / 2.0), 2.0) +
+ Math.Cos(d1) * Math.Cos(d2) * Math.Pow(Math.Sin(num2 / 2.0), 2.0);
+
+ return 6376500.0 * (2.0 * Math.Atan2(Math.Sqrt(d3), Math.Sqrt(1.0 - d3)));
+ }
+ }
+}
diff --git a/src/CoreSpeed/Models/Download.cs b/src/CoreSpeed/Models/Download.cs
index 120c612..71b0c04 100644
--- a/src/CoreSpeed/Models/Download.cs
+++ b/src/CoreSpeed/Models/Download.cs
@@ -1,20 +1,20 @@
-using System.Xml.Serialization;
-
-namespace CoreSpeed.Models
-{
- [XmlRoot("download")]
- public class Download
- {
- [XmlAttribute("testlength")]
- public int TestLength { get; set; }
-
- [XmlAttribute("initialtest")]
- public string InitialTest { get; set; }
-
- [XmlAttribute("mintestsize")]
- public string MinTestSize { get; set; }
-
- [XmlAttribute("threadsperurl")]
- public int ThreadsPerUrl { get; set; }
- }
+using System.Xml.Serialization;
+
+namespace CoreSpeed.Models
+{
+ [XmlRoot("download")]
+ public class Download
+ {
+ [XmlAttribute("testlength")]
+ public int TestLength { get; set; }
+
+ [XmlAttribute("initialtest")]
+ public string InitialTest { get; set; }
+
+ [XmlAttribute("mintestsize")]
+ public string MinTestSize { get; set; }
+
+ [XmlAttribute("threadsperurl")]
+ public int ThreadsPerUrl { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/CoreSpeed/Models/Server.cs b/src/CoreSpeed/Models/Server.cs
index d03546a..288fec4 100644
--- a/src/CoreSpeed/Models/Server.cs
+++ b/src/CoreSpeed/Models/Server.cs
@@ -1,49 +1,49 @@
-using System;
-using System.Xml.Serialization;
-
-namespace CoreSpeed.Models
-{
- [XmlRoot("server")]
- public class Server
- {
- [XmlAttribute("id")]
- public int Id { get; set; }
-
- [XmlAttribute("name")]
- public string Name { get; set; }
-
- [XmlAttribute("country")]
- public string Country { get; set; }
-
- [XmlAttribute("sponsor")]
- public string Sponsor { get; set; }
-
- [XmlAttribute("host")]
- public string Host { get; set; }
-
- [XmlAttribute("url")]
- public string Url { get; set; }
-
- [XmlAttribute("lat")]
- public double Latitude { get; set; }
-
- [XmlAttribute("lon")]
- public double Longitude { get; set; }
-
- public double Distance { get; set; }
-
- public int Latency { get; set; }
-
- private Lazy geoCoordinate;
- public Coordinate GeoCoordinate
- {
- get { return geoCoordinate.Value; }
- }
-
- public Server()
- {
- // note: geo coordinate will not be recalculated on Latitude or Longitude change
- geoCoordinate = new Lazy(() => new Coordinate(Latitude, Longitude));
- }
- }
+using System;
+using System.Xml.Serialization;
+
+namespace CoreSpeed.Models
+{
+ [XmlRoot("server")]
+ public class Server
+ {
+ [XmlAttribute("id")]
+ public int Id { get; set; }
+
+ [XmlAttribute("name")]
+ public string Name { get; set; }
+
+ [XmlAttribute("country")]
+ public string Country { get; set; }
+
+ [XmlAttribute("sponsor")]
+ public string Sponsor { get; set; }
+
+ [XmlAttribute("host")]
+ public string Host { get; set; }
+
+ [XmlAttribute("url")]
+ public string Url { get; set; }
+
+ [XmlAttribute("lat")]
+ public double Latitude { get; set; }
+
+ [XmlAttribute("lon")]
+ public double Longitude { get; set; }
+
+ public double Distance { get; set; }
+
+ public int Latency { get; set; }
+
+ private Lazy geoCoordinate;
+ public Coordinate GeoCoordinate
+ {
+ get { return geoCoordinate.Value; }
+ }
+
+ public Server()
+ {
+ // note: geo coordinate will not be recalculated on Latitude or Longitude change
+ geoCoordinate = new Lazy(() => new Coordinate(Latitude, Longitude));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/CoreSpeed/Models/ServerConfig.cs b/src/CoreSpeed/Models/ServerConfig.cs
index 430cedd..9b805a5 100644
--- a/src/CoreSpeed/Models/ServerConfig.cs
+++ b/src/CoreSpeed/Models/ServerConfig.cs
@@ -1,11 +1,11 @@
-using System.Xml.Serialization;
-
-namespace CoreSpeed.Models
-{
- [XmlRoot("server-config")]
- public class ServerConfig
- {
- [XmlAttribute("ignoreids")]
- public string IgnoreIds { get; set; }
- }
+using System.Xml.Serialization;
+
+namespace CoreSpeed.Models
+{
+ [XmlRoot("server-config")]
+ public class ServerConfig
+ {
+ [XmlAttribute("ignoreids")]
+ public string IgnoreIds { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/CoreSpeed/Models/ServersList.cs b/src/CoreSpeed/Models/ServersList.cs
index 0e81c61..4c92acd 100644
--- a/src/CoreSpeed/Models/ServersList.cs
+++ b/src/CoreSpeed/Models/ServersList.cs
@@ -1,26 +1,26 @@
-using System.Collections.Generic;
-using System.Xml.Serialization;
-
-namespace CoreSpeed.Models
-{
- [XmlRoot("settings")]
- public class ServersList
- {
- [XmlArray("servers")]
- [XmlArrayItem("server")]
- public List Servers { get; set; }
-
- public ServersList()
- {
- Servers = new List();
- }
-
- public void CalculateDistances(Coordinate clientCoordinate)
- {
- foreach (var server in Servers)
- {
- server.Distance = clientCoordinate.GetDistanceTo(server.GeoCoordinate);
- }
- }
- }
+using System.Collections.Generic;
+using System.Xml.Serialization;
+
+namespace CoreSpeed.Models
+{
+ [XmlRoot("settings")]
+ public class ServersList
+ {
+ [XmlArray("servers")]
+ [XmlArrayItem("server")]
+ public List Servers { get; set; }
+
+ public ServersList()
+ {
+ Servers = new List();
+ }
+
+ public void CalculateDistances(Coordinate clientCoordinate)
+ {
+ foreach (var server in Servers)
+ {
+ server.Distance = clientCoordinate.GetDistanceTo(server.GeoCoordinate);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/CoreSpeed/Models/Settings.cs b/src/CoreSpeed/Models/Settings.cs
index 5015178..8dbdecf 100644
--- a/src/CoreSpeed/Models/Settings.cs
+++ b/src/CoreSpeed/Models/Settings.cs
@@ -1,31 +1,31 @@
-using System.Collections.Generic;
-using System.Xml.Serialization;
-
-namespace CoreSpeed.Models
-{
- [XmlRoot("settings")]
- public class Settings
- {
- [XmlElement("client")]
- public Client Client { get; set; }
-
- [XmlElement("times")]
- public Times Times { get; set; }
-
- [XmlElement("download")]
- public Download Download { get; set; }
-
- [XmlElement("upload")]
- public Upload Upload { get; set; }
-
- [XmlElement("server-config")]
- public ServerConfig ServerConfig { get; set; }
-
- public List Servers { get; set; }
-
- public Settings()
- {
- Servers = new List();
- }
- }
+using System.Collections.Generic;
+using System.Xml.Serialization;
+
+namespace CoreSpeed.Models
+{
+ [XmlRoot("settings")]
+ public class Settings
+ {
+ [XmlElement("client")]
+ public Client Client { get; set; }
+
+ [XmlElement("times")]
+ public Times Times { get; set; }
+
+ [XmlElement("download")]
+ public Download Download { get; set; }
+
+ [XmlElement("upload")]
+ public Upload Upload { get; set; }
+
+ [XmlElement("server-config")]
+ public ServerConfig ServerConfig { get; set; }
+
+ public List Servers { get; set; }
+
+ public Settings()
+ {
+ Servers = new List();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/CoreSpeed/Models/Times.cs b/src/CoreSpeed/Models/Times.cs
index cce61b0..09ba916 100644
--- a/src/CoreSpeed/Models/Times.cs
+++ b/src/CoreSpeed/Models/Times.cs
@@ -1,26 +1,26 @@
-using System.Xml.Serialization;
-
-namespace CoreSpeed.Models
-{
- [XmlRoot("times")]
- public class Times
- {
- [XmlAttribute("dl1")]
- public int Download1 { get; set; }
-
- [XmlAttribute("dl2")]
- public int Download2 { get; set; }
-
- [XmlAttribute("dl3")]
- public int Download3 { get; set; }
-
- [XmlAttribute("ul1")]
- public int Upload1 { get; set; }
-
- [XmlAttribute("ul2")]
- public int Upload2 { get; set; }
-
- [XmlAttribute("ul3")]
- public int Upload3 { get; set; }
- }
+using System.Xml.Serialization;
+
+namespace CoreSpeed.Models
+{
+ [XmlRoot("times")]
+ public class Times
+ {
+ [XmlAttribute("dl1")]
+ public int Download1 { get; set; }
+
+ [XmlAttribute("dl2")]
+ public int Download2 { get; set; }
+
+ [XmlAttribute("dl3")]
+ public int Download3 { get; set; }
+
+ [XmlAttribute("ul1")]
+ public int Upload1 { get; set; }
+
+ [XmlAttribute("ul2")]
+ public int Upload2 { get; set; }
+
+ [XmlAttribute("ul3")]
+ public int Upload3 { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/CoreSpeed/Models/Upload.cs b/src/CoreSpeed/Models/Upload.cs
index abbe1a7..981f634 100644
--- a/src/CoreSpeed/Models/Upload.cs
+++ b/src/CoreSpeed/Models/Upload.cs
@@ -1,32 +1,32 @@
-using System.Xml.Serialization;
-
-namespace CoreSpeed.Models
-{
- [XmlRoot("upload")]
- public class Upload
- {
- [XmlAttribute("testlength")]
- public int TestLength { get; set; }
-
- [XmlAttribute("ratio")]
- public int Ratio { get; set; }
-
- [XmlAttribute("initialtest")]
- public int InitialTest { get; set; }
-
- [XmlAttribute("mintestsize")]
- public string MinTestSize { get; set; }
-
- [XmlAttribute("threads")]
- public int Threads { get; set; }
-
- [XmlAttribute("maxchunksize")]
- public string MaxChunkSize { get; set; }
-
- [XmlAttribute("maxchunkcount")]
- public string MaxChunkCount { get; set; }
-
- [XmlAttribute("threadsperurl")]
- public int ThreadsPerUrl { get; set; }
- }
+using System.Xml.Serialization;
+
+namespace CoreSpeed.Models
+{
+ [XmlRoot("upload")]
+ public class Upload
+ {
+ [XmlAttribute("testlength")]
+ public int TestLength { get; set; }
+
+ [XmlAttribute("ratio")]
+ public int Ratio { get; set; }
+
+ [XmlAttribute("initialtest")]
+ public int InitialTest { get; set; }
+
+ [XmlAttribute("mintestsize")]
+ public string MinTestSize { get; set; }
+
+ [XmlAttribute("threads")]
+ public int Threads { get; set; }
+
+ [XmlAttribute("maxchunksize")]
+ public string MaxChunkSize { get; set; }
+
+ [XmlAttribute("maxchunkcount")]
+ public string MaxChunkCount { get; set; }
+
+ [XmlAttribute("threadsperurl")]
+ public int ThreadsPerUrl { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/CoreSpeed/Properties/AssemblyInfo.cs b/src/CoreSpeed/Properties/AssemblyInfo.cs
index 58a7a42..e675916 100644
--- a/src/CoreSpeed/Properties/AssemblyInfo.cs
+++ b/src/CoreSpeed/Properties/AssemblyInfo.cs
@@ -1,19 +1,19 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("CoreSpeed")]
-[assembly: AssemblyTrademark("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("717ff9b2-9c64-4964-875f-1844b818d1c9")]
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("CoreSpeed")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("717ff9b2-9c64-4964-875f-1844b818d1c9")]