<?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-7169950164568476037</id><updated>2012-02-16T02:00:28.499-08:00</updated><category term='javascript'/><title type='text'>Lifeslave</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://lifeslave.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7169950164568476037/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://lifeslave.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>anaik</name><uri>http://www.blogger.com/profile/18142318504544854123</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>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7169950164568476037.post-7651523202835145175</id><published>2008-12-11T06:24:00.000-08:00</published><updated>2009-06-02T23:09:36.917-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>Make hot curry using Javascript</title><content type='html'>Being originally a Java developer, the only Javascript that I used to write (during those days) was to validate web application forms. But I have come to realize that Javascript is an extremely powerful language. One example is&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Currying"&gt;currying&lt;/a&gt;.  A lot of people have written curry functions for various purposes, mainly callback functions for events. I wrote a generic curry function some time ago that can be used in any scenario where callbacks are required.&lt;br /&gt;&lt;br /&gt;So here's a recipe for a hot curry:&lt;br /&gt;Ingredients: Javascript, A pinch of mojo&lt;br /&gt;&lt;br /&gt;&lt;pre style="overflow:auto; height:540px;" class="prettyprint lang-js"&gt;&lt;br /&gt;/**&lt;br /&gt; * Changes the scope of function "fn" to the "scope" parameter specified or&lt;br /&gt; * if not, defaults to window scope. The scope of the function determines what&lt;br /&gt; * "this" keyword evaluates to, inside the function "fn". Any additional arguments&lt;br /&gt; * specified in this are passed to the underlying "curried" function. If the underlying&lt;br /&gt; * function is already passed some arguments, the optional arguments are appended&lt;br /&gt; * to the argument array of the underlying function. &lt;br /&gt; * You can pass any number of arguments that are passed to the underlying (curried) function&lt;br /&gt; *&lt;br /&gt; * @param fn {Function} The function to curry&lt;br /&gt; * @param scope {Object} The scope to be set inside the curried function, if&lt;br /&gt; *              not specified, defaults to window&lt;br /&gt; * @param args... Any other optional arguments ot be passed to the curried function&lt;br /&gt; * @author anaik&lt;br /&gt; */&lt;br /&gt;function $curry(fn, scope /*, opt arguments */) {&lt;br /&gt;   scope = scope || window;&lt;br /&gt;   var actualArgs = arguments;&lt;br /&gt;   &lt;br /&gt;   return function() {&lt;br /&gt;      var args = [];&lt;br /&gt;      for(var j = 0; j &lt; arguments.length; j++) {&lt;br /&gt;         args.push(arguments[j]);&lt;br /&gt;      }&lt;br /&gt;      for(var i = 2; i &lt; actualArgs.length; i++) {&lt;br /&gt;         args.push(actualArgs[i]);&lt;br /&gt;      }&lt;br /&gt;      return fn.apply(scope, args);&lt;br /&gt;   };&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Consider the following "class" Person. The getName method refers to other instance methods of the same class. Hence the "this" keyword inside this function refers to the Person instance.&lt;br /&gt;&lt;pre style="overflow:auto; height:280px;" class="prettyprint lang-js"&gt;&lt;br /&gt;function Person(firstName, lastName)   {&lt;br /&gt;    var fname = firstName;&lt;br /&gt;    var lname = lastName;&lt;br /&gt;    return {&lt;br /&gt;        getName: function(separator)  {&lt;br /&gt;            return this.getFirstName() + separator + this.getLastName();&lt;br /&gt;        },&lt;br /&gt;        getFirstName: function()   {&lt;br /&gt;            return fname;&lt;br /&gt;        },&lt;br /&gt;        getLastName: function() {&lt;br /&gt;            return lname&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But if you call this function on the click of a button like this:&lt;br /&gt;&lt;pre style="overflow:auto; height:65px;" class="prettyprint lang-js"&gt;&lt;br /&gt;var btn = document.getElementById("mybutt");&lt;br /&gt;btn.onclick = person.getName;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The "this" reference changes to the button instance since it was attached as the onclick event handler for this button. In this case the method getName fails with error. To avoid this and preserve the "this" reference inside getName to the person instance we will "curry" this function like so:&lt;br /&gt;&lt;pre style="overflow:auto; height:65px;" class="prettyprint lang-js"&gt;&lt;br /&gt;var btn = document.getElementById("mybutt");&lt;br /&gt;btn.onclick = $curry(person.getName, person);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But how would you pass the "separator" argument? Like this:&lt;br /&gt;&lt;pre style="overflow:auto; height:65px;" class="prettyprint lang-js"&gt;&lt;br /&gt;var btn = document.getElementById("mybutt");&lt;br /&gt;btn.onclick = $curry(person.getName, person, ", ");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So there you go, we now have a generic curry that tastes good with everything javascript.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7169950164568476037-7651523202835145175?l=lifeslave.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lifeslave.blogspot.com/feeds/7651523202835145175/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7169950164568476037&amp;postID=7651523202835145175' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7169950164568476037/posts/default/7651523202835145175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7169950164568476037/posts/default/7651523202835145175'/><link rel='alternate' type='text/html' href='http://lifeslave.blogspot.com/2008/12/how-to-make-hot-curry-using-javascript.html' title='Make hot curry using Javascript'/><author><name>anaik</name><uri>http://www.blogger.com/profile/18142318504544854123</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-7169950164568476037.post-503620006783767787</id><published>2008-12-05T10:45:00.000-08:00</published><updated>2009-06-02T23:07:17.241-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>Publish Subscribe in Javascript</title><content type='html'>Recently, I came across a &lt;a href="http://ajaxian.com/archives/using-html-5-postmessage"&gt;couple&lt;/a&gt; &lt;a href="http://ajaxian.com/archives/decoupling-data-and-ui-layers-with-pubsub-architecture"&gt;of&lt;/a&gt; articles on Ajaxian that reminded me of an implementation I had written a few of months back. This can be easily extended to implement the HTML5 "postMessage" functionality in browsers not supporting HTML5 (I am working on this currently). Additionally, with a little additions, this library can be also used to implement asynchronous comet-like messages from the sever. Here's a sample usage code for the library usage and the library itself:&lt;br /&gt;&lt;br /&gt;Usage:&lt;br /&gt;&lt;pre style="overflow:auto; height:400px;" class="prettyprint lang-js"&gt;&lt;br /&gt;&lt;br /&gt;/* &lt;br /&gt; * Subscribe to all the channels. Subscriptions can be wildcards e.g.&lt;br /&gt; * "/foo/bar"   : Subscribes to the channel /foo/bar only&lt;br /&gt; * "/foo/bar/*"  : Subscribes to the channel all the children of /foo/bar/ e.g. /foo/bar/baz, /foo/bar/buz but not /foo/bar/baz/boo&lt;br /&gt; * "/foo/bar/**" : Subscribes to all the descentends of /foo/bar/ e.g. /foo/bar/baz, /foo/bar/baz/boo, /foo/bar/bar/baz/boo&lt;br /&gt; * Below, we shall receive all the messages to all the channels&lt;br /&gt; */&lt;br /&gt;jaf.core.MessageBus.subscribe("/**", function(objMsg, strChannel) {&lt;br /&gt;  alert(strChannel + ": " + objMsg);&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * To publish a message, just call the MessageBus's publish method like so:&lt;br /&gt; */&lt;br /&gt;jaf.core.MessageBus.publish("/foo/bar", {&lt;br /&gt;   name: "MessageName",&lt;br /&gt;   messageHeader: "This is a header string but can be any object",&lt;br /&gt;   body: "This is body but can be any arbitrary object"&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Library:&lt;br /&gt;&lt;pre style="overflow:auto; height:700px;" class="prettyprint lang-js"&gt;&lt;br /&gt;/**&lt;br /&gt; * Copyright: &lt;a href="mailto:aniketn3@gmail.com"&gt;Aniket Naik&lt;/a&gt;&lt;br /&gt; * From the "jaf"&lt;br /&gt; * &lt;br /&gt; */&lt;br /&gt;// create a jaf.core namespace&lt;br /&gt;// jaf.namespace("jaf.core");&lt;br /&gt;&lt;br /&gt;var jaf = {};&lt;br /&gt;jaf.core = {};&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * @class&lt;br /&gt; * This class contains utility functions required throughout the framework&lt;br /&gt; */&lt;br /&gt;jaf.core.Util = function()   {&lt;br /&gt;   /** @scope jaf.core.Util */&lt;br /&gt;   return   {&lt;br /&gt;      /**&lt;br /&gt;       * Trims the white spaces from the begining of the specified String&lt;br /&gt;       * @param {String} s The String to trim&lt;br /&gt;       * @return The "left trimmed" string&lt;br /&gt;       */&lt;br /&gt;      ltrim: function(s) {&lt;br /&gt;         return s.replace(/(^\s+)/g, "");   &lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Trims the white spaces from the end of the specified String&lt;br /&gt;       * @param {String} s The String to trim&lt;br /&gt;       * @return The "right trimmed" string&lt;br /&gt;       */&lt;br /&gt;      rtrim: function(s) {&lt;br /&gt;         return s.replace(/\s+$/g, "");   &lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Trims the white spaces from the begining and the end of the specified String&lt;br /&gt;       * @param {String} s The String to trim&lt;br /&gt;       * @return The "trimmed" string&lt;br /&gt;       */&lt;br /&gt;      trim: function(s) {&lt;br /&gt;         return s.replace(/(^\s+)|\s+$/g, "");   &lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Gets whether the specified String &lt;tt&gt;s&lt;/tt&gt; starts with the given String&lt;br /&gt;       * &lt;tt&gt;strSearch&lt;/tt&gt;&lt;br /&gt;       * @param {String} s The string to search&lt;br /&gt;       * @param {String} strSearch The search String&lt;br /&gt;       * @return true if &lt;tt&gt;s&lt;/tt&gt; starts with &lt;tt&gt;strSearch&lt;/tt&gt;&lt;br /&gt;       * @see endsWith(String, String)&lt;br /&gt;       */&lt;br /&gt;      startsWith: function(s, strSearch)  {&lt;br /&gt;         return s.indexOf(strSearch) == 0;&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      hasOwnProperty: function(object, property)   {&lt;br /&gt;         if(object.hasOwnProperty)  {&lt;br /&gt;            return object.hasOwnProperty(property);&lt;br /&gt;         }&lt;br /&gt;         var prop = object[property];&lt;br /&gt;         return typeof(pro) !== "undefined" &amp;&amp; prop !== object.constructor.prototype[property];&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Gets whether the specified String &lt;tt&gt;s&lt;/tt&gt; ends with the given String&lt;br /&gt;       * &lt;tt&gt;strSearch&lt;/tt&gt;&lt;br /&gt;       * @param {String} s The string to search&lt;br /&gt;       * @param {String} strSearch The search String&lt;br /&gt;       * @return true if &lt;tt&gt;s&lt;/tt&gt; ends with &lt;tt&gt;strSearch&lt;/tt&gt;&lt;br /&gt;       * @see startsWith(String, String)&lt;br /&gt;       */&lt;br /&gt;      endsWith: function(s, strSearch)   {&lt;br /&gt;         if(s.indexOf(strSearch) == -1)   {&lt;br /&gt;            return false;&lt;br /&gt;         }&lt;br /&gt;         return (s.lastIndexOf(strSearch) + strSearch.length) == s.length;&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Gets the string representation of the specified object. This method is &lt;br /&gt;       * used for debugging&lt;br /&gt;       * @param {Object} Object to convert to string&lt;br /&gt;       * @return {String} The string representation of the object&lt;br /&gt;       */&lt;br /&gt;      toObjectSource: function(obj)   {&lt;br /&gt;         if(obj == null)   {&lt;br /&gt;            return "[null]";&lt;br /&gt;         }&lt;br /&gt;         if(obj == undefined) {&lt;br /&gt;            return "[undefined]";&lt;br /&gt;         }&lt;br /&gt;         &lt;br /&gt;         var str = "[";&lt;br /&gt;         var member = null;&lt;br /&gt;         for(var each in obj) {&lt;br /&gt;            member = obj[each];&lt;br /&gt;            str += each + "=" + member + ", "&lt;br /&gt;         }&lt;br /&gt;         return str + "]";&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Gets all the keys (properties) of the given object as an array&lt;br /&gt;       * @param {Object} obj The object to retrieve keys&lt;br /&gt;       * @param {Array} Properties of the object as an array&lt;br /&gt;       */&lt;br /&gt;      objectKeys: function(obj)  {&lt;br /&gt;         var arr = [];&lt;br /&gt;         for(key in obj)   {&lt;br /&gt;            if(this.hasOwnProperty(obj, key))   {&lt;br /&gt;               arr.push(key);&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;         return arr;&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;   };&lt;br /&gt;}();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * A Channel/Topic/Queue to which messages are published. Each channel is represented&lt;br /&gt; * by a path name of the form /some/channel/name which is hierarchical&lt;br /&gt; * @constructor&lt;br /&gt; * @param {String} strName The name of this channel. Should be of the form /some/name&lt;br /&gt; */&lt;br /&gt;jaf.core.Channel = function(strName)  {&lt;br /&gt;   var name = strName;&lt;br /&gt;   var subscribers = [];&lt;br /&gt;   &lt;br /&gt;   /** @scope jaf.core.Channel */&lt;br /&gt;   return {&lt;br /&gt;      /**&lt;br /&gt;       * Adds a subscriber to this channel. All the messages published to this&lt;br /&gt;       * channel will be delivered to it.&lt;br /&gt;       * @param {Function} funSubscriber The subscriber function. This function takes one&lt;br /&gt;       *        parameter, the message object&lt;br /&gt;       */&lt;br /&gt;      addSubscriber: function(funSubscriber) {&lt;br /&gt;         if(typeof(funSubscriber) === "function")  {&lt;br /&gt;            subscribers.push(funSubscriber);&lt;br /&gt;         }&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Removes a previously added subscriber from this channel&lt;br /&gt;       * @param {Function} funSubscriber The subscriber to remove&lt;br /&gt;       */&lt;br /&gt;      removeSubscriber: function(funSubscriber) {&lt;br /&gt;         for(var i = 0, len = subscribers.length; i &lt; len; i++)   {&lt;br /&gt;            if(subscribers[i] === funSubscriber) {&lt;br /&gt;               return subscribers.splice(i, 1);&lt;br /&gt;            } &lt;br /&gt;         }&lt;br /&gt;         return null;&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Gets all subscribers as array&lt;br /&gt;       * @return {Array} an array of subscribers added to this channel&lt;br /&gt;       */&lt;br /&gt;      getSubscribers: function()  {&lt;br /&gt;         var len = subscribers.length;&lt;br /&gt;         var copy  = new Array(len);&lt;br /&gt;         for(var i = 0; i &lt; len; i++)  {&lt;br /&gt;            copy[i] = subscribers[i];&lt;br /&gt;         }&lt;br /&gt;         return copy;&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Publishes a messages to this channel. All the subscribers added to this&lt;br /&gt;       * channel will receive this message&lt;br /&gt;       * @param {Object} objMessage The message to publish&lt;br /&gt;       */&lt;br /&gt;      publish: function(objMessage) {&lt;br /&gt;         for(var i = 0, len = subscribers.length; i &lt; len; i++)   {&lt;br /&gt;            subscribers[i](objMessage, strName);&lt;br /&gt;         }&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      getName: function()  {&lt;br /&gt;         return name;&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      toString: function() {&lt;br /&gt;         return "Channel[" + name + "]";&lt;br /&gt;      }&lt;br /&gt;   };&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * @class&lt;br /&gt; * Defines a simple publish/subscribe messaging system where messages can be sent&lt;br /&gt; * or subscribed for.&lt;br /&gt; * @constructor&lt;br /&gt; */&lt;br /&gt;jaf.core.MessageBus = function(parentMessageBus)   {&lt;br /&gt;   var channels = {};&lt;br /&gt;   var patternSubscribers = {};&lt;br /&gt;   var Util = jaf.core.Util;&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * IDEA: The parent child relationship will work as follows:&lt;br /&gt;    * This message bus will subscribe to the parent message bus and listen to&lt;br /&gt;    * all messages on all channels. As soon as messages come to those channels,&lt;br /&gt;    * they will be published to channels with same path with this message bus&lt;br /&gt;    * On the unload of this document or view, the listener to the parent message&lt;br /&gt;    * bus is removed&lt;br /&gt;    */&lt;br /&gt;   var parent = parentMessageBus || null;&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * Creates a new Channel for the specified name. This method is always called&lt;br /&gt;    * after calling checkChannelName(name)&lt;br /&gt;    * @param {String} theName The name for this channel. This should be of the &lt;br /&gt;    * form "/some/name"&lt;br /&gt;    * @return {Channel} the newly created channel object&lt;br /&gt;    */&lt;br /&gt;   function createChannel(theName)   {&lt;br /&gt;      // trim the trailing slash if any&lt;br /&gt;      if(theName.length &gt; 1 &amp;&amp; Util.endsWith(theName, "/"))  {&lt;br /&gt;         theName = theName.substring(0, theName.length - 1);&lt;br /&gt;      }&lt;br /&gt;      return new jaf.core.Channel(theName);&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * Gets the segments of the specified channel name as array.&lt;br /&gt;    * e.g. If the channel name is specified as "/some/name",  an array containing&lt;br /&gt;    * two segments is returned like this: ["some", "name"]&lt;br /&gt;    * @param {String} theName The channel name &lt;br /&gt;    * @return {Array} The array containing the segments&lt;br /&gt;    */&lt;br /&gt;   function getSegments(theName) {&lt;br /&gt;      var segs = theName.split("/");&lt;br /&gt;      if(segs[0] === "")  {&lt;br /&gt;         segs.slice(0, 1);&lt;br /&gt;      }&lt;br /&gt;      return segs;&lt;br /&gt;      // return theName.split("/");&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * Checks whether the specified channel name is a valid name&lt;br /&gt;    * @param {String} theName The name of the channel&lt;br /&gt;    */&lt;br /&gt;   function checkChannelName(theName)   {&lt;br /&gt;      if(!theName || Util.trim(theName).length == 0 || !Util.startsWith(theName, "/"))   {&lt;br /&gt;         throw new Error("Invalid channel name: " + theName);&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * Determines if the specified name is a wildcard pattern&lt;br /&gt;    * @return true if the name ends with /* or /**&lt;br /&gt;    */&lt;br /&gt;   function isPattern(theName)   {&lt;br /&gt;      return Util.endsWith(theName, "/*") || Util.endsWith(theName, "/**");&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * Determines if &lt;tt&gt;strName&lt;/tt&gt; matches with channel name specified by&lt;br /&gt;    * &lt;tt&gt;strChannel&lt;/tt&gt;. This method also supports wildcard pattern matching&lt;br /&gt;    * for two wildcards:&lt;br /&gt;&lt;br /&gt;    * "/*" For children and "/**" For descendents&lt;br /&gt;    * @return true if strName matches with strChannel&lt;br /&gt;    */&lt;br /&gt;   function matches(strName, strChannel) {&lt;br /&gt;      if(strName == strChannel) {&lt;br /&gt;         return true;&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      if(!isPattern(strName) || isPattern(strChannel))  {&lt;br /&gt;         return false;&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      // okay theName is a pattern&lt;br /&gt;      var segs = getSegments(strName);&lt;br /&gt;      var channelSegs = getSegments(strChannel);&lt;br /&gt;      var depth = segs.length;&lt;br /&gt;      var channelDepth = channelSegs.length;&lt;br /&gt;      &lt;br /&gt;      if(depth &gt; channelDepth)   {&lt;br /&gt;         return false;&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      // if(isPattern(strName)) {&lt;br /&gt;      segs.splice(segs.length - 1, 1);&lt;br /&gt;      depth = segs.length;&lt;br /&gt;&lt;br /&gt;      var channelPart = (channelSegs.slice(0, depth).join("/"));&lt;br /&gt;      var namePart = (segs.join("/"));&lt;br /&gt;      if(channelPart !== namePart)  {&lt;br /&gt;         return false;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      if(Util.endsWith(strName, "/**"))   {&lt;br /&gt;         return true;&lt;br /&gt;      }else {&lt;br /&gt;         return (channelDepth - depth) == 1;&lt;br /&gt;      }&lt;br /&gt;      // }&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * Adds any of the subscribers that are pattern subscribers to a Channel.&lt;br /&gt;    * This is called internally when a message is published to a channel and&lt;br /&gt;    * that channel does not exist yet. When this happens, a new Channel is created&lt;br /&gt;    * and any previously registered pattern subscribers are added to the channel&lt;br /&gt;    * @param {jaf.core.Channel} objChannel The channel to which wildcard or pattern &lt;br /&gt;    * subscribers are added if they match.&lt;br /&gt;    */&lt;br /&gt;   function addPatternSubscribers(objChannel)   {&lt;br /&gt;      var patternChannels = Util.objectKeys(patternSubscribers);&lt;br /&gt;      for(var i = 0, len = patternChannels.length; i &lt; len; i++)  {&lt;br /&gt;         var patternCh = patternChannels[i];&lt;br /&gt;         if(matches(patternCh, objChannel.getName()))   {&lt;br /&gt;            var subscribers = patternSubscribers[patternCh];&lt;br /&gt;            if(subscribers)   {&lt;br /&gt;               for(var j = 0, jlen = subscribers.length; j &lt; jlen; j++)  {&lt;br /&gt;                  objChannel.addSubscriber(subscribers[j]);&lt;br /&gt;               }&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   return {&lt;br /&gt;      /**&lt;br /&gt;       * Publishes the message &lt;tt&gt;objMessage&lt;/tt&gt; to channel &lt;tt&gt;strChannel&lt;/tt&gt;&lt;br /&gt;       * All the subscribers registered with this channel will get the message&lt;br /&gt;       * @param strChannel {String} The name of the channel to publish to&lt;br /&gt;       * @param objMessage {Object} The message to publish&lt;br /&gt;       */&lt;br /&gt;      publish: function(strChannel, objMessage)  {&lt;br /&gt;         if(isPattern(strChannel))  {&lt;br /&gt;            alert("Publishing to wildcard channels coming soon.. ;)");&lt;br /&gt;            // IDEA: Support publish to wildcard channels?&lt;br /&gt;            return;&lt;br /&gt;         }else {&lt;br /&gt;            var channel = channels[strChannel];&lt;br /&gt;            if(! channel)  {&lt;br /&gt;               channel = createChannel(strChannel);&lt;br /&gt;               channels[strChannel] = channel;&lt;br /&gt;               addPatternSubscribers(channel);&lt;br /&gt;            }&lt;br /&gt;            channel.publish(objMessage);&lt;br /&gt;         }&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Subscribes to specified channel. If the channel specified by &lt;tt&gt;strChannel&lt;/tt&gt;&lt;br /&gt;       * does not exist, its created. Any message published to this channel will&lt;br /&gt;       * be delivered to &lt;tt&gt;funCallback&lt;/tt&gt; who is the subscriber to this channel&lt;br /&gt;       * @param strChannel {String} The name of the channel. This can be a wildcard&lt;br /&gt;       * pattern like so: /some/channel/* or some/channel&lt;br /&gt;       * @param funCallback {Function} The callback function that will be called&lt;br /&gt;       * with message as the parameter&lt;br /&gt;       */&lt;br /&gt;      subscribe: function(strChannel, funCallback)   {&lt;br /&gt;         // check if the channel name is valid&lt;br /&gt;         checkChannelName(strChannel);&lt;br /&gt;         &lt;br /&gt;         // check for valid callback function&lt;br /&gt;         if(!typeof(funCallback) === "function")   {&lt;br /&gt;            throw new Error("Invalid subsription callback. Must be a function");&lt;br /&gt;         }&lt;br /&gt;         &lt;br /&gt;         var subscriber = funCallback;&lt;br /&gt;         &lt;br /&gt;         // check if this subscription is a pattern i.e. /some/name/** | some/name/*&lt;br /&gt;         if(isPattern(strChannel))  {&lt;br /&gt;            if(patternSubscribers[strChannel])  {&lt;br /&gt;               patternSubscribers[strChannel].push(subscriber);&lt;br /&gt;            }else {&lt;br /&gt;               patternSubscribers[strChannel] = [subscriber];&lt;br /&gt;            }&lt;br /&gt;            &lt;br /&gt;            // check if this subscriber matches for any of the channel already created&lt;br /&gt;            var channelNames = Util.objectKeys(channels);&lt;br /&gt;            for(var i = 0, len = channelNames.length; i &lt; len; i++)  {&lt;br /&gt;               var cName = channelNames[i];&lt;br /&gt;               if(matches(strChannel, cName)) {&lt;br /&gt;                  channels[cName].addSubscriber(subscriber);&lt;br /&gt;               }&lt;br /&gt;            }&lt;br /&gt;         }else {  //no pattern so existing or a new channel&lt;br /&gt;            var channel = channels[strChannel];&lt;br /&gt;            if(! channel)  {&lt;br /&gt;               channel = createChannel(strChannel);&lt;br /&gt;               channels[strChannel] = channel;&lt;br /&gt;            }&lt;br /&gt;            channel.addSubscriber(subscriber);&lt;br /&gt;         }         &lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      /**&lt;br /&gt;       * Unsubscribes to specified channel. &lt;br /&gt;       * @param strChannel {String} The name of the channel (can be a wildcard&lt;br /&gt;       * in which case funCallback from all the matching channels is removed&lt;br /&gt;       * @param funCallback {Function} The callback function that was used when&lt;br /&gt;       * subscribing&lt;br /&gt;       */&lt;br /&gt;      unsubscribe: function(strChannel, funCallback) {&lt;br /&gt;         var subscriber = null;&lt;br /&gt;         if(isPattern(strChannel))  {&lt;br /&gt;            var arrSubs = patternSubscribers[strChannel];&lt;br /&gt;            var subsIndex = -1;&lt;br /&gt;            if(arrSubs) {&lt;br /&gt;               for(var i = 0, len = arrSubs.length; i &lt; len; i++) {&lt;br /&gt;                  if(arrSubs[i] == funCallback) {&lt;br /&gt;                     subsIndex = i;&lt;br /&gt;                     break;&lt;br /&gt;                  }&lt;br /&gt;               }&lt;br /&gt;               &lt;br /&gt;               if(subsIndex != -1)  {&lt;br /&gt;                  arrSubs.splice(subsIndex, 1);&lt;br /&gt;               }&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;         &lt;br /&gt;         // check if this subscriber matches for any of the channel already created&lt;br /&gt;         var channelNames = Util.objectKeys(channels);&lt;br /&gt;         for(var j = 0, jlen = channelNames.length; j &lt; jlen; j++)  {&lt;br /&gt;            var cName = channelNames[j];&lt;br /&gt;            if(matches(cName, strChannel)) {&lt;br /&gt;               subscriber = channels[cName].removeSubscriber(subscriber);&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      },&lt;br /&gt;      &lt;br /&gt;      toString: function() {&lt;br /&gt;         return "MessageBus"&lt;br /&gt;      }&lt;br /&gt;   };&lt;br /&gt;}(null);&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/7169950164568476037-503620006783767787?l=lifeslave.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lifeslave.blogspot.com/feeds/503620006783767787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7169950164568476037&amp;postID=503620006783767787' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7169950164568476037/posts/default/503620006783767787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7169950164568476037/posts/default/503620006783767787'/><link rel='alternate' type='text/html' href='http://lifeslave.blogspot.com/2008/12/publish-subscribe-in-javascript.html' title='Publish Subscribe in Javascript'/><author><name>anaik</name><uri>http://www.blogger.com/profile/18142318504544854123</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>3</thr:total></entry></feed>
