Tuesday, October 13, 2015

What technology that helps the blind

Ten years ago, I evaluated a number of technologies that is of use to visually handicapped (VH). It was quite a fruitless search. Ten years later I attended the China Information Accessibility Forum in Beijing and it showed quite a number of improvement. The following is a description of some of the technologies available as gathered from the forum.

I am not a fan of Apple iPhone but I do admire the free VoiceOver accessibility feature available. With it, VH can use the phone almost as easily as others.  There were apps written to help blinds. Ariande can help blind navigate places alone. LookTell Money reader can read money denominations (only US$). Color ID Free can read colors (can only read simple color). VizWiz provides human assistance to help VH. Android has assistive technology also but is a far fetch from VoiceOver.

Another technology by Apple is also of interest. It is the iBeacon technology. This technology allows a BT beacon to beam its proximity and some static information to the user. Obviously, user must use iPhone to do it. (Android have apps that can do it too.) It has a number of applications for VH. If every bus could be equipped with such beacon, it would help VH to detect which bus is the required one.

If the beacon can be fixed on every bus stop then VH will know which one to disembark on the last announced stop. If a building is equipped with Beacon, It will greatly help VH or sighted to know their exact location with a given virtual map of the building. Even those sighted can get lost in a very large shopping mall. Android has yet to catch up on this. Samsung is reportedly following suit but I am yet to see it.

Voice dictation system. Microsoft demonstrated its Cortana system that integrates voice recognition with linkage to app activation - a sort of personal assistance. Although it failed several times to perform during the presentation, it nevertheless a good technology to adapt for the blind. I have not seen Apple Siri at work but it is basically implemented much earlier than Microsoft. Android does not have one but there are quite a number of apps that does the same. How good is it is yet to be ascertained.

Obstacle Avoidance and Detection system. This technology was not that new but has not been very successful. Saw a video on this system. It could be helpful but as far as I know, detecting suspended small/pointed objects is still an issue.

Object location tag. Saw from booths in the forum that allows items to be tagged with a tag that has a buzzer built in. You could call up to 8 devices per calling device. It is nothing new just that the idea is rather interesting. If they could make it into adhesive tag then its use might be wider. I would like to see something like a RFID. It uses passive tags. The reader must be able to pinpoint the tag among other tags.

Face recognition and detection. According to the demonstrator, it helps the blind to be able to talk to others face-to-face by detecting where is the person. It allows pre-recorded face so that it can even announce the person's name. It did recognize me as a 50 plus old anonymous guy.

Small MP3 like equipment that can play music and read documents (without screen) is something of interest. A number of companies were making it. I would be more interested if it can automatically change language according to the mixed language document.

PC screen reader. It has been ages since this technology is available. Nothing much changed. Laptops and PC sales are going down due to increasing mobile handphone use. It is sunset technology.

Some researcher was trying to integrate all the technologies in one app. It might be useful but probably takes decades to do so.

One biggest challenge is to make the equipment affordable. Many of the VH have low or no income. Having such equipments are next to impossible. Don't forget many of the equipment requires internet access. There is a monthly bill to pay. Many equipments also require general public to take part like iBeacon for buildings/bus. The infrastructure cost is huge. Other VH are also illiterate. Coaxing, educating them enough to use such equipments is a long and tedious task.





Sunday, September 13, 2015

Passing parameters to Filemaker Script

Filemaker only accept one parameter when you "perform script". There are many suggestions to pass more than one parameters. Some use custom functions. One of the most noted function is #Parameters. It stores name and value set into a dictionary. Others suggest using "List".

For those who do not use Filemaker advanced, there is no way to create custom functions. For list, if you just pass it a list of values separated by "carriage return". The only problem is that if you passed a blank value, the next value will be used instead. This caused considerable inconveniences.

Some others passes a XML or JSON as parameter and it requires a function to do the extraction. I guess this is the best way to do it. The following is an example of getting the variable value by creating a XML, stored as global value and call the script with node name as parameter.

# Construct a xml for all the variable and values. Store as global variable $$xml
# The passed xml must not contain carriage return just join all the nodes end to end
# The xml constructed must also be escaped to make it valid.
Set Variable [ $pkey ; Value: Get(ScriptParameter) ] 
Set Variable [ $$xml ; Value: Substitute ( $$xml ; "><" ; ">"  & ¦ & "<" ) ] 
Set Variable [ $ccount ; Value: 1 ] 
Set Variable [ $pcount ; Value: PatternCount ( $$xml ; ¦ ) ] 
Set Variable [ $pvalue ; Value: "" ] 
Loop
 Exit Loop If [ $ccount > $pcount ] 
 Set Variable [ $xsearch ; Value: GetValue($$xml;$ccount) ] 
 Show Custom Dialog [ "test" ; $xsearch ] 
 If [ PatternCount ( $xsearch ; "<" & $pkey & ">" ) =1 ] 
  Set Variable [ $pvalue ; Value: Let ( [ $p = Substitute ( $xsearch ; "<" & $pkey & ">" ; "" ) ; $p = Substitute ( $p ; "</" & $pkey &">" ; "" )] ; $p ) ] 
  Set Variable [ $ccount ; Value: $pcount ] 
 End If
 Set Variable [ $ccount ; Value: $ccount+1 ] 
End Loop
Exit Script [ Result: $pvalue ] 

Note that the | symbol is actually the Filemaker "carriage return" sign.

Recent development see another way of passing parameters. This is done by using JSON. Filemaker has added functionalities to read/write the elements of JSON. It makes passing parameters much easier with much less hassles.





Friday, September 11, 2015

Filemaker example of Xpath

Previously I talked about using Filemaker to extracting xml node text without using plugins. I have created a working script that does just that. You just need to call the first script that does a "Tidy". The script will remove unnecessary carriage return, tabs and extra spaces between nodes. It also add carriage return after every node. You can get the node text value by adding the xpath path with a carriage return in front of the xml as one parameter to the second script.

The reason for putting them in two script is that you only need to "Tidy" the xml once but you need execute  the second script a number of times to extract multiple node values.

The first script is called "xtidy". The script is as follows

Set Variable [ $xml ; Value: Get(ScriptParameter) ] 
Set Variable [ $xlen ; Value: Length ( $xml ) ] 
Set Variable [ $ccount ; Value: 1 ] 
Set Variable [ $xout ; Value: "" ] 
Set Variable [ $xfound ; Value: 0 ] 
Set Variable [ $xtext ; Value: "" ] 
Loop
 Exit Loop If [ $ccount > $xlen ] 
 Set Variable [ $xsearch ; Value: Middle ( $xml ; $ccount ; 1) ] 
 If [ $xsearch = ">" ] 
  Set Variable [ $xfound ; Value: 1 ] 
  Set Variable [ $xout ; Value: $xout & $xsearch ] 
 Else If [ $xsearch = "<" ] 
  Set Variable [ $xtext ; Value: Substitute ( $xtext ; Char ( 13 ) ; "" ) ] 
  Set Variable [ $xtext ; Value: Substitute ( $xtext ; Char ( 11 ) ; "" ) ] 
  Set Variable [ $xtext ; Value: Trim ( $xtext ) ] 
  Set Variable [ $xout ; Value: $xout & $xtext & "<" ] 
  Set Variable [ $xtext ; Value: "" ] 
  Set Variable [ $xfound ; Value: 0 ] 
 Else If [ $xfound = 1 ] 
  Set Variable [ $xtext ; Value: $xtext & $xsearch ] 
 Else
  Set Variable [ $xout ; Value: $xout & $xsearch ] 
 End If
 Set Variable [ $ccount ; Value: $ccount+1 ] 
End Loop
Set Variable [ $xout ; Value: Substitute ( $xout ; "><" ; ">" & ¦ & "<" ) ] 
Exit Script [ Result: $xout ] 
The second script is call "Xpath". The script is as follows



# Just add the path with a carriage return to the xml like $xpath & $xml as parameter
Set Variable [ $xml ; Value: Get(ScriptParameter) ] 
Set Variable [ $xmlcount ; Value: PatternCount ( $xml ; ¦ ) ] 
Set Variable [ $xpath ; Value: GetValue($xml;1) ] 
Set Variable [ $xpath ; Value: Substitute ( $xpath ; "//" ; "" ) ] 
Set Variable [ $xcount ; Value: PatternCount ( $xpath ; "/" )+1 ] 
Set Variable [ $xpath ; Value: Substitute ( $xpath ; "/" ; ¦ ) ] 
Set Variable [ $pathLevelCount ; Value: 0 ] 
Set Variable [ $pathRepeatCount ; Value: 0 ] 
Set Variable [ $lastXsearch ; Value: "" ] 
Set Variable [ $lastXsearchCount ; Value: 0 ] 
Set Variable [ $xmlresult ; Value: "" ] 
Set Variable [ $xcurPath ; Value: "/" ] 
Set Variable [ $xlevel ; Value: 0 ] 
Set Variable [ $xlevelCurrent ; Value: 0 ] 
Set Variable [ $ccount ; Value: 1 ] 
Set Variable [ $xml ; Value: Middle ( $xml ; Position ( Upper ($xml) ; "" ; 1 ; 1 )+15 ; Position ( Upper($xml) ; "" ; 1 ; 1 )-Position ( Upper($xml) ; "" ; 1 ; 1 )-15 ) ] 
Set Variable [ $xmlcount ; Value: PatternCount ( $xml ; ¦ ) ] 
# Script to find lowest level of the first search path
Loop
 Exit Loop If [ $ccount > $xmlcount ] 
 Set Variable [ $xsearch ; Value: GetValue($xml;$ccount) ] 
 If [ Left ( $xsearch ; 2 ) = "</" ] 
  Set Variable [ $xlevelCurrent ; Value: $xlevelCurrent-1 ] 
 Else If [ PatternCount ( $xsearch ; "<" ) = 1 ] 
  Set Variable [ $xlevelCurrent ; Value: $xlevelCurrent+1 ] 
 End If
 Set Variable [ $xnode ; Value: Middle ( $xsearch ; 2 ; Position ( $xsearch ; ">" ; 1 ; 1 )-2) ] 
 If [ PatternCount ($xnode;"/")  ­ 0 ] 
  Set Variable [ $xnode ; Value: ¦ & ¦ & ¦ & ¦ ] 
 End If
 If [ Position ( GetValue($xpath;1) ; $xnode ; 1 ; 1 )  > 0 ] 
  If [ $xlevel = 0 ] 
   Set Variable [ $xlevel ; Value: $xlevelCurrent ] 
  Else If [ $xlevel > $xlevelCurrent ] 
   Set Variable [ $xlevel ; Value: $xlevelCurrent ] 
  End If
 End If
 Set Variable [ $ccount ; Value: $ccount + 1 ] 
End Loop
Set Variable [ $xlevelCurrent ; Value: 0 ] 
Set Variable [ $ccount ; Value: 1 ] 
Loop
 Exit Loop If [ $ccount > $xmlcount ] 
 Set Variable [ $xsearch ; Value: GetValue($xml;$ccount) ] 
 If [ Left ( $xsearch ; 2 ) = "</" ] 
  Set Variable [ $xlevelCurrent ; Value: $xlevelCurrent-1 ] 
 Else If [ PatternCount ( $xsearch ; "<" ) = 1 ] 
  Set Variable [ $xlevelCurrent ; Value: $xlevelCurrent+1 ] 
 End If
 # Look for path start
 Set Variable [ $xpathtxt ; Value: GetValue($xpath;$pathLevelCount+1) ] 
 If [ Position ( $xpathtxt ; "[" ; 1 ; 1 )  ­ 0 ] 
  Set Variable [ $xpathary ; Value: Substitute ( $xpathtxt ; "[" ; ¦ ) ] 
  Set Variable [ $xtxt ; Value: GetValue($xpathary;1) ] 
  Set Variable [ $ycount ; Value: GetAsNumber ( GetValue ( $xpathary ; 2 ) ) ] 
 Else
  Set Variable [ $xtxt ; Value: $xpathtxt ] 
  Set Variable [ $ycount ; Value: 1 ] 
 End If
 # Look for path end
 Exit Loop If [ Position ( $xsearch ; $lastXsearch ; 1 ; 1 ) = 1 ] 
 If [ Position ( $xsearch ; "<" & $xtxt & ">" ; 1 ; 1 ) = 1 and $xlevelCurrent = $xlevel+$pathLevelCoiunt ] 
  Set Variable [ $pathRepeatCount ; Value: $pathRepeatCount+1 ] 
  If [ $pathRepeatCount=$ycount and $pathLevelCount  < $xcount ] 
   Set Variable [ $pathLevelCount ; Value: $pathLevelCount+1 ] 
   Set Variable [ $lastXsearch ; Value: "</" & $xsearch & ">" ] 
  End If
  If [ $pathLevelCount = $xcount and $pathRepeatCount = $ycount ] 
   Set Variable [ $xmlresult ; Value: Middle ( $xsearch ; Position ( $xsearch ; ">" ; 1 ; 1 )+1 ; Position ( $xsearch ; "<" ; 1 ; 2 )-Position ( $xsearch ; ">" ; 1 ; 1 )-1 ) ] 
   Set Variable [ $ccount ; Value: 50 ] 
  End If
  If [ $pathRepeatCount=$ycount and $pathLevelCount < $xcount ] 
   Set Variable [ $pathRepeatCount ; Value: 0 ] 
   Set Variable [ $lastXsearch ; Value: "</" & $xtxt & ">" ] 
  End If
 End If
 Set Variable [ $ccount ; Value: $ccount + 1 ] 
End Loop
Exit Script [ Result: $xmlresult ] 



Wednesday, September 09, 2015

How to read XML nodes if you don't have XML parser?

I used Filemaker to create database applications. On of the application need to access to Web Services. The returned text is XML. Therefore, I use a plugin called BaseElements to read the nodes. However, recent development requires the same functionality to be available in iPad. Filemaker for iPad does not allow plugins.

Fortunately, the xml parser is not a general parser that translates XML to an array. It just returns the text value of the node defined by the path.

To circumvent the issue, I decided to replicate the same functionality of the BaseElement plugin (BE_XPath() function). The function works like this. You pass it a XML and a path and it returns you the result. For exmaple, BE_XPath($xml;"//Data/myname") will return you the text value from the path. If there are more than one "Data" then you need to define it as a sort of array like Data[1].

It is not at all difficult to interpret the xml. There is just one step to do before parsing it. You need to add [Carriage Return] after every node. Usually the xml is returned as a continuous text without a carriage return character. What I need to do is just search for "><" and replace it with ">[CR]<". [CR] is the character code 13.

The result of doing such replacements means each node will be on a line ending with a carriage return. For example,

<myname>xxx</myname><myphone>yyy</myphone>

will be come

<myname>xxx</myname>
<myphone>yyy</myphone>

What you need to do is search for the path in the sequence for each line of the XML. My example uses Data and myname. So I just read each line and look for first. If it is found then I look for . If reaches first then is not found. If the line returns "" before the two nodes are found then the path is not available.

If the path is Data[x], I just need to repeat the search for till the x occurrence is reached. It is as simple as that.

Once the node name is found, it is time to remove the xml node name. Well, it is quite simple. You simply replace the enclosing node names together with its XML markup as "". Don't worry as XML does not allow "<" and ">" to be part of node text.

Obviously, you need to look out for <myname/>. This means that the node exists but no value. But since I am looking for the node text, whether it exists or have no value is not an issue, I just return a blank unless it is specifically required to determine whether the node actually exists.

The above is assuming that the XML is without carriage returns, tabs and spaces. If the xml is generated by hand and is "tidied". the situation more complicated. You will need to reformat the xml to remove all the carriage return, linefeed, and leading and trailing spaces first then proceed to add carriage return as per described above.




What is the difference between SOAP and POX on Web Services

My previous two blog talks about two aspects of Web Services. What is the differences between the two methods. To make it simple, it is basically the same except that one is easier and the other is harder. They both return exactly the same result.

Let's talk about the easier one. Using SOAP is by far the easiest way. You just need to compose an array according to the documentation available for the Web Services and send to a function of the WS object.

The harder one is to compose the XML envelop then add the nodes to make a complete XML document and then send it.

How did the Web Services work with two different methods? Actually they are both the same except that the XML is posted to the second stage. Allow me to explain the process.

When we use SOAP, we creates a connection to the Web Services (henceforth WS). We then called the particular function via the connection object and pass it an array of parameters. In PHP the script is as follows.

$client= new SoapClient("http://webservices_address", $opt);
$param=array('action'=>'theaction');
$test=$client->thefunction($param);
echo $test->functionresponse->result;

Now if the arguments is a multiple array type the $param will be something like this

$param=array('action'=>array('subaction'=>subtheaction'))

You have to know what function to call and what parameter to pass. Normally this is found in WS documentations. Now, it is very important to be specific about the object name of the array. It is often case sensitive. "subaction" is not the same as "subAction". Often WS will simply tells you that a parameter is missing because of case differences.

To a user, the PHP script is all that is needed to get it working. In actual fact PHP works in the back ground and actually posts the data in a different form. You guess it right. It actually posts a XML to WS after composing it from the WSDL that it first addressed to. This means that it actually interprets the returned value when it first posts to WS, compose the XML based on the definition then sends the XML to another address (usually a sub address of the original) according to the definition.

Our second method actually composes the XML directly and posts to the sub address. It is therefore the same thing except you need to compose the XML the hard way unless you download the WSDL of the WS and do a transpose yourself.

How does the multiple array looks in XML? It is exactly the same except in different format.

subtheaction

Obviously, the PHP array is much easier to read. Now, you would say why not just use SOAP since it is much easier? Yes it is unless the application you use does not have SOAP functionality. PHP have both SOAP and CURL (which provide POX functionality by sending the XML as post). If I use PHP I would prefer to use SOAP instead of CURL. What if you use an application for your business but that application only have CURL?

Since CURL can post a XML to the WS and still gets back the same result, it is pretty alright to use it to access WS. It will be more difficult as you will need to understand what to do when composing the entire XML. Some WS does provide the XML information and allows POX.

Filemaker is a good application for a small business. It is very easy to create a complete database application without much technical knowledge. To access to WS, there is no choice but to use CURL. It might be harder but it will still work.

Actually Filemaker can post to a web site and gets the result but then it has to call a PHP script, pass the information to it and it in turn calls WS, get the result and return it to Filemaker. It is pretty round the world way but it still works.

Post note. SOAP communication has been discontinued. The only way is to use POX now.




Sunday, August 30, 2015

How to Access Web Services using SOAP

Previously I mentioned about accessing Web Services in Communicating with Apple Web Services. It communicates directly with the Web Services by posting a XML to it.

My previous post talks about using Filemaker to access the Web Services. Actually you can use a browser to access it. In actual fact, using browser is the more common methods of accessing Web Services. Most browser has Javascript facility. Javascript has a function called XMLHttpRequest that can access web services. This method is usually called AJAX (Asynchronous Javascript And XML). Using this method, you still send the XML to the Web Services.

It is no joke composing the XML. There is an easier way to access Web Services if you have a web site that runs on PHP. PHP has a module that provides SOAP (Simple Object Access Protocol). What you need to do is to call the function and pass it an array of the parameters.

Generally you need to tell the Web Services what to do with the data. But how to know what to send? Well, it is quite simple. Web services usually uses a language called WSDL (Web Services Definition Language.) If you use a web browser and call the address directly like a web page, it actually returns you a XML telling you what functionality it has and what parameters to provide.

Below is a simple PHP program to communicate with a Web Services. It calls a function called "thefunction" and passes a parameter called $param. It echoes a node name called "result" in the returned XML.

$opt= array('encoding'=>'UTF-8');
$client= new SoapClient("http://webservices_address", $opt);
$param=array('action'=>'theaction');
$test=$client->thefunction($param);
echo $test->functionresponse->result;

Nested parameters can be done by adding arrays in an array like below

array('higherlevel'=>array('lowerlevel'=>'xxx','lowerlevel2=>'yyy'))

Note that php actually parses the returned xml automatically into an object array. You need to use the object reference method to access individual values. Converting the object to other form is beyond the scope of this blog.

There are some Web Services that require client cert. This can be easily done by adding "'local_cert=>'certname.pem'" to the variable $opt. The cert and key must be in the same file.






Saturday, July 04, 2015

A case of two cyclist again

Was cycling on Upper Thomson Road towards the East. This cyclist on a MTB was cycling on foot path. I am cycling on the road. I am travelling at 28-30KPH. Overtook him after SLE. Did not notice till I slowed down at a slope. He was trying to catch up.

He was on a MTB and on footpath. I was on a hybrid and is on road. There is no way he could catch up as it is impossible to go fast on footpaths. Unlike the previous case, I have no hindrances to slow me down. He has plenty. Anyhow, he could not play tag with me as I am simply too fast.

There is only one instance where he actually catches up. After I am aware of his efforts. I simply keep at 30KPH and he could not even be seen. He finally managed to catch up when I stopped at traffic lights at Yio Chu Kang Rd. I don't know whether he turned off or stopped after that. As it is down slopes after the junction, I go easily at 32-36KPH till Ang Mo Kio Ave 1 where I slow down and turned into it.

Cycling on footpath at over 20KPH in the early morning is dangerous as the footpath is not designed for cycling and visibility is poor. Even cycling on PCN has its many dangers already. I do not want to encourage him to speed so I make it impossible for him to catch up rather than allow him to play tag with me at my my usual slower pace.