tag:blogger.com,1999:blog-210527322024-09-13T22:29:45.977-07:00Ideas and essays on code developmentMike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]Blogger33125tag:blogger.com,1999:blog-21052732.post-91326284354204148882018-10-22T08:58:00.000-07:002018-10-23T07:44:40.768-07:00JavaScript pattern matching<div dir="ltr" style="text-align: left;" trbidi="on">
If you like JavaScript (and I have been writing quite a bit again recently) then you probably also love Reg “raganwald” Braithwaite's mind stretching JavaScript articles and books.<br />
<br />
I have just been enjoying a <a href="http://raganwald.com/2018/10/17/recursive-pattern-matching.html">recent post on pattern matching</a> that is elegant and demanding of the reader. Fabulous stuff which I enjoyed greatly but all the time I was reading the piece there was a niggle at the back of my head. The niggle kept trying to intrude with the message "matching parentheses is what stacks are for". OK, not strictly true - stacks are for a lot of things but the thought that JavaScript arrays act as an archetypal stack out of the box doubled down on the message.<br />
<br />
I had to try "my way" to see how that went.<br />
<br />
<style type="text/css">
span {
font-family: 'Courier New';
font-size: 10pt;
color: #000000;
}
.sc0 {
background: #F2F4FF;
}
.sc4 {
color: #FF0000;
background: #F2F4FF;
}
.sc5 {
font-weight: bold;
font-style: italic;
color: #000080;
background: #F2F4FF;
}
.sc6 {
color: #808080;
background: #F2F4FF;
}
.sc10 {
font-weight: bold;
background: #F2F4FF;
}
.sc11 {
background: #F2F4FF;
}
</style>
<br />
<div style="background: #FFFFFF; float: left; line-height: 1; white-space: pre;">
<span class="sc5">function</span><span class="sc0"> </span><span class="sc11">balanced</span><span class="sc10">(</span><span class="sc11">str</span><span class="sc10">){</span><span class="sc0">
</span><span class="sc11">let</span><span class="sc0"> </span><span class="sc11">chrs</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc11">str</span><span class="sc10">.</span><span class="sc11">split</span><span class="sc10">(</span><span class="sc6">""</span><span class="sc10">);</span><span class="sc0">
</span><span class="sc11">let</span><span class="sc0"> </span><span class="sc11">lefts</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc6">"({["</span><span class="sc10">;</span><span class="sc0">
</span><span class="sc11">let</span><span class="sc0"> </span><span class="sc11">rights</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc6">")}]"</span><span class="sc10">;</span><span class="sc0">
</span><span class="sc11">let</span><span class="sc0"> </span><span class="sc11">stack</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc10">[];</span><span class="sc0">
</span><span class="sc5">for</span><span class="sc10">(</span><span class="sc11">let</span><span class="sc0"> </span><span class="sc11">i</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc4">0</span><span class="sc10">;</span><span class="sc0"> </span><span class="sc11">i</span><span class="sc0"> </span><span class="sc10"><</span><span class="sc0"> </span><span class="sc11">chrs</span><span class="sc10">.</span><span class="sc11">length</span><span class="sc10">;</span><span class="sc0"> </span><span class="sc11">i</span><span class="sc10">++){</span><span class="sc0">
</span><span class="sc5">if</span><span class="sc10">(</span><span class="sc11">lefts</span><span class="sc10">.</span><span class="sc11">indexOf</span><span class="sc10">(</span><span class="sc11">chrs</span><span class="sc10">[</span><span class="sc11">i</span><span class="sc10">])>-</span><span class="sc4">1</span><span class="sc10">){</span><span class="sc0">
</span><span class="sc11">stack</span><span class="sc10">.</span><span class="sc11">push</span><span class="sc10">(</span><span class="sc11">chrs</span><span class="sc10">[</span><span class="sc11">i</span><span class="sc10">]);</span><span class="sc0">
</span><span class="sc10">}</span><span class="sc0"> </span><span class="sc5">else</span><span class="sc0"> </span><span class="sc10">{</span><span class="sc0">
</span><span class="sc11">let</span><span class="sc0"> </span><span class="sc11">idx</span><span class="sc0"> </span><span class="sc10">=</span><span class="sc0"> </span><span class="sc11">rights</span><span class="sc10">.</span><span class="sc11">indexOf</span><span class="sc10">(</span><span class="sc11">chrs</span><span class="sc10">[</span><span class="sc11">i</span><span class="sc10">]);</span><span class="sc0">
</span><span class="sc5">if</span><span class="sc10">(</span><span class="sc11">idx</span><span class="sc0"> </span><span class="sc10">>=</span><span class="sc0"> </span><span class="sc4">0</span><span class="sc0"> </span><span class="sc10">&&</span><span class="sc0"> </span><span class="sc11">idx</span><span class="sc0"> </span><span class="sc10"><=</span><span class="sc0"> </span><span class="sc4">2</span><span class="sc10">){</span><span class="sc0">
</span><span class="sc5">if</span><span class="sc10">(</span><span class="sc11">stack</span><span class="sc10">[</span><span class="sc11">stack</span><span class="sc10">.</span><span class="sc11">length</span><span class="sc10">-</span><span class="sc4">1</span><span class="sc10">]</span><span class="sc0"> </span><span class="sc10">===</span><span class="sc0"> </span><span class="sc11">lefts</span><span class="sc10">.</span><span class="sc11">substr</span><span class="sc10">(</span><span class="sc11">idx</span><span class="sc10">,</span><span class="sc4">1</span><span class="sc10">)){</span><span class="sc0">
</span><span class="sc11">stack</span><span class="sc10">.</span><span class="sc11">pop</span><span class="sc10">();</span><span class="sc0">
</span><span class="sc10">}</span><span class="sc0"> </span><span class="sc5">else</span><span class="sc0"> </span><span class="sc10">{</span><span class="sc0">
</span><span class="sc11">stack</span><span class="sc10">.</span><span class="sc11">push</span><span class="sc10">(</span><span class="sc11">chrs</span><span class="sc10">[</span><span class="sc11">i</span><span class="sc10">]);</span><span class="sc0">
</span><span class="sc10">}</span><span class="sc0">
</span><span class="sc10">}</span><span class="sc0">
</span><span class="sc10">}</span><span class="sc0">
</span><span class="sc10">}</span><span class="sc0">
</span><span class="sc5">return</span><span class="sc0"> </span><span class="sc11">stack</span><span class="sc10">.</span><span class="sc11">length</span><span class="sc0"> </span><span class="sc10">===</span><span class="sc0"> </span><span class="sc4">0</span><span class="sc10">;</span><span class="sc0">
</span><span class="sc10">}</span></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The strings <b>lefts</b> and <b>rights</b> store the characters to be balanced in a nice extendable way. The first line that splits the function string argument uses the empty string as a delimiter so that the resulting array is constructed with each character in the input string becoming an individual array element.<br />
<br />
The process is simple. If a left hand bracket character (lefts) is found then it is pushed onto the stack. If a right hand bracket character (rights) is found then the top element of the stack should be the matching left hand character. If the match is found then it is popped from the stack with any unmatched right hand items being added to the stack to force the correct result and to aid debugging. [If the test strings were likely to be long then you would probably force a return at that point.] The function returns true if the stack is empty after the process has run and otherwise false.<br />
<br />
Works with raganwald's test strings such as <span style="background-color: white; color: #dd1144; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit;">({}(()))(()</span> => false and <span style="background-color: white; color: #dd1144; font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit;">({()[]})[[(){}]]</span> => true.<br />
<br />
Do we go with elegant or (brutal) pragmatic?<br />
<br />
<Edit> Of course one of those lines of code should have been<br />
<br />
<div style="background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, "Courier New", monospace; font-size: 14px; line-height: 19px; white-space: pre;">
<span style="color: #c586c0;">if</span>(<span style="color: #9cdcfe;">idx</span> >= <span style="color: #b5cea8;">0</span>){</div>
<br />
</Edit><br />
<Addendum><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieMe8Mo9j0F6JWXcudnkiyWI5PbdSGbbj8EgeY-Vxm6STaKDD2HBFoKVpcVza_v8roGNCzZCTbW4GqKdk8tzDzXWDp5u-ZhKWMD8EIrkUJPRCfhFV8YKRMl10siVzUNqRLzz4Uow/s1600/tweet.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="168" data-original-width="635" height="105" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieMe8Mo9j0F6JWXcudnkiyWI5PbdSGbbj8EgeY-Vxm6STaKDD2HBFoKVpcVza_v8roGNCzZCTbW4GqKdk8tzDzXWDp5u-ZhKWMD8EIrkUJPRCfhFV8YKRMl10siVzUNqRLzz4Uow/s400/tweet.png" width="400" /></a></div>
</Addendum><br />
<br /></div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]2tag:blogger.com,1999:blog-21052732.post-73870414249928496772017-01-15T09:09:00.000-08:002017-01-15T09:09:46.745-08:00Docker and .NET on a Windows machine<div dir="ltr" style="text-align: left;" trbidi="on">
It was time to take some first steps with Docker (way past time some might claim). I was moved to have a bash (pun – see later) on a Friday afternoon after seeing an intro article in <a href="http://www.dotnetcurry.net/s/dnc-mag-28th-single">issue 28 of the DNC “magazine”</a> written by Daniel Jimenez Garcia. However I did hit the odd issue when following the article so this post follows the first steps but includes the odd tweak. I am writing this based upon a Windows 10 Pro, 64 bit host machine – valid alternate hosts exist but this is what I have and I suspect will be available to many who want to dip in a toe. The Hyper-V package must be enabled for Docker on Windows to work. The Docker for Windows installer will enable it for you, if needed. I think that Developer Mode must also be set for your Windows 10 installation in “Settings : Update and Security” but you probably already have that set.<br />
<br />
First off, install Docker for Windows 10. Browse to <a href="https://www.docker.com/">https://www.docker.com/ </a>click “Get Started” and then the offered download option. Run the install (.msi) and after the usual confirmations and a little set-up delay you will get confirmation of a successful install with the option to start Docker. Go for it.<br />
<br />
Fire up a Command Prompt and then type the following<br />
<br />
<b>></b><span style="color: blue;">docker run --rm –it microsoft/dotnet:latest</span><br />
<br />
Docker then looks for the microsoft/dotnet image and if it is not found (as this is the first use) then it will be downloaded and installed. This will take a few short minutes during which there is plenty of feedback on progress.<br />
<br />
N.B. If you follow the DNC article you will see that the image name has been capitalised there (Microsoft/dotnet) but this is a magazine editing error.<br />
<br />
Docker will then start a new container for the downloaded image and execute the appropriate entry point with the container attached to your Command Prompt so you can interact with it.<br />
You should see a Linux bash prompt – something like:<br />
<br />
<b>root@6077575d9218:/# </b><br />
<b><br /></b>
which is particularly cool if you have not previously fired up Linux on you Windows 10 installation.<br />
<br />
Now we can create a new folder (don’t worry, as we typed –rm none of this will exist once you exit so will not clutter up your hard drive). Then create a new .NET program in that folder and run it.<br />
<br />
<b>root@6077575d9218:/#</b> <span style="color: blue;">mkdir hellodocker</span><br />
<b>root@6077575d9218:/#</b> <span style="color: blue;">cd hellodocker</span><br />
<b>root@6077575d9218:/hellodocker#</b> <span style="color: blue;">dotnet new</span><br />
<b>Created new C# project in /hellodocker.</b><br />
<b>root@6077575d9218:/hellodocker#</b> <span style="color: blue;">dotnet restore</span><br />
l<b>og : Restoring packages for /hellodocker/project.json...</b><br />
<b>root@6077575d9218:/hellodocker#</b> <span style="color: blue;">dotnet run</span><br />
<b>Project hellodocker (.NETCoreApp,Version=v1.1) will be compiled because expected outputs are missing</b><br />
<b>Compiling hellodocker for .NETCoreApp,Version=v1.1</b><br />
<b>Compilation succeeded.</b><br />
<b> 0 Warning(s)</b><br />
<b> 0 Error(s)</b><br />
<b>Time elapsed 00:00:05.7903169</b><br />
<span style="color: red;">Hello World!</span><br />
<b>root@6077575d9218:/hellodocker#</b><br />
<b><br /></b>
We have just run a .NET Core program in a Docker instance running on a Linux virtual machine hosted by our Windows 10 PC.<br />
<br />
Type <span style="color: blue;">exit</span> to terminate the container and return to the command prompt.<br />
<br />
We are next going to create a .NET program instance in a Windows folder. This makes use of the .Net Command Line Interface (CLI) which may not yet be installed on your machine. The simplest way to check is to try and use it with the following sequence of commands:<br />
<br />
><span style="color: blue;">mkdir hellodocker</span><br />
><span style="color: blue;">cd hellodocker </span><br />
><span style="color: blue;">dotnet new</span><br />
<br />
And if you get an error message from the last command then you will need to install the Command Line Interface. The latest version should be available here <a href="https://www.microsoft.com/net/core#windowsvs2015">https://www.microsoft.com/net/core#windowsvs2015</a><br />
<br />
The install presupposes that you have Visual Studio 2015 installed and that it is up to date (update 3 as at January 2017). Once installed you will need to close and re-open your command prompt window as the system path has now been updated to point to dotnet.<br />
<br />
Now typing ><span style="color: blue;">dotnet new</span> will result in the response that a new C# project has been created in your folder. The folder now contains two files – Program.cs and project.json<br />
They look like this<br />
<br />
<div>
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
using System;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
</div>
</code></pre>
and<br />
<pre style="background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="text-align: left;">
<span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">{</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "version": "1.0.0-*",</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "buildOptions": {</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "debugType": "portable",</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "emitEntryPoint": true</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> },</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "dependencies": {},</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "frameworks": {</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "netcoreapp1.0": {</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "dependencies": {</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "Microsoft.NETCore.App": {</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "type": "platform",</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "version": "1.0.1"</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> },</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> "imports": "dnxcore50"</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: segoe ui;"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">}</span><span style="font-family: Times New Roman;"><span style="white-space: normal;">
</span></span></div>
</code></pre>
Now we can start a new Docker container mounting the Windows folder we just created as a volume.<br />
<br />
You will need to substitute your user name into the Windows path below but on my machine I typed:<br />
<br />
<span style="color: blue;">docker run --rm -it -v /c/Users/mike/hellodocker:/app microsoft/ dotnet:latest</span><br />
<br />
which bumped nicely into the next problem as my C: drive was not shared.<br />
<br />
There will be a Docker icon sitting somewhere at the bottom right of your screen (could be in the “hidden” group), so right click that and select “Settings”. Click the “Shared Drives” tab and check the relevant box before the “Apply” button.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR93__IHRnfSHYJtw-C2aMoVkH5sVt1iV9m-CbJ9yEvPcoucbNGdzn8GAS9D68qBcAZ1rn3vObZhTlFO6hes9d-S2IQymrOBbXjHXC43AgCsn_LJ6z4yV2QShZNclSDv3sgOVM6A/s1600/DockerSettings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR93__IHRnfSHYJtw-C2aMoVkH5sVt1iV9m-CbJ9yEvPcoucbNGdzn8GAS9D68qBcAZ1rn3vObZhTlFO6hes9d-S2IQymrOBbXjHXC43AgCsn_LJ6z4yV2QShZNclSDv3sgOVM6A/s400/DockerSettings.png" width="400" /></a></div>
<br />
You should be prompted for your password and then Docker can implement the share. Back in our Command Prompt window, repeating the last command should see that all is now well. We can check that the Windows folder is now mounted as /app by typing the following command:<br />
<br />
<span style="color: blue;">ls /app</span><br />
<br />
which will list the two existing files in the .NET Core project.<br />
<br />
Now it should be straightforward to compile and run the program with the following:<br />
<br />
<b>root@4c4e67eedfdc:/#</b> <span style="color: blue;">cd /app && dotnet restore && dotnet run</span><br />
<span style="color: blue;"><br /></span>
which in my case produced a lot of interesting output but failed to run. It looked like the two versions of .NET Core (Docker’s and the Windows CLI version just installed) were different.<br />
<br />
The version specified in the json file I created in Windows was 1.0.1 but the Docker image was version 1.1.0. This was probably a timing issue and thus transient though I might have tried specifying a version instead of :latest in my Docker command.<br />
<br />
The command <span style="color: blue;">cat project.json</span> listed the json file and confirmed the project specified version number.<br />
<br />
My work around was a simple text substitution in the json file:<br />
<br />
<span style="color: blue;">sed -i -e 's/1.0.1/1.1.0/g' project.json</span><br />
<br />
followed by a <span style="color: blue;">dotnet restore</span> and <span style="color: blue;">dotnet run</span> and all was well with the program compiling and executing. A quick look back at the Windows folder shows that bin and obj debug folders have been created and populated.<br />
<br />
I can only recommend continuing with the DNC article and building some initial Docker experience – I will be next Friday. <a href="http://www.dotnetcurry.net/s/dnc-mag-28th-single">http://www.dotnetcurry.net/s/dnc-mag-28th-single</a></div>
<div>
<br /></div>
<div>
<b>Links:</b></div>
<div>
<div>
.NET Core CLI tools <a href="https://docs.microsoft.com/en-us/dotnet/articles/core/tools/">https://docs.microsoft.com/en-us/dotnet/articles/core/tools/</a></div>
<div>
<br /></div>
<div>
Get started with Docker for Windows <a href="https://docs.docker.com/docker-for-windows/">https://docs.docker.com/docker-for-windows/</a></div>
<div>
<br /></div>
<div>
(Related follow up) Turning on the Windows subsystem for Linux and getting to know “Bash on Ubuntu” <a href="http://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/">http://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/</a> with a helpful MS FAQ here <a href="https://msdn.microsoft.com/en-us/commandline/wsl/faq">https://msdn.microsoft.com/en-us/commandline/wsl/faq</a></div>
</div>
<div>
<br /></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-18123947604487000522016-09-27T07:42:00.002-07:002017-01-19T06:38:04.957-08:00Fuzzy Dates<div dir="ltr" style="text-align: left;" trbidi="on">
I can remember Fuzzy Logic being quite the thing in the nascent computer based AI projects in the late 70’s and early 80’s. The idea being that you might not have precise values for a given data or that a set of rules might be more or less applicable within a given process – things could be fuzzy but you could still hope to obtain a near optimal output for a given system. If I recall correctly then some of the Expert Systems development work relied upon classes of input that were often akin to broad estimates (at least ranges) rather than precise values.<br />
<br />
Anyone who has developed software that deals with scheduling or calendars or some such has run into issues relating to the human cognitive imprecision with dates and times. Often there is an intention to get something done “that evening” or by “Thursday week” and mostly software ends up forcing the user to plump for some measure of precision and carry the fuzziness of that intention in their heads which is suboptimal.<br />
<br />
Entering dates to a computer based system has always been a programming challenge. In far off pre-GUI days we built a callable routine for date entry on Vax/VMS that was pretty liberal in what it would accept and attempt to convert into a precise date. Among a number of date formats this also included short-hand like t (today) and t-1 (yesterday) etc.. GUIs have brought us clickable calendar like objects but these can be remarkably clumsy to use and do little to help with the issues around imprecision.<br />
<br />
App outputs need to do more to be human sensible. “Tomorrow” or “next week” might communicate a date more effectively to a user than 02/11/2016 (which in any case might be in November or February – you choose). A while back we prototyped some software that converted a date of birth to an age and, within the context of young children, that needed to output values like “3 days old” or “4 weeks” or “9 months” or “4 years” as the date receded into the past and our human expression of age changed accordingly.<br />
<br />
The iOS NSDateFormatter has a doesRelativeDateFormatting option that can manage yesterday, today and tomorrow (at least) and Rails has a more extensive distance_of_time_in_words function and I believe that John Resig wrote pretty.js for JavaScript. I do not doubt a great many programmers have knocked up something along these lines over the years. These are all fine but are based upon a specific date or date/time. Being a little less sure about when (“next week” is a nice example) makes things a little more interesting.<br />
<br />
The <a href="https://github.com/wanasit/chrono">Chrono project in GitHub</a> is a nice introduction to the challenges of parsing a date time string as precise as Sat Aug 17 2013 18:40:39 GMT+0900 or as fuzzy as “last Friday” but that in turn raises the implementation issue of how precisely will a given user supply their date as well as reminding us that in many contexts the time zone might be extremely relevant. There is also some discussion <a href="http://stackoverflow.com/questions/887189/fuzzy-date-time-picker-control-in-c-sharp-net">with code samples on StackExchange</a><br />
<br />
Storing an imprecise date or date time is probably best accomplished with a maximum and minimum value. One might consider storing a single value with a precision indicator but I suspect that code would inevitably be required to convert that precision into a range for comparison purposes and so you might as well settle for twin values from get go. There are some <a href="http://programmers.stackexchange.com/questions/194286/how-do-you-store-fuzzy-dates-into-a-database">interesting StackExchange discussions on this topic</a> as well.<br />
<br />
A satisfactory solution on the input side would need to take account of semantics. The shorthand for today plus one week (T+1w perhaps) is not the same as “next week” which is also not the same as “in the next week”. A humanised output is probably simpler but it looks like this would have to be heavily influenced by context so a standardised class might need some alternate output vocabulary options (age and “elapsed time” being two obvious examples).<br />
<br />
This is a DRAFT version of a class that will accept a range of strings and convert those in turn into a date range representing a fuzzy date. The class steals happily from some of the sources mentioned above. Input can include things like:<br />
<br />
<br />
<ul style="text-align: left;">
<li>Today</li>
<li>Tomorrow</li>
<li>Yesterday</li>
<li>next or Last Month</li>
<li>Next or Last Year</li>
<li>In the Next n Months</li>
<li>In the next n Days</li>
<li>During the next week/month/year</li>
<li>T(oday) + or – n d(ays)/w(eeks)/m(onths/y(ears)</li>
<li>next/last (day of week)</li>
<li>next/last (named month)</li>
</ul>
<br />
<pre style="background: rgb(240, 240, 240); border: 1px dashed rgb(204, 204, 204); height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="text-align: left;">
<span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">class</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">FuzzyDate</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">{</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#region</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> private declarations</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#region</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> static declarations</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">static</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">readonly</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> sqlMinDate = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(1753, 1, 1); </span><span style="color: green; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">// minimum SQLServer datetime</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">static</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">List</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"><</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">> dayList = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">List</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"><</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">>() { </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"sun"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"mon"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"tue"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"wed"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"thu"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"fri"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"sat"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> };</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">static</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">List</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"><</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">> monthList = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">List</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"><</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">>() { </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"jan"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"feb"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"mar"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"apr"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"may"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"jun"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"jul"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"aug"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"sep"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"oct"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"nov"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"dec"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> };</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">static</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">List</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"><</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">IDateTimeInput</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">> parsers = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">List</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"><</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">IDateTimeInput</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">>()</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"next +([2-9]\d*) +months"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">,</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> (</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m) </span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> val = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">int</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Parse(m.Groups[1].Value);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now, </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now.AddMonths(val)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"next +([2-9]\d*) +days"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">,</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> val = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">int</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Parse(m.Groups[1].Value);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now, </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now.AddDays(val)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"tomorrow"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">,</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dt = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.AddDays(1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {dt, </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(dt.Year, dt.Month, dt.Day, 23, 59, 59, 999)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"today"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">,</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dt = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] { dt, </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(dt.Year, dt.Month, dt.Day, 23, 59, 59, 999)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"yesterday"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">,</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dt = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.AddDays(-1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] { dt, </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(dt.Year, dt.Month, dt.Day, 23, 59, 59, 999)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"(in|during) * (last|next) * (year|month|week)"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">,</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">if</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(m.Groups[2].Value == </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"last"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">switch</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(m.Groups[3].Value)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"year"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dt = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.AddYears(-1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {dt, </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"month"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dtm = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.AddMonths(-1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {dtm, </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"week"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dtl = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.AddDays(-7);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {dtl, </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">default</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">null</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> } </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">else</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">switch</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(m.Groups[3].Value)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"year"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dt = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now.AddYears(1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now, dt};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"month"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dtm = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now.AddMonths(1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now, dtm};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"week"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dtl = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {dtl, dtl.AddDays(7)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">default</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">null</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"(last|next) *(year|month|week)"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">,</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">int</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> val = (m.Groups[1].Value == </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"last"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">)? -1 :1;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">switch</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(m.Groups[2].Value)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"year"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dt = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now.AddYears(val);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(dt.Year,1,1), </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(dt.Year,12,31,23,59,59,999)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"month"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dtm = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Now.AddMonths(val);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {startOfMonth(dtm), endOfMonth(dtm)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"week"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> val = (val == 1) ? 7 - (</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">int</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">)</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.DayOfWeek : -(7 + (</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">int</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">)</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.DayOfWeek);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dtl = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.AddDays(val);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {dtl, dtl.AddDays(7).AddSeconds(-1)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">default</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">null</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">String</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Format(</span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"(last|next) *({0}).*"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">String</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Join(</span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"|"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, dayList.ToArray())),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> day = m.Groups[2].Value;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> val = dayList.IndexOf(day.Substring(0,3));</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> adj = (m.Groups[1].Value == </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"last"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">) ? -1 : 1;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">if</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(val >= 0)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> val = adj * (val - (</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">int</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">)</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.DayOfWeek);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">if</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(val <= 0) {val += 7; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dt = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.AddDays(val * adj);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {dt, dt.AddDays(1).AddSeconds(-1)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> } </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">else</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> { </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">null</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;}</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">String</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Format(</span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"(last|next) *({0}).*"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">String</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Join(</span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"|"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, monthList.ToArray())),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> month = m.Groups[2].Value;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> val = monthList.IndexOf(month.Substring(0,3));</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> adj = (m.Groups[1].Value == </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"last"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">) ? -1 : 1;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">if</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(val >= 0)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> val = adj * (val - ((</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">int</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">)</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.Month-1));</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">if</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(val <= 0) {val += 12; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dt = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.AddMonths(val * adj).AddDays(-(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today.Day -1));</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {dt, dt.AddMonths(1).AddSeconds(-1)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> } </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">else</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> { </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">null</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;}</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }),</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: maroon; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">@"t(\s)?(\-|\+)(\s)?([1-9]\d*)(\s)?(d|m|y|w)"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">, </span><span style="color: green; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">// t \=/- n d,w,m,y format</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> sign = m.Groups[2].Value;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> mVal = m.Groups[4].Value;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> mType = m.Groups[6].Value;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> val = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Int32</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Parse(mVal);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">if</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(sign == </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"-"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">) {val *= -1; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> tDay = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.Today;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">switch</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> (mType)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"y"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> tDay = tDay.AddYears(val);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">break</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"m"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> tDay = tDay.AddMonths(val);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">break</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"w"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> tDay = tDay.AddDays(7 * val);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">break</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">case</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #a31515; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">"d"</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> tDay = tDay.AddDays(val);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">break</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">default</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">:</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">null</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] {tDay, tDay.AddDays(1).AddSeconds(-1)};</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> })</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> };</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#endregion</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> minDate = sqlMinDate;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> maxDate = </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.MaxValue;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">bool</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> timeSignificant = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">true</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">; </span><span style="color: green; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">// or false - we shall see</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#endregion</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#region</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> public constructors and methods</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> FuzzyDate()</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> FuzzyDate(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> setDate)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> minDate = maxDate = setDate;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> FuzzyDate(</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dateString)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> setDate(dateString.ToLower());</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">void</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> SetDate(</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dateString)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> setDate(dateString.ToLower());</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">void</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> SetDate(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dateTime)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> minDate = maxDate = dateTime;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#endregion</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#region</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> public properties</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> MinDate</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">get</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> { </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> minDate; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">set</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> { minDate = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">value</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> MaxDate</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">get</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> { </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> maxDate; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">set</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> { maxDate = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">value</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">bool</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> TimeSignificant</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">get</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> { </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> timeSignificant; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">set</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> { timeSignificant = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">value</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">bool</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> IsFuzzy</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">get</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> { </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> minDate == maxDate; }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#endregion</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#region</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> private methods</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">void</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> setDate(</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dateString)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] dt;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">foreach</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> parser </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">in</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> parsers)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dt = parser.Parse(dateString);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">if</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(dt != </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">null</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> minDate = dt[0];</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> maxDate = dt[1];</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">break</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">static</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> startOfMonth(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dayInMonth)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(dayInMonth.Year, dayInMonth.Month, 1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">static</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> endOfMonth(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dayInMonth)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> rVal = dayInMonth.AddMonths(1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> rVal = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(rVal.Year, rVal.Month, 1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> rVal.AddSeconds(-1);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#endregion</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#region</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> local interface and class</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">interface</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">IDateTimeInput</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] Parse(</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dateString);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">private</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">class</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">RegexDateParser</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> : </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">IDateTimeInput</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">delegate</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Interpreter</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(</span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Match</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> m);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">protected</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Regex</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> regEx;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">protected</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Interpreter</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> interpreter;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> RegexDateParser(</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> regexString, </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Interpreter</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> interpreter)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> regEx = </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">new</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">Regex</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">(regexString);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">this</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">.interpreter = interpreter;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">public</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: #2b91af; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">DateTime</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">[] Parse(</span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">string</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> dateString)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">var</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> match = regEx.Match(dateString);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">if</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> (match.Success)</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> {</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> interpreter(match);</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">return</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">null</span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">;</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> }</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;"> </span><span style="color: blue; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">#endregion</span><span style="font-family: "segoe ui";"><span style="font-size: 12px;">
</span></span><span style="color: black; font-family: "segoe ui"; font-size: 12px; font-style: normal; font-weight: normal;">}</span><span style="font-family: "times new roman";"><span style="white-space: normal;">
</span></span></div>
</code></pre>
<div>
<br />
The output of human sensible dates based upon a given DateTime is rather simpler with the details being rather dependent upon the context. In my working examples of “elapsed time” and “age” the output is dependent upon the difference between a given date and the current one. This is normally expressed in the .NET environment as a TimeSpan object. However the TimeSpan class lacks a few features that would make life much simpler when dealing with time spans that represent more than just a few days. I have therefore explored the potential for a custom DateTimeSpan class that could probably be collapsed and simplified into a set of extensions for the .NET supplied standard. So please treat this as another draft idea.</div>
<div>
<br /></div>
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">DateTimeSpan</span>
{
<span style="color: blue;">private</span> <span style="color: blue;">const</span> <span style="color: blue;">int</span> WEEK = 7;
<span style="color: blue;">private</span> <span style="color: blue;">const</span> <span style="color: blue;">int</span> MONTH = 30;
<span style="color: blue;">private</span> <span style="color: blue;">const</span> <span style="color: blue;">int</span> YEAR = 365;
<span style="color: blue;">private</span> <span style="color: blue;">const</span> <span style="color: blue;">int</span> MONTHS_IN_YEAR = 12;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> years;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> months;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> weeks;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> days;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> hours;
<span style="color: blue;">private</span> <span style="color: #2b91af;">Int64</span> minutes;
<span style="color: blue;">private</span> <span style="color: #2b91af;">Int64</span> seconds;
<span style="color: blue;">private</span> <span style="color: #2b91af;">Int64</span> milliseconds;
<span style="color: blue;">public</span> DateTimeSpan(<span style="color: #2b91af;">TimeSpan</span> timeSpan)
{
grabValues(timeSpan);
estimateValues();
}
<span style="color: blue;">public</span> DateTimeSpan(<span style="color: #2b91af;">DateTime</span> datePast)
{
grabValues(<span style="color: #2b91af;">DateTime</span>.Now.Subtract(datePast));
calculateValues(datePast, <span style="color: #2b91af;">DateTime</span>.Now);
}
<span style="color: blue;">public</span> DateTimeSpan(<span style="color: #2b91af;">DateTime</span> fromDate, <span style="color: #2b91af;">DateTime</span> toDate)
{
grabValues(toDate.Subtract(fromDate));
calculateValues(fromDate, toDate);
}
<span style="color: blue;">public</span> <span style="color: blue;">int</span> TotalYears { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> years; } }
<span style="color: blue;">public</span> <span style="color: blue;">int</span> TotalMonths { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> months; } }
<span style="color: blue;">public</span> <span style="color: blue;">int</span> TotalWeeks { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> weeks; } }
<span style="color: blue;">public</span> <span style="color: blue;">int</span> TotalDays { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> days; } }
<span style="color: blue;">public</span> <span style="color: blue;">int</span> TotalHours { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> hours; } }
<span style="color: blue;">public</span> <span style="color: #2b91af;">Int64</span> TotalMinutes { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> minutes; } }
<span style="color: blue;">public</span> <span style="color: #2b91af;">Int64</span> TotalSeconds { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> seconds; } }
<span style="color: blue;">public</span> <span style="color: #2b91af;">Int64</span> TotalMilliseconds { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> milliseconds; } }
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> IsNegative { <span style="color: blue;">get</span> { <span style="color: blue;">return</span> milliseconds < 0; } }
<span style="color: blue;">private</span> <span style="color: blue;">void</span> grabValues(<span style="color: #2b91af;">TimeSpan</span> timeSpan)
{
milliseconds = (<span style="color: #2b91af;">Int64</span>)timeSpan.TotalMilliseconds;
seconds = (<span style="color: #2b91af;">Int64</span>)timeSpan.TotalSeconds;
minutes = (<span style="color: #2b91af;">Int64</span>)timeSpan.TotalMinutes;
hours = (<span style="color: blue;">int</span>)timeSpan.TotalHours;
days = (<span style="color: blue;">int</span>)timeSpan.TotalDays;
<span style="color: blue;">if</span> (days >= WEEK)
{
weeks = days / WEEK;
}
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> estimateValues()
{
<span style="color: blue;">if</span>(days >= MONTH)
{
months = days / MONTH;
}
<span style="color: blue;">if</span>(days >= YEAR)
{
years = days / YEAR;
months = years * MONTHS_IN_YEAR + ((days - years * YEAR) / MONTH);
}
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> calculateValues(<span style="color: #2b91af;">DateTime</span> fromDate, <span style="color: #2b91af;">DateTime</span> toDate)
{
<span style="color: blue;">int</span> sign = 1;
<span style="color: blue;">if</span>(fromDate > toDate)
{
<span style="color: blue;">var</span> hdate = toDate;
toDate = fromDate;
fromDate = hdate;
sign = -1;
}
<span style="color: blue;">int</span> monthCount = -1;
<span style="color: blue;">while</span> (fromDate <= toDate)
{
fromDate = fromDate.AddMonths(1);
monthCount++;
}
months = monthCount * sign;
years = monthCount / 12;
}
<span style="font-family: "consolas"; font-size: 12.666666666666666;">}</span>
</div>
</code></pre>
<div>
<br />
Any given output requirement would probably only need one set of rules but just for fun here is a class that can manage two and could be easily expanded to handle more.<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">PrettyDate</span>
{
<span style="color: blue;">public</span> <span style="color: blue;">enum</span> <span style="color: #2b91af;">PrettyTypes</span>
{
[<span style="color: #2b91af;">Description</span>(<span style="color: #a31515;">"Returns date as an age string"</span>)]
Age,
[<span style="color: #2b91af;">Description</span>(<span style="color: #a31515;">"Returns date/time as elapsed time"</span>)]
Elapsed
}
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">string</span> GetPrettyDate(<span style="color: #2b91af;">DateTime</span> theDate, <span style="color: #2b91af;">PrettyTypes</span> prettyType)
{
<span style="color: #2b91af;">DateTimeSpan</span> dSince = <span style="color: blue;">new</span> <span style="color: #2b91af;">DateTimeSpan</span>(theDate);
<span style="color: blue;">if</span>(prettyType == <span style="color: #2b91af;">PrettyTypes</span>.Elapsed)
{
<span style="color: blue;">if</span>(dSince.IsNegative) { <span style="color: blue;">return</span> <span style="color: #a31515;">"not happened yet"</span>; }
<span style="color: blue;">if</span>(dSince.TotalYears > 0)
{
<span style="color: green;">// could be tweaked for a rounded number in a number of ways - this is one</span>
<span style="color: blue;">int</span> months = dSince.TotalMonths - dSince.TotalYears * 12;
<span style="color: blue;">int</span> years = (months >= 10) ? dSince.TotalYears + 1 : dSince.TotalYears;
<span style="color: blue;">return</span> years + <span style="color: #a31515;">" year"</span> + ((years > 1) ? <span style="color: #a31515;">"s ago"</span> : <span style="color: #a31515;">" ago"</span>);
} <span style="color: blue;">else</span> <span style="color: blue;">if</span> (dSince.TotalMonths > 0)
{
<span style="color: blue;">return</span> dSince.TotalMonths + <span style="color: #a31515;">" month"</span> + ((dSince.TotalMonths > 1) ? <span style="color: #a31515;">"s ago"</span> : <span style="color: #a31515;">" ago"</span>);
} <span style="color: blue;">else</span> <span style="color: blue;">if</span>(dSince.TotalWeeks > 0)
{
<span style="color: blue;">return</span> dSince.TotalWeeks + <span style="color: #a31515;">" week"</span> + ((dSince.TotalWeeks > 1) ? <span style="color: #a31515;">"s ago"</span> : <span style="color: #a31515;">" ago"</span>);
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span>(dSince.TotalDays > 0)
{
<span style="color: blue;">return</span> dSince.TotalDays + <span style="color: #a31515;">" day"</span> + ((dSince.TotalDays > 1) ? <span style="color: #a31515;">"s ago"</span> : <span style="color: #a31515;">" ago"</span>);
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (dSince.TotalHours > 0)
{
<span style="color: blue;">return</span> dSince.TotalHours + <span style="color: #a31515;">" hour"</span> + ((dSince.TotalHours > 1) ? <span style="color: #a31515;">"s ago"</span> : <span style="color: #a31515;">" ago"</span>);
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span>(dSince.TotalMinutes > 0)
{
<span style="color: blue;">return</span> dSince.TotalMinutes + <span style="color: #a31515;">" minute"</span> + ((dSince.TotalMinutes > 1) ? <span style="color: #a31515;">"s ago"</span> : <span style="color: #a31515;">" ago"</span>);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">return</span> <span style="color: #a31515;">"now"</span>; <span style="color: green;">// adjust to taste</span>
}
} <span style="color: blue;">else</span>
{
<span style="color: blue;">if</span> (dSince.IsNegative) { <span style="color: blue;">return</span> <span style="color: #a31515;">"not born yet"</span>; }
<span style="color: blue;">if</span> (dSince.TotalYears >= 5)
{
<span style="color: blue;">return</span> dSince.TotalYears + <span style="color: #a31515;">" years"</span>;
} <span style="color: blue;">else</span> <span style="color: blue;">if</span>(dSince.TotalYears >= 3)
{
<span style="color: blue;">int</span> months = dSince.TotalMonths - dSince.TotalYears * 12;
<span style="color: blue;">string</span> fract = <span style="color: #a31515;">""</span>;
<span style="color: blue;">if</span>(months >= 8)
{
fract = <span style="color: #2b91af;">String</span>.Concat(<span style="color: #a31515;">" "</span>, (<span style="color: blue;">char</span>)190);
} <span style="color: blue;">else</span> <span style="color: blue;">if</span>(months >= 5)
{
fract = <span style="color: #2b91af;">String</span>.Concat(<span style="color: #a31515;">" "</span>, (<span style="color: blue;">char</span>)189);
} <span style="color: blue;">else</span> <span style="color: blue;">if</span>(months >= 2)
{
fract = <span style="color: #2b91af;">String</span>.Concat(<span style="color: #a31515;">" "</span>, (<span style="color: blue;">char</span>)188);
} <span style="color: blue;">else</span>
{
fract = <span style="color: #a31515;">" years"</span>;
}
<span style="color: blue;">return</span> dSince.TotalYears + fract;
} <span style="color: blue;">else</span> <span style="color: blue;">if</span>(dSince.TotalMonths >= 6)
{
<span style="color: blue;">return</span> dSince.TotalMonths + <span style="color: #a31515;">" months"</span>;
} <span style="color: blue;">else</span> <span style="color: blue;">if</span>(dSince.TotalWeeks >= 2)
{
<span style="color: blue;">return</span> dSince.TotalWeeks + <span style="color: #a31515;">" weeks"</span>;
} <span style="color: blue;">else</span> <span style="color: blue;">if</span>(dSince.TotalDays >= 2)
{
<span style="color: blue;">return</span> dSince.TotalDays + <span style="color: #a31515;">" days"</span>;
} <span style="color: blue;">else</span>
{
<span style="color: blue;">return</span> <span style="color: #a31515;">"newborn"</span>;
}
}
}
<span style="font-family: "consolas"; font-size: 12.666666666666666;">}</span>
</div>
</code></pre>
It is very likely that any application with a requirement to process dates in the manner suggested here would need substantial code changes to match the working context. I may well return to this topic to explore the usage of dates stored as a range rather than as a single value.<br />
<br />
<b>Edited Jan 2017</b><br />
Added <a href="https://medium.com/samsung-internet-dev/making-input-type-date-complicated-a544fd27c45a#.pj57d93cq">this link to a great piece by Peter-Paul Koch</a> on "input type=date" and why that is (or is not) complicated even when user hostile. Well worth your time.</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-49355723727499088102016-08-05T09:07:00.000-07:002016-08-05T09:07:02.419-07:00A Persistent Queue with C#<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
This is just a bit of programming trivia.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
I wanted to run a queue of tasks each of which could take a
while to complete. Given that the program could be terminated before all tasks
had been run then I needed to store any remaining tasks until a later
opportunity to process them. Also I wanted to run the task queue on a
background thread and be able to add to the queue of tasks from the UI thread.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Fortunately .NET has an inbuilt <span style="color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">ConcurrentQueue</span><span style="font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"><</span><span style="color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">T</span><span style="font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">> </span>in<span style="font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">
System.Collections.Concurrent </span>that can be accessed from multiple threads without issue. All that
needed to be added was some code to persist uncompleted queue tasks. In the
code below I am using the .NET port of SQLite but a flat file would work fine
as would any other database.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
As I
was using a database I wanted to differentiate between queued tasks already in
the relevant table and any added from the UI thread. [Not of course forgetting
to delete tasks in the database that are completed.] So a little class to
represent a task – the task itself being just a string in this instance.<o:p></o:p><br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">class</span> <span style="color: #2b91af;">QueuedTask</span>
{
<span style="color: blue;">private</span> <span style="color: blue;">string</span> task;
<span style="color: blue;">private</span> <span style="color: blue;">bool</span> fromDatabase = <span style="color: blue;">false</span>;
<span style="color: blue;">public</span> QueuedTask(<span style="color: blue;">string</span> task)
{
<span style="color: blue;">this</span>.task = task;
}
<span style="color: blue;">public</span> QueuedTask(<span style="color: blue;">string</span> task, <span style="color: blue;">bool</span> fromDatabase)
{
<span style="color: blue;">this</span>.task = task;
<span style="color: blue;">this</span>.fromDatabase = fromDatabase;
}
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> InDatabase
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> fromDatabase; }
}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Task
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> task; }
}
}
</div>
</code></pre>
<div class="MsoNormal">
Creating an instance of my <span style="color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">PersistentQueue
</span>Class starts a timer that loads any saved tasks into the queue on
another thread so as not to block the UI thread.. The main program form
FormClosing() event calls the class SaveTasks() method that saves any remaining
tasks in the queue to the database.<o:p></o:p></div>
<div class="MsoNormal">
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">class</span> <span style="color: #2b91af;">PersistentQueue</span>
{
<span style="color: blue;">public</span> <span style="color: #2b91af;">ConcurrentQueue</span><<span style="color: #2b91af;">QueuedTask</span>> TaskQueue = <span style="color: blue;">new</span> <span style="color: #2b91af;">ConcurrentQueue</span><<span style="color: #2b91af;">QueuedTask</span>>();
<span style="color: blue;">private</span> <span style="color: blue;">string</span> dbPath = <span style="color: #a31515;">""</span>;
<span style="color: blue;">private</span> <span style="color: #2b91af;">Timer</span> readTimer = <span style="color: blue;">new</span> <span style="color: #2b91af;">Timer</span>();
<span style="color: blue;">private</span> <span style="color: blue;">const</span> <span style="color: blue;">int</span> startDelay = 10000;
<span style="color: blue;">public</span> PersistentQueue(<span style="color: blue;">string</span> dbPath)
{
<span style="color: blue;">this</span>.dbPath = dbPath;
readTimer.Interval = startDelay;
readTimer.Elapsed += (sender, e) => loadSavedTasks();
readTimer.Start();
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> SaveTasks()
{
readTimer.Close();
<span style="color: blue;">if</span> (!TaskQueue.IsEmpty)
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">SQLiteConnection</span> newCon = <span style="color: blue;">new</span> <span style="color: #2b91af;">SQLiteConnection</span>(dbPath);
newCon.Open();
<span style="color: #2b91af;">SQLiteCommand</span> mCommand = <span style="color: blue;">new</span> <span style="color: #2b91af;">SQLiteCommand</span>(<span style="color: #a31515;">"Insert Into Tasks (Task) Values(@Task)"</span>, newCon);
mCommand.Parameters.Add(<span style="color: blue;">new</span> <span style="color: #2b91af;">SQLiteParameter</span>(<span style="color: #a31515;">"@Task"</span>));
<span style="color: #2b91af;">QueuedTask</span> mTask;
<span style="color: blue;">while</span> (TaskQueue.TryDequeue(<span style="color: blue;">out</span> mTask))
{
<span style="color: blue;">if</span> (!mTask.InDatabase)
{
mCommand.Parameters[<span style="color: #a31515;">"@Task"</span>].Value = mTask.Task;
mCommand.ExecuteNonQuery();
}
}
mCommand.Dispose();
newCon.Close();
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ex)
{
}
}
}
<span style="color: blue;">private</span> <span style="color: blue;">async</span> <span style="color: blue;">void</span> loadSavedTasks()
{
readTimer.Stop();
<span style="color: blue;">await</span> <span style="color: #2b91af;">Task</span>.Run(() => loadTasks());
<span style="color: green;">// this is where you might start a new Timer to execute any tasks sitting</span>
<span style="color: green;">// in the queue - again using await Task.Run() and to periodically check the</span>
<span style="color: green;">// queue for new entries after the current queue has been emptied</span>
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> loadTasks()
{
<span style="color: blue;">try</span>
{
<span style="color: #2b91af;">SQLiteConnection</span> newCon = <span style="color: blue;">new</span> <span style="color: #2b91af;">SQLiteConnection</span>(dbPath);
newCon.Open();
<span style="color: #2b91af;">SQLiteCommand</span> mCommand = <span style="color: blue;">new</span> <span style="color: #2b91af;">SQLiteCommand</span>(<span style="color: #a31515;">"Select Task From Tasks"</span>, newCon);
<span style="color: #2b91af;">SQLiteDataReader</span> mReader = mCommand.ExecuteReader();
<span style="color: blue;">while</span> (mReader.Read())
{
TaskQueue.Enqueue(<span style="color: blue;">new</span> <span style="color: #2b91af;">QueuedTask</span>(<span style="color: #2b91af;">Convert</span>.ToString(mReader[0]), <span style="color: blue;">true</span>));
}
mReader.Close();
mCommand.Dispose();
newCon.Close();
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ex)
{
<span style="color: #2b91af;">LiteLog</span> myerror = <span style="color: blue;">new</span> <span style="color: #2b91af;">LiteLog</span>(<span style="color: #a31515;">"PersistentQueue.cs"</span>, <span style="color: #a31515;">"loadTasks"</span>, ex.Message);
myerror.UpdateClass();
}
}
}
</div>
</code></pre>
</div>
<div class="MsoNormal">
<br /></div>
</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-41441583271788216542016-08-04T10:03:00.000-07:002016-08-05T02:30:19.553-07:00Not a Porter Stemmer<div dir="ltr" style="text-align: left;" trbidi="on">
If you are considering indexing a sequence of text documents with a view to applying some sort of search facility then there is a lot to be said for <a href="https://en.wikipedia.org/wiki/Stemming">stemming</a>.<br />
<br />
Stemming is the process of reducing words to their stem or root such that related words are reduced to the same stem. The result may not be the true etymological stem – all stemming algorithms look for is consistency. The benefit is that searches based upon such stems can find references for related words and this reduces the pressure on search users to guess the optimal words or phrases for a given requirement.<br />
<br />
Some examples might be:<br />
<br />
caresses => caress<br />
ponies => poni<br />
cats => cat<br />
matting => mat<br />
meetings => meet<br />
<br />
Perhaps the best known stemming algorithm is the “<a href="http://tartarus.org/~martin/PorterStemmer/">Porter Stemmer</a>” by Martin Porter. This algorithm was “frozen” in the past and now new developments in such techniques are based upon the newer Snowball stemmer.<br />
<br />
C# Snowball* stemmers for a range of human languages can be found on<a href="https://stemmersnet.codeplex.com/"> Codeplex</a> with the warning that the code has been ported from Java (a brief review more or less confirmed that). Martin Porter’s stemming site presents his algorithm in a range of languages but again it is clear from the structure that the C# versions are translated.<br />
<br />
I took one of the C# Porter Stemmer versions and ran it against the 23,531 word test set and reassured by a perfect score decided to then “translate” the code into something just a little easier to follow and possibly tweak. Now my version (presented below) is not a Porter Stemmer as the output varies from the standard for a handful of words (I just have to mess with things).<br />
<br />
I preferred:<br />
advertise, advertised and advertising being stemmed to advert rather than advertis<br />
merchandise becomes merchand and not merchandis<br />
etc.<br />
<br />
You probably get the picture – I have treated “ise” the same as “ize” (which works better in GB English I think) but it would not take anyone 5 minutes to undo if you wanted to be a purist but alternately you might fancy tweaking things further.<br />
<br />
The code presented here is almost certainly much slower than the original but it is way easier to follow and debug. I have also added a cache so that words previously stemmed can be retrieved without re-processing although I will have to watch cache growth if the process is long running.<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"><summary></span>
<span style="color: grey;">///</span><span style="color: green;"> AditStemmer is a stemmer algorithm based upon the Porter stemmer algorithm </span>
<span style="color: grey;">///</span><span style="color: green;"> but has some slight but deliberate differences in output</span>
<span style="color: grey;">///</span><span style="color: green;"> see http://tartarus.org/~martin/PorterStemmer/ for more details and test data</span>
<span style="color: grey;">///</span><span style="color: green;"> This software is completely free for any purpose but is not warrented to be defect free</span>
<span style="color: grey;">///</span><span style="color: green;"> </span><span style="color: grey;"></summary></span>
<span style="color: blue;">class</span> <span style="color: #2b91af;">AditStemmer</span>
{
<span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">string</span>> cache = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">string</span>>(); <span style="color: green;">// could initialise this to avoid known issues (eg universal, university, universe)</span>
<span style="color: blue;">public</span> <span style="color: blue;">string</span> stemWord(<span style="color: blue;">string</span> word)
{
<span style="color: blue;">string</span> stemWord;
<span style="color: blue;">if</span> (!cache.TryGetValue(word, <span style="color: blue;">out</span> stemWord))
{
stemWord = tryStem(word);
cache.Add(word, stemWord);
}
<span style="color: blue;">return</span> stemWord;
}
<span style="color: blue;">private</span> <span style="color: blue;">string</span> tryStem(<span style="color: blue;">string</span> word)
{
<span style="color: blue;">if</span> (word.Length > 2)
{
<span style="color: green;">// following the steps of giants - step 1 remove plurals, -ed, -ing</span>
word = step1(word);
word = step2(word);
word = step3(word);
word = step4(word);
word = step5(word);
word = step6(word);
}
<span style="color: blue;">return</span> word;
}
<span style="color: blue;">private</span> <span style="color: blue;">string</span> step1(<span style="color: blue;">string</span> word)
{
<span style="color: blue;">int</span> wordLen = word.Length;
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"s"</span>))
{
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"sses"</span>) || word.EndsWith(<span style="color: #a31515;">"ies"</span>))
{
wordLen -= 2;
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (!word.EndsWith(<span style="color: #a31515;">"ss"</span>))
{
wordLen--;
}
word = word.Substring(0, wordLen);
}
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"eed"</span>))
{
<span style="color: blue;">if</span> (countConsonants(word, wordLen - 1) > 0)
{
wordLen--;
}
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">if</span> ((word.EndsWith(<span style="color: #a31515;">"ed"</span>) && hasVowelInStem(word, wordLen - 2)) || (word.EndsWith(<span style="color: #a31515;">"ing"</span>) && hasVowelInStem(word, wordLen - 3)))
{
<span style="color: blue;">int</span> checkTo = wordLen - (word.EndsWith(<span style="color: #a31515;">"ed"</span>) ? 2 : 3);
<span style="color: blue;">string</span> stem = word.Substring(0, checkTo);
<span style="color: blue;">if</span> (stem.EndsWith(<span style="color: #a31515;">"at"</span>) || stem.EndsWith(<span style="color: #a31515;">"bl"</span>) || stem.EndsWith(<span style="color: #a31515;">"iz"</span>) || stem.EndsWith(<span style="color: #a31515;">"is"</span>))
{
word = stem + <span style="color: #a31515;">"e"</span>;
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (isDoubleCon(word, checkTo - 1))
{
<span style="color: blue;">if</span> (!(stem.EndsWith(<span style="color: #a31515;">"l"</span>) || stem.EndsWith(<span style="color: #a31515;">"s"</span>) || stem.EndsWith(<span style="color: #a31515;">"z"</span>)))
{
word = stem.Substring(0, checkTo - 1);
}
<span style="color: blue;">else</span> { word = stem; }
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (countConsonants(word, checkTo) == 1 && isConVowCon(word, checkTo - 1))
{
word = stem + <span style="color: #a31515;">"e"</span>;
}
<span style="color: blue;">else</span>
{
word = stem;
}
wordLen = word.Length;
}
}
<span style="color: blue;">return</span> word.Substring(0, wordLen);
}
<span style="color: blue;">private</span> <span style="color: blue;">string</span> step2(<span style="color: blue;">string</span> word)
{
<span style="color: green;">// not too exciting just changes y to i if another vowel in the stem - but that comes in useful later</span>
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"y"</span>) && hasVowelInStem(word, word.Length - 1))
{
word = word.Substring(0, word.Length - 1) + <span style="color: #a31515;">"i"</span>;
}
<span style="color: blue;">return</span> word;
}
<span style="color: blue;">private</span> <span style="color: blue;">string</span> step3(<span style="color: blue;">string</span> word)
{
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ational"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ational"</span>, <span style="color: #a31515;">"ate"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"tional"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"tional"</span>, <span style="color: #a31515;">"tion"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"enci"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"enci"</span>, <span style="color: #a31515;">"ence"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"anci"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"anci"</span>, <span style="color: #a31515;">"ance"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"izer"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"izer"</span>, <span style="color: #a31515;">"ize"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"bli"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"bli"</span>, <span style="color: #a31515;">"ble"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"alli"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"alli"</span>, <span style="color: #a31515;">"al"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"entli"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"entli"</span>, <span style="color: #a31515;">"ent"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"eli"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"eli"</span>, <span style="color: #a31515;">"e"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ousli"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ousli"</span>, <span style="color: #a31515;">"ous"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ization"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ization"</span>, <span style="color: #a31515;">"ize"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"isation"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"isation"</span>, <span style="color: #a31515;">"ize"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ation"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ation"</span>, <span style="color: #a31515;">"ate"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ator"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ator"</span>, <span style="color: #a31515;">"ate"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"alism"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"alism"</span>, <span style="color: #a31515;">"al"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"iveness"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"iveness"</span>, <span style="color: #a31515;">"ive"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"fulness"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"fulness"</span>, <span style="color: #a31515;">"ful"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ousness"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ousness"</span>, <span style="color: #a31515;">"ous"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"aliti"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"aliti"</span>, <span style="color: #a31515;">"al"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"iviti"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"iviti"</span>, <span style="color: #a31515;">"ive"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"biliti"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"biliti"</span>, <span style="color: #a31515;">"ble"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"logi"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"logi"</span>, <span style="color: #a31515;">"log"</span>); }
<span style="color: blue;">return</span> word;
}
<span style="color: blue;">private</span> <span style="color: blue;">string</span> step4(<span style="color: blue;">string</span> word)
{
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"icate"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"icate"</span>, <span style="color: #a31515;">"ic"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ative"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ative"</span>, <span style="color: #a31515;">""</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"alize"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"alize"</span>, <span style="color: #a31515;">"al"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"alise"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"alise"</span>, <span style="color: #a31515;">"al"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"iciti"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"iciti"</span>, <span style="color: #a31515;">"ic"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ical"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ical"</span>, <span style="color: #a31515;">"ic"</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ful"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ful"</span>, <span style="color: #a31515;">""</span>); }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ness"</span>)) { <span style="color: blue;">return</span> conditionalReplace(word, <span style="color: #a31515;">"ness"</span>, <span style="color: #a31515;">""</span>); }
<span style="color: blue;">return</span> word;
}
<span style="color: blue;">private</span> <span style="color: blue;">string</span> step5(<span style="color: blue;">string</span> word)
{
<span style="color: blue;">int</span> truncAt = word.Length;
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"al"</span>)) { truncAt -= 2; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ance"</span>) || word.EndsWith(<span style="color: #a31515;">"ence"</span>)) { truncAt -= 4; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"er"</span>)) { truncAt -= 2; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ic"</span>)) { truncAt -= 2; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"able"</span>) || word.EndsWith(<span style="color: #a31515;">"ible"</span>)) { truncAt -= 4; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ant"</span>)) { truncAt -= 3; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ement"</span>))
{
truncAt -= 5;
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ment"</span>))
{
truncAt -= 4;
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ent"</span>))
{
truncAt -= 3;
}
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ion"</span>) && word.Length > 4)
{
<span style="color: blue;">if</span> (word.ElementAt(word.Length - 4) == <span style="color: #a31515;">'t'</span> || word.ElementAt(word.Length - 4) == <span style="color: #a31515;">'s'</span>)
{
truncAt -= 3;
}
}
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ou"</span>)) { truncAt -= 2; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ism"</span>)) { truncAt -= 3; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ate"</span>)) { truncAt -= 3; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"iti"</span>)) { truncAt -= 3; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ous"</span>)) { truncAt -= 3; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ive"</span>)) { truncAt -= 3; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ize"</span>)) { truncAt -= 3; }
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ise"</span>)) { truncAt -= 3; }
<span style="color: blue;">if</span> (countConsonants(word, truncAt) > 1)
{
word = word.Substring(0, truncAt);
}
<span style="color: blue;">return</span> word;
}
<span style="color: blue;">private</span> <span style="color: blue;">string</span> step6(<span style="color: blue;">string</span> word)
{
<span style="color: green;">// mostly removes trailing e</span>
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"e"</span>))
{
<span style="color: blue;">int</span> cCount = countConsonants(word, word.Length - 1);
<span style="color: blue;">if</span> (cCount > 1 || cCount == 1 && !isConVowCon(word, word.Length - 2))
{
word = word.Substring(0, word.Length - 1);
}
}
<span style="color: green;">// reduces ll to l where appropriate</span>
<span style="color: blue;">if</span> (word.EndsWith(<span style="color: #a31515;">"ll"</span>) && countConsonants(word, word.Length - 1) > 1)
{
word = word.Substring(0, word.Length - 1);
}
<span style="color: blue;">return</span> word;
}
<span style="color: blue;">private</span> <span style="color: blue;">string</span> conditionalReplace(<span style="color: blue;">string</span> word, <span style="color: blue;">string</span> replace, <span style="color: blue;">string</span> with)
{
<span style="color: green;">// the condition is that there is at least one preceeding consonant sequence</span>
<span style="color: blue;">int</span> stemLength = word.Length - replace.Length;
<span style="color: blue;">if</span> (countConsonants(word, stemLength) > 0)
{
word = word.Substring(0, stemLength) + with;
}
<span style="color: blue;">return</span> word;
}
<span style="color: blue;">private</span> <span style="color: blue;">int</span> countConsonants(<span style="color: blue;">string</span> word, <span style="color: blue;">int</span> to)
{
<span style="color: green;">//counts sequences of consonants before to but after any initial consonant sequence</span>
<span style="color: blue;">int</span> cCount = 0;
<span style="color: blue;">bool</span> wasVowel = <span style="color: blue;">false</span>;
<span style="color: blue;">for</span> (<span style="color: blue;">var</span> ci = 0; ci < to; ci++)
{
<span style="color: blue;">if</span> (hasConsonantAt(word, ci))
{
<span style="color: blue;">if</span> (wasVowel)
{
wasVowel = <span style="color: blue;">false</span>;
cCount++;
}
}
<span style="color: blue;">else</span>
{
wasVowel = <span style="color: blue;">true</span>;
}
}
<span style="color: blue;">return</span> cCount;
}
<span style="color: blue;">private</span> <span style="color: blue;">bool</span> isDoubleCon(<span style="color: blue;">string</span> word, <span style="color: blue;">int</span> at)
{
<span style="color: green;">// is double consonant</span>
<span style="color: blue;">if</span> (at < 1) { <span style="color: blue;">return</span> <span style="color: blue;">false</span>; }
<span style="color: blue;">if</span> (word.ElementAt(at) != word.ElementAt(at - 1))
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
<span style="color: blue;">return</span> hasConsonantAt(word, at);
}
<span style="color: blue;">private</span> <span style="color: blue;">bool</span> isConVowCon(<span style="color: blue;">string</span> word, <span style="color: blue;">int</span> to)
{
<span style="color: green;">/* is true <=> i-2,i-1,i has the form consonant - vowel - consonant</span>
<span style="color: green;"> and also if the second c is not w,x or y. this is used when trying to</span>
<span style="color: green;"> restore an e at the end of a short word. e.g.</span>
<span style="color: green;"> cav(e), lov(e), hop(e), crim(e), but</span>
<span style="color: green;"> snow, box, tray.</span>
<span style="color: green;"> */</span>
<span style="color: blue;">if</span> (to < 2 || !hasConsonantAt(word, to) || hasConsonantAt(word, to - 1) || !hasConsonantAt(word, to - 2))
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
<span style="color: blue;">if</span> (word.ElementAt(to) == <span style="color: #a31515;">'w'</span> || word.ElementAt(to) == <span style="color: #a31515;">'x'</span> || word.ElementAt(to) == <span style="color: #a31515;">'y'</span>)
{
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
<span style="color: blue;">return</span> <span style="color: blue;">true</span>;
}
<span style="color: blue;">private</span> <span style="color: blue;">bool</span> hasVowelInStem(<span style="color: blue;">string</span> word, <span style="color: blue;">int</span> to)
{
<span style="color: blue;">for</span> (<span style="color: blue;">var</span> vi = 0; vi < to; vi++)
{
<span style="color: blue;">if</span> (!hasConsonantAt(word, vi))
{
<span style="color: blue;">return</span> <span style="color: blue;">true</span>;
}
}
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
}
<span style="color: blue;">private</span> <span style="color: blue;">bool</span> hasConsonantAt(<span style="color: blue;">string</span> word, <span style="color: blue;">int</span> at)
{
<span style="color: blue;">switch</span> (word.ElementAt(at))
{
<span style="color: blue;">case</span> <span style="color: #a31515;">'a'</span>:
<span style="color: blue;">case</span> <span style="color: #a31515;">'e'</span>:
<span style="color: blue;">case</span> <span style="color: #a31515;">'i'</span>:
<span style="color: blue;">case</span> <span style="color: #a31515;">'o'</span>:
<span style="color: blue;">case</span> <span style="color: #a31515;">'u'</span>:
<span style="color: blue;">return</span> <span style="color: blue;">false</span>;
<span style="color: blue;">case</span> <span style="color: #a31515;">'y'</span>:
<span style="color: blue;">return</span> (at == 0) ? <span style="color: blue;">true</span> : !hasConsonantAt(word, at - 1); <span style="color: green;">// y can act as consonant and vowel</span>
<span style="color: blue;">default</span>:
<span style="color: blue;">return</span> <span style="color: blue;">true</span>;
}
}
<span style="font-family: "consolas"; font-size: 12.666666666666666;">}</span>
</div>
</code></pre>
<br />
*More details of the Snowball algorithm can be found here <a href="http://snowball.tartarus.org/">http://snowball.tartarus.org/</a><br />
<div>
<br />
<Edit>Fixed the colour errors in the demo code. The cause (something to do with text size) is under investigation</Edit></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-828759952541741322016-07-21T07:33:00.001-07:002016-07-21T07:33:20.238-07:00.NET Reflection bug<div dir="ltr" style="text-align: left;" trbidi="on">
Had a fun bug with an app the other day. I had been leaving the app to run for a long time so I could monitor memory usage to check for any possible leaks. But the following bug was reported after a couple of hours:<br />
<br />
“target invocation exception” in System.Reflection<br />
<br />
at the following line<br />
<br />
<div class="MsoNormal">
<span style="color: blue; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-bidi-font-family: Consolas;">this</span><span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;">.Icon = ((System.Drawing.</span><span style="color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-bidi-font-family: Consolas;">Icon</span><span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;">)(resources.GetObject(</span><span style="color: #a31515; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-bidi-font-family: Consolas;">"$this.Icon"</span><span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;">)));<o:p></o:p></span></div>
<br />
but that line was in the form.designer.cs generated by Visual Studio and you would assume that this code was only executed when the form was first rendered.<br />
<br />
I was potentially fighting an abstraction then – <a href="http://www.joelonsoftware.com/articles/LeakyAbstractions.html">clearly one that had leaked</a><br />
<br />
Then I remembered that the program updated the task bar icon to alert its user to potentially new and interesting occurrences. I had made sense at the time of writing to make use of the icon stored as a resource associated with the form. The image was retrieved using:<br />
<br />
<div class="MsoNormal">
<span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;">Bitmap b = this.Icon.ToBitmap();<o:p></o:p></span></div>
<br />
then decorated and set as a revised taskbar icon – which is (of course) also the current form icon which just might give some insight into what was going wrong or at least a faint hint.<br />
<br />
The icon file itself was properly formatted and contained 16x16 and 32x32 pixel bitmaps but it was clear that somewhere along the line and after several successful invocations in each instance something went wrong in mscorlib and the debug facility in Visual Studio pinned the problem back on the partial (designer) class for the form.<br />
<br />
A couple of solutions came to mind but I went with embedding a 32x32 .png image as an additional assembly resource and retrieving that when it was required. So far, that has yet to fail but yes, there is a small memory leak somewhere so I am not finished yet. Testing and modifying programs designed to run continuously for extended periods within a Windows environment can be a challenge. </div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-32414802438230736272016-05-12T06:20:00.000-07:002016-12-22T08:23:16.926-08:00Drag and Drop<div dir="ltr" style="text-align: left;" trbidi="on">
Drag and Drop is one of the fundamental building blocks of a modern GUI. It is so fundamental it is easy to overlook the potential for enhancement. There are lots of code fragments about if you look for enhancing the basics but most explanations seem a bit partial – hence this tutorial that I hope covers the wider ground.<br />
<br />
Starting with the basic default process and a simple (but perhaps unlikely) example.<br />
<br />
Consider a Label with some text that you might want to drag into a text box to edit. The TextBox has the AllowDrop attribute set to true. The drag process starts with a mouse down event on the label so we need some code to start the DragDrop process.<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: blue;">void</span> label1_MouseDown(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">MouseEventArgs</span> e)
{
DoDragDrop(label1.Text, <span style="color: #2b91af;">DragDropEffects</span>.Copy);
}
</div>
</code></pre>
<div>
<br />
The DoDragDrop method has been passed the label Text property as the data and the DragDropEffects value of Copy set to indicate the intention of the process. The main values are Copy, Link and Move with additional values of Scroll, None and All (multiple values can be combined with the Or operator) . The data can be supplied as an object and in this instance is a string.<br />
<br />
Our target Textbox needs to handle two events, DragEnter and DragDrop.<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: blue;">void</span> textBox1_DragEnter(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">DragEventArgs</span> e)
{
<span style="color: blue;">if</span> (e.Data.GetDataPresent(<span style="color: #2b91af;">DataFormats</span>.Text))
{
e.Effect = <span style="color: #2b91af;">DragDropEffects</span>.Copy;
}
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> textBox1_DragDrop(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">DragEventArgs</span> e)
{
textBox1.Text += e.Data.GetData(<span style="color: #2b91af;">DataFormats</span>.Text);
}
</div>
</code></pre>
<br />
That’s all that is required for this basic example. The drag drop process gets the default visual feedback effects and a drop onto the TextBox copies and adds the Label Text to the TextBox Text.<br />
<br />
Now let us consider a more complex scenario. I might have multiple objects that could be dragged and dropped on the same page. It could also be true that things might be dragged with multiple potential purposes – I might be implicitly copying the content if I dropped it at one location but simply moving the content about within another screen area. The user needs feedback on the impact of a drop event at different locations – this makes a case for custom cursors. It is also important that the control receiving the “drop” knows the drag source as this might influence that drop action and certainly identifies the unique “content”.<br />
<br />
As the DoDragDrop method accepts type “object” as the data source we could rewrite the code from above to use the Label (or any other) control itself:<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: blue;">void</span> label1_MouseDown(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">MouseEventArgs</span> e)
{
DoDragDrop(label1, <span style="color: #2b91af;">DragDropEffects</span>.Copy);
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> textBox1_DragEnter(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">DragEventArgs</span> e)
{
<span style="color: blue;">if</span> (e.Data.GetDataPresent(label1.GetType()))
{
e.Effect = <span style="color: #2b91af;">DragDropEffects</span>.Copy;
}
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> textBox1_DragDrop(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">DragEventArgs</span> e)
{
textBox1.Text += ((<span style="color: blue;">dynamic</span>)e.Data.GetData(label1.GetType())).Text;
}
</div>
</code></pre>
<div>
<br /></div>
but this approach is somewhat limited as it would mean writing specific code for each individual data source.<br />
<br />
The <a href="https://msdn.microsoft.com/en-us/library/system.windows.dataformats(v=vs.110).aspx">DataFormats class</a> has a long list of predefined fields ranging from Bitmap through Text (as we have seen) and includes useful types like XAML. This list of DataFormats is the same list as is used by the Windows Copy/Paste functionality and it is perfectly straightforward to add additional types to that list.<br />
<br />
The code below declares a new custom DataFormat and then uses that DataFormat identity to store an instance of a class in a DataObject and then passes that DataObject through the Drag and Drop process to the target control. The code can thus support multiple instances of said class generically.<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">DataFormats</span>.<span style="color: #2b91af;">Format</span> cardFormat = <span style="color: #2b91af;">DataFormats</span>.GetFormat(<span style="color: #a31515;">"CCard"</span>);
<span style="color: blue;">private</span> <span style="color: blue;">void</span> label1_MouseDown(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">MouseEventArgs</span> e)
{
<span style="color: #2b91af;">CCard</span> mCard = <span style="color: blue;">new</span> <span style="color: #2b91af;">CCard</span>(); <span style="color: green;">// create a class instance</span>
mCard.CardTitle = <span style="color: #a31515;">"New Card Title"</span>; <span style="color: green;">// set a property value</span>
<span style="color: #2b91af;">DataObject</span> mDataObject = <span style="color: blue;">new</span> <span style="color: #2b91af;">DataObject</span>(cardFormat.Name, mCard);
DoDragDrop(mDataObject, <span style="color: #2b91af;">DragDropEffects</span>.Copy);
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> textBox1_DragEnter(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">DragEventArgs</span> e)
{
<span style="color: blue;">if</span> (e.Data.GetDataPresent(cardFormat.Name))
{
e.Effect = <span style="color: #2b91af;">DragDropEffects</span>.Copy;
}
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> textBox1_DragDrop(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">DragEventArgs</span> e)
{
<span style="color: #2b91af;">CCard</span> cCard = (<span style="color: #2b91af;">CCard</span>)e.Data.GetData(cardFormat.Name); <span style="color: green;">// retrieve the class</span><span style="color: green;"> instance</span>
textBox1.Text += cCard.CardTitle; <span style="color: green;">// and use one or more proprty values</span>
}
</div>
</code></pre>
<br />
In our more complex scenario, each data source type might be represented by a specific class and then each data source instance would simply supply an instance of the relevant class. The DragDrop targets can inspect the DataFormat to decide upon the relevant Effect for that DataFormat and the Drop event can process the given class instance where appropriate.<br />
<br />
As that may not be the clearest explanation it would probably help to have some demo code. First though I want to look at custom Cursors.<br />
<br />
My custom Cursor creation functions are encapsulated within a utility class<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">namespace</span> Adit.Classes
{
<span style="color: blue;">public</span> <span style="color: blue;">struct</span> <span style="color: #2b91af;">IconInfo</span>
{
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> fIcon;
<span style="color: blue;">public</span> <span style="color: blue;">int</span> xHotspot;
<span style="color: blue;">public</span> <span style="color: blue;">int</span> yHotspot;
<span style="color: blue;">public</span> <span style="color: #2b91af;">IntPtr</span> hbmMask;
<span style="color: blue;">public</span> <span style="color: #2b91af;">IntPtr</span> hbmColor;
}
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">CursorUtil</span>
{
[<span style="color: #2b91af;">DllImport</span>(<span style="color: #a31515;">"user32.dll"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">extern</span> <span style="color: #2b91af;">IntPtr</span> CreateIconIndirect(<span style="color: blue;">ref</span> <span style="color: #2b91af;">IconInfo</span> icon);
[<span style="color: #2b91af;">DllImport</span>(<span style="color: #a31515;">"user32.dll"</span>)]
[<span style="color: blue;">return</span>: <span style="color: #2b91af;">MarshalAs</span>(<span style="color: #2b91af;">UnmanagedType</span>.Bool)]
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">extern</span> <span style="color: blue;">bool</span> GetIconInfo(<span style="color: #2b91af;">IntPtr</span> hIcon, <span style="color: blue;">ref</span> <span style="color: #2b91af;">IconInfo</span> pIconInfo);
[<span style="color: #2b91af;">DllImport</span>(<span style="color: #a31515;">"gdi32.dll"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">extern</span> <span style="color: blue;">bool</span> DeleteObject(<span style="color: #2b91af;">IntPtr</span> handle);
[<span style="color: #2b91af;">DllImport</span>(<span style="color: #a31515;">"user32.dll"</span>, CharSet = <span style="color: #2b91af;">CharSet</span>.Auto)]
<span style="color: blue;">extern</span> <span style="color: blue;">static</span> <span style="color: blue;">bool</span> DestroyIcon(<span style="color: #2b91af;">IntPtr</span> handle);
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">Cursor</span> CreateCursor(<span style="color: #2b91af;">Bitmap</span> bm, <span style="color: blue;">int</span> xHotspot, <span style="color: blue;">int</span> yHotspot, <span style="color: blue;">bool</span> resize = <span style="color: blue;">true</span>)
{
<span style="color: #2b91af;">IntPtr</span> ptr = (resize) ? ((<span style="color: #2b91af;">Bitmap</span>)ResizeBitmap(bm, 32, 32)).GetHicon() : bm.GetHicon();
<span style="color: #2b91af;">IconInfo</span> inf = <span style="color: blue;">new</span> <span style="color: #2b91af;">IconInfo</span>();
GetIconInfo(ptr, <span style="color: blue;">ref</span> inf);
inf.xHotspot = xHotspot;
inf.yHotspot = yHotspot;
inf.fIcon = <span style="color: blue;">false</span>;
<span style="color: #2b91af;">IntPtr</span> cursorPtr = CreateIconIndirect(<span style="color: blue;">ref</span> inf);
<span style="color: blue;">if</span> (inf.hbmColor != <span style="color: #2b91af;">IntPtr</span>.Zero) { DeleteObject(inf.hbmColor); }
<span style="color: blue;">if</span> (inf.hbmMask != <span style="color: #2b91af;">IntPtr</span>.Zero) { DeleteObject(inf.hbmMask); }
<span style="color: blue;">if</span> (ptr != <span style="color: #2b91af;">IntPtr</span>.Zero) { DestroyIcon(ptr); }
<span style="color: #2b91af;">Cursor</span> c = <span style="color: blue;">new</span> <span style="color: #2b91af;">Cursor</span>(cursorPtr);
c.Tag = (resize) ? <span style="color: blue;">new</span> <span style="color: #2b91af;">Size</span>(32, 32) : bm.Size;
<span style="color: blue;">return</span> c;
}
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">Bitmap</span> ResizeBitmap(<span style="color: #2b91af;">Image</span> image, <span style="color: blue;">int</span> maxWidth, <span style="color: blue;">int</span> maxHeight)
{
<span style="color: blue;">double</span> ratio = System.<span style="color: #2b91af;">Math</span>.Min((<span style="color: blue;">double</span>)maxHeight / image.Height, (<span style="color: blue;">double</span>)maxWidth / image.Width);
<span style="color: blue;">var</span> propWidth = (<span style="color: blue;">int</span>)(image.Width * ratio);
<span style="color: blue;">var</span> propHeight = (<span style="color: blue;">int</span>)(image.Height * ratio);
<span style="color: blue;">var</span> newImage = <span style="color: blue;">new</span> <span style="color: #2b91af;">Bitmap</span>(propWidth, propHeight);
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> g = <span style="color: #2b91af;">Graphics</span>.FromImage(newImage))
{
g.DrawImage(image, 0, 0, propWidth, propHeight);
}
<span style="color: blue;">return</span> newImage;
}
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">Bitmap</span> GetControlBitmap(<span style="color: #2b91af;">Control</span> c, <span style="color: #2b91af;">Color</span> transparent)
{
<span style="color: blue;">var</span> bm = <span style="color: blue;">new</span> <span style="color: #2b91af;">Bitmap</span>(c.Width, c.Height);
c.DrawToBitmap(bm, <span style="color: blue;">new</span> <span style="color: #2b91af;">Rectangle</span>(0, 0, c.Width, c.Height));
<span style="color: blue;">if</span> (transparent != <span style="color: blue;">null</span>)
{
bm.MakeTransparent(transparent);
}
<span style="color: blue;">return</span> bm;
}
<span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">Bitmap</span> OverlayBitmap(<span style="color: #2b91af;">Bitmap</span> baseBitmap, <span style="color: #2b91af;">Bitmap</span> overlay, <span style="color: #2b91af;">Point</span> atPosition)
{
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> g = <span style="color: #2b91af;">Graphics</span>.FromImage(baseBitmap))
{
g.DrawImage(overlay, <span style="color: blue;">new</span> <span style="color: #2b91af;">Rectangle</span>(atPosition, overlay.Size));
}
<span style="color: blue;">return</span> baseBitmap;
}
}
}
</div>
</code></pre>
<br />
I have used these functions to create cursors from 96x96 pixel .png files (some originally sourced from the <a href="https://design.google.com/icons/">Material Icons download page</a>). I have also used the GetControlBitmap function to create a Cursor from a Bitmap displaying a copy of a control captured at run-time.<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">Cursor</span>[] cursors = <span style="color: blue;">new</span> <span style="color: #2b91af;">Cursor</span>[4];
<span style="color: green;">//later</span>
cursors[0] = <span style="color: #2b91af;">CursorUtil</span>.CreateCursor((<span style="color: #2b91af;">Bitmap</span>)imageList1.Images[2], 0, 0);
<span style="color: green;">//and</span>
cursors[2] = <span style="color: #2b91af;">CursorUtil</span>.CreateCursor(<span style="color: #2b91af;">CursorUtil</span>.GetControlBitmap(label1, <span style="color: #2b91af;">SystemColors</span>.Control), 0, 0, <span style="color: blue;">false</span>);
</div>
</code></pre>
<br />
Important thing is, we can easily create custom Cursors from bitmaps ready to apply during our Drag and Drop.<br />
<br />
Just one quick aside though, the cursor "hot-spot" does not have to be at position 0,0 as in the above examples. Think of (say) the Paint.NET flood-fill or Color-Picker cursors where the hot-spot is marked by a cross or is at the tip of the "eye dropper". You might want to use something like my OverlayBitmap() function to add a suitable symbol to a control image and set the hot-spot to the relevant position in the final image.<br />
<br />
OK - one other aside. My cursor building function adds the image size to the Tag property. You might wonder why. If you create a custom cursor (say) from a control image you might be surprised to find that the resulting cursor Size attribute will always return 32,32 (or just possibly 64,64) and not the actual size of the cursor. You can access (say) the true Width of a cursor via the Tag property with code something like:<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue; font-family: "consolas"; font-size: 12.666666666666666;">int</span><span style="font-family: "consolas"; font-size: 12.666666666666666;"> cWidth = ((</span><span style="color: blue; font-family: "consolas"; font-size: 12.666666666666666;">dynamic</span><span style="font-family: "consolas"; font-size: 12.666666666666666;">)</span><span style="font-family: "consolas"; font-size: 12.666666666666666;">myCursor.</span><span style="font-family: "consolas"; font-size: 12.666666666666666;">Tag).Width;</span>
</div>
</code></pre>
<br />
We can apply our custom cursors in a GiveFeedback event handler. so first we might create custom Cursors for Copy and None and then apply them in a function<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">Cursor</span> myCopyCursor, myNoneCursor;
myCopyCursor = <span style="color: #2b91af;">CursorUtil</span>.CreateCursor((<span style="color: #2b91af;">Bitmap</span>)imageList1.Images[2], 0, 0);
myNoneCursor = <span style="color: #2b91af;">CursorUtil</span>.CreateCursor((<span style="color: #2b91af;">Bitmap</span>)imageList1.Images[3], 0, 0);
<span style="color: blue;">private</span> <span style="color: blue;">void</span> giveFeedback(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">GiveFeedbackEventArgs</span> e)
{
<span style="color: blue;">if</span>(e.Effect == <span style="color: #2b91af;">DragDropEffects</span>.Copy)
{
e.UseDefaultCursors = <span style="color: blue;">false</span>;
<span style="color: #2b91af;">Cursor</span>.Current = myCopyCursor;
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span>(e.Effect == <span style="color: #2b91af;">DragDropEffects</span>.None)
{
e.UseDefaultCursors = <span style="color: blue;">false</span>;
<span style="color: #2b91af;">Cursor</span>.Current = myNoneCursor;
}
}
</div>
</code></pre>
We add the giveFeedback() function to the GiveFeedback event of the Form - perhaps during the form Load()<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">this</span>.GiveFeedback += giveFeedback;
</div>
</code></pre>
<br />
and then slightly counter-intuitively set the AllowDrop property to true for the form and <b>all</b> controls over which you anticipate the user might drag. This does not allow a drop to occur at these sites (that requires code to handle DragEnter and DragDrop but it does allow any relevant custom Cursor to be displayed during any drag over the form and control surfaces.<br />
<br />
A point worth noting is that DragDrop event arguments include X/Y coordinates and these are screen co-ordinates as drags are not restricted to the originating window. Drag/Drop is a key element of OLE (Object Linking and Embedding). This can make using those conveniently presented values slightly tricky when managing things like local scrolling under program control. Which brings me nicely to my demo application (<a href="https://github.com/MikeGWem/DragDropDemo">zipped as a Visual Studio 2015 project ready to download</a>) that manages just that.<br />
<br />
First off, this is demo and not production code and thus likely to include bugs, ignore edge cases, certainly takes shortcuts, is unduly verbose in places and might totally fail to explain some key point you are interested in. However it might provide a platform that can be used to try out alternate scenarios and approaches without having to build the whole thing from scratch.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHXblQXeN1WXldgHPIY7cTKjyjXakjGH6fNHmR01DpEdkIxhQuJd2ohsmiMuoh5Q0ytCUrWyPTs-QMlpDEATfNQWhjnn1TuiUtQeSSRNzJLGcLsh1ZSDr78ebpO4R0QUOtGehsog/s1600/DragDropDemo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="262" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHXblQXeN1WXldgHPIY7cTKjyjXakjGH6fNHmR01DpEdkIxhQuJd2ohsmiMuoh5Q0ytCUrWyPTs-QMlpDEATfNQWhjnn1TuiUtQeSSRNzJLGcLsh1ZSDr78ebpO4R0QUOtGehsog/s320/DragDropDemo.png" width="320" /></a></div>
<br />
Here you can see a screen image from the demo program. Addresses can be entered in the mini form on the left of the window and dragged onto the FlowLayoutPanel on the right that is acting as an "address store". To save energy, the "Fill" button will populate the form with up to 50 addresses taken randomly from an embedded list.<br />
<br />
Addresses in the right hand panel can be dragged back to the address entry form for editing. Addresses can also be dragged up and down the list to reorder them.<br />
<br />
We thus have two sorts of object that can be dragged for (is it) three different purposes. Some simple custom icons are created and used during the drag events.<br />
<br />
The demo features loading data from an embedded resource (.csv file) using the Visual Basic TextFieldParser class (don't panic this is C# demo code). There are two custom DataFormats declared and used in the Drag operations. The addresses in the notional "address store" are encapsulated within multiple UserControls and these controls use Delegates to communicate with the Form. Dragging an address within the FlowLayoutPanel will trigger an automatic scroll when the scroll bar is active and the drag nears the top or bottom of the panel..<br />
<br />
Exercises for further study might include using an image of an AddressControl as a cursor and/or dragging new addresses to a specific location in the FlowLayoutPanel instead of just adding them at the bottom irrespective of the drop location.<br />
<br />
An analysis of the code will note that the demo "cheats" when determining the target location of a move within the FlowLayoutPanel and that it is possible to dodge around one or more address and expose the bug.<br />
<br />
Inspect or download the demo code at <a href="https://github.com/MikeGWem/DragDropDemo">https://github.com/MikeGWem/DragDropDemo</a><br />
<br />
If anyone knows or finds out what <span class="typ" style="background-color: #eff0f1; border: 0px; color: #2b91af; font-family: "consolas" , "menlo" , "monaco" , "lucida console" , "liberation mono" , "dejavu sans mono" , "bitstream vera sans mono" , "courier new" , monospace , sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">DragDropEffects</span><span class="pun" style="background-color: #eff0f1; border: 0px; color: #303336; font-family: "consolas" , "menlo" , "monaco" , "lucida console" , "liberation mono" , "dejavu sans mono" , "bitstream vera sans mono" , "courier new" , monospace , sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">.</span><span class="typ" style="background-color: #eff0f1; border: 0px; color: #2b91af; font-family: "consolas" , "menlo" , "monaco" , "lucida console" , "liberation mono" , "dejavu sans mono" , "bitstream vera sans mono" , "courier new" , monospace , sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">Scroll</span> actually does then please let me know as so far the answer to that has eluded me.<br />
<br />
<b>Addendum:</b><br />
<br />
The "bug fix" (to decide where a drop happens relative to the existing list of addresses in the "store" could be based upon a calculation performed at the same time as the test to see if the panel should be scrolled.<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: blue;">void</span> maybeScrollpanel(<span style="color: blue;">int</span> dragY)
{
<span style="color: blue;">if</span> ((dragY - panelTop) <= flowLayoutPanel1.VerticalScroll.Value && flowLayoutPanel1.VerticalScroll.Value > 0)
{
flowLayoutPanel1.VerticalScroll.Value -= (flowLayoutPanel1.VerticalScroll.Value > scrollAt) ? scrollAt : flowLayoutPanel1.VerticalScroll.Value;
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> (dragY - panelTop >= flowLayoutPanel1.Height - scrollAt && flowLayoutPanel1.VerticalScroll.Maximum > 0)
{
flowLayoutPanel1.VerticalScroll.Value += (flowLayoutPanel1.VerticalScroll.Maximum - flowLayoutPanel1.VerticalScroll.Value > scrollAt) ? scrollAt : flowLayoutPanel1.VerticalScroll.Maximum - flowLayoutPanel1.VerticalScroll.Value;
}
calculatedPosition = calculatePosition(dragY - panelTop);
}
<span style="color: blue;">private</span> <span style="color: blue;">int</span> calculatePosition(<span style="color: blue;">int</span> dragY)
{
<span style="color: blue;">if</span> (flowLayoutPanel1.Controls.Count == 1 || dragY < flowLayoutPanel1.Controls[1].Height) <span style="color: green;">// || allows lazy evaluation</span>
{
<span style="color: blue;">return</span> 1;
}
<span style="color: #2b91af;">Point</span> pt = <span style="color: blue;">new</span> <span style="color: #2b91af;">Point</span>(flowLayoutPanel1.Width / 2, dragY); <span style="color: green;">// asumes single column of controls in panel</span>
<span style="color: #2b91af;">Control</span> cAt = flowLayoutPanel1.GetChildAtPoint(pt);
<span style="color: blue;">while</span> (cAt == <span style="color: blue;">null</span> && pt.Y < (flowLayoutPanel1.Height + flowLayoutPanel1.VerticalScroll.Maximum))
{
pt.Y += 5; <span style="color: green;">// arbitrary - adjust at will</span>
cAt = flowLayoutPanel1.GetChildAtPoint(pt);
}
<span style="color: blue;">return</span> (cAt != <span style="color: blue;">null</span>) ? ((<span style="color: #2b91af;">AddressControl</span>)cAt).Sequence : (flowLayoutPanel1.Controls.OfType<<span style="color: #2b91af;">AddressControl</span>>().Max(a => a.Sequence) + 1);
}
</div>
</code></pre>
Then applied to the drop events like<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: blue;">void</span> flowLayoutPanel1_DragDrop(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">DragEventArgs</span> e)
{
<span style="color: green;">// the two paths could share more of the code but...</span>
<span style="color: blue;">if</span> (e.Data.GetDataPresent(dragAddress.Name))
{
<span style="color: green;">//handles drop of new address onto the panel</span>
<span style="color: #2b91af;">AddressControl</span> newControl = <span style="color: blue;">new</span> <span style="color: #2b91af;">AddressControl</span>((<span style="color: #2b91af;">DragAddress</span>)e.Data.GetData(dragAddress.Name), DoControlDrag, DraggedPast, flowLayoutPanel1.Controls.Count);
<span style="color: blue;">foreach</span>(<span style="color: #2b91af;">AddressControl</span> ac <span style="color: blue;">in</span> flowLayoutPanel1.Controls.OfType<<span style="color: #2b91af;">AddressControl</span>>().Where(a => a.Sequence >= calculatedPosition))
{
ac.Sequence++;
}
newControl.Sequence = calculatedPosition;
flowLayoutPanel1.Controls.Add(newControl);
reorderAddresses();
resetPnlEdit();
} <span style="color: blue;">else</span> <span style="color: blue;">if</span> (e.Data.GetDataPresent(addressControl.Name))
{
<span style="color: green;">// handles drop of an existing AddressControl into (presumably) a new position</span>
<span style="color: blue;">int</span> newSeq = 1;
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">AddressControl</span> ac <span style="color: blue;">in</span> flowLayoutPanel1.Controls.OfType<<span style="color: #2b91af;">AddressControl</span>>().OrderBy(a => a.Sequence))
{
<span style="color: blue;">if</span>(ac.Sequence == dragItemSequence)
{
ac.Sequence = calculatedPosition;
} <span style="color: blue;">else</span> <span style="color: blue;">if</span>(ac.Sequence == calculatedPosition)
{
ac.Sequence++;
newSeq = ac.Sequence;
} <span style="color: blue;">else</span>
{
ac.Sequence = newSeq;
}
newSeq++;
}
newSeq = 1;
<span style="color: green;">// is redoing the sequence to avoid breaks a bit too anal?</span>
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">AddressControl</span> ac <span style="color: blue;">in</span> flowLayoutPanel1.Controls.OfType<<span style="color: #2b91af;">AddressControl</span>>().OrderBy(a => a.Sequence))
{
ac.Sequence = newSeq;
newSeq++;
}
reorderAddresses();
}
}
</div>
</code></pre>
For the rest of the code check out GitHub at <a href="https://github.com/MikeGWem/DragDropDemo">https://github.com/MikeGWem/DragDropDemo</a><br />
<br />
<b>End Note:</b><br />
None of this looks like it will work with UWP and .NET Core so I will try and write up a few notes on that once I have something working that looks usable for others.</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]1tag:blogger.com,1999:blog-21052732.post-75595566114181533872016-04-22T06:35:00.000-07:002016-04-22T06:35:51.165-07:00A textbox that auto-wraps to fit contents<div dir="ltr" style="text-align: left;" trbidi="on">
The Windows Forms Textbox control is a thin wrapper for the underlying Win32 control and there is no Paint event you can hang extra code on in the normal way. If you write something like <span style="font-family: "courier new" , "courier" , monospace;">mycontrol.Paint += myFunction;</span> and <span style="font-family: "courier new" , "courier" , monospace;">mycontrol</span> is a Textbox them <span style="font-family: "courier new" , "courier" , monospace;">myFunction()</span> will never get called.<br />
<br />
You can go the whole hog and<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="font-family: "consolas"; font-size: 12.666666666666666;">SetStyle(</span><span style="color: #2b91af; font-family: "consolas"; font-size: 12.666666666666666;">ControlStyles</span><span style="font-family: "consolas"; font-size: 12.666666666666666;">.UserPaint, </span><span style="color: blue; font-family: "consolas"; font-size: 12.666666666666666;">true</span><span style="font-family: "consolas"; font-size: 12.666666666666666;">);</span>
</div>
</code></pre>
<div>
<br />
and provide a Paint method but you have to do everything as it is no good calling the <span style="font-family: "courier new" , "courier" , monospace;">base.OnPaint()</span>. Give it a try, and you will end up with an astonishingly unresponsive textbox.<br />
<br />
I wanted to create a version of a Textbox that would resize itself vertically to accommodate extended word wrapped text. That did not result in any issues – all it needed was a FitToContents() method that retained the set width and allowed the height to vary to fit the control content.<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> FitToContents()
{
<span style="color: #2b91af;">Size</span> size = <span style="color: blue;">this</span>.GetPreferredSize(<span style="color: blue;">new</span> <span style="color: #2b91af;">Size</span>(<span style="color: blue;">this</span>.Width, 0));
<span style="color: blue;">if</span> (multiLine) { <span style="color: blue;">this</span>.Height = size.Height; }
}
</div>
</code></pre>
<br /></div>
<div>
However I also wanted to be able to switch between a label displaying a given string and a textbox capable of editing that string. Just to make that interesting I wanted a “fade in” and “fade out” animation to switch between the two. While I was at it, I also wanted to support a textbox “Placeholder” facility to keep the UI nice and clean. It was that final element that reminded me that it was possible to slide a limited paint facility into position to be used in place of the controls own paint when the control was relatively inactive. My own paint facility only needed to manage the fades and the placeholder text display – all the rest could be left to the underlying control.<br />
<br />
Fading text in and out was just a matter of tweaking the Alpha component of the control ForeColor in steps over a defined time period. It was a good opportunity to use the recently introduced async/await functionality although a timer would have worked just fine. The control border is unreachable to all intents and purposes although if the control was set borderless one could be drawn around it and arrangements made to fade that rectangle in and out.<br />
<br />
<b>OK – I know - WPF</b> and all that, but I also have this funny feeling that as soon as I invest any real time in WPF code Microsoft are going to announce a newer superer duperer common base for Windows apps and it will all be to no avail. Don’t take advice from me though – anything could happen.<br />
<br />
The full code for this class can be found at the bottom of this post – <b>usual caveats</b>.<br />
<br />
In case anyone fancies just using the placeholder functionality I have generously added an attribute (AutoMultiLine) that can be set false to stop the control re-sizing in response to text longer than the control width. Just set the PlaceHolderText attribute at design or run time. You can always ignore or remove the code associated with the fade.<br />
<br />
The control based upon Label with a matching fade facility is very similar but simpler and again the code can be found below. This label also supports automatic height resizing to match the Text.<br />
<br />
Please note that these controls are using a language feature from .NET v4.5 so you would need to switch to using a timer to make use of the fade functionality with earlier versions.<br />
<br />
Combining these two custom controls into a UserControl made sense as they could then be addressed together as a single entity. This did have its challenges – partly because the TextBox BackColor property can’t be set Transparent and that makes the fade through a bit clunky in one direction – perhaps I should have gone for a “wipe” effect instead…<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">namespace</span> Adit.Classes.Controls
{
[<span style="color: #2b91af;">ToolboxBitmap</span>(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">TextBox</span>))]
<span style="color: blue;">class</span> <span style="color: #2b91af;">MultiLineTextBox</span> : <span style="color: #2b91af;">TextBox</span>
{
<span style="color: blue;">#region</span> Private Declarations
<span style="color: blue;">private</span> <span style="color: #2b91af;">Color</span> foreColour;
<span style="color: blue;">private</span> <span style="color: #2b91af;">Color</span> placeholderColour = <span style="color: #2b91af;">Color</span>.Gray;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> opacity = 256;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> fadeSteps = 10;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> fadeTime = 750;
<span style="color: blue;">private</span> <span style="color: blue;">string</span> placeholderText = <span style="color: #a31515;">"Type here"</span>;
<span style="color: blue;">private</span> <span style="color: blue;">bool</span> showPlaceholderText = <span style="color: blue;">false</span>, multiLine = <span style="color: blue;">true</span>;
<span style="color: blue;">#endregion</span>
<span style="color: blue;">public</span> MultiLineTextBox()
{
<span style="color: blue;">this</span>.Multiline = multiLine;
<span style="color: blue;">this</span>.WordWrap = multiLine;
}
<span style="color: blue;">#region</span> Design attributes
[<span style="color: #2b91af;">Description</span>(<span style="color: #a31515;">"Fade time in milliseconds"</span>), <span style="color: #2b91af;">Category</span>(<span style="color: #a31515;">"Behavior"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">int</span> FadeTime
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> fadeTime; }
<span style="color: blue;">set</span> { fadeTime = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">Description</span>(<span style="color: #a31515;">"Number of steps from transparent 0 to opaque 256"</span>), <span style="color: #2b91af;">Category</span>(<span style="color: #a31515;">"Behavior"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">int</span> FadeSteps
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> fadeSteps; }
<span style="color: blue;">set</span> { fadeSteps = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">Description</span>(<span style="color: #a31515;">"Placeholder Text"</span>), <span style="color: #2b91af;">Category</span>(<span style="color: #a31515;">"Appearance"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">string</span> PlaceHolderText
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> placeholderText; }
<span style="color: blue;">set</span> { placeholderText = <span style="color: blue;">value</span>; Invalidate(); }
}
[<span style="color: #2b91af;">Description</span>(<span style="color: #a31515;">"Placeholder Colour"</span>), <span style="color: #2b91af;">Category</span>(<span style="color: #a31515;">"Appearance"</span>)]
<span style="color: blue;">public</span> <span style="color: #2b91af;">Color</span> PlaceHolderColour
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> placeholderColour; }
<span style="color: blue;">set</span> { placeholderColour = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">Description</span>(<span style="color: #a31515;">"Automatic switch to multiline"</span>), <span style="color: #2b91af;">Category</span>(<span style="color: #a31515;">"Appearance"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">bool</span> AutoMultiLine
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> multiLine; }
<span style="color: blue;">set</span> {
multiLine = <span style="color: blue;">value</span>;
Multiline = <span style="color: blue;">value</span>;
WordWrap = <span style="color: blue;">value</span>;
}
}
<span style="color: blue;">#endregion</span>
<span style="color: blue;">#region</span> Public methods
<span style="color: blue;">public</span> <span style="color: blue;">async</span> <span style="color: blue;">void</span> FadeInOut()
{
<span style="color: blue;">bool</span> saveUserPaint = GetStyle(<span style="color: #2b91af;">ControlStyles</span>.UserPaint);
foreColour = ForeColor;
<span style="color: blue;">int</span> opStep = 256 / fadeSteps;
<span style="color: blue;">if</span> (Visible)
{
opacity = 256;
opStep *= -1;
} <span style="color: blue;">else</span>
{
Visible = <span style="color: blue;">true</span>;
opacity = 0;
}
SetStyle(<span style="color: #2b91af;">ControlStyles</span>.UserPaint, <span style="color: blue;">true</span>); <span style="color: green;">// set after any Visibility change</span>
opacity = opacity + opStep;
<span style="color: blue;">while</span>(opacity > 0 && opacity < 256)
{
foreColour = fadeColour(opacity, foreColour);
placeholderColour = fadeColour(opacity, placeholderColour);
Invalidate();
<span style="color: blue;">await</span> <span style="color: #2b91af;">Task</span>.Delay(fadeTime / fadeSteps);
opacity = opacity + opStep;
}
Visible = (opacity >= 255);
SetStyle(<span style="color: #2b91af;">ControlStyles</span>.UserPaint, saveUserPaint);
<span style="color: blue;">if</span> (Visible)
{
Invalidate();
Focus();
}
}
<span style="color: blue;">#endregion</span>
<span style="color: blue;">#region</span> Override control methods
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnResize(<span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: blue;">base</span>.OnResize(e);
<span style="color: blue;">this</span>.FitToContents();
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnKeyUp(<span style="color: #2b91af;">KeyEventArgs</span> e)
{
<span style="color: blue;">base</span>.OnKeyUp(e);
FitToContents();
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnTextChanged(<span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: blue;">base</span>.OnTextChanged(e);
placeholderToggle();
FitToContents();
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnCreateControl()
{
<span style="color: blue;">base</span>.OnCreateControl();
placeholderToggle();
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnPaint(<span style="color: #2b91af;">PaintEventArgs</span> e)
{
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> drawBrush = <span style="color: blue;">new</span> <span style="color: #2b91af;">SolidBrush</span>((showPlaceholderText)? placeholderColour: foreColour))
{
e.Graphics.DrawString((showPlaceholderText) ? placeholderText : Text, Font, drawBrush, <span style="color: blue;">this</span>.ClientRectangle);
<span style="color: green;">// The underlying control is probably using TextRenderer.DrawText (gdi not gdi+)</span>
}
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> FitToContents()
{
<span style="color: #2b91af;">Size</span> size = <span style="color: blue;">this</span>.GetPreferredSize(<span style="color: blue;">new</span> <span style="color: #2b91af;">Size</span>(<span style="color: blue;">this</span>.Width, 0));
<span style="color: blue;">if</span> (multiLine) { <span style="color: blue;">this</span>.Height = size.Height; }
}
<span style="color: blue;">#endregion</span>
<span style="color: blue;">#region</span> Private methods
<span style="color: blue;">private</span> <span style="color: #2b91af;">Color</span> fadeColour(<span style="color: blue;">int</span> opacity, <span style="color: #2b91af;">Color</span> argbColour)
{
<span style="color: blue;">return</span> <span style="color: #2b91af;">Color</span>.FromArgb(opacity, argbColour);
}
<span style="color: blue;">private</span> <span style="color: blue;">void</span> placeholderToggle()
{
showPlaceholderText = (Text.Length > 0) ? <span style="color: blue;">false</span> : <span style="color: blue;">true</span>;
SetStyle(<span style="color: #2b91af;">ControlStyles</span>.UserPaint, showPlaceholderText);
}
<span style="color: blue;">#endregion</span>
}
}
</div>
</code></pre>
</div>
<div>
<br />
and<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">namespace</span> CheckBuilder.Classes.Controls
{
<span style="color: blue;">public</span> <span style="color: blue;">partial</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">WrapLabel</span> : <span style="color: #2b91af;">Label</span>
{
<span style="color: blue;">#region</span> Private Declarations
<span style="color: blue;">private</span> <span style="color: #2b91af;">Color</span> foreColour;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> opacity = 256;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> fadeSteps = 10;
<span style="color: blue;">private</span> <span style="color: blue;">int</span> fadeTime = 750;
<span style="color: blue;">private</span> <span style="color: blue;">bool</span> fading = <span style="color: blue;">false</span>;
<span style="color: blue;">#endregion</span>
<span style="color: blue;">public</span> WrapLabel()
{
<span style="color: blue;">base</span>.AutoSize = <span style="color: blue;">false</span>;
}
<span style="color: blue;">#region</span> Public methods
<span style="color: blue;">public</span> <span style="color: blue;">async</span> <span style="color: blue;">void</span> FadeInOut()
{
fading = <span style="color: blue;">true</span>;
foreColour = ForeColor;
<span style="color: blue;">int</span> opStep = 256 / fadeSteps;
<span style="color: blue;">if</span> (Visible)
{
opacity = 256;
opStep *= -1;
}
<span style="color: blue;">else</span>
{
opacity = 0;
Visible = <span style="color: blue;">true</span>;
}
opacity = opacity + opStep;
<span style="color: blue;">while</span> (opacity > 0 && opacity < 256)
{
Invalidate();
<span style="color: blue;">await</span> <span style="color: #2b91af;">Task</span>.Delay(fadeTime / fadeSteps);
opacity = opacity + opStep;
}
Visible = (opacity >= 255);
fading = <span style="color: blue;">false</span>;
}
<span style="color: blue;">#endregion</span>
<span style="color: blue;">#region</span> Design attributes
[<span style="color: #2b91af;">Description</span>(<span style="color: #a31515;">"Fade time in milliseconds"</span>), <span style="color: #2b91af;">Category</span>(<span style="color: #a31515;">"Behavior"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">int</span> FadeTime
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> fadeTime; }
<span style="color: blue;">set</span> { fadeTime = <span style="color: blue;">value</span>; }
}
[<span style="color: #2b91af;">Description</span>(<span style="color: #a31515;">"Number of steps from transparent 0 to opaque 256"</span>), <span style="color: #2b91af;">Category</span>(<span style="color: #a31515;">"Behavior"</span>)]
<span style="color: blue;">public</span> <span style="color: blue;">int</span> FadeSteps
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> fadeSteps; }
<span style="color: blue;">set</span> { fadeSteps = <span style="color: blue;">value</span>; }
}
<span style="color: blue;">#endregion</span>
<span style="color: blue;">#region</span> Override control events
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnPaint(<span style="color: #2b91af;">PaintEventArgs</span> pe)
{
<span style="color: blue;">if</span>(fading)
{
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> drawBrush = <span style="color: blue;">new</span> <span style="color: #2b91af;">SolidBrush</span>(fadeColour(opacity, foreColour)))
{
pe.Graphics.DrawString(Text, Font, drawBrush, ClientRectangle);
}
} <span style="color: blue;">else</span>
{
<span style="color: blue;">base</span>.OnPaint(pe);
}
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnResize(<span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: blue;">base</span>.OnResize(e);
<span style="color: blue;">this</span>.FitToContents();
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnTextChanged(<span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: blue;">base</span>.OnTextChanged(e);
<span style="color: blue;">this</span>.FitToContents();
}
<span style="color: blue;">protected</span> <span style="color: blue;">virtual</span> <span style="color: blue;">void</span> FitToContents()
{
<span style="color: #2b91af;">Size</span> size = <span style="color: blue;">this</span>.GetPreferredSize(<span style="color: blue;">new</span> <span style="color: #2b91af;">Size</span>(<span style="color: blue;">this</span>.Width, 0));
<span style="color: blue;">this</span>.Height = size.Height;
}
<span style="color: blue;">protected</span> <span style="color: blue;">override</span> <span style="color: blue;">void</span> OnCreateControl()
{
<span style="color: blue;">base</span>.OnCreateControl();
<span style="color: blue;">this</span>.AutoSize = <span style="color: blue;">false</span>;
}
<span style="color: blue;">#endregion</span>
<span style="color: blue;">#region</span> Stomp on AutoSize
[<span style="color: #2b91af;">DefaultValue</span>(<span style="color: blue;">false</span>), <span style="color: #2b91af;">Browsable</span>(<span style="color: blue;">false</span>), <span style="color: #2b91af;">EditorBrowsable</span>(<span style="color: #2b91af;">EditorBrowsableState</span>.Never), <span style="color: #2b91af;">DesignerSerializationVisibility</span>(<span style="color: #2b91af;">DesignerSerializationVisibility</span>.Hidden)]
<span style="color: blue;">public</span> <span style="color: blue;">override</span> <span style="color: blue;">bool</span> AutoSize
{
<span style="color: blue;">get</span> { <span style="color: blue;">return</span> <span style="color: blue;">base</span>.AutoSize; }
<span style="color: blue;">set</span> { <span style="color: blue;">base</span>.AutoSize = <span style="color: blue;">value</span>; }
}
<span style="color: blue;">#endregion</span>
<span style="color: blue;">#region</span> Private methods
<span style="color: blue;">private</span> <span style="color: #2b91af;">Color</span> fadeColour(<span style="color: blue;">int</span> opacity, <span style="color: #2b91af;">Color</span> argbColour)
{
<span style="color: blue;">return</span> <span style="color: #2b91af;">Color</span>.FromArgb(opacity, argbColour);
}
<span style="color: blue;">#endregion</span>
}
}
</div>
</code></pre>
<br /></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-65636802406211023992016-04-19T12:00:00.000-07:002016-04-19T12:00:19.688-07:00Structure C# like JavaScript<div dir="ltr" style="text-align: left;" trbidi="on">
Been building a “proof of concept” Windows program that ended up including 9 different user controls, 4 Custom controls and some (gasp) printed output.<br />
<br />
My custom controls included:<br />
<ul style="text-align: left;">
<li>A Textbox with the equivalent of the HTML Textbox “placeholder”.</li>
<li>A custom Checkbox to emulate a material Design checkbox.</li>
<li>A Label control to automatically support word wrapped text – like HTML.</li>
<li>A Panel with rounded corners (which also required a couple of extensions to System.Drawing.Graphics to support drawing and filling the bounding round cornered “box”<b>**</b>).</li>
</ul>
There was the makings of a “rant” here; taking Microsoft to task on the lack of updates to the basic controls to meet modern requirements. I stifled it when I realised that rather than providing solutions matching what would, after all, be ever shifting changes in design “fashion” they had simply provided the tools necessary to remedy the situation. If you count yourself as a programmer then you have to accept the challenge to one’s design skills – mine do lack I admit.<br />
<br />
<b>What is the true difference between a Custom Control and a User Control?</b><br />
<br />
This is a question I have seen asked in many places and so far all the answers I have seen have been “lies for children<b>*</b>” (simplifications that attempt to help someone make the right choice).<br />
<br />
The key difference is that a User Control inherits from UserControl and a Custom control inherits from Control. That’s about it. You can add other controls to either and both will turn up in the visual designer “toolbox” in Visual Studio after a “build”. They can both place custom attributes and events into the control properties window as well as take advantage of properties inherited from their base types (these can also be suppressed if required).<br />
<br />
Generally, you would choose to create a Custom Control if it is intended as a single control rather than a defined collection. (However there is no reason why a custom control might not act as a custom container for other Windows controls added, perhaps, at design time – like my panel with rounded corners). You would also select this type if you intend to manage drawing the control and also if you intend to subclass an existing control type.<br />
<br />
User controls are a good choice if you are going to build a control using two or more pre-existing controls. This approach effectively provides a local name space and would normally provide code to handle individual sub-component events. User controls are better used when adding additional visual attributes during the paint event rather than managing the whole drawing requirement.<br />
<br />
I think that my custom built control base type selection would normally be founded upon usage. “User Controls” being particular to a given application while “Custom Controls” might well be ported to other projects. Which probably does not help at all.<br />
<br />
<b>Why all those User Controls?</b><br />
<br />
Well the program required repetitive collections of controls arranged as cards, subsections of cards and subsections of those subsections – all at the whim of the user. In addition, the program provides a preview pane to show how the output would be presented with support for interactive testing on the fly. At the design stage I could see that this had quite a lot of potential to get messy built using a conventional Windows Forms approach. I knew that if I built something similar in JavaScript then I would end up with a set of objects that managed their portion of the UI and dealt with the relevant events. Any required communication would be through callbacks to functions. The C# equivalent then became clear – a set of UserControls communication between themselves using Delegates. In fact some of the presentation side of the program had already been built using JavaScript and it was interesting to note the strong similarities between some of the C# and JavaScript code blocks.<br />
<br />
That was how it worked out – a varying number of custom UserControls communicating with each other in the main but with the owning form being called upon to manage “global” functions like database saves. I can only estimate the savings in code lines as “substantial”.<br />
<br />
<b>Printing controls</b><br />
<br />
Providing a print output started out feeling a bit “retro” as the most obvious way to accomplish the task was to print what was effectively an image of the program output preview pane (or at least the contents). I could just about recall that the Visual Basic 3 manual(s)<b>***</b> had included some functionality to print a window content but had never actually done any such thing in all my years of code.<br />
<br />
Establishing the basic mechanism proved simple enough as any control has the capacity to draw itself to a bitmap and the resulting bitmaps can easily be drawn to the printed page (scaling as required).<br />
<br />
Worth noting that when doing this it is easy to add a drop shadow by extending the size of the bitmap by a few pixels. You can then draw some lines in a sequence of grey shades to create the shadow effect.<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">Bitmap</span> drawControlsImage(<span style="color: #2b91af;">Control</span> control, <span style="color: blue;">bool</span> addShadow = <span style="color: blue;">false</span>)
{
<span style="color: #2b91af;">Bitmap</span> bm = <span style="color: blue;">new</span> <span style="color: #2b91af;">Bitmap</span>(control.Width, control.Height + ((addShadow) ? 3 : 0));
control.DrawToBitmap(bm, <span style="color: blue;">new</span> <span style="color: #2b91af;">Rectangle</span>(0, 0, control.Width, control.Height));
<span style="color: blue;">if</span>(dropShadow)
{
<span style="color: #2b91af;">Point</span> pt = <span style="color: blue;">new</span> <span style="color: #2b91af;">Point</span>(0, bm.Height - 3);
<span style="color: blue;">using</span> (<span style="color: #2b91af;">Graphics</span> g = <span style="color: #2b91af;">Graphics</span>.FromImage(bm))
{
<span style="color: blue;">using</span> (<span style="color: blue;">var</span> pen = <span style="color: blue;">new</span> <span style="color: #2b91af;">Pen</span>(shadow[0]))
{
<span style="color: blue;">for</span> (<span style="color: blue;">var</span> sp = 0; sp < 3; sp++)
{
pen.Color = shadow[sp];
g.DrawLine(pen, pt.X, pt.Y, pt.X + bm.Width - 2, pt.Y);
pt.Y++;
}
}
}
}
<span style="color: blue;">return</span> bm;
}
</div>
</code></pre>
<div>
<br />
having previously coded<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">Color</span>[] shadow = <span style="color: blue;">new</span> <span style="color: #2b91af;">Color</span>[3];
and
shadow[0] = <span style="color: #2b91af;">Color</span>.FromArgb(181, 181, 181);
shadow[1] = <span style="color: #2b91af;">Color</span>.FromArgb(195, 195, 195);
shadow[2] = <span style="color: #2b91af;">Color</span>.FromArgb(211, 211, 211);
</div>
</code></pre>
<br />
My printer output took the form of one or more major components (User Controls) emulating a Material design “card”. Finding the best way to order the cards in columns to optimise the printed layout looked set to be an interesting problem. It was analogous to the 2D rectangle bin packing challenge but modified in that there was at least an implicit order in the cards plus the target rectangle could be proportionately increased in size (at least conceptually) by applying ScaleTransform() to the output graphics surface and thus (negative) zoom. While thinking of the best approach I also thought about the issue as a “flow layout” problem – with the option to resize the logical bounding rectangle until a fit was achieved.<br />
<br />
After a happy hour reading around the potential algorithms I realised that my requirement was very much a special case – a simple stacking exercise.<br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV_SmDRNz9-xGDzoZ80ZfU_MnCrMfoQ_GnPQLFexSExQDKz83ubVjxMbXWnEOpdghWptsTBsOEDFZoN6KduBq4jNRMbr1eXF37X8hGjQdvC1xkm7PZg2qanYwELZL-kbr1ibdVsQ/s1600/PackingAlgo.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV_SmDRNz9-xGDzoZ80ZfU_MnCrMfoQ_GnPQLFexSExQDKz83ubVjxMbXWnEOpdghWptsTBsOEDFZoN6KduBq4jNRMbr1eXF37X8hGjQdvC1xkm7PZg2qanYwELZL-kbr1ibdVsQ/s640/PackingAlgo.png" width="640" /></a></div>
<div>
Which at first sight produced an acceptable result – but a little thought turned up the most obvious fault. Early positioning of objects in a column could undermine later reductions in the overall width.<br />
<br />
What was needed was a two pass process with the first pass constrained to not building a column “higher” than the measured page “vertical” space. Second pass could then work as before towards the smallest packed size. So far, testing shows that the two pass method produces a better result and (on most occasions) a nicely balanced layout.<br />
<br />
It amused me to note that I was quite happy to write the first draft of my stacking algorithm based upon a two dimensional array of SizeF (SizeF[,]) but when I came to re-write it to include two passes I changed the structure to List<List<SizeF>> (effectively a sparse array with inbuilt equivalents of Push() and Pop()) and achieved some code reduction as a consequence.</div>
<div>
<br /></div>
<div>
<b>*</b> <a href="https://en.wikipedia.org/wiki/Lie-to-children">Lies-to-children have a scholarly root</a>. </div>
<div>
<br /></div>
<div>
<b>**</b> Graphics extensions: You might like to take a look at<a href="http://www.codeproject.com/Articles/38436/Extended-Graphics-Rounded-rectangles-Font-metrics"> this Code Project post</a> by Arun Zaheeruddin which provides a fully overloaded set of rounded rectangle drawing functions that look enticing.</div>
<div>
<br /></div>
<div>
<b>***</b> The VB3 manual set (included in the box) was probably the pinnacle of written language documentation. It was clearly intended to empower a generation of new Windows programmers – as indeed it probably did. We have come to accept that Google searches and Stack Overflow now provide detailed technical documentation for most things but this well written, detailed and accurate set in three (as I recall) volumes filled in the gap for a vast army until the World Wide Web was invented.</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-31360081154961056102016-04-11T05:39:00.001-07:002016-04-11T05:39:51.787-07:00Dynamic C#<div dir="ltr" style="text-align: left;" trbidi="on">
Just used the dynamic key word for the first time in C# - to get the compiler to relax a bit and act more like VB which allows late binding.<br />
<br />
I was using a control Tag to store a couple of data items and as Tag accepts an object decided to use an Anonymous Object rather than define another class or whatnot. Something like:<br />
<br />
<pre>aControl.Tag = new { Sequence = ItemSequence, id = ItemID};</pre>
<br />
But how to consume those object attributes in another function?<br />
<br />
The IDE and compiler are not going to take kindly to anything like aControl.Tag.Sequence as that can only make sense at runtime.<br />
<br />
The dynamic keyword comes to the rescue.<br />
<br />
Here I am looping through a control collection filtered by my specific control type and in the order of the Sequence attribute in the anonymous object stored in the control Tag:<br />
<br />
<pre>foreach(MyCheckbox mb in this.Controls.OfType<mycheckbox>().OrderBy(p => ((dynamic)p.Tag).Sequence))
{ … }
</mycheckbox></pre>
<br />
Also (after prompting by Visual Studio) used the following syntax to check if a reference to a delegate is null and execute it if it is valid:<br />
<br />
<pre>notifyChange?.Invoke(ids);</pre>
<br />
You can add a conditional call to a delegate to a standard control event. For example:<br />
<br />
<pre>myControl.SizeChanged += (object s, EventArgs e) => { checkSize?.Invoke(); };</pre>
<br />
The “is” keyword also came in handy with the ability to say something like:<br />
<br />
<pre>if (myobj is CardSubsection){} </pre>
<br />
and do something if myobj can be safely cast to the relevant class. “is” makes it way simpler (and produces clearer code) when passing one of a range of classes into a function via an object reference.<br />
<br />
On the subject of clarity, I came across a little bit of code like this in a blog:<br />
<br />
<pre>if (pa.TicksToGo-- > 0) {}</pre>
<br />
which is shorter than<br />
<br />
<pre style="background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif"); background: #f0f0f0; border: 1px dashed #cccccc; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: "segoe ui"; font-size: 12; font-style: normal; font-weight: normal; text-align: left;">
pa.TicksToGo--; <span style="color: green;">//</span><span style="color: green;"> or maybe pa.TicksToGo -=1;</span><br />
<span style="color: black;"><span style="color: blue;">if</span> (pa.TicksToGo > 0) {}
</span></div>
</code></pre>
<br />
but less easy to maintain at some future date. I know that JSLint would like to persuade you that -– and ++ are evil in and of themselves but I am not convinced – safe to use with due caution I think.<br />
<br />
Looks like C# is going to “keep on giving” with the news that the dev teams for C# and VB are going to let the two languages drift further apart. Seems that developers using VB favour stability (presumably finding multiple language versions bothersome within their organisations) and the C# types are gluttons for novelty. Should be interesting.<br />
<br />
Read more here: <a href="http://www.infoworld.com/article/3051066/application-development/microsoft-c-visual-basic-are-now-set-to-diverge.html">http://www.infoworld.com/article/3051066/application-development/microsoft-c-visual-basic-are-now-set-to-diverge.html</a><br />
<div>
<br /></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-68826860485215874552016-03-20T09:55:00.004-07:002016-03-30T02:49:23.409-07:00Material Design Lite<div dir="ltr" style="text-align: left;" trbidi="on">
<b>A short and incomplete review</b><br />
<b><br /></b>
<a href="https://www.getmdl.io/">Material Design Lite</a> (MDL) is a Google project intended to deliver a “Material design” look and feel to websites. This HTML, CSS and JavaScript project is a work in progress so shortcomings experienced might well be short lived so please bear in mind that this limited review was based upon version 1.1.2.<br />
<br />
The project FAQ makes the following point. “We optimise for websites heavy on content, such as marketing pages, articles, blogs and general web content that isn’t particularly app-y.” However the supplied layout components respond well to variations in screen size and thus provide a solid basis for web pages targeting smartphones alongside desktop browsers. Where things are a bit clunky at the moment is in the area of dynamic page changes after the initial load and it may be that this will prove to be an enduring issue as (after all) that could be considered somewhat app-y.<br />
<br />
The layout components provide a good range of page formats that can include navigation, a drawer, tabs, a straightforward and responsive grid and a footer. There is inbuilt JavaScript support for most of the layout options – you just set out your mark-up <a href="https://www.getmdl.io/components/index.html#layout-section">as directed </a>and you are good to go. Colour choice is deliberately restrained but you can select from a range of themes to build a ‘custom’ CSS file.<br />
<br />
Other components include a good variety of buttons, excellent cards, lists, menus, sliders, toggles and text fields. There is a dialog component but this is limited by only partial browser support although there is a<a href="https://github.com/GoogleChrome/dialog-polyfill"> polyfill available</a>. The only obviously lacking component is a <select> but I found a <a href="http://codepen.io/pudgereyem/pen/PqBxQx">CSS only solution</a> that filled the gap nicely.<br />
<br />
There is full support for the Google Material Design Icons although for MDL I only used the icon font having previously used the SVG and CSS sprite versions on other projects. As expected the font more than met my requirements.<br />
<br />
I have a fondness for the consistency and flexibility of jQuery when it comes to DOM manipulation (however untrendy) and can confirm that jQuery works happily with MDL as long as you remember that jQuery objects are a collection of elements and that when calling an MDL function you may need to pass the first (or selected) element of the relevant collection:<br />
<br />
Which brings me nicely to the app-y bits.<br />
<br />
I first drafted out a reasonably complex static page to get a feel for the components and how they are laid out. The results were pleasing with just enough animation to give the design some life. Next I set up a skeleton MDL layout and attempted to build the same page content from JSON using JavaScript in the browser. Once the DOM has been updated with the new elements then you must call the componentHandler.upgradeElement() utility to apply the MDL layout magic to the new DOM elements. This worked very well for the set of cards I inserted together with their <div>s, text and checkboxes.<br />
<br />
I then started to build the layout for a “visual” form constructor and started to run into some limitations. I envisaged my form constructor being based upon multiple tabs with the user being able to add a new tab to start a new ‘form’. I was able to inject the same structures into the DOM as would be required to initialise an MDL tabbed page but calling the upgradeElement() utility only gave me a partial result lacking in any MDL script support.<br />
<br />
Currently most of the MDL documentation consists of asking questions on Stack Overflow.<br />
<br />
There I learned about the downgradeElements() utility (although it does get a mention on the MDL web pages) that should be applied to a container that has already been sprinkled with the MDL fairy dust prior to calling the upgradeElement() function to rebuild things with any new inclusions. Indeed user HR_117 has kindly supplied a <a href="https://codepen.io/anon/pen/qZaggg">CodePen demo</a> of this being applied to a set of MDL tabs. Trouble is, I found this failed when the tab container was itself wrapped within an MDL header (reported as an improbable bug so the true cause was masked in some way). Could very well be that I missed a trick here but how many hours can you spend on just one issue? My workaround (horror) was to create a bunch of tabs up front and to hide them on page load until they were required (a remarkably low overhead in reality as I was able to recycle previously used and subsequently closed tabs).<br />
<br />
I hit similar problems with the clever “Text with Floating Label” component when injected into a pre-existing layout. After a short losing battle (quite possibly my misunderstanding or whatever) I switched to using this <a href="http://clubdesign.github.io/floatlabels.js/">http://clubdesign.github.io/floatlabels.js/</a> alternative jQuery plugin that was a very nice substitute well within the style and spirit of Material Design.<br />
<br />
In the end I got a functional page although many interactive elements of the layout were untidy. I knew I was in for a long round of CSS tweaking to get things polished but then again I have hit similar walls when working with Bootstrap. It was one of the reasons I had my first dalliance with Polymer where, by default, you can avoid the intrusion of inherited CSS – and the overhead of tracking down and fixing localised layout glitches. So maybe I should have a bash at mixing Polymer components into an MDL ‘frame’ – now that sounds like a winner and indeed should be very doable. A definite if I get to re-visit this specific task.<br />
<br />
I am convinced enough by MDL as it stands to be sure of using it for aspects a commercial project currently in development. If you can avoid bumping into the limitations (and they will fast retreat I am sure – or maybe future documentation will show me, at least, the error of my ways) then it is very effective and can support a responsive web page that is bang up to date in design terms.<br />
<br />
The experiment with MDL was a nice opportunity to exercise my JavaScript muscles after a bit of a lengthy break where C#, Java and even a touch of VB.NET had been the required tools. JavaScript is always a delight to get back to, as I find it a very satisfying language to work with. You can take liberties that other languages could not support but in the end I always feel a certain obligation to refactor code until it is fit for public display – even though I then feed it through <a href="https://developers.google.com/closure/compiler/#what-is-the-closure-compiler">Closure *</a> to optimise browser download and execution. I found the (reasonably) recent addition of the Array.forEach() functionality (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach">Mozilla polyfill available</a>) very effective in reducing code complexity and enhancing readability – looks like ECMA 5 is creeping into my code. Array.find() is also another great – er – find.<br />
<br />
<br />
* I do hope that Closure is extended to be a compiler for <a href="https://hacks.mozilla.org/2015/12/compiling-to-webassembly-its-happening/">WebAssembly</a> when that gets support across the browser range (looking good so far).<br />
<br />
<b>Addendum:</b><br />
<br />
In many ways it makes more sense to implement the (rather restricted) forms designer app-y page that highlighted the MDL issues above as an app. Mobile development platforms are obviously going to be happy with the design concepts but how about good old Windows?<br />
<br />
There is a Material Design skin project <a href="https://github.com/IgnaceMaes/MaterialSkin">on GitHub</a> addressing Windows forms projects although it has been a while since there were any updates. There is also a <a href="https://github.com/ButchersBoy/MaterialDesignInXamlToolkit">WPF focused project</a> that looks a lot more complete and is certainly active - maybe attention has drifted from the former to the latter.<br />
<br />
A little experiment showed that some Material Design styling can be added to a pretty basic Windows Forms app by overriding the Paint() events on some of the key components. Turning a panel into a card, for instance, does not require a lot of effort.<br />
<br />
So, for Windows, a bit of mix and match should do the trick...<br />
<div>
<br /></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]3tag:blogger.com,1999:blog-21052732.post-89553443560167722612016-01-06T02:28:00.000-08:002016-02-06T03:06:31.389-08:00Kickstart a Graphics Book<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.6667px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>Why you should fund this graphics Book</b></span></div>
<b id="docs-internal-guid-1fc061a0-1679-a7a5-2158-a88c73bd546a" style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><a href="https://www.kickstarter.com/projects/2002981747/net-graphics-programming-omnibus/description">https://www.kickstarter.com/projects/2002981747/net-graphics-programming-omnibus/description</a></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You are primarily a .NET developer and/or a regular user of C#, VB or even F# but do not encounter graphics as a regular requirement within your projects. You are now wondering why I am promoting a book about .NET graphics to you in particular. There are two reasons.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The first is just that when you do need to include some graphical techniques into some development task then you will need a book that can jumpstart your skills acquisition and/or provide just the code you need for an unexpected task.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The second is that keeping up with developments in User Interface (UI) techniques is going to make increasing demands upon graphical skills. The UI will advance faster than the Windows API (or under surrogate APIs like WPF) and users, product managers and designers are going to be making some tough demands upon all developers with code running in the “human domain” (shall we call it?).</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Now you could prepare for this upcoming eventuality by brushing up on the maths involved - maybe starting here </span><a href="http://codeofthedamned.com/index.php/introduction-to-the-math-of" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">http://codeofthedamned.com/index.php/introduction-to-the-math-of</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> - but it would be way easier to let someone else tease out the crucial bits and present the results alongside their immediate sample application.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Why this specific Book? The answer to that is very straightforward. The last time Rod wrote a book about graphics it was brilliant - and I have some authority here. When I first started Windows programming I chose a development area that was entirely graphical (an early mapping application). This was before the Internet and the vast resources that has exposed - then if you wanted to know how something was done then you had to sit and work it out for yourself. I had an early copy of Charles Petzold’s master work (Programming Windows) to lookup the (Windows 3.1.) API calls and, in extremis, access to Microsoft developer support via CompuServe [</span><a href="https://en.m.wikipedia.org/wiki/CompuServe" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://en.m.wikipedia.org/wiki/CompuServe</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ] (yup you could email the guys that actually wrote the stuff in those dim and distant days and if your enquiery was interesting enough they would reply). Rod had not yet written his book and I struggled to learn and to develop the techniques required to produce even moderately efficient graphics code.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Some time later Rod’s book was published and I grabbed a copy - partly as personal affirmation but also to learn just how often I had done it all wrong. Here was a definitive work that you could dip into as required and I found that thereafter I did, saving time in recalling (or discovering) the optimal path every time I needed to. As .NET took over as the best development framework then I found I was using the book rather less. I knew that Rod had an updated opus in mind but sadly he could not convince a publisher that a market of the scale they required was waiting for a new book to be written.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here is our opportunity to fund a book of undoubted value for all - a definite plus on anyone's electronic bookshelf. Please join me in funding this Kickstarter. It will benefit the community of .NET developers as well as each individual “investor”.</span></div>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Start here </span><a href="https://www.kickstarter.com/projects/2002981747/net-graphics-programming-omnibus/description" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://www.kickstarter.com/projects/2002981747/net-graphics-programming-omnibus/description</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and then please encourage others to join in and make sure this book becomes a reality.</span><br />
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.6667px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>Addendum</b></span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">:</span><br />
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Sadly this Kickstarter has been withdrawn.</span></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-88011335492292190812015-12-07T09:19:00.002-08:002016-01-20T09:53:22.639-08:00Bare Minimum Software<div dir="ltr" style="text-align: left;" trbidi="on">
With the financial year end fast approaching it is time to consider any kit purchases in anticipation of activities during 2016 (and I don’t get that list right very often in truth). A laptop upgrade to something smaller and lighter looks a good idea – particularly with one of the teenagers having a dead machine and thus more than grateful for my cast off (actually not a bad spec - certainly going to outperform most current low end offerings).<br />
<br />
Buying hardware is just a few clicks in a web browser these days but the software component list promises a long session just running installs.<br />
<br />
What would be on your list for a basic set-up?<br />
<br />
I started with:<br />
<br />
<br />
<ul style="text-align: left;">
<li>Chrome browser</li>
<li>FireFox browser</li>
<li>Visual Studio 2015</li>
<li>Android Studio</li>
<li>SQL Server</li>
<li><a href="http://www.getpaint.net/index.html">Paint.NET</a> </li>
<li>Notepad++</li>
<li><a href="https://sourcegear.com/diffmerge/downloads.php">SourceGear diff/merge tool</a></li>
<li>SQLiteBrowser</li>
<li><a href="http://www.fosshub.com/Password-Safe.html">Bruce Schneier ‘s PasswordSafe</a></li>
<li>Hex Editor</li>
<li><a href="http://www.advanced-ip-scanner.com/">IPScanner </a> </li>
<li>Dropbox</li>
<li><a href="http://www.linqpad.net/Download.aspx#LINQPad5">LinQPad </a></li>
<li><a href="http://www.putty.org/">Putty</a> </li>
</ul>
<br />
<br />
Plus some homemade tools and utilities.<br />
<br />
Then there is the question of MS Office – will Gmail’s ability to display (say) Word documents fill in enough on incoming attachments to get by?<br />
<br />
Something to read PDF’s I suppose.<br />
<br />
Any suggested additions?<br />
<br />
Factor in a few system updates to add to the confusion and slow package download speeds and this already looks like a day’s work<br />
<br />
<b>Edit:</b><br />
<br />
Cracked and added a copy of MS Office. With the release of Office 2016 there are a lot of bargains around - particularly with earlier versions. In fact by a series of stock shortages I ended up with a copy of 2016 Pro for the price of a 2013 Home & Office on the residual market.<br />
<div>
<br /></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-36395307811176881922015-12-01T10:00:00.001-08:002015-12-02T01:17:16.907-08:00Raspberry Pi music<div dir="ltr" style="text-align: left;" trbidi="on">
<b>Somewhat off topic.</b><br />
<br />
I am the very happy owner of a five year old Brennan JB7 digital music system which includes a couple of their speakers sitting on some carefully positioned stands. Recently Brennan sent me an email to introduce the new “B2” model – and very nice it looks but I wondered if the price at £579.00 for the top model was strictly warranted (with all due respect for the undoubted product quality).<br />
<br />
As the new device seemed to be based upon a Raspberry Pi I ran through a few numbers for building something equivalent:<br />
<br />
<ul style="text-align: left;">
<li>1tb USB drive – retails at around £40</li>
<li>Raspberry Pi 2 – around £30 (often less)</li>
<li>Micro sd card - £5</li>
<li>Amplifier - £50</li>
<li>Power supplies- £20</li>
<li>CD drive - £8</li>
<li>Sundries (cables, case etc.) - £25</li>
</ul>
<br />
The Brennan box also has digital SPDIF and Line Out plus input options (all of which add a little to their costs) but I can’t see me making use of those in these minimalist times. I would just like to add digital radio and streaming to a disk based music playback capability.<br />
<br />
In going through my shopping list I started to get enthusiastic and wondered just how good a device I could put together. Now I am a software man – so what am I doing with what looks like a hardware project? Well not much in the way of electronics – I just need to hook the main components together – so perhaps just a little soldering. The nitty gritty all looks to be in the software.<br />
<br />
First task was effectively a side project. I felt that testing with speakers would be clumsy within the relatively confined area of my personal workspace – but I could manage headphones. So I decided to build a (near) empty box to hook some speaker terminals up to a headphone jack socket. With this I could provide an amplifier with something to drive and use the headphones to check the output without disturbing the peace.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCuRGLu-HIBqMhgk9cftHA4YNQFuvaKbAy2DrK7CT2-bM00k60rS5R_6-BAQqQppacjnNXnLexATVa9AnR2TCzGg61qU1ixZKUvnub3eE22_LoREJuipJi9PgBO8y585OX3NAj9A/s1600/SpeakerBox.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="343" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCuRGLu-HIBqMhgk9cftHA4YNQFuvaKbAy2DrK7CT2-bM00k60rS5R_6-BAQqQppacjnNXnLexATVa9AnR2TCzGg61qU1ixZKUvnub3eE22_LoREJuipJi9PgBO8y585OX3NAj9A/s400/SpeakerBox.png" width="400" /></a></div>
<br />
<div>
<div>
The hard drive is one recovered from a retired laptop sitting in a box that adapts the SATA interface and makes it a USB drive – cost less than £3 on Amazon if I recall. The Pi can’t supply enough power for the drive through the USB port so there is an additional power supply that takes the 12 volts arriving at my “box” and converts it to the 5 volts required delivered through a USB connection and a standard “Y” USB cable.</div>
<div>
<br /></div>
<div>
The main power supply is a butchered mains/car adapter but an old laptop power supply would probably do – depending upon the voltage limits of any amplifier used. The HifiBerry Amp+ used here can happily operate between 12 volts and 18 volts and in turn powers the Raspberry Pi which helps reduce the complexity of the wiring rat’s nest you can see below. The idea was to start with longish hook-ups and then shorten them as required when the components get fixed into the case.</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJRzULsV-mryF7bV7YP1VfgQbaCoGqEHWjJ5vnm1LHPBxyYf6XCm7RrKqRz-F3mWOftEjUptNseivb_buaTjC3j-vFqU_2-e5WdY-_ZW7tkEa9Kcifqa_gXnceTme_Mul6WI7VBQ/s1600/ratsnest.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJRzULsV-mryF7bV7YP1VfgQbaCoGqEHWjJ5vnm1LHPBxyYf6XCm7RrKqRz-F3mWOftEjUptNseivb_buaTjC3j-vFqU_2-e5WdY-_ZW7tkEa9Kcifqa_gXnceTme_Mul6WI7VBQ/s400/ratsnest.png" width="300" /></a></div>
<div>
<br /></div>
<div>
<div>
The case already has a power lead entry and an on/off rocker switch drilled and fitted. I have also drilled the back plate for the speaker connections and super-glued the main part of the loudspeaker terminal block to the outer face. </div>
<div>
<br /></div>
<div>
I will have to decide if I am going to go with wifi or add an RJ45 fitting to the back plate for a wired Internet connection. The box will certainly need a ‘power on’ led indicator and I would like to add an infra-red remote control for volume and track skipping at least (although most control will probably be via a web browser interface). Given that the pi can join the network and expose the music storage location (so I can add albums) the inclusion of a CD drive is still a choice to be made (one that might tax my ability to neatly tackle the case modifications).</div>
<div>
<br /></div>
<div>
I first started the Raspberry Pi with a copy of the standard Raspbian Linux variant. This booted just fine but (of course) was not aware of the amplifier so a rather quiet initial test. I then downloaded and installed the distro supplied by HiFiBerry and tried that. Now I quickly ran into the limits of my Linux knowledge and had some difficulty in getting sound to the amplifier. In the end, I pointed the web browser at Amazon, found the latest Enya album page and clicked on the track samples. That initially got some loud clicks from the headphones but after adjusting the (xwindows) volume control I heard some very nicely re-produced music. That at least confirmed that the amplifier worked and that my speaker/headphone adapter also functioned as expected.</div>
<div>
<br /></div>
<div>
It was now time to widen the testing and this meant entering (at least initially) the sometimes murky world of “open source” software. I might have the odd moan in this section but I would not want to imply any criticism of any of the projects mentioned or the teams that labour on them. Without open source and free projects we would all be the poorer (financially and culturally). In the past I have published open source software myself and that’s all I am saying (I have shared the pain guys).</div>
<div>
<br /></div>
<div>
A few minutes Googling showed that the Pi has inherited a solid core of key music related components from Linux and that there were a number of live projects looking to deliver the ‘ultimate’ solution. Two projects (RuneAudio and Volumio) seemed to be forks of the much respected RaspyFi project that itself now looks defunct. These projects currently sport PHP web interfaces that in turn make use of the MPD (Music Player Daemon) music playing server. A few posts suggest that the RuneAudio/Volumio divide was a little bitter.</div>
<div>
<br /></div>
<div>
I tried the RuneAudio project first. This was partly because the main internet page showed a picture of the HiFiBerry amp I had selected with the implicit promise that this and other selected Raspberry Pi (HiFi) add-ons were supported. I was also slightly put off by the way the Volumio project announcement was ‘camped out’ on top of the RaspyFi site. First I had to download the RuneAudio distribution (based I think on ArchLinux) and pop it on the micro SD card. It booted and I quickly located the web interface from the browser on my PC. It was clear the RuneAudio had located the albums stored on the hard drive and so I had a stab at selecting one to be played. Not a lot could be heard. A Google search found a commitment to support my amplifier from early 2014 and some suggestions on how to manage the trick short of that support eventually being delivered. This involved installing some software and settings. I logged into the distro and started trying to follow the instructions. The first irritation was that my keyboard was not supported (symbols all over the place and inexplicably the <y> and <z> keys swapped) but I struggled on. Then the installations failed with 404 errors and so I decided to try my luck elsewhere.</div>
<div>
<br /></div>
<div>
Next up was Pi MusicBox which has a web site like something from the early 90’s but – it’s the software that counts. Unfortunately (for me at least) the software sort of booted and then hung. To be fair, this might have been because my Pi was the recent Pi2. So I tried again.</div>
<div>
<br /></div>
<div>
I tried Volumio after all. Another distro (based on Debian this time I think) to install on the old SD card. This distro booted and the web app quickly became available from my PC’s web browser. The web page presented was nearly identical to the RuneAudio one which probably means both are inherited in turn. A quick trip to the settings page located the HiFiBerry amp and well - it just worked, playing albums and tracks from the hard drive. I turned to the Web radio options and soon had the BBC World Service coming through load and clear (sitting there with my headphones it could have been a clip from an old 1960’s spy film – although there was no short-wave crackle and I was not wearing a hat).</div>
<div>
<br /></div>
<div>
So with a working sound source it was time to stop and take stock (actually I should try Mopidy soon as that is Python based and thus potentially susceptible to some constructive hacks).</div>
<div>
<br /></div>
<div>
On the face of it Volumio might look like a good start point for further development. I am no fan of PHP but how bad could it be? However, the Volumio project has now started a complete re-write using Node.js. Now that is probably the best current start point for a new project of this nature but this does imply that future releases might be “feature incomplete” and that not much attention is going to be paid to moving the current release forward (this is not a criticism – just a comment).</div>
<div>
<br /></div>
<div>
Everything tried thus far has been based upon a custom distro which presumably greatly simplifies the task of distributing software updates (as well as integrating any developments with core OS changes). This does make the process of adding custom additions (like a CD “ripper” and IR interface) a teensy bit problematic. I am assuming that the additional power of the Pi2 will compensate for any extra “drag” from any software mods and additions I make – but that we will have to see.</div>
<div>
<br /></div>
<div>
I will next dig out a pair of old Mission monitor speakers I have in the garage and give them a try – cranking up the output to see just what this little rig can deliver.</div>
<div>
<br /></div>
<div>
One sad note – I had hoped that this little project could deliver BBC radio output (2, 4 and 5 anyway) and thus preclude the medium term purchase of a DAB radio for my office space. Turns out that earlier in the year the Beeb retreated into their iPlayer and websites so they could control (read stop) who got to hear the output based upon a proxy for location (IP address). I am not at all sure how to view this – particularly as I though the BBC had a mission to communicate with the world and not just those who pay the UK license fee. The continued availability of the World Service channel just sort of underlines this parochialism.<br />
<br />
<b>Speaker Update:</b><br />
<br />
The amp drove the speakers very well indeed. Loads of power - going to be as loud as anyone would want even in a large room. Not set up for a more discerning listening test yet but the "sound stage" was clearly evident and I could not detect any obvious amplifier induced distortion.</div>
</div>
<div>
<br /></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-35255950888096589522015-11-16T08:20:00.000-08:002015-11-25T01:18:24.721-08:00And This Week’s Language is F#<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
What? Why? Are you going to endlessly post indecipherable and
incomprehensible snippets and rants on functional programming like those Haskell
types? (Just joking guys – honest.) Well at least I can’t bang on about Monads
as F# does not have them (‘cos the close equivalent are called “Computation
Expressions”)<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Continuing on my “meta” travels I started to look at what
was available to the .NET developer in the general field of “numerics”. Linear
Algebra, Regression, Optimization, Time Series Analysis and beyond – hopefully with
a liberal license. There are a lot out there but an interesting subset were
clearly developed in F# - time to clone the odd GitHub repository (and also see
what Nuget could provide as packages) and see if I could make sense of anything.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
You might be interested by Microsoft Research’s “Tabular” <a href="http://research.microsoft.com/en-us/projects/tabular/">http://research.microsoft.com/en-us/projects/tabular/</a><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Or Deedle from BlueMountain Capital <a href="http://blogs.msdn.com/b/fsharpteam/archive/2013/11/13/announcing-deedle-data-frame-and-time-series-package-for-exploratory-data-programming-with-f-and-c.aspx">http://blogs.msdn.com/b/fsharpteam/archive/2013/11/13/announcing-deedle-data-frame-and-time-series-package-for-exploratory-data-programming-with-f-and-c.aspx</a><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Or indeed<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span lang="FR">Cronos </span><span lang="FR"><a href="http://cronos.codeplex.com/">http://cronos.codeplex.com/</a></span><span lang="FR"><o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Math.NET <span lang="FR"><span lang="EN-GB"><a href="http://numerics.mathdotnet.com/">http://numerics.mathdotnet.com/</a></span></span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="FR"><br /></span></div>
<div class="MsoNormal">
Meta Numerics <a href="http://metanumerics.codeplex.com/">http://metanumerics.codeplex.com/</a><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Of course R.NET <a href="http://nugetmusthaves.com/Package/R.NET.Community">http://nugetmusthaves.com/Package/R.NET.Community</a>
to “wrap” the R statistical package <a href="https://www.r-project.org/">https://www.r-project.org/</a>
<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
And lots more…<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Please don’t get the impression these are all F# projects
but it does look like F# has a distinct appeal to the people that build them
and those that use them.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
You may already have F# as an optional programming language
available within your copy of Visual Studio but VS2015 installed the option “on
the fly” for me after I cloned “Tabular” from GitHub. After that I did a quick
search on my C: drive for fsi.exe (the F# interactive console), located it
among the Microsoft SDKs and then created a desktop shortcut. Once double
clicked, this allowed me to try out some of the tutorial stuff on the web –
just to get familiar with the basics of the language. Yes, in that respect at
least it does feel a bit like Python – but with the comfortable option to
compile code and include it in a C# app. Did I say comfortable? F# is
distinctive – say that for it.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN3zFnNbuxDvN6yo98o6IBldvM4Dpv3lOwRFP82JSb4e7A4cPNwWt9IC75tsJfdvXBD6XOWrunCLTVzxsYVSomsrwSe01iRzQWeSq-1l2GXDj9L6CeCeA_nLhdS8yAJP_iMG_Slw/s1600/fsiwindow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="428" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN3zFnNbuxDvN6yo98o6IBldvM4Dpv3lOwRFP82JSb4e7A4cPNwWt9IC75tsJfdvXBD6XOWrunCLTVzxsYVSomsrwSe01iRzQWeSq-1l2GXDj9L6CeCeA_nLhdS8yAJP_iMG_Slw/s640/fsiwindow.png" width="640" /></a></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
At first glance the variable assignment statements above
look like those of many other languages – the double semi-colons by the way are
a feature of the interactive interpreter as they indicate that a statement is
complete – which is a marker for some of what is to come.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
First off, variables are not variables but immutable values
and are thus referred to as values. Well except when they are not (because
sometimes you might need to switch to an imperative style or do stuff like
populate and save data records) and that is when you use the mutable keyword:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
> Let mutable x = 8;;<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
With a special mutable assignment operator:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
> X <- 23;;<o:p></o:p></div>
<div class="MsoNormal">
> x;;<o:p></o:p></div>
<div class="MsoNormal">
Val it : int = 10 <span style="color: #274e13;">\\the
fsi output</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
But I am wandering from the point – stick with values are immutable.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Functions are simply defined:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
> let addfunction x y = x + y;;<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Which defines a function that takes two integers and returns
their integer sum. Did I mention that F# is (very) strongly typed? Probably
not. I did not define any types in the code statements above but F# inferred a
type – that defaults to integer. I could have written<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
> let addfunction (x : float) (y : float) = x + y;;<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
But what I could not have done (unlike most languages) is
write<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
> let addfunction (x : float) ( y : int) = x + y;;<o:p></o:p></div>
<div class="MsoNormal">
<span style="color: red;">error the type ‘int’ does not match the
type ‘float’<o:p></o:p></span></div>
<div class="MsoNormal">
<span style="color: red;"><br /></span></div>
<div class="MsoNormal">
F# does not support implicit casts even safe ones like int
to int64.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
> let addfunction (x : float) ( y : int) = x + (float y);;
<span style="color: #274e13;"> // works though, with the explicit
cast</span>.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Here is a longer function –<a href="http://mikeoncode.blogspot.co.uk/2015/10/c-memoization.html"> our old friend Fibonacci </a>– and no
I have not yet figured out how to memoize it:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
let rec fib = function<br />
| 0 -> 0<br />
| 1 -> 1<br />
| n -> fib (n – 1) + fib
(n – 2)<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The “rec” keyword indicates the function is recursive
(despite that being obvious) and you can clearly see something similar to a
switch statement and “arrow notation” indicating the values to be returned. <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Going back to a
simpler form – say:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
let addString x y = (x + y).ToString();;<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
the ToString() bit looks .NET normal shall we call it but if
you type it into fsi.exe you get the following response:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
val addString : x:int -> y:int -> string<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
and this needs exploring. The implication is that the second
parameter is passed to a function that returns a string and the first integer
parameter is passed to a function that returns an integer. This would (broadly)
be correct as F# functions only take a single argument and only return a single
type. So how is that? F# automatically curries functions. See <a href="https://en.wikipedia.org/wiki/Currying">https://en.wikipedia.org/wiki/Currying</a>
for a quick dip into currying if you have not played with the technique. Then pause
and thing about how that might impact upon a language where functions are not
just first class citizens but rather the whole point.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
To quote the Wikipedia article “<i>F# is a strongly typed, multi-paradigm programming language that
encompasses functional, imperative, and object-oriented programming techniques</i>.”
Which maybe understates things a bit as there does not seem much at the cutting
edge of language development left out – and all encapsulated within a
functional programming paradigm.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<o:p></o:p></div>
<div class="MsoNormal">
</div>
<div class="MsoNormal">
For the moment I will be content when I have taken on board
enough of the language syntax to be able to follow the relevant math library
code but I will be coming back to try and write something non trivial in F#.
The syntax is superficially daunting but starts to make sense as the underlying
functionality becomes a little clearer. F# feels like it could give you (like Oddball's Sherman) a very
nice “edge” (in some of life's more complex coding challenges).<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<audio controls="controls">
<source src="http://adit.co.uk/averyniceedge.mp3" type="audio/mpeg"></source>
<embed height="80px" width="100px"></embed>
Your browser does not support this audio
</audio>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="MsoNormal">
<b>Addendum:</b><br />
<br />
If you are a user of Visual Studio it is easier to run Fsi.exe withing that environment by pressing <ctrl><alt><f> with an F# project open.. The text is clearer as well.<br />
<br />
F# is more that somewhat absorbing - although it does suffer from the "this is the only way" crowd banging on a bit. I can see my next side project might be C# for the UI and F# for all the functionality which would be a neat solution solving some of the issues raised by Python - and hey guess what? F# borrowed the concept of "significant white-space" from that very source (plus a few other bits I think).</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-31870665605094646972015-10-16T04:20:00.000-07:002015-11-03T04:48:02.157-08:00Constructing and compiling C# using Roslyn<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
The optimal path for my current project requires the ability
to create and use new classes at runtime. The alternatives all look rather
clumsy while this approach looked elegant.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
.NET has had some capacity to compile arbitrary code since
the beginning but a lot of effort has recently gone in to a new compiler –
known as Roslyn. On the face of it there are two ways towards my goal – use the
CodeDom which is language agnostic or try out the newer (Microsoft) open source
Roslyn technology that is designed to compile C# and VB.NET. <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
CodeDom and Roslyn are only partly related and after some
research it looked like Roslyn was the way ahead as it provides a feature
complete compiler for my language of choice C#. The other major plus is that Roslyn runs “in process” while CodeDom runs compiles through another executable with
(perhaps) a rather clunky API.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
If you fancy going the well tried CodeDom way then MSDN has
a good code example towards the <a href="https://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider(v=VS.100).aspx">bottom of this article</a>.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
To add the Roslyn tooling to a project use the NuGet Package
Manager option on the Tools menu and Choose “Manage NuGet Packages for Solution…”
Select nuget.org as the package source and then search for “Microsoft.CodeAnalysis”.
Click on Microsoft.CodeAnalysis.CSharp , click the “Install” button and when
offered, accept the license.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The actual development task turned out to be pretty steady.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
I started with a class to define the properties of the class
to be constructed<o:p></o:p></div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">internal</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">ClassProperty</span>
{
<span style="color: blue;">public</span> <span style="color: blue;">string</span> PropertyName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; } = <span style="color: #a31515;">""</span>;
<span style="color: blue;">public</span> <span style="color: blue;">string</span> DataType { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; } = <span style="color: #a31515;">""</span>;
<span style="color: blue;">public</span> ClassProperty() { }
<span style="color: blue;">public</span> ClassProperty(<span style="color: blue;">string</span> propertyName, <span style="color: blue;">string</span> dataType)
{
PropertyName = propertyName;
DataType = dataType;
}
}
</div>
</code></pre>
<div class="MsoNormal">
And supplied a populated <span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">List</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"><</span><span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">ClassProperty</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">></span><span style="font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"> </span>to a new class that
I was going to use to construct and compile the code. In fact I created a
little method to loop through the fields of a database table and populate the
list (as that was the direction I was going in and I am lazy) but a List can be
quickly populated with just a few lines of code.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The new class also had properties exposed for a namespace,
class name, using directives, inheritance and interfaces. (The latter two are
part implemented in the following code in that they are added to the class
declaration but any related methods remain unimplemented at this stage.)<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
I backed up the property creation by creating a Dictionary
of default values and you can see how it is applied after this.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">string</span>> defaultValues = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">string</span>, <span style="color: blue;">string</span>>(<span style="color: #2b91af;">StringComparer</span>.OrdinalIgnoreCase)
{
[<span style="color: #a31515;">"string"</span>] = <span style="color: #a31515;">" = String.Empty;"</span>,
[<span style="color: #a31515;">"Int64"</span>] = <span style="color: #a31515;">" = 0;"</span>,
[<span style="color: #a31515;">"Int32"</span>] = <span style="color: #a31515;">" = 0;"</span>,
[<span style="color: #a31515;">"Int16"</span>] = <span style="color: #a31515;">" = 0;"</span>,
[<span style="color: #a31515;">"DateTime"</span>] = <span style="color: #a31515;">" = new DateTime(1970,1,1);"</span>,
[<span style="color: #a31515;">"double"</span>] = <span style="color: #a31515;">" = 0;"</span>,
[<span style="color: #a31515;">"single"</span>] = <span style="color: #a31515;">" = 0;"</span>,
[<span style="color: #a31515;">"Decimal"</span>] = <span style="color: #a31515;">" = 0;"</span>,
[<span style="color: #a31515;">"bool"</span>] = <span style="color: #a31515;">" = false;"</span>,
[<span style="color: #a31515;">"Boolean"</span>] = <span style="color: #a31515;">" = false;"</span>,
[<span style="color: #a31515;">"int"</span>] = <span style="color: #a31515;">" = 0;"</span>,
[<span style="color: #a31515;">"long"</span>] = <span style="color: #a31515;">" = 0;"</span>
};
</div>
</code></pre>
<div class="MsoNormal">
<br />
The method to create the code is pretty short.</div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: blue;">string</span> buildClassCode()
{
<span style="color: #2b91af;">StringBuilder</span> sb = <span style="color: blue;">new</span> <span style="color: #2b91af;">StringBuilder</span>();
<span style="color: blue;">foreach</span>(<span style="color: blue;">string</span> uses <span style="color: blue;">in</span> usings)
{
sb.AppendLine(<span style="color: #a31515;">"using "</span> + uses + <span style="color: #a31515;">";"</span>);
}
sb.AppendLine(<span style="color: #a31515;">"namespace "</span> + nameSpace);
sb.AppendLine(<span style="color: #a31515;">"{"</span>); <span style="color: green;">// start namespace</span>
<span style="color: blue;">string</span> classInherits = (inherits.Length > 0 || interfaces.Count > 0) ? <span style="color: #a31515;">" : "</span> + inherits : <span style="color: #a31515;">""</span>;
<span style="color: blue;">foreach</span>(<span style="color: blue;">string</span> inface <span style="color: blue;">in</span> interfaces)
{
classInherits += (classInherits.Length > 3) ? <span style="color: #a31515;">", "</span> + inface : inface;
}
sb.AppendLine(<span style="color: #a31515;">$"public class </span>{tableName}{classInherits}<span style="color: #a31515;">"</span> );
sb.AppendLine(<span style="color: #a31515;">"{"</span>); <span style="color: green;">// start class</span>
sb.AppendLine(<span style="color: #a31515;">$"public </span>{tableName}<span style="color: #a31515;">()"</span>); <span style="color: green;">// default constructor</span>
sb.AppendLine(<span style="color: #a31515;">"{}"</span>);
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">ClassProperty</span> newProperty <span style="color: blue;">in</span> classProperties)
{
sb.AppendLine(<span style="color: #a31515;">$"public </span>{newProperty.DataType}<span style="color: #a31515;"> </span>{newProperty.PropertyName}<span style="color: #a31515;"> </span>{<span style="color: #a31515;">"{ get; set;}"</span>}{defaultValues[newProperty.DataType]}<span style="color: #a31515;">"</span>);
}
sb.AppendLine(<span style="color: #a31515;">"}"</span>); <span style="color: green;">// end class</span>
sb.AppendLine(<span style="color: #a31515;">"}"</span>); <span style="color: green;">// end namespace</span>
<span style="color: blue;">return</span> sb.ToString();
}
</div>
</code></pre>
<div class="MsoNormal">
I tested this by popping the output into a multi-line
textbox. while the code lacks indentation it is perfectly clear as the image
below shows<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTNi0XtNQ9WhmBdeVU48WT5-r2qu45vf4TMxac2DEnUC35YkEeK3a5Bpi3B_7TE-H-djgD3LeRS_0DJGtNk8KL8NfM7WpnEmqn-hA74NuBx05Y3-akF2jNyT4deH1m0ChcIg33vg/s1600/codegenScreenShot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTNi0XtNQ9WhmBdeVU48WT5-r2qu45vf4TMxac2DEnUC35YkEeK3a5Bpi3B_7TE-H-djgD3LeRS_0DJGtNk8KL8NfM7WpnEmqn-hA74NuBx05Y3-akF2jNyT4deH1m0ChcIg33vg/s400/codegenScreenShot.png" width="400" /></a></div>
<br />
<div class="MsoNormal">
Now to get that code compiled and run an initial test using
VS Debug mode to step through the code and watch the results.<o:p></o:p></div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: blue;">void</span> buildinstance()
{
<span style="color: blue;">string</span> instance = buildClassCode();
<span style="color: #2b91af;">SyntaxTree</span> syntaxTree = <span style="color: #2b91af;">CSharpSyntaxTree</span>.ParseText(instance);
<span style="color: green;">// </span><span style="color: green;">inspect the tree</span>
<span style="color: green;">//SyntaxNode root = syntaxTree.GetRoot();</span>
<span style="color: green;">//foreach (var node in root.DescendantNodes())</span>
<span style="color: green;">//{</span>
<span style="color: green;">// var x = node.GetText();</span>
<span style="color: green;">//}</span>
<span style="color: blue;">string</span> assemblyName = tableName; <span style="color: green;">//Path.GetRandomFileName();</span>
<span style="color: #2b91af;">MetadataReference</span>[] references = <span style="color: blue;">new</span> <span style="color: #2b91af;">MetadataReference</span>[]
{
<span style="color: #2b91af;">MetadataReference</span>.CreateFromFile(<span style="color: blue;">typeof</span>(<span style="color: blue;">object</span>).Assembly.Location),
<span style="color: #2b91af;">MetadataReference</span>.CreateFromFile(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">Enumerable</span>).Assembly.Location)
};
<span style="color: #2b91af;">CSharpCompilation</span> compilation = <span style="color: #2b91af;">CSharpCompilation</span>.Create(
assemblyName,
syntaxTrees: <span style="color: blue;">new</span>[] { syntaxTree },
references: references,
options: <span style="color: blue;">new</span> <span style="color: #2b91af;">CSharpCompilationOptions</span>(<span style="color: #2b91af;">OutputKind</span>.DynamicallyLinkedLibrary)); <span style="color: green;">// you can also build as a console app, windows.exe etc</span>
<span style="color: #2b91af;">Assembly</span> assembly = <span style="color: blue;">null</span>;
<span style="color: blue;">var</span> ms = <span style="color: blue;">new</span> <span style="color: #2b91af;">MemoryStream</span>();
<span style="color: #2b91af;">EmitResult</span> eResult = compilation.Emit(ms);
<span style="color: blue;">if</span> (eResult.Success)
{
ms.Seek(0, <span style="color: #2b91af;">SeekOrigin</span>.Begin);
assembly = <span style="color: #2b91af;">Assembly</span>.Load(ms.ToArray());
<span style="color: #2b91af;">Type</span> type = assembly.GetType(nameSpace + <span style="color: #a31515;">"."</span> + tableName);
<span style="color: blue;">object</span> newObject = <span style="color: #2b91af;">Activator</span>.CreateInstance(type);
<span style="color: green;">// now we can prove that worked by stepping through the code while iterating over the properties</span>
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">PropertyInfo</span> propertyInfo <span style="color: blue;">in</span> newObject.GetType().GetProperties())
{
<span style="color: blue;">string</span> pName = propertyInfo.Name;
<span style="color: blue;">string</span> dataType = propertyInfo.PropertyType.Name;
<span style="color: green;">// and test we can assign a value</span>
<span style="color: blue;">if</span> (dataType.Equals(<span style="color: #a31515;">"String"</span>, <span style="color: #2b91af;">StringComparison</span>.OrdinalIgnoreCase))
{
propertyInfo.SetValue(newObject, <span style="color: #a31515;">"foo"</span>, <span style="color: blue;">null</span>);
}
}
}
<span style="color: blue;">else</span>
{
<span style="color: #2b91af;">IEnumerable</span><<span style="color: #2b91af;">Diagnostic</span>> failures = eResult.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError || diagnostic.Severity == <span style="color: #2b91af;">DiagnosticSeverity</span>.Error);
<span style="color: blue;">string</span> msg = <span style="color: #a31515;">""</span>;
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">Diagnostic</span> diagnostic <span style="color: blue;">in</span> failures)
{
msg+= <span style="color: #a31515;">$"</span>{diagnostic.Id}<span style="color: #a31515;">: </span>{diagnostic.GetMessage()}<span style="color: #a31515;">"</span> + <span style="color: #a31515;">"\r\n"</span>;
}
<span style="color: green;">// do something useful with the message</span>
}
ms.Close();
ms.Dispose();
}
</div>
</code></pre>
Ran first time, although I went back and added the diagnostics you can see just to step throght things as they happened.<br />
<br />
<div class="MsoNormal">
The <span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">SyntaxTree</span>
built a structure for the code elements from the string. The <span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">CSharpCompilation</span> object took that
syntax tree and compiled the code as C#. The compiled assembly was saved into a
memory stream and the compilation results checked for errors. Assuming no
errors, the code was loaded into an <span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-ansi-language: EN-GB; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-highlight: white;">Assembly</span> object and a new instance of the compiled object
(class in this instance) created and inspected.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Next I checked that I could execute a method on the compiled
class. I added the following line to the class code creation method:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
sb.AppendLine(<span style="color: #a31515;">"public string getBar(string foo) {return foo + \" bar\";}"</span>);
</div>
</code></pre>
<div class="MsoNormal">
<br />
<div class="MsoNormal">
and a code line to call the method after the object is
created in the <span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">buildinstance()</span><span style="font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"> </span>method tested above<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">string</span> res = (<span style="color: blue;">string</span>)type.InvokeMember(<span style="color: #a31515;">"getBar"</span>, <span style="color: #2b91af;">BindingFlags</span>.Default | <span style="color: #2b91af;">BindingFlags</span>.InvokeMethod,
<span style="color: blue;">null</span>, newObject, <span style="color: blue;">new</span> <span style="color: blue;">object</span>[] { <span style="color: #a31515;">"foo"</span> });
</div>
</code></pre>
<div class="MsoNormal">
<br />
<div class="MsoNormal">
which returned the string “foo bar” to the variable res.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Job done.<br />
<br />
<div class="MsoNormal">
<b>Addendum</b><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Thought I would check that the default class constructor was
executed when the compiled object instance was created. Thought it must be but…<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Adjusted the class constructor to set one of the properties
and then read that back when looping over the properties. Worked as expected.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="line-height: 13.15pt;">The <span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; mso-highlight: white;">Activator</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt;">.CreateInstance()</span><span style="font-family: "consolas"; font-size: 9.5pt;"> </span>method can be called with a parameter list to actuate alternate constructors with their parameters thus:<o:p></o:p>
</pre>
<pre style="line-height: 13.15pt;"><span style="color: blue;">public</span> <span style="color: blue;">static</span> <span style="color: blue;">object</span> CreateInstance(Type type, <span style="color: blue;">params</span> <span style="color: blue;">object</span>[] args)<o:p></o:p></pre>
<br />
<div class="MsoNormal">
which probably covers that issue as an Interface can’t
contain a constructor but can contain any other methods I want to expose.
Clearly, there is a wee bit more code to write to get a practical
implementation but it is also clear that the overall approach is very
practical.<o:p></o:p><br />
<br />
<div class="MsoNormal">
<b>And Then The Real World</b><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
In the real world your compiled class will probably
reference one or more System/.NET dll, a custom library or your new class may
inherit from another class already defined in the main program assembly.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
You can add such references but you need to supply the path
to the relevant dll or exe file. Apparently this changed from early Roslyn
releases so (like me) you might find many obsolete methods if you Google around
the subject. You also need to include the relevant "using" statements in the code itself of course (see above).<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
In my first stab at this the <span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">CSharpCompilation</span> constructor was supplied with a
default array of <span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">MetadataReference</span>
objects. This array can be extended to include whatever is required.</div>
<br />
<div class="MsoNormal">
The default location for the main System dlls can be found
with this line of code:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span style="background: white; color: blue; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">var</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"> assemblyPath = </span><span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">Path</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">.GetDirectoryName(</span><span style="background: white; color: blue; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">typeof</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">(</span><span style="background: white; color: blue; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">object</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">).Assembly.Location);</span><o:p></o:p></div>
<div class="MsoNormal">
<span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal">
<span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"></span></div>
<div class="MsoNormal">
You can then construct a path to (say) System.dll and
Syatem.Data.dll like so:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">string</span> sysTm = <span style="color: #2b91af;">Path</span>.Combine(assemblyPath, <span style="color: #a31515;">"System.dll"</span>);
<span style="color: blue;">string</span> sysData = <span style="color: #2b91af;">Path</span>.Combine(assemblyPath, <span style="color: #a31515;">"System.Data.dll"</span>);
</div>
</code></pre>
<div class="MsoNormal">
<br />
<div class="MsoNormal">
You can similarly construct the path to the classes in your
own program as well (assuming they are public):<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span style="background: white; color: blue; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">string</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"> mePath = </span><span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">Path</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">.Combine(</span><span style="background: white; color: #2b91af; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">Application</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">.StartupPath, </span><span style="background: white; color: #a31515; font-family: "consolas"; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">"MyProg.exe"</span><span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;">);</span><o:p></o:p></div>
<div class="MsoNormal">
<span style="background: white; font-family: "consolas"; font-size: 9.5pt; line-height: 107%;"><br /></span></div>
<br />
<div class="MsoNormal">
The paths can then be used to add the references like so:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: #2b91af;">MetadataReference</span>[] references = <span style="color: blue;">new</span> <span style="color: #2b91af;">MetadataReference</span>[]
{
<span style="color: #2b91af;">MetadataReference</span>.CreateFromFile(<span style="color: blue;">typeof</span>(<span style="color: blue;">object</span>).Assembly.Location),
<span style="color: #2b91af;">MetadataReference</span>.CreateFromFile(<span style="color: blue;">typeof</span>(<span style="color: #2b91af;">Enumerable</span>).Assembly.Location),
<span style="color: #2b91af;">MetadataReference</span>.CreateFromFile(sysTm),
<span style="color: #2b91af;">MetadataReference</span>.CreateFromFile(sysData),
<span style="color: #2b91af;">MetadataReference</span>.CreateFromFile(mePath)
};
</div>
</code></pre>
<div class="MsoNormal">
<br />
<div class="MsoNormal">
And that is how to add those vital references to your Roslyn compiled assembly.<o:p></o:p></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]2tag:blogger.com,1999:blog-21052732.post-52896997753035027642015-10-13T04:49:00.000-07:002015-10-16T08:33:58.767-07:00Interfaces and Unknown Classes<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
I wanted to make use of the <a href="http://mikeoncode.blogspot.co.uk/2015/10/reading-excel-with-open-xml-sdk.html">ExcelReader class I created</a> as a
source of data to create class instances. <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Generally the classes in question inherit from a base class
that also knows how to save itself to a database. I could, of course maintain a
list of such classes within my Excel reading code and call an appropriate
routine as required. However I had in mind to create something that was generic
enough to handle a whole raft of classes – including some created and compiled “on
the fly” and thus unknowable to the source code.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The normal method for dealing with a range of classes
through a common function would be to specify an interface common to all and
then to interact through that interface.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
Interfaces (if this is an unfamiliar term)<o:p></o:p></div>
<br />
<div class="MsoNormal" style="margin-left: 36.0pt;">
An interface is a list of public
properties and methods (also indexers and events) that <s>should</s> must be exposed
by a class that implements the interface. Interfaces themselves can be
inherited but contain no actual code – just the signatures (if you like) of the
components being specified.<o:p></o:p></div>
<div class="MsoNormal" style="margin-left: 36.0pt;">
<br /></div>
<div class="MsoNormal" style="margin-left: 36.0pt;">
One of the simplest ways of
creating an interface is to (VS2015) right click on the class name in the code
window and select “Extract Interface” from the “Quick Actions” context menu.
Earlier versions of Visual Studio offer a “Refactor” menu option that includes
extracting an interface.<o:p></o:p></div>
<div class="MsoNormal" style="margin-left: 36.0pt;">
<br /></div>
<div class="MsoNormal" style="margin-left: 36.0pt;">
Requiring a specific Interface is
an excellent way of ensuring that objects calling the functionality of a class you
provide supply full support. You can rely upon a method or event handler being
available – even if it just a “stub”. IComparable would be a good example of
just such an interface.<o:p></o:p></div>
<div class="MsoNormal" style="margin-left: 36.0pt;">
<br /></div>
<div class="MsoNormal" style="margin-left: 36.0pt;">
I have used interfaces in the
past for testing alternate algorithms. An interface allowed me to construct a
standardised software socket into which I could plug different classes at will.
I could thus test performance and function of alternate approaches without
having to change the code “consuming” the service/process.<o:p></o:p></div>
<div class="MsoNormal" style="margin-left: 36.0pt;">
<br /></div>
<div class="MsoNormal" style="margin-left: 36.0pt;">
If I come across a great in depth
web page on Interfaces I will post a link here but for a couple of helpful
examples you can do a lot worse than this <a href="http://www.csharp-station.com/Tutorial/CSharp/Lesson13">C# Station post</a> <o:p></o:p></div>
<br />
<div class="MsoNormal">
Just about the only thing my target classes have in common is
an Update method. This limits the scope of any Interface a bit. The properties
could be addressed through reflection and it was a reasonable bet that a class
Clone() method could be used to create new class instances. So that was
beginning to sound like a workable strategy.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
So my interface ended up being defined like this:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">interface</span> <span style="color: #2b91af;">ObjectClone</span>
{
<span style="color: blue;">object</span> CloneAsObject();
<span style="color: blue;">void</span> UpdateClass();
}
</div>
</code></pre>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<div class="MsoNormal">
Each
class implementing the interface needs then to add a CloneAsObject method
alongside an UpdateClass method. The CloneAsObject() method is very simple:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">public</span> <span style="color: blue;">object</span> CloneAsObject()
{
<span style="color: blue;">return</span> (<span style="color: #2b91af;">MyClassName</span>)<span style="color: blue;">this</span>.MemberwiseClone();
}
</div>
</code></pre>
<div class="MsoNormal">
<br />
There is an assumption here that all such classes expose public properties for all of the key data elements.<br />
<br /></div>
<div class="MsoNormal">
<div class="MsoNormal">
I
defined an ExcelDataLoader class that will use an instance of the <a href="http://mikeoncode.blogspot.co.uk/2015/10/reading-excel-with-open-xml-sdk.html">ExcelReaderclass</a> to gather data from selected columns in a spreadsheet and use this data
to create instances of a class that implements that very simple ObjectClone
Interface.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
The ExcelDataLoader
class needs a local definition and a public property:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">ObjectClone</span> targetClass = <span style="color: blue;">null</span>;
<span style="color: blue;">public</span> <span style="color: #2b91af;">ObjectClone</span> TargetClass
{
<span style="color: blue;">set</span> { targetClass = <span style="color: blue;">value</span>; }
}
</div>
</code></pre>
<div class="MsoNormal">
<div class="MsoNormal">
To pass in a <b>new</b>
instance of the required class.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Plus I also needed a way of passing the required
instructions to the ExcelDataLoader. A simple class to define the required
columns and the associated data name and type seemed the thing and that could
be as simple as:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">public</span> <span style="color: blue;">class</span> <span style="color: #2b91af;">ExcelColumnData</span> : <span style="color: #2b91af;">IComparable</span>
{
<span style="color: blue;">public</span> <span style="color: blue;">string</span> ColumnName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; } = <span style="color: #a31515;">""</span>;
<span style="color: blue;">public</span> <span style="color: blue;">string</span> DataName { <span style="color: blue;">get</span>; <span style="color: blue;">set</span>; } = <span style="color: #a31515;">""</span>;
<span style="color: blue;">public</span> ExcelColumnData()
{
}
<span style="color: blue;">public</span> ExcelColumnData(<span style="color: blue;">string</span> ColumnName, <span style="color: blue;">string</span> DataName)
{
<span style="color: blue;">this</span>.ColumnName = ColumnName;
<span style="color: blue;">this</span>.DataName = DataName;
}
<span style="color: blue;">public</span> <span style="color: blue;">int</span> CompareTo(<span style="color: blue;">object</span> objx)
{
<span style="color: #2b91af;">ExcelColumnData</span> x = (<span style="color: #2b91af;">ExcelColumnData</span>)objx;
<span style="color: blue;">int</span> res = <span style="color: blue;">this</span>.ColumnName.Length.CompareTo(x.ColumnName.Length);
<span style="color: blue;">return</span> (res == 0) ? <span style="color: blue;">this</span>.ColumnName.CompareTo(x.ColumnName) : res; <span style="color: green;">// AA after Z</span>
}
}
</div>
</code></pre>
<div class="MsoNormal">
<br /></div>
</div>
<div class="MsoNormal">
<div class="MsoNormal">
Although you will note that this class implements an
interface – Icomparable so that List<T>Sort() can be used to ensure the
columns are presented in order.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
These column definitions could then be passed as a List<ExcelColumndData>
to the ExcelDataLoader class.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
</div>
</div>
</div>
<div class="MsoNormal">
The ExcelDataLoader class loadData() method uses an instance
of the ExcelReader class to extract some columns of data from a specified sheet
and then creates an instance of the class to be created. It then uses
reflection to loop through the class properties and if one of these matches a
specified data name associated with an Excel data column then the expected data
type is checked and an attempt made to cast (or parse) the data extracted from
Excel to the required type. If the parse works then the property is set to the
excel value.<o:p></o:p></div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: blue;">int</span> loadData()
{
<span style="color: blue;">int</span> recCount = 0;
excelReader = <span style="color: blue;">new</span> <span style="color: #2b91af;">ExcelReader</span>(excelFilepath, sheetName);
<span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> colNames = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>();
<span style="color: blue;">if</span>(excelColumns.Count > 1) { excelColumns.Sort(); }
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">ExcelColumnData</span> eColData <span style="color: blue;">in</span> excelColumns)
{
colNames.Add(eColData.ColumnName);
}
<span style="color: #2b91af;">List</span><<span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>> selCols = excelReader.GetSelectedColumns(colNames, skipFirstRow);
<span style="color: blue;">foreach</span>(<span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> excelRow <span style="color: blue;">in</span> selCols)
{
<span style="color: #2b91af;">ObjectClone</span> newObject = (<span style="color: #2b91af;">ObjectClone</span>)targetClass.CloneAsObject();
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">PropertyInfo</span> propertyInfo <span style="color: blue;">in</span> newObject.GetType().GetProperties())
{
<span style="color: blue;">if</span> (propertyInfo.CanWrite)
{
<span style="color: blue;">string</span> propertyName = propertyInfo.Name;
<span style="color: blue;">string</span> dataType = propertyInfo.PropertyType.Name;
<span style="color: blue;">for</span>(<span style="color: blue;">var</span> eci=0; eci< excelColumns.Count; eci++)
{
<span style="color: blue;">if</span> (excelColumns[eci].DataName.Equals(propertyName, <span style="color: #2b91af;">StringComparison</span>.OrdinalIgnoreCase))
{
<span style="color: green;">// the strategy is to set the Property value if the incoming data is valid for the Property type</span>
<span style="color: green;">// otherwise the value is left as the class default setting</span>
<span style="color: blue;">if</span> (dataType.Equals(<span style="color: #a31515;">"String"</span>, <span style="color: #2b91af;">StringComparison</span>.OrdinalIgnoreCase))
{
propertyInfo.SetValue(newObject, excelRow[eci], <span style="color: blue;">null</span>);
} <span style="color: blue;">else</span> <span style="color: blue;">if</span> (dataType.Equals(<span style="color: #a31515;">"Int64"</span>, <span style="color: #2b91af;">StringComparison</span>.OrdinalIgnoreCase))
{
<span style="color: blue;">long</span> intVal = 0;
<span style="color: blue;">if</span> (<span style="color: blue;">long</span>.TryParse(excelRow[eci], <span style="color: blue;">out</span> intVal))
{
propertyInfo.SetValue(newObject, intVal, <span style="color: blue;">null</span>);
}
} <span style="color: blue;">else</span> <span style="color: blue;">if</span> (dataType.Equals(<span style="color: #a31515;">"Int32"</span>, <span style="color: #2b91af;">StringComparison</span>.OrdinalIgnoreCase))
{
<span style="color: blue;">int</span> intVal = 0;
<span style="color: blue;">if</span> (<span style="color: blue;">int</span>.TryParse(excelRow[eci], <span style="color: blue;">out</span> intVal))
{
propertyInfo.SetValue(newObject, intVal, <span style="color: blue;">null</span>);
}
} <span style="color: blue;">else</span> <span style="color: blue;">if</span> (dataType.Equals(<span style="color: #a31515;">"Int16"</span>, <span style="color: #2b91af;">StringComparison</span>.OrdinalIgnoreCase))
{
<span style="color: #2b91af;">Int16</span> intVal = 0;
<span style="color: blue;">if</span> (<span style="color: #2b91af;">Int16</span>.TryParse(excelRow[eci], <span style="color: blue;">out</span> intVal))
{
propertyInfo.SetValue(newObject, intVal, <span style="color: blue;">null</span>);
}
} <span style="color: green;">... etc</span>
<span style="color: green;"> ''' </span>
<span style="color: green;"> ...</span>
}
}
}
newObject.UpdateClass();
recCount++;
}
<span style="color: blue;">return</span> recCount;
}
</div>
</code></pre>
<br />
And you can pump data from Excel (or anywhere else) to create classes that are anonymous as far as the process is concerned and (in this instance) call a method to retain the data in a database for future use.<br />
<br />
Usual caveats as this is prototype (although working) code and my production version will inevitably grow "horns" over time as I deal with edge cases and extra features.<br />
<br /></div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-89306129812243665682015-10-09T03:28:00.000-07:002015-10-13T05:38:44.306-07:00Reading Excel with the Open XML SDK<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<div class="MsoNormal">
A while back I posted <a href="http://mikeoncode.blogspot.co.uk/2015/03/look-mum-no-office.html">Look Mum no Office</a> on the subject of the Microsoft Open XML SDK that I had used for writing an
Excel file without the need for a copy of Office on the machine running the
code. This proved to be very straightforward and there was some <a href="http://mikesknowledgebase.azurewebsites.net/pages/CSharp/ExportToExcel.htm">excellent samplecode available</a> <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Yesterday I needed to read data from an Excel workbook and
decided to write a class that I could use in multiple scenarios to grab data
from this source. Using the Open XML SDK looked the way to go as this should
work with all Excel files produced by versions after Office 2003.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
First use the Package Manager to grab the support libraries<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span style="background: white; color: #222222; font-family: "Courier New"; font-size: 10.0pt; line-height: 107%;">PM> Install-Package
DocumentFormat.OpenXml</span><o:p></o:p></div>
<div class="MsoNormal">
<span style="background: white; color: #222222; font-family: "Courier New"; font-size: 10.0pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal">
And then add WindowsBase.dll to the project references (it
is in the Framework Assembly list so easy to spot using the “Add Reference”
dialog.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
My first Excel reading class function was to read the list
of Sheet Names in a workbook.<o:p></o:p></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> getSheetNames()
{
<span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>> sheetNames = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>();
<span style="color: blue;">try</span>
{
<span style="color: blue;">var</span> document = <span style="color: #2b91af;">SpreadsheetDocument</span>.Open(excelFilePath, <span style="color: blue;">false</span>);
<span style="color: blue;">var</span> workbookPart = document.WorkbookPart;
<span style="color: blue;">var</span> sheets = workbookPart.Workbook.Descendants<<span style="color: #2b91af;">Sheet</span>>();
<span style="color: blue;">foreach</span>(<span style="color: #2b91af;">Sheet</span> sheet <span style="color: blue;">in</span> sheets)
{
sheetNames.Add(sheet.Name);
}
document.Close();
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ex)
{
<span style="color: #2b91af;">...</span>
}
<span style="color: blue;">return</span> sheetNames;
}
</div>
</code></pre>
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
This was a good
indicator that this process was going to be pretty steady although there were a
couple of twists coming up (with all making sense when thought about).<o:p></o:p></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
I wanted my class to
have two further main features. One to take a sample of rows from a specified
sheet and another to extract defined columns from a specified sheet. As both
cover similar ground, let’s look at the development of the sample row extract.<o:p></o:p></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<br /></div>
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
The process is 1.
Identify the worksheet, 2. Grab the sheet, 3. Extract the sheet data and then 4
Loop through the Rows in the sheet data. Within each row we can loop through
the cells and read the string content.<o:p></o:p></div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>> initialGetSampleRows()
{
<span style="color: #2b91af;">List</span><<span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>> samples = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>>();
<span style="color: blue;">try</span>
{
<span style="color: blue;">int</span> selCount = 0;
<span style="color: blue;">var</span> document = <span style="color: #2b91af;">SpreadsheetDocument</span>.Open(excelFilePath, <span style="color: blue;">false</span>);
<span style="color: blue;">var</span> workbookPart = document.WorkbookPart;
<span style="color: blue;">var</span> sheets = workbookPart.Workbook.Descendants<<span style="color: #2b91af;">Sheet</span>>();
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">Sheet</span> sheet <span style="color: blue;">in</span> sheets)
{
<span style="color: blue;">if</span> (sheet.Name == sheetName)
{
<span style="color: blue;">var</span> workSheet = ((<span style="color: #2b91af;">WorksheetPart</span>)workbookPart.GetPartById(sheet.Id)).Worksheet;
<span style="color: blue;">var</span> sheetData = workSheet.Elements<<span style="color: #2b91af;">SheetData</span>>().First();
<span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Row</span>> rows = sheetData.Elements<<span style="color: #2b91af;">Row</span>>().ToList();
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">Row</span> row <span style="color: blue;">in</span> rows)
{
<span style="color: blue;">var</span> thisRow = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>();
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">Cell</span> cell <span style="color: blue;">in</span> row.Descendants<<span style="color: #2b91af;">Cell</span>>())
{
<span style="color: blue;">var</span> cellContent = cell.CellValue;
thisRow.Add((cellContent == <span style="color: blue;">null</span>) ? cell.InnerText : cellContent.Text);
}
samples.Add(thisRow);
selCount++;
<span style="color: blue;">if</span> (selCount >= sampleRowCount)
{
<span style="color: blue;">break</span>;
}
}
<span style="color: blue;">break</span>;
}
}
document.Close();
}
<span style="color: blue;">catch</span> (<span style="color: #2b91af;">Exception</span> ex)
{
<span style="color: #2b91af;">...</span>
}
<span style="color: blue;">return</span> samples;
}
</div>
</code></pre>
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
Does it work? Well there
are a few snags. Dates are (perhaps not unexpectedly) showing as a number,
numbers themselves are fine but cells with a string content are being read as
an integer of some sort.<o:p></o:p></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<br /></div>
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
Turns out that strings
are held in a shared string table so we need to change the code to read that
table when required based on the cell DataType ("s"). <o:p></o:p></div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">Cell</span> cell <span style="color: blue;">in</span> row.Descendants<<span style="color: #2b91af;">Cell</span>>())
{
<span style="color: blue;">var</span> cellContent = cell.CellValue;
<span style="color: blue;">var</span> cellText = (cellContent == <span style="color: blue;">null</span>) ? cell.InnerText : cellContent.Text;
<span style="color: blue;">var</span> dataType = cell.DataType ?? <span style="color: #2b91af;">CellValues</span>.Error;
<span style="color: blue;">if</span> (dataType == <span style="color: #2b91af;">CellValues</span>.SharedString)
{
cellText = workbookPart.SharedStringTablePart.SharedStringTable.Elements<<span style="color: #2b91af;">SharedStringItem</span>>().ElementAt(<span style="color: #2b91af;">Convert</span>.ToInt32(cell.CellValue.Text)).InnerText;
}
thisRow.Add(cellText);
}
</div>
</code></pre>
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
Excel dates are stored
as an integer number of days since 31<sup>st</sup> December 1899 – so the Excel
date for 1<sup>st</sup> January 1900 is 1. There is a snag inherited for compatibility
reasons from Lotus – where the year 1900 was assumed not to be a leap year when in
fact (unlike the year 2000) it was. So the numbers are almost always out by
1. Dates are represented as human sensible dates on an Excel spreadsheet by
using a “style”. It is possible to detect a style value for a cell although
this is normally null.</div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
Something like:<o:p></o:p></div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">uint</span> styleIndex = cell.StyleIndex ?? <span style="color: blue;">uint</span>.MinValue;
<span style="color: blue;">if</span> (styleIndex == 3)
{
<span style="color: #2b91af;">Double</span> serialDate;
<span style="color: blue;">if</span> (<span style="color: #2b91af;">Double</span>.TryParse(cellText, <span style="color: blue;">out</span> serialDate))
{
<span style="color: #2b91af;">DateTime</span> cellDate = <span style="color: #2b91af;">DateTime</span>.FromOADate(serialDate);
cellText = cellDate.ToString(dateFormat);
}
}
</div>
</code></pre>
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
Where we can use the
inbuilt <span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; mso-highlight: white;">DateTime</span><span style="background: white; font-family: Consolas; font-size: 9.5pt;">.FromOADate(</span><span style="font-family: Consolas; font-size: 9.5pt;">) </span>function to handle the
conversion, applying string formatting to suite.<o:p></o:p></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
There is another snag. It would not make any sense for an
XML based Excel file to include empty cells. This means that when a row of
cells is read the row only contains cells with content. This would present a
problem where empty cells appear (perhaps now and again) before columns of
cells of interest. Fortunately each cell object contains a CellReference that can
be used to extract the Column+Row identity we are familiar with on Excel sheets.
This can be used to detect a cell being presented earlier than expected in a
row.<o:p></o:p></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
One solution (<b>now deprecated</b> - see below) is to create an Enumerator that can
manage the detection of missing cells and supply empty ones as required. The class code was re-structured a bit at this point in time as well – partly to make the
code units available to functionality to be added to the class later.<o:p></o:p></div>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<br /></div>
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
The Enumerator looks like this:<o:p></o:p></div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">IEnumerator</span><<span style="color: #2b91af;">Cell</span>> excelCellEnumerator(<span style="color: #2b91af;">Row</span> row)
{
<span style="color: blue;">int</span> currentCount = 0;
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">Cell</span> cell <span style="color: blue;">in</span> row.Descendants<<span style="color: #2b91af;">Cell</span>>())
{
<span style="color: blue;">string</span> columnName = columnNameFromReference(cell.CellReference);
<span style="color: blue;">int</span> thisColIndex = convertColumnNameToNumber(columnName);
<span style="color: blue;">while</span>(currentCount < thisColIndex)
{
<span style="color: blue;">var</span> emptyCell = <span style="color: blue;">new</span> <span style="color: #2b91af;">Cell</span>()
{
DataType = <span style="color: blue;">null</span>,
CellValue = <span style="color: blue;">new</span> <span style="color: #2b91af;">CellValue</span>(<span style="color: blue;">string</span>.Empty)
};
<span style="color: blue;">yield</span> <span style="color: blue;">return</span> emptyCell;
currentCount++;
}
<span style="color: blue;">yield</span> <span style="color: blue;">return</span> cell;
currentCount++;
}
}
</div>
</code></pre>
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
With support from:<o:p></o:p></div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: blue;">string</span> columnNameFromReference(<span style="color: blue;">string</span> cellReference)
{
<span style="color: blue;">var</span> regex = <span style="color: blue;">new</span> <span style="color: #2b91af;">Regex</span>(<span style="color: #a31515;">"[A-Za-z]+"</span>);
<span style="color: blue;">var</span> match = regex.Match(cellReference);
<span style="color: blue;">return</span> match.Value;
}
<span style="color: blue;">private</span> <span style="color: blue;">int</span> convertColumnNameToNumber(<span style="color: blue;">string</span> columnName)
{
<span style="color: blue;">char</span>[] colAlphas = columnName.ToCharArray();
<span style="color: #2b91af;">Array</span>.Reverse(colAlphas);
<span style="color: blue;">int</span> colNumber = 0;
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> i = 0; i < colAlphas.Length; i++)
{
<span style="color: blue;">char</span> alpha = colAlphas[i];
<span style="color: blue;">int</span> tAlpha = i == 0 ? alpha - 65 : alpha - 64;
colNumber += tAlpha * (<span style="color: blue;">int</span>)<span style="color: #2b91af;">Math</span>.Pow(26, i);
}
<span style="color: blue;">return</span> colNumber;
}
</div>
</code></pre>
<br />
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
And with the nitty
gritty of the sample extract function being changed to use the Enumerator thus:<o:p></o:p></div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">foreach</span>(<span style="color: #2b91af;">Row</span> row <span style="color: blue;">in</span> rows)
{
<span style="color: blue;">var</span> thisRow = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>();
<span style="color: blue;">var</span> cellEnumerator = excelCellEnumerator(row);
<span style="color: blue;">while</span> (cellEnumerator.MoveNext())
{
<span style="color: blue;">var</span> cell = cellEnumerator.Current;
<span style="color: blue;">var</span> contentString = readCellContent(cell, workbookPart);
thisRow.Add(contentString);
}
samples.Add(thisRow);
}
</div>
</code></pre>
<span style="font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%; mso-ansi-language: EN-GB; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;"><br /></span>
<span style="font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%; mso-ansi-language: EN-GB; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;">And
the reading of the cell content (all code earlier in the post) being moved to a
separate function.</span><br />
<span style="font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%; mso-ansi-language: EN-GB; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;"><br /></span>
<span style="font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%; mso-ansi-language: EN-GB; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;"><b>Addendum</b></span><br />
<span style="font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%; mso-ansi-language: EN-GB; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;"><br /></span>
<br />
<div class="MsoNormal">
A little experimentation indicated that it might also be a
good idea to make provision for Boolean values in an Excel sheet. Where Booleans
exist they are presented in Excel as TRUE and FALSE but the underlying values
are a (reasonable) 1 and 0 respectively. You can detect Boolean values using
the cell DataType which (in this instance) would be set to <span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">CellValues</span><span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;">.Boolean</span><span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;">.<o:p></o:p></span></div>
<div class="MsoNormal">
<span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;"><br /></span></div>
<div class="MsoNormal">
There
is also a CellValues enum <span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">CellValues</span><span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;">.</span><span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;">Date</span> but strangely this is not set in any of my
sample data so the original technique of inspecting the StyleIndex still
stands.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<span style="font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%; mso-ansi-language: EN-GB; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;">
</span><br />
<div class="MsoNormal">
You
might however wish to add the following code snippet to deal with Booleans:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">if</span>(dataType == <span style="color: #2b91af;">CellValues</span>.Boolean)
{
<span style="color: blue;">int</span> bVal;
<span style="color: blue;">if</span>(<span style="color: blue;">int</span>.TryParse(cellText, <span style="color: blue;">out</span> bVal))
{
<span style="color: blue;">if</span>(bVal == 0)
{
cellText = <span style="color: #a31515;">"false"</span>;
} <span style="color: blue;">else</span>
{
cellText = <span style="color: #a31515;">"true"</span>;
}
}
}
</div>
</code></pre>
<div class="MsoNormal">
<br />
<div class="MsoNormal">
Parsing the value rather than just casting it may just be
paranoia but…<o:p></o:p><br />
<br />
<div class="MsoNormal">
<b>Further Thought</b><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Of course <b>Yield
return</b> is sheer flummery in this context – although the Iterator was lots
of fun. </div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Yield should be reserved for computationally expensive processes where
you want to spread the load a bit. In this instance most or all cells are going
to be available in the Row object and so we would be better writing a function
to return the whole list of cells in one go.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Cell</span>> getExcelRowCells(<span style="color: #2b91af;">Row</span> row)
{
<span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Cell</span>> theCells = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Cell</span>>();
<span style="color: blue;">int</span> currentCount = 0;
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">Cell</span> cell <span style="color: blue;">in</span> row.Descendants<<span style="color: #2b91af;">Cell</span>>())
{
<span style="color: blue;">string</span> columnName = columnNameFromReference(cell.CellReference);
<span style="color: blue;">int</span> thisColIndex = convertColumnNameToNumber(columnName);
<span style="color: blue;">while</span> (currentCount < thisColIndex)
{
<span style="color: blue;">var</span> emptyCell = <span style="color: blue;">new</span> <span style="color: #2b91af;">Cell</span>()
{
DataType = <span style="color: blue;">null</span>,
CellValue = <span style="color: blue;">new</span> <span style="color: #2b91af;">CellValue</span>(<span style="color: blue;">string</span>.Empty)
};
theCells.Add(emptyCell);
currentCount++;
}
theCells.Add(cell);
currentCount++;
}
<span style="color: blue;">return</span> theCells;
}
</div>
</code></pre>
<div class="MsoNormal">
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
And then consume the list as before but with conventional
List<T> iteration:<o:p></o:p></div>
</div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">foreach</span> (<span style="color: #2b91af;">Row</span> row <span style="color: blue;">in</span> rows)
{
<span style="color: blue;">var</span> thisRow = <span style="color: blue;">new</span> <span style="color: #2b91af;">List</span><<span style="color: blue;">string</span>>();
<span style="color: #2b91af;">List</span><<span style="color: #2b91af;">Cell</span>> rowCells = getExcelRowCells(row);
<span style="color: blue;">foreach</span>(<span style="color: #2b91af;">Cell</span> cell <span style="color: blue;">in</span> rowCells)
{
thisRow.Add(readCellContent(cell, workbookPart));
}
samples.Add(thisRow);
selCount++;
<span style="color: blue;">if</span> (selCount >= sampleRowCount)
{
<span style="color: blue;">break</span>;
}
}
</div>
</code></pre>
</div>
</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-23339238399730810342015-10-05T10:21:00.000-07:002015-10-13T02:02:29.506-07:00C# Memoization<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
Memoization is a program optimisation technique that stores
the results of a computationally expensive function in a cache and then returns
values from that cache if the function is called again with the same input(s).<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal" style="background: white; line-height: 12.0pt;">
Wikipedia has
the term coined by (a personal hero) Donald Michie in 1968 although I can’t
find the word in the original paper (dated 1967) [link: <span style="color: #006621; font-family: "Arial",sans-serif; font-size: 10.5pt; mso-fareast-font-family: "Times New Roman"; mso-fareast-language: EN-GB;"><a href="https://saltworks.stanford.edu/assets/kr445kk4694.pdf">https://saltworks.stanford.edu/assets/kr445kk4694.pdf</a></span><span style="color: grey; font-family: "Arial",sans-serif; font-size: 12.0pt; mso-fareast-font-family: "Times New Roman"; mso-fareast-language: EN-GB;"> ] </span>so it probably came
into being as the idea was applied.<span style="color: grey; font-family: "Arial",sans-serif; font-size: 12.0pt; mso-fareast-font-family: "Times New Roman"; mso-fareast-language: EN-GB;"><o:p></o:p></span></div>
<div class="MsoNormal" style="background: white; line-height: 12.0pt;">
<br /></div>
<div class="MsoNormal">
I had previously used the technique in JavaScript but that
was a while ago and it took me a few moments to even remember the precise term –
let alone work out how to do the trick in C#.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The archetypal example of memoization in JavaScript is a
function to calculate Fibonacci numbers and I found this one on <a href="http://stackoverflow.com/">http://stackoverflow.com/</a><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
var fibonacci = (function () {
var memo = [0, 1];
var fib = function (n) {
var result = memo[n];
if (typeof result !== 'number') {
result = fib(n - 1) + fib(n - 2);
memo[n] = result;
}
return result;
};
return fib;
}());
</div>
</code></pre>
<div class="MsoNormal" style="background: rgb(238, 238, 238); margin-bottom: 0.0001pt;">
<br /></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The var fibonacci contains a function that can be used to
calculate a result. It will return a cached value for any previously requested
calculation and will recursively call itself to calculate a new value – which will
often be returned from the cache (well certainly if a sequence of values are
requested). </div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The cache takes the form of an array (memo[]) and this is wrapped
in a “closure” so that it remains accessible to the inner function fib(). </div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Closure, recursion and memorization in one function – has all the dangerous signs of an
interview question.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
I wanted a function in C# to look-up a subset of values
previously stored in a database (in this instance identity integers) with a
high likelihood that individual values would be repeatedly requested over the
run of the process but without being able to sort the requests in any
meaningful way. So assuming that database reads are relatively slow, memorization
looked like the technique to try.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
My requirement is a simple case – I have a function into
which I pass a string as a key and the function does a database lookup and
retunes a long integer. So let us start there<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: blue;">long</span> lookUpDimension(<span style="color: blue;">string</span> dkey)
{
<span style="color: blue;">long</span> idVal = 0;
<span style="color: blue;">try</span>
{
<span style="color: green;">// code to access the databse and do the lookup</span>
}
<span style="color: blue;">return</span> idVal;
}
</div>
</code></pre>
<div class="MsoNormal" style="margin-bottom: 0.0001pt;">
<br /></div>
<div class="MsoNormal">
Just a simple function (well after all the database access
code is removed for clarity). Point being – it is just an ordinary function –
takes a single argument and returns the output.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The class containing that look-up function also has two
static functions to work some magic.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">Func</span><<span style="color: #2b91af;">TArg</span>, <span style="color: #2b91af;">TResult</span>> Memoize<<span style="color: #2b91af;">TArg</span>, <span style="color: #2b91af;">TResult</span>>(<span style="color: #2b91af;">Func</span><<span style="color: #2b91af;">TArg</span>, <span style="color: #2b91af;">TResult</span>> function)
{
<span style="color: blue;">return</span> Memoize(function, <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: #2b91af;">TArg</span>, <span style="color: #2b91af;">TResult</span>>());
}
<span style="color: blue;">private</span> <span style="color: blue;">static</span> <span style="color: #2b91af;">Func</span><<span style="color: #2b91af;">TArg</span>, <span style="color: #2b91af;">TResult</span>> Memoize<<span style="color: #2b91af;">TArg</span>, <span style="color: #2b91af;">TResult</span>>(<span style="color: #2b91af;">Func</span><<span style="color: #2b91af;">TArg</span>, <span style="color: #2b91af;">TResult</span>> function, <span style="color: #2b91af;">IDictionary</span><<span style="color: #2b91af;">TArg</span>, <span style="color: #2b91af;">TResult</span>> cache)
{
<span style="color: blue;">return</span> key => cache.ContainsKey(key) ? cache[key] : (cache[key] = function(key));
}</div>
</code></pre>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
So – what is this <span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">Func</span><span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;"><</span><span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">TArg</span><span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;">, </span><span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">TResult</span><span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;">></span> stuff?<o:p></o:p><br />
<br /></div>
<div class="MsoNormal">
Func is a predefined Delegate, this one takes a single
argument in and outputs a single result. There are more defined (up to 8
inputs) and we could express the second one (2 inputs) thus:<o:p></o:p><br />
<br /></div>
<pre style="line-height: 13.15pt;"><span style="color: blue;">public</span> <span style="color: blue;">delegate</span> TResult Func<<span style="color: blue;">in</span> T1, <span style="color: blue;">in</span> T2, <span style="color: blue;">out</span> TResult>(<o:p></o:p></pre>
<pre style="line-height: 13.15pt;"> <span lang="FR">T1 arg1,<o:p></o:p></span></pre>
<pre style="line-height: 13.15pt;"><span lang="FR"> T2 arg2<o:p></o:p></span></pre>
<pre style="line-height: 13.15pt;"><span lang="FR">)<o:p></o:p></span></pre>
<div class="MsoNormal">
But <span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">Func</span><span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;"><</span><span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">T1</span><span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;">,</span><span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-highlight: white;"> T2</span><span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;">, </span><span style="background: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%; mso-highlight: white;">TResult</span><span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;">></span> is syntactic sugar of the
right sort.<o:p></o:p><br />
<br /></div>
<div class="MsoNormal">
My code needed to declare something like this<o:p></o:p><br />
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: #2b91af;">Func</span><<span style="color: blue;">string</span>, <span style="color: blue;">long</span>> memLookup = <span style="color: blue;">null</span>;
</div>
</code></pre>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
which declares a delegate instance with a string input
and a long integer output<o:p></o:p></div>
<div class="MsoNormal">
and then the following code needs to be executed:<o:p></o:p><br />
<span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;"><br /></span>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
memLookup = Memoize<<span style="color: blue;">string</span>, <span style="color: blue;">long</span>>(lookUpDimension);
</div>
</code></pre>
<br /></div>
<div class="MsoNormal">
sometime when the class is being created perhaps or
certainly before the memorized function is required. The class then exposes a
method like:</div>
<div class="MsoNormal">
<o:p></o:p><br />
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">public</span> <span style="color: blue;">long</span> LookupDimValue(<span style="color: blue;">string</span> dkey)
{
<span style="color: blue;">return</span> memLookup(dkey);
}
</div>
</code></pre>
<div class="MsoNormal">
<br />
Because memLookup() now “contains” a memoized version of the
original lookUpDimension() function taking a string input and returning a long
integer.<o:p></o:p></div>
<br />
<div class="MsoNormal">
One note of caution about the sort of memorized function I
have used in this example. If the function fails to locate a database record
corresponding to the given key then it returns a value indicating that (a zero).
One option might be to then insert a new record but the memorized function will
“remember” that the key is not valid and continue to return the original
response. The insert would therefore have to be managed from within the memorized
function and the relevant value for the new record returned.<o:p></o:p><br />
<br />
<b>Just a thought </b>(added 11/10/15)<br />
What is the simplest C# code to match the JavaScript function we started with?<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: #2b91af; font-family: Consolas; font-size: 12.666666666666666;">Dictionary</span><span style="font-family: Consolas; font-size: 12.666666666666666;"><</span><span style="color: blue; font-family: Consolas; font-size: 12.666666666666666;">int</span><span style="font-family: Consolas; font-size: 12.666666666666666;">, </span><span style="color: blue; font-family: Consolas; font-size: 12.666666666666666;">long</span><span style="font-family: Consolas; font-size: 12.666666666666666;">> memo = </span><span style="color: blue; font-family: Consolas; font-size: 12.666666666666666;">new</span><span style="font-family: Consolas; font-size: 12.666666666666666;"> </span><span style="color: #2b91af; font-family: Consolas; font-size: 12.666666666666666;">Dictionary</span><span style="font-family: Consolas; font-size: 12.666666666666666;"><</span><span style="color: blue; font-family: Consolas; font-size: 12.666666666666666;">int</span><span style="font-family: Consolas; font-size: 12.666666666666666;">, </span><span style="color: blue; font-family: Consolas; font-size: 12.666666666666666;">long</span><span style="font-family: Consolas; font-size: 12.666666666666666;">>() { { 0, 0 }, { 1, 1 } };</span>
</div>
</code></pre>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: blue;">long</span> fib(<span style="color: blue;">int</span> n)
{
<span style="color: blue;">long</span> result;
<span style="color: blue;">if</span> (!memo.TryGetValue(n, <span style="color: blue;">out</span> result))
{
result = fib(n - 1) + fib(n - 2);
memo.Add(n, result);
}
<span style="color: blue;">return</span> result;
}
</div>
</code></pre>
Fewer lines but less "functional" as it makes use of a Dictionary object that is external to the function. Memoization would often be a better approach.<br />
<br />
If you are wondering if memoization (at least in some form) is an effective technique then try writing a fibonacci function without and give it a run - as the input n increases the response time can be considerable.<br />
<br />
<b>And more</b> (added 13/10/2015)<br />
<br />
C#6 now allows a different form for initialising a Dictionary<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">int</span>, <span style="color: blue;">long</span>> memo = <span style="color: blue;">new</span> <span style="color: #2b91af;">Dictionary</span><<span style="color: blue;">int</span>, <span style="color: blue;">long</span>>
{
[0] = 0,
[1] = 1
};
</div>
</code></pre>
<br />
which is bound to be useful when the assignment can add value (just a thought).</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-74848253006192444082015-09-25T07:52:00.000-07:002016-03-30T02:48:11.546-07:00More .NET monospace font nonsense<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
Just to make the point. Wikipedia defines a monospaced font
as follows:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span style="background: white; color: #252525; font-family: "arial" , sans-serif; font-size: 10.5pt; line-height: 107%;">A<span class="apple-converted-space"> </span></span><b>monospaced
font</b>, also called a<span class="apple-converted-space"> </span><b>fixed-pitch</b>,<span class="apple-converted-space"> </span><b>fixed-width</b>, or<span class="apple-converted-space"> </span><b>non-<a href="https://en.wikipedia.org/wiki/Typeface#Proportion" title="Typeface"><span style="color: #0b0080; text-decoration: none;">proportional</span></a><span class="apple-converted-space"> </span>font</b>, is a<span class="apple-converted-space"> </span><a href="https://en.wikipedia.org/wiki/Font" title="Font"><span style="background: white; color: #0b0080; font-family: "arial" , sans-serif; font-size: 10.5pt; line-height: 107%; text-decoration: none;">font</span></a><span class="apple-converted-space"><span style="background: white; color: #252525; font-family: "arial" , sans-serif; font-size: 10.5pt; line-height: 107%;"> </span><span style="background: white; color: #252525; font-family: "arial" , sans-serif; font-size: 10.5pt; line-height: 107%;">whose
letters and characters each occupy the same amount of horizontal space.</span><o:p></o:p></span></div>
<div class="MsoNormal">
<span style="background: white; color: #252525;">Now not everything you read on Wikipedia is necessarily true
but I am confident that a technical reader would be happy with that definition.<o:p></o:p></span></div>
<div class="MsoNormal">
<span style="background: white; color: #252525;"><br /></span></div>
<div class="MsoNormal">
<span style="background: white; color: #252525;">You might be less happy to find that the .NET Graphics.DrawString()
method does not adhere strictly to this approach. My earlier experience while
trying to measure a monospaced font character width was a clue that issues
might arise in actual usage. Arise they did.<o:p></o:p></span></div>
<div class="MsoNormal">
<span style="background: white; color: #252525;"><br /></span></div>
<div class="MsoNormal">
<span style="background: white; color: #252525;">You can’t see it at first but as printed lines become longer
then it becomes clear that the line length is less than it should be. Pixels in
the X axis are being “lost” along the way. My test data was printed at the
correct register for the first 7 characters but the 8<sup>th</sup> was one
pixel to the left of where it should have been. Somewhere around 90 plus characters
into a line the positioning is out by 10 pixels (a single character width for
the font in question).<o:p></o:p></span></div>
<div class="MsoNormal">
<span style="background: white; color: #252525;"><br /></span></div>
<div class="MsoNormal">
Each character in every line is correctly positioned
relative to the other lines but incorrectly positioned based upon any rational
definition of a monospaced font.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
The image below shows the 97<sup>th</sup> character (H) in
the first line of text showing correctly in position while the second line
rendered by the DrawString() method being passed the whole line of text shows
the “H” well to the left of the correct location.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0SY5TIzJfjHETyG5PcbBc52LKPyNiRjI8ux9JpaY9FSYytpux4VrOd9DtupJXMgKPsi75NuDgh_b4WC6hrKENll-8ZunbRPvNMtLooko_DhudICTTOMygSOjpqiJYsVX2TbAeBA/s1600/Monospace.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0SY5TIzJfjHETyG5PcbBc52LKPyNiRjI8ux9JpaY9FSYytpux4VrOd9DtupJXMgKPsi75NuDgh_b4WC6hrKENll-8ZunbRPvNMtLooko_DhudICTTOMygSOjpqiJYsVX2TbAeBA/s640/Monospace.png" width="640" /></a></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
In case you wondered the blue “divider” is placed by an algorithm
that looks for probable field positions by analysing transitions between
character types (in this case a white space prior to a “letter”)<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
So if (like me) you are working in the .NET environment and
you want to know where the nth character is on a “painted” surface of a
window/control using (for crying out loud) a monospaced font – then you need to
print each character individually at the correct location. On that basis, you
could do just as well with a nominally proportional font of course.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
At least this showed that, at longer string lengths, there
was some consistency between MeasureString() and DrawString() even if both (in
this instance) are wrong.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
</div>
<div class="MsoNormal">
Programming in .NET is sometimes all about fighting .NET (or
GDI+ or whatever is actually responsible for the rendering under the covers).
On reflection, this is true of every software platform I have ever worked on.<o:p></o:p><br />
<br />
<b>Final word:</b><br />
While subsequently working on something else completely, I found out that MeasureString() uses GDI+ while by default .DrawString() uses GDI and their rendering is not the same. Well we live and learn I suppose but you would have expected consistency within the .NET defaults wouldn't you?</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-84361975927198360952015-09-21T04:42:00.000-07:002015-09-22T03:40:29.441-07:00Accurately measure monospace font widths<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
I was building a custom control in C# to allow a user to
identify the positions of data fields in a flat text file. So one of the things
the control needs to know is where a given character position is in a line of
text.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Easy peasy you may say – make the font Courier New or GenericMonospace (of course) and
use the Graphics.Measure<span style="background: white; font-family: Consolas; font-size: 9.5pt; line-height: 107%;">String</span><span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;">()
function.<o:p></o:p></span></div>
<div class="MsoNormal">
<span style="font-family: Consolas; font-size: 9.5pt; line-height: 107%;"><br /></span></div>
<br />
<div class="MsoNormal">
Here is some test code:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: blue;">void</span> Dummy2_Load(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> e)
{
<span style="color: #2b91af;">Font</span> mFont = <span style="color: blue;">new</span> <span style="color: #2b91af;">Font</span>(<span style="color: #2b91af;">FontFamily</span>.GenericMonospace, (<span style="color: blue;">float</span>)12);
<span style="color: blue;">this</span>.Font = mFont;
<span style="color: #2b91af;">Graphics</span> g = <span style="color: blue;">this</span>.CreateGraphics();
label1.Text += <span style="color: #2b91af;">Convert</span>.ToString(g.MeasureString(<span style="color: #a31515;">"A"</span>, mFont));
label2.Text += <span style="color: #2b91af;">Convert</span>.ToString(g.MeasureString(<span style="color: #a31515;">"AA"</span>, mFont));
label3.Text += <span style="color: #2b91af;">Convert</span>.ToString(g.MeasureString(<span style="color: #a31515;">"AbCdEfGhIj"</span>, mFont));
g.Dispose();
mFont.Dispose();
}
</div>
</code></pre>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<div class="MsoNormal">
Which gives a result like:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8HzaAlQ11XhlIVLa7Ki-oABOv-ujcurlQOa4lBBZT9FMwryrZDddqWMaQztlYGYjY1SAsNJMsZaUieXHEzWIIyBGHZs-MinNC7nkxfZrQTKl9hM456hUcLf2pdeZGsBJxR8R-7g/s1600/Dummy2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="177" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8HzaAlQ11XhlIVLa7Ki-oABOv-ujcurlQOa4lBBZT9FMwryrZDddqWMaQztlYGYjY1SAsNJMsZaUieXHEzWIIyBGHZs-MinNC7nkxfZrQTKl9hM456hUcLf2pdeZGsBJxR8R-7g/s640/Dummy2.png" width="640" /></a></div>
<div class="MsoNormal">
So is a character 15.2 pixels wide or 12.5 pixels wide or
10.4 pixels wide or...?<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
</div>
<div class="MsoNormal">
If I grab a screen shot and count the pixels I can see ALL
of the characters are drawn with a width of 10 pixels. [I am currently ignoring
the supposed character height as I assume that is a notional line height (but
w.t.f?).]<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwRKsBOjfAZsnOCgKD8uayYkVWY41bkBcF7AaUhOZr5BI9oe8FMKSOaq7x0Gw47HfFbVM-mqFmFL4zb9mOV_hW8oGUfcMwNVSavZKyIpVzBpATo42TxeTuatknZf_ANoHnLpL2HA/s1600/Dummy2B.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="129" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwRKsBOjfAZsnOCgKD8uayYkVWY41bkBcF7AaUhOZr5BI9oe8FMKSOaq7x0Gw47HfFbVM-mqFmFL4zb9mOV_hW8oGUfcMwNVSavZKyIpVzBpATo42TxeTuatknZf_ANoHnLpL2HA/s640/Dummy2B.png" width="640" /></a></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
So if you or I want to determine the character width on an unknown
device with unknown settings we have a bit of a problem.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
</div>
<div class="MsoNormal">
One might wonder if the function returns a notional “overhead”
for any given string. But if we subtract the width returned for the single character from
the width of 10 characters and then divide by 9 – we get 9.89 pixels. So any overhead is not consistent.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The reducing “error” returned by MeasureString() as the length
of the initial test strings increased might make you wonder if a very long
string would give an accurate result. Sadly a string of 100 characters measures
at 9.94 pixels per character which at least could “round up” to the correct
value but raises new questions about just what is being measured. <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Perhaps there is an optimal string length that could be
applied?<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
A bit more code came up with a value of 48 characters for an
optimal result on my development system – but I have no idea if that is fully “portable” for the full
range of font sizes and screen resolutions.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
</div>
<div class="MsoNormal">
N.B. Just in case you were wondering, and even though you know
the code is using a monospaced font – you get identical results substituting
lower case i's into any or all of the test strings.<o:p></o:p><br />
<br />
<b>Addendum</b><br />
After posting this I built a little class to measure the true font size. The class creates a bitmap and then draws the characters q and j onto the bitmap and scans the pixels to find the first and last rows of pixels that contain part of one of the characters - this gives the true height. Then the bitmap is cleared and two j's drawn next to each other. The class then measures the number of pixels between the first column containing a pixel for the first character and the first column of pixels used to draw the second. This gives the true width.<br />
<br />
The code is more than a bit scrappy so feel free to correct/optimise. Please treat it as a prototype (which it is) and not production quality code.<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">class</span> <span style="color: #2b91af;">MeasureMonoFont</span> : <span style="color: #2b91af;">IDisposable</span>
{
<span style="color: blue;">private</span> <span style="color: #2b91af;">Graphics</span> g;
<span style="color: blue;">private</span> <span style="color: #2b91af;">Bitmap</span> bm;
<span style="color: blue;">private</span> <span style="color: #2b91af;">SolidBrush</span> br;
<span style="color: #2b91af;">StringFormat</span> drawFormat;
<span style="color: blue;">private</span> <span style="color: blue;">const</span> <span style="color: blue;">int</span> defBitmapSize = 100;
<span style="color: blue;">public</span> MeasureMonoFont()
{
bm = <span style="color: blue;">new</span> <span style="color: #2b91af;">Bitmap</span>(defBitmapSize, defBitmapSize);
g = <span style="color: #2b91af;">Graphics</span>.FromImage(bm);
br = <span style="color: blue;">new</span> <span style="color: #2b91af;">SolidBrush</span>(<span style="color: #2b91af;">Color</span>.Black);
drawFormat = <span style="color: blue;">new</span> <span style="color: #2b91af;">StringFormat</span>();
}
<span style="color: blue;">public</span> <span style="color: #2b91af;">SizeF</span> GetCharSize(<span style="color: #2b91af;">Font</span> withFont)
{
<span style="color: #2b91af;">SizeF</span> cSize = <span style="color: blue;">new</span> <span style="color: #2b91af;">SizeF</span>();
g.Clear(<span style="color: #2b91af;">Color</span>.White);
<span style="color: #2b91af;">PointF</span> cPoint = <span style="color: blue;">new</span> <span style="color: #2b91af;">PointF</span>(0, 0);
g.DrawString(<span style="color: #a31515;">"qj"</span>, withFont, br, cPoint, drawFormat);
<span style="color: #2b91af;">Color</span> tPixel;
<span style="color: blue;">int</span> firstRow = -1;
<span style="color: blue;">int</span> lastRow = -1;
<span style="color: blue;">for</span> (<span style="color: blue;">var</span> yp = 0; yp < defBitmapSize; yp++)
{
<span style="color: blue;">for</span> (<span style="color: blue;">var</span> xp = 0; xp < defBitmapSize; xp++)
{
tPixel = bm.GetPixel(xp, yp);
<span style="color: blue;">if</span> (!(tPixel.ToArgb() == <span style="color: #2b91af;">Color</span>.White.ToArgb()))
{
<span style="color: blue;">if</span>(firstRow == -1) { firstRow = yp; }
<span style="color: blue;">if</span>(yp > lastRow) { lastRow = yp; }
}
}
}
cSize.Height = ++lastRow - firstRow;
g.Clear(<span style="color: #2b91af;">Color</span>.White);
g.DrawString(<span style="color: #a31515;">"jj"</span>, withFont, br, cPoint, drawFormat);
firstRow = -1;
lastRow = -1;
<span style="color: blue;">bool</span> secondChar = <span style="color: blue;">false</span>;
<span style="color: blue;">bool</span> firstChar = <span style="color: blue;">false</span>;
<span style="color: blue;">bool</span> emptyColumn = <span style="color: blue;">false</span>;
<span style="color: blue;">for</span> (<span style="color: blue;">var</span> xp = 0; xp < defBitmapSize && lastRow == -1; xp++)
{
emptyColumn = <span style="color: blue;">true</span>;
<span style="color: blue;">for</span> (<span style="color: blue;">var</span> yp = 0; yp < defBitmapSize && lastRow == -1; yp++)
{
tPixel = bm.GetPixel(xp, yp);
<span style="color: blue;">if</span> (!(tPixel.ToArgb() == <span style="color: #2b91af;">Color</span>.White.ToArgb()))
{
<span style="color: blue;">if</span> (!firstChar)
{
firstChar = <span style="color: blue;">true</span>;
firstRow = xp;
}
<span style="color: blue;">if</span> (secondChar) { lastRow = xp; }
emptyColumn = <span style="color: blue;">false</span>;
}
}
<span style="color: blue;">if</span>(firstChar && emptyColumn) { secondChar = <span style="color: blue;">true</span>; }
}
cSize.Width = lastRow - firstRow;
<span style="color: blue;">return</span> cSize;
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> Dispose()
{
g.Dispose();
bm.Dispose();
br.Dispose();
drawFormat.Dispose();
}
}
</div>
</code></pre>
<br /></div>
</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-85373877023133436712015-09-16T07:41:00.000-07:002015-09-16T07:41:52.810-07:00Reading a delimited text file in C#<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
You can of course write your own string parsing code or you can take the
easy way and add a reference to Microsoft.VisualBasic within your Visual Studio
project and make use of the <span style="background-color: white; color: #2b91af; font-family: Consolas; font-size: 9.5pt; line-height: 107%;">TextFieldParser</span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
This
little snippet loads the content of a delimited text file into a ListView</div>
<div class="MsoNormal">
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">using</span> Microsoft.VisualBasic.FileIO;
<span style="color: blue;">private</span> <span style="color: blue;">void</span> loadCSVFile(<span style="color: blue;">string</span> filePath, <span style="color: blue;">string</span> delimiter)
{
<span style="color: #2b91af;">TextFieldParser</span> tfParser = <span style="color: blue;">new</span> <span style="color: #2b91af;">TextFieldParser</span>(filePath);
tfParser.TextFieldType = <span style="color: #2b91af;">FieldType</span>.Delimited;
tfParser.SetDelimiters(delimiter);
<span style="color: blue;">string</span>[] curRow;
<span style="color: #2b91af;">ListViewItem</span> lvi;
<span style="color: blue;">while</span> (!tfParser.EndOfData)
{
curRow = tfParser.ReadFields();
lvi = listView1.Items.Add(curRow[0]);
<span style="color: blue;">for</span> (<span style="color: blue;">var</span> ci = 1; ci < curRow.Length; ci++)
{
lvi.SubItems.Add(curRow[ci]);
}
}
tfParser.Close();
tfParser.Dispose();
}
</div>
</code></pre>
<div class="MsoNormal">
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Sometimes
VB is your friend.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
Usual
caveats about production code (try/catch etc.)<o:p></o:p></div>
</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-1306128011703005942015-09-14T07:22:00.000-07:002015-09-14T07:22:05.394-07:00Wot no Python Executable?<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
So how did my first foray into Python go? </div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Well partly I
cheated and wrote Iron Python code in Visual Studio – so obviously I write a
lot of .NET code but using Python syntax. The idea was to get a running start
on how to structure my Python and I wrote a bunch of classes with methods,
adopting the MVC pattern to push that beyond where I would normally go. So far,
I am still enthusiastic about the language. There are odd puzzles to do with
variable scope but I am confident those will work out nicely as I write more
code. The short and snappy syntax bodes well for productivity although
debugging minor spelling mistakes (character case and all that) counteracts
that a bit.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
You might think that building a .NET Python app was a quick
route to having something I could distribute as an executable to others but
(and this is a big BUT) – it is possible to encapsulate an Iron Python program
as an executable but it is a big hill to climb.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<a href="https://glyph.twistedmatrix.com/2015/09/software-you-can-use.html">This post covers the general Python app distribution problem</a>
domain way better than I can.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Python looks like a programming language for YOU to use but
the infrastructure lacks more than a little when it comes to sharing. A given
program can (perhaps must) be built on a plethora of pre-existing libraries that
may not be apparent to your neighbour when it comes to sharing. Worse for me ‘cos
I generally think command line programs stink (and I do understand why you
might think otherwise) – perhaps I had better try and explain where I am coming
from. Some (or maybe all) of it is a history.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
My first programs were COBOL encoded in <a href="https://en.wikipedia.org/wiki/EBCDIC">EBCDIC</a> and punched onto <a href="https://en.wikipedia.org/wiki/Punched_card">80 column cards</a>. These
cards were fed into a card reader’s “hopper”, compiled and (if all went well) the
program ran. The program caused other punched cards containing data to be read
and the resulting output was printed (astonishingly quickly by today’s
standards) on a line printer – or just possibly output as newly punched cards
ready for another process. If I got my program and data into the computer room “in-tray”
by 17:00 I usually got the output the following day. The ultimate “command line”.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Then I started in a new job and was assigned to try out
something called BASIC on a DEC PDP 11/70 as this was a platform that was seen as
suitable for “end user” computing and someone was needed to be able to help out
with development work within various departments of the business. I was handed
the language specification for <a href="https://en.wikipedia.org/wiki/BASIC-PLUS#BASIC_Plus_2">DEC’s Basic+</a> and left to my own devices for a
bit. It was a pivotal moment because BASIC contains two very important keywords
– INPUT and PRINT. I realised that my future programs could interact with the
user while they were running. The other “tools” were a bit primitive – <a href="https://en.wikipedia.org/wiki/VT52">VT52VDUs</a> and <a href="http://www.computinghistory.org.uk/det/3367/Digital-DECWriter-II/">printer terminals </a> hooked up to the computer room via 300 baud modems. Clunky kit but the software
(in comparison to what had gone before) could soar.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
At about the same time the Apple ll and <a href="http://www.vintage-computer.com/pet8032.shtml">Commodore PET</a> micro computers were also introducing a new and interactive model to a wider
audience (here too BASIC was a key component). A common anti-pattern of that
era was to get the user to type in some data, validate it and then display the
result. The “anti” bit came when the validation failed – typically this
resulted in user punishment with a GOTO command taking the program back to the
beginning with all data previously entered lost. This was lazy programming and
(despite the miniscule available RAM) it was a personal fundamental that user
data was corrected with minimal effort on the part of the human running the
program.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
As clerical tasks were “computerised” it was also crucial
that the user remained in control. We needed to preserve the knowledge of how
things were done – as otherwise the next edge case could become a major problem.
Software has a duty to educate as well as undertake the drudgery of so many
tasks. Fortunately terminals (and micro-computers) evolved and improved. Every
advance was applied to the task of improving the quality of the interaction
between user and software.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
To cut to the chase, it became second nature for me to
ensure that the UI (User Interface) was a critical part of every bit of
software. So much so that the tools I write for myself typically have a strong
UI even as this adds perceptibly to the development time.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
So even if I had to explain to you why (say) I have a
utility that takes an SQL table definition and outputs boilerplate class code
(in C#, VB.NET or Java at choice) together with support stored procedure
definitions (with variants for SQLite if required) you could copy the
executable to your machine and just run it. You might not appreciate the “why”
but the “how” should be obvious.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
So given my fervour for strong user interfaces I have some
difficulties with the current Python infrastructure. I
have in mind a project that would make very effective use of all that Python
list handling goodness. My problem would be in sharing any resulting software
with others who might make use of it – particularly if it became a commercial
proposition.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
For the moment Python has to be just for me and is not for
sharing. Probably confined to the Raspberry Pi – actually it will be interesting
to try out the Kivy library to interact via a touch screen on that platform. So I am not finished yet that's for sure.<o:p></o:p></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-91085322620923077852015-09-08T09:45:00.001-07:002015-09-08T09:45:24.335-07:00This week’s language is Python<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
Warning – these notes on Python are based on very short acquaintance
and may well be misleading and/or factually incorrect.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
OK – coming late to the table most people would think – but then
again. The last time I took a look at Python was around the time Python 3 came
out and the status and functionality of the mass of C support libraries was in
some doubt. Turns out that is still true in many instances with a lot of effort
still seemingly going into Python 2.n and it is not clear that the world at
large has collectively taken the big step to Unicode. <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Anyway, I wanted to do some stuff with one of those new
Raspberry Pi 2 machines and Python looks to be the lingua Franca for that platform
when running Linux. So I had another look. <b>**</b><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The specific feature that figures in any introduction to
Python is that white space (specifically line indentation) is significant and
part of the language syntax. Most introductions wax on about there being no
need for {curly braces} or semicolons but then again you do have to frown a bit
at those unmentioned colons at the end of significant lines<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
>>> def myfun(arg)<b><span style="font-size: 14.0pt; line-height: 107%;">:</span></b><o:p></o:p></div>
<div class="MsoNormal">
<b><span style="font-size: 14.0pt; line-height: 107%;">. . .</span></b></div>
<div class="MsoNormal">
>>> for w in something<b><span style="font-size: 14.0pt; line-height: 107%;">:</span></b><o:p></o:p></div>
<div class="MsoNormal">
<b><span style="font-size: 14.0pt; line-height: 107%;">. . .</span></b></div>
<div class="MsoNormal">
<b><span style="font-size: 14.0pt; line-height: 107%;"><br /></span></b></div>
<div class="MsoNormal">
Then my reading got to len(something). </div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
What? I thought.
Surely the length of something (number of characters in a string or the count
of entries in a list) would be an attribute of the relevant object. I even
found Guido van Rossum’s explanation in an old Python FAQ but also found it
less than convincing. I looked further and found there were at least 60
language features implemented as methods. Wow! I thought this is BASIC born
again. There are even Input and Print methods. Then I looked at how such
methods as len() were implemented – and then I think I reached an understanding.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Each object type (tricky to get the terminology right) where
a length measurement makes sense implements a method called __len__() that will
be used automatically by the language len() method. Programmers can implement
the __len__() method on their custom objects confident that the language’s
len() method will act as a standard interface to that functionality. In a
language envisioned for code sharing (and multiple standard libraries) this is
actually a powerful concept. You don’t have to know how (say) an unknown object
implements a readable string representation of itself – you can just use
str(object) with confidence.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
So it looks like the BASIC style language methods can be
extended to include new types of object which is a massive step forwards.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Python is also big on Lists. I suspect that languages influential
in the design of Python included Prolog, Smalltalk and Lisp (I might have said a
Lispy JavaScript but the languages while not quite contemporaneous were both
born around the same time). No surprise then that Python is a very popular language
in AI research. There is nothing in Python Lists that you can’t do with (say)
C# but the language is rich in list manipulation functionality “out of the box”.<o:p></o:p></div>
<div class="MsoNormal">
I love the fact that you can use expressions to create and
populate a list:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
>>> squares = [x**2 for x in range(10)]<br />
>>> squares<br />
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
And range() itself is a fascinating and flexible tool for
controlling loops.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Tuples look interesting as immutable collections of heterogeneous
elements although I have yet to work out how a mutable element (like a list)
might fare inside a tuple.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Sets are another specialised form of list with support for
set operators like union and intersection. Takes me back to college maths. Can’t
wait to see what I can do with these. Curley braces <b>do</b> turn up in the language here and then also with dictionaries.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Dictionaries are available and look well supported and I
have always liked the “associative array” concept<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Functions are first class objects and I greeted the huge
range of options for passing arguments into a function with a lot of interest.
There are potential traps for the unwary here I think but also a flexibility
not available anywhere else. Lambda’s as well of course.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Built in JSON serialisation and de-serialisation supports
the storage and transfer of objects and the capacity to execute strings as code
opens up the opportunity to implement a DSL (Domain Specific Language) among
other opportunities. Then there are Generators (see <a href="http://stackoverflow.com/questions/102535/what-can-you-use-python-generator-functions-for">http://stackoverflow.com/questions/102535/what-can-you-use-python-generator-functions-for</a>)
to help scale data presentation and high data volumes.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Classes have similarities to the equivalent JavaScript
objects. They can contain the equivalent of static variables, instance
variables, attributes and methods. Instance variables can be created and
manipulated on individual instances of a class. Scope and the order that
objects are defined or assigned can impact upon the meaning of the code.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Classes support inheritance (including multiple inheritance)
with the ability to override base class methods. Operator overloading is also
supported.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The construction and importing of code modules (which then
act as name spaces) is an effective mechanism for code structure and code
sharing.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Python runs into a bit of a steep incline (not a wall) when
it comes to complex interactions with the user. It is fundamentally a scripting
language and is not primarily intended to maintain a GUI (Graphical User
Interface). KiVy is going to be bigger on the Raspberry Pi with the newly
announced touch display. For PCs Iron Python is an open source community
project that integrates the Python language with .NET might well be one
workaround for more complex projects and with Visual Studio 2015 (community
edition) being free for a lot of projects and developers it is a viable option.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
When you have been working in JavaScript for a few days and the
code is really starting to flow then this is partly because you have erected a
good mental model of the variable and method scope in play. I strongly suspect
that constructing and maintaining a similar mental model for a large Python
codebase would be essential – there are some similarities but also some key
differences. Getting “in the groove” might take a little effort.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
None of this is intended to act as any sort of Python
introduction – rather the intention is to communicate a little of the
enthusiasm I am feeling for the language now I have taken a proper look. Python
is different (a big bonus), clever and very capable. Now all I have to do is
learn how to write effective code in this language – a big step on from just
assembling an overview of the functionality after all. So the next side-project
is going to be in Python.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
<b>**</b> plan is to have two SD cards so I can “dual boot” one of
the Linux variants available for the Pi and Windows 10 – should be fun. I also
see Python runs on Windows OIT Core as well as on the usual Linux variations.<o:p></o:p></div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0tag:blogger.com,1999:blog-21052732.post-83675332941125840762015-09-01T07:18:00.000-07:002015-09-02T02:37:13.098-07:00Eating the Browser cake<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
That side-project again. One of the primary outputs of the
app is data and text collected from web sites in (mostly) HTML format. This can
most simply be wrapped to create an HTML document and displayed in the
WebBrowser control made available by Visual Studio. This works well up to a
point – the WebBrowser control is a “wrapper” for the Internet Explorer COM
object but only exposes a limited set of events and properties. There is also
an issue with multi-threading – using the WebBrowser control makes it very
difficult to update the UI thread from (say) a BackgroundWorker.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
I was happy with the HTML presentation within the WebBrowser
control but wanted to handle any user clicks on links by pushing the link off
to the default browser on the relevant machine. An external link could require
a whole host of support facilities not enabled by the WebBrowser control so
this made sense as well as (probably) reflecting the expectations of any user.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
So, how to push responsibility to those external links off
to the user’s preferred browser. Turns out to be easy to handle in the
Navigating event:<o:p></o:p><br />
<br /></div>
</div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> <span style="color: blue;">void</span> webViewer_Navigating(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">WebBrowserNavigatingEventArgs</span> e)
{
<span style="color: blue;">if</span> (!hasStarted)
{
hasStarted = <span style="color: blue;">true</span>;
<span style="color: blue;">return</span>;
}
e.Cancel = <span style="color: blue;">true</span>;
<span style="color: blue;">var</span> startInfo = <span style="color: blue;">new</span> <span style="color: #2b91af;">ProcessStartInfo</span>
{
FileName = e.Url.ToString()
};
<span style="color: #2b91af;">Process</span>.Start(startInfo);
}
</div>
</code></pre>
<div class="MsoNormal">
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The bool pageShown is set false before loading the original page in
the WebBrowser control and this is set true by the first Navigating event
resulting from that page load. Subsequent Navigating events before the
pageShown value is reset are pushed off to the default application (a web
browser certainly) that handles URLs.<o:p></o:p><br />
<br /></div>
<div class="MsoNormal">
This worked fine up until the HTML content being displayed contained
an <iframe> tag. While loading graphics and scripts from remote servers
caused no issues filling the content of an <iframe> triggered a
Navigating event. So I needed to know if a Navigating event was being triggered
by an <iframe> requesting content as this may happen after the main
content had loaded and the DocumentCompleted event fired (so I could not
reliably re-set the pageShown Boolean within that event handler.<o:p></o:p><br />
<br />
<a href="http://stackoverflow.com/">StackOverflow </a>is your friend here of course. Questions like “possible to detect whether an iframe is loaded in the navigating event” hit the nail on the head. This starts a trail that initially leads to a March 2006 Code Project post by Jeroen Landheer <a href="http://www.codeproject.com/Articles/13598/Extended-NET-2-0-WebBrowser-Control#CreateIWebBrowser2">http://www.codeproject.com/Articles/13598/Extended-NET-2-0-WebBrowser-Control#CreateIWebBrowser2</a> but also mentions the BeforeNavigate2 event thus exposed and the opportunity to insert a test into the BrowserExtendedNavigatingEventArgs class.<br />
<br />
There is also this <a href="http://www.codeproject.com/Articles/18935/The-most-complete-C-Webbrowser-wrapper-control">http://www.codeproject.com/Articles/18935/The-most-complete-C-Webbrowser-wrapper-control</a> CodeProject article from May 2007 which is worthy of investigation if you need to follow a similar path.<br />
<br />
It looks like the Windows System SHDocVw.dll exposes a whole range of additional interfaces and events for IE not exposed by the WebBrowser control but getting a handle on them takes a little effort to say the least – hence the projects to sub-class the WebBrowser in the two CodeProject articles mentioned.<br />
<br />
Anyway – the only snag remaining is that the standard WebBrowser Navigating event fires before the BeforeNavigate2 event which is slightly counter-intuitive. So the trick is to move the functionality from the Navigating event into the WebBrowserExtendedEvents class BeforeNavigate2 event by adding a Boolean property to that class for the main form to notify the start (and end) of the main document loading.<br />
<br />
As an aside, I did wonder if there were alternatives to the provided WebBrowser control. Turns out there have been projects to “wrap” WebKit and FireFox browsers but what looks like the most able and up-to-date project provides a wrapper for the Chrome browser and the GitHub repository is here https://github.com/cefsharp/CefSharp/wiki . However if you were expecting a nice Visual Studio control to “drop onto” a form then you might be disappointed. I think the idea is that you will want to wrap the functionality in a custom control of your own perhaps supporting tabs and other browser flummery. The simplest way to add the CefSharp control to your form is programmatically in the form class constructor thus:<br />
<div>
<br /></div>
</div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOXt6mD1Fn2KnEXzUUf4viYqwWOhisanrHWF9gRJxS1Nh8k0v0Xh_WqwM-4CSdRxP1mO3-MFSVRCp4iW44mrmi3xpJgykKQvKmovZtt7X1KW8Z86wOUR54ANT1no5TAkwROZ6REg/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-size: 110%; height: auto; line-height: 1; margin: 0px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="word-wrap: normal;"><div style="color: black; font-family: Segoe UI; font-size: 12; font-style: normal; font-weight: normal; text-align: Left;">
<span style="color: blue;">private</span> CefSharp.WinForms.<span style="color: #2b91af;">ChromiumWebBrowser</span> mBrowser;
<span style="color: blue;">public</span> Form1()
{
InitializeComponent();
mBrowser = <span style="color: blue;">new</span> CefSharp.WinForms.<span style="color: #2b91af;">ChromiumWebBrowser</span>(<span style="color: #a31515;">"http://www.hanselman.com/blog/"</span>)
{
Dock = <span style="color: #2b91af;">DockStyle</span>.Fill,
};
<span style="color: blue;">this</span>.Controls.Add(mBrowser);
}
</div>
</code></pre>
It works and seems very fast and responsive. The documentation currently takes the form of “read the code” so it was not immediately obvious I could solve my problems by switching the underlying browser but at first glance it did look possible. What stopped me spending too much time here was the requirement to build your project against the 32bit or 64 bit version. While there are fewer 32bit PCs out there it still represents an additional issue should this project ever be shared with others even informally.<br />
<br />
<div class="MsoNormal">
</div>
</div>
</div>
Mike Griffithshttp://www.blogger.com/profile/09355113888181272959[email protected]0