browse by category or date

Today I installed Ionic Pack for Visual Studio 2015. This extension will provide IntelliSense when editing Ionic’s HTML source code.

Unfortunately, this extension will clashed with ReSharper’s HTML IntelliSense. Here’s how to disable it.

  1. Open ReSharper’s Option
    devenv_2016-05-05_16-57-23
  2. Select IntelliSense -> General
    devenv_2016-05-05_16-59-16
  3. Select Custom IntelliSense
    devenv_2016-05-05_17-01-15

This way, I enable ReSharper only when editing .cs files. And it works!
devenv_2016-05-05_17-03-58

That’s all. I hope it helps.

About Hardono

Hi, I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 9 years.

Long time ago, Konstantin reported that the ouput of JSON Table editor is in encoded format (unicode-escape character). For example, if the input is:

{ 
   id: 0, 
   text: 'Привет', 
   translation: 'Hi' 
}

The output will be:

{ 
   "id": 0, 
   "text": "\u041f\u0440\u0438\u0432\u0435\u0442", 
   "translation": "Hi" 
}

Thanks to Mathias Bynens’ great article on Javascript problem with unicode, I can fix this problem.

First, we need to ensure that method String.FromCodePoint is available. Some browsers like IE and Safari didn’t have this method. Thus we need create the polyfills:

/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
if (!String.fromCodePoint) {
  (function() {
    var defineProperty = (function() {
      // IE 8 only supports `Object.defineProperty` on DOM elements
      try {
        var object = {};
        var $defineProperty = Object.defineProperty;
        var result = $defineProperty(object, object, object) && $defineProperty;
      } catch(error) {}
      return result;
    }());
    var stringFromCharCode = String.fromCharCode;
    var floor = Math.floor;
    var fromCodePoint = function() {
      var MAX_SIZE = 0x4000;
      var codeUnits = [];
      var highSurrogate;
      var lowSurrogate;
      var index = -1;
      var length = arguments.length;
      if (!length) {
        return '';
      }
      var result = '';
      while (++index < length) {
        var codePoint = Number(arguments[index]);
        if (
          !isFinite(codePoint) ||       // `NaN`, `+Infinity`, or `-Infinity`
          codePoint < 0 ||              // not a valid Unicode code point
          codePoint > 0x10FFFF ||       // not a valid Unicode code point
          floor(codePoint) != codePoint // not an integer
        ) {
          throw RangeError('Invalid code point: ' + codePoint);
        }
        if (codePoint <= 0xFFFF) { // BMP code point
          codeUnits.push(codePoint);
        } else { // Astral code point; split in surrogate halves
          // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
          codePoint -= 0x10000;
          highSurrogate = (codePoint >> 10) + 0xD800;
          lowSurrogate = (codePoint % 0x400) + 0xDC00;
          codeUnits.push(highSurrogate, lowSurrogate);
        }
        if (index + 1 == length || codeUnits.length > MAX_SIZE) {
          result += stringFromCharCode.apply(null, codeUnits);
          codeUnits.length = 0;
        }
      }
      return result;
    };
    if (defineProperty) {
      defineProperty(String, 'fromCodePoint', {
        'value': fromCodePoint,
        'configurable': true,
        'writable': true
      });
    } else {
      String.fromCodePoint = fromCodePoint;
    }
  }());
}

Now we can use this function to replace any instance of unicode escape character.

str = str.replace(/\\u([a-fA-F0-9]{1,6})/g, 
         function (e, n) {
	    var t = parseInt(n, 16);
	    return String.fromCodePoint(t);
});

That’s it guys. So happy that 2-years old bug is finally fixed 😀 Cheers!

About Hardono

Hi, I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 9 years.

 

My IT Department is using ManageEngine for application/server monitoring. It will send out emails whenever an application/server is down. But, it’s not enough because not everyone have the email sync-ed to their smartphone. So we need to explore new ways to send the notifications. SMS Gateway is definitely out of the equation (I proposed before, but kena shoot down).

Since we already have a WhatsApp group, sending the alerts to the group would be the best solution. But alas, WhatsApp doesn’t provide you API to do this.

Enter Telegram

I have used Telegram for quite sometime now. It was started when I was invited to my high school group. The group was moved from WhatsApp due to its limitation on how many members in a group.

As I read Telegram documentation, I found that Telegram allows you to create bot. The bot can be controlled through HTTP request. Convinced that the API is good enough to meet my needs. I decided to go ahead. Here’s how.

 

Before creating the bot, I need to create the group and invite all my colleagues to join.
chrome_2016-04-06_23-48-30

Note the group id is highlighted in red

Note the group id is highlighted in red

After all my colleagues joined the group, it’s time to create the bot. For that we need to talk to the BotFather :D:D (click the below picture to start talking)

03b57814e13713da37

Once the BotFather’s chat window is open. Follow the following interactions:

  1. chrome_2016-04-07_11-44-26
  2. Reply with the name of the bot.
    chrome_2016-04-07_11-47-36
  3. Reply with the bot’s new user id chrome_2016-04-07_11-49-20

That’s all. Now we have our bot ready. Please record down your bot’s token (highlighted in red rectangle) because we will need it to access the HTTP API.

 

My work emails is stored in MS Exchange Server. So I assumed that it would be dead simple to retrieve email using C#. I was wrong. After googling for this solution, I found that many people take the IMAP route instead of using Exchange Web Service API (only available in Exchange 2007 or later). Since I had a very limited time allocated to this project, I follow the recommended IMAP client library, AE.Net.Mail.

We can install this library through Nuget:

Install-Package AE.Net.Mail

This step is quite simple. First, we retrieve the email. Second, check whether the email’s subject is inside the list of subjects that should be relayed to Telegram. If yes, send the message to Telegram. Finally, delete the email regardless it relayed to Telegram or not.

Here’s my code to retrieve the email.

using System;
using System.Configuration;
using AE.Net.Mail;

//..SNIP..

static void Main(string[] args)
{
   var setting = ConfigurationManager.AppSettings;
   var lastRun = DateTime.Now.AddMinutes(-6);
   var imap = new ImapClient(
        setting["emailHost"], 
		setting["emailUser"],
        setting["emailPassword"], 
		AuthMethods.Login, 
		993,  // IMAP secure port
		true, // is Secure?
		true  // skip SSL validation?
   );
   
   // Entity object containing the list of important email subjects
   var db = new ITBotEntities();  
   
   while (true)
   {
      // Check email every 5 minutes
      if (lastRun.AddMinutes(5) < DateTime.Now)
      {
	     
		 var msgs = imap.SearchMessages(
			SearchCondition.Undeleted().And(        
				SearchCondition.SentSince(lastRun)
			));
		 foreach (var msg in msgs)	
		 {
		    //StripSpaces will remove all the whitespaces
		    var subject = StripSpaces(msg.Subject);
		   
		    foreach (var obj in db.LookupParams)
		    {
		       var objHeader = StripSpaces(obj.header);
		 	   if (subject.Equals(objHeader))
			   {					
			      Console.WriteLine(obj.header);
				  //Send alerts to Telegram
				  var content = SendTelegramMessage(obj.header); 
				  Console.WriteLine(content);
			   }
		    }
		    imap.DeleteMessage(msg);
		 }
		 lastRun = DateTime.Now;
	  }
	  else
   	     Thread.Sleep(5000);
   }
}

So how do we actually make the bot send alerts to the group? It's dead simple. Just remember to replace ##TOKEN## and ##GROUP_ID## with values we obtain in step 2.

private static string SendTelegramMessage(string message)
{
	var request =
		WebRequest.Create(
			"https://api.telegram.org/bot##TOKEN##/sendMessage?chat_id=-##GROUP_ID##&text=" +
			WebUtility.UrlEncode(message));
	var resp = request.GetResponse();
	var reader = new StreamReader(resp.GetResponseStream());
	var content = reader.ReadToEnd();
	/*
	the JSON object returned
	{
		"ok": true,
		"result": {
			"message_id": 7,
			"from": {
				"id": 189119520,
				"first_name": "IT-Bot",
				"username": "rlit_bot"
			},
			"chat": {
				"id": -##GROUP_ID##,
				"title": "Richland IT",
				"type": "group"
			},
			"date": 1459696911,
			"text": "Alarm from the Applications Manager - [ EDI File Monitor is down ]"
		}
	}
	
	*/
	reader.Close();
	resp.Dispose();
	return content;
} 

 

It's really easy to create Telegram Bot and to use to send messages. If we read the API further, we should find that Telegram also provide WebHook. This way we can setup a web service to monitor the messages received by the bot, in real-time. Imagine the unlimited possibilities! Restart a server? Just send message to the bot. If we combine this with Raspberry Pi, Home automation is super achievable! But keep in mind to keep the token secured to prevent the unwanted!.

That's all folks. I hope it helps. Cheers!

About Hardono

Hi, I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 9 years.

Recently I was required to do enhancements to an old ASP.NET Projects. It is an ASP.NET MVC 2 project supplemented with Ext.NET. Since the enhancements are quite minor, and no major enhancements planned, there’s no good reason to upgrade to the later ASP.NET MVC version. Not to mention that we didn’t renew our Ext.NET license 😀

On the other hand, I recently upgraded my workstation to Windows 10. All my previous development tools (VS 2008 Pro, IntelliJ, VS 2012) also have been installed. So I expect nothing wrong with loading this old project in VS 2008. But I was wrong. I got the dreaded “the project type is not supported by this installation” error.

devenv_2016-03-30_21-32-06

Possible Cause No. 1

I suspected that I forgotten to install ASP.NET MVC 2 Tools for Visual Studio 2008. So I went to Microsoft and download the installer. When I install it, it strangely complained that another version of MVC 2 is already installed. So I uninstall the installed ASP.NET MVC 2, then install again using the executable I just downloaded. It still failed.

Possible Cause No. 2

Could it be that Ext.NET prevented the project loading? From the project’s web.config, I can see that it is using Ext.NET v.1.xx. I vaguely remember that I need to install something in order to create Ext.Net project and to have intellisense on Ext.Net’s classes. Unfortunately, Ext.NET website doesn’t provide download for previous versions. 🙁 So, nothing can be done here.

Possible Cause No. 3

Could it be that this project is other that MVC 2? I open the .csproj in Notepad++ and found that the project type GUID is exactly just F85E285D-A4E0-4152-9332-AB1D724D3325. When I Google this GUID, it is exactly the GUID of ASP.NET MVC 2 project.

Solution

Out of desperation, I opened Visual Studio’s About window. Perhaps I missed any components.

vs2008sp1

Hmm, SP 1. Could this be the problem? Since I have no other way, I decided to uninstall Visual Studio 2008 SP 1 (9.0.30729.1) and install the previous version (without SP 1).

devenv_2016-03-30_23-21-49

Lo and behold! Now I can load my ASP.NET MVC 2 project!.

Conclusion

Visual Studio 2008 SP 1 (9.0.30729.1) is not compatible with ASP.NET MVC 2 project (Project Type GUID: F85E285D-A4E0-4152-9332-AB1D724D3325).

About Hardono

Hi, I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 9 years.

This trick is useful for handling suspicious emails. By looking on its header, we can see from which IP address the email was sent.

  1. Double click the email to make it open in a new window
  2. Click the Tags button
    OUTLOOK_2016-03-29_00-20-49

OUTLOOK_2016-03-29_00-23-16

Using online WHOIS, we can find out more about the IP address:
chrome_2016-03-29_00-31-28

Whois result:
chrome_2016-03-29_01-21-02

If you really have nothing to do, you can submit complaint to the ISP of that naughty IP address. But very likely, the PC on that IP address is just a dummy, and is a part of a BotNet.

About Hardono

Hi, I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 9 years.

Yesterday, I found myself in need of a TIFF image splitter. Reason: The scanner in my office didn’t allow me to retain the settings after a document scan. So every time I choose to ‘End Scanning’, the output image quality setting is reset to default. Which means I need change the output settings for each of document that I want to scan. The only way was to scan all documents at one go. That lead me to the situation where a TIFF splitter is needed.

A quick Google-search brought me to a simple, free and open-source program called Tiff Splitter. It is exactly the kind of program that I need. It is simple, and does its job well.

Because it does the job well, I become interested to find out how exactly Tiff Splitter works. Since it’s an open-source, I can immediately take a dive and learn.

TiffSplit_2016-01-28_15-16-40

After we click, select an input file, or, drop a file, the event handlers will eventually call processFile method.

private void processFile(string fileName)
{
   // ... SNIP ...
   
   _configs.inputFile = fileName;

   // Configure the extractor
   RetObj retObj = TiffSplitCode.Prepare(_configs, out numOfPages);
   
   // ... SNIP ...
   
   // Let user select pages to extract
   PageSelection ps = new PageSelection(numOfPages);
   ps.ShowDialog();
   _configs.fromPage = ps.PageFrom;
   _configs.toPage = ps.PageTo;
   _configs.doOverwrite = ps.OverwriteFiles;
   
   // ... SNIP ...
   
   // do the work in separate thread
   backgroundWorkerSplit.RunWorkerAsync(_configs);
}

On the worker thread it will do the splitting

private void backgroundWorkerSplit_DoWork(object sender, DoWorkEventArgs e)
{
	ConfObj input = e.Argument as ConfObj;  
	RetObj retObj = TiffSplitCode.Split(input, _updateProgress);
	e.Result = retObj;
}

The actual work was done by TiffSplitCode

public static RetObj Split(ConfObj input, UpdateProgress updateProgress)
{
	int numOfPages = input.toPage - input.fromPage + 1;                               
	// save each image
	for (int i = 0; i < numOfPages; i++)
	{
		_coder.Save(input.fromPage - 1 + i);
		// ... SNIP ...
	}
	// ... SNIP ...
}


Hmm, it looks simple. But who is _coder? How does it able to distinguish PDF, TIFF or JPG? Different format definitely requires different treatment right (or so I thought) ?

The secret is in Prepare and CoderFactory method.

public static RetObj Prepare(ConfObj input, out int numOfPages)
{
	// .. Snipped: Validate input file ..	

	// overwrite output type if the input is PDF
	if (ext.ToUpper() == ".PDF")
		input.outputType = OutputType.PDF;

	// create output coder
	_coder = CoderFactory(input.outputType);

	// open file
	numOfPages = _coder.LoadImage(input.inputFile);

	// prepare
	_coder.Prepare(input);

	return retobj;
}

static private ICoder CoderFactory(OutputType type)
{
	switch (type)
	{
		case OutputType.TIF:
			return new TiffCoder();
		case OutputType.JPG:
			return new JpegCoder();
		case OutputType.PDF:
			return new PDFCoder();
		default:
			throw new Exception("Unknown output format.");
	}
}


So now it's clear that the actual loading and splitting in classes which implement ICoder interface. So for Tiff, the work is done by TiffCoder

public class TiffCoder : ICoder
{
	private Image _image;
	private FrameDimension _dim;
	
	// ... SNIP ...

	public int LoadImage(string fileName)
	{
		_inputImageName = fileName;
		_image = Image.FromFile(fileName);
		Guid guid = _image.FrameDimensionsList[0];
		_dim = new FrameDimension(guid);
		return _image.GetFrameCount(_dim);
	}


	public void Save(int pageNum)
	{
		_image.SelectActiveFrame(_dim, pageNum);
		string outputFileName = null;

		// ... SNIP: Output file name

		if (!_config.doOverwrite)
		{
			outputFileName = HelperMethods.ModifyFileName(outputFileName);
		}

		_image.Save(outputFileName);
	}

	// ... SNIP ...
}


Well that's interesting. The program actually uses .NET's System.Drawing.Image instead of some external library to handle TIFF. As a dig deeper, I found out that System.Drawing is actually a managed interface to Windows' native library, GDI+ (mind blown!)

I'll stop my exploration here, perhaps in the future I'll have the motivation to dig deeper than today. For more reading please check the following references:

  1. System.Drawing.Image source code
  2. brief introduction to GDI
  3. Microsoft GDI+ page

About Hardono

Hi, I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 9 years.