tag:blogger.com,1999:blog-14053187054729344522024-02-06T22:38:54.035-05:00Instanceof IdeaMike Conway's adventures in IT, and other misc ramblings.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.comBlogger126125tag:blogger.com,1999:blog-1405318705472934452.post-67359446920606576182011-07-20T22:38:00.003-04:002011-07-20T22:50:20.297-04:00So that's what happened to WaveI tried Wave, was unimpressed, but felt like it would follow the classic hype curve. At any rate, I'm working on my Masters of Science in Information Science at the School of Information and Library Science. It's a wonderful program, though challenging with family + full time job + music gig. I'm holding it together (but procrastinating on some homework right now).<div><br /></div><div>I am interested in collaborative search and sense-making from back in the day at RENCI when I was looking at <a href="http://instanceofidea.blogspot.com/2009/01/infomesa-and-databases-in-cloud-windows.html">InfoMesa</a>, and recent research in my summer class has me thinking about this again. Many aspects of collaborative search and sense-making were captured in the original intent of <a href="http://code.google.com/apis/wave/">Wave</a>. I never bought that it was a new form of communication, or that it was revolutionary in that respect. What I still think is that it has some aspects of a platform for collaborative search and sense making. I especially like how it can combine time-shifted asynchronous activities with synchronous activities. What's most compelling is to look at what Wave was doing as an application platform. Collaborative search and knowledge discovery could be a great one for Wave.</div><div><br /></div><div>I guess I've been busy working, because I'd hardly noticed that Wave has<a href="http://techcrunch.com/2010/08/04/google-wave-eric-schmidt/"> gone over to Apache</a> as '<a href="http://www.waveprotocol.org/wave-in-a-box">Wave in a Box</a>'. While it appears to be in early incubator stage (they probably don't know what to do with it either), it bears watching.</div>Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-4517888573373726322011-07-19T12:58:00.004-04:002011-07-19T13:01:13.667-04:00Working on releasing Jargon-coreI'm working on a beta release of Jargon core, and all the fun involved in setting up the maven release plug-in for git and Nexus. Needless to say, I've made a few U-turns.<div><br /></div><div>Here's my tip (I'm saving this for myself) on deleting the git tag to tackle some config errors:</div><div><br /></div><div><a href="http://nathanhoad.net/how-to-delete-a-remote-git-tag">http://nathanhoad.net/how-to-delete-a-remote-git-tag</a></div><div><br /></div><div>Thanks Nathan!</div>Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-25212685010445270802011-07-16T09:41:00.003-04:002011-07-16T09:49:11.947-04:00Recent Jargon UpdatesThere's a lot of activity on various types of interfaces, but I wanted to update folks on things at the API level, especially in the jargon-core API.<br /><p><a target="_blank" rel="nofollow" href="http://www.google.com/url?sa=D&q=https://code.renci.org/gf/project/jargon/">https://code.renci.org/gf/project/jargon/</a><br /></p><p>This is late beta, we are working on moving to a schedule of releases, frankly, we need to work out maven and git and the maven release plug-in, there is a lot going on and we're trying to get that done.<br /></p><p>Some highlights:<br /></p><ul><li> The big push has been to put a new public API out that is easier to use and maintain. I think this is shaping up (you can tell me whether that's so). There are plenty of capabilities that have never been exposed outside of the C API that are either in there, or planned.</li><li>There are lots of implementing and testing going on in several places, providing a nice amount of friction to help the API come along. As things settle in, we're starting to be able to shift perspective more to optimization. There are lots more places where buffering is implemented, and baby steps to looking at NIO. With the presence of the RENCI team, we're starting to stand up resources where we could start doing benchmarks to help guide optimization.</li><li>We will be working to pull the jargon-trunk and php code out of the main iRODS trunk into separate areas for the next release. The schedules are pretty tight, so that's still a tentative plan.</li><li>Several key community wish list items are under development, some things that may be of interest are below:<br /></li></ul><p>Configuration, setting options for operations, defaulting<br /></p><p>With the 'clean code' practice of separating code from metadata in mind, there is a jargon.properties file now. This is where config info is being consolidated over time. The IRODSSession object is the place where expensive stuff like loading configuration properties, extensible metadata mappings, and such occurs. You can access the default jargon properties there, or override them. (So in Spring, you can wire in configured properties at startup for your web app, etc).<br /></p><p>When you do transfers, you can call methods like below:<br /><br /></p><pre class="brush:java">/**<br />* Put a file or a collection (recursively) to iRODS. This method allows<br />* registration of a <code>TransferStatusCallbackListener</code> that will<br />* provide callbacks about the status of the transfer suitable for progress<br />* monitoring<br />*<br />* @param sourceFile<br />* <code>File</code> with the source directory or file.<br />* @param targetIrodsFile<br />* {@link org.irods.jargon.core.pub.io.IRODSFile} with the target<br />* iRODS file or collection.<br />* @param transferControlBlock<br />* an optional<br />* {@link org.irods.jargon.core.transfer.TransferControlBlock}<br />* that provides a common object to communicate between the<br />* object requesting the transfer, and the method performing the<br />* transfer. This control block may contain a filter that can be<br />* used to control restarts, and provides a way for the<br />* requesting process to send a cancellation. This may be set to<br />* null if not required.<br />* @throws JargonException<br />*/<br />void putOperation(<br />final File sourceFile,<br />final IRODSFile targetIrodsFile,<br />final TransferStatusCallbackListener transferStatusCallbackListener,<br />final TransferControlBlock transferControlBlock)<br />throws JargonException;<br /></pre><br /><p></p><p>I wanted to point out the 'transferStatusCallbackListener'. You can implement this interface, pass it to the method, and get callbacks like initiation of operation, file transfer update, completion of operation. We are working on also providing a callback for 'messages', like 'starting parallel transfer', or 'computing checksum' so those can start surfacing in UI like iDrop. There are plans soon to provide optional 'intra-file' callbacks, so you could throw up a progress bar for what's going on inside of a file transfer. Look for that soon. Of course, you can leave that null if you don't care.<br /></p><p>The 'transferControlBlock' is important. It is the communication pipeline between the thing calling the transfer, and the transfer itself. You can peek at aggregate numbers, set a cancel flag, etc. The point is, there is now also a transferOptions that can be set. The transfer options can include things like 'no parallel transfers', or 'max transfer threads', or buffer sizes, or things like the recently added 'compute and verify checksum'. You can either set a transfer options in that transfer control block, or leave it alone and defaults will be computed based on the settings in the jargon properties. The checksum validation is in there now (a community request), and the rerouting of gets/puts to the owning resource server should be there soon. The checksum and checksum validation functions were just added<br /></p><p><span style="font-weight: bold;font-size:130%;" >Parallel Transfer Pools</span><br /></p><p>Another community request in the optimization department was to set up a thread pool for parallel transfer threads. This has been done in a first implementation, but turned off by default. This should be handy in mid-tier apps, where you might want to cap the number of threads. More testing needs to be done, is it fixed? What are the time-outs, etc.<br /></p><p><span style="font-weight: bold;font-size:130%;" >GSS/Kerberos, etc</span><br /></p>There are threads here about security, GSS, etc. This is a high-priority item from the user group meeting, and this is next on the list of 'core' development. Folks who are really facile with GSS, Kerberos and the like who have comments and insight are invited to give input. I think once this part is in jargon-core, we can go to a full-on 'release'. The code is pretty solid, much more so than the older API, we're seeing, and will continue to see, performance gains, and it's much easier to use in mid-tier situations, or if you are 'Spring'-happy. Please let me know your experiences, comments, criticisms, and keep an eye out!Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-57805764091839463272011-01-03T19:02:00.002-05:002011-01-03T19:11:01.555-05:00Another undocumented annoyance with testing Grails controllersI switched from rendering JSON in my <a href="http://instanceofidea.blogspot.com/2011/01/testing-grails-controller-getting-thing.html">previous post</a> to using a gsp to format an HTML ul tag based on a model containing my list of results. This is because I find it easier when using JQuery to do my AJAX using HTML content. JQuery seems to natively prefer HTML to JSON, whereas Dojo seemd to run on JSON.<br /><br />At any rate, I changed my controller to something like this:<br /><br /><pre class="brush:java"><br /><br /><br />def loadTree = { <br /> def parent = params['dir']<br /> log.info "loading tree for parent path: ${parent}"<br /> def collectionAndDataObjectListAndSearchAO = irodsAccessObjectFactory.getCollectionAndDataObjectListAndSearchAO(irodsAccount)<br /> def collectionAndDataObjectList = collectionAndDataObjectListAndSearchAO.listDataObjectsAndCollectionsUnderPath(parent)<br /> log.debug("retrieved collectionAndDataObjectList: ${collectionAndDataObjectList}")<br /> render(view:"loadTree",model:[collectionAndDataObjectList:collectionAndDataObjectList, parent:parent])<br /> }<br /></pre><br />I altered my unit test, per the docs, to inspect the model and view. I attempted to get at the model entry for 'parent', which contained the parent dir, like this:<br /><br /><pre><br />def parent = mav.model.parent<br /></pre><br /><br />It turns out that that does not work anymore, instead, you need to interpose a reference to linkedHasMap like so:<br /><br /><pre class="brush:java"><br />void testBrowse() {<br /> controller.params.dir = "/"<br /> controller.irodsAccessObjectFactory = irodsAccessObjectFactory<br /> controller.irodsAccount = irodsAccount<br /> controller.loadTree()<br /> def mav = controller.modelAndView<br /> def name = mav.viewName<br /> assertNotNull("null mav", mav)<br /> assertEquals("view name should be loadTree", "loadTree", name)<br /> def parent = mav.model.linkedHashMap.parent<br /> assertEquals("parent dir not found", "/", parent)<br /> <br /> }<br /><br /></pre><br /><br />Now my Grails controller and test are working again. My next step is to create a decent JavaScript object that can bridge between methods in this BrowseController and a lazy-loadable <a href="http://www.jstree.com/">JQuery JSTree</a>. Maybe the next post can share some developments there.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-7454328706980755322011-01-01T11:59:00.008-05:002011-01-02T20:52:55.191-05:00Testing a Grails Controller - getting the $*&@ thing to workI wanted to post on two things. First, of general interest, I wanted to show how I got a working test on a Grails controller. Second, I wanted to highlight some of the new Jargon API and how it can fit into apps written using Groovy and Grails (this should also translate to Jython and JRuby, as well as other dynamic JVM languages).<br /><br />There is lots of contradictory information on the web, even in the Grails docs, on testing Grails controllers. The biggest issues are understanding the ControllerUnitTestCase, and what it does and does not do.<br /><br />First, here's a controller I'm developing that will back a JQuery JTree component. The first method will take a parent path name, and return a JSON representation of the iRODS file system for the parent path using some new Jargon methods that are meant to assist in Swing and JQuery tree development.<br /><br /><br /><br /><pre class="brush:html"><br /><br />package org.irods.mydrop.controller<br /><br />import org.springframework.security.core.context.SecurityContextHolder;<br />import org.irods.jargon.core.pub.*;<br />import org.irods.jargon.core.connection.*;<br />import org.irods.jargon.core.exception.*;<br />import grails.converters.*<br /><br />/**<br />* Controller for browser functionality<br />* @author Mike Conway - DICE (www.irods.org)<br />*/<br /><br />class BrowseController {<br /><br />IRODSAccessObjectFactory irodsAccessObjectFactory<br />IRODSAccount irodsAccount<br /><br />/**<br />* Interceptor grabs IRODSAccount from the SecurityContextHolder<br />*/<br />def beforeInterceptor = {<br />def irodsAuthentication = SecurityContextHolder.getContext().authentication<br /><br />if (irodsAuthentication == null) {<br /> throw new JargonRuntimeException("no irodsAuthentication in security context!")<br />}<br /><br />irodsAccount = irodsAuthentication.irodsAccount<br />log.debug("retrieved account for request: ${irodsAccount}")<br />}<br /><br /><br />/**<br />* Display initial browser<br />*/<br />def index = { }<br /><br /><br />/**<br />* Render the tree node data for the given parent.<br />* <p><br />* Requires param 'dir' from request to derive parent<br />*<br />*/<br />def loadTree = {<br />def parent = params['dir']<br />log.info "loading tree for parent path: ${parent}"<br />def collectionAndDataObjectListAndSearchAO = irodsAccessObjectFactory.getCollectionAndDataObjectListAndSearchAO(irodsAccount)<br />def collectionAndDataObjectList = collectionAndDataObjectListAndSearchAO.listDataObjectsAndCollectionsUnderPath(parent)<br />log.debug("retrieved collectionAndDataObjectList: ${collectionAndDataObjectList}")<br />render collectionAndDataObjectList as JSON<br /><br />}<br /><br />}<br /><br /><br /><br /></p></pre>A few things to note. The new Jargon libraries are meant to provide simple POJO's that represent various domain objects within iRODS. There also is an idea of Access Objects, that roughly equate with the DAO pattern. iRODS is not a database, so the mapping is not the same, but to me, the idea of Access Objects for iRODS at least gives some comfort in familiarity. One access object I'm developing is meant to assist in tree depictions and searching on file and collection paths to support such elements in typical web and Swing GUI applications. We'll use that Access Object.<br /><br /><br />I've wired in my Spring security objects as described in an<a href="http://instanceofidea.blogspot.com/2010/12/grails-and-spring-security.html"> earlier post</a>. My interceptor in my controller grabs the saved authentication token from the Spring Security layer and extracts the IRODSAccount object. In the loadTree method, this IRODSAccount object is used with a factory injected into my controller to get a CollectionAndDataObjectListAndSearchAO. My controller uses the method that takes a parent path, and returns JSON objects that represent iRODS files and collections under that parent path.<br /><br />The approach taken in Jargon seems to map fairly easily into Grails apps, that's a good sign. This shows that quick development of arbitrary interfaces on top of iRODS will become easier with the newer Jargon libraries. Yay!<br /><br />So, the problems really began with trying to test. First, let me share a working test, then I'll talk about some of the problems I ran into:<br /><br /><br /><pre class="brush:java"><br /><br />package org.irods.mydrop.controller<br /><br /><br />import grails.test.*<br />import java.util.Properties<br />import org.irods.jargon.core.connection.IRODSAccount<br />import org.irods.jargon.core.pub.IRODSAccessObjectFactory<br />import org.irods.jargon.core.pub.IRODSFileSystem;<br />import org.irods.jargon.core.pub.io.IRODSFile<br />import org.irods.jargon.core.query.CollectionAndDataObjectListingEntry<br />import org.irods.jargon.testutils.TestingPropertiesHelper<br />import org.irods.jargon.testutils.filemanip.FileGenerator<br />import org.irods.jargon.testutils.TestingPropertiesHelper<br />import org.irods.jargon.spring.security.IRODSAuthenticationToken;<br />import org.springframework.security.core.context.SecurityContextHolder;<br />import grails.converters.*<br /><br /><br /><br />class BrowseControllerTests extends ControllerUnitTestCase {<br /><br />IRODSAccessObjectFactory irodsAccessObjectFactory<br />IRODSAccount irodsAccount<br />Properties testingProperties<br />TestingPropertiesHelper testingPropertiesHelper<br />IRODSFileSystem irodsFileSystem<br /><br /><br />protected void setUp() {<br />super.setUp()<br />testingPropertiesHelper = new TestingPropertiesHelper()<br />testingProperties = testingPropertiesHelper.getTestProperties()<br />irodsAccount = testingPropertiesHelper.buildIRODSAccountFromTestProperties(testingProperties)<br />irodsFileSystem = IRODSFileSystem.instance()<br />irodsAccessObjectFactory = irodsFileSystem.getIRODSAccessObjectFactory()<br />def irodsAuthentication = new IRODSAuthenticationToken(irodsAccount)<br />SecurityContextHolder.getContext().authentication = irodsAuthentication<br />}<br /><br />protected void tearDown() {<br /> super.tearDown()<br />}<br /><br />void testBrowseNoLogin() {<br />controller.params.dir = "/"<br />controller.irodsAccessObjectFactory = irodsAccessObjectFactory<br />controller.irodsAccount = irodsAccount<br />controller.loadTree()<br />def controllerResponse = controller.response.contentAsString<br />def jsonResult = JSON.parse(controllerResponse)<br />assertNotNull("missing json result", jsonResult)<br /><br />}<br />}<br /><br /></pre><br /><br /><br />One of the first sources of confusion to me were <a href="http://www.grails.org/doc/1.0.x/guide/9.%20Testing.html">documents</a> that seemed to imply that running the grails command create-controller would put the relevant test in the integration tests directory. It didn't, it placed the test in the test/unit directory. Go figure. Maybe I'm missing something, but I'm taking what Grails does at it's word, so to speak. I tried moving the test to the integration test directory, but found that this resulted in the setup methods not running. Fine...I'll just forget this rabbit-hole.<br /><br />Second, I had the hardest time setting up the params. My controller expects a request param of 'dir', with my test specifying the root '/' directory. I kept getting a "No such property: params" error when I tried doing the<br /><br /><pre><br /><br /><br />controller.params.dir = "/"<br /><br /><br /></pre><br /><br /><br />test setup. It turns out that the ControllerUnitTestCase is wanting to wire in and extend your controller for you, creating a 'controller' variable automatically, with the test target controller defined by convention using the test name. So instead of creating my controller in a def using the 'new' keyword, I had to let the ControllerUnitTestCase do it for me.<br /><br />I also ran into the issue of irodsAccount being null. The ControllerUnitTestCase does not run my interceptor for me. I was getting a null irodsAccount, and realized that I had to manually inject that variable in my test code.<br /><br />Well, I was almost home, I kept getting a 'null' for my controller variable in my test case. Doh...I had plugged a bunch of code into setUp() in my test case, and I had to go back and add the super() call in my test case so that ControllerUnitTestCase could do it's magic on the controller variable. So now it works! There's still lots of refactoring I want to do in the controller, and I need to do things like parse and test the actual JSON response, but these are the details to work out now that I can get the stupid test cases to run.<br /><br />Now that's progress...hopefully that will help you avoid some of my own frustrations. Here's to a New Year and new adventures in coding. I think Grails/Groovy feels as immature as most new dynamic scripting languages, but at the same time, I really feel like, combined with the new Jargon libraries, I'm well on my way to a rapid web development stack on top of iRODS. That's a good thing!Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-24498015431438572392010-12-29T12:28:00.008-05:002011-01-03T06:50:23.249-05:00Grails and Spring SecurityI'm developing a personal 'cloud browser' application for iRODS based on my Jargon libraries. Previously, I had started looking at a set of Spring Security libraries that could be used in web apps, such that authentication and gathering of roles could be done against the iRODS security, using iRODS user groups for role based access.<br /><br />My Spring Security library has a custom AuthenticationManager as well as a custom AuthenticationFilter and AuthenticationToken, as iRODS security uses not only user and password, but also zone, resource, host, and port. Because of the differences, I did not find the Spring Security Grails plug-in to be suitable. Besides, since I am already testing a set of custom libraries, I wanted to take advantage of the library and the XML wiring I had already created.<br /><br />First, here's what my XML wiring looks like:<br /><script type="syntaxhighlighter" class="brush:html"><![CDATA[<br /><br /><br /><beans:beans xmlns="http://www.springframework.org/schema/security" beans="http://www.springframework.org/schema/beans" xsi="http://www.w3.org/2001/XMLSchema-instance" schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"><br /><br /> <beans:bean id="irodsConnectionManager" class="org.irods.jargon.core.connection.IRODSSimpleProtocolManager" method="instance"><br /> </beans:bean><br /><br /> <beans:bean id="irodsSession" class="org.irods.jargon.core.connection.IRODSSession" method="instance"><br /> <beans:constructor-arg type="org.irods.jargon.core.connection.IRODSProtocolManager" ref="irodsConnectionManager"><br /> </beans:constructor-arg><br /><br /> <beans:bean id="irodsAccessObjectFactory" class="org.irods.jargon.core.pub.IRODSAccessObjectFactoryImpl"><br /> <beans:constructor-arg ref="irodsSession"></beans:constructor-arg><br /> </beans:bean><br /><br /> <beans:bean id="authenticationManager" class="org.irods.jargon.spring.security.IRODSAccountAuthenticationManager"><br /> <beans:property name="irodsAccessObjectFactory" ref="irodsAccessObjectFactory"></beans:property><br /> </beans:bean><br /><br /> <beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy"><br /> <filter-chain-map type="ant"><br /> <filter-chain pattern="/css/**" filters="none"><br /> <filter-chain pattern="/images/**" filters="none"><br /> <filter-chain pattern="/js/**" filters="none"><br /> <filter-chain pattern="/login/*" filters="none"><br /> <filter-chain pattern="/**" filters="securityContextPersistenceFilter, logoutFilter, authenticationProcessingFilter, exceptionTranslationFilter, filterSecurityInterceptor"><br /> </filter-chain><br /> </filter-chain><br /><br /> <beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor"><br /> <beans:property name="authenticationManager" ref="authenticationManager"><br /> <beans:property name="accessDecisionManager" ref="accessDecisionManager"><br /> <beans:property name="securityMetadataSource"><br /> <filter-security-metadata-source expressions="true"><br /> <intercept-url pattern="/images/**" access="permitAll"><br /> <intercept-url pattern="/css/**" access="permitAll"><br /> <intercept-url pattern="/js/**" access="permitAll"><br /> <intercept-url pattern="/login*" access="permitAll"><br /> <intercept-url pattern="/**" access="isAuthenticated()"><br /><br /> </intercept-url><br /> </intercept-url><br /> </intercept-url><br /><br /> <beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"><br /> <beans:constructor-arg value="/login/login"><br /> <beans:constructor-arg><br /> <beans:list><br /> <beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"><br /> </beans:bean><br /> </beans:list><br /> <beans:property name="filterProcessesUrl" value="/login/logout"><br /> </beans:property><br /><br /> <beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter"><br /> <beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint"><br /> <beans:property name="accessDeniedHandler" ref="accessDeniedHandler"><br /> </beans:property><br /><br /> <beans:bean id="authenticationProcessingFilter" class="org.irods.jargon.spring.security.IRODSAccountAuthenticationFilter"><br /> <beans:property name="authenticationManager" ref="authenticationManager"><br /> <beans:property name="filterProcessesUrl" value="/login/authenticate"><br /> <beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler"><br /> </beans:property><br /><br /> <beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"><br /> <beans:property name="decisionVoters"><br /> <beans:list><br /> <beans:bean class="org.springframework.security.web.access.expression.WebExpressionVoter"><br /> </beans:bean><br /> </beans:list><br /> </beans:property><br /><br /> <beans:bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"><br /> <beans:property name="loginFormUrl" value="/login/login"><br /> </beans:property><br /><br /> <beans:bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl"><br /> <beans:property name="errorPage" value="/login/login"><br /> </beans:property><br /><br /> <beans:bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"><br /> <beans:property name="'securityContextRepository'"><br /> <beans:bean class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"><br /> <beans:property name="'allowSessionCreation'" value="'true'"><br /> </beans:property><br /> </beans:bean><br /> </beans:property><br /><br /> <beans:bean id="authenticationFailureHandler" class="org.irods.jargon.spring.security.IRODSAuthenticationFailureHandler"><br /> <beans:property name="defaultFailureUrl" value="/login/login"><br /> </beans:property><br /></beans:bean></beans:bean></beans:bean></beans:bean></beans:bean></beans:property></beans:property></beans:bean></beans:property></beans:bean></beans:constructor-arg></beans:constructor-arg></beans:bean></intercept-url></intercept-url></filter-security-metadata-source></beans:property></beans:property></beans:property></beans:bean></filter-chain></filter-chain></filter-chain></filter-chain-map></beans:bean></beans:bean></beans:beans>]]></script><br /><br />I had started to re-create this using Spring DSL in my resources.groovy file, but I was finding it difficult to translate (I'm still very new at Spring DSL, and it had more to do with just getting this done).<br /><br />I added my mappings to the resources.xml file in my Grails app, and started things up just to see if Spring could wire this together. Knock me over with a feather but that worked! The one issue I had was a complaint about the Spring Security namespace, which was corrected by adding these items to my BuildConfig.groovy:<br /><br /><br /><pre class="brush:java">dependencies {<br /> // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg.<br /> compile 'org.irods:jargon-core:0.0.3-SNAPSHOT'<br /> compile 'org.irods:jargon-security:0.0.1-SNAPSHOT'<br /> compile 'org.springframework.security:spring-security-core:3.0.5.RELEASE'<br /> compile 'org.springframework.security:spring-security-web:3.0.5.RELEASE'<br /> compile 'org.springframework.security:spring-security-config:3.0.5.RELEASE'<br /> <br /> //test 'org.irods:jargon-test:0.0.1-SNAPSHOT'<br /> // runtime 'mysql:mysql-connector-java:5.1.5'<br /> }</pre>The key was actually the spring-security-config dependency.<br /><br />Next, I started testing with a browser, only to find that the security was not being enforced. The missing step was to add the delegating filter proxy to my web.xml file. Well...what web.xml file? Like I said, I'm very new to Grails. It turns out that I needed to fire up the grails console and do a<br /><br /><blockquote>grails install-templates</blockquote><br /><br />command. This adds templates for various artifacts to my project. Then it's a simple matter of editing the template web.xml file to add my delegating filter proxy mapping like so:<br /><script type="syntaxhighlighter" class="brush:html"><![CDATA[<br /><br /><filter><br /> <filter-name>springSecurityFilterChain</filter-name><br /> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><br /> </filter><br /><br /> <filter-mapping><br /> <filter-name>springSecurityFilterChain</filter-name><br /> <url-pattern>/*</url-pattern><br /> </filter-mapping>]]></script><br /><br />Now, I have not completed all the testing, but it does seem like I'm on the right path. I'll let you all know how it's going, but I think it'll work out.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-37813383530217404202010-12-28T12:11:00.002-05:002010-12-28T12:14:05.535-05:00Fedora 14 running full-screen on Virtual Box for MacA big shout-out to www.sysprobs.com for this entry:<br /><br /><br /><a href="http://www.sysprobs.com/install-fedora-14-virtualbox-working-guest-additions">http://www.sysprobs.com/install-fedora-14-virtualbox-working-guest-additions</a><br /><br />As I was having endless headaches mining the Google for tips on getting Fedora Linux 14 to run in full-screen mode on my Mac using VirtualBox. The missing pieces were some yum updates that had to be run, it's now running beautifully.<br /><br />As is typical, I had to wade through several pages of hits that didn't solve the problem, hopefully this will boost the real solution.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-23091007339583150492010-12-12T08:09:00.003-05:002010-12-12T08:20:06.132-05:00Testing Groovy/Grails with JargonI'm having a great time looking at <a href="http://www.grails.org/">Groovy and Grails</a> as a rapid development environment for <a href="https://www.irods.org/index.php/IRODS:Data_Grids,_Digital_Libraries,_Persistent_Archives,_and_Real-time_Data_Systems">iRODS</a> web interfaces via the new Jargon API I am developing.<br /><br />Jargon is a pure Java API that encapsulates the iRODS server protocol. I am developing a new version, and one of the goals is to make it more usable in Spring-based apps. I have web projects to develop, and at the same time, I need to kick the tires on how Jargon works with dynamic scripting languages. So far, so good. I'm able to wire together some simple things, and utilize the Jargon libraries quite smoothly. Here's a little bit of wiring together of IRODSFileSystem using Spring DSL:<br /><br /><blockquote>beans = {<br /> <br /> irodsFileSystem(org.irods.jargon.core.pub.IRODSFileSystem) {<br /> bean -><br /> bean.factoryMethod = "instance"<br /> bean.singleton = true<br /> }<br /> <br /> <br /> irodsFileServiceWrapperService(mydrop.IrodsFileServiceWrapperService) {<br /> irodsFileSystem = ref("irodsFileSystem")<br /> }<br /> <br /> irodsAuthenticationHelperService(mydrop.IRODSAuthenticationHelperService) {<br /> irodsFileServiceWrapperService = ref("irodsFileServiceWrapperService")<br /> }<br /> <br />}</blockquote><br /><br /><br /><br /><br />Here's a bit of my hacked auth code (I need to see how to more formally wire in Spring Security with Grails:<br /><blockquote><br />IrodsFileServiceWrapperService irodsFileServiceWrapperService<br /><br /> /**<br /> * Validate the user by logging into iRODS under the given credentials. Also retrieve the iRODS user groups for<br /> * use in role-based access<br /> * @param host<br /> * @param port<br /> * @param zone<br /> * @param userName<br /> * @param password<br /> * @param resource<br /> * @return<br /> */<br /> def authenticate(String host, int port, String zone, String userName, String password, String resource) throws AuthenticationException {<br /> def irodsAccount = IRODSAccount.instance(host, port, userName, password, resource, zone, "")<br /> def irodsFileSystem = irodsFileServiceWrapperService.getIrodsFileSystem()<br /> def irodsAccountAuthenticationManager = new IRODSAccountAuthenticationManager()<br /> irodsAccountAuthenticationManager.setIrodsAccessObjectFactory irodsFileSystem.getIRODSAccessObjectFactory()<br /> def irodsAuthentication = new IRODSAuthenticationToken(irodsAccount)<br /> def irodsAuthenticationToken = irodsAccountAuthenticationManager.authenticate(irodsAuthentication)<br /> SecurityContextHolder.getContext().setAuthentication(irodsAuthenticationToken);<br /> }</blockquote><br /><br /><br />I'm certain that this is not the most beautiful Grails code, but it's promising nevertheless.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-38141264248687877592010-10-26T14:13:00.002-04:002010-10-26T14:15:50.311-04:00Peeking at iRODS XML packing instructions using icommandsIn working on the Jargon API, I'm often comparing the protocol operations with icommands. A helpful tip to turn on XML logging of the icommands you are executing:<br /><br />type this at the command prompt before issuing your commands to set some environment variables:<br /><br />export irodsProt=1; export irodsLogLevel=9;Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-71256521657360390062010-10-20T16:26:00.002-04:002010-10-20T16:32:05.763-04:00Hover highlighting for drag and drop in a Swing JTreeThis was a pain in the butt. I am working on a file browser for iRODS that allows easy movement of data from local file system to iRODS resources. I'm implementing drag-and-drop gestures of all sorts, and the Swing JTree is pretty bare-bones, and lacked hover highlighting when dragging.
<br />
<br />I found a very helpful thread <a href="http://www.hbtrel.com/java-swing/16935/">here</a>, pertaining to Swing JTables, but I found it easily adaptable to JTree, adding an alpha background color to the original code. In my subclass of JTree, in which I implement DropTargetListener, I added this
<br />
<br />
<br /><span style="font-family: lucida grande;">class {</span>
<br />
<br /><span style="font-family: lucida grande;"> private int highlightedRow = -1;</span>
<br /><span style="font-family: lucida grande;"> private Rectangle dirtyRegion = null;</span>
<br /><span style="font-family: lucida grande;"> private Color highlightColor = new Color(Color.BLUE.getRed(), Color.BLUE.getGreen(), Color.BLUE.getBlue(), 100);</span>
<br />
<br />
<br /><span style="font-family: lucida grande;">...</span>
<br />
<br />
<br /><span style="font-family: lucida grande;">@Override</span>
<br /><span style="font-family: lucida grande;"> public void dragOver(DropTargetDragEvent dtde) {</span>
<br />
<br /><span style="font-family: lucida grande;"> Point location = dtde.getLocation();</span>
<br /><span style="font-family: lucida grande;"> int closestRow = this.getClosestRowForLocation((int) location.getX(), (int) location.getY());</span>
<br /><span style="font-family: lucida grande;"> boolean highlighted = false;</span>
<br />
<br /><span style="font-family: lucida grande;"> Graphics g = getGraphics();</span>
<br />
<br /><span style="font-family: lucida grande;"> // row changed</span>
<br />
<br /><span style="font-family: lucida grande;"> if (highlightedRow != closestRow) {</span>
<br /><span style="font-family: lucida grande;"> if (null != dirtyRegion) {</span>
<br /><span style="font-family: lucida grande;"> paintImmediately(dirtyRegion);</span>
<br /><span style="font-family: lucida grande;"> }</span>
<br />
<br /><span style="font-family: lucida grande;"> for (int j = 0; j<getrowcount();>
<br /><span style="font-family: lucida grande;"> if (closestRow == j) {</span>
<br />
<br /><span style="font-family: lucida grande;"> Rectangle firstRowRect = getRowBounds(closestRow);</span>
<br /><span style="font-family: lucida grande;"> this.dirtyRegion = firstRowRect;</span>
<br /><span style="font-family: lucida grande;"> g.setColor(highlightColor);</span>
<br />
<br /><span style="font-family: lucida grande;"> g.fillRect((int) dirtyRegion.getX(), (int) dirtyRegion.getY(), (int) dirtyRegion.getWidth(), (int) dirtyRegion.getHeight());</span>
<br /><span style="font-family: lucida grande;"> highlightedRow = closestRow;</span>
<br /><span style="font-family: lucida grande;"> }</span>
<br /><span style="font-family: lucida grande;"> }</span>
<br />
<br /><span style="font-family: lucida grande;"> }</span>
<br />
<br />
<br /><span style="font-family: lucida grande;">...</span>
<br />
<br /><span style="font-family: lucida grande;"> @Override</span>
<br /><span style="font-family: lucida grande;"> public void dragExit(DropTargetEvent dte) {</span>
<br /><span style="font-family: lucida grande;"> if (null != dirtyRegion) {</span>
<br /><span style="font-family: lucida grande;"> paintImmediately(dirtyRegion);</span>
<br /><span style="font-family: lucida grande;"> }</span>
<br /><span style="font-family: lucida grande;"> }</span>
<br />
<br />
<br /><span style="font-family: lucida grande;"> }</span>
<br />
<br /><span style="font-family: lucida grande;">}</span>
<br />
<br />Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-41887240192061212992009-10-14T16:12:00.003-04:002009-10-14T16:18:17.198-04:00Sun VirtualBoxA few quick tips on Sun <a href="http://www.virtualbox.org/">VirtualBox</a>, their open virtualization platform. I'm runing a host with Windows XP, and I want to host some Linux servers for various purposes (more on that later).<br /><br />Anyhow, a few quick hits. First, I installed VirtualBox, and immediately went for Fedora 11 from RedHat. Never could get Fedora to see the virtual drives I had created. I switched from Fedora 11 to the latest version of Ubuntu and it works fine.<br /><br />Second, I was working on creating a shared folder on my Windows host that could be seen by the Linux box, using the provided command:<br /><br /><pre class="screen">mount -t vboxsf [-o OPTIONS] sharename mountpoint<br /><br /><br /></pre>This was returning an error that it did not know about vboxsf as a type. I found that the 'missing' step was, once you install the 'Guest Additions', to issue the following command on your guest Linux server...<br /><br /><span class="kw2">sudo</span> <span class="sy0">/</span>media<span class="sy0">/</span>cdrom<span class="sy0">/</span>VBoxLinuxAdditions-x86.run<br /><br />This will let Ubuntu know about the vboxsf type. <br /><br />I'm liking VirtualBox so far, it appears to be a useful tool in the toolbox.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-20462901520246349202009-07-08T06:48:00.002-04:002009-07-08T07:03:59.905-04:00Google Chrome OS?Since forever in web time the chatter has been about a new 'web OS' from Google. With the advent of rich internet applications in the form of GMail, Google Documents, Calendar, etc we're seeing the migration of information to the web, followed by the migration of the application to the web as a service.<br /><br />Look at the information habits of people around you, we're relying on portable devices to access the bits of information relevant to time and space, and taking much smaller bites out of the apple..search for a gas station with the lowest price, find the number to a good plumber, send a text message to the baby-sitter. It only makes sense to re-think the relationship of all of these types of applications to the traditional desktop or laptop, or at least Google thinks so..<br /><br />From<a href="http://googleblog.blogspot.com/2009/07/introducing-google-chrome-os.html"> Google</a>...<br /><br /><span style="font-style: italic;">So today, we're announcing a new project that's a natural extension of Google Chrome — the Google Chrome Operating System. It's our attempt to re-think what operating systems should be.</span><br /><br />The Chrome OS is targeted first towards small notebooks (and probably tablets?) The post makes it clear that ChromeOS and <a href="http://code.google.com/android/">Android </a>are separate concerns, though a good deal of overlap is acknowledged. Certainly the services that would be consumed by Android are the same services that a typical 'notebook' computer would want, and many of us would treat a notebook and smart phone as interchangable for many tasks. <br /><br />Intermittantly connected (a-la <a href="http://gears.google.com/">Gears</a>) rich internet applications will be a key application delivery mode, whether in the form of widgets, or in full-blown browser-based applications. Combine this with a growing number of cloud services running on big grids, and maybe a web OS makes sense?Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-82156439076322135692009-06-08T20:23:00.005-04:002009-06-08T20:36:48.771-04:00Note to self...I just wasted a few minutes on the obvious...Working on a JavaScript with Dojo, going through the excellent Mastering Dojo book from the Pragmatic Programmers.<br /><br />I'm working on the script, and looking at this bit of code:<br /><br /><span style="color: rgb(0, 153, 0);">dojo.addOnLoad(function() {</span><br /><span style="color: rgb(0, 153, 0);"> dojo.connect(dojo.byId("qform"), "submit", function(e){</span><br /><span style="color: rgb(0, 153, 0);"> //stop default processing and propagation</span><br /><span style="color: rgb(0, 153, 0);"> //(we really don't want to submit the form)</span><br /><span style="color: rgb(0, 153, 0);"> dojo.stopEvent(e);</span><br /><span style="color: rgb(0, 153, 0);"> </span><br /><span style="color: rgb(0, 153, 0);"> //erase any previous borders...</span><br /><span style="color: rgb(0, 153, 0);"> dojo.query("*", "fixture").style("border", "");</span><br /><span style="color: rgb(0, 153, 0);"> </span><br /><span style="color: rgb(0, 153, 0);"> //set all elements found by the query to have a red border...</span><br /><span style="color: rgb(0, 153, 0);"> var query= dojo.byId("query").value;</span><br /><span style="color: rgb(0, 153, 0);"> dojo.query(query, "fixture").style("border", "2px solid red");</span><br /><span style="color: rgb(0, 153, 0);"> });</span><br /><span style="color: rgb(0, 153, 0);"> });</span><br /><br />The error I'm getting is in the 'addOnLoad' method, with a "dojo not defined" error. Looking further up, I indeed have my dojo root specified.<br /><br />See the problem? Of course not, because there is not a problem with this code. I was looking at the code (mismatched parens? missing semi-colon) when the issue was that I had retrieved the page by putting the file name in the browser, instead of the the http URL, so my code was not being served by my Apache server, therefore making it impossible to find the dojo code. Switch to an http url, and it works like a charm.<br /><br />Someone is going to make the same mistake, and it's an object lesson (no pun intended) that sometimes there IS a simple solution, but that solution is often overlooked. I hope to save you a few minutes scratching your head.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-45820248414408063312009-06-05T19:47:00.003-04:002009-06-05T19:49:20.986-04:00Come into my officeThis is just a bit of fun....click <a href="http://unc.renci.org/rencinews/take-a-stroll-around-the-social-computing-room">here</a> to read about my 'office' and visit it via the Unity browser plug-in! Good weekend to all.<br /><br />While I'm pimping...here's my 'other life', my band <a href="http://www.goodrockingsam.com/">Good Rocking Sam</a>.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-32751649205279745562009-06-01T08:06:00.005-04:002009-06-01T08:34:19.957-04:00UpdatesHere's a quick rundown of projects, and some of the technologies I'm working with..<br /><br /><span style="font-weight: bold;">The </span><a style="font-weight: bold;" href="http://unc.renci.org/resources/visualization-resources/social-computing-room">Social Computing Room</a><span style="font-weight: bold;"> at RENCI has been busy...</span><ul><li>I'm working on a new media projects that uses <a href="http://www.cycling74.com/products/max5">Max/MSP/Jitter</a> to create MIDI music using tangible objects with embedded UbiSense tags as the 'instrument'.<br /></li><li>I'm working on installing a very cool Flash/Flex based media project that uses all four surfaces of the Social Computing Room. This work has been installed elsewhere, so it's an adaptation. It really looks cool! This has allowed me to learn a bit more about Flash and Flex. As a programmer, I 'get' Flex much better than I get Flash.</li><li>I'm working on a virtual worlds project, utilizing a <a href="http://unc.renci.org/rencinews/virtual-court-in-the-social-computing-room">360-degree Second Life client to stage mock trials</a>.</li></ul><span style="font-weight: bold;">I'm still looking at the </span><a style="font-weight: bold;" href="http://sambbiblog.spaces.live.com/blog/cns%21794708049C7AE9C2%211164.entry">InfoMesa technology demonstrator</a><span style="font-weight: bold;">, and building an application based on WPF technology for the large display environment in the Social Computing Room.</span><br /><br />I've been working mostly on the back-end, creating a services layer for storing metadata (the part I'm working on now) and for accessing arbitrary data stores based on the metadata. The metadata service layer is pluggable by interface, and my first implementation uses <a href="https://www.hibernate.org/343.html">NHibernate</a> to store metadata on a back end server. Once this done, that metadata layer can have pluggable modules for things like cloud databases.<br /><br />For the pluggable data stores, the first stores will probably be a mounted file system, then a database, then an <a href="https://www.irods.org/index.php/IRODS:Data_Grids%2C_Digital_Libraries%2C_Persistent_Archives%2C_and_Real-time_Data_Systems">iRods </a>repository. After this, in order, it will probably be http, ftp, then cloud databases.<br /><br />The Social Computing Room will be integrating a<a href="http://vis.renci.org/multitouch/"> multi-touch</a> table later in the summer, and therefore I'm kicking some of the user interface stuff down the road. I want to allow folks to sit at the multi-touch table and interact with arbitrary data stores, manipulating on the touch table, and viewing on the 360-degree display. This would be soooooo cool.<br /><br /><span style="font-weight: bold;">Serious Games</span><br /><br />I'm learning about the <a href="http://unity3d.com/">Unity3d</a> game engine in my 'spare cycles'. <a href="http://unc.renci.org/rencinews/serious-gaming-and-simulation-at-renciunc"> We've ported a few Unity projects to the dome, and blogged about it</a>.<br /><br />Lots of things going on, as you can see. Main technologies I've worked with in the last two months:<br /><br /><ul><li>.Net, C#, WPF</li><li>Java, including some Jetty work, and some socket stuff.</li><li>Max/MSP patches</li><li>Flex and Flash development</li><li>Wordpress and a bit of PHP</li><li>Quicktime Streaming Server and Quicktime Broadcaster</li><li>Unity3D</li><li>Second Life building and LSL scripting.</li></ul>This is why I like my job...now I busted some solder joints Friday doing some testing, so I've got to play with a soldering iron.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-58561623138942219842009-01-29T12:52:00.004-05:002009-01-29T15:39:19.770-05:00Sitting on Top of the (virtual) worldWith apologies to Howling Wolf, Here's a pic we took in the Social Computing Room yesterday. It's showing an adaptation of the Second Life client that provides a 360-degree view of the virtual world. The development work on the SL client was done by a colleague, David Borland.<br /><br />The idea is to embed the Social Computing Room within a larger virtual space, so that you can look out in every direction to see what is happening in the virtual world. In the pic below, I'm in the SCR looking at my avatar...<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgM8LYqluxFbWGLRX6u20QYpOqTfw00DgDB9tDwyNjpldG9O6t6n6QGtiBYJLQp7N7XWMRjzK6lwn_XDKapdwRCAMI_dRAIJEG3FHDVKixzXuKFfhLilgrnzyc4pTDz9oj7jl6pCTW1VhY/s1600-h/IMG_0497.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgM8LYqluxFbWGLRX6u20QYpOqTfw00DgDB9tDwyNjpldG9O6t6n6QGtiBYJLQp7N7XWMRjzK6lwn_XDKapdwRCAMI_dRAIJEG3FHDVKixzXuKFfhLilgrnzyc4pTDz9oj7jl6pCTW1VhY/s320/IMG_0497.JPG" alt="" id="BLOGGER_PHOTO_ID_5296813973901440082" border="0" /></a><br /><br />How about looking in? We have video cameras from all angles, so I thought about building a 'fish tank' from the SL perspective so that avatars can walk around the SCR and see inside of it. The bread and butter of two-way audio and video, along with text chat is the obvious next step. Here's a shot from SL looking into the Social Computing Room...<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2kHFjuHOpqsMYCeJ45Y1nnGzHexAstUHQ5b1EOOioqJ5f2LbbdkOR1kPE6T-lPRx8oc1XtJDeBwIjjX_UjdZaVZ-3S2TJcbmwfcSG3t8pHRW03STtou7eXgMZwpVmEdDCUrUouU39wA4/s1600-h/Snapshot_001.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 187px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2kHFjuHOpqsMYCeJ45Y1nnGzHexAstUHQ5b1EOOioqJ5f2LbbdkOR1kPE6T-lPRx8oc1XtJDeBwIjjX_UjdZaVZ-3S2TJcbmwfcSG3t8pHRW03STtou7eXgMZwpVmEdDCUrUouU39wA4/s320/Snapshot_001.jpg" alt="" id="BLOGGER_PHOTO_ID_5296817042562830946" border="0" /></a><br />Right now it's just a bare media object, and one interesting question I have is what to build on the virtual side? Do I want to mirror the room, or perhaps the SCR could be sitting on the bottom of the sea? Once the basics are tackled, the SCR and the 4-channel Second Life client make for a unique research space. The SCR is well suited for installation of all sorts of sensors, robotics, and input devices. This is something of a side project, but I've noted how intrigued people are when they visit the SCR and see the first prototypes!Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com1tag:blogger.com,1999:blog-1405318705472934452.post-48385336754240151372009-01-28T16:14:00.004-05:002009-01-28T16:26:23.657-05:00The world of mobile sensorsI've been sharing around a<a href="http://www.research.nokia.com/files/insight/NTI_Sensing_-_Dec_2008.pdf"> white paper by Nokia</a> that considers the mobile phone as a sensor. The key point:<br /><br /><span style="font-style: italic;">As mobile device subscriptions pass the four billion mark, we’re looking at</span><br /><span style="font-style: italic;">the world’s most distributed and pervasive sensing instrument. Thanks to an increasing number of built-in sensors—ambient light, orientation, acoustical, video, velocity, GPS—each device can capture, classify, and transmit many types</span><br /><span style="font-style: italic;">of data with exceptional granularity. The perfect platform for sensing the world</span><br /><span style="font-style: italic;">is already in our hands.</span><br /><br />Well, here's a cool example, from <a href="http://www.openspime.com/2009/01/25/widenoise-to-let-all-familiarize-with-the-concept-of-spimes/">OpenSpime</a>, <a href="http://www.widetag.com/widenoise/">WideNoise </a>is an iPhone application that uses the microphone on the iPhone to measure environmental noise. These geo-tagged reports can then be used to create a noise map.<br /><br />Rewind a bit, 'Spime' is an abbreviate of 'space' + 'time'. A Spime is defined by OpenSpime as: <span style="font-style: italic;">a technologically enabled device that interacts both with the physical and the digital environment, aware of its location and with an history about itself.</span> OpenSpime is working to create a Jabber/XMPP protocol that allows Spimes to report information about themselves, and has a<a href="http://code.google.com/p/pyopenspime/"> set of python libraries in development</a> as a first project.<br /><br />A handful of threads that really are woven together...Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-37774978121528387192009-01-16T13:06:00.001-05:002009-01-16T13:07:52.046-05:00Renci featured in Endeavors MagazineCool article on Renci and the power of visualization...in Endeavors Magazine right <a href="http://research.unc.edu/endeavors/win2009/lets_get_visual.php">here</a>.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-52023421863777620172009-01-15T08:38:00.000-05:002009-01-15T08:38:41.699-05:00InfoMesa and Databases in the Cloud - Windows LiveInfoMesa is a technology demonstrator from Microsoft Life Sciences that I've blogged about <a href="http://instanceofidea.blogspot.com/2008/10/adapting-infomesa-to-social-computing.html">previously</a>. I've been working (as time permits) on two tracks. <br /><br />First, I've forked the code to investigate how the interactive whiteboard/electronic research notebook would work in an environment like the Social Computing Room. I've already had some interesting results, and the product of that work is in actual use by researchers in day-to-day work. The main departure in this case is turning the interface 'inside out', essentially creating a 12,288x768 workspace, while migrating all of the other interface items into context menus. In the SCR port, there's more concern with laying out content around the room than having a free-flowing scrollable palate. Essentially, I'm trying to put this fork 'out there', and then asking researchers what sorts of tools they would like. I'm incrementally porting InfoMesa features to this environment as I can, and am especially keen on adding annotation features.<br /><br />This brings me to the second track, which is looking at the 'cloud' as the source of data. In this way, InfoMesa becomes a 'browser' of sorts. The InfoMesa database becomes a link repository, a tagging service, and an annotation service. The whiteboards are composed of objects that may exist outside of the InfoMesa metadata repository. The data may be in a database, may be a resource on the web, identified by a URI, or may be stored in a cloud database, such as SQL Data Services in <a href="http://www.microsoft.com/azure/default.mspx">Microsoft Azure</a>, or<a href="http://aws.amazon.com/s3/"> Amazon S3</a>. The InfoMesa blog has some interesting demonstrations of porting the whiteboard metadata to Azure in the post <a href="http://sambbiblog.spaces.live.com/blog/cns%21794708049C7AE9C2%212060.entry">InfoMesa and Databases in the Cloud - Windows Live.</a><br /><br />I think the cloud data idea is useful, making whiteboards accessible anywhere. What I think is potentially more interesting is to think of InfoMesa as a resource browser and annotation platform, and looking at creating pluggable hooks in InfoMesa to be able to retrieve whiteboard objects from different locations, such as the above mentioned cloud data services. Questions to answer include designing such a pluggable architecture, laying out the metadata schema that would be able to store and properly access data in the cloud, and defining the security layer such that a whiteboard can acess data with proper security. <br /><br />The ability to store and annotate data in these views has other interesting benefits, including 'wall-to-wall' collaboration. I imagine augmenting collaboration sessions with video conferencing between two visualization environments, where some ability to synchronize whiteboards brings remote parties together. I also am interested in the more pragmatic ability to allow a researcher to design a whiteboard that represents the agenda for a research group meeting at their desktop, and be able to walk up to a visualization wall, or an environment like the SCR, and have their data appear, ready to go. Think if this as a more fluid way of developing a presentation, where sequences of slides are less useful than a free-flowing group interaction with imagery, video, and other types of visual data. <br /><br />You can see that the potential is endless. I'm trying to keep it focused on practical use, making working in the SCR a productive and fun experience.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-11219191724907346522009-01-07T10:46:00.000-05:002009-01-07T10:50:44.779-05:00Working on a blog/website for Renci@UNCI'm working on a Wordpress based website and blog for the Renci@UNC engagement center. I've added a Flickr photostream...well at least a start, which should be visible on my blog. I'm using a Wordpress plug-in (<a href="http://www.growlingranger.com/flickrbox/">FlickrBox</a>) to incorporate this into the new Renci@UNC site.<br /><br />Lots of cool stuff to talk about, alas, a bit busy actually doing the stuff to blog about it, but will soon (New Year's resolution). Anyhow, back from the Holidays, and glad to be into it again!Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-87087167660551869422008-12-04T11:15:00.000-05:002008-12-04T11:25:37.175-05:00Vid from Supercomputing 08Here's some <a href="http://www.renci.org/sc08/video/">Renci Vid from SC08</a>, showing some of the technology in the Renci booth. As stated before, I'd love to put a touch table in as a centerpiece to the <a href="http://instanceofidea.blogspot.com/2008/11/bit-about-social-computing-room.html">Social Computing Room</a>, and have multi-touch applications that interact with the 360-degree viz display. This idea meshes well with the ideas demonstrated by <a href="http://instanceofidea.blogspot.com/2008/10/adapting-infomesa-to-social-computing.html">InfoMesa</a>.<br /><br />Also cool to note is the HoloPanel that can be seen in the corner of the booth. A pair of these was used in the Social Computing Room as a part of the <a href="http://comm.unc.edu/newsevents/productionevent">Spectacular Justice</a> installation, and they were stunning!<br /><br />All that said, really this is just to share some cool technology. I'm lucky to work with such smart and resourceful people at Renci.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-65845387978130732992008-11-17T06:52:00.001-05:002008-11-17T08:22:53.461-05:00Renci Multi-Touch blogHere's the<a href="http://vis.renci.org/multitouch/"> multi-touch blog</a> from Renci. There are two form factors that Renci is working with, a large <a href="http://vis.renci.org/multitouch/?cat=5">multi-touch wall at Duke</a>, and a <a href="http://vis.renci.org/multitouch/?p=164">horizontal touch-table</a> at Europa.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://vis.renci.org/multitouch/wp-content/themes/daleri-dark-10/img/front.jpg"><img style="cursor: pointer; width: 356px; height: 74px;" src="http://vis.renci.org/multitouch/wp-content/themes/daleri-dark-10/img/front.jpg" alt="" border="0" /></a><br /><br /><br />My hope is that a touch-table will grace the <a href="http://instanceofidea.blogspot.com/2008/11/bit-about-social-computing-room.html">Social Computer Room</a>. A long-term vision would be to extend our <a href="http://instanceofidea.blogspot.com/2008/10/adapting-infomesa-to-social-computing.html">Collage/InfoMesa ideas</a> in the SCR, using the 360-degree display to provide visual real estate. Imagine a group working around a touch table, shooting images out to the 360-degree wall with gestures on the touch table.Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-27347161939218074612008-11-13T09:39:00.000-05:002008-11-13T10:51:25.164-05:00Putting Google Earth into a WPF windowThis may end up being fruitless, but I was inspired by this <a href="http://channel9.msdn.com/posts/briankel/PDC2008-ShowOff-Entry-Multi-channel-Virtual-Earth/">multi-channel version of Microsoft Virtual Earth</a>. It looks like they linked multiple version of Virtual Earth with different camera settings, and I wanted to try something similar with Google Earth for our Global Immersion dome. This four-projector rig needs a viewport and four camera views to work right. Can I create a full-screen app that has these four viewports, and have four synchronized version of Google Earth running? I don't know, but the first step was to see if I could create a WPF app that had Google Earth embedded in the WPF window. You can at least do that, and that's interesting in itself, because I can add a Google Earth widget to my <a href="http://instanceofidea.blogspot.com/2008/10/adapting-infomesa-to-social-computing.html">InfoMesa/Collage experiments</a> described here...<br /><br />Anyhow, here's the window in all its (yawn) glory:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIwVkY1QBXwNeMBf4ge9fysf5GsvMKDEZ6SGEb0RDCd0q2ZjiYG7lMo7by2AtaKHN3TpI8sBOsF1QjYtXncEWiidt1eO1Te-zq2tRKXbbG_WncNt0cTV13obgaIRyUGwb1D5XaQs8Z00s/s1600-h/ge_in_wpf.jpg"><img style="cursor: pointer; width: 320px; height: 240px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIwVkY1QBXwNeMBf4ge9fysf5GsvMKDEZ6SGEb0RDCd0q2ZjiYG7lMo7by2AtaKHN3TpI8sBOsF1QjYtXncEWiidt1eO1Te-zq2tRKXbbG_WncNt0cTV13obgaIRyUGwb1D5XaQs8Z00s/s320/ge_in_wpf.jpg" alt="" id="BLOGGER_PHOTO_ID_5268153232830034306" border="0" /></a><br /><br />It was a bit of a slog to get it right, and I'll share the code that worked. First, I had to get Google Earth, which gives you this <a href="http://earth.google.com/comapi/index.html">COM SDK</a>. I did this using C#, Vis Studio 2008. I added a project ref to the COM Google Earth library, and created a class that extended HwndHost.<br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Collections.Generic;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Linq;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Text;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows.Controls;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows.Data;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows.Documents;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows.Input;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows.Media;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows.Media.Imaging;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows.Navigation;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows.Shapes;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Windows.Interop;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using System.Runtime.InteropServices;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >using EARTHLib;</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >namespace GeTest</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >{</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > class MyHwndHost : HwndHost</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > {</span><br /><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > [DllImport("user32.dll")]</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static extern int SetParent(int hWndChild, int hWndParent);</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > IApplicationGE iGeApp;</span><br /><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > [DllImport("user32.dll", EntryPoint = "GetDC")]</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > public static extern IntPtr GetDC(IntPtr ptr);</span><br /><br /><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > [DllImport("user32.dll", EntryPoint = "GetWindowDC")]</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > public static extern IntPtr GetWindowDC(Int32 ptr);</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > [DllImport("user32.dll", EntryPoint = "IsChild")]</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > public static extern bool IsChild(int hWndParent, int hwnd);</span><br /><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > [DllImport("user32.dll", EntryPoint = "ReleaseDC")]</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > [DllImport("user32.dll", CharSet = CharSet.Auto)]</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > public extern static bool SetWindowPos(int hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > [DllImport("user32.dll", CharSet = CharSet.Auto)]</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > public static extern IntPtr PostMessage(int hWnd, int msg, int wParam, int lParam);</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > //PInvoke declarations</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > [DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Auto)]</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > internal static extern IntPtr CreateWindowEx(int dwExStyle,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > string lpszClassName,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > string lpszWindowName,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > int style,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > int x, int y,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > int width, int height,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > IntPtr hwndParent,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > IntPtr hMenu,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > IntPtr hInst,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > [MarshalAs(UnmanagedType.AsAny)] object pvParam);</span><br /><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > readonly IntPtr HWND_BOTTOM = new IntPtr(1);</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > readonly IntPtr HWND_TOP = new IntPtr(0);</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > readonly IntPtr HWND_TOPMOST = new IntPtr(-1);</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_NOSIZE = 1;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_NOMOVE = 2;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_NOZORDER = 4;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_NOREDRAW = 8;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_NOACTIVATE = 16;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_FRAMECHANGED = 32;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_SHOWWINDOW = 64;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_HIDEWINDOW = 128;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_NOCOPYBITS = 256;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_NOOWNERZORDER = 512;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly UInt32 SWP_NOSENDCHANGING = 1024;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly Int32 WM_CLOSE = 0xF060;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > static readonly Int32 WM_QUIT = 0x0012;</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > private IntPtr GEHrender = (IntPtr)0;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > private IntPtr GEParentHrender = (IntPtr)0;</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > internal const int</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > WS_CHILD = 0x40000000,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > WS_VISIBLE = 0x10000000,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > LBS_NOTIFY = 0x00000001,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > HOST_ID = 0x00000002,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > LISTBOX_ID = 0x00000001,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > WS_VSCROLL = 0x00200000,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > WS_BORDER = 0x00800000;</span><br /><br /><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > public ApplicationGEClass googleEarth;</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > protected override HandleRef BuildWindowCore(HandleRef hwndParent)</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > {</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > // start google earth</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > googleEarth = new ApplicationGEClass();</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > int ge = googleEarth.GetRenderHwnd();</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > IntPtr hwndControl = IntPtr.Zero;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > IntPtr hwndHost = IntPtr.Zero;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > int hostHeight = 200;</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > int hostWidth = 300;</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > // create a host window that is a child of this HwndHost. I'll plug this HwndHost class as a child of</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > // a border element in my WPF app, </span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > hwndHost = CreateWindowEx(0, "static", "",</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > WS_CHILD | WS_VISIBLE,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > 0, 0,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > hostHeight, hostWidth,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > hwndParent.Handle,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > (IntPtr)HOST_ID,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > IntPtr.Zero,</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > 0);</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > </span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > // set the parent of the Google Earth window to be the host I created here</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > int oldPar = SetParent(ge, (int) hwndHost);</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > // check to see if I'm now a child, for my own amusement</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > if (IsChild(hwndHost.ToInt32(), ge)) {</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > System.Console.WriteLine("now a child");</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > }</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > </span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > // return a ref to the hwndHost, which should now be the parent of the google earth window</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > return new HandleRef(this, hwndHost);</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > }</span><br /><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > protected override void DestroyWindowCore(HandleRef hwnd)</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > {</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > throw new NotImplementedException();</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > }</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" > }</span><br /><span style="color: rgb(102, 51, 255);font-family:courier new;" >}</span><br /><br /><br /><br />The main window of my WPF app, in its constructor for the Window, just plugs this HwndHost as a child of a Border control:<br /><br /><span style="color: rgb(102, 0, 204);font-family:verdana;" > public Window1()</span><br /><span style="color: rgb(102, 0, 204);font-family:verdana;" > {</span><br /><br /><span style="color: rgb(102, 0, 204);font-family:verdana;" > InitializeComponent();</span><br /><span style="color: rgb(102, 0, 204);font-family:verdana;" > MyHwndHost hwndHost = new MyHwndHost();</span><br /><span style="color: rgb(102, 0, 204);font-family:verdana;" > border1.Child = hwndHost;</span><br /><span style="color: rgb(102, 0, 204);font-family:verdana;" > </span><br /><br /><span style="color: rgb(102, 0, 204);font-family:verdana;" > }</span><br /><br /><br />And you are off to the races! I found a lot of different approaches to this all over the web, but none of them seemed to work, as is often the case. Maybe this will work for you, or maybe it adds to the confusion.<br /><br />UPDATE: can't run more than one Google Earth, so it's a bust, but still has use in my InfoMesa/Collage project. I wonder about Virtual Earth?Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com1tag:blogger.com,1999:blog-1405318705472934452.post-59214268981250275562008-11-12T14:50:00.001-05:002008-11-12T16:38:39.925-05:00Video for Ubisense/MIDI demoHere's the video that <a href="http://instanceofidea.blogspot.com/2008/11/music-and-media-in-scr.html">was described in this post</a>. The point of this experiment was to see if we could reasonably map carpet squares in the<a href="http://instanceofidea.blogspot.com/2008/11/bit-about-social-computing-room.html"> Social Computing Room</a> to MIDI notes, and output those notes to the on-board MIDI implementation.<br /><br /><br /><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dyFaBdmO5QYHEDp1vg1WZgDQWOnILO4kYI-P6Cpl9EoVzI3BaMSecN8L-_dKo7YH-kD20Asly2nOlJ9I03o9g' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br /><br />Oh well...off to a Games4Learning event...see ya there!Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0tag:blogger.com,1999:blog-1405318705472934452.post-42372853838274708592008-11-10T08:00:00.000-05:002008-11-10T09:01:45.488-05:00A bit about the Social Computing RoomIn<a href="http://instanceofidea.blogspot.com/2008/11/music-and-media-in-scr.html"> the last blog entry</a>, I had put down a spot to link to a description of the 'Social Computing Room', and realized that I didn't have one. So I wanted to fill in a few details and fix that link.<br /><br />The Social Computing Room, (or SCR for short) is a visualization space at the <a href="http://www.renci.org/">Renci </a>Engagement Center at <a href="http://www.renci.org/resources/viz/unc.php">UNC Chapel Hill</a>. We're over near the hospital in the <a href="http://its.unc.edu/about-its/its-manning.html">ITS-Manning</a> building in Chapel Hill. It's one of three spaces, the other being the Showcase Dome (a 5-meter tilted Global Immersion dome), and Teleimmersion, which is a 4K (4 x HD resolution) stereo environment. We're working on some virtual tours for a new web site, so there should be some more info soon on those other spaces.<br /><br />One of the primary features of the SCR is its 360-degree display. The room is essentially a 12,288x768 Windows desktop. (I've also tested a Mac in this environment, and it works as well). Here's a pic of the SCR...<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizrOs2BT0kEXidmsVrtQEcG_O6uuJ8VMK4d4wk_j_3TfD4MUq0Y4DRdpVt7gT9H5XvvpKqelwMkglqNNvH9bCGWELhFWUxVdST-BU7aDrULysq8AvwgzwUoyPDHU6zaG20kJU36szVMzs/s1600-h/social_comp18.jpg"><img style="cursor: pointer; width: 400px; height: 266px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizrOs2BT0kEXidmsVrtQEcG_O6uuJ8VMK4d4wk_j_3TfD4MUq0Y4DRdpVt7gT9H5XvvpKqelwMkglqNNvH9bCGWELhFWUxVdST-BU7aDrULysq8AvwgzwUoyPDHU6zaG20kJU36szVMzs/s400/social_comp18.jpg" alt="" id="BLOGGER_PHOTO_ID_5267023120616014578" border="0" /></a><br /><br />The room has multiple cameras, wireless mics, multi-channel sound, 3D location tracking for people and objects, and is ultra-configurable (plenty of cat-6 for connecting things, Unistrut ceiling for adding new hardware). The room has so many possibilities that it gets difficult to keep up with all of the ideas. I think of it as a place where you can paint the walls with software, and make it into anything you want. There are currently a few emerging themes:<br /><br /><ul><li>The SCR is a collaborative visualization space. The room seems especially suited for groups considering a lot of information, doing comparison, interperetation, and grouping. There is a lot of visual real estate, and the four-wall arrangement seems to lend itself to spatial organization of data. As groups use the space for this purpose, I'm trying to capture how they work, and what they need. The goal is to create a seemless experience for collaboration. This is the reason I've been interested in WPF, and the InfoMesa technology demonstrator,<a href="http://instanceofidea.blogspot.com/2008/10/adapting-infomesa-to-social-computing.html"> as covered in this previous post</a>.</li><li>The SCR is a new media space. Its been used for art installations, and it has interesting possibilities for all sorts of interactive experiences, as illustrated by <a href="http://instanceofidea.blogspot.com/2008/11/music-and-media-in-scr.html">this recent experiment</a>.<br /></li><li>The SCR is a place for interacting with the virtual world. We're working on a Second Life client that would have a 360-degree perspective, so that we can embed the SCR inside of a larger virtual enviroment, enabling all sorts of new possibilities.</li></ul>These are just a few of the areas I'm interested in. Each of the areas can be enhanced by the use of different types of sensors and robotics, and I've been started with Wiimotes, SunSpots, and the Ubisense location tracking hardware.<br /><br />That's a bit about the SCR, it's a really fascinating environment, and if you are on the UNC campus, give me a shout out and I'll show you around!<br /><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbITrqycBXpyPJedmSC1wqBimZdNrin6GWGUstN3l6KpRitNQgtnoMO1FK2LNP0yXOf0fDehjjtRKcfSxYEzg9RN6PmNrV-Kpl1STGC6BVabT1ocrYYdsPQasdNIVJUAF0HyfS8L6EdVM/s1600-h/scr_sl.JPG"><img style="cursor: pointer; width: 400px; height: 265px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbITrqycBXpyPJedmSC1wqBimZdNrin6GWGUstN3l6KpRitNQgtnoMO1FK2LNP0yXOf0fDehjjtRKcfSxYEzg9RN6PmNrV-Kpl1STGC6BVabT1ocrYYdsPQasdNIVJUAF0HyfS8L6EdVM/s400/scr_sl.JPG" alt="" id="BLOGGER_PHOTO_ID_5267028099382606818" border="0" /></a>Anonymoushttp://www.blogger.com/profile/08560846342306382608noreply@blogger.com0