{{error}}
{{(quickSearchResults.length>10)?'10+':(quickSearchResults.length)}} {{(quickSearchResults.length==1)?'result':'results'}}
{{result.title}} {{result.timeStamp | mysql2ymd }}
I am sorry, no such article was written yet.
HTML5 Canvas - sample gauge for smart home monitoring systems
Wrapper over HTML5 canvas for polar drawing (coordinates origin are in the centre of the canvas, the angle coordinate goes anti-clockwise, and the unitary magniture is the minimum of width and height of canvas) is attached. Instantiation is:
		var canvas=document.getElementById(dialName+"_z");
		var drawing=new Drawing(canvas);
. Sample usage (partial code) is in Sample.js. Result is:

2 files attached: Canvas.js Sample.js
Canvas.js Sample.js
:for(var sensorIdx=0;sensorIdx<sensors.length;sensorIdx++){
	var dialName=sensors[sensorIdx];
	var canvas=document.getElementById(dialName+"_z");
	var drawing=new Drawing(canvas);
	drawing.clear();
	drawing.circle({w:0.5,r:1,fg:'#000',bg:'#448'});
	drawing.circle({r:0.85,fg:'#111',bg:'#eee'});
	drawing.line({w:4,fg:'#f00',from:{a:Math.PI/2,m:0},to:{a:Math.PI/2,m:0.98}});
	drawing.line({w:2,fg:'#ff0',from:{a:Math.PI/2,m:0},to:{a:Math.PI/2,m:0.97}});
	for(var hour=1;hour<=12;hour++){
		drawing.line({w:0.25,fg:'#777',from:{x:0,y:0},to:{a:offsetA-Math.PI*2*(hour)/(12),m:0.85}});
		drawing.text({a:offsetA-Math.PI*2*(hour)/(12),m:0.925,text:hour,size:0.125,fg:'#bbb'});
	}
	:
	if(MOUSE_OVER){
		if(dialName==MOUSE_OVER.sensor){
			MOUSE_OVER.at=Math.atan2(-MOUSE_OVER.y+canvas.height/2,MOUSE_OVER.x-canvas.width/2);
			while(MOUSE_OVER.at<0)
				MOUSE_OVER.at+=2*Math.PI;
			while(MOUSE_OVER.at>=2*Math.PI)
				MOUSE_OVER.at-=2*Math.PI;
			drawing.line({from:{a:0,m:0},to:{a:MOUSE_OVER.at,m:0.85},w:2,fg:'#f70'});
		}
	}
	:
	drawing.circle({w:0.5,r:0.4,fg:'#000',bg:'#dde'});
	var params={};
	drawing.text({x:0,y:1.2,text:allSensors[sensorProperties.name].label,size:0.2,align:'center',bg:'#000',fg:'#ff0'});
	var lastPoint=null;
	var tooltips=[];
	for(var dataIdx=0;dataIdx<data.length;dataIdx++){
		var x=data[dataIdx][0];
		if(lastTS-x>1000000)continue;
		if(!minTSIdx)minTSIdx=dataIdx;
		if(data[minTSIdx][0]>x)
			minTSIdx=dataIdx;
		var y=data[dataIdx][1+json.sensor2column[sensorProperties.name]];
		if(!data[dataIdx][1+json.sensor2column[sensorProperties.name]])continue;
		if((x==null)||(y==null))continue;
		x/=100;
		var min=x%100;
		var hour=((x-min)/100)%100;
		var params={};
		params.w=0.5+3*dataIdx/data.length*dataIdx/data.length;
		params.from=lastPoint;
		var chan=2.5+2.5*Math.sin(Math.PI*2*((12+6+hour-1)/24));
		chan=Math.round(chan);
		params.fg='rgba('+chan*255/5+',0,'+(5-chan)*255/5+','+(1)+')';
		params.to={};
		params.to.a=offsetA-2*Math.PI*(hour/12+min/12/60);
		while(params.to.a<0)
			params.to.a+=2*Math.PI;
		while(params.to.a>=2*Math.PI)
			params.to.a-=2*Math.PI;
		params.to.m=(y-minVal)/(maxVal-minVal)*0.4+0.4;
		params.y=y;
		if(lastPoint){
			drawing.line(params);
			if(MOUSE_OVER)
			if(dialName==MOUSE_OVER.sensor){
					//alert(params.from.a);
						//alert([params.from.a,MOUSE_OVER.at,params.to.a]);
						if(between(params.from.a,MOUSE_OVER.at,params.to.a)){
							if(tooltips.length==2)
								alert([params.from.a,MOUSE_OVER.at,params.to.a]);
							tooltips.push(dataIdx);
						}
				}
		}
		lastPoint=params.to;
	}
	var rezolutie=allSensors[sensorProperties.name].resolution;
	//alert(rezolutie);
	var actualValue=Math.round(params.y/rezolutie)*rezolutie;
	var yesterdaysValue=Math.round(data[minTSIdx][colIdx]/rezolutie)*rezolutie;
	actualValue=1*actualValue.toFixed(6);
	yesterdaysValue=1*yesterdaysValue.toFixed(6);
	var delta=actualValue-yesterdaysValue;
	delta=1*delta.toFixed(6);
	if(delta>0)
		delta='+'+delta;
	delta=delta+' ';
	//alert(data[minTSIdx][0]);
	drawing.text({x:0,y:-0.34,text:minVal,size:0.1,bg:"#bbb"});
	drawing.text({x:0,y:+0.34,text:maxVal,size:0.1,bg:"#bbb"});
	if(actualValue>yesterdaysValue){
		drawing.text({x:0,y:0.2,text:actualValue,size:0.25,align:'center',fg:params.fg,bg:params.fg});
		drawing.text({x:0,y:0,text:delta+"&#8599;",size:0.1,bg:"#f00",align:"center"});
		drawing.text({x:0,y:-0.15,text:allSensors[sensorProperties.name].um,size:0.2,align:'center',fg:params.fg,bg:params.fg});
		//drawing.text({x:0,y:-0.05,text:delta,size:0.1,align:"center"});
	}else if(actualValue<yesterdaysValue){
		drawing.text({x:0,y:0.2,text:actualValue,size:0.25,align:'center',fg:params.fg,bg:params.fg});
		drawing.text({x:0,y:0,text:delta+"&#8600;",size:0.1,bg:"#00f",align:"center"});
		drawing.text({x:0,y:-0.15,text:allSensors[sensorProperties.name].um,size:0.2,align:'center',fg:params.fg,bg:params.fg});
		//drawing.text({x:0,y:-0.05,text:,size:0.1,align:"center"});
	}else{
		drawing.text({x:0,y:0,text:actualValue+allSensors[sensorProperties.name].um,size:0.2,align:'center',fg:params.fg,bg:params.fg});
	}
JackRabbit JCR - initial setup and "Hello World" to check that R/W access was granted
How I made the first Jackrabbit JCR have R/W access on the local environment. The smoke test (ran from a different application) is mentioned in SmokeTest.java. The reason I published this trivial code snippet (most of it copied from somewhere from the internet) is that I got frustrated for hours searching for a working snippet to grant me writing access.
2 files attached: Test.java SmokeTest.java
Test.java SmokeTest.java
Node root=session.getRootNode();
System.out.println(root.addNode("message!").getPath());
root.setProperty("number",123); System.out.println(root.getPath());
System.out.println(root.getNode("message!"));
How to batch-kill processes in Windows from command prompt - taskkill /im image.exe /t /f
Automating web pages in Chrome using Selenium leads to lots of Chrome windows open that even if closed, the driver remains open. I am using the command taskkill /im chromedriver.exe /t /f to:
  • close all the Chrome Driver server processes;
  • close the Chrome Driver server process tree of children (/t);
  • close the Chrome Driver server processes forcefully (/f);
How to parse in PHP the cPanel mime type configuration, and how to filter the files using the .htaccess
Hosting more sites on a single IP and with an economic entry-level support from ISP (but still, allowed to process requests from more domains through the same PHP engine) leads to a long series of challanges.
One of them is that even though each site has its own files structured in its own folder, in case that a file was not found or there were conflicting files, the server seemed to pick randomly a file from another domain's folder.
Problem looked solved with the following configuration:
#Resources to their folders
RewriteCond %{REQUEST_URI} \.(pdf|doc|xml|pem|crx|apk|svg)$
RewriteCond %{DOCUMENT_ROOT}/%{HTTP_HOST}%{REQUEST_URI} -f
#RewriteCond %{DOCUMENT_ROOT}/%{HTTP_HOST}%{REQUEST_URI} !-d
RewriteRule ^(.+)$ %{HTTP_HOST}%{REQUEST_URI}
But it does not do what it should obviously do (due to whatever small detail, mistake, or misunderstanding from my side), so I found myself in need to filter the files through PHP code (yes, I know, let the web server deliver the static file contents). But until this will happen, I had to urgently improvise the code below.
The problem got solved by .htaccess-routing all the txt|png|jpeg|... to .mimeDelivery.php code (mentioned below).
The principle is that the script picks all the htaccessed mime types (as saved by cPanel in Perl store (serialized form). Perl deserialization algorithm is mentioned below.
1 files attached: Algorithm.php
Algorithm.php
Android - how to find the physical size of a display - using the DPI/PPI scale
Most of solutions found on internet compute the diagonal of the display by dividing the number of pixels to the DPI resolution. The capital mistake is that the DPI returns the dots per inch, and not the pixels. For this, you may use the scaledDensity to convert from DPI to PPI.
		float x=outMetrics.widthPixels/outMetrics.xdpi;
		float y=outMetrics.heightPixels/outMetrics.ydpi;
		double diag=Math.hypot(x, y);
		double physicalDiagonal=diag/outMetrics.scaledDensity;
		s+="Diag. logică: "+diag+";\n";
		s+="Diag. fizică: "+diag/physicalDiagonal+"\"";
Simple universal HTML client filter
A simple JS script for HTML client-side filtering of nodes:
function filterNodes(jQuerySet,value){
	value=(""+value).toUpperCase();
	var values=value.split(" ");
	var signs=[];
	for(var i=0;i<values.length;i++){
		if(values[i].charAt(0)=='!'){
			signs[i]=1;
			values[i]=values[i].substr(1);
		}
		values[i]=unescape(values[i]);
	}
	var nodes=jQuerySet;
	for(var i=0;i<nodes.length;i++){
		var nodeValue=nodes[i].innerHTML.toUpperCase();
		try{
			nodeValue=nodeValue.replace(/<[^>]+>/g, '');
		}catch(e){}
		$temporaryValue=1;
		if(value!='')
			for(var j=0;j<values.length;j++)
				if(values[j])
					if(signs[j]^(nodeValue.indexOf(values[j])<0)){
						$temporaryValue=false;
						break;
					}
		if($temporaryValue)
			$(nodes[i]).show();
		else
			$(nodes[i]).hide();
	}
}
How to request and generate authentication nonces via emails
Some clues on how to implement a fast ad-hoc authentication mechanism based on the email of the user.
  1. Publish a page where the user may request the ad-hoc token;
  2. On the ad-hoc page request the user to input the email address;
    • To avoid bot spamming you may generate the form field name based on a secret name stored on the server-side session;
    • As a consequence, the submitted form must always come as a response to a pre-exising server session, session that is not preserved using the classical curl libraries used by bots;
  3. An email with the nonce will be sent to the given address;
    • The nonce will be stored only on the server side, so the only way to know it is to open the email - which means that the user has access to the given mail;
  4. The user will put the nonce from mail in form; together with the nonce, the server will keep in session also the generation time;
Advantages:
  • nonce may be short, it does not have to be long and secure;
  • only the server side and the email address owner have access to nonce;
  • nonce cannot be reused if another one has been generated for that given session;
  • the mechanism guarantees that the owner of the mail address is the user of the page;
  • the user does not need any 3rd party credentials authority supplier.
Menu sample:
1 files attached: OpenIdAuthenticationProvider
OpenIdAuthenticationProvider
Emgu.CV video surveillance - part 2: how to keep only relevant images
One big issue in video surveillance is disseminating between relevant images and irrelevant images. For such comparison we need to compute the distance between two images, and for this a first step would be to bring images to only one relevant chanel, as example being:
  • luminosity channel - for comparing high resolution noiseless images;
  • crominance channel - when we have goot luminosity, but it changes over time;
Once we decide on the relevant channel for comparison, the next step is to filter the image (remove the noise). For this task I used the simple erode/dilate method mixed with median smoothing.
Once images are softened, I just compute the norm of the binary difference.
As seen in this code, I do run differences between thumbnails of images (which is much faster than the full image comparison.
Very important is that the value of threshold which is in my case 24 was not chosen randomly, but it is the one that gives best results on images both on day and night time.
To reach this value of 24 I ran tests on samples as following:
  • night time similar images;
  • night time small-difference images;
  • day time similar images;
  • day time small-difference images.
Even though the algorithm seems quite simple, it took me around one week to reach to it, as before I used various much more complex adaptive algorithms depending on other properties of images (including median luminance and noise quantity in image). At the end I reached to this very simple solution that brings the same quality but with much less code and much less complexity.
1 files attached: Campture.cs
Campture.cs
C#-Selenium bridge to automate browser application testing
Depending on the application under test and the technical restrictions you may need to test applications on different platforms. One solution is to use Selenium. However, a huge limitation of Selenium is that windows cannot be reused. In order to automate various browsers my recommended way is to plug Selenium in a host (C#, Java, Python, or whatever else).
Attached is a scripting engine I used to automate with Selenium over C#. As a precondition, you need to import in the project the browser connectors:
  • chromedriver.exe
  • IEDriverServer.exe
The Firefox connector comes out of the box with Selenium.
Another important component is the attached test set class.
This second class is the big thing in application, which will be able to parse files as in main.dms. Or, sample1.dms, and sample2.dms.
5 files attached: SeleniumWrapper.cs TestSet.cs test.dms sample1.dms sample2.dms
SeleniumWrapper.cs TestSet.cs test.dms
#browser ie
#on step.before step_before.js

#timeout 20
#include login.dms

#include client_sim_add-remove.dms
#include client_people.dms
sample1.dms
window.location="http://betalogin.mdmconsole.com";
UNTIL => (''+window.location).match('^http://hidden-url.com/')

##Login > input email, password
$('input#email') <= 'secret@example.com'
$('input#password') <= 'secret-password'
##Login > click Login
$CLICK => $('button:contains(\"Login\")')
##Console > Wait for "Logout" button to appear
UNTIL => $('button:contains(\"Logout\")').length==1
##Console > Log in as
$CLICK => $('button:contains("Log in as")')
##Console > Log in as > roles := client; userId:=SecretUser*
$CLICK => $('input#roles').siblings("img")
$CLICK => $('.x-combo-list-item:contains("Client")')
$CLICK => $('input[name="userID"]').siblings('input[value^="Akela"]')
##Console > Click "Log in"
$CLICK => $('#btnLogin button:contains("Log in")')
sample2.dms
##People
$CLICK => $('#nav-Endusers button:contains("People")')
##People > Add
$CLICK => $('table:contains("Export to CSV") button:contains("Add")')
##People > Add > first_name, last_name, email, owner language, pass1, pass2, Active:=true, Save
$(':contains("Person details") input[name="first_name"]') <= d2a('%EXECUTION_ID%FirstName')
$(':contains("Person details") input[name="last_name"]') <= d2a('%EXECUTION_ID%LastName')
$(':contains("Person details") input[name="email"]') <= d2a('e%EXECUTION_ID%@example.com')
$('#EditPersonWindow input#ownerLanguage') <= 'English'
$('#EditPersonWindow input#pass1') <= d2a('%EXECUTION_ID%')
$('#EditPersonWindow input#pass2') <= d2a('%EXECUTION_ID%')
$('#EditPersonWindow label:contains("Active:")').siblings().find("input") <= true
$CLICK => $('#EditPersonWindow button:contains("Save")')
UNTIL => $('#EditPersonWindow').length==0
C# Emgu.CV video surveillance - part 1: how to capture snapshots every few seconds
A sample application to capture every two seconds a photo with the video camera using Emgu.CV on C#.
1 files attached: EmguCapture.cs
EmguCapture.cs
using Emgu.CV;
using System.Collections;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;
using Emgu.CV.Structure;
using Emgu.CV.Features2D;
using System;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;

namespace ConsoleApplication2
{
	class Program
	{
		static void Main(string[] args)
		{
			if (args.Length!=0){
				if (args[0] == "start")
					CaptureStart();
				if (args[0] == "stop")
					CaptureStop();
			}
			Console.WriteLine("Capture start | stop");
		}
		public static void CaptureStart()
		{
			var signature = "" + new Random().Next();
			Config.set("capture-session", signature);
			Capture c = new Capture();
			c.SetCaptureProperty(CAP_PROP.CV_CAP_PROP_FRAME_WIDTH, 1024);
			c.SetCaptureProperty(CAP_PROP.CV_CAP_PROP_FRAME_HEIGHT, 768);
			for (;;)
			{
				if (Config.get("capture-session") != signature) return;
				try
				{
					Thread.Sleep(3000);
					var thumbnail = c.QueryGrayFrame();
						Storage.Save(c.QueryFrame());
				}
				catch (Exception e)
				{
					Console.WriteLine(e.StackTrace);
				}
			}
		}
		public static void CaptureStop()
		{
			Config.set("capture-session", "");
		}
	}
}