Data Visualization

WebID authentication and subsequent visualization of the dereferenced WebID profile

Up until now, I have not had any kind of authentication on Nexus.  I have tracked client sessions adding them as RDF statements in Nexus's system graph, but I had never bothered to validate who the user was.  Early last year, I fell in love with WebID.  What is WebID?  In a nutshell, it is public key encryption crossed with FOAF files in order to achieve password-less, single-sign on authentication.  It originally went under the monkier "FOAF+SSL".  A feature of WebID's public key design is that it does not require the normal key signing agents like Verisign and Godaddy.  For additional information, please see http://webid.info/.  There is also an excellent video by Manu Sporny on WebID.  WebID is being worked on by the WebID Community Group.  For this rest of this blog entry, I'm going to assume you watched and read up on WebID.

Now, how to add WebID to Nexus?  The first step was to create a WebID for myself.  Sadly, as much time as I have spent studying the Semantic Web, I had never created a FOAF file for myself.  My initial WebID profile was created using the following shell script https://gist.github.com/niclashoyer/2498494.  The resultant file was enriched with additional information about myself.  My newly created WebID profile can be seen at:
http://www.ebremer.com/foaf.rdf#me

If you think you foaf:know me, send me your URI and I will add you to my file (does anyone really foaf:know anyone?) ;-)

At this point, I now have my WebID profile and my private key (which contains my WebID URI) is stored in my browser.

The server coding was a bit more challanging.  Nexus's http/WebSocket engine is based on Jetty.  At the time I started coding the WebID authentication for Nexus, it was based on Jetty 8.  I created and installed a digital certificate for Jetty and got the WebSocket and http working over SSL.  This part was not difficult and only required flipping the "ws://" calls in the Nexus WebGL client to "wss://".  The current Jetty documentation worked fine for this.  The next step was to enable client certificate authentication and interrupt the normal client certificate validation chain in Java.  There are numerous examples of this all over the web where an "all-trusting" Java TrustManger is created to over-ride the default Trust Manager: 

	TrustManager[] trustAllCerts = new TrustManager[] { 
	      new X509TrustManager()
	      {
		 @Override
		 public X509Certificate[] getAcceptedIssuers()
		 {
			return null;
		 }
					
		 @Override
		 public void checkServerTrusted(X509Certificate[] chain, String authType)
			throws CertificateException
		 {
		 }
					
		 @Override
		 public void checkClientTrusted(X509Certificate[] chain, String authType)
			throws CertificateException
		 {
		 }
	    }

The pity was that most these examples were all wrong, well dated.  Why?  How?  I had upgraded my development environment to JDK 1.7.X from JDK 1.6.X. and after lots of reading, I discovered that the SSL was handled a bit differently in JDK 1.7.  You could no longer return null in the getAcceptedIssuers method.  It had to be written slightly different:

    public X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[]{};
    }

With this change made, I could finally get the browser to pop up the client certificate list and then grab the WebID client certificate file server-side.  During the troubleshooting of getAcceptedIssuers, I upgraded Nexus's Jetty 8 to Jetty 9 M3 (now M5).  I also needed to modify three stock classes in Jetty 9 in order to pass the client WebID certificate to Nexus's WebSockets section.  The modifications are fairly simple but I did have to get a bit more intimate with Jetty's source code.  At the time of this blog entry, Jetty is now 9 RC0.  Once I got a handle on the submitted client certificate, I was able to dereference the WebID URI in the certificate and validate it's public key modulus and exponent against the dereferenced WebID file.

The above video, demonstrates the current login process for Nexus using WebID.  I do not have to visualize the dereferenced WebID profile, but I did so to test the authentication code and to demonstrate that you get more than just the client's WebID.  You also get things such as last name, first name, a client picture, contact information, and so on.

Changes

To date, I have been using N-TRIPLE RDF data streamed between the Nexus client and server over WebSockets.  I've flipped this to RDF Turtle over WebSockets.  Why? Better performance since Turtle allows for a more compact notation compressing more information into fewer bytes.  I've also discovered while reading up on UCC (unified communications and collaborations) for my campus, that the widely-used XMPP protocol (used for things like Google Talk) is nothing more than XML over http.  There is now work being done to have XMPP go over WebSockets (see spec) as opposed to http.  XMPP also uses JabberIDs (RFC 6122) as identifiers.  Personally, I prefer my Turtle RDF over WebSockets using WebID's for identifiers, but seeing XMPP gives me a sense of validation that the Turtle/WebSockets/WebID idea has merit.  In any case, see above video, it does work. :-)

Roadmap

Creation of WebID profiles - for now, you have to bring-your-own WebID to log onto Nexus which is absolutely fine.  However, I would like to be able to provide WebID profiles by Nexus as well for those who may want that feature.

I will also be adding alternate visualizations other than the ball-N-stick display.  One I will add soon is the representation of a foaf:Person as a cube instead of a sphere and then mapping that foaf:Person's foaf:img to the faces of the cube.  This will help provide a more visually compressed image.

The WebID work I am doing on Nexus will, in-part, be ported to VIVO.  VIVO is a web application that creates web profiles for researchers, their publications, grants, teachings, research interests, and so on.  VIVO does all of this on a foundation of RDF.  VIVO provides RDF profiles currently which should make is relatively easy to add the WebID components to it.  You can see the VIVO instance my Department has built for SUNY REACH here http://reach.suny.edu/.

Sample RDF data from WebID visualization (above) after layout is applied:

<http://shield.ebremer.com/resources/29bb010a-ac87-4b82-9171-c7c2b81793f8>
      a       <nex:cube> ;
      <nex:HoverText> "Erich Bremer" ;
      <nex:xyz> "6.757046,-3.423891,6.078216" .

<http://shield.ebremer.com/resources/fb33cb18-d2b7-4cd6-ad1b-dd4545dfe5ef>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://purl.org/dc/elements/1.1/creator" ;
      <nex:objxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:plen> "18.392017" ;
      <nex:rotation> "0.15562783 -0.0 0.7405087 0.653779" ;
      <nex:subjxyz> "18.789173,-6.010832,4.313797" ;
      <nex:xyz> "10.038619,-4.139514,2.194232" .

<http://shield.ebremer.com/resources/60fd2aea-37a7-4dbf-bbc2-c78cf60df689>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/birthday" ;
      <nex:objxyz> "-4.3850303,3.3814554,1.5917158" ;
      <nex:plen> "8.148866" ;
      <nex:rotation> "0.3897549 0.0 -0.23882553 0.88941187" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "-1.5484823,0.55662966,0.8331915" .

<http://xmlns.com/wordnet/1.6/Airport>
      <nex:rnode> <http://shield.ebremer.com/resources/b2df90a3-d67b-4496-ab74-0bd28dcb3f52> ;
      <nex:vnode> <http://shield.ebremer.com/resources/b2df90a3-d67b-4496-ab74-0bd28dcb3f52> .

<http://shield.ebremer.com/resources/ccf4eef8-837f-4277-b458-30aa04defa62>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ;
      <nex:objxyz> "3.6347718,-25.323143,8.237062" ;
      <nex:plen> "7.2201514" ;
      <nex:rotation> "0.78663164 0.0 -0.45067078 -0.4220266" ;
      <nex:subjxyz> "1.9194171,-20.529259,3.117803" ;
      <nex:xyz> "2.7770944,-22.9262,5.677433" .

<http://shield.ebremer.com/resources/567ce25a-5c4c-421c-a815-ad5d8f892d8c>
      a       <nex:cylinder> ;
      <nex:HoverText> "nex:millitime" ;
      <nex:objxyz> "24.7447,-8.840323,1.3769542" ;
      <nex:plen> "7.217989" ;
      <nex:rotation> "0.9552735 0.0 0.2129643 -0.20517975" ;
      <nex:subjxyz> "18.789173,-6.010832,4.313797" ;
      <nex:xyz> "21.766937,-7.4255776,2.8453755" .

<http://shield.ebremer.com/nex/graphs/7203197c-a0b3-48a6-885c-d12e3598e86a>
      <nex:lnode> <http://shield.ebremer.com/resources/3680e5d4-ccce-48c8-be93-994c8039e2b9> ;
      <nex:pnode> <http://shield.ebremer.com/resources/db23a1f7-83eb-4402-8bbd-28a477393d88> ;
      <nex:vnode> <http://shield.ebremer.com/resources/db23a1f7-83eb-4402-8bbd-28a477393d88> , <http://shield.ebremer.com/resources/3680e5d4-ccce-48c8-be93-994c8039e2b9> .

<http://shield.ebremer.com/resources/89548bed-ce50-401e-846b-3fa2632b24fd>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/accountServiceHomepage" ;
      <nex:objxyz> "13.079804,11.690309,-15.968671" ;
      <nex:plen> "7.182698" ;
      <nex:rotation> "0.715777 -0.0 0.5695869 0.40402234" ;
      <nex:subjxyz> "12.902582,7.535981,-10.111939" ;
      <nex:xyz> "12.991194,9.613145,-13.040305" .

<http://shield.ebremer.com/sessions/5d24b75c-7325-4122-9cf3-cf9c8708a534>
      a       <nex:clientsession> ;
      <http://purl.org/dc/elements/1.1/creator>
              <http://www.ebremer.com/foaf.rdf#me> ;
      <nex:ip4> "68.195.227.26" ;
      <nex:millitime> "1360634398601" ;
      <nex:rnode> <http://shield.ebremer.com/resources/98cfdf87-8afa-438d-aeeb-715349442223> ;
      <nex:vnode> <http://shield.ebremer.com/resources/98cfdf87-8afa-438d-aeeb-715349442223> .

<http://shield.ebremer.com/resources/1d3c6e2f-d152-4907-b29e-c3262a9e4fa9>
      a       <nex:cube> ;
      <nex:HoverText> "99" ;
      <nex:xyz> "-13.684594,19.697659,-7.6601453" .

<http://shield.ebremer.com/resources/b2adefe1-d185-48bd-ad43-12d36ae6812e>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.daml.org/2001/10/html/airport-ont#iataCode" ;
      <nex:objxyz> "-13.065482,20.259962,5.5250096" ;
      <nex:plen> "6.9649067" ;
      <nex:rotation> "0.7950134 0.0 -0.575792 0.19083306" ;
      <nex:subjxyz> "-14.904862,18.146603,-0.8515341" ;
      <nex:xyz> "-13.985172,19.203281,2.3367376" .

<http://shield.ebremer.com/resources/ce47d7b7-02d2-491a-8a80-3fc723c21fa7>
      a       <nex:cube> ;
      <nex:HoverText> "ISP" ;
      <nex:xyz> "-13.065482,20.259962,5.5250096" .

<http://shield.ebremer.com/nex/graphs/7bac972c-0aa8-48a1-ba8f-8e608bd26922>
      <nex:pnode> <http://shield.ebremer.com/resources/8eff4274-4595-4556-8b5c-b56309bd0d8c> ;
      <nex:vnode> <http://shield.ebremer.com/resources/8eff4274-4595-4556-8b5c-b56309bd0d8c> .

<http://shield.ebremer.com/resources/a4c68454-8597-4efd-8b3a-3328068aa5a9>
      a       <nex:cube> ;
      <nex:HoverText> "MacArthur Airport" ;
      <nex:xyz> "-17.589022,25.33923,-4.8700905" .

<http://shield.ebremer.com/resources/bd6d61f7-32cf-41c3-97ce-d10e88baba18>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/primaryTopic" ;
      <nex:objxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:plen> "10.131038" ;
      <nex:rotation> "0.97251564 -0.0 0.11701429 0.20129848" ;
      <nex:subjxyz> "-7.744496,-6.2348194,2.3804553" ;
      <nex:xyz> "-3.2282152,-4.2515078,1.2275612" .

<http://shield.ebremer.com/nex/graphs/329bd0e1-e559-49ff-bdef-ef2c20b6cd65>
      <nex:pnode> <http://shield.ebremer.com/resources/6eaa9557-cb96-49d0-ab66-18c57c097404> ;
      <nex:vnode> <http://shield.ebremer.com/resources/6eaa9557-cb96-49d0-ab66-18c57c097404> .

<http://shield.ebremer.com/resources/bcc8f0a5-e903-4fc2-83e5-3b3d2b774669>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/knows" ;
      <nex:objxyz> "-1.3737096,-9.053491,-14.856207" ;
      <nex:plen> "16.61494" ;
      <nex:rotation> "0.64799553 0.0 0.693401 -0.31511417" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "-0.042821944,-5.6608434,-7.39077" .

<http://www.rpi.edu>
      <nex:rnode> <http://shield.ebremer.com/resources/a59dd00a-e501-4c76-ac18-de0141a3f0d4> ;
      <nex:vnode> <http://shield.ebremer.com/resources/a59dd00a-e501-4c76-ac18-de0141a3f0d4> .

<http://xmlns.com/foaf/0.1/OnlineAccount>
      <nex:rnode> <http://shield.ebremer.com/resources/94e333ba-d4c1-43c9-883a-43a432b84e03> ;
      <nex:vnode> <http://shield.ebremer.com/resources/94e333ba-d4c1-43c9-883a-43a432b84e03> .

<http://shield.ebremer.com/resources/3680e5d4-ccce-48c8-be93-994c8039e2b9>
      a       <nex:cube> ;
      <nex:HoverText> 65537 ;
      <nex:xyz> "-2.369653,-26.378757,3.3365998" .

<http://shield.ebremer.com/resources/8fe9f157-afdc-45fe-a669-c2f51de7e7a5>
      a       <nex:sphere> ;
      <nex:HoverText> "mailto:erich@ebremer.com" ;
      <nex:xyz> "2.5592043,6.2678094,-1.043553" .

<http://shield.ebremer.com/nex/graphs/d27be237-da93-4c84-b04f-3955298d5916>
      <nex:pnode> <http://shield.ebremer.com/resources/4c7d190d-c4f4-4c01-85b4-f91d0a54099a> ;
      <nex:vnode> <http://shield.ebremer.com/resources/4c7d190d-c4f4-4c01-85b4-f91d0a54099a> .

<http://shield.ebremer.com/nex/graphs/f1dbdd3f-230b-4003-9921-4438619affe9>
      <nex:pnode> <http://shield.ebremer.com/resources/ccf4eef8-837f-4277-b458-30aa04defa62> ;
      <nex:vnode> <http://shield.ebremer.com/resources/ccf4eef8-837f-4277-b458-30aa04defa62> .

<http://shield.ebremer.com/resources/4c7d190d-c4f4-4c01-85b4-f91d0a54099a>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ;
      <nex:objxyz> "-10.496608,24.227457,-1.1073451" ;
      <nex:plen> "7.514981" ;
      <nex:rotation> "0.8906727 -0.0 0.01910923 0.45424342" ;
      <nex:subjxyz> "-14.904862,18.146603,-0.8515341" ;
      <nex:xyz> "-12.700735,21.18703,-0.9794396" .

<http://shield.ebremer.com/resources/9c1059d0-aa65-4f7b-86c6-3d1b25ba7bf7>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/mbox" ;
      <nex:objxyz> "2.5592043,6.2678094,-1.043553" ;
      <nex:plen> "8.702275" ;
      <nex:rotation> "0.7569907 -0.0 0.08487387 0.6478901" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "1.923635,1.9998066,-0.48444292" .

<http://shield.ebremer.com/nex/graphs/288cc48b-e1e3-4f70-89d7-d9f5d15516ed>
      <nex:pnode> <http://shield.ebremer.com/resources/8f9ae0ed-a856-4892-b679-a8bfed744e44> ;
      <nex:vnode> <http://shield.ebremer.com/resources/8f9ae0ed-a856-4892-b679-a8bfed744e44> .

<http://shield.ebremer.com/resources/c7954db7-d627-4cc3-9c3c-38dc35e18d51>
      a       <nex:cube> ;
      <nex:HoverText> "1968-04-22" ;
      <nex:xyz> "-4.3850303,3.3814554,1.5917158" .

<http://shield.ebremer.com/resources/c4107112-7c4d-4f45-b6a0-727e0d2c1fc5>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/img" ;
      <nex:objxyz> "0.9335052,-8.212778,5.893996" ;
      <nex:plen> "8.3263645" ;
      <nex:rotation> "0.6918877 0.0 -0.5050704 -0.5159413" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "1.1107855,-5.240487,2.9843314" .

<http://shield.ebremer.com/nex/graphs/f4ae2cdd-0c15-43b3-ab4e-c1908574e05c>
      <nex:pnode> <http://shield.ebremer.com/resources/6b9c8582-487c-42d9-8298-e9cc51762d2f> ;
      <nex:vnode> <http://shield.ebremer.com/resources/6b9c8582-487c-42d9-8298-e9cc51762d2f> .

<http://shield.ebremer.com/resources/9a016505-55fc-40e1-bbe0-5895319289be>
      a       <nex:cube> ;
      <nex:HoverText> "Erich Bremer's profile" ;
      <nex:xyz> "-13.243382,-8.80005,7.3699355" .

<http://shield.ebremer.com/nex/graphs/eba969cf-cc66-499d-90ce-634771c379d2>
      <nex:pnode> <http://shield.ebremer.com/resources/c4107112-7c4d-4f45-b6a0-727e0d2c1fc5> ;
      <nex:vnode> <http://shield.ebremer.com/resources/c4107112-7c4d-4f45-b6a0-727e0d2c1fc5> .

<http://shield.ebremer.com/nex/graphs/b381ebe9-2a45-4c94-b4ff-09b871cc9f98>
      <nex:lnode> <http://shield.ebremer.com/resources/1d3c6e2f-d152-4907-b29e-c3262a9e4fa9> ;
      <nex:pnode> <http://shield.ebremer.com/resources/bb45dfba-9062-496e-9035-e8d4e9454ee4> ;
      <nex:vnode> <http://shield.ebremer.com/resources/1d3c6e2f-d152-4907-b29e-c3262a9e4fa9> , <http://shield.ebremer.com/resources/bb45dfba-9062-496e-9035-e8d4e9454ee4> .

<http://shield.ebremer.com/nex/graphs/d4a989d0-d6dc-4a52-a9c7-c574ab1ec856>
      <nex:pnode> <http://shield.ebremer.com/resources/9e449a77-55e3-4aab-a281-225071956f18> ;
      <nex:vnode> <http://shield.ebremer.com/resources/9e449a77-55e3-4aab-a281-225071956f18> .

<http://shield.ebremer.com/resources/9486c237-8fe4-4f7a-a121-d32288e22bdb>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ;
      <nex:objxyz> "-0.31521404,-6.5853963,-9.528153" ;
      <nex:plen> "5.966578" ;
      <nex:rotation> "0.7672692 0.0 -0.58192295 0.26956198" ;
      <nex:subjxyz> "-1.3737096,-9.053491,-14.856207" ;
      <nex:xyz> "-0.8444618,-7.8194437,-12.192181" .

<http://shield.ebremer.com/resources/94e333ba-d4c1-43c9-883a-43a432b84e03>
      a       <nex:sphere> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/OnlineAccount" ;
      <nex:xyz> "18.817831,6.775251,-14.205012" .

<http://shield.ebremer.com/resources/bb08e58a-655b-4920-b5ee-1588914ae382>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/family_name" ;
      <nex:objxyz> "-1.0298611,-9.309256,-1.8062805" ;
      <nex:plen> "7.647697" ;
      <nex:rotation> "0.59030145 0.0 0.20832536 -0.7798363" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "0.12910229,-5.788726,-0.8658067" .

<http://shield.ebremer.com/nex/graphs/1ccc0a38-5e58-499c-99b7-6a21b72b70d1>
      <nex:lnode> <http://shield.ebremer.com/resources/d2ce17d5-c4cd-434f-8c78-7fe5e9b79fff> ;
      <nex:pnode> <http://shield.ebremer.com/resources/1b5e3f92-4346-45b9-9bcd-8a1200f751e2> ;
      <nex:vnode> <http://shield.ebremer.com/resources/d2ce17d5-c4cd-434f-8c78-7fe5e9b79fff> , <http://shield.ebremer.com/resources/1b5e3f92-4346-45b9-9bcd-8a1200f751e2> .

<http://shield.ebremer.com/nex/graphs/0aa6ac74-225a-468f-86ce-81e54424d0f9>
      <nex:lnode> <http://shield.ebremer.com/resources/051b6934-d1d3-493a-b8b7-6d6547204aa6> ;
      <nex:pnode> <http://shield.ebremer.com/resources/9eaad767-89c0-44eb-bd3f-3d764dfea398> ;
      <nex:vnode> <http://shield.ebremer.com/resources/9eaad767-89c0-44eb-bd3f-3d764dfea398> , <http://shield.ebremer.com/resources/051b6934-d1d3-493a-b8b7-6d6547204aa6> .

<http://shield.ebremer.com/nex/graphs/5048521a-dc4f-488c-b926-0c4354779b98>
      <nex:lnode> <http://shield.ebremer.com/resources/5997861f-a88d-479d-8e2a-52a701c49cb1> ;
      <nex:pnode> <http://shield.ebremer.com/resources/567ce25a-5c4c-421c-a815-ad5d8f892d8c> ;
      <nex:vnode> <http://shield.ebremer.com/resources/5997861f-a88d-479d-8e2a-52a701c49cb1> , <http://shield.ebremer.com/resources/567ce25a-5c4c-421c-a815-ad5d8f892d8c> .

<http://shield.ebremer.com/resources/a6f011f3-fb26-4cd3-ae74-1738843268de>
      a       <nex:cube> ;
      <nex:HoverText> "Erich" ;
      <nex:xyz> "6.9691315,-3.1183655,-5.7980638" .

<http://shield.ebremer.com/nex/graphs/7758c5a1-86d0-4582-9d61-052ec69ba209>
      <nex:lnode> <http://shield.ebremer.com/resources/92f18885-f7cb-4b4b-8e64-ae07ba8e127c> ;
      <nex:pnode> <http://shield.ebremer.com/resources/69d0c361-57e6-4ea2-b353-c14a12de84e1> ;
      <nex:vnode> <http://shield.ebremer.com/resources/69d0c361-57e6-4ea2-b353-c14a12de84e1> , <http://shield.ebremer.com/resources/92f18885-f7cb-4b4b-8e64-ae07ba8e127c> .

<http://shield.ebremer.com/resources/9eaad767-89c0-44eb-bd3f-3d764dfea398>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/2003/01/geo/wgs84_pos#long" ;
      <nex:objxyz> "6.546685,1.1909465,23.601688" ;
      <nex:plen> "7.2011604" ;
      <nex:rotation> "0.89797086 0.0 -0.40392396 0.1746243" ;
      <nex:subjxyz> "2.134508,-1.0674458,18.377794" ;
      <nex:xyz> "4.3405967,0.061750352,20.989742" .

<http://shield.ebremer.com/resources/a1e381fd-5527-4cba-a92c-9174792ca6a2>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ;
      <nex:objxyz> "18.817831,6.775251,-14.205012" ;
      <nex:plen> "7.233403" ;
      <nex:rotation> "0.9533542 0.0 0.2967717 -0.05515739" ;
      <nex:subjxyz> "12.902582,7.535981,-10.111939" ;
      <nex:xyz> "15.860207,7.155616,-12.158476" .

<http://shield.ebremer.com/resources/77915d2a-0bef-4f82-bab3-9bf5a1e38998>
      a       <nex:cube> ;
      <nex:HoverText> "erich.bremer" ;
      <nex:xyz> "17.448757,13.079433,-9.482868" .

<http://xmlns.com/foaf/0.1/PersonalProfileDocument>
      <nex:rnode> <http://shield.ebremer.com/resources/b3adf0db-7020-4ef7-b279-9b5188171c26> ;
      <nex:vnode> <http://shield.ebremer.com/resources/b3adf0db-7020-4ef7-b279-9b5188171c26> .

<http://www.w3.org/2003/01/geo/wgs84_pos#Point>
      <nex:rnode> <http://shield.ebremer.com/resources/fe02cb3e-5e78-4345-8ffd-dc664eb00162> ;
      <nex:vnode> <http://shield.ebremer.com/resources/fe02cb3e-5e78-4345-8ffd-dc664eb00162> .

<http://shield.ebremer.com/nex/graphs/b3af923a-b650-4f6d-8842-99ba66ed16d4>
      <nex:pnode> <http://shield.ebremer.com/resources/c80a1c26-be88-4859-a97b-155acb835e1f> ;
      <nex:vnode> <http://shield.ebremer.com/resources/c80a1c26-be88-4859-a97b-155acb835e1f> .

<http://shield.ebremer.com/nex/graphs/edf8b9b1-43b0-495b-9928-69cb6163b613>
      <nex:lnode> <http://shield.ebremer.com/resources/4adc5dcd-ddf4-4592-9e54-0c0686dd8f9b> ;
      <nex:pnode> <http://shield.ebremer.com/resources/857ad6b4-8dca-4304-aaaf-60f97a304f51> ;
      <nex:vnode> <http://shield.ebremer.com/resources/4adc5dcd-ddf4-4592-9e54-0c0686dd8f9b> , <http://shield.ebremer.com/resources/857ad6b4-8dca-4304-aaaf-60f97a304f51> .

<http://shield.ebremer.com/resources/b2df90a3-d67b-4496-ab74-0bd28dcb3f52>
      a       <nex:sphere> ;
      <nex:HoverText> "http://xmlns.com/wordnet/1.6/Airport" ;
      <nex:xyz> "-10.496608,24.227457,-1.1073451" .

<http://xmlns.com/foaf/0.1/Person>
      <nex:rnode> <http://shield.ebremer.com/resources/f6bdf9f1-7650-4da8-b376-241ef12e7bcb> ;
      <nex:vnode> <http://shield.ebremer.com/resources/f6bdf9f1-7650-4da8-b376-241ef12e7bcb> .

<http://shield.ebremer.com/nex/graphs/39dd280a-547f-490a-822e-88dd02ea1306>
      <nex:pnode> <http://shield.ebremer.com/resources/292e2152-f326-4417-9ede-b77864831e4a> ;
      <nex:vnode> <http://shield.ebremer.com/resources/292e2152-f326-4417-9ede-b77864831e4a> .

<http://shield.ebremer.com/nex/graphs/9dc0d1ad-c8f1-445b-9efd-6e5dafff46f1>
      <nex:lnode> <http://shield.ebremer.com/resources/77915d2a-0bef-4f82-bab3-9bf5a1e38998> ;
      <nex:pnode> <http://shield.ebremer.com/resources/1b686e0b-95b8-469b-ad05-ae5c0abf6a03> ;
      <nex:vnode> <http://shield.ebremer.com/resources/1b686e0b-95b8-469b-ad05-ae5c0abf6a03> , <http://shield.ebremer.com/resources/77915d2a-0bef-4f82-bab3-9bf5a1e38998> .

<http://shield.ebremer.com/resources/8d846a2a-1bb0-4a85-bbbd-941caba6cce4>
      a       <nex:cylinder> ;
      <nex:HoverText> "nex:ip4" ;
      <nex:objxyz> "22.810303,-9.893983,8.884933" ;
      <nex:plen> "7.221055" ;
      <nex:rotation> "0.8822873 0.0 -0.35874307 -0.30474994" ;
      <nex:subjxyz> "18.789173,-6.010832,4.313797" ;
      <nex:xyz> "20.799738,-7.9524074,6.599365" .

<http://shield.ebremer.com/resources/f6bdf9f1-7650-4da8-b376-241ef12e7bcb>
      a       <nex:sphere> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/Person" ;
      <nex:xyz> "-0.31521404,-6.5853963,-9.528153" .

<http://shield.ebremer.com/resources/66172254-f3cf-4223-859c-1dedec337a45>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ;
      <nex:objxyz> "-14.76252,-9.281522,0.552921" ;
      <nex:plen> "7.8660626" ;
      <nex:rotation> "0.23217401 0.0 0.5003387 -0.83412015" ;
      <nex:subjxyz> "-7.744496,-6.2348194,2.3804553" ;
      <nex:xyz> "-11.253508,-7.7581706,1.4666882" .

<http://shield.ebremer.com/nex/graphs/4526ae0f-0e48-41ba-8d1e-42a6b07916ee>
      <nex:pnode> <http://shield.ebremer.com/resources/ed15e725-1eb6-4189-9895-11ae2a47cdad> ;
      <nex:vnode> <http://shield.ebremer.com/resources/ed15e725-1eb6-4189-9895-11ae2a47cdad> .

<http://shield.ebremer.com/resources/d7df5776-3106-45ab-a138-f370afa01cd2>
      a       <nex:sphere> ;
      <nex:HoverText> "http://tdiprima.com/foaf.rdf#me" ;
      <nex:xyz> "-6.128773,-8.901025,-20.684343" .

<http://www.w3.org/ns/auth/cert#RSAPublicKey>
      <nex:rnode> <http://shield.ebremer.com/resources/a6e56026-c5bd-4331-ab7a-20b0f1c8660a> ;
      <nex:vnode> <http://shield.ebremer.com/resources/a6e56026-c5bd-4331-ab7a-20b0f1c8660a> .

<http://shield.ebremer.com/resources/c35ce390-4f59-4f99-9cec-fa3b041d5614>
      a       <nex:sphere> ;
      <nex:nodesize> "4" ;
      <nex:numlinks> "4" ;
      <nex:q> "4" ;
      <nex:xyz> "-1.3737096,-9.053491,-14.856207" .

<mailto:tammy.diprima@stonybrook.edu>
      <nex:rnode> <http://shield.ebremer.com/resources/a6ff1888-c243-4126-acbf-b44c651855b0> ;
      <nex:vnode> <http://shield.ebremer.com/resources/a6ff1888-c243-4126-acbf-b44c651855b0> .

<http://shield.ebremer.com/resources/66ded436-abb8-43d8-b8c4-ad4b016544fc>
      a       <nex:cube> ;
      <nex:HoverText> "40.789278" ;
      <nex:xyz> "-20.15058,16.152966,3.8811495" .

<http://shield.ebremer.com/resources/ed15e725-1eb6-4189-9895-11ae2a47cdad>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/schoolHomepage" ;
      <nex:objxyz> "-2.4844422,-1.1644895,7.222489" ;
      <nex:plen> "8.157288" ;
      <nex:rotation> "0.51842505 0.0 -0.84510744 0.13049439" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "-0.5981883,-1.7163428,3.648578" .

<http://shield.ebremer.com/resources/292e2152-f326-4417-9ede-b77864831e4a>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/maker" ;
      <nex:objxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:plen> "10.131038" ;
      <nex:rotation> "0.97251564 -0.0 0.11701429 0.20129848" ;
      <nex:subjxyz> "-7.744496,-6.2348194,2.3804553" ;
      <nex:xyz> "-3.2282152,-4.2515078,1.2275612" .

<http://shield.ebremer.com/nex/graphs/08915ade-c3e3-49bd-954a-de7de9ec72bf>
      <nex:pnode> <http://shield.ebremer.com/resources/9c1059d0-aa65-4f7b-86c6-3d1b25ba7bf7> ;
      <nex:vnode> <http://shield.ebremer.com/resources/9c1059d0-aa65-4f7b-86c6-3d1b25ba7bf7> .

<http://shield.ebremer.com/resources/583634b9-1410-4e35-8bbc-40a12317ac72>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/title" ;
      <nex:objxyz> "-13.243382,-8.80005,7.3699355" ;
      <nex:plen> "7.855767" ;
      <nex:rotation> "0.38731062 0.0 -0.8199309 -0.42154926" ;
      <nex:subjxyz> "-7.744496,-6.2348194,2.3804553" ;
      <nex:xyz> "-10.493939,-7.5174346,4.8751955" .

<http://shield.ebremer.com/resources/1b686e0b-95b8-469b-ad05-ae5c0abf6a03>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/accountName" ;
      <nex:objxyz> "17.448757,13.079433,-9.482868" ;
      <nex:plen> "7.1967564" ;
      <nex:rotation> "0.90324354 0.0 -0.048386943 0.42639163" ;
      <nex:subjxyz> "12.902582,7.535981,-10.111939" ;
      <nex:xyz> "15.17567,10.307707,-9.797403" .

<http://shield.ebremer.com/resources/c5a8ee68-26e2-4f8e-af3a-239042d5cf27>
      a       <nex:cube> ;
      <nex:HoverText> "Bremer" ;
      <nex:xyz> "-1.0298611,-9.309256,-1.8062805" .

<http://www.skype.com/>
      <nex:rnode> <http://shield.ebremer.com/resources/322e2c62-2466-4250-82d0-95bd38dea1f8> ;
      <nex:vnode> <http://shield.ebremer.com/resources/322e2c62-2466-4250-82d0-95bd38dea1f8> .

<http://shield.ebremer.com/nex/graphs/7e755837-bd55-4ae4-af08-4211fe6ab667>
      <nex:pnode> <http://shield.ebremer.com/resources/b703c2aa-c634-46b0-85e6-96cb3c94d34b> ;
      <nex:vnode> <http://shield.ebremer.com/resources/b703c2aa-c634-46b0-85e6-96cb3c94d34b> .

<http://shield.ebremer.com/nex/graphs/0416566b-2173-4e4a-a516-509c868f6aca>
      <nex:pnode> <http://shield.ebremer.com/resources/9486c237-8fe4-4f7a-a121-d32288e22bdb> ;
      <nex:vnode> <http://shield.ebremer.com/resources/9486c237-8fe4-4f7a-a121-d32288e22bdb> .

<http://shield.ebremer.com/nex/graphs/7271f99f-b4df-45ec-a9ba-08f55f6a5764>
      <nex:lnode> <http://shield.ebremer.com/resources/b923152a-8efc-4ff2-9dba-1d1abdedab44> ;
      <nex:pnode> <http://shield.ebremer.com/resources/35f94abd-847a-490a-86eb-22f2e3726060> ;
      <nex:vnode> <http://shield.ebremer.com/resources/35f94abd-847a-490a-86eb-22f2e3726060> , <http://shield.ebremer.com/resources/b923152a-8efc-4ff2-9dba-1d1abdedab44> .

<http://shield.ebremer.com/resources/1b5e3f92-4346-45b9-9bcd-8a1200f751e2>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.daml.org/2001/10/html/airport-ont#longitude" ;
      <nex:objxyz> "-23.10833,20.7913,-1.7015207" ;
      <nex:plen> "8.66105" ;
      <nex:rotation> "0.16253012 -0.0 0.3019099 0.9393798" ;
      <nex:subjxyz> "-14.904862,18.146603,-0.8515341" ;
      <nex:xyz> "-19.006596,19.468952,-1.2765274" .

<http://shield.ebremer.com/nex/graphs/af7c2a2c-c4db-475a-99fd-94613fc1a5a7>
      <nex:pnode> <http://shield.ebremer.com/resources/89548bed-ce50-401e-846b-3fa2632b24fd> ;
      <nex:vnode> <http://shield.ebremer.com/resources/89548bed-ce50-401e-846b-3fa2632b24fd> .

<http://shield.ebremer.com/resources/58b36f00-9c37-4888-849a-fe8485ddbe3c>
      a       <nex:sphere> ;
      <nex:nodesize> "3" ;
      <nex:numlinks> "3" ;
      <nex:q> "3" ;
      <nex:xyz> "1.9194171,-20.529259,3.117803" .

<http://shield.ebremer.com/nex/graphs/762e5172-5fd0-4520-a9c0-4c4d085979d6>
      <nex:lnode> <http://shield.ebremer.com/resources/a6f011f3-fb26-4cd3-ae74-1738843268de> ;
      <nex:pnode> <http://shield.ebremer.com/resources/58ec8462-762e-4982-a46e-6737b8254dfb> ;
      <nex:vnode> <http://shield.ebremer.com/resources/58ec8462-762e-4982-a46e-6737b8254dfb> , <http://shield.ebremer.com/resources/a6f011f3-fb26-4cd3-ae74-1738843268de> .

<http://shield.ebremer.com/resources/f9ba89b7-fe3d-43a8-bc80-018e0b18e8a2>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/2003/01/geo/wgs84_pos#lat" ;
      <nex:objxyz> "1.8440512,-5.244094,24.264164" ;
      <nex:plen> "7.223441" ;
      <nex:rotation> "0.69274443 0.0 -0.58816665 -0.41733107" ;
      <nex:subjxyz> "2.134508,-1.0674458,18.377794" ;
      <nex:xyz> "1.9892795,-3.1557698,21.32098" .

<http://shield.ebremer.com/resources/857ad6b4-8dca-4304-aaaf-60f97a304f51>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/title" ;
      <nex:objxyz> "8.727002,1.4348108,0.31527075" ;
      <nex:plen> "8.313117" ;
      <nex:rotation> "0.9733558 0.0 -0.014867452 0.22881734" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "5.007534,-0.41669267,0.19496895" .

<http://shield.ebremer.com/nex/graphs/ef301870-a995-46b8-8a4f-5de6569e7e32>
      <nex:pnode> <http://shield.ebremer.com/resources/66172254-f3cf-4223-859c-1dedec337a45> ;
      <nex:vnode> <http://shield.ebremer.com/resources/66172254-f3cf-4223-859c-1dedec337a45> .

<http://www.ebremer.com/ebfiles/erich.jpg>
      <nex:rnode> <http://shield.ebremer.com/resources/e2ac006c-0dfe-42d8-b140-9941afc549c8> ;
      <nex:vnode> <http://shield.ebremer.com/resources/e2ac006c-0dfe-42d8-b140-9941afc549c8> .

<http://shield.ebremer.com/resources/8f9ae0ed-a856-4892-b679-a8bfed744e44>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ;
      <nex:objxyz> "-1.2423172,1.9353592,23.958439" ;
      <nex:plen> "7.1807647" ;
      <nex:rotation> "0.51465523 0.0 -0.7550353 0.4062656" ;
      <nex:subjxyz> "2.134508,-1.0674458,18.377794" ;
      <nex:xyz> "0.44609535,0.43395674,21.168118" .

<http://shield.ebremer.com/nex/graphs/59c7440e-990b-4ade-a872-1b3abfe57c8d>
      <nex:lnode> <http://shield.ebremer.com/resources/027fd95a-b962-4f27-8634-a61fd7f3741d> ;
      <nex:pnode> <http://shield.ebremer.com/resources/6bdc1b94-5bff-4e96-a39e-fe04be1d1f79> ;
      <nex:vnode> <http://shield.ebremer.com/resources/027fd95a-b962-4f27-8634-a61fd7f3741d> , <http://shield.ebremer.com/resources/6bdc1b94-5bff-4e96-a39e-fe04be1d1f79> .

<http://shield.ebremer.com/resources/6bdc1b94-5bff-4e96-a39e-fe04be1d1f79>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/ns/auth/cert#modulus" ;
      <nex:objxyz> "5.035039,-26.519365,0.5492316" ;
      <nex:plen> "7.2239904" ;
      <nex:rotation> "0.8459575 0.0 0.21015319 -0.49009344" ;
      <nex:subjxyz> "1.9194171,-20.529259,3.117803" ;
      <nex:xyz> "3.4772282,-23.524311,1.8335173" .

<http://tdiprima.com/foaf.rdf#me>
      <nex:rnode> <http://shield.ebremer.com/resources/d7df5776-3106-45ab-a138-f370afa01cd2> ;
      <nex:vnode> <http://shield.ebremer.com/resources/d7df5776-3106-45ab-a138-f370afa01cd2> .

<http://shield.ebremer.com/nex/graphs/04700542-5082-40dc-bd39-dc3adc9dbcc7>
      <nex:lnode> <http://shield.ebremer.com/resources/66ded436-abb8-43d8-b8c4-ad4b016544fc> ;
      <nex:pnode> <http://shield.ebremer.com/resources/007e136b-e05a-4061-b70e-1db5127a42b2> ;
      <nex:vnode> <http://shield.ebremer.com/resources/007e136b-e05a-4061-b70e-1db5127a42b2> , <http://shield.ebremer.com/resources/66ded436-abb8-43d8-b8c4-ad4b016544fc> .

<http://shield.ebremer.com/nex/graphs/46ea5446-2766-477a-b8d4-5aa50c506fc0>
      <nex:lnode> <http://shield.ebremer.com/resources/a4c68454-8597-4efd-8b3a-3328068aa5a9> ;
      <nex:pnode> <http://shield.ebremer.com/resources/feb37eec-a3b8-48ba-9bd1-780baa0923c5> ;
      <nex:vnode> <http://shield.ebremer.com/resources/feb37eec-a3b8-48ba-9bd1-780baa0923c5> , <http://shield.ebremer.com/resources/a4c68454-8597-4efd-8b3a-3328068aa5a9> .

<http://shield.ebremer.com/resources/7a62ac94-793e-4bba-8a72-6cfae00b86b1>
      a       <nex:cube> ;
      <nex:HoverText> "KISMP" ;
      <nex:xyz> "-19.809538,15.09504,-5.055586" .

<http://www.ebremer.com/foaf.rdf#me>
      a       <http://xmlns.com/foaf/0.1/Person> ;
      <http://www.w3.org/2000/10/swap/pim/contact#nearestAirport>
              [ a       <http://xmlns.com/wordnet/1.6/Airport> ;
                <http://www.daml.org/2001/10/html/airport-ont#elevation>
                        "99" ;
                <http://www.daml.org/2001/10/html/airport-ont#iataCode>
                        "ISP" ;
                <http://www.daml.org/2001/10/html/airport-ont#icaoCode>
                        "KISMP" ;
                <http://www.daml.org/2001/10/html/airport-ont#latitude>
                        "40.789278" ;
                <http://www.daml.org/2001/10/html/airport-ont#location>
                        "Islip, New York, United States" ;
                <http://www.daml.org/2001/10/html/airport-ont#longitude>
                        "-73.097545" ;
                <http://www.daml.org/2001/10/html/airport-ont#name>
                        "MacArthur Airport" ;
                <nex:rnode> <http://shield.ebremer.com/resources/b6ecaf9e-d9fe-44f8-bd45-9188fec00d0b> ;
                <nex:vnode> <http://shield.ebremer.com/resources/b6ecaf9e-d9fe-44f8-bd45-9188fec00d0b>
              ] ;
      <http://www.w3.org/ns/auth/cert#key>
              [ a       <http://www.w3.org/ns/auth/cert#RSAPublicKey> ;
                <http://www.w3.org/ns/auth/cert#exponent>
                        65537 ;
                <http://www.w3.org/ns/auth/cert#modulus>
                        "B8CD08202DB1C18A704AE4ABBF0C2C7A23C7FD9C8D85BC957645D91922BC79BF81C468A75A80629DD134CB639213B661E1762B365A85EFC37E110E6946A882A429103E2601C1EBC42F612635E8E5B9C968D53940FA9EDC4644B20A89E9CA2963232B0625D2FFED66AB5BB97E700D2ACCE91D972D37005370B01B3632CA43E42B0DD8DD283D5B811059547FA772480A2B5DB8781E69CF7DBD6BDC61A5165A2F659DE7904006A5AC4C70AA226FDCCEC514B9AE081C40E917368B4882F769F9A8BAA818E8BD72DBEDD3ABCF9BCB66BD9AAC916CD56F47FCAA3DA4337E99B4064DF4AF4F2869D751E35F324C8E06996D7B1491F55F1C7B05E5BD5D31C95919D25801"^^<http://www.w3.org/2001/XMLSchema#hexBinary> ;
                <nex:rnode> <http://shield.ebremer.com/resources/58b36f00-9c37-4888-849a-fe8485ddbe3c> ;
                <nex:vnode> <http://shield.ebremer.com/resources/58b36f00-9c37-4888-849a-fe8485ddbe3c>
              ] ;
      <http://xmlns.com/foaf/0.1/based_near>
              [ a       <http://www.w3.org/2003/01/geo/wgs84_pos#Point> ;
                <http://www.w3.org/2003/01/geo/wgs84_pos#lat>
                        "40.836695" ;
                <http://www.w3.org/2003/01/geo/wgs84_pos#long>
                        "-72.916725" ;
                <nex:rnode> <http://shield.ebremer.com/resources/0d0579a8-c217-4b3f-a0ed-734870eb5ede> ;
                <nex:vnode> <http://shield.ebremer.com/resources/0d0579a8-c217-4b3f-a0ed-734870eb5ede>
              ] ;
      <http://xmlns.com/foaf/0.1/birthday>
              "1968-04-22" ;
      <http://xmlns.com/foaf/0.1/family_name>
              "Bremer" ;
      <http://xmlns.com/foaf/0.1/firstName>
              "Erich" ;
      <http://xmlns.com/foaf/0.1/givenname>
              "Erich" ;
      <http://xmlns.com/foaf/0.1/holdsAccount>
              [ a       <http://xmlns.com/foaf/0.1/OnlineAccount> ;
                <http://xmlns.com/foaf/0.1/accountName>
                        "erich.bremer" ;
                <http://xmlns.com/foaf/0.1/accountServiceHomepage>
                        <http://www.skype.com/> ;
                <nex:rnode> <http://shield.ebremer.com/resources/68fb1356-03c3-4cc1-9bb0-7d8ac852fd55> ;
                <nex:vnode> <http://shield.ebremer.com/resources/68fb1356-03c3-4cc1-9bb0-7d8ac852fd55>
              ] ;
      <http://xmlns.com/foaf/0.1/homepage>
              <http://www.ebremer.com> ;
      <http://xmlns.com/foaf/0.1/img>
              <http://www.ebremer.com/ebfiles/erich.jpg> ;
      <http://xmlns.com/foaf/0.1/knows>
              [ a       <http://xmlns.com/foaf/0.1/Person> ;
                <http://www.w3.org/2000/01/rdf-schema#seeAlso>
                        <http://tdiprima.com/foaf.rdf#me> ;
                <http://xmlns.com/foaf/0.1/mbox>
                        <mailto:tammy.diprima@stonybrook.edu> ;
                <http://xmlns.com/foaf/0.1/name>
                        "Tammy DiPrima" ;
                <nex:rnode> <http://shield.ebremer.com/resources/c35ce390-4f59-4f99-9cec-fa3b041d5614> ;
                <nex:vnode> <http://shield.ebremer.com/resources/c35ce390-4f59-4f99-9cec-fa3b041d5614>
              ] ;
      <http://xmlns.com/foaf/0.1/mbox>
              <mailto:erich@ebremer.com> ;
      <http://xmlns.com/foaf/0.1/name>
              "Erich Bremer" ;
      <http://xmlns.com/foaf/0.1/phone>
              <tel:631-444-3560> ;
      <http://xmlns.com/foaf/0.1/schoolHomepage>
              <http://www.rpi.edu> ;
      <http://xmlns.com/foaf/0.1/status>
              "Happy" ;
      <http://xmlns.com/foaf/0.1/title>
              "Mr." ;
      <nex:rnode> <http://shield.ebremer.com/resources/d7b6d0c8-b610-4146-8e2b-6ea31ac1eb91> ;
      <nex:vnode> <http://shield.ebremer.com/resources/d7b6d0c8-b610-4146-8e2b-6ea31ac1eb91> .

<http://shield.ebremer.com/resources/9eeb0614-e1ed-4603-96e7-587ddaba32ca>
      a       <nex:cube> ;
      <nex:HoverText> "Happy" ;
      <nex:xyz> "-5.6631656,-1.3325166,-4.3307486" .

<http://shield.ebremer.com/resources/71fb6b92-4ea0-48e3-a2a7-48ec9275069d>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/homepage" ;
      <nex:objxyz> "6.8995605,-8.502952,-0.75715226" ;
      <nex:plen> "8.429293" ;
      <nex:rotation> "0.9126099 0.0 0.054065812 -0.40524074" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "4.093813,-5.385574,-0.34124255" .

<http://shield.ebremer.com/nex/graphs/22b1e8a2-eaac-4ce6-b62b-4901500e6748>
      <nex:lnode> <http://shield.ebremer.com/resources/c7954db7-d627-4cc3-9c3c-38dc35e18d51> ;
      <nex:pnode> <http://shield.ebremer.com/resources/60fd2aea-37a7-4dbf-bbc2-c78cf60df689> ;
      <nex:vnode> <http://shield.ebremer.com/resources/60fd2aea-37a7-4dbf-bbc2-c78cf60df689> , <http://shield.ebremer.com/resources/c7954db7-d627-4cc3-9c3c-38dc35e18d51> .

<http://shield.ebremer.com/resources/98cfdf87-8afa-438d-aeeb-715349442223>
      a       <nex:sphere> ;
      <nex:HoverText> "http://shield.ebremer.com/sessions/5d24b75c-7325-4122-9cf3-cf9c8708a534" ;
      <nex:nodesize> "4" ;
      <nex:numlinks> "4" ;
      <nex:q> "4" ;
      <nex:xyz> "18.789173,-6.010832,4.313797" .

<http://shield.ebremer.com/resources/af0c590e-779f-4743-b2fb-dbdf510b33ce>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/ns/auth/cert#key" ;
      <nex:objxyz> "1.9194171,-20.529259,3.117803" ;
      <nex:plen> "18.523653" ;
      <nex:rotation> "0.7190561 0.0 -0.114235714 -0.6854987" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "1.6037414,-11.398727,1.5962352" .

<http://shield.ebremer.com/nex/graphs/f1a77278-fe74-4f7a-a9f7-369ca786d3f2>
      <nex:lnode> <http://shield.ebremer.com/resources/ce47d7b7-02d2-491a-8a80-3fc723c21fa7> ;
      <nex:pnode> <http://shield.ebremer.com/resources/b2adefe1-d185-48bd-ad43-12d36ae6812e> ;
      <nex:vnode> <http://shield.ebremer.com/resources/b2adefe1-d185-48bd-ad43-12d36ae6812e> , <http://shield.ebremer.com/resources/ce47d7b7-02d2-491a-8a80-3fc723c21fa7> .

<http://shield.ebremer.com/nex/graphs/80e35282-6932-4a43-89a8-ace539ce016d>
      <nex:pnode> <http://shield.ebremer.com/resources/b4c745b0-a99a-4844-9437-396b719f1a4d> ;
      <nex:vnode> <http://shield.ebremer.com/resources/b4c745b0-a99a-4844-9437-396b719f1a4d> .

<http://shield.ebremer.com/resources/bb45dfba-9062-496e-9035-e8d4e9454ee4>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.daml.org/2001/10/html/airport-ont#elevation" ;
      <nex:objxyz> "-13.684594,19.697659,-7.6601453" ;
      <nex:plen> "7.0888653" ;
      <nex:rotation> "0.7655516 -0.0 0.6273029 0.14290461" ;
      <nex:subjxyz> "-14.904862,18.146603,-0.8515341" ;
      <nex:xyz> "-14.294728,18.92213,-4.25584" .

<http://shield.ebremer.com/resources/0d0579a8-c217-4b3f-a0ed-734870eb5ede>
      a       <nex:sphere> ;
      <nex:nodesize> "3" ;
      <nex:numlinks> "3" ;
      <nex:q> "3" ;
      <nex:xyz> "2.134508,-1.0674458,18.377794" .

<http://shield.ebremer.com/nex/graphs/bdb06cd0-ffd2-4dbe-9a9e-f64865d27a32>
      <nex:lnode> <http://shield.ebremer.com/resources/9eeb0614-e1ed-4603-96e7-587ddaba32ca> ;
      <nex:pnode> <http://shield.ebremer.com/resources/abe1d3d6-51ba-4060-a412-763d92ef4c06> ;
      <nex:vnode> <http://shield.ebremer.com/resources/abe1d3d6-51ba-4060-a412-763d92ef4c06> , <http://shield.ebremer.com/resources/9eeb0614-e1ed-4603-96e7-587ddaba32ca> .

<http://shield.ebremer.com/resources/007e136b-e05a-4061-b70e-1db5127a42b2>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.daml.org/2001/10/html/airport-ont#latitude" ;
      <nex:objxyz> "-20.15058,16.152966,3.8811495" ;
      <nex:plen> "7.34101" ;
      <nex:rotation> "0.37777174 0.0 -0.85328114 -0.35944363" ;
      <nex:subjxyz> "-14.904862,18.146603,-0.8515341" ;
      <nex:xyz> "-17.527721,17.149784,1.5148077" .

<http://shield.ebremer.com/resources/b3adf0db-7020-4ef7-b279-9b5188171c26>
      a       <nex:sphere> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/PersonalProfileDocument" ;
      <nex:xyz> "-14.76252,-9.281522,0.552921" .

<http://shield.ebremer.com/resources/051b6934-d1d3-493a-b8b7-6d6547204aa6>
      a       <nex:cube> ;
      <nex:HoverText> "-72.916725" ;
      <nex:xyz> "6.546685,1.1909465,23.601688" .

<http://shield.ebremer.com/resources/dff7e450-4434-48cf-9719-0144563cfe03>
      a       <nex:cube> ;
      <nex:HoverText> "40.836695" ;
      <nex:xyz> "1.8440512,-5.244094,24.264164" .

<http://shield.ebremer.com/resources/4e386d68-59b4-40a4-b2b1-172ce8ea572f>
      a       <nex:sphere> ;
      <nex:HoverText> "tel:631-444-3560" ;
      <nex:xyz> "0.61919737,2.2530727,-6.9366236" .

<http://shield.ebremer.com/resources/69d0c361-57e6-4ea2-b353-c14a12de84e1>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/givenname" ;
      <nex:objxyz> "3.5382593,4.096192,6.0742407" ;
      <nex:plen> "9.031261" ;
      <nex:rotation> "0.7903025 0.0 -0.42028958 0.445846" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "2.4131625,0.9139979,3.0744538" .

<http://shield.ebremer.com/resources/6eaa9557-cb96-49d0-ab66-18c57c097404>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/mbox" ;
      <nex:objxyz> "-2.7040677,-15.5965185,-18.37289" ;
      <nex:plen> "7.5463986" ;
      <nex:rotation> "0.64175904 0.0 0.36307096 -0.6755181" ;
      <nex:subjxyz> "-1.3737096,-9.053491,-14.856207" ;
      <nex:xyz> "-2.0388887,-12.325005,-16.614548" .

<http://www.ebremer.com/foaf.rdf>
      a       <http://xmlns.com/foaf/0.1/PersonalProfileDocument> ;
      <http://xmlns.com/foaf/0.1/maker>
              <http://www.ebremer.com/foaf.rdf#me> ;
      <http://xmlns.com/foaf/0.1/primaryTopic>
              <http://www.ebremer.com/foaf.rdf#me> ;
      <http://xmlns.com/foaf/0.1/title>
              "Erich Bremer's profile" ;
      <nex:rnode> <http://shield.ebremer.com/resources/b41b960d-45dc-42b9-9140-6a8c494dfe50> ;
      <nex:vnode> <http://shield.ebremer.com/resources/b41b960d-45dc-42b9-9140-6a8c494dfe50> .

<http://shield.ebremer.com/nex/graphs/9d6ac1b0-6f2f-47c0-ae34-a500e7700bbf>
      <nex:lnode> <http://shield.ebremer.com/resources/c5a8ee68-26e2-4f8e-af3a-239042d5cf27> ;
      <nex:pnode> <http://shield.ebremer.com/resources/bb08e58a-655b-4920-b5ee-1588914ae382> ;
      <nex:vnode> <http://shield.ebremer.com/resources/c5a8ee68-26e2-4f8e-af3a-239042d5cf27> , <http://shield.ebremer.com/resources/bb08e58a-655b-4920-b5ee-1588914ae382> .

<http://shield.ebremer.com/resources/7513d558-1ab3-4705-ae5f-7ee586ec4b0b>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/based_near" ;
      <nex:objxyz> "2.134508,-1.0674458,18.377794" ;
      <nex:plen> "18.361992" ;
      <nex:rotation> "0.72322106 0.0 -0.68913525 0.04520973" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "1.7112868,-1.6678209,9.226231" .

<http://shield.ebremer.com/resources/35f94abd-847a-490a-86eb-22f2e3726060>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.daml.org/2001/10/html/airport-ont#location" ;
      <nex:objxyz> "-18.284475,24.98204,3.2179208" ;
      <nex:plen> "8.643232" ;
      <nex:rotation> "0.55180943 0.0 -0.42661977 0.7165905" ;
      <nex:subjxyz> "-14.904862,18.146603,-0.8515341" ;
      <nex:xyz> "-16.59467,21.564322,1.1831933" .

<http://shield.ebremer.com/resources/027fd95a-b962-4f27-8634-a61fd7f3741d>
      a       <nex:cube> ;
      <nex:HoverText> "B8CD08202DB1C18A704AE4ABBF0C2C7A23C7FD9C8D85BC957645D91922BC79BF81C468A75A80629DD134CB639213B661E1762B365A85EFC37E110E6946A882A429103E2601C1EBC42F612635E8E5B9C968D53940FA9EDC4644B20A89E9CA2963232B0625D2FFED66AB5BB97E700D2ACCE91D972D37005370B01B3632CA43E42B0DD8DD283D5B811059547FA772480A2B5DB8781E69CF7DBD6BDC61A5165A2F659DE7904006A5AC4C70AA226FDCCEC514B9AE081C40E917368B4882F769F9A8BAA818E8BD72DBEDD3ABCF9BCB66BD9AAC916CD56F47FCAA3DA4337E99B4064DF4AF4F2869D751E35F324C8E06996D7B1491F55F1C7B05E5BD5D31C95919D25801"^^<http://www.w3.org/2001/XMLSchema#hexBinary> ;
      <nex:xyz> "5.035039,-26.519365,0.5492316" .

<http://www.ebremer.com>
      <nex:rnode> <http://shield.ebremer.com/resources/666541e3-5ed4-4ee1-87eb-3fc170af8b59> ;
      <nex:vnode> <http://shield.ebremer.com/resources/666541e3-5ed4-4ee1-87eb-3fc170af8b59> .

<http://shield.ebremer.com/resources/db23a1f7-83eb-4402-8bbd-28a477393d88>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/ns/auth/cert#exponent" ;
      <nex:objxyz> "-2.369653,-26.378757,3.3365998" ;
      <nex:plen> "7.2567644" ;
      <nex:rotation> "0.4521922 0.0 -0.033338398 -0.8912972" ;
      <nex:subjxyz> "1.9194171,-20.529259,3.117803" ;
      <nex:xyz> "-0.22511792,-23.454008,3.2272015" .

<http://shield.ebremer.com/resources/a6e56026-c5bd-4331-ab7a-20b0f1c8660a>
      a       <nex:sphere> ;
      <nex:HoverText> "http://www.w3.org/ns/auth/cert#RSAPublicKey" ;
      <nex:xyz> "3.6347718,-25.323143,8.237062" .

<http://shield.ebremer.com/nex/graphs/bb1f51ac-d0e5-4e17-8948-6e8b7cf9ba38>
      <nex:pnode> <http://shield.ebremer.com/resources/a1e381fd-5527-4cba-a92c-9174792ca6a2> ;
      <nex:vnode> <http://shield.ebremer.com/resources/a1e381fd-5527-4cba-a92c-9174792ca6a2> .

<http://shield.ebremer.com/nex/graphs/53f44285-1ec2-4a25-a65a-edb37287ddc5>
      <nex:lnode> <http://shield.ebremer.com/resources/9a016505-55fc-40e1-bbe0-5895319289be> ;
      <nex:pnode> <http://shield.ebremer.com/resources/583634b9-1410-4e35-8bbc-40a12317ac72> ;
      <nex:vnode> <http://shield.ebremer.com/resources/9a016505-55fc-40e1-bbe0-5895319289be> , <http://shield.ebremer.com/resources/583634b9-1410-4e35-8bbc-40a12317ac72> .

<http://shield.ebremer.com/resources/68fb1356-03c3-4cc1-9bb0-7d8ac852fd55>
      a       <nex:sphere> ;
      <nex:nodesize> "3" ;
      <nex:numlinks> "3" ;
      <nex:q> "3" ;
      <nex:xyz> "12.902582,7.535981,-10.111939" .

<http://shield.ebremer.com/resources/322e2c62-2466-4250-82d0-95bd38dea1f8>
      a       <nex:sphere> ;
      <nex:HoverText> "http://www.skype.com/" ;
      <nex:xyz> "13.079804,11.690309,-15.968671" .

<http://shield.ebremer.com/resources/8762b36d-8dec-4a91-9f68-869a1a5db36f>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/name" ;
      <nex:objxyz> "1.7432859,-10.034435,-21.6401" ;
      <nex:plen> "7.529882" ;
      <nex:rotation> "0.84081805 0.0 0.5357458 -0.07746834" ;
      <nex:subjxyz> "-1.3737096,-9.053491,-14.856207" ;
      <nex:xyz> "0.18478817,-9.5439625,-18.248154" .

<http://shield.ebremer.com/nex/graphs/59170156-1382-4874-bd1c-92fd9d9e1274>
      <nex:pnode> <http://shield.ebremer.com/resources/71fb6b92-4ea0-48e3-a2a7-48ec9275069d> ;
      <nex:vnode> <http://shield.ebremer.com/resources/71fb6b92-4ea0-48e3-a2a7-48ec9275069d> .

<http://shield.ebremer.com/nex/graphs/eb5cf9d4-b962-4a40-88e0-9792b9ce0631>
      <nex:lnode> <http://shield.ebremer.com/resources/dff7e450-4434-48cf-9719-0144563cfe03> ;
      <nex:pnode> <http://shield.ebremer.com/resources/f9ba89b7-fe3d-43a8-bc80-018e0b18e8a2> ;
      <nex:vnode> <http://shield.ebremer.com/resources/f9ba89b7-fe3d-43a8-bc80-018e0b18e8a2> , <http://shield.ebremer.com/resources/dff7e450-4434-48cf-9719-0144563cfe03> .

<http://shield.ebremer.com/resources/8f667cb6-ba11-4f04-95fb-6f8de631b750>
      a       <nex:cube> ;
      <nex:HoverText> "68.195.227.26" ;
      <nex:xyz> "22.810303,-9.893983,8.884933" .

<http://shield.ebremer.com/nex/graphs/183bf392-422e-4f79-80c4-73a80d8bfefd>
      <nex:lnode> <http://shield.ebremer.com/resources/7a62ac94-793e-4bba-8a72-6cfae00b86b1> ;
      <nex:pnode> <http://shield.ebremer.com/resources/05b2d050-0b51-4230-9056-ec14340663a2> ;
      <nex:vnode> <http://shield.ebremer.com/resources/7a62ac94-793e-4bba-8a72-6cfae00b86b1> , <http://shield.ebremer.com/resources/05b2d050-0b51-4230-9056-ec14340663a2> .

<mailto:erich@ebremer.com>
      <nex:rnode> <http://shield.ebremer.com/resources/8fe9f157-afdc-45fe-a669-c2f51de7e7a5> ;
      <nex:vnode> <http://shield.ebremer.com/resources/8fe9f157-afdc-45fe-a669-c2f51de7e7a5> .

<http://shield.ebremer.com/resources/58ec8462-762e-4982-a46e-6737b8254dfb>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/firstName" ;
      <nex:objxyz> "6.9691315,-3.1183655,-5.7980638" ;
      <nex:plen> "8.215002" ;
      <nex:rotation> "0.9196596 0.0 0.38866487 -0.05626531" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "4.1285987,-2.6932807,-2.8616984" .

<http://shield.ebremer.com/resources/9e449a77-55e3-4aab-a281-225071956f18>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ;
      <nex:objxyz> "24.798235,-2.705969,6.5723734" ;
      <nex:plen> "7.220257" ;
      <nex:rotation> "0.95714426 0.0 -0.16340853 0.23910758" ;
      <nex:subjxyz> "18.789173,-6.010832,4.313797" ;
      <nex:xyz> "21.793705,-4.3584003,5.443085" .

<tel:631-444-3560>
      <nex:rnode> <http://shield.ebremer.com/resources/4e386d68-59b4-40a4-b2b1-172ce8ea572f> ;
      <nex:vnode> <http://shield.ebremer.com/resources/4e386d68-59b4-40a4-b2b1-172ce8ea572f> .

<http://shield.ebremer.com/resources/0a277f4a-241d-437d-8a28-84cae8d9cbde>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/name" ;
      <nex:objxyz> "6.757046,-3.423891,6.078216" ;
      <nex:plen> "8.202926" ;
      <nex:rotation> "0.9128831 0.0 -0.40086132 -0.07716658" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "4.022556,-2.8460436,3.0764415" .

<nex:clientsession>
      <nex:rnode> <http://shield.ebremer.com/resources/170959a5-3e99-4dc9-9fbd-e94c2e55b419> ;
      <nex:vnode> <http://shield.ebremer.com/resources/170959a5-3e99-4dc9-9fbd-e94c2e55b419> .

<http://shield.ebremer.com/nex/graphs/86fc0ea3-742a-44c6-9e72-7176b2410f74>
      <nex:lnode> <http://shield.ebremer.com/resources/8f667cb6-ba11-4f04-95fb-6f8de631b750> ;
      <nex:pnode> <http://shield.ebremer.com/resources/8d846a2a-1bb0-4a85-bbbd-941caba6cce4> ;
      <nex:vnode> <http://shield.ebremer.com/resources/8d846a2a-1bb0-4a85-bbbd-941caba6cce4> , <http://shield.ebremer.com/resources/8f667cb6-ba11-4f04-95fb-6f8de631b750> .

<http://shield.ebremer.com/nex/graphs/15b7f9b2-58b8-43e4-95ba-a76b2b4ccfb2>
      <nex:pnode> <http://shield.ebremer.com/resources/af0c590e-779f-4743-b2fb-dbdf510b33ce> ;
      <nex:vnode> <http://shield.ebremer.com/resources/af0c590e-779f-4743-b2fb-dbdf510b33ce> .

<http://shield.ebremer.com/nex/graphs/ae649e36-e6f7-477c-80c2-7e1c4b4a24e9>
      <nex:lnode> <http://shield.ebremer.com/resources/29bb010a-ac87-4b82-9171-c7c2b81793f8> ;
      <nex:pnode> <http://shield.ebremer.com/resources/0a277f4a-241d-437d-8a28-84cae8d9cbde> ;
      <nex:vnode> <http://shield.ebremer.com/resources/29bb010a-ac87-4b82-9171-c7c2b81793f8> , <http://shield.ebremer.com/resources/0a277f4a-241d-437d-8a28-84cae8d9cbde> .

<http://shield.ebremer.com/resources/c0438c52-0da4-46db-953e-c3d4d5224d5a>
      a       <nex:cube> ;
      <nex:HoverText> "Tammy DiPrima" ;
      <nex:xyz> "1.7432859,-10.034435,-21.6401" .

<http://shield.ebremer.com/nex/graphs/bef64ed1-e056-4889-a1fe-9079eb88b6b6>
      <nex:lnode> <http://shield.ebremer.com/resources/c0438c52-0da4-46db-953e-c3d4d5224d5a> ;
      <nex:pnode> <http://shield.ebremer.com/resources/8762b36d-8dec-4a91-9f68-869a1a5db36f> ;
      <nex:vnode> <http://shield.ebremer.com/resources/c0438c52-0da4-46db-953e-c3d4d5224d5a> , <http://shield.ebremer.com/resources/8762b36d-8dec-4a91-9f68-869a1a5db36f> .

<http://shield.ebremer.com/nex/graphs/a3e64c9f-e7ca-4c50-8692-489a60b02d59>
      <nex:pnode> <http://shield.ebremer.com/resources/7513d558-1ab3-4705-ae5f-7ee586ec4b0b> ;
      <nex:vnode> <http://shield.ebremer.com/resources/7513d558-1ab3-4705-ae5f-7ee586ec4b0b> .

<http://shield.ebremer.com/nex/graphs/cd2f3763-96c8-458a-81d9-4797a29d3de8>
      <nex:pnode> <http://shield.ebremer.com/resources/bcc8f0a5-e903-4fc2-83e5-3b3d2b774669> ;
      <nex:vnode> <http://shield.ebremer.com/resources/bcc8f0a5-e903-4fc2-83e5-3b3d2b774669> .

<http://shield.ebremer.com/resources/05b2d050-0b51-4230-9056-ec14340663a2>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.daml.org/2001/10/html/airport-ont#icaoCode" ;
      <nex:objxyz> "-19.809538,15.09504,-5.055586" ;
      <nex:plen> "7.1443634" ;
      <nex:rotation> "0.3959104 0.0 0.7431519 -0.53942585" ;
      <nex:subjxyz> "-14.904862,18.146603,-0.8515341" ;
      <nex:xyz> "-17.3572,16.620821,-2.9535599" .

<http://shield.ebremer.com/resources/666541e3-5ed4-4ee1-87eb-3fc170af8b59>
      a       <nex:sphere> ;
      <nex:HoverText> "http://www.ebremer.com" ;
      <nex:xyz> "6.8995605,-8.502952,-0.75715226" .

<http://shield.ebremer.com/resources/170959a5-3e99-4dc9-9fbd-e94c2e55b419>
      a       <nex:sphere> ;
      <nex:HoverText> "nex:clientsession" ;
      <nex:xyz> "24.798235,-2.705969,6.5723734" .

<http://shield.ebremer.com/nex/graphs/d8f859e7-3a2c-49c5-8ae3-0e977fa10d20>
      <nex:pnode> <http://shield.ebremer.com/resources/fb33cb18-d2b7-4cd6-ad1b-dd4545dfe5ef> ;
      <nex:vnode> <http://shield.ebremer.com/resources/fb33cb18-d2b7-4cd6-ad1b-dd4545dfe5ef> .

<http://shield.ebremer.com/resources/c80a1c26-be88-4859-a97b-155acb835e1f>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/2000/01/rdf-schema#seeAlso" ;
      <nex:objxyz> "-6.128773,-8.901025,-20.684343" ;
      <nex:plen> "7.523367" ;
      <nex:rotation> "0.42892927 -0.0 0.90302914 0.023623515" ;
      <nex:subjxyz> "-1.3737096,-9.053491,-14.856207" ;
      <nex:xyz> "-3.7512414,-8.977258,-17.770275" .

<http://shield.ebremer.com/resources/b4c745b0-a99a-4844-9437-396b719f1a4d>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/holdsAccount" ;
      <nex:objxyz> "12.902582,7.535981,-10.111939" ;
      <nex:plen> "18.297153" ;
      <nex:rotation> "0.904094 -0.0 0.30789486 0.29633576" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "7.095324,2.6338925,-5.018636" .

<http://shield.ebremer.com/resources/d7b6d0c8-b610-4146-8e2b-6ea31ac1eb91>
      a       <nex:sphere> ;
      <nex:HoverText> "http://www.ebremer.com/foaf.rdf#me" ;
      <nex:nodesize> "18" ;
      <nex:numlinks> "18" ;
      <nex:q> "18" ;
      <nex:xyz> "1.2880657,-2.268196,0.074667156" .

<http://shield.ebremer.com/resources/b703c2aa-c634-46b0-85e6-96cb3c94d34b>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/phone" ;
      <nex:objxyz> "0.61919737,2.2530727,-6.9366236" ;
      <nex:plen> "8.369435" ;
      <nex:rotation> "0.67826325 -0.0 0.617552 0.39823174" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "0.9536315,-0.0075616837,-3.4309783" .

<http://shield.ebremer.com/resources/b41b960d-45dc-42b9-9140-6a8c494dfe50>
      a       <nex:sphere> ;
      <nex:HoverText> "http://www.ebremer.com/foaf.rdf" ;
      <nex:nodesize> "4" ;
      <nex:numlinks> "4" ;
      <nex:q> "4" ;
      <nex:xyz> "-7.744496,-6.2348194,2.3804553" .

<http://shield.ebremer.com/resources/5997861f-a88d-479d-8e2a-52a701c49cb1>
      a       <nex:cube> ;
      <nex:HoverText> "1360634398601" ;
      <nex:xyz> "24.7447,-8.840323,1.3769542" .

<http://shield.ebremer.com/resources/4adc5dcd-ddf4-4592-9e54-0c0686dd8f9b>
      a       <nex:cube> ;
      <nex:HoverText> "Mr." ;
      <nex:xyz> "8.727002,1.4348108,0.31527075" .

<http://shield.ebremer.com/resources/a6ff1888-c243-4126-acbf-b44c651855b0>
      a       <nex:sphere> ;
      <nex:HoverText> "mailto:tammy.diprima@stonybrook.edu" ;
      <nex:xyz> "-2.7040677,-15.5965185,-18.37289" .

<http://shield.ebremer.com/resources/d2ce17d5-c4cd-434f-8c78-7fe5e9b79fff>
      a       <nex:cube> ;
      <nex:HoverText> "-73.097545" ;
      <nex:xyz> "-23.10833,20.7913,-1.7015207" .

<http://shield.ebremer.com/resources/b923152a-8efc-4ff2-9dba-1d1abdedab44>
      a       <nex:cube> ;
      <nex:HoverText> "Islip, New York, United States" ;
      <nex:xyz> "-18.284475,24.98204,3.2179208" .

<http://shield.ebremer.com/resources/a59dd00a-e501-4c76-ac18-de0141a3f0d4>
      a       <nex:sphere> ;
      <nex:HoverText> "http://www.rpi.edu" ;
      <nex:xyz> "-2.4844422,-1.1644895,7.222489" .

<http://shield.ebremer.com/resources/abe1d3d6-51ba-4060-a412-763d92ef4c06>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://xmlns.com/foaf/0.1/status" ;
      <nex:objxyz> "-5.6631656,-1.3325166,-4.3307486" ;
      <nex:plen> "8.2826805" ;
      <nex:rotation> "0.28350577 -0.0 0.93804586 0.19923441" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "-2.18755,-1.8003564,-2.1280408" .

<http://shield.ebremer.com/resources/fe02cb3e-5e78-4345-8ffd-dc664eb00162>
      a       <nex:sphere> ;
      <nex:HoverText> "http://www.w3.org/2003/01/geo/wgs84_pos#Point" ;
      <nex:xyz> "-1.2423172,1.9353592,23.958439" .

<http://shield.ebremer.com/resources/feb37eec-a3b8-48ba-9bd1-780baa0923c5>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.daml.org/2001/10/html/airport-ont#name" ;
      <nex:objxyz> "-17.589022,25.33923,-4.8700905" ;
      <nex:plen> "8.6652975" ;
      <nex:rotation> "0.5874693 -0.0 0.3947039 0.7064621" ;
      <nex:subjxyz> "-14.904862,18.146603,-0.8515341" ;
      <nex:xyz> "-16.246943,21.742916,-2.8608122" .

<http://shield.ebremer.com/resources/8eff4274-4595-4556-8b5c-b56309bd0d8c>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ;
      <nex:objxyz> "-0.31521404,-6.5853963,-9.528153" ;
      <nex:plen> "10.650018" ;
      <nex:rotation> "0.6517121 0.0 0.69177145 -0.311004" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "0.48642582,-4.426796,-4.726743" .

<http://shield.ebremer.com/resources/b6ecaf9e-d9fe-44f8-bd45-9188fec00d0b>
      a       <nex:sphere> ;
      <nex:nodesize> "8" ;
      <nex:numlinks> "8" ;
      <nex:q> "8" ;
      <nex:xyz> "-14.904862,18.146603,-0.8515341" .

<http://shield.ebremer.com/nex/graphs/d9971994-d4f1-40c5-acce-b2ddf093a59f>
      <nex:pnode> <http://shield.ebremer.com/resources/bd6d61f7-32cf-41c3-97ce-d10e88baba18> ;
      <nex:vnode> <http://shield.ebremer.com/resources/bd6d61f7-32cf-41c3-97ce-d10e88baba18> .

<http://shield.ebremer.com/resources/e2ac006c-0dfe-42d8-b140-9941afc549c8>
      a       <nex:sphere> ;
      <nex:HoverText> "http://www.ebremer.com/ebfiles/erich.jpg" ;
      <nex:xyz> "0.9335052,-8.212778,5.893996" .

<http://shield.ebremer.com/resources/6b9c8582-487c-42d9-8298-e9cc51762d2f>
      a       <nex:cylinder> ;
      <nex:HoverText> "http://www.w3.org/2000/10/swap/pim/contact#nearestAirport" ;
      <nex:objxyz> "-14.904862,18.146603,-0.8515341" ;
      <nex:plen> "26.073603" ;
      <nex:rotation> "0.43528903 -0.0 0.040803414 0.8993656" ;
      <nex:subjxyz> "1.2880657,-2.268196,0.074667156" ;
      <nex:xyz> "-6.8083982,7.9392033,-0.3884335" .

<http://shield.ebremer.com/resources/92f18885-f7cb-4b4b-8e64-ae07ba8e127c>
      a       <nex:cube> ;
      <nex:HoverText> "Erich" ;
      <nex:xyz> "3.5382593,4.096192,6.0742407" .

Tags: 

Nexus WebGL 3D RDF client in Technicolor

It took less time than I thought it would, but here is an updated version of the 3D FOAF graph from my last posting with node sizes determined by the log base 10 of the number of links into a particular node.  The coulombs law for the larger nodes is adjusted so that larger nodes "push" out harder to accomodate the larger spheres preventing sphere clashes.  This images was taken with the WebGL running in Chrome.

Next on the agenda for additional functionality is the actual display of text labels over subjects, predicates, and objects.  Also to be added is WebGL camera and avatar positioning data.  What's this?  In the Opensimulator client, dozens of people can view and interact with the same RDF model/structure.  Where one of those people are looking or focusing their attention is indicated by their 3D cursor or avatar.  However, this leaves the WebGL client users in the dark as to what the OpenSimulator users and/or other WebGL clients are doing in the simulation.  I am planning to synchronize this information between all of the clients by streaming the avatar (or camera position data in the case of WebGL) back to the Nexus server where it will be pushed out to all clients in the form of more RDF triples.

The SPARQL commands for the colors and such for this image are as follows:

1) Make everything blue
insert {?rnode <nex:color> "0,0,1"} where {?node <nex:rnode> ?rnode}
insert {?pnode <nex:color> "0,0,1"} where {?node <nex:pnode> ?pnode}

2) Color white all literals
insert {?lnode <nex:color> "1,1,1"} where {?node <nex:lnode> ?lnode}

3) Color red all triples that are of foaf:knows
modify delete {?rnode <nex:color> "0,0,1"} insert {?rnode <nex:color> "1,0,0"}  where {?node <nex:rnode> ?rnode . ?node foaf:knows ?o }
modify delete {?pnode <nex:color> "0,0,1"} insert {?pnode <nex:color> "1,0,0"}  where {?node <nex:pnode> ?pnode . ?node rdf:predicate foaf:knows }

4) color green all triples of type rdf:type
modify delete {?rnode <nex:color> "0,0,1"} insert {?rnode <nex:color> "0,1,0"}  where {?node <nex:rnode> ?rnode . ?node rdf:type ?o }
modify delete {?pnode <nex:color> "0,0,1"} insert {?pnode <nex:color> "0,1,0"}  where {?node <nex:pnode> ?pnode . ?node rdf:predicate rdf:type }

5) Make everything shiny
insert {?rnode <nex:shiny> "3"} where {?node <nex:rnode> ?rnode}
insert {?pnode <nex:shiny> "3"} where {?node <nex:pnode> ?pnode}
insert {?lnode <nex:shiny> "3"} where {?node <nex:lnode> ?lnode}

Yes, I am planning on coming up with a far easier interface for the user other than SPARQL. :-)

Tags: 

SPARQL 1.1 Controlled 3D RDF Visualization - from a Force-Directed Layout to a Molecular Visualization of DNA using Nexus in OpenSimulator

Nexus is an experiment with Semantic Web RDF data visualized in three dimensiodians that can be done collaboratively amongst many people (and concurrently) at disparate locations.  Nexus also acts as a platform to try out various design ideas, technologies, and methodologies.  The original Nexus design read and displayed RDF data and could also export it.  I have reworked the back-end of Nexus to use RDF internally and to communicate with its front-end client(s) in pure N-Triples.  The internal RDF representation enables the use of SPARQL (the query language for RDF) via Jena ARQ to manipulate the RDF graph and thus the over-all visualization.  In this posting, I will show the SPARQL 1.1 commands used to manipulate the structural data of a strand of DNA that has been converted to RDF from the original PDB format.  The resulting display will be shown as a force-directed layout and then manipulated into a physical RDF layout determined by crystal structure coordinates contained within the RDF.  Essentially, this will allow for molecular visualization within Nexus allowing us to actually see the strand of DNA in a physical form.

Basic Visualization Design Concepts in Nexus
The basic unit of information we want to visualize is the RDF triple:

Subject - Predicate - Object

In keeping with the "pure RDF" concept, this triple would be annotated with a RDF triples using a display ontology designed for Nexus, it's prefix being "nex".  Statements like nex:color, nex:xyz, nex:glow, nex:nodesize could be made about any resource whether it be subject or object.  For each resource, a "display node" triple is introduced and attached to the original rdf resource. RDF nex statements would then be made about that display node.  For example:

?s ?p ?o
?s nex:rnode ?displaynode
?displaynode nex:color "1,0,0" (red)
?displaynode nex:xyz "2.34,7.34,1.23"e
?displaynode rdf:type nex:sphere
?displaynode nex:radius "3.4"
    and so on.....

Adding this "display node" layer added a large degree of flexibility for RDF displays.  At one point, the display nodes were represented as blank nodes, but in the current version of Nexus, I converted these to resources.  It was just easier to work with in this way.

Fun with RDF Reification
Visualization nodes cannot be attached directly to predicates and literals because RDF statements cannot be made about predicates or literals.  You can only make RDF statements about resources.  However, you can make statements about statements through a process known as RDF reification.  The triples for a single reified statement for nexus would look as follows:

?s ?p ?literal  (statement to be visualized)

The following RDF statements attach a display node to the predicate (?p) and literal (?literal)

?viznode rdf:type rdf:Statement
?viznode rdf:subject ?s
?viznode rdf:predicate ?p
?viznode rdf:object ?literal
?viznode nex:pnode ?displaynode
?viznode nex:lnode ?displaynode

No, RDF reification is not pretty, I know, I'm not a fan of the syntax, but it does allow you to make statements about other statements, and in my case, be used to make indirect statements about specific predicates and literals without having to modify any of the ontologies or resorting to use named graphs (not that this method is bad, I just haven't thought about it yet much).  So, at this point, we have three kinds of display nodes - rnodes (for resources), pnodes (for predicates), and lnodes (for literals).  These three types are actually all the same, but by assigning them different names it is easier to distinguish them from each other when querying the RDF.  This could have been done with a rdf:type statment but this was a bit more compact.  I may or may not change it later.  The W3C RDF working group had a recent discussion of whether RDF reification should be deprecated (see here).  I think the functionality of reification is needed, I just think it's syntax and design need to be re-worked.  For now, it is enabling me to do my arbitrary 3D visualizations.

OpenSimulator Object References
Rather than relying upon OpenSimulator's inventory mechanism and object ID system, objects are stored as RDF and assigned dereferencable RDF URI's which allow the objects to be accessed from remote OpenSimulator regions via the Nexus server code/triple store.  This will allow multiple regions (even if on different grids) to access concurrently the same RDF visualization.  The same RDF URI method could be used as a universal reference to refer to OpenSimulator users and groups (as well as the objects), RDF data interchange between OpenSimulator regions could also be quite handy, but that's another project for another day... :-)  For now, we'll see how well it works within Nexus.

Laying out the RDF Graph
Nexus implements a basic force-directed layout algorithm where the force of the nodes are modeled with Coulomb's Law and the predicates are modeled as springs with Hooke's Law.  When applying the force-layout to the loaded RDF graph (and this can be any RDF graph), the Nexus triples are ignored.  Later down the road, I would like to experiment with various modifications of the force-directed method and/or different methods all together.  I still have a bit of work to do on Nexus force-directed layout engine so that the results are more usable.

Sending the back-end RDF model to the front-end for visualization
The purpose of the front-end is to render the visualization nodes.  The RDF is pulled from the back-end using http and is sent purely as RDF N-Triples.  In an earlier version of Nexus, this was mostly RDF, now it is purely RDF.  When commands are needed to instruct the front-end to do things, the commands are sent as RDF triples.  For example, if I want the front-end to redraw the model, the back-end sends a triple about the session to the front-end as follows:

<http://www.ebremer.com/nexus/sessionmodel/1234567890> <nex:redraw> "true"  (an example)

Turning RDF into DNANexus - Semantic DNA
Back when I attended CSHALS 2010, I had started to write a pdb ontology to express PDB as RDF but shelved it to work on the core of Nexus.  No one else had an RDF representation of PDB that I could find.  Periodically, I checked, and finally during the summer of 2010 I discovered that the Michel Dumontier Lab had written a conversion for pdb and made the conversion program available (pdb2rdf).  And there was rejoicing in the streets!  I had a program now that could do the pdb (protein databank format) to RDF conversion.  The pdb file converted resulted in 16,473 triples.  It doesn't look like pdb2rdf transfers the bonding/connect information in the pdb files yet, so I'm limited to space-filled at the moment.  When the bond information gets added to the RDF conversion, I will be able to do ball and stick views as well.

Now, in order to turn the force directed graph into a visualization of DNA as seen in the first figure to that of the second figure, we would issue the following SPARQL 1.1 commands:

Step #1 - Set all display nodes visible property to false.  The nex:visible predicate tells the server whether to include that visualization node in the final display or whether to even consider it in the layout routines.

modify delete {?s <nex:visible> ?o} insert {?s <nex:visible> "0"} where {?s <nex:visible> ?o}

Step #2 - Set all display nodes visible property attached to atom nodes to true.  We use the predicate "pdb:hasSpatialLocation" to select atoms nodes since the atom nodes are the only nodes that have a spatial location.

modify delete {?rnode <nex:visible> ?o} insert {?rnode <nex:visible> "1"} where {?atom <nex:rnode> ?rnode . ?atom pdb:hasSpatialLocation ?loc . ?rnode <nex:visible> ?o}

Step #3 - We now change the coordinates of the force-directed determined atoms (their visualization nodes) to the crystal-determined XYZ location by reconstructing a vector from the XYZ triples.

modify delete {?rnode <nex:xyz> ?o} insert {?rnode <nex:xyz> ?xyz} where {?atom <nex:rnode> ?rnode . ?rnode <nex:xyz> ?o . ?atom pdb:hasSpatialLocation ?loc . ?loc pdb:hasXCoordinate ?xc . ?loc pdb:hasYCoordinate ?yc . ?loc pdb:hasZCoordinate ?zc. ?xc pdb:hasValue ?x . ?yc pdb:hasValue ?y . ?zc pdb:hasValue ?z . let (?xyz := fn:concat(?x,",",?y,",",?z)) }

Step #4 - The following series of commands sets the nodesize (radius) of the atom visualization nodes to the values that represent the actual atomic radii of the various types of atom present in the structure.  If this data was entered into the system as RDF triples, these six commands could be reduced to one.

modify delete {?rnode <nex:nodesize> ?o} insert {?rnode <nex:nodesize> "1.0"} where {?atom <nex:rnode> ?rnode . ?atom rdf:type pdb:HydrogenAtom . ?rnode <nex:nodesize> ?o}

modify delete {?rnode <nex:nodesize> ?o} insert {?rnode <nex:nodesize> "2.8"} where {?atom <nex:rnode> ?rnode . ?atom rdf:type pdb:CarbonAtom . ?rnode <nex:nodesize> ?o}

modify delete {?rnode <nex:nodesize> ?o} insert {?rnode <nex:nodesize> "2.6"} where {?atom <nex:rnode> ?rnode . ?atom rdf:type pdb:NitrogenAtom . ?rnode <nex:nodesize> ?o}

modify delete {?rnode <nex:nodesize> ?o} insert {?rnode <nex:nodesize> "3.4"} where {?atom <nex:rnode> ?rnode . ?atom rdf:type pdb:PhosphorusAtom . ?rnode <nex:nodesize> ?o}

modify delete {?rnode <nex:nodesize> ?o} insert {?rnode <nex:nodesize> "2.4"} where {?atom <nex:rnode> ?rnode . ?atom rdf:type pdb:OxygenAtom . ?rnode <nex:nodesize> ?o}

modify delete {?rnode <nex:nodesize> ?o} insert {?rnode <nex:nodesize> "3.2"} where {?atom <nex:rnode> ?rnode . ?atom rdf:type pdb:SufurousAtom . ?rnode <nex:nodesize> ?o}

Step #5 - Now for a little flair, we set the shininess of the atom visualization nodes to a glossy metallic value, again, using the "hasSpatialLocation" predicate to pick out the atom nodes.

insert {?rnode <nex:shiny> "3"} where {?atom <nex:rnode> ?rnode . ?atom pdb:hasSpatialLocation ?loc}

Step #6 - We now color all atom visualization nodes to blue

insert {?rnode <nex:color> "0,0,1"} where {?atom <nex:rnode> ?rnode . ?atom pdb:hasSpatialLocation ?loc}

Step #7 - The next five commands color the backbone of the DNA green by selecting atom nodes with a name in the form *' and *'', the backbone atom labels are traditionally labeled with apostrophe and double apostrophe. The last three commands handle the phosphates.

modify delete {?rnode <nex:color> ?o} insert {?rnode <nex:color> "0,1,0"} where {?atom <nex:rnode> ?rnode . ?atom pdb:hasSpatialLocation ?loc . ?atom rdfs:label ?name . ?rnode <nex:color> ?o . filter regex (?name, "''")}

modify delete {?rnode <nex:color> ?o} insert {?rnode <nex:color> "0,1,0"} where {?atom <nex:rnode> ?rnode . ?atom pdb:hasSpatialLocation ?loc . ?atom rdfs:label ?name . ?rnode <nex:color> ?o . filter regex (?name, "'")}

modify delete {?rnode <nex:color> ?o} insert {?rnode <nex:color> "0,1,0"} where {?atom <nex:rnode> ?rnode . ?atom pdb:hasSpatialLocation ?loc . ?atom rdfs:label ?name . ?rnode <nex:color> ?o . filter regex (?name, "P")}

modify delete {?rnode <nex:color> ?o} insert {?rnode <nex:color> "0,1,0"} where {?atom <nex:rnode> ?rnode . ?atom pdb:hasSpatialLocation ?loc . ?atom rdfs:label ?name . ?rnode <nex:color> ?o . filter regex (?name, "OP1")}

modify delete {?rnode <nex:color> ?o} insert {?rnode <nex:color> "0,1,0"} where {?atom <nex:rnode> ?rnode . ?atom pdb:hasSpatialLocation ?loc . ?atom rdfs:label ?name . ?rnode <nex:color> ?o . filter regex (?name, "OP2")}

Step #8 - Lastly, we set the phosphor atom display nodes to glow by inserting nex:glow statements attached to the corresponding phosphor atom display nodes.

insert {?rnode <nex:glow> "0.2"} where {?atom <nex:rnode> ?rnode . ?atom pdb:hasSpatialLocation ?loc . ?atom rdfs:label ?name . filter (?name="P")}

The resulting 3D RDF graph now looks like a DNA model that I had done with my prior Monolith project which dealt exclusively with non-RDF PDB-formatted data.  The DNA structure can be colored and effects set in many different ways by using the powerful new SPARQL 1.1 query language using any of the data present in the loaded RDF graph, not just what is displayed.  We can even access remote SPARQL end points and include their data as well.  Since Nexus handles any RDF, we are not limited to just molecular visualization.  We can branch off into other linked data by using the PubMed ID triple present into the RDF-converted PDB file and link over to PubMed publications data or anywhere else in the LOD (Linked Open Data) cloud.  For those of you thinking "these commands are not easy nor obvious" (perhaps to the SemWeb junkies) you would be correct.  I'm exploring ways in which the commands can be executed visually via the 3D front-end interface, but, I needed a flexible foundation on which to build and the SPARQL-driven engine seemed the best way to achieve this.  As it is, several of the above commands could be re-written to be a bit more compact and fewer, but, I am learning about this stuff myself as I go along.  I'm getting better. ;-)

Next Steps
I've been focused on doing the semantic web/molecular visualization cross-over and now that I've hit that milestone, there is some front-end and back-end work that still needs to be done.  The data is there, but I am not currently displaying any of it in the actual visualization (RDF labels and such).  I would also like to enable  a user to interact with the model graphically.  Interaction now is limited to command-line SPARQL commands only.  I had tossed out the half-SPARQL, half my own concoction commands in favor of the SPARQL.

This year, I did a poster presentation of Nexus combined with work that I have done with my colleagues at Stony Brook University (Dr. Janos Hajagos and Tammy DiPrima) for CSHALS 2011 (see poster here).  In the poster, I mentioned a couple of other things I am working on.  One of them is another Nexus front-end client based on WebGL/HTML5.   I had started this last year, but shelved it while I redesigned the Nexus back-end (server) to be all-RDF that it is now.  Now that the server is working again I will get back to the WebGL/HTML5 client.  As part of that project, I wanted to experiment with using WebSockets rather that http calls between the WebGL client and Nexus.  I will also update the original Nexus client which I did in Second Life, but, it will not be able to render as large of displays as I can in OpenSimulator since Linden Labs limits region objects to 15,000 primitives.  The DNA force-directed model seen here is 26,713 primitives, nearly twice what the Second Life regions allow.  But, I have provisions to allow a limited client to see a smaller window of a larger model.  All three clients will use the same back-end server and will be able to view any of the server models at the same time.  For example, 30 avatars in an OpenSimulator region will be able to work with 30 avatars in a Second Life region along with 30 different WebGL/HTML5 clients at the same time and see changes done from any of the clients live.  RDF breaks down the walled gardens between worlds.

Tags: 

Files: 

Monolith used in photo of Proteopedia, winner of the 2010 TheScientist "Best Science Website" Labby Awards"

Proteopedia is the winner of the 2010 TheScientist "Best Science Website" Labby Awards.  The picture used is of the website Proteopedia (http://www.proteopedia.org) next to an 3D RNA model.  The picture was taken at the Stony Brook University's SOM Second Life region.  The structure was generated using Monolith http://www.ebremer.com/monolith

I hadn't known someone took a picture at the region and used it for the awards photo until Dr. Joel Sussman stopped by my office and told me during a visit.  It gave me a big smile. :-)  Congratulations to the whole Proteopedia community!  The structure is still up at the Stony Brook region.

Tags: 

The Magic behind Monolith - how it works

The other year, I developed a molecular visualization system inside of Second Life (see http://www.ebremer.com/monolith) with a demonstration video of it in operation on YouTube for purposes of learning the scripting language LSL of Second Life and for the fact that I found the concept of a 3D collaborative visualization environment with IM and group voice incredibly intriguing.  Building Monolith seemed a good way to demonstrate the utility of the environment to myself and hopefully others.  There had been other projects for molecular visualization done in Second Life before Monolith (Hiro's molecule rezzer, ORAC, Peter Miller's Protein Rezzing Toolkit, and work by Troy McConaghy), so, what was I going to add to this arena?  In short, speed and flexibility.  Easier said then done, so here's how it works for those of you interested in Monolith and Second Life LSL scripting:

Bringing the data in-world
The source of Monolith's data is the Rutgers Protein Databank.  Rutgers provides a http interface for retrieving the various accession numbers which can be used to retrieve known structures of various proteins and DNA.  The problem here is that these files are larger than 2048 bytes.  Why is this a problem?  Because the command for accessing http data from within the Second Life environment is handled by the command llHTTPRequest.  Linden Lab (LL), limits singular http requests with this command to only the first 2048 bytes no matter how long the document is, so, how do you retrieve documents that are larger?  I got around this by developing a java servlet back-end which is what the in-world Monolith front-end talks to.  When the in-world user sends the command to Monolith for a particular accession number, the request is actually sent to the java servlet back-end which then turns around and downloads the entire file from Rutgers.  The java servlet then spoon-feeds the data to Monolith's front-end which resides in Second Life (aka in-world).  Ok, another problem here, LL also throttles llHTTPRequest to 1 call per second and no more than 25 calls in any 20 second period with a burst of up to 25 calls in a one second time-period per in-world object.  UGH!  That means a single object in-world can only bring in 50k/per 20 seconds or 2.5K/sec.  I worked around this problem by using multiple http objects which are rezzed by the primary object which can go as high as needed, so for 50 http objects gives me 125k/sec which is a whole lot more workable than 2.5K/sec.  Later, I added this "multiple http object streaming" method to my atom nodes themselves eliminating the need for separate http objects.  The process to this point now is that one command pulls all of the data to the java back-end fromn Rutgers where it is "chunked-up" a sent in-world to feed multiple requesting objects which then re-assemble it all so to speak.

On rezzing objects rapidly in-world aka "en-masse"
In order to understand how Monolith works, you need to know the basic architecture of it.  Atoms are represented with individual scripted spherical primitives (prims).  So for a decent sized protein, 3000 atom primitives are used and thus there are 3000 concurrently running scripts.  Monolith is a parallel processing machine.  The next problem is getting 3000 scripted prims into existence.  Enter the LSL function llRezObject.  This function rezzes a singular object, but, there is a 0.1 second sleep delay that is forced when it is called to prevent massive numbers of objects being rezzed which would cause griefing denial of service issues within the Second Life region simulator.  I understand why LL does it, but it does not help people who wish to rez larger number of objects for legitimate purposes.  My first choice for solving this was to use multiple rezzers.   Each rezzer creates objects one at a time and even with the 0.1 second sleep delay, the aggregate rezzing of multiple rezzers would solve the problem.  The first time I tested this algorithm it failed.  I was greeted with numerous "gray goo wall" errors.  WTH, another barrier!  I thought about rezzing complex linked objects since llRezObject rezzes objects not just singular prims.  The problem with this approach is that linking and delinking permissions would be requested by Monolith when it would want to do them.  I found this approach annoying and confusing for the user.  So what to do?  The solution I used was rezzing complex UNLINKED objects.  What's that?  You can select multiple prims that are not linked (or combination of linked and unlinked) and pull them into the inventory as a complex singular non-linked object.  One llRezObject call can rez as many unlinked scripted prims as needed thus avoiding the gray goo wall choke.

On multiple scripted object coordination
The next problem that needed to be solved was the one that using thousands of scripted objects created.  How to coordinate thousands of objects that all use the SAME script (actually thousands of copies of the same script)?  Data is brought in-world over as many as 50 different concurrent http calls into separate objects.  How do we send the data from these objects to the different "smart atoms" to let them know if they are an oxygen, a nitrogen, a carbon, or a hydrogen?  How do we tell the different atoms where they are supposed to be?  Should they be blue? Red? Although all of the atoms run the same script (well copy of the same script), they need their own identity to differentiate themseleves from other atoms.  Some way of being uniquely addressed.  Every object in Second Life gets it's own unique UUID number that could be used for this.  The problem with this is how does the back-end java server know what the the UUIDs are?  One method would be to use llHTTPRequest to send that data out and have each smart atom report it's name to the back-end engine. The problem here is that 3000 smart atoms would send 3000 http calls to the back-end.  I had concerns about scalability and causing issues with the region simulator with that many http calls.  Now it would be simpler if the 3000 atoms could just be named 1, 2, 3, 4, .... 3000.  Then, I would have a way to uniquely address them that would apriori be known to the back-end without having tp send that data.  Two problems now on this, how to get the 1->3000 naming scheme and how to get them to talk to each other (the smart atoms).  On the later, Monolith takes advantage of llListen.  llListen creates a listening function on a set communications channel.  There are about 4 billion potential channels to use.  More than enough.  Each "smart atom" in Monolith has it's own private communication channel, as well as, a global communications channel.  In this fashion, data can be sent to an individual atom and to all atoms at the same time from the primary Monolith object.  But, how do we get them named 1->3000?  One method would be to pre-generate 3000 atoms named 1-3000 (but the same script inside), that then those scripts could reference the name of the object to find out it's node id/name.  The 3000 atoms could be brought into Monolith's inventory as a singular composite object that could be rezzed with a single llRezObject call.  The problem with this is that not all molecules have 3000 atoms, some more, some less.  The maximum number of prims could be used (15,000) and then delete what is not needed.  Would work somewhat, but some regions have other things going on and 15,000 prims not always available, not to mention the lag in creating 15,000 scripted objects needlessly.  The comprimise used solution is this: create a block of 50 smart atoms, named atom1, atom2, atom3...atom50.  Bring the 50 atoms into Monolith's inventory as a singular scripted object and use multiple llRezObject calls to generate as many multiples as needed.  The maximum "waste" prims would be 49.  Acceptable.  But, this method would create multiple groups of 1-50.  So if 10 calls were used to create 500 prims, we would have 10 atom1's, 10, atom2's and so on.  How do we fix this?  llRezObject has a parameter on the end of the function llRezObject( string inventory, vector pos, vector vel, rotation rot, integer param ) called "param".   An integer placed here is passed to the rezz'd object or objects linked or not.  On the first llRezObject we pass a 0, then 1, then 2, and so on up to what is needed.  We then tell each atom that when it rezzes, to reference the part of it's name atom# (# being a # from 1-50) and then adding this number to the product of the the param value times the shard size, in this case 50 (param is the shard # value I pass to the llRezObject function) to determine it's name and identitiy.  We are then left with (1+0*50, 2+0*50, 3+0*50, 4+0*50, 5+0*50, 6+0*50....1+4*50, 2+4*50, 3+4*50) which then yields the desired 1-->3000 sequence but each atom runs the same script, but it's behavior will vary depending on the data sent to it by the http calling objects.  Each line of data brought into Monolith from Rutgers is just a compressed version of the pdb file format.  Each atom in the pdb file is numbered 1->n atoms.  This is used to steer the data when it gets in-world by sending, for example, atom 5's data to communication channel #5.  Atom 5 will get the data since it configures itself to listen on channel 5 because it's name is atom5.  Cute huh? :-)  So atom 5 can be told, you are a nitrogen, you are located at xyz independently.  When global commands like color red atom type nitrogen are sent out, they go over the global channel all atoms listen to.  Each atom, now knowing what it is, can say, "am I a nitrogen? yes?  I will color myself blue.  No? Ignore it".

On Atom Movement
llRezObject can only rez an object no more than 10m away from the calling script.  Since each atom has a script, it can move itself around.  My first reaction was to use llSetPos and move in 10m increments, but it was easier to use llWarpPos and move the atom in one motion.  In my Monolith demostration video, I enable "physics" on a strand of DNA thus collapsing it into a big pile of balls for effect.  Since each atom know it's original location, a single command can disable physics and reposition all atoms back into their original locations thus bringing the DNA back together again.  Useless for molecular visualization, but handy to show how things can be done and it makes my kids laugh.

On the Risks of these methods
LL has been talking about "script limits".  Whereas I do not know what it will ultimately mean, the danger could be if the number of concurrent scripts per region is limited per person.  This could toast any large-scale Monolith visualization or project using these methods.  Whereas I do understand the need in shared "public" regions, private region owners should be able to disable the chokes and caps up to the maximum a region simulator can use.  In other words, if I pay for the whole region, I should be able to use the resources the way I want.  Moore's law gives us more in terms of computation, networking, and such.  Things in this environment should not remain flat for a given flat $$$ amount.

Bringing Monolith to OpenSimulator
Bringing Monolith to OpenSimulator required yanking most of the above out.  The 0.1 second delay on llRezObject can be turned off.  There are no limits on llHTTPRequest.  The code just needed to be simplified and the shard value of 50 was just increased accordingly.  Otherwise, it functions the same.  The trick with non-linked composited objects does not work because it is not yet supported in OpenSimulator.  However, being able to disable sleep on llHTTPRequest in Opensimulator eliminates the need for it.

The Future of Monolith
I've halted development of Monolith in favor of Nexus some time ago.  Nexus swaps out pdb data for Semantic Web RDF data.  Instead of streaming pdb data in-world, rdf triples are streamed.  Nexus will have the ability to visualize far more than just molecules, but will be able to do what Monolith does in a near-future release of Nexus, but it will do it semantically.  It will also be able to access numerous RDF data sources and follow semantically linked data where it goes.  In this fashion, I can do two projects for the price of one and get more in the end.  The first public release of Nexus will be an OpenSimulator region module, followed by a concurrently developed WebGL front-end for WebGL capable browsers, followed by an LSL-version for when installing region modules is not an option.  - E

Tags: 

3D RDF FOAF Graphs in OpenSimulator

Here is an image (click on image for larger image) of a model I did earlier with Nexus in Second Life using Tim Berner-Lee and James Hendler's FOAF data linked and visualized in 3D within OpenSimulator with Nexus.  The only code change needed port it over to OpenSimulator from Second Life was the removal of the warppos function since it is no longer needed, however, I think I may have uncovered a small bug/limitation in OpenSimulator URL lengths.  I put a small work-around by shortening the URL's to the FOAF data to avoid the bug when loading from the remote http source, but I will have to go back and figure out what is actually going on and report it if need be to the OpenSimulator programmers.  The Nexus commands used were:

color <1,0,0> spo where { ?s ?p ?o . filter ( ?p=foaf:knows ) }
color <0,1,0> spo where { ?s ?p ?o . filter ( ?p=rdf:type ) }
color <1,1,1> o where { ?s ?p ?o . filter ( isLiteral(?o) ) }
glow 0.2 o where { ?s ?p ?o . filter ( isLiteral(?o) ) }

Since the last time I did this FOAF data, I changed the default shape for literals to cubes and made them smaller so as not to have the literals dominate the scene as much.  Also added were some glow effects to high-light elements of interest.

Tags: 

Monolith Molecular Visualization in OpenSimulator 0.7.0.2

OpenSimulator is a open-source version of Second Life's server software that emulates much of Second Life's functionality and in some ways, goes beyond it.  Earlier this year, I moth-balled my Monolith project in favor of my Nexus project - it's semantic replacement and then some.  But I decided to visit my old friend Monolith again and wanted to see how difficult it would be to port it to OpenSimulator.

It took a couple of hours to do, but as you can see, it works! :-)  Most of the time I spent on it was removing code that I wrote in Monolith to bypass many of Second Life's, Linden Lab-imposed restrictions, namely:

1) object creation limits 15,000 primitives per region
2) # of calls to llRezObject function (gray goo wall)
3) http call data cap (Linden Lab only allows 2048 bytes per http call)
4) http call rate (the # of http calls in any period per script is also capped)

The speed enhancements were no longer needed since none of the above is limited in OpenSimulator.  The limit on the number of primitives in a region appears to be only limited by the hardware on which the OpenSimulator is executed.  There were some limits in OpenSimulator that prevented a few other tricks I do from working, but I removed these by editing the OpenSimulator.ini file.  Namely, the object movement limit (10M max by default) and the # of llListeners were also limited in OpenSimulator, again, a simple edit to the INI file and they were gone.

My current installation of OpenSimulator is running on Windows XP within a virtual machine using VMware workstation 7.X.  The hardware specifications for the virtual machine are 4 cores and 4GB RAM with a 50GB disk.   The underlying machine is an 4Ghz over-clocked I7 with a RAID-10 disk system.

I will also be porting my Nexus project to OpenSimulator since I am interested in visualizing a huge number of RDF triples far more than the 15,000 primitive limit of Second Life will allow.  I'm looking forward to seeing how far I can push OpenSimulator.

Tags: 

3D RDF Model of RxNorm data

The following is a 3D RDF Model of RxNorm data of drugs (example here) that contain lithium carbonate as an ingredient.  The red balls are the drug products and the greens (difficult to see them in this view, easier to view in 3D) are the various ways lithium carbonate is listed in the RxNorm database.  Predicates rxnorm:ingredient_of and rxnorm:hac_ingredient are colored yellow.  The RxNorm data was converted/maintained by my colleague Dr. Janos Hajagos at Stony Brook University.  He participates in the W3C Linked Open Drug Data group.  The original RxNorm data can be found at:

http://www.nlm.nih.gov/research/umls/rxnorm/

and the RDF version can be found at our SPARQL endpoint/Triple Store (based on Virtuoso) at:

http://link.informatics.stonybrook.edu/sparql/

The data set for this model was constructed with the following RDF query:

prefix rxnorm: <http://link.informatics.stonybrook.edu/rxnorm/>
construct {
  ?aui ?auip ?auio .
  ?auiingred ?auiingredp ?auiingredo . }
where {
<http://link.informatics.stonybrook.edu/rxnorm/RXAUI/2072077> rxnorm:hasRXCUI ?cui .
?aui rxnorm:hasRXCUI ?cui .
?aui ?auip ?auio .
?aui <http://link.informatics.stonybrook.edu/rxnorm/REL#ingredient_of> ?auiingred .
?auiingred ?auiingredp ?auiingredo
}

Nexus to this point, used FOAF data for testing.  I did this model to test with something a bit different.  This model is also a bit more complex and it will help with visualizations in the future as additional visual functions are added, as well as, modifications to the layout engine.

Tags: 

Color 3D RDF FOAF Graphs in Second Life

Added a new command for coloring of the 3D RDF graphs.  It uses the syntax:

color <r,g,b> spo where { pattern }

where:

<r,g,b> is a rgb color vector.  <1,1,0> would be yellow.

spo is either spo, sp, so, po, s, p, o to have the command operate on one of the combinations of subject, predicate, and/or object of the triple.

where { pattern } is borrowed right out of SPARQL's syntax.  Nexus actually uses it's own ontology that is used to describe the visual features of the 3D graph such as {nex:color, nex:alpha, nex:xyz, etc}  All graph data can then be streamed out and include the Nexus ontology for persistence of a visualization session for later viewing or sharing.  In these three graphs, the @timberners_lee and @jahendler FOAF graph data that I have been using as test data are colored by issuing the following two commands:

color <1,0,0> spo where { ?s ?p ?o . filter ( ?p=foaf:knows ) }
color <0,1,0> spo where { ?s ?p ?o . filter ( ?p=rdf:type ) }

The first command colors all foaf:know triples red and the second command colors all triples that are rdf:type green.  The default color for everything is blue <0,0,1>  In the lower right image, the lone green ball is actually foaf:Person.  No, data that can be loaded can be any RDF not just FOAF.  This model is currently on display at the Stony Brook SOM region.  Yes, this is in Second Life, so, bring your friends and look at it together and use IM and voice to discuss it collaboratively while your there.  The region supports up to 100 concurrent users.

Tags: 

Subscribe to Data Visualization