<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6857714793830341639</id><updated>2011-11-23T01:37:19.242-08:00</updated><category term='Virtual Machine'/><category term='Python'/><category term='Sqlite'/><category term='cajs'/><category term='Adapter'/><category term='Orbited'/><category term='AJAX'/><category term='Visitor'/><category term='XML'/><category term='Rogue'/><category term='YUI'/><category term='Game Development'/><category term='STOMP'/><category term='Programming'/><category term='C++'/><category term='Namespace'/><category term='jquery'/><category term='Virtual Box'/><category term='Metaclass'/><category term='COMET'/><category term='Django'/><category term='RabbitMQ'/><category term='MMO'/><category term='Memory'/><category term='Signals and Slots'/><category term='Inversion-Of-Control'/><category term='JavaScript'/><category term='Android'/><category term='Unification'/><category term='GankWar'/><category term='Design Patterns'/><title type='text'>Code for the Closet</title><subtitle type='html'>C, C++, Python, JavaScript, and other programming coolness.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>25</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-5331941659850661135</id><published>2011-10-30T08:35:00.000-07:00</published><updated>2011-10-30T09:17:04.135-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GankWar'/><category scheme='http://www.blogger.com/atom/ns#' term='Game Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>Ganked Android Interface</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-3filSFwkWrg/Tq1u3GBbj4I/AAAAAAAAAEI/VoIwkYWr6cw/s1600/GankedAndroid0.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="margin: 0px 10px 10px 0px; width: 194px; height: 320px; float: left; cursor: pointer;" id="BLOGGER_PHOTO_ID_5669309398717796226" border="0" alt="" src="http://3.bp.blogspot.com/-3filSFwkWrg/Tq1u3GBbj4I/AAAAAAAAAEI/VoIwkYWr6cw/s320/GankedAndroid0.png" /&gt;&lt;/a&gt;I have not spoken much about Ganked lately, but I have modified the library to use Boost shared pointers for memory management, Boost graph library for path finding algorithms, Boost serialization for map state, and I have created google V8 bindings to the library for use in &lt;a href="http://nodejs.org/"&gt;Node.js&lt;/a&gt; .&lt;br /&gt;&lt;br /&gt;I have recently started working on the Android interface to the game server.  for the QuickAction bar, I used the great code provided by Lorensius in his &lt;a href="http://www.londatiga.net/it/how-to-create-quickaction-dialog-in-android/"&gt;Blog Post on QuickActions.&lt;/a&gt;  The great RPG icons for the interface concept are coming from Ails as part of the collection you can find at &lt;a href="http://ails.deviantart.com/"&gt;Ails' Deviant Art RPG Collection.&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="clear: both;"&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/-laxA8fgPLY8/Tq1yT_16jcI/AAAAAAAAAEg/Pk2EW0PU0p4/s1600/GankedAndroid2.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="margin: 0px 0px 10px 10px; width: 320px; height: 294px; cursor: pointer;" id="BLOGGER_PHOTO_ID_5669313193809972674" border="0" alt="" src="http://1.bp.blogspot.com/-laxA8fgPLY8/Tq1yT_16jcI/AAAAAAAAAEg/Pk2EW0PU0p4/s320/GankedAndroid2.png" /&gt;&lt;/a&gt;&lt;br /&gt;At the moment, persistence works, you select a location and it gives you the option to change the current item or clear the existing item.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="clear: both;"&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-URgMbjHqMcQ/Tq11EkGyG8I/AAAAAAAAAEs/YsN9h2i8W4E/s1600/GankedAndroid3.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="margin: 0px 10px 10px 0px; width: 320px; height: 294px; cursor: pointer;" id="BLOGGER_PHOTO_ID_5669316227201375170" border="0" alt="" src="http://4.bp.blogspot.com/-URgMbjHqMcQ/Tq11EkGyG8I/AAAAAAAAAEs/YsN9h2i8W4E/s320/GankedAndroid3.png" /&gt;&lt;/a&gt;&lt;br /&gt;If you choose to change the item, a list of items in your inventory is presented that is appropriate for the given slot.  &lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/-qUdGeaou3Do/Tq114n7CbJI/AAAAAAAAAE4/bUcEuK5KHdo/s1600/GankedAndroid4.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="margin: 0px auto 10px; width: 200px; height: 184px; text-align: center; display: block; cursor: pointer;" id="BLOGGER_PHOTO_ID_5669317121579052178" border="0" alt="" src="http://4.bp.blogspot.com/-qUdGeaou3Do/Tq114n7CbJI/AAAAAAAAAE4/bUcEuK5KHdo/s200/GankedAndroid4.png" /&gt;&lt;/a&gt;&lt;br /&gt;You are returned to the previous screen with the selected item in the appropriate slot.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-5331941659850661135?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/5331941659850661135/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2011/10/ganked-android-interface.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/5331941659850661135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/5331941659850661135'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2011/10/ganked-android-interface.html' title='Ganked Android Interface'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-3filSFwkWrg/Tq1u3GBbj4I/AAAAAAAAAEI/VoIwkYWr6cw/s72-c/GankedAndroid0.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-1587488436569700809</id><published>2011-10-14T08:46:00.000-07:00</published><updated>2011-10-14T08:50:05.535-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GankWar'/><category scheme='http://www.blogger.com/atom/ns#' term='Game Development'/><title type='text'>Moved to Node.js</title><content type='html'>It has been quiet for a long time on the game development front.  It is a hobby that I do not get to spend much time with, but I have not been completely lazy!  I have refined the Ganked library and created bindings for Node.js.  I am currently trying to decide how to document the system in terms of a user guide.  Look for more soon!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-1587488436569700809?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/1587488436569700809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2011/10/moved-to-nodejs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/1587488436569700809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/1587488436569700809'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2011/10/moved-to-nodejs.html' title='Moved to Node.js'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-5045828556182074454</id><published>2011-01-24T19:42:00.001-08:00</published><updated>2011-01-24T19:44:11.895-08:00</updated><title type='text'>Quick Note on Partitioned Maps</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_1KXNfxxY42M/TT5G55LnKXI/AAAAAAAAABY/vT_BrvmLH7U/s1600/sample.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 241px;" src="http://3.bp.blogspot.com/_1KXNfxxY42M/TT5G55LnKXI/AAAAAAAAABY/vT_BrvmLH7U/s320/sample.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5565964149892524402" /&gt;&lt;/a&gt;&lt;br /&gt;I wanted to add a visual dot graph of the partition space described in my previous post.  I hope you enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-5045828556182074454?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/5045828556182074454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2011/01/quick-note-on-partitioned-maps.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/5045828556182074454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/5045828556182074454'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2011/01/quick-note-on-partitioned-maps.html' title='Quick Note on Partitioned Maps'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_1KXNfxxY42M/TT5G55LnKXI/AAAAAAAAABY/vT_BrvmLH7U/s72-c/sample.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-8474961897549511361</id><published>2011-01-24T16:23:00.000-08:00</published><updated>2011-01-24T16:33:22.362-08:00</updated><title type='text'>New Phase to the Map Processing</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_1KXNfxxY42M/TT4aODEk9SI/AAAAAAAAABQ/Ct42ErHr5f4/s1600/phase5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 200px;" src="http://1.bp.blogspot.com/_1KXNfxxY42M/TT4aODEk9SI/AAAAAAAAABQ/Ct42ErHr5f4/s320/phase5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5565915018121508130" /&gt;&lt;/a&gt;&lt;br /&gt;I mentioned in my previous post that I had partitioned the map to generate hallways.  Next I have begun to tackle the problem of navigation.  Taking a 200 x 200 map, that generates 40,000 vertices, each vertex can have an edge with an adjacent vertex.  It is easy to see this problem could get big!  Finding your way from point A to point B could be very expensive.  The map you see above turns out to have 6776 vertices (i.e. X,Y coordinates) with 28,669 edges between those vertices.  To try to reduce the problem, I have taken a common approach of creating a navigational mesh.  By creating partition spaces, I can reduce the problem set dramatically.  It would probably be better if my partitions were of similar size, but I have expanded them as much as I could x and y.  I may take a square approach at a later time, but hallways.... "Bleh!"  In the picture above, each partition has its own colour.  I measure the weight of an edge between two partitions to be the distance from one partitions centre to the centre of an adjacent partition.  This reduces the navigation problem to finding the best path from a point within a partition to the edge of an adjacent partition, and a path of partitions.  The partition graph in the example above is only 65 vertices (partitions) with 66 edges ( shared sides between partitions).  I apologize for the horrible description, but hopefully you found this interesting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-8474961897549511361?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/8474961897549511361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2011/01/new-phase-to-map-processing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/8474961897549511361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/8474961897549511361'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2011/01/new-phase-to-map-processing.html' title='New Phase to the Map Processing'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_1KXNfxxY42M/TT4aODEk9SI/AAAAAAAAABQ/Ct42ErHr5f4/s72-c/phase5.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-4763498372727460863</id><published>2011-01-17T11:07:00.000-08:00</published><updated>2011-01-17T11:24:33.255-08:00</updated><title type='text'>Dynamic Map Generation in Ganked</title><content type='html'>I have been working on the dynamic map generation for Ganked.  I have been prototyping it in python; though, the final implementation will likely live in C++.  I currently have 4 phases of map generation:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Phase 1&lt;/span&gt;:  Using a room placement strategy ( 2 strategies exist at the moment), place the rooms&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1KXNfxxY42M/TTSUK-U0g0I/AAAAAAAAAAw/JRnMrCFW3-Q/s1600/step1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://2.bp.blogspot.com/_1KXNfxxY42M/TTSUK-U0g0I/AAAAAAAAAAw/JRnMrCFW3-Q/s320/step1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5563234355959333698" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Phase 2 :&lt;/span&gt;  I create a navigation map with lines extending from the center of rooms, but terminating just before any other room it may run into.  This will form the paths that hallway generation will use to create hallways in later steps.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_1KXNfxxY42M/TTSVCF6ubOI/AAAAAAAAAA4/1AAYX-fl_Es/s1600/step2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://1.bp.blogspot.com/_1KXNfxxY42M/TTSVCF6ubOI/AAAAAAAAAA4/1AAYX-fl_Es/s320/step2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5563235302890171618" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Phase 3:&lt;/span&gt; Using a clustering algorithm based on distance between centers, I cluster the rooms to determine what will be connected to what.  Rooms are initially turned into a cluster node and then cluster nodes are clustered into composite nodes based on distances between centers.  This continues until there is only one node left in the list.  In the graphic above, each clustering is outlined in its own color.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_1KXNfxxY42M/TTSV-iv63gI/AAAAAAAAABA/s0gmmKi6lOE/s1600/step3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://3.bp.blogspot.com/_1KXNfxxY42M/TTSV-iv63gI/AAAAAAAAABA/s0gmmKi6lOE/s320/step3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5563236341421628930" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Phase 4:  Using a depth first approach to the clustered nodes, begin connecting nodes to each other with a simple A* pathfinding hallway generator with all spaces blocked except those identified in phase 2 (the lines).  Now we have hallways connecting all of our rooms!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_1KXNfxxY42M/TTSXDN72_dI/AAAAAAAAABI/qo0fRM3moe8/s1600/step4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://1.bp.blogspot.com/_1KXNfxxY42M/TTSXDN72_dI/AAAAAAAAABI/qo0fRM3moe8/s320/step4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5563237521245535698" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In future iterations I hope to have hallway "diggers" widen out the hallways based on relationships to room sizes they connect to and potential space they have to dig in.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-4763498372727460863?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/4763498372727460863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2011/01/dynamic-map-generation-in-ganked.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/4763498372727460863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/4763498372727460863'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2011/01/dynamic-map-generation-in-ganked.html' title='Dynamic Map Generation in Ganked'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_1KXNfxxY42M/TTSUK-U0g0I/AAAAAAAAAAw/JRnMrCFW3-Q/s72-c/step1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-4710700090554648418</id><published>2011-01-04T18:44:00.000-08:00</published><updated>2011-01-04T18:54:24.952-08:00</updated><title type='text'>GankWar Lives!</title><content type='html'>I have started work on GankWars again.  My first approach is to revamp the C++ libraries to use boost.  I have started, and am almost 80% complete.  Next phase will likely be Google V8 bindings.  I good friend of mine has joined in on the fun, Brian Watson.  Hopefully we can make some headway.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-4710700090554648418?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/4710700090554648418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2011/01/gankwar-lives.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/4710700090554648418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/4710700090554648418'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2011/01/gankwar-lives.html' title='GankWar Lives!'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-1911517830010602683</id><published>2010-05-15T18:16:00.000-07:00</published><updated>2010-05-15T18:18:23.099-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Design Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='cajs'/><title type='text'>Workflow added to CAJS</title><content type='html'>CAJS has been updated on Google code hosting.  Would love any peer review and input.  The tests could do with, well .. more tests!  Suggestions for improvements are welcome, as I am sure it can be improved in many ways.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-1911517830010602683?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/1911517830010602683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2010/05/workflow-added-to-cajs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/1911517830010602683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/1911517830010602683'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2010/05/workflow-added-to-cajs.html' title='Workflow added to CAJS'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-5701953210557696012</id><published>2010-05-01T13:07:00.000-07:00</published><updated>2010-05-01T13:09:12.191-07:00</updated><title type='text'>CAJS up on Google Hosting</title><content type='html'>I have cleaned up some of my code and provided it as library on Google Hosting, named: CAJS.  You can find it at http://code.google.com/p/cajs/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-5701953210557696012?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/5701953210557696012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2010/05/cajs-up-on-google-hosting.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/5701953210557696012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/5701953210557696012'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2010/05/cajs-up-on-google-hosting.html' title='CAJS up on Google Hosting'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-6134837587175303069</id><published>2009-12-22T07:21:00.000-08:00</published><updated>2009-12-22T13:04:23.712-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Orbited'/><category scheme='http://www.blogger.com/atom/ns#' term='RabbitMQ'/><category scheme='http://www.blogger.com/atom/ns#' term='GankWar'/><category scheme='http://www.blogger.com/atom/ns#' term='Django'/><category scheme='http://www.blogger.com/atom/ns#' term='Sqlite'/><title type='text'>What in the Gank(war) has been going on!</title><content type='html'>Some of you may be wondering what the silence around GankWar has been.  Is it dead, Is it alive...  It is, in fact, alive.  It has undergone a big transition.  I have been working on message communication, mostly combat chat, and I ran into some performance issues.  Some of the performance may be related to the fact that I am developing and testing on a cheap laptop.  This caused me to do a few things:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Move to Ubuntu for development&lt;/li&gt;&lt;ul&gt;&lt;li&gt;No longer worrying with windows for compiling server code&lt;/li&gt;&lt;li&gt;Client still in browser, so folks can play from any machine&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Administration and Data Changes&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Introduced some &lt;a href="http://www.sqlite.org/"&gt;Sqlite&lt;/a&gt; for the persistence of data&lt;/li&gt;&lt;li&gt;Moved application layer (e.g. Admin) to &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;&lt;/li&gt;&lt;li&gt;   Maintained &lt;a href="http://orbited.org/"&gt;Orbited&lt;/a&gt; as Comet server&lt;/li&gt;&lt;li&gt;   Testing &lt;a href="http://www.rabbitmq.com/"&gt;RabbitMQ&lt;/a&gt; in place of MorbidQ (which was part of Orbited)&lt;/li&gt;&lt;/ul&gt;&lt;/ol&gt;&lt;br /&gt;I have recieved HUGE speedups for game world "ticks" in Linux, but I am up against two bottlenecks:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Message Serialization (to JSON), which is big, but I have not optimized the message structure itself&lt;/li&gt;&lt;li&gt;Message Delivery&lt;/li&gt;&lt;ul&gt;&lt;li&gt;  I believe the issue here is running too much on the same machine(thought that does not appear to be it by looking at the processes resource use)&lt;/li&gt;&lt;li&gt;    I hope that simply moving Orbited and/or the STOMP server to a different machine will make a difference, but I do not have a second machine to test from.&lt;/li&gt;&lt;li&gt;  I am playing with different Message Queue types (MorbidQ vs RabbitMQ) to look for a difference/speedup with that change.&lt;/li&gt;&lt;/ul&gt;&lt;/ol&gt;&lt;br /&gt;It is going slow, but I will try to keep you up to date!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-6134837587175303069?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/6134837587175303069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2009/12/what-in-gankwar-has-been-going-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/6134837587175303069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/6134837587175303069'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2009/12/what-in-gankwar-has-been-going-on.html' title='What in the Gank(war) has been going on!'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-395330456953209614</id><published>2009-11-16T17:50:00.001-08:00</published><updated>2009-11-16T17:59:08.971-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Orbited'/><category scheme='http://www.blogger.com/atom/ns#' term='GankWar'/><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='COMET'/><title type='text'>GankWar Screen Shot</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_1KXNfxxY42M/SwIBlmWctnI/AAAAAAAAAAc/HnkifsEIsqk/s1600/screen.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 302px;" src="http://3.bp.blogspot.com/_1KXNfxxY42M/SwIBlmWctnI/AAAAAAAAAAc/HnkifsEIsqk/s320/screen.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5404884248259507826" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The above is a screen shot of the current user interface.  It uses icons designed by &lt;a href="http://ails.deviantart.com/"&gt;Ails&lt;/a&gt;.  This will likely not change until someone with a lot more graphic design skill than myself changes it!  This UI is using HTML5 Canvas with jquery behind the scenes.  I don't have much to post at the moment, but I did want to provide a screen shot!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-395330456953209614?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/395330456953209614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2009/11/gankwar-screen-shot.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/395330456953209614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/395330456953209614'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2009/11/gankwar-screen-shot.html' title='GankWar Screen Shot'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_1KXNfxxY42M/SwIBlmWctnI/AAAAAAAAAAc/HnkifsEIsqk/s72-c/screen.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-4215549554510868316</id><published>2009-11-05T20:16:00.001-08:00</published><updated>2009-11-09T09:39:58.977-08:00</updated><title type='text'>TickHandler and its Kids!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1KXNfxxY42M/SvOjLyL1bRI/AAAAAAAAAAU/lsauKsgZWts/s1600-h/tickhandler.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 274px; height: 163px;" src="http://2.bp.blogspot.com/_1KXNfxxY42M/SvOjLyL1bRI/AAAAAAAAAAU/lsauKsgZWts/s320/tickhandler.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5400839800992656658" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As mentioned previously, the TickHandler can receive tick events from the GameObjectCollector.  We previously discussed Tickhandler, but now we will cover its two direct subclasses: GameObject and PyTickHandler.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;GameObject&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="cpp"&gt;&lt;br /&gt;  GameObject (GameObjectCollector *c)&lt;br /&gt;  GameObject (GameObjectCollector *c, const string &amp;grid)&lt;br /&gt;  GameObject (GameObjectCollector *c, const char *rGrid)&lt;br /&gt;GOComponent *  GetGOC (const char *rFamilyID)&lt;br /&gt;GOComponent *  GetGOC (const string &amp;familyID)&lt;br /&gt;void  SetGOC (GOComponent *newGOC)&lt;br /&gt;void  DelGOC (const char *rFamilyID)&lt;br /&gt;void  DelGOC (const string &amp;familyID)&lt;br /&gt;void  ClearGOCs ()&lt;br /&gt;void  SetLocation (GameMapLocation *gloc)&lt;br /&gt;GameMapLocation *  GetLocation ()&lt;br /&gt;Point  GetLocationPoint ()&lt;br /&gt;GamePoint *  GWGetLocation ()&lt;br /&gt;bool  Tick (TickPhase phase)&lt;br /&gt;bool  TestProposition (char *name, bool truth, float value)&lt;br /&gt;void  UpdateProposition (GameProposition &amp;g)&lt;br /&gt;void  AddProposition (GameProposition *prop)&lt;br /&gt;GameProposition *  GetProposition (string &amp;name, bool truth)&lt;br /&gt;GameProposition *  GetProposition (char *name, bool truth)&lt;br /&gt;float  Distance (GameObject *obj)&lt;br /&gt;GameReferenceType  GetReferenceType ()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;GameObject is intended to be the first concrete class to be registered with the GameObjectCollector.  It could be thought as an object in the game environment.  It could represent both and actor or a tree.  The GameObject uses a game object component system that is very similar to what is described in &lt;a href="http://www.amazon.com/Game-Programming-Gems-CD-ROM-Development/dp/1584504501/ref=pd_sim_b_6/179-4342794-1416547"&gt;Game Programming Gems: 6&lt;/a&gt;.  The components make up the specialized behavior of varios GameObjects, and will be covered in much more detail in my next post.  It is the ability to set and get these components that allow some objects, an avatar for example, to have an Artificial Intelligence, and some objects, such as a trap, to have minimal intelligence.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;PyTickHandler&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="cpp"&gt;&lt;br /&gt;  PyTickHandler (PyObject *o, GameObjectCollector *c, const char *tid)&lt;br /&gt;bool  Tick (TickPhase phase)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This handler is very generic, and dellegates the handling of the Tick call to whatever python object is attached to this object.  This allows a great deal of extensibility, as you can allow any python object to participate in the tick events of the GameObjectCollector.  An example might be a timing component, a state renderer, or simply an object that resurrects fallen avatars as their deaths are detected in the tick event cycle.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-4215549554510868316?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/4215549554510868316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2009/11/tickhandler-and-its-kids.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/4215549554510868316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/4215549554510868316'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2009/11/tickhandler-and-its-kids.html' title='TickHandler and its Kids!'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_1KXNfxxY42M/SvOjLyL1bRI/AAAAAAAAAAU/lsauKsgZWts/s72-c/tickhandler.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-1199796963055919995</id><published>2009-11-03T11:32:00.000-08:00</published><updated>2009-11-03T14:57:50.580-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GankWar'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>GameReference, GameObjectCollector, and TickHandler</title><content type='html'>&lt;span style="font-weight:bold;"&gt;GameReference&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="cpp"&gt;&lt;br /&gt;GameReference (GameObjectCollector *c)&lt;br /&gt;GameReference (GameObjectCollector *c, const string &amp;grid)&lt;br /&gt;GameReference (GameObjectCollector *c, const char *rGrid)&lt;br /&gt;virtual ~GameReference ()&lt;br /&gt;const string &amp;  GetID ()&lt;br /&gt;char *  GetIDRaw ()&lt;br /&gt;bool  IncRef ()&lt;br /&gt;bool  DecRef ()&lt;br /&gt;int  RefCount ()&lt;br /&gt;bool  Collectable ()&lt;br /&gt;bool  Attach (PyObject *p)&lt;br /&gt;bool  Collect (bool force=false)&lt;br /&gt;PyObject *GetPyObject ()&lt;br /&gt;GameObjectCollector *GetCollector ()&lt;br /&gt;virtual GameReferenceType GetReferenceType ()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In GankWar, the GameReference is the basic class of entities in the game.  GameReference provices a reference counting scheme, which allows for memory management of items in the "zone".  You might ask why I bothered implementing my own refcounting mechanism?  It just seemed right.  I was spending a lot of time know when something was crossing the reference boundaries between c++ and python; so, I used this system to work it out.  To increment the reference count, you would call IncRef(), and to decrement DecRef().  If the reference count reaches zero, the item will be marked for collection in the next cycle of the GameObjectCollector.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;GameObjectCollector&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="cpp"&gt;&lt;br /&gt;GameObjectCollector (const string &amp;tid)&lt;br /&gt;GameObjectCollector (const char *tid)&lt;br /&gt;~GameObjectCollector ()&lt;br /&gt;void  Put (GameReference *ref)&lt;br /&gt;GameReference *  Get (const string &amp;id)&lt;br /&gt;GameReference *  Get (const char *rid)&lt;br /&gt;void  Collect (GameReference *ref)&lt;br /&gt;void  CollectAll ()&lt;br /&gt;void  PutAll ()&lt;br /&gt;string  NextID ()&lt;br /&gt;void  Register (TickHandler *handler, TickPhase phase)&lt;br /&gt;void  UnRegister (TickHandler *handler, TickPhase phase)&lt;br /&gt;void  Tick ()&lt;br /&gt;void  ForEach (GameReferenceType grt, foreachgameobject_cb fn, void *user_data)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The GameObjectCollector is the heart of a zone, as it manages GameReferences.  It also handles "Tick" events within the scenario.  As mentioned previously, it will insert and collect GameReferences at the beginning of each Tick cycle.  A Tick has three specific phases to it, pretick, tick, and posttick.  These various tick events are handled by TickHandlers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;TickHandler&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="cpp"&gt;&lt;br /&gt;TickHandler (GameObjectCollector *c)&lt;br /&gt;TickHandler (GameObjectCollector *c, const string &amp;grid)&lt;br /&gt;TickHandler (GameObjectCollector *c, const char *rGrid)&lt;br /&gt;virtual bool  Tick (TickPhase phase)&lt;br /&gt;void  StopTicking (TickPhase phase)&lt;br /&gt;void  StartTicking (TickPhase phase)&lt;br /&gt;bool  IsTicking (TickPhase phase)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;TickHandler is a subclass of GameReference that can be registered with the GameObjectCollector to recieve Tick events for a given phase in the Tick.  They server various roles and are very flexible to support behavior that needs to occur at a given Tick.  And example might be a reporting component that reports on the state of the simulation at the end of every tick.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-1199796963055919995?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/1199796963055919995/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2009/11/gamereference-gameobjectcollector-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/1199796963055919995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/1199796963055919995'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2009/11/gamereference-gameobjectcollector-and.html' title='GameReference, GameObjectCollector, and TickHandler'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-7161004491848692674</id><published>2009-10-29T19:45:00.001-07:00</published><updated>2009-10-29T19:52:33.916-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='STOMP'/><category scheme='http://www.blogger.com/atom/ns#' term='Orbited'/><category scheme='http://www.blogger.com/atom/ns#' term='GankWar'/><category scheme='http://www.blogger.com/atom/ns#' term='Virtual Machine'/><category scheme='http://www.blogger.com/atom/ns#' term='Virtual Box'/><title type='text'>GankWar and Virtualization</title><content type='html'>I have been working on making GankWar more Linux friendly, which will allow folks to work on it without requiring they have Visual Studio.  With that in mind, I installed various components on &lt;a href="http://www.virtualbox.org/"&gt;Virtual Box&lt;/a&gt; with &lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt; desktop version, and I got everything running.  &lt;br /&gt;&lt;br /&gt;I am still having some issues, as I can hit orbited locally on the VM and everything behaves like it should, and the Zone Runner messages are received.  I can hit &lt;a href="http://orbited.org/"&gt;Orbited&lt;/a&gt; from outside the VM, and it appears to connect, registers for the same channel as the local &lt;a href="http://stomp.codehaus.org/"&gt;STOMP&lt;/a&gt; client does, but does not receive the messages that the local client is receiving.  I am guessing it is either in how I am sending the messages or some domain thing to channel registration...  okay I don't believe that either /grin.  I am chalking it up to me being an &lt;a href="http://orbited.org/"&gt;Orbited&lt;/a&gt; Noob, and I am rolling up my sleeves to dig deeper.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-7161004491848692674?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/7161004491848692674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2009/10/gankwar-and-virtualization.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/7161004491848692674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/7161004491848692674'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2009/10/gankwar-and-virtualization.html' title='GankWar and Virtualization'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-2655463032101970928</id><published>2009-10-27T06:07:00.001-07:00</published><updated>2009-10-27T06:21:20.818-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='STOMP'/><category scheme='http://www.blogger.com/atom/ns#' term='Orbited'/><category scheme='http://www.blogger.com/atom/ns#' term='GankWar'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='Rogue'/><title type='text'>High Level GankWar System View</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_1KXNfxxY42M/Subwu8Y0m7I/AAAAAAAAAAM/FjER0Rq6tps/s1600-h/gw_client_server_high.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 177px; height: 320px;" src="http://4.bp.blogspot.com/_1KXNfxxY42M/Subwu8Y0m7I/AAAAAAAAAAM/FjER0Rq6tps/s320/gw_client_server_high.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5397265892725005234" /&gt;&lt;/a&gt;  GankWar is a simulation type game, where players will be either able to play their avatars, or allow artificial intelligence instructions, through &lt;a href="http://aigamedev.com/open/articles/bt-overview/"&gt;behavior trees&lt;/a&gt;, to guide the actions of their players.  The AI will be able to be switched on and off, but the avatar will always be present in the gaming world.&lt;br /&gt;&lt;br /&gt;The interface will use HTML and Canvas, which makes compatibility with Internet Explorer unlikely, though not impossible.  The web interface will provide something slightly more graphical than the typical &lt;a href="http://en.wikipedia.org/wiki/Roguelike"&gt;roguelike&lt;/a&gt;, but will play much the same as one.&lt;br /&gt;&lt;br /&gt;In order to stream events to and from the browser, a &lt;a href="http://en.wikipedia.org/wiki/Comet_(programming)"&gt;Comet&lt;/a&gt; server will be used, to handle the persistent connection and data pushed from the server.  Data and presentation pulled from the server by the client will be handled by a standard web framework.  In the prototype, my chosen Comet server, &lt;a href="http://orbited.org/"&gt;Orbited&lt;/a&gt;, will handle both Comet and presentation layer, but shortly into full development I see something like Django taking over the presentation layer surrounding the map.&lt;br /&gt;&lt;br /&gt;The MapRunner is a &lt;a href="http://twistedmatrix.com/"&gt;Twisted&lt;/a&gt; Python STOMP client, that is running the Game Engine while communicating with the connected clients via the STOMP protocol.  &lt;br /&gt;&lt;br /&gt;More to come as I have time!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-2655463032101970928?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/2655463032101970928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2009/10/high-level-gankwar-system-view.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/2655463032101970928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/2655463032101970928'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2009/10/high-level-gankwar-system-view.html' title='High Level GankWar System View'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_1KXNfxxY42M/Subwu8Y0m7I/AAAAAAAAAAM/FjER0Rq6tps/s72-c/gw_client_server_high.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-7141402323386685085</id><published>2009-10-21T18:21:00.000-07:00</published><updated>2009-10-21T18:30:37.172-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GankWar'/><category scheme='http://www.blogger.com/atom/ns#' term='Game Development'/><category scheme='http://www.blogger.com/atom/ns#' term='MMO'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>From Sleep I Rise!</title><content type='html'>Well, I have not exactly been sleeping, but I have been buried under work.  My blogging has not been going... period.  I am going to try to fix that by turning to a project that I am doing for fun:  GankWar.  There is nothing new about the idea, but I will be implementing a &lt;a href="http://en.wikipedia.org/wiki/Roguelike"&gt;Roguelike&lt;/a&gt; Multiplayer Online (Just MO... No MMO) that will enable players to write artificial intelligence to drive their persona while they are not in game.  I hope this will add more diversity to the mob AI. The engine is a C++ library that has python bindings.  My objective for this game is not to rock the gaming world with my brilliance, as that would be a comedy and not a game, but to hopefully learn a few things about game making, while having fun along the way. &lt;br /&gt;&lt;br /&gt;Anyhow, I will be updating this blog periodically with code samples and such as it progresses.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-7141402323386685085?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/7141402323386685085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2009/10/from-sleep-i-rise.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/7141402323386685085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/7141402323386685085'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2009/10/from-sleep-i-rise.html' title='From Sleep I Rise!'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-3427199809770042218</id><published>2009-03-28T06:56:00.000-07:00</published><updated>2009-03-28T07:11:14.430-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Memory'/><title type='text'>I think I've Lost My Memory!</title><content type='html'>I know it has been forever since I have posted, but work has been busy.  I do want to share something, not ground breaking, that we have started doing to track down memory issues in our javascript applications.  In my example below, I create this alien registerEventHandler function that would take an object and register for an event on it by name, taking a function and a scope.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;function getClosure(arg1,arg2){&lt;br /&gt;  var trkel = document.createElement("DIV");&lt;br /&gt;  trkel.setAttribute("id","TRACK_getClosure" );&lt;br /&gt;  registerEventHandler(arg1,"click",&lt;br /&gt;     function(){ .... },this);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As we can see, when this function is ran, we register a function as a handler.  A function which involves a closure ( function within function holds containing scope).  This is not a problem, so much, if it is cleaned up, after the arg1 has seen its day.  When we have a stray memory issue we will use sIEve and code like above.  While the closure is alive, sIEve will show the element whose ID is "TRACK_getClosure" as not freed and orphaned.  When our code behaves, the element is dereferenced and gets freed.  This same approach can be used to track the life of objects, and if they get destroyed, by assigning the tracker_el instance directly too the object; so, when all references to the object are cleaned up, the element will be reclaimed. &lt;br /&gt;&lt;br /&gt;I hope this helps you all like it has helped us!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-3427199809770042218?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/3427199809770042218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2009/03/i-think-ive-lost-my-memory.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/3427199809770042218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/3427199809770042218'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2009/03/i-think-ive-lost-my-memory.html' title='I think I&apos;ve Lost My Memory!'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-6187032502614765183</id><published>2008-12-18T21:12:00.000-08:00</published><updated>2009-02-16T06:57:59.783-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='Metaclass'/><title type='text'>Event Driven Construction Part 2</title><content type='html'>In my previous post,&lt;span class="Apple-style-span" style="color: rgb(204, 102, 0);  line-height: 25px; "&gt;&lt;a href="http://codeforthecloset.blogspot.com/2008/12/event-driven-construction.html" style="text-decoration: none; font-weight: normal; color: rgb(51, 51, 51); display: inline !important; "&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Event Driven Construction&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; , I discussed the concept of using metaclasses to provide event driven construction of singleton services.  I wanted to introduce two more examples.  One is a class which combines the two metaclasses from the previous post together:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class CreateAndSignal(EventSingleton,&lt;br /&gt;  CreateOnSignal):&lt;br /&gt;     pass&lt;br /&gt;&lt;br /&gt;class D(object):&lt;br /&gt;     __metaclass__ = CreateAndSignal&lt;br /&gt;     _i_signal = "C-Created"&lt;br /&gt;     _o_signal = "D-Created"&lt;br /&gt;&lt;br /&gt;class E(object):&lt;br /&gt;    __metaclass__ = CreateAndSignal&lt;br /&gt;    _i_signal = "C-Created"&lt;br /&gt;    _o_signal = "E-Created"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the code above, I have created two classes of type CreateAndSignal, which construct themselves on recieving &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;_i_signal&lt;/span&gt;, and upon construction throw the event &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;_o_signal&lt;/span&gt;.  In the example both classes await the event "C-Created"; so, lets provide that class as well, which is of type  EventSingleton from the previous post.&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class C(object):&lt;br /&gt;    __metaclass__ = EventSingleton&lt;br /&gt;    _o_signal = "C-Created"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now with a class that does the same by tracking a few signals we can wait on multiple events.&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;def getOnDependancy(sig,k):&lt;br /&gt;     x = lambda *args:k.onDependancy(sig)&lt;br /&gt;     return x&lt;br /&gt;class CreateAfterDependancies(Singleton):&lt;br /&gt;     msg="[%s]CreateAfterDependancies(%s)%s"&lt;br /&gt;     def __init__(cls,name,bases,dic):&lt;br /&gt;        super(CreateAfterDependancies,cls).\&lt;br /&gt;        __init__(name,bases,dic)&lt;br /&gt;        cls._d_signal_lookup = {}&lt;br /&gt;        cls._d_signals = list(cls._d_signals)&lt;br /&gt;        for signal in cls._d_signals:&lt;br /&gt;           rec=getOnDependancy(signal,cls)&lt;br /&gt;           cls._d_signal_lookup[signal] = rec&lt;br /&gt;        connectEx(rec,signal)&lt;br /&gt;     def __call__(cls,*args,**kw):&lt;br /&gt;        if cls.isSatisfied():&lt;br /&gt;           return super(&lt;br /&gt;              CreateAfterDependancies,cls).\&lt;br /&gt;                 __call__(*args,**kw)&lt;br /&gt;        else:&lt;br /&gt;           msg = "Dependencies not met"&lt;br /&gt;           raise Exception(msg)&lt;br /&gt;      def isSatisfied(cls):&lt;br /&gt;         return len(cls._d_signals) == 0&lt;br /&gt;      def onDependancy(cls,signal):&lt;br /&gt;         if signal in cls._d_signals:&lt;br /&gt;            rec=cls._d_signal_lookup[signal]&lt;br /&gt;      del cls._d_signal_lookup[signal]&lt;br /&gt;            cls._d_signals.remove(signal)&lt;br /&gt;            satisfied = (cls.isSatisfied() \&lt;br /&gt;               and 1) or 0&lt;br /&gt;            msg=["--%s"%repr(cls._d_signals),&lt;br /&gt;               "--Creating"]&lt;br /&gt;            print cls.msg%(signal,&lt;br /&gt;              cls.__name__,&lt;br /&gt;              msg[satisfied])&lt;br /&gt;            if satisfied:&lt;br /&gt;               cls()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;By creating closures to functions that will remove the signal when fired and check to see if all dependencies have been met, this class allows us to create based off of more than one event, as previous classes worked.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class G(object):&lt;br /&gt;   __metaclass__ = CreateAfterDependancies&lt;br /&gt;   _d_signals = ["E-Created","F-Created"]&lt;br /&gt;&lt;br /&gt;C()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The classes above create a build condition which can be visualized by:&lt;br /&gt;C-&gt;D&lt;br /&gt;   -&gt;E -&gt; F&lt;br /&gt;And the output of:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;[C]EventSingleton(C-Created)&lt;br /&gt;[D]CreateOnSignal(C-Created)&lt;br /&gt;[D]EventSingleton(D-Created)&lt;br /&gt;[E]CreateOnSignal(C-Created)&lt;br /&gt;[E]EventSingleton(E-Created)&lt;br /&gt;[E-Created]CreateAfterDependancies(G)--['F-Created']&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-6187032502614765183?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/6187032502614765183/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/event-driven-construction-part-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/6187032502614765183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/6187032502614765183'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/event-driven-construction-part-2.html' title='Event Driven Construction Part 2'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-3621279046612490044</id><published>2008-12-15T14:55:00.001-08:00</published><updated>2008-12-16T04:30:58.436-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='Metaclass'/><title type='text'>Event Driven Construction</title><content type='html'>I have always had fun playing with &lt;a href="http://en.wikipedia.org/wiki/Metaclass"&gt;metaclasses&lt;/a&gt; in python.  If you are not familair with metaclasses, you may want to read about them in general here or a brief introduction to them in &lt;a href="http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html"&gt;python&lt;/a&gt;. If you want the short, Mike-Webb, possibly wrong verion, then without getting in too deep, I will try to give a crash introduction to metaclasses.  You can think of a metaclass as the class of a class or as a type.  Objects are instances of Classes and Classes are instances of Types.  __metaclass__ attribute of classes in python allow one to declare the type of that class.  That may sound whacky, but what a metaclass allows you to do is change the bahvoir of class instantiation and construction, possibly doing things such as override behavior at compile time.  A method defined on a type, becomes a classmethod of the class, but not of an instance of the class.  This allows us to override behavior such as making the class callable, as well as overriding representation behavior, construction behavior, and initialization behavior.  One metaclass I use a lot in python helps implement the singleton pattern borrowed from &lt;a href="http://code.activestate.com/recipes/102187/#c8"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class Singleton(type):&lt;br /&gt;def __init__(cls,name,bases,dic):&lt;br /&gt;   super(Singleton,cls).__init__(name,&lt;br /&gt;     bases,dic)&lt;br /&gt;   cls.instance=None&lt;br /&gt;def __call__(cls,*args,**kw):&lt;br /&gt;   if cls.instance is None:&lt;br /&gt;      cls.instance=super(Singleton,cls).\&lt;br /&gt;         __call__(*args,**kw)&lt;br /&gt;   return cls.instance&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see, this class overrides the call behavior to only create a new instance if one did not already exist.&lt;br /&gt;&lt;br /&gt;I tend to use Singleton to represent services in my projects.  Something I have difficulty with often, is sometimes my services have dependencies on lower level services.  No matter how I try to refactor them, I either have autonomy and services that do too much or services that depend on lower level services.  As I was thinking about this issue, I started thinking more about order of instantiation and dependency.  I thought it would be neat to create a set of metaclasses that helped classes define their dependency with one another based on events that must take place.  The idea was that if a services threw an event which notifies that the services was created, then other service classes could register for that event, and instantiate themselves when the environment was right for them.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To make this example work, we must assume that two functions exist:&lt;/div&gt;&lt;div&gt;sendEx - which will send an event&lt;/div&gt;&lt;div&gt;connectEx - which will connect a function to handle an event&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Lets look at a metaclass which will cause a class to be instantiated if a signal is recieved:&lt;/div&gt;&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class EventSingleton(Singleton):&lt;br /&gt; """This Class needs to have an attribute&lt;br /&gt; named _o_signal that defines the signal&lt;br /&gt; that will be thrown when this class is&lt;br /&gt; created"""&lt;br /&gt; def __call__(cls,*args,**kw):&lt;br /&gt;     if cls.instance is None:&lt;br /&gt;         super(EventSingleton,cls).__call__\&lt;br /&gt;             (*args,**kw)&lt;br /&gt;         msg = "[%s]EventSingleton(%s)"%\&lt;br /&gt;             (cls.__name__,cls._o_signal)&lt;br /&gt;         print msg&lt;br /&gt;         sendEx(cls._o_signal)&lt;br /&gt;     return cls.instance&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the above metaclass, a class defined an attribute named _o_signal that identifies the event the class should throw when it is instantiated for the first time.&lt;br /&gt;Now lets look at a metaclass that will create a class after a signal has been received for the first time.&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class CreateOnSignal(Singleton):&lt;br /&gt; """This Class needs to have an attribute&lt;br /&gt; named _i_signal that defines the signal&lt;br /&gt; that will create the class"""&lt;br /&gt; def __init__(cls,name,bases,dic):&lt;br /&gt;    super(CreateOnSignal,cls).__init__(&lt;br /&gt;    name,bases,dic)&lt;br /&gt;    #set a flag that indicates if we have&lt;br /&gt;    #been signaled&lt;br /&gt;    cls.signaled = False&lt;br /&gt;    connectEx(cls.onCreateEvent,&lt;br /&gt;         cls._i_signal)&lt;br /&gt; def __call__(cls,*args,**kw):&lt;br /&gt;     if not cls.signaled:&lt;br /&gt;         exc ="Signal not raised!"&lt;br /&gt;         raise Exception(exc)&lt;br /&gt;     return super(CreateOnSignal,cls).\&lt;br /&gt;         __call__(*args,**kw)&lt;br /&gt; def onCreateEvent(cls):&lt;br /&gt;     msg = "[%s]CreateOnSignal(%s)"%\&lt;br /&gt;         (cls.__name__,cls._i_signal)&lt;br /&gt;     print msg&lt;br /&gt;     cls.signaled=True&lt;br /&gt;     cls()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now lets write a class that throws a signal and one that waits on it!&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class A(object):&lt;br /&gt; __metaclass__ = EventSingleton&lt;br /&gt; _o_signal = "A-Created"&lt;br /&gt;&lt;br /&gt;class B(object):&lt;br /&gt; __metaclass__ = CreateOnSignal&lt;br /&gt; _i_signal = "A-Created"&lt;br /&gt;&lt;br /&gt;&gt;&gt;&gt; A()&lt;br /&gt;[A]EventSingleton(A-Created)&lt;br /&gt;[B]CreateOnSignal(A-Created)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In part 2 I will show more on the idea of dependencies and multiple dependencies, but let me leave you with a sendEx and connectEx function that will allow you to play with this code:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;def makeConnectAndSend():&lt;br /&gt; registry = {}&lt;br /&gt; def cE(fn,msg):&lt;br /&gt;     fl = registry.setdefault(msg,[])&lt;br /&gt;     fl.append(fn)&lt;br /&gt; def sE(msg):&lt;br /&gt;     fl = registry.setdefault(msg,[])&lt;br /&gt;     for fn in fl:&lt;br /&gt;         fn()&lt;br /&gt; return cE,sE&lt;br /&gt;&lt;br /&gt;connectEx,sendEx = makeConnectAndSend()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-3621279046612490044?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/3621279046612490044/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/event-driven-construction.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/3621279046612490044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/3621279046612490044'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/event-driven-construction.html' title='Event Driven Construction'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-7447569417203243117</id><published>2008-12-12T12:50:00.000-08:00</published><updated>2008-12-12T14:40:47.918-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Design Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Unification'/><category scheme='http://www.blogger.com/atom/ns#' term='Visitor'/><title type='text'>Visitor Pattern for Unification via JavaScript</title><content type='html'>One of the libraries that the company I work for has written, is one that implements &lt;a href="http://en.wikipedia.org/wiki/Unification"&gt;unification&lt;/a&gt;.  As I was thinking about my last post on the &lt;span class="Apple-style-span" style="color: rgb(204, 102, 0);  line-height: 25px; "&gt;&lt;a href="http://codeforthecloset.blogspot.com/2008/12/vistor-pattern-for-javascript.html" style="text-decoration: none; color: rgb(204, 102, 0); font-weight: normal; display: inline !important; "&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Visitor Pattern for JavaScript&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;, I thought about how the pattern could be applied to unification.  Using the same accept functions from the previous post, I fooled around, creating a visitor that could handle unification.  One of the things I wanted to provide for was partial unification; so, I could use a few attributes of an object, like a query does. &lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;/**&lt;br /&gt;* @module UnificationVisitor&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* A class implementing a variation of the&lt;br /&gt;* visitor pattern, which performs unifying&lt;br /&gt;* operations on datastructures&lt;br /&gt;* @class unifyVisitor&lt;br /&gt;* @constructor&lt;br /&gt;* @param {object} config configuration object&lt;br /&gt;*/&lt;br /&gt;var unifyVisitor = function(config){&lt;br /&gt;  /**&lt;br /&gt;  *@config functions&lt;br /&gt;  *@description indicate if functions should&lt;br /&gt;  *be traversed&lt;br /&gt;  *@type boolean&lt;br /&gt;  */&lt;br /&gt;  config.functions = config.functions ||&lt;br /&gt;      false;&lt;br /&gt;  /**&lt;br /&gt;  *@config partial&lt;br /&gt;  *@description indicate if a unification can&lt;br /&gt;  *occure when all attributes #present#&lt;br /&gt;  *match even if they are not all present&lt;br /&gt;  *@type boolean&lt;br /&gt;  */&lt;br /&gt;  config.partial = config.partial || false;&lt;br /&gt;  this.config = config;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Create a new token for carrying&lt;br /&gt;* around state&lt;br /&gt;* @method newToken&lt;br /&gt;* @return Object an object to hold&lt;br /&gt;* the state of the call.  It is used&lt;br /&gt;* as a dictionary for lugging around&lt;br /&gt;* more state.&lt;br /&gt;*/&lt;br /&gt;unifyVisitor.prototype.newToken = function(){&lt;br /&gt;  var obj = {};&lt;br /&gt;  //Copy config onto the token&lt;br /&gt;  for(var key in this.config){&lt;br /&gt;      var val = this[key];&lt;br /&gt;      if(this.config.hasOwnProperty(key) &amp;amp;&amp;amp;&lt;br /&gt;        typeof(val)!=="function"){&lt;br /&gt;          obj[key]=val;&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;  return obj;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Attempts to visit an object&lt;br /&gt;* @method dispatchVisit&lt;br /&gt;* @param {Unknown} visitee the value&lt;br /&gt;* currently being visited&lt;br /&gt;* @param {Object} token an object to hold&lt;br /&gt;* additional info the visitor may need&lt;br /&gt;*/&lt;br /&gt;unifyVisitor.prototype.dispatchVisit =&lt;br /&gt;function(a,b,token){&lt;br /&gt;  /*Create a token if this is the first call&lt;br /&gt;  * and a token is not provided*/&lt;br /&gt;  if(!token){&lt;br /&gt;      token = this.newToken();&lt;br /&gt;  }&lt;br /&gt;  /*if the first value is of no value,&lt;br /&gt;  * give the other value an opportunity&lt;br /&gt;  * to match*/&lt;br /&gt;  if(a==null || a==undefined){&lt;br /&gt;      /*if both are null then they&lt;br /&gt;      * are unified*/&lt;br /&gt;      if(a===b){&lt;br /&gt;          token.result = true;&lt;br /&gt;          return true;&lt;br /&gt;      }&lt;br /&gt;      /*final being true represents a&lt;br /&gt;      * match being performed on right&lt;br /&gt;      * operand of the match*/&lt;br /&gt;      if(!token.final){&lt;br /&gt;          token.final = true;&lt;br /&gt;          /* call dispatchVisit instead&lt;br /&gt;          * of accept as b may be null&lt;br /&gt;          * or undefined*/&lt;br /&gt;          return this.dispatchVisit(b,&lt;br /&gt;              a,token);&lt;br /&gt;      }&lt;br /&gt;      return false;&lt;br /&gt;  }&lt;br /&gt;  /*Everything else should have an accept&lt;br /&gt;  * function*/&lt;br /&gt;  else{&lt;br /&gt;      a.accept(this,b,token);&lt;br /&gt;      return true;&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Registers a handler for the&lt;br /&gt;* visitation of a named item&lt;br /&gt;* @method addVisitHandler&lt;br /&gt;* @param {String} name the name of the&lt;br /&gt;* item this handler visits&lt;br /&gt;* @param {Function} handler the function&lt;br /&gt;* handling the visitation&lt;br /&gt;*/&lt;br /&gt;unifyVisitor.addVisitHandler = function( name,&lt;br /&gt;handler ){&lt;br /&gt;  unifyVisitor.prototype["visit"+name] =&lt;br /&gt;      handler;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Default visitor method&lt;br /&gt;* @class VisitorHandlersCollection&lt;br /&gt;* @method visitDefault&lt;br /&gt;* @param {Unknown} visitee the value&lt;br /&gt;* currently being visited&lt;br /&gt;* @param {ArrayLike} args an array-like&lt;br /&gt;* object that holds the values passed&lt;br /&gt;* to the originating accept function&lt;br /&gt;*/&lt;br /&gt;var visitDefault = function(item,args){&lt;br /&gt;  var other = args[1];&lt;br /&gt;  var token = args[2];&lt;br /&gt;  //test equality&lt;br /&gt;  if(item == other){&lt;br /&gt;      token.result = true;&lt;br /&gt;  }&lt;br /&gt;  //if not final let right side try&lt;br /&gt;  else if(!token.final){&lt;br /&gt;      token.final = true;&lt;br /&gt;      if(!this.dispatchVisit(&lt;br /&gt;          other,item,token)){&lt;br /&gt;            token.result = false;&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;  /*we are teh right side and none&lt;br /&gt;  * matched*/&lt;br /&gt;  else{&lt;br /&gt;      token.result = false;&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;//need to deal with null and undefined values&lt;br /&gt;unifyVisitor.addVisitHandler("String",&lt;br /&gt;  visitDefault);&lt;br /&gt;unifyVisitor.addVisitHandler("Number",&lt;br /&gt;  visitDefault);&lt;br /&gt;unifyVisitor.addVisitHandler("Function",&lt;br /&gt;  visitDefault);&lt;br /&gt;/**&lt;br /&gt;* Handles the visitation of objects&lt;br /&gt;* Not sure how to define non-method&lt;br /&gt;* functions in YUI Doc&lt;br /&gt;* @method visitObject&lt;br /&gt;* @param {Object} item the object&lt;br /&gt;* currently being visited&lt;br /&gt;* @param {ArrayLike} args an array-like&lt;br /&gt;* object that holds the values passed&lt;br /&gt;* to the originating accept function&lt;br /&gt;*/&lt;br /&gt;var visitObject = function( item, args){&lt;br /&gt;  var other = args[1];&lt;br /&gt;  var token = args[2];&lt;br /&gt;  var a_match = false;&lt;br /&gt;  if(!token.final){&lt;br /&gt;      /*I am not the right side so&lt;br /&gt;      * let the right go first!*/&lt;br /&gt;      token.final = true;&lt;br /&gt;      /*If we fail to dispatch&lt;br /&gt;      * set failure as object wont&lt;br /&gt;      * match null or undefined*/&lt;br /&gt;      if(!this.dispatchVisit(&lt;br /&gt;          other,item,token)){&lt;br /&gt;            token.result = false;&lt;br /&gt;            return;&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;  /*If it is partial, give us a chance&lt;br /&gt;  * to match something in the other object*/&lt;br /&gt;  if(token.result === false &amp;amp;&amp;amp;&lt;br /&gt;      !token.partial){&lt;br /&gt;        return;&lt;br /&gt;  }&lt;br /&gt;  var key;&lt;br /&gt;  var result = true;&lt;br /&gt;  //iterate keys&lt;br /&gt;  for(key in item){&lt;br /&gt;      var value = item[key];&lt;br /&gt;      /*skip functions if config.functions&lt;br /&gt;      * is false*/&lt;br /&gt;      if(item.hasOwnProperty(key) &amp;amp;&amp;amp;&lt;br /&gt;          (!token.functions ||&lt;br /&gt;          typeof(value)!="function")){&lt;br /&gt;            var oval = other[key];&lt;br /&gt;          /*If key is undefined in other and&lt;br /&gt;          * config.partial was false,&lt;br /&gt;          *fail out*/&lt;br /&gt;          if(oval==undefined &amp;amp;&amp;amp;&lt;br /&gt;              !token.partial){&lt;br /&gt;                result = false;&lt;br /&gt;                break;&lt;br /&gt;          }&lt;br /&gt;          var new_token = this.newToken();&lt;br /&gt;          new_token.result = false;&lt;br /&gt;          /*try to unify the values*/&lt;br /&gt;          this.dispatchVisit(value,oval,&lt;br /&gt;              new_token);&lt;br /&gt;          /*capture if we got a match*/&lt;br /&gt;          if(new_token.result){&lt;br /&gt;              a_match = true;&lt;br /&gt;          }&lt;br /&gt;          /*match failed, so if not&lt;br /&gt;          * partial, fail out*/&lt;br /&gt;          else if(!token.partial){&lt;br /&gt;              result = false;&lt;br /&gt;              break;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;  /* Other side could have declared&lt;br /&gt;  * a match, if not, see if this&lt;br /&gt;  * obj did*/&lt;br /&gt;  if(!token.result){&lt;br /&gt;      if(result == false){&lt;br /&gt;          token.result = false;&lt;br /&gt;      }&lt;br /&gt;      else if(result==true){&lt;br /&gt;          /*if we matched any we must&lt;br /&gt;          * be matched*/&lt;br /&gt;          if(a_match){&lt;br /&gt;              token.result = true;&lt;br /&gt;          }&lt;br /&gt;          else{&lt;br /&gt;              token.result = false;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }                           &lt;br /&gt;};&lt;br /&gt;unifyVisitor.addVisitHandler("Object",&lt;br /&gt;  visitObject);&lt;br /&gt;/**&lt;br /&gt;* Handles the visitation of arrays&lt;br /&gt;* @method visitArray&lt;br /&gt;* @param {Array} item the array&lt;br /&gt;* currently being visited&lt;br /&gt;* @param {ArrayLike} args an array-like&lt;br /&gt;* object that holds the values passed&lt;br /&gt;* to the originating accept function&lt;br /&gt;*/&lt;br /&gt;var visitArray = function( item, args){&lt;br /&gt;  var other = args[1];&lt;br /&gt;  var token = args[2];&lt;br /&gt;  if(!token.final){&lt;br /&gt;      /*I am not the right side so&lt;br /&gt;      * let the right go first!*/&lt;br /&gt;      token.final = true;&lt;br /&gt;   &lt;br /&gt;if(!this.dispatchVisit(other,item,token)){&lt;br /&gt;          token.result = false;&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;  else{&lt;br /&gt;      /*lengths must match for a match*/&lt;br /&gt;      if(item.length != other.length){&lt;br /&gt;          token.result = false;&lt;br /&gt;      }&lt;br /&gt;      else{&lt;br /&gt;          /*assume a match*/&lt;br /&gt;          token.result = true;&lt;br /&gt;          for(var i=0;i&amp;lt;item.length;i++){&lt;br /&gt;              var value = item[i];&lt;br /&gt;              var oval = other[i];&lt;br /&gt;              var new_token =&lt;br /&gt;                  this.newToken();&lt;br /&gt;              new_token.result = false;&lt;br /&gt;              /*unify values*/&lt;br /&gt;              this.dispatchVisit(value,&lt;br /&gt;                  oval,new_token);&lt;br /&gt;              /*if unify fails, fail out*/&lt;br /&gt;              if(!new_token.result){&lt;br /&gt;                  token.result = false;&lt;br /&gt;                  break;&lt;br /&gt;              }&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }                         &lt;br /&gt;};&lt;br /&gt;unifyVisitor.addVisitHandler("Array",&lt;br /&gt;  visitArray);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above provides a way to unify the base types, but to provide a bit more utility, we will introduce the idea of a variable.  In order to customize a visit experience, an object need only to implement the &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;accept&lt;/span&gt;&lt;/span&gt; function, and possibly register its own handler, which is exactly what we will do for Variables:&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;/**&lt;br /&gt;* Unifies with anything storing the&lt;br /&gt;* matched object as its value&lt;br /&gt;* @class Variable&lt;br /&gt;* @constructor&lt;br /&gt;*/&lt;br /&gt;var Variable = function(){&lt;br /&gt;  this.value = undefined;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Gets the value of the Variable&lt;br /&gt;* @method getValue&lt;br /&gt;* @return {object} the matched value&lt;br /&gt;*/&lt;br /&gt;Variable.prototype.getValue = function(){&lt;br /&gt;  return this.value;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Sets the value of the Variable&lt;br /&gt;* @method setValue&lt;br /&gt;* @param {object} the value&lt;br /&gt;*/&lt;br /&gt;Variable.prototype.setValue = function(val){&lt;br /&gt;  this.value = val;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Accepts the visitor&lt;br /&gt;* @method accept&lt;br /&gt;* @param {Visitor} the visitor&lt;br /&gt;* @param {...} variable number of args passed&lt;br /&gt;* along to the visitVariable fuction&lt;br /&gt;*/&lt;br /&gt;Variable.prototype.accept = function(){&lt;br /&gt;  var visitor = arguments[0];&lt;br /&gt;  visitor.visitVariable(this,arguments);&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Handles the visitation of arrays&lt;br /&gt;* @method visitArray&lt;br /&gt;* @for VisitorHandlersCollection&lt;br /&gt;* @param {Array} item the array&lt;br /&gt;* currently being visited&lt;br /&gt;* @param {ArrayLike} args an array-like&lt;br /&gt;* object that holds the values passed&lt;br /&gt;* to the originating accept function&lt;br /&gt;*/&lt;br /&gt;var visitVariable = function( item, args){&lt;br /&gt;  var other = args[1];&lt;br /&gt;  var token = args[2];&lt;br /&gt;  token.result = true;&lt;br /&gt;  /*store the matched value*/&lt;br /&gt;  item.setValue(other);&lt;br /&gt;};&lt;br /&gt;unifyVisitor.addVisitHandler("Variable",&lt;br /&gt;  visitVariable);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you look at the visitVariable function, you can see that all the variable is doing is saving a reference to the value it is being unified with and setting &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;token.result&lt;/span&gt;&lt;/span&gt; to true to indicate a unification has occurred.  Below is an example of how this simple unification could work.  In this example the variable will have a value of 13, as the c attribute is unified:&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;//exclude functions&lt;br /&gt;var v = new unifyVisitor({functions:false});&lt;br /&gt;var vari = new Variable();&lt;br /&gt;var o1 = {a:11,b:12,c:13};&lt;br /&gt;var o2 = {a:11,b:12,c:vari};&lt;br /&gt;var t = v.newToken();&lt;br /&gt;//try to unify&lt;br /&gt;v.dispatchVisit(o3,o4,t);&lt;br /&gt;//did they unify?&lt;br /&gt;if(t.result){&lt;br /&gt;  alert("Val is "+vari.getValue());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;A more complex example of overriding accept can be seen in matching an entire object base on partial results.  Unlike the variable example, the entire object partially matched will be saved.  In this example we did not need to create a visitorHandler, because the conditions argument is being used in place of the &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;MatchObject&lt;/span&gt;&lt;/span&gt; to partial match against the object trying to unifty with the MatchObject:&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;/**&lt;br /&gt;* Unifies with value that matches&lt;br /&gt;* conditions at least partially&lt;br /&gt;* @class MatchObject&lt;br /&gt;* @constructor&lt;br /&gt;* @param {object} conditions the object which&lt;br /&gt;* must be partially matched&lt;br /&gt;*/&lt;br /&gt;var MatchObject = function(conditions){&lt;br /&gt;  this.value = undefined;&lt;br /&gt;  this.conditios = conditions;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Accepts the visitor&lt;br /&gt;* @method accept&lt;br /&gt;* @param {Visitor} the visitor&lt;br /&gt;* @param {object} other the object to match&lt;br /&gt;* @param {object} token the object holding&lt;br /&gt;* additional call state&lt;br /&gt;* along to the visitVariable fuction&lt;br /&gt;*/&lt;br /&gt;MatchObject.prototype.accept = function(visitor&lt;br /&gt;  ,other,token){&lt;br /&gt;    var partial = token.partial;&lt;br /&gt;    token.partial = true;&lt;br /&gt;    /*try the match on conditions*/&lt;br /&gt;    visitor.visitObject(this.conditios,&lt;br /&gt;      arguments);&lt;br /&gt;    token.partial = partial;&lt;br /&gt;    if(token.result){&lt;br /&gt;      this.setValue(other);&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Gets the value of the MatchObject&lt;br /&gt;* @method getValue&lt;br /&gt;* @return {object} the matched value&lt;br /&gt;*/&lt;br /&gt;MatchObject.prototype.getValue = function(){&lt;br /&gt;  return this.value;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Sets the value of the MatchObject&lt;br /&gt;* @method setValue&lt;br /&gt;* @param {object} the value&lt;br /&gt;*/&lt;br /&gt;MatchObject.prototype.setValue = function(val){&lt;br /&gt;  this.value = val;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And example using it:&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;//Example data&lt;br /&gt;var data = [ {x:11,y:10},&lt;br /&gt;             {x:3,y:14},&lt;br /&gt;             {x:12,y:34},&lt;br /&gt;             {x:11,y:3},&lt;br /&gt;             {x:0,y:0}];&lt;br /&gt;/*A function that will iterate the&lt;br /&gt;* data and try to match, returning&lt;br /&gt;* a list of all matched object,&lt;br /&gt;* like a query*/&lt;br /&gt;var iterArray = function(mo,arry,viz){&lt;br /&gt;    var result = [];&lt;br /&gt;    for(var i=0;i&amp;lt;arry.length;i++){&lt;br /&gt;        var t = v.newToken();&lt;br /&gt;        //try to unify&lt;br /&gt;        v.dispatchVisit(arry[i],mo,t);&lt;br /&gt;        //if unify add to result list&lt;br /&gt;        if(t.result){&lt;br /&gt;            result.push(mo.getValue());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    return result;&lt;br /&gt;};&lt;br /&gt;var v = new unifyVisitor({final:false});&lt;br /&gt;var mo = new MatchObject({x:11});&lt;br /&gt;var itemz = iterArray(mo,data,v);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you would guess the value in itemz is:&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;[Object x=11 y=10, Object x=11 y=3]&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-7447569417203243117?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/7447569417203243117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/visitor-pattern-for-unification-via.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/7447569417203243117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/7447569417203243117'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/visitor-pattern-for-unification-via.html' title='Visitor Pattern for Unification via JavaScript'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-1507985490445661713</id><published>2008-12-11T10:17:00.000-08:00</published><updated>2008-12-12T11:57:51.281-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='YUI'/><category scheme='http://www.blogger.com/atom/ns#' term='Design Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='Visitor'/><title type='text'>Visitor Pattern for JavaScript</title><content type='html'>I find myself using some variation of the &lt;a href="http://en.wikipedia.org/wiki/Visitor_pattern"&gt;visitor pattern&lt;/a&gt; often in my JavaScript for things varying from validation of data structures to serialization/de-serialization of UI state.  It has an exaulted spot in my pattern toolbox!  The basics to the pattern is that classes have an &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(102, 51, 51);"&gt;accept&lt;/span&gt;&lt;/span&gt; function that takes a visitor.  In turn, that accept function will call the proper &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(102, 51, 51);"&gt;visit&lt;/span&gt;&lt;/span&gt; function on the visitor, passing itself in as an argument.  The visit function is described as using double dispatch to get the right object to the right handler, but to get around this in JavaScript without using conditional statements, I like to name my visit functions after the object it will be visiting.  An example would be &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="color: rgb(102, 51, 51);"&gt;visitString&lt;/span&gt;&lt;/span&gt; for a visitor function that handles visiting strings.  I find with the visitor pattern it is much easier to understand by jumping in with both feet!  I am trying out the &lt;a href="http://developer.yahoo.com/yui/yuidoc/"&gt;YUI Doc&lt;/a&gt; with this code; so, it may explain the structure of the comments.  In the following code  I have created accept functions for  some of the built-in types of JavaScript:&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;Function.prototype.accept = function(){&lt;br /&gt;var visitor = arguments[0];&lt;br /&gt;visitor.visitFunction(this,arguments);&lt;br /&gt;};&lt;br /&gt;Object.prototype.accept = function(){&lt;br /&gt;var visitor = arguments[0];&lt;br /&gt;visitor.visitObject(this,arguments);&lt;br /&gt;};&lt;br /&gt;String.prototype.accept = function(){&lt;br /&gt;var visitor = arguments[0];&lt;br /&gt;visitor.visitString(this,arguments);&lt;br /&gt;};&lt;br /&gt;Array.prototype.accept = function(){&lt;br /&gt;var visitor = arguments[0];&lt;br /&gt;visitor.visitArray(this,arguments);&lt;br /&gt;};&lt;br /&gt;Number.prototype.accept = function(){&lt;br /&gt;var visitor = arguments[0];&lt;br /&gt;visitor.visitNumber(this,arguments);&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I like to include arguments with  my visit functions.  This is not necessary, as you could have all state managed by the visitor function, but as you will see later, I like to allow registration of visitor handlers that can extend the function of the visitor without changing too much about what the visitor has to know.  You may find it cleaner to keep the visit functions pure, by only calling them with this, such as:&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;Number.prototype.accept = function(visitor){&lt;br /&gt;visitor.visitNumber(this);&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now that you see the accept functions, I will create a visitor that will use them and will generate an XML representation of these basic JavaScript types.&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;/**&lt;br /&gt;* @module XMLVisitor&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* A class implementing a variation of the&lt;br /&gt;* visitor pattern, which transforms js&lt;br /&gt;* objects into xml&lt;br /&gt;* @class xmlVisitor&lt;br /&gt;* @constructor&lt;br /&gt;*/&lt;br /&gt;var xmlVisitor = function(){&lt;br /&gt;this.reset();&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Resets the current instance in&lt;br /&gt;* preperation for visiting a new&lt;br /&gt;* root object&lt;br /&gt;* @method reset&lt;br /&gt;*/&lt;br /&gt;xmlVisitor.prototype.reset = function(){&lt;br /&gt;var obj = {};&lt;br /&gt;obj.xml = [];&lt;br /&gt;obj.indent = "";&lt;br /&gt;obj.depth = 0;&lt;br /&gt;this.token = obj;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Create a new token for carrying&lt;br /&gt;* around state&lt;br /&gt;* @method newToken&lt;br /&gt;* @return Object an object to hold&lt;br /&gt;* the state of the call&lt;br /&gt;*/&lt;br /&gt;xmlVisitor.prototype.newToken = function(){&lt;br /&gt;return this.token;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Returns the XML generated&lt;br /&gt;* from the most recent visit(s)&lt;br /&gt;* conducted by the visitor&lt;br /&gt;* @method toXML&lt;br /&gt;* @return String the xml string&lt;br /&gt;*/&lt;br /&gt;xmlVisitor.prototype.toXML = function(){&lt;br /&gt;return this.token.xml.join("\n");&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Attempts to visit an object&lt;br /&gt;* @method dispatchVisit&lt;br /&gt;* @param {Unknown} visitee the value&lt;br /&gt;* currently being visited&lt;br /&gt;* @param {Object} token an object to hold&lt;br /&gt;* additional info the visitor may need&lt;br /&gt;*/&lt;br /&gt;xmlVisitor.prototype.dispatchVisit =&lt;br /&gt;function(visitee,token){&lt;br /&gt;/* Get a new token for handling&lt;br /&gt;* state*/&lt;br /&gt;if(!token){&lt;br /&gt;   token = this.newToken();&lt;br /&gt;}&lt;br /&gt;//Hanlde null&lt;br /&gt;if(visitee==null){&lt;br /&gt;   var&lt;br /&gt;   token.xml.push(token.indent+&lt;br /&gt;      "&amp;lt;atomic type='null'/&amp;gt;");&lt;br /&gt;}&lt;br /&gt;else{&lt;br /&gt;   visitee.accept(this,token);&lt;br /&gt;}&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Registers a handler for the&lt;br /&gt;* visitation of a named item&lt;br /&gt;* @method addVisitHandler&lt;br /&gt;* @param {String} name the name of the&lt;br /&gt;* item this handler visits&lt;br /&gt;* @param {Function} handler the function&lt;br /&gt;* handling the visitation&lt;br /&gt;*/&lt;br /&gt;xmlVisitor.addVisitHandler = function( name,&lt;br /&gt;   handler ){&lt;br /&gt;xmlVisitor.prototype["visit"+name] =&lt;br /&gt;   handler;&lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Default visitor method&lt;br /&gt;* @class VisitorHandlersCollection&lt;br /&gt;* @static&lt;br /&gt;* @param {Unknown} visitee the value&lt;br /&gt;* currently being visited&lt;br /&gt;* @param {ArrayLike} args an array-like&lt;br /&gt;* object that holds the values passed&lt;br /&gt;* to the originating accept function&lt;br /&gt;*/&lt;br /&gt;var visitDefault = function(visitee,args){&lt;br /&gt;   var token = args[1];&lt;br /&gt;   //push an xml representation on the list&lt;br /&gt;   var ttype = "Unknown";&lt;br /&gt;   if(visitee.constructor==String){&lt;br /&gt;       ttype = "String";&lt;br /&gt;   }&lt;br /&gt;   else if(visitee.constructor==Number){&lt;br /&gt;      ttype = "Number";&lt;br /&gt;   }&lt;br /&gt;   token.xml.push(token.indent+&lt;br /&gt;      "&amp;lt;atomic type='"+ttype+&lt;br /&gt;      "'value='"+visitee+"'/&amp;gt;");&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt;* Handles the visitation of objects&lt;br /&gt;* Not sure how to define non-method&lt;br /&gt;* functions in YUI Doc&lt;br /&gt;* @static&lt;br /&gt;* @param {Object} item the object&lt;br /&gt;* currently being visited&lt;br /&gt;* @param {ArrayLike} args an array-like&lt;br /&gt;* object that holds the values passed&lt;br /&gt;* to the originating accept function&lt;br /&gt;*/&lt;br /&gt;var visitObject = function( item, args){&lt;br /&gt;var token = args[1];&lt;br /&gt;var indent = token.indent;&lt;br /&gt;//push opening tag&lt;br /&gt;token.xml.push(indent+"&amp;lt;Object&amp;gt;");&lt;br /&gt;token.indent = indent+"      ";&lt;br /&gt;var keyindent = indent+"   ";&lt;br /&gt;//cal accept on children&lt;br /&gt;for(var key in item){&lt;br /&gt;   var value = item[key];&lt;br /&gt;   if(item.hasOwnProperty(key) &amp;amp;&amp;amp;&lt;br /&gt;       typeof(value)!="function")&lt;br /&gt;   {&lt;br /&gt;       //push on key tag&lt;br /&gt;       token.xml.push(keyindent+&lt;br /&gt;           "&amp;lt;attribute "+&lt;br /&gt;           "name='"+key+"'&amp;gt;");&lt;br /&gt;       //push on value&lt;br /&gt;       this.dispatchVisit(value,token);&lt;br /&gt;       token.xml.push(keyindent+&lt;br /&gt;           "&amp;lt;/attribute&amp;gt;");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;token.indent = indent;&lt;br /&gt;token.xml.push(indent+"&amp;lt;/Object&amp;gt;");    &lt;br /&gt;         &lt;br /&gt;};&lt;br /&gt;/**&lt;br /&gt;* Handles the visitation of arrays&lt;br /&gt;* @static&lt;br /&gt;* @param {Array} item the array&lt;br /&gt;* currently being visited&lt;br /&gt;* @param {ArrayLike} args an array-like&lt;br /&gt;* object that holds the values passed&lt;br /&gt;* to the originating accept function&lt;br /&gt;*/&lt;br /&gt;var visitArray = function( item, args){&lt;br /&gt;var token = args[1];&lt;br /&gt;var indent = token.indent;&lt;br /&gt;token.xml.push(indent+"&amp;lt;Array&amp;gt;");&lt;br /&gt;token.indent = indent+"   ";&lt;br /&gt;for(var i=0;i&amp;lt;item.length;i++){&lt;br /&gt;   var value = item[i];&lt;br /&gt;   this.dispatchVisit(value,token);&lt;br /&gt;}&lt;br /&gt;token.indent = indent;&lt;br /&gt;token.xml.push(indent+"&amp;lt;/Array&amp;gt;");     &lt;br /&gt;        &lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;//register Handlers&lt;br /&gt;xmlVisitor.addVisitHandler("String",&lt;br /&gt;visitDefault);&lt;br /&gt;xmlVisitor.addVisitHandler("Number",&lt;br /&gt;visitDefault);&lt;br /&gt;xmlVisitor.addVisitHandler("Function",&lt;br /&gt;function(){});&lt;br /&gt;xmlVisitor.addVisitHandler("Object",&lt;br /&gt;visitObject);&lt;br /&gt;xmlVisitor.addVisitHandler("Array",visitArray);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;With the code above we can run the following test:&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;var v = new xmlVisitor();&lt;br /&gt;var val = [1,2,"three",&lt;br /&gt;{'value':4,'str':'four'}];&lt;br /&gt;v.dispatchVisit(val);&lt;br /&gt;v.toXML();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The output of the last function call would be:&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;Array&amp;gt;&lt;br /&gt;&amp;lt;atomic type='Number' value='1'/&amp;gt;&lt;br /&gt;&amp;lt;atomic type='Number' value='2'/&amp;gt;&lt;br /&gt;&amp;lt;atomic type='String' value='three'/&amp;gt;&lt;br /&gt;&amp;lt;Object&amp;gt;&lt;br /&gt; &amp;lt;attribute name='value'&amp;gt;&lt;br /&gt;   &amp;lt;atomic type='Number' value='4'/&amp;gt;&lt;br /&gt; &amp;lt;/attribute&amp;gt;&lt;br /&gt; &amp;lt;attribute name='str'&amp;gt;&lt;br /&gt;   &amp;lt;atomic type='String' value='four'/&amp;gt;&lt;br /&gt; &amp;lt;/attribute&amp;gt;&lt;br /&gt;&amp;lt;/Object&amp;gt;&lt;br /&gt;&amp;lt;/Array&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I hope this was a useful example of the Visitor pattern.  You may have noticed that to accommodate custom classes, all one would need to do is implement the accept function in that class to override what visit function would be called.  Also new functions could be registered by calling the addVisitHandler method.  If you know of other examples of visitor pattern in the JavaScript wild, please drop me a comment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-1507985490445661713?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/1507985490445661713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/vistor-pattern-for-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/1507985490445661713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/1507985490445661713'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/vistor-pattern-for-javascript.html' title='Visitor Pattern for JavaScript'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-8800128920977392591</id><published>2008-12-09T10:19:00.000-08:00</published><updated>2008-12-10T05:52:39.019-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Adapter'/><category scheme='http://www.blogger.com/atom/ns#' term='Design Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Inversion-Of-Control'/><title type='text'>Inversion-of-Control: Dependency Injection with JavaScript Part 2</title><content type='html'>When writing about Inversion of Control in my post &lt;span class="Apple-style-span" style="line-height: 25px; "&gt;&lt;a href="http://codeforthecloset.blogspot.com/2008/12/dependency-injection.html" style="text-decoration: none; font-weight: normal; display: inline !important; "&gt;&lt;span class="Apple-style-span" style="color: rgb(204, 102, 0);"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Inversion-of-Control: Dependency Injection with JavaScript&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;, I had touched upon the idea of mutators.  I did not provide an example; so, I wanted to rectify that problem.  To tie in the idea of Adaptation, I will also be using the code from my post &lt;span class="Apple-style-span" style="color: rgb(204, 102, 0); line-height: 25px; "&gt;&lt;a href="http://codeforthecloset.blogspot.com/2008/12/featurebroker-factory-function-factory.html" style="text-decoration: none; color: rgb(204, 102, 0); font-weight: normal; display: inline !important; "&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Adaptation: Adapter Design Pattern and JavaScript&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;.  If you have not read those posts, it might be worth the time to browse through them or print out the code to use as a reference. &lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;/* Adapter : Mutator function&lt;br /&gt;* returns a function that will adapt&lt;br /&gt;* a value passed into the resulting&lt;br /&gt;* function to the interface required&lt;br /&gt;* through iFace&lt;br /&gt;* iFace - the interface to adapt to*/&lt;br /&gt;var Adapter = function(iFace){&lt;br /&gt;   return function(o){&lt;br /&gt;       return AdapterRegistry.Adapt(o,iFace);&lt;br /&gt;   };&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Create adapter from IAnotherConsole&lt;br /&gt;* to IConsole*/&lt;br /&gt;var IAnotherConsole2IConsole = function(o){&lt;br /&gt;   return {&lt;br /&gt;       WriteLine : o.AlertIt&lt;br /&gt;   };&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;//Register the adapter&lt;br /&gt;AdapterRegistry.Add(IAnotherConsole,&lt;br /&gt;    IConsole,IAnotherConsole2IConsole);&lt;br /&gt;&lt;br /&gt;/* Register AnotherConsole from the Adapter&lt;br /&gt;* post, whose interface is IAnotherConsole*/&lt;br /&gt;Features.Provide("Console",AnotherConsole);&lt;br /&gt;&lt;br /&gt;var GreeterClass = function(name){&lt;br /&gt;   /* The salutation feature was defined&lt;br /&gt;    * in the IoC post*/&lt;br /&gt;   this.salutation = name+","+&lt;br /&gt;      RequiredFeature("Salutation",&lt;br /&gt;           IsTypeOf("string"));&lt;br /&gt;   this.con = RequiredFeature("Console",&lt;br /&gt;          NoAssertion,Adapter(IConsole));&lt;br /&gt;}&lt;br /&gt;GreeterClass.prototype.greet = function(){&lt;br /&gt;   this.con.WriteLine(this.salutation);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see from the above code, the &lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;con&lt;/span&gt; attribute of &lt;span class="Apple-style-span" style="color: rgb(51, 102, 255);"&gt;GreeterClasss&lt;/span&gt; is provided by &lt;span class="Apple-style-span" style="color: rgb(51, 102, 255);"&gt;AnotherConsole&lt;/span&gt;.  AnotherConsole implements the &lt;span class="Apple-style-span" style="color: rgb(51, 102, 255);"&gt;IAnotherConsole&lt;/span&gt; interface, while GreeterClass expects a &lt;span class="Apple-style-span" style="color: rgb(51, 102, 255);"&gt;IConsole&lt;/span&gt; interface.  To Achieve this, we pass in the &lt;span class="Apple-style-span" style="color: rgb(51, 102, 255);"&gt;Adapt&lt;/span&gt; mutator, which will return an object of the IConsole interface using the &lt;span class="Apple-style-span" style="color: rgb(51, 102, 255);"&gt;AdapterRegistry&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;From looking at the code above, you might have noticed that I used &lt;span class="Apple-style-span" style="color: rgb(51, 102, 255);"&gt;NoAssertion&lt;/span&gt;, an always-true assertion.  To enforce the IConsole interface, I could have used the &lt;span class="Apple-style-span" style="color: rgb(51, 102, 255);"&gt;DoesImplement&lt;/span&gt; function from the Adapter post.  With that function we could enforce the interface through the required feature as below:&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;   this.con = RequiredFeature("Console",&lt;br /&gt;          DoesImplement(IConsole),Adapter(IConsole));&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-8800128920977392591?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/8800128920977392591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/inversion-of-control-dependency.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/8800128920977392591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/8800128920977392591'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/inversion-of-control-dependency.html' title='Inversion-of-Control: Dependency Injection with JavaScript Part 2'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-3222755272470475346</id><published>2008-12-09T08:14:00.001-08:00</published><updated>2008-12-09T08:39:00.922-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Signals and Slots'/><title type='text'>Signals and Slots for JavaScript</title><content type='html'>&lt;a href="http://trolltech.com/products"&gt;Qt&lt;/a&gt; implements a message decoupling approach called &lt;a href="http://doc.trolltech.com/3.3/signalsandslots.html"&gt;Signals and Slots&lt;/a&gt; (S&amp;amp;S).  I am not very familiar with S&amp;amp;S, but the idea sounded interesting, and I wanted to see what it would look like in JavaScript.  As far as I could determine from here, the S&amp;amp;S approach registers a receiver and its function (slot) to a sender and a method (signal).  The Signal has no real implementation on the programmer's side, except in defining a name as a signal.  Using the convertArguments function from &lt;span class="Apple-style-span" style="color: rgb(204, 102, 0);  line-height: 25px; "&gt;&lt;a href="http://codeforthecloset.blogspot.com/2008/12/dependency-injection.html" style="text-decoration: none; color: rgb(204, 102, 0); font-weight: normal; display: inline !important; "&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Inversion-of-Control: Dependency Injection with JavaScript&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;, I implemented Signals with a factory function, Signal, and created a connect function to align them with slots.&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;/* Signal : Factory Function&lt;br /&gt;* Returns a function that has methods&lt;br /&gt;* for connecting and disconnecting functions&lt;br /&gt;* from it.&lt;br /&gt;* When the function is invoked, the invocation&lt;br /&gt;* is dispatched to each of the registered&lt;br /&gt;* functions&lt;br /&gt;* stateful - if the calling scope should be&lt;br /&gt;*    passed on to&lt;br /&gt;*    underlying dispatches. */&lt;br /&gt;var Signal = function (stateful){&lt;br /&gt;   var slots = [];&lt;br /&gt;   /* _signal : Proxy Function&lt;br /&gt;    * acts as a multicast proxy to the&lt;br /&gt;    * functions connected to it,&lt;br /&gt;    * passing along the arguments it was&lt;br /&gt;    * invoked with */  &lt;br /&gt;   var _signal = function()&lt;br /&gt;   {&lt;br /&gt;       var arglist = [];&lt;br /&gt;       if(stateful)&lt;br /&gt;           arglist.push(this);&lt;br /&gt;       convertArguments(arguments,0,arglist);&lt;br /&gt;       for(var j=0;j&amp;lt;slots.length;j++){&lt;br /&gt;           var obj = slots[j][0];&lt;br /&gt;           if(obj==undefined)&lt;br /&gt;               obj = this;&lt;br /&gt;           var fun = slots[j][1];&lt;br /&gt;           try{&lt;br /&gt;               fun.apply(obj,arglist);&lt;br /&gt;           }catch(e){}&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;   /* _signal.connect: Function&lt;br /&gt;   * Connects a function and the scope to be&lt;br /&gt;   * called when the signal is invoked.&lt;br /&gt;   * fun - The function to be invoked on&lt;br /&gt;   *    signal.&lt;br /&gt;   * obj - The scope&lt;br /&gt;   */&lt;br /&gt;   _signal.connect = function(fun,scope)&lt;br /&gt;   {&lt;br /&gt;       slots.push( [scope,fun] );&lt;br /&gt;   }&lt;br /&gt;   /*  _signal.disconnect: Function&lt;br /&gt;   * Disconnects a matching function from a&lt;br /&gt;   * signal.&lt;br /&gt;   * fun - The function to be removed.&lt;br /&gt;   * obj - The scope&lt;br /&gt;   */&lt;br /&gt;   _signal.disconnect = function(fun,scope)&lt;br /&gt;   {&lt;br /&gt;       var shift=false;&lt;br /&gt;       for(var i=0; i&amp;lt;slots.length;i++){&lt;br /&gt;           if(shift)&lt;br /&gt;               slots[i-1]=slots[i];&lt;br /&gt;           else if(scope==slots[i][0] &amp;amp;&amp;amp;&lt;br /&gt;    fun==slots[i][1])shift=true;&lt;br /&gt;       }&lt;br /&gt;       if(shift)&lt;br /&gt;           slots.pop();&lt;br /&gt;   }&lt;br /&gt;   _signal.disconnect_all = function()&lt;br /&gt;   {&lt;br /&gt;       var slen = slots.length;&lt;br /&gt;       for(var i=0;i&amp;lt;slen;i++)&lt;br /&gt;       {&lt;br /&gt;           slots.pop();&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;   return _signal;&lt;br /&gt;};&lt;br /&gt;/* Connect : Helper function&lt;br /&gt;* connects a sender to a reciever&lt;br /&gt;* through a signal and slot&lt;br /&gt;* sender - the object which will send&lt;br /&gt;*      the signal.&lt;br /&gt;* signal - string name representing&lt;br /&gt;*      the signal&lt;br /&gt;* rec - object to recieve the&lt;br /&gt;*      signal notification.&lt;br /&gt;* slot - a string that will be used&lt;br /&gt;*      to look up the same named attr&lt;br /&gt;*      on rec, which should be a&lt;br /&gt;*      function.  The function gets&lt;br /&gt;*      the arguments passed to the&lt;br /&gt;*      signal.  If stateful, the&lt;br /&gt;*      first argument will be the&lt;br /&gt;*      scope of the connect call.*/&lt;br /&gt;var Connect = function(sender,signal,&lt;br /&gt;       rec,slot){&lt;br /&gt;   var sigf;&lt;br /&gt;   var err = null;&lt;br /&gt;   if(sender[signal]==undefined){&lt;br /&gt;       sigf = Signal(true);&lt;br /&gt;       sender[signal] = sigf;&lt;br /&gt;   }else{&lt;br /&gt;       if(!sender[signal].connect){&lt;br /&gt;           err="No Signal "+signal;&lt;br /&gt;           throw new Error(err);&lt;br /&gt;       }&lt;br /&gt;       else{&lt;br /&gt;           sigf = sender[signal];&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;   var slot_type = typeof(slot);&lt;br /&gt;   var rec_type = typeof(rec);&lt;br /&gt;   if(rec){&lt;br /&gt;       var slotf = rec[slot];&lt;br /&gt;       if(typeof(slotf)=="function"){&lt;br /&gt;           sigf.connect(slotf,rec);&lt;br /&gt;           return;&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;   err = "Bad Slot";&lt;br /&gt;   throw new Error(err);&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Using an &lt;a href="http://doc.trolltech.com/3.3/signalsandslots.html"&gt;example from the Qt website&lt;/a&gt;, we can see how this would be used in javascript compared to how it is used in C++.&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;var Foo = function(){&lt;br /&gt;   this.val = null;&lt;br /&gt;}&lt;br /&gt;Foo.prototype.value = function(){&lt;br /&gt;    return this.val;&lt;br /&gt;}&lt;br /&gt;Foo.prototype.setValue = function(value){&lt;br /&gt;    if(this.val!=value){&lt;br /&gt;        this.val = value;&lt;br /&gt;        this.valueChanged(value);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;Foo.prototype.valueChanged = Signal(false);&lt;br /&gt;&lt;br /&gt;var a = new Foo();&lt;br /&gt;var b = new Foo();&lt;br /&gt;Connect(a,"valueChanged",b,"setValue");&lt;br /&gt;a.setValue(45);&lt;br /&gt;alert(a.value()==b.value());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I did not implement a disconnect helper function, but since the signal supports disconnect, it should be trivial to introduce one.  I did add create a signal within the Connect helper if one did not exist, and made the signal stateful, meaning the calling context of the signal would be inserted at index 0 into the arguments passed along to the slots.  This could be a way to use this approach with objects that were constructed in another framework, for instance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-3222755272470475346?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/3222755272470475346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/signals-and-slots-for-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/3222755272470475346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/3222755272470475346'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/signals-and-slots-for-javascript.html' title='Signals and Slots for JavaScript'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-3407560610028085821</id><published>2008-12-08T11:08:00.000-08:00</published><updated>2008-12-08T11:53:15.091-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Namespace'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Python Namespaces</title><content type='html'>&lt;span class="Apple-style-span"   style="color: rgb(167, 166, 170);   font-style: italic; line-height: 15px; font-family:Verdana;font-size:11px;"&gt;Thomas Herchenröder&lt;/span&gt;, wrote a cool approach to using namespaces in python, &lt;a href="http://news.qooxdoo.org/name-spaces-in-python-using-__getattr__"&gt;Name spaces in Python using __getattr__&lt;/a&gt;. He covers the existing methods in Python for namespacing, such as modules/packages.  I am not sure how or where I would use Namespaces, but it tickled my python-bone.  I played with the idea and hacked in a way to share namespaces across modules.  The code below has not been tested, much /grin.  I recommend you reading the original post by Thomas.  This is me foolin around! &lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;import threading&lt;br /&gt;reg_lock = threading.RLock()&lt;br /&gt;&lt;br /&gt;class NameSpace(object):&lt;br /&gt;#for multithreading&lt;br /&gt;registry = {}&lt;br /&gt;def __new__(typ, ns_name, *args, **kw):&lt;br /&gt;   reg_lock.acquire()&lt;br /&gt;   last_obj = typ.registry.get(ns_name)&lt;br /&gt;   if last_obj==None:&lt;br /&gt;       namelist = ns_name.split(".")&lt;br /&gt;       cnl = []         &lt;br /&gt;       registry = typ.registry&lt;br /&gt;       for name in namelist:&lt;br /&gt;           cnl.append(name)&lt;br /&gt;           current_name = ".".join(cnl)&lt;br /&gt;           obj = registry.get(name)&lt;br /&gt;           if obj==None:&lt;br /&gt;               obj = object.__new__(typ)&lt;br /&gt;               registry[current_name]=obj&lt;br /&gt;               obj.__ns__ = current_name&lt;br /&gt;               if last_obj:&lt;br /&gt;                   setattr(last_obj,name,obj)&lt;br /&gt;           last_obj = obj&lt;br /&gt;   reg_lock.release()&lt;br /&gt;   return last_obj&lt;br /&gt;def __getattribute__(self,name):&lt;br /&gt;   reg_lock.acquire()&lt;br /&gt;   try:&lt;br /&gt;       p = object.__getattribute__(self,name)&lt;br /&gt;   except:&lt;br /&gt;       p = NameSpace("%s.%s"%(self.__ns__,name))&lt;br /&gt;   reg_lock.release()&lt;br /&gt;   return p&lt;br /&gt;&lt;br /&gt;cool_example = NameSpace("cool.example")&lt;br /&gt;cool = NameSpace("cool")&lt;br /&gt;cool_example2 = cool.example&lt;br /&gt;print cool_example == cool_example2&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-3407560610028085821?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/3407560610028085821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/python-namespaces.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/3407560610028085821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/3407560610028085821'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/python-namespaces.html' title='Python Namespaces'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-2803346823362003525</id><published>2008-12-05T07:45:00.000-08:00</published><updated>2008-12-08T11:29:59.422-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Design Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='Inversion-Of-Control'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Inversion-of-Control: Dependency Injection with JavaScript</title><content type='html'>A few weeks ago I found a nifty python implementation of Inversion of Control, called &lt;a href="http://code.activestate.com/recipes/413268/"&gt;Dependency Injection The Python Way&lt;/a&gt;, and I thought it would be interesting to do something similar for JavaScript.  The code below is a translation of that implementation.  I have added the addition of a mutator to the RequiredFeature, as I cannot resist fooling around.  It might be best to remove that, as it makes the function carry on extra duties.  I will leave it in, as I have fun with it.  I will leave the mutator subject with defining a mutator as a function that will be called with the resulting feature and having its return value assigned as the feature, giving the function the opportunity to mutate the result.  This post will not cover mutators. &lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;/* convertArguments : Utility Function&lt;br /&gt; * copies array A starting at index i&lt;br /&gt; * into existing array R, or new R if undefined */&lt;br /&gt;var convertArguments = function(A,i,R){&lt;br /&gt;    if(R==undefined){&lt;br /&gt;        R = [];&lt;br /&gt;    }&lt;br /&gt;    for(;i&amp;lt;A.length;i++){&lt;br /&gt;        R.push(A[i]);&lt;br /&gt;    }&lt;br /&gt;    return R;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* FeatureBroker : Factory Function&lt;br /&gt; * Factory for a feature broker that provides &lt;br /&gt; * methods to register and lookup a provider&lt;br /&gt; * allowReplace - bool indicating if features &lt;br /&gt; * can be overwrote by providers registering &lt;br /&gt; * to provide the same feature */&lt;br /&gt;FeatureBroker = function(allowReplace){&lt;br /&gt;    var providers = {};&lt;br /&gt;    return {&lt;br /&gt;        /* Provide: Method of FeatureBroker&lt;br /&gt;         * Function to register a feature &lt;br /&gt;         * provider.&lt;br /&gt;         * feature - a string representing the &lt;br /&gt;         * feature being provided&lt;br /&gt;         * provider - the function which will &lt;br /&gt;         *        provide the feature or&lt;br /&gt;         *        a value representing the &lt;br /&gt;         *        feature&lt;br /&gt;         * scope - the scope in which to call &lt;br /&gt;         *        the providing function&lt;br /&gt;         * ... - any additional arguments get &lt;br /&gt;         *       passed as arguments&lt;br /&gt;         *       to the provider function */&lt;br /&gt;        Provide : function(feature, provider, &lt;br /&gt;            scope){&lt;br /&gt;            if(!self.allowReplace &amp;amp;&amp;amp; &lt;br /&gt;                providers[feature]!=undefined){&lt;br /&gt;                throw new &lt;br /&gt;                   Error("Duplicate: "+feature);&lt;br /&gt;            }&lt;br /&gt;            var call;&lt;br /&gt;            if(typeof(provider)=="function"){&lt;br /&gt;                var args = convertArguments(&lt;br /&gt;                           arguments,3);&lt;br /&gt;                /* call : Closure of Provide&lt;br /&gt;                 * Invokes the callable provider&lt;br /&gt;                 */&lt;br /&gt;                call = function(){&lt;br /&gt;                    return provider.apply(&lt;br /&gt;                                scope,args);&lt;br /&gt;                }&lt;br /&gt;            }else{&lt;br /&gt;                /* call : Closure of Provide&lt;br /&gt;                 * returns the value of provider&lt;br /&gt;                 */&lt;br /&gt;                call = function(){&lt;br /&gt;                    return provider;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            providers[feature] = call;&lt;br /&gt;        },&lt;br /&gt;        /* Lookup: Method of FeatureBroker&lt;br /&gt;         * Function to lookup a feature &lt;br /&gt;         * provider.&lt;br /&gt;         * feature - a string representing the&lt;br /&gt;         * feature being provided*/&lt;br /&gt;        Lookup : function(feature){&lt;br /&gt;            var provider = providers[feature];&lt;br /&gt;            if(provider!=undefined){&lt;br /&gt;                return provider();&lt;br /&gt;            }else{&lt;br /&gt;                throw new &lt;br /&gt;                   Error("Unknown:"+feature);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;var Features = FeatureBroker(false);&lt;br /&gt;&lt;br /&gt;//No-Op functions&lt;br /&gt;var NoMutation = function(o){ return o; }&lt;br /&gt;var NoAssertion = function(o){ return true; }&lt;br /&gt;&lt;br /&gt;/* RequiredFeature : Factory Function&lt;br /&gt; * feature - a string representing the feature &lt;br /&gt; *          being required&lt;br /&gt; * assertion - a function acting as a constraint&lt;br /&gt; *          to test the result of the provided &lt;br /&gt; *          result&lt;br /&gt; * mutator - a function that mutates a provided&lt;br /&gt; *          feature */&lt;br /&gt;var RequiredFeature = function(feature,&lt;br /&gt;                       assertion,mutator){&lt;br /&gt;    assertion = assertion || NoAssertion;&lt;br /&gt;    mutator = mutator || NoMutation;&lt;br /&gt;    var value = Features.Lookup(feature);&lt;br /&gt;    if(!assertion(value)){&lt;br /&gt;        throw new &lt;br /&gt;              Error(feature+" fails criteria");&lt;br /&gt;    }&lt;br /&gt;    return mutator(value);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now to define an example assertion:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;/* IsTypeOf : Factory that returns an Example&lt;br /&gt; * Assertion Function&lt;br /&gt; * Tests the typeof call on the value&lt;br /&gt; * type_str - string representation of the type &lt;br /&gt; *                    (e.g. "string")&lt;br /&gt; */&lt;br /&gt;var IsTypeOf = function(type_str){&lt;br /&gt;    /* Anonymous Function&lt;br /&gt;     * Tests the typeof call on the value&lt;br /&gt;     * o - feature result being tested */&lt;br /&gt;    return function(o){&lt;br /&gt;        return typeof(o)==type_str;&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Using this code provides a way to design components without assuming too much about what tools they use to perform the duties of the component, such as a CSS selector implementation.  An example of this:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;//Define the providers somewhere in your glue code&lt;br /&gt;//Set the Application Node Feature&lt;br /&gt;Features.Provide("ApplicationNode","#appNode");&lt;br /&gt;//Register Sizzle to provide CSS selection&lt;br /&gt;Features.Provide("CSS_Selector",Sizzle);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*Create something that uses the Features in&lt;br /&gt; * later code */&lt;br /&gt;var AppHelper = function(){&lt;br /&gt;    this.selectionString = &lt;br /&gt;         RequiredFeature("ApplicationNode",&lt;br /&gt;                       IsTypeOf("string"));&lt;br /&gt;    this.selectionFunction = &lt;br /&gt;         RequiredFeature("CSS_Selector",&lt;br /&gt;                       IsTypeOf("function"));&lt;br /&gt;}&lt;br /&gt;AppHelper.prototype.selectApp = function(){&lt;br /&gt;    return &lt;br /&gt;       this.selectionFunction(this.selectionString)[0];&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;//use the class&lt;br /&gt;var helper = new AppHelper();&lt;br /&gt;var appNode = helper.selectApp();&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-2803346823362003525?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/2803346823362003525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/dependency-injection.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/2803346823362003525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/2803346823362003525'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/dependency-injection.html' title='Inversion-of-Control: Dependency Injection with JavaScript'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6857714793830341639.post-6565806779780058885</id><published>2008-12-05T06:26:00.000-08:00</published><updated>2008-12-09T10:29:46.641-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Adapter'/><category scheme='http://www.blogger.com/atom/ns#' term='Design Patterns'/><title type='text'>Adaptation: Adapter Design Pattern and JavaScript</title><content type='html'>Adaptation is something I find interesting as a tool to decouple your own code.  It can also be used to bring differing libraries and frameworks together in your glue code.  Below is an implementation of an Adapter Registry that allows functions performing adaptation to register for interfaces which they adapt from and to.  The implementation of the interface code is from that discussed in &lt;a href="http://jsdesignpatterns.com/"&gt;Pro JavaScript Design Patterns,&lt;/a&gt; in chapter two.  The code samples are downloadable from the books link.  In the &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;DoesImplement&lt;/span&gt;&lt;/span&gt; function, below, the &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;Interface.ensureImplements&lt;/span&gt;&lt;/span&gt; is implemented in the chapter two code.&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;var DoesImplement = function(obj,iFace){&lt;br /&gt;  try{&lt;br /&gt;      Interface.ensureImplements(obj, iFace);&lt;br /&gt;      return true;&lt;br /&gt;  }catch(ex){&lt;br /&gt;      return false;&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/* AdapterRegistry : Singleton&lt;br /&gt;* Provides facilities for registering&lt;br /&gt;* and looking up adapters */&lt;br /&gt;var AdapterRegistry = (function(){&lt;br /&gt;  var registry = [];//private&lt;br /&gt;  return {&lt;br /&gt;      /* Add : Method of AdapterRegistry&lt;br /&gt;       * Provides facilities for registering&lt;br /&gt;       * an adaptation&lt;br /&gt;       * from_ - the Interface being adapted&lt;br /&gt;       * to_ - the Interface of the adaptation&lt;br /&gt;       * adapter - the function that performs&lt;br /&gt;       *  the adaptation&lt;br /&gt;       */&lt;br /&gt;      Add : function(from_,to_,adapter){&lt;br /&gt;          registry.push( { 'from_' : from_,&lt;br /&gt;                           'to_' : to_,&lt;br /&gt;                           'adapter' : adapter&lt;br /&gt;                       } );&lt;br /&gt;      },&lt;br /&gt;      /* Adapt : Method of AdapterRegistry&lt;br /&gt;       * Adapts an object to a given interface&lt;br /&gt;       * obj - the object being adapted&lt;br /&gt;       * to_ - the Interface the object should&lt;br /&gt;       * adapt to&lt;br /&gt;       */&lt;br /&gt;      Adapt : function(obj,to_){&lt;br /&gt;          if(DoesImplement(obj,to_)){&lt;br /&gt;              return obj;&lt;br /&gt;          }&lt;br /&gt;          for(var i=0;i&amp;lt;registry.length;i++){&lt;br /&gt;              var entry = registry[i];&lt;br /&gt;              if(to_==entry.to_){&lt;br /&gt;                  if(DoesImplement(obj,&lt;br /&gt;                              entry.from_)){&lt;br /&gt;                     return entry.adapter(obj);&lt;br /&gt;                  }&lt;br /&gt;              }&lt;br /&gt;          }&lt;br /&gt;          throw new&lt;br /&gt;               Error("No Adaptation Found");&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Using the Interface implementation from Pro JavaScript Design Patterns, we can see an example of adaptation of a simple class:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="jscript"&gt;&lt;br /&gt;/* Example Interface */&lt;br /&gt;var IConsole = new Interface("IConsole",&lt;br /&gt;      ["WriteLine"]);&lt;br /&gt;/* Example Interface */&lt;br /&gt;var IAnotherConsole = new Interface(&lt;br /&gt;      "IAnotherConsole", ["AlertIt"]);&lt;br /&gt;&lt;br /&gt;//Impliments IAnotherConsole&lt;br /&gt;var aConsole = { &lt;br /&gt;     AlertIt: function(val){ &lt;br /&gt;          alert(val); &lt;br /&gt;     } };&lt;br /&gt;&lt;br /&gt;var adaptIAnotherConsoleToIConsole = function(o){&lt;br /&gt;    return {&lt;br /&gt;        WriteLine : o.AlertIt&lt;br /&gt;    };&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;//Register the adapter&lt;br /&gt;AdapterRegistry.Add(IAnotherConsole,&lt;br /&gt;      IConsole,adaptIAnotherConsoleToIConsole);&lt;br /&gt;//Use the adapter&lt;br /&gt;AdapterRegistry.Adapt(aConsole,&lt;br /&gt;      IConsole).WriteLine("Hey!");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As you can see in the example, without recreating the wheel, you can provide glue between different interfaces/libraries/frameworks using an approach like this one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6857714793830341639-6565806779780058885?l=codeforthecloset.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforthecloset.blogspot.com/feeds/6565806779780058885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/featurebroker-factory-function-factory.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/6565806779780058885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6857714793830341639/posts/default/6565806779780058885'/><link rel='alternate' type='text/html' href='http://codeforthecloset.blogspot.com/2008/12/featurebroker-factory-function-factory.html' title='Adaptation: Adapter Design Pattern and JavaScript'/><author><name>Mike Webb</name><uri>http://www.blogger.com/profile/12548092378697267864</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
