function convertTxt2Html(txt, m)
	{
		var nlPos = [], p = -1, html = '';

		while ((p = txt.indexOf('\n', p + 1)) > -1)
		{
			nlPos.push(p + 1);
		}

		m.sort(function(a, b)
		{
			return a.s - b.s;
		});

		var sMap = {}, ends = [];

		for (var i = 0; i < m.length; i++) //TODO Using newlines to mark the end of blocks without end has some issues 
		{
			var item = m[i];
			
			if (sMap[item.s] == null)
			{
				for (var j = 0; j < nlPos.length; j++)
				{
					if (nlPos[j] > item.s)
					{
						sMap[item.s] = nlPos[j];
						break;
					}
				}

				if (sMap[item.s] == null)
				{
					sMap[item.s] = txt.length;
				}
			}

			if (item.e == null)
			{
				item.e = sMap[item.s];
			}

			ends.push(item);
		}

		ends.sort(function(a, b)
		{
			return a.e - b.e;
		});

		var i = 0, j = 0, curStyles = {}, openTags = [], openTagsCount = [], listActive = false, listType, listItemActive = false;
		
		function startTag(styles, newBlock)
		{
			var str = '';
			var tagCount = 0;
			var t = styles['t'];

			if (styles['lk'])
			{
				var lk = styles['lk'];
				
				if (lk.v != null && lk.v.length > 0 && lk.v[0].tp == 'ext')
				{
					str += '<a href="' + lk.v[0].url + '">';
					openTags.push('a');
					tagCount++;
				}
			}
			
			if (newBlock)
			{
				var l = styles['l'] || {};
				
				if (t != null && (listActive == false || listActive != t.v || listType != l.v))
				{
					if (listActive)
					{
						str += endTag();
					}
					
					listActive = t.v;
					listType = l.v;
					
					if (t.v == 'ul')
					{
						str += '<ul ';
						openTags.push('ul');
					}
					else
					{
						str += '<ol ';
						openTags.push('ol');
					}
					
					openTagsCount.push(1);
					str += 'style="margin: 0px; text-align:' + (styles['a']? styles['a'].v : 'left') + '; list-style-type:';
					
					if (t.v == 'hl')
					{
						str += 'upper-roman';
					}
					else
					{
						switch(l.v)
						{
							case 'auto':
								str += 'disc';
								break;
							case 'inv': //Approx
								str += 'circle';
								break;
							case 'disc': 
								str += 'circle';
								break;
							case 'trib': //Approx
								str += 'square';
								break;
							case 'square':
								str += 'square';
								break;	
							case 'dash': //Approx
								str += 'square';
								break;	
							case 'heart': //Approx
								str += 'disc';
								break;
							default:
								str += 'decimal';					
						}
					}
					
					str += '">';
				}
				else if (t == null)
				{
					if (listActive)
					{
						str += endTag();
						listActive = false;
					}

					str += '<div style="';
					openTags.push('div');
					tagCount++;
				}
			}
			else
			{
				if (listActive && !listItemActive)
				{
					str += endTag();
					listActive = false;
				}
				
				str += '<span style="';
				openTags.push('span');
				tagCount++;
			}

			if (newBlock && t != null)
			{
				listItemActive = true;
				str += '<li>';
				openTags.push('li');
				tagCount++;
				
				str += '<span style="';
				openTags.push('span');
				tagCount++;
			}

			if (styles['s'])
			{
				str += 'font-size:' + Math.round(styles['s'].v * scale) + 'px;';
			}

			if (styles['c'])
			{
				var v = styles['c'].v;
				
				if (v != null)
				{
					if (v.charAt(0) != '#')
					{
						v = '#' + v;
					}

					v = v.substring(0, 7);
					str += 'color:' + v + ';';
				}
			}

			if ((styles['b'] && styles['b'].v) || (styles['fc'] && styles['fc'].v && styles['fc'].v.indexOf('Bold') == 0))
			{
				str += 'font-weight: bold;';
			}
			
			if (styles['i'] && styles['i'].v)
			{
				str += 'font-style: italic;';
			}

			if (styles['u'] && styles['u'].v)
			{
				str += 'text-decoration: underline;';
			}

			if (!listActive)
			{
				str += 'text-align: ' + (styles['a']? styles['a'].v : 'center') + ';';
			}
			
			if (styles['il'])
			{
				str += 'margin-left: ' + Math.round(styles['il'].v * scale - (listActive? 21 : 0)) + 'px;';
			}

			if (styles['ir'])
			{
				str += 'margin-right: ' + Math.round(styles['ir'].v * scale) + 'px;';
			}

			if (styles['mt'])
			{
				str += 'margin-top: ' + Math.round(styles['mt'].v * scale) + 'px;';
			}

			if (styles['mb'])
			{
				str += 'margin-bottom: ' + Math.round(styles['mb'].v * scale) + 'px;';
			}

			str += '">'
			openTagsCount.push(tagCount);

			return str;
		};

		function endTag(txt, curS, curE, all)
		{
			var str = txt? txt.substring(curS, curE) : '';

			//TODO Check this is always the case. Most of the time this is correct, also, the empty tag should be removed
			if (str == '\n')
			{
				str = '';
			}
			
			str = str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
			
			do
			{
				var count = openTagsCount.pop();
	
				for (var i = 0; i < count; i++) 
				{
					var tag = openTags.pop();
					
					if (tag == 'li')
					{
						listItemActive = false;
					}
					
					str += '</' + tag + '>';
				}
			}
			while(all && openTags.length > 0);

			return str;
		}
		
		var curS = 0, curE = 0;
		
		while(i >= j && (i < m.length || j < ends.length))
		{
			var s = m[i], e = ends[j];

			if (s && e && s.s < e.e) //s can be null when all starts are used, e ends after s BUT sometimes there are errors in the file
			{
				curS = s.s;
				var newBlock = false;

				if (curS - curE > 0)
				{
					html += startTag(curStyles, newBlock) + endTag(txt, curE, curS); 
				}
				
				while(s != null && s.s == curS)
				{
					//TODO alignment ('a') sometimes introduce unnecessary new lines. Maybe use newline to define block elements
					if (s.n == 'a' || s.n == 'il' || s.n == 'ir' || s.n == 'mt' || s.n == 'mb' || s.n == 't')
					{
						newBlock = true;
					}
					
					curStyles[s.n] = s;
					s = m[++i];
				}
				
				html += startTag(curStyles, newBlock);
			}
			else if (e)
			{
				curE = e.e;

				do
				{
					delete curStyles[e.n];
					e = ends[++j];
				}
				while(e != null && e.e == curE);
				
				html += endTag(txt, curS, curE);
				curS = curE;
			}
		}
		
		html += endTag(null, null, null, true); //End any open tag

		return html;
	}
Handles paste from Lucidchart

TODO: Move to dynamic loading minimized plugin.