diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_renderjs_js.js b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_renderjs_js.js
index 0c3d4cc41386ecc157dfa930dcad587659314ecc..55d6fc3f57e7b0268d6698b27d86c9c153720a24 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_renderjs_js.js
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_renderjs_js.js
@@ -665,7 +665,58 @@ if (typeof document.contains !== 'function') {
     return this.documentElement.contains(node);
  }
 }
-;/*! RenderJs */
+;(function (DOMParser) {
+  "use strict";
+
+  try {
+    if ((new window.URL("../a", "https://example.com/")).href === "https://example.com/a") {
+      return;
+    }
+  } catch (ignore) {}
+
+  var isAbsoluteOrDataURL = /^(?:[a-z]+:)?\/\/|data:/i;
+
+  function resolveUrl(url, base_url) {
+    var doc, base, link,
+      html = "<!doctype><html><head></head></html>";
+ 
+    if (url && base_url) {
+      doc = (new DOMParser()).parseFromString(html, 'text/html');
+      base = doc.createElement('base');
+      link = doc.createElement('link');
+      doc.head.appendChild(base);
+      doc.head.appendChild(link);
+      base.href = base_url;
+      link.href = url;
+      return link.href;
+    }
+    return url;
+  }
+
+  function URL(url, base) {
+    if (base !== undefined) {
+      if (!isAbsoluteOrDataURL.test(base)) {
+        throw new TypeError("Failed to construct 'URL': Invalid base URL");
+      }
+      url = resolveUrl(url, base);
+    }
+    if (!isAbsoluteOrDataURL.test(url)) {
+      throw new TypeError("Failed to construct 'URL': Invalid URL");
+    }
+    this.href = url;
+  }
+  URL.prototype.href = "";
+
+  if (window.URL && window.URL.createObjectURL) {
+    URL.createObjectURL = window.URL.createObjectURL;
+  }
+  if (window.URL && window.URL.revokeObjectURL) {
+    URL.revokeObjectURL = window.URL.revokeObjectURL;
+  }
+
+  window.URL = URL;
+
+}(DOMParser));;/*! RenderJs */
 /*jslint nomen: true*/
 
 /*
@@ -809,6 +860,7 @@ if (typeof document.contains !== 'function') {
     gadget_loading_klass_list = [],
     renderJS,
     Monitor,
+    Mutex,
     scope_increment = 0,
     isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i'),
     is_page_unloaded = false,
@@ -825,6 +877,64 @@ if (typeof document.contains !== 'function') {
     is_page_unloaded = true;
   });
 
+  /////////////////////////////////////////////////////////////////
+  // Mutex
+  /////////////////////////////////////////////////////////////////
+  Mutex = function createMutex() {
+    if (!(this instanceof Mutex)) {
+      return new Mutex();
+    }
+    this._latest_defer = null;
+  };
+
+  Mutex.prototype = {
+    constructor: Mutex,
+
+    lock: function lockMutex() {
+      var previous_defer = this._latest_defer,
+        current_defer = RSVP.defer(),
+        queue = new RSVP.Queue();
+
+      this._latest_defer = current_defer;
+
+      if (previous_defer !== null) {
+        queue.push(function acquireMutex() {
+          return previous_defer.promise;
+        });
+      }
+
+      // Create a new promise (.then) not cancellable
+      // to allow external cancellation of the callback
+      // without breaking the mutex implementation
+      queue
+        .fail(current_defer.resolve.bind(current_defer));
+
+      return queue
+        .push(function generateMutexUnlock() {
+          return function runAndUnlock(callback) {
+            return new RSVP.Queue()
+              .push(function executeMutexCallback() {
+                return callback();
+              })
+              .push(function releaseMutexAfterSuccess(result) {
+                current_defer.resolve(result);
+                return result;
+              }, function releaseMutexAfterError(error) {
+                current_defer.resolve(error);
+                throw error;
+              });
+          };
+        });
+    },
+
+    lockAndRun: function (callback) {
+      return this.lock()
+        .push(function executeLockAndRunCallback(runAndUnlock) {
+          return runAndUnlock(callback);
+        });
+    }
+  };
+
   /////////////////////////////////////////////////////////////////
   // Helper functions
   /////////////////////////////////////////////////////////////////
@@ -1251,15 +1361,26 @@ if (typeof document.contains !== 'function') {
   /////////////////////////////////////////////////////////////////
   // RenderJSGadget.declareMethod
   /////////////////////////////////////////////////////////////////
-  RenderJSGadget.declareMethod = function declareMethod(name, callback) {
+  RenderJSGadget.declareMethod = function declareMethod(name, callback,
+                                                        options) {
     this.prototype[name] = function triggerMethod() {
       var context = this,
-        argument_list = arguments;
+        argument_list = arguments,
+        mutex_name;
+
+      function waitForMethodCallback() {
+        return callback.apply(context, argument_list);
+      }
 
+      if ((options !== undefined) && (options.hasOwnProperty('mutex'))) {
+        mutex_name = '__mutex_' + options.mutex;
+        if (!context.hasOwnProperty(mutex_name)) {
+          context[mutex_name] = new Mutex();
+        }
+        return context[mutex_name].lockAndRun(waitForMethodCallback);
+      }
       return new RSVP.Queue()
-        .push(function waitForMethodCallback() {
-          return callback.apply(context, argument_list);
-        });
+        .push(waitForMethodCallback);
     };
     // Allow chain
     return this;
@@ -1295,54 +1416,37 @@ if (typeof document.contains !== 'function') {
       return this.element;
     })
     .declareMethod('changeState', function changeState(state_dict) {
-      var next_onStateChange = new RSVP.Queue(),
-        previous_onStateCHange,
-        context = this;
-      if (context.hasOwnProperty('__previous_onStateChange')) {
-        previous_onStateCHange = context.__previous_onStateChange;
-        next_onStateChange
-          .push(function waitForPreviousStateChange() {
-            return previous_onStateCHange;
+      var context = this,
+        key,
+        modified = false,
+        previous_cancelled = context.hasOwnProperty('__modification_dict'),
+        modification_dict;
+      if (previous_cancelled) {
+        modification_dict = context.__modification_dict;
+        modified = true;
+      } else {
+        modification_dict = {};
+      }
+      for (key in state_dict) {
+        if (state_dict.hasOwnProperty(key) &&
+            (state_dict[key] !== context.state[key])) {
+          context.state[key] = state_dict[key];
+          modification_dict[key] = state_dict[key];
+          modified = true;
+        }
+      }
+      if (modified && context.__state_change_callback !== undefined) {
+        context.__modification_dict = modification_dict;
+        return new RSVP.Queue()
+          .push(function waitForStateChangeCallback() {
+            return context.__state_change_callback(modification_dict);
           })
-          .push(undefined, function handlePreviousStateChangeError() {
-            // Run callback even if previous failed
-            return;
+          .push(function handleStateChangeSuccess(result) {
+            delete context.__modification_dict;
+            return result;
           });
       }
-      context.__previous_onStateChange = next_onStateChange;
-      return next_onStateChange
-        .push(function checkStateModification() {
-          var key,
-            modified = false,
-            previous_cancelled = context.hasOwnProperty('__modification_dict'),
-            modification_dict;
-          if (previous_cancelled) {
-            modification_dict = context.__modification_dict;
-            modified = true;
-          } else {
-            modification_dict = {};
-          }
-          for (key in state_dict) {
-            if (state_dict.hasOwnProperty(key) &&
-                (state_dict[key] !== context.state[key])) {
-              context.state[key] = state_dict[key];
-              modification_dict[key] = state_dict[key];
-              modified = true;
-            }
-          }
-          if (modified && context.__state_change_callback !== undefined) {
-            context.__modification_dict = modification_dict;
-            return new RSVP.Queue()
-              .push(function waitForStateChangeCallback() {
-                return context.__state_change_callback(modification_dict);
-              })
-              .push(function handleStateChangeSuccess(result) {
-                delete context.__modification_dict;
-                return result;
-              });
-          }
-        });
-    });
+    }, {mutex: 'changestate'});
 
   /////////////////////////////////////////////////////////////////
   // RenderJSGadget.declareAcquiredMethod
@@ -2038,6 +2142,7 @@ if (typeof document.contains !== 'function') {
   /////////////////////////////////////////////////////////////////
   // global
   /////////////////////////////////////////////////////////////////
+  renderJS.Mutex = Mutex;
   window.rJS = window.renderJS = renderJS;
   window.__RenderJSGadget = RenderJSGadget;
   window.__RenderJSEmbeddedGadget = RenderJSEmbeddedGadget;
@@ -2427,4 +2532,4 @@ if (typeof document.contains !== 'function') {
   );
 
 }(document, window, RSVP, DOMParser, Channel, MutationObserver, Node,
-  FileReader, Blob, navigator, Event, URL));
\ No newline at end of file
+  FileReader, Blob, navigator, Event, URL));
diff --git a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_renderjs_js.xml b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_renderjs_js.xml
index 2bf92012d2c30c4380682105f3f22763a8f9891b..55cedbe136ff90e37c7743580b44cf26649d4f5e 100644
--- a/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_renderjs_js.xml
+++ b/bt5/erp5_web_renderjs_ui/PathTemplateItem/web_page_module/rjs_renderjs_js.xml
@@ -230,7 +230,7 @@
             </item>
             <item>
                 <key> <string>serial</string> </key>
-                <value> <string>962.24020.58652.57139</string> </value>
+                <value> <string>964.57262.9791.60330</string> </value>
             </item>
             <item>
                 <key> <string>state</string> </key>
@@ -248,7 +248,7 @@
                     </tuple>
                     <state>
                       <tuple>
-                        <float>1508945098.52</float>
+                        <float>1516196938.48</float>
                         <string>UTC</string>
                       </tuple>
                     </state>
diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/renderjs.js.js b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/renderjs.js.js
index 0c3d4cc41386ecc157dfa930dcad587659314ecc..55d6fc3f57e7b0268d6698b27d86c9c153720a24 100644
--- a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/renderjs.js.js
+++ b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/renderjs.js.js
@@ -665,7 +665,58 @@ if (typeof document.contains !== 'function') {
     return this.documentElement.contains(node);
  }
 }
-;/*! RenderJs */
+;(function (DOMParser) {
+  "use strict";
+
+  try {
+    if ((new window.URL("../a", "https://example.com/")).href === "https://example.com/a") {
+      return;
+    }
+  } catch (ignore) {}
+
+  var isAbsoluteOrDataURL = /^(?:[a-z]+:)?\/\/|data:/i;
+
+  function resolveUrl(url, base_url) {
+    var doc, base, link,
+      html = "<!doctype><html><head></head></html>";
+ 
+    if (url && base_url) {
+      doc = (new DOMParser()).parseFromString(html, 'text/html');
+      base = doc.createElement('base');
+      link = doc.createElement('link');
+      doc.head.appendChild(base);
+      doc.head.appendChild(link);
+      base.href = base_url;
+      link.href = url;
+      return link.href;
+    }
+    return url;
+  }
+
+  function URL(url, base) {
+    if (base !== undefined) {
+      if (!isAbsoluteOrDataURL.test(base)) {
+        throw new TypeError("Failed to construct 'URL': Invalid base URL");
+      }
+      url = resolveUrl(url, base);
+    }
+    if (!isAbsoluteOrDataURL.test(url)) {
+      throw new TypeError("Failed to construct 'URL': Invalid URL");
+    }
+    this.href = url;
+  }
+  URL.prototype.href = "";
+
+  if (window.URL && window.URL.createObjectURL) {
+    URL.createObjectURL = window.URL.createObjectURL;
+  }
+  if (window.URL && window.URL.revokeObjectURL) {
+    URL.revokeObjectURL = window.URL.revokeObjectURL;
+  }
+
+  window.URL = URL;
+
+}(DOMParser));;/*! RenderJs */
 /*jslint nomen: true*/
 
 /*
@@ -809,6 +860,7 @@ if (typeof document.contains !== 'function') {
     gadget_loading_klass_list = [],
     renderJS,
     Monitor,
+    Mutex,
     scope_increment = 0,
     isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i'),
     is_page_unloaded = false,
@@ -825,6 +877,64 @@ if (typeof document.contains !== 'function') {
     is_page_unloaded = true;
   });
 
+  /////////////////////////////////////////////////////////////////
+  // Mutex
+  /////////////////////////////////////////////////////////////////
+  Mutex = function createMutex() {
+    if (!(this instanceof Mutex)) {
+      return new Mutex();
+    }
+    this._latest_defer = null;
+  };
+
+  Mutex.prototype = {
+    constructor: Mutex,
+
+    lock: function lockMutex() {
+      var previous_defer = this._latest_defer,
+        current_defer = RSVP.defer(),
+        queue = new RSVP.Queue();
+
+      this._latest_defer = current_defer;
+
+      if (previous_defer !== null) {
+        queue.push(function acquireMutex() {
+          return previous_defer.promise;
+        });
+      }
+
+      // Create a new promise (.then) not cancellable
+      // to allow external cancellation of the callback
+      // without breaking the mutex implementation
+      queue
+        .fail(current_defer.resolve.bind(current_defer));
+
+      return queue
+        .push(function generateMutexUnlock() {
+          return function runAndUnlock(callback) {
+            return new RSVP.Queue()
+              .push(function executeMutexCallback() {
+                return callback();
+              })
+              .push(function releaseMutexAfterSuccess(result) {
+                current_defer.resolve(result);
+                return result;
+              }, function releaseMutexAfterError(error) {
+                current_defer.resolve(error);
+                throw error;
+              });
+          };
+        });
+    },
+
+    lockAndRun: function (callback) {
+      return this.lock()
+        .push(function executeLockAndRunCallback(runAndUnlock) {
+          return runAndUnlock(callback);
+        });
+    }
+  };
+
   /////////////////////////////////////////////////////////////////
   // Helper functions
   /////////////////////////////////////////////////////////////////
@@ -1251,15 +1361,26 @@ if (typeof document.contains !== 'function') {
   /////////////////////////////////////////////////////////////////
   // RenderJSGadget.declareMethod
   /////////////////////////////////////////////////////////////////
-  RenderJSGadget.declareMethod = function declareMethod(name, callback) {
+  RenderJSGadget.declareMethod = function declareMethod(name, callback,
+                                                        options) {
     this.prototype[name] = function triggerMethod() {
       var context = this,
-        argument_list = arguments;
+        argument_list = arguments,
+        mutex_name;
+
+      function waitForMethodCallback() {
+        return callback.apply(context, argument_list);
+      }
 
+      if ((options !== undefined) && (options.hasOwnProperty('mutex'))) {
+        mutex_name = '__mutex_' + options.mutex;
+        if (!context.hasOwnProperty(mutex_name)) {
+          context[mutex_name] = new Mutex();
+        }
+        return context[mutex_name].lockAndRun(waitForMethodCallback);
+      }
       return new RSVP.Queue()
-        .push(function waitForMethodCallback() {
-          return callback.apply(context, argument_list);
-        });
+        .push(waitForMethodCallback);
     };
     // Allow chain
     return this;
@@ -1295,54 +1416,37 @@ if (typeof document.contains !== 'function') {
       return this.element;
     })
     .declareMethod('changeState', function changeState(state_dict) {
-      var next_onStateChange = new RSVP.Queue(),
-        previous_onStateCHange,
-        context = this;
-      if (context.hasOwnProperty('__previous_onStateChange')) {
-        previous_onStateCHange = context.__previous_onStateChange;
-        next_onStateChange
-          .push(function waitForPreviousStateChange() {
-            return previous_onStateCHange;
+      var context = this,
+        key,
+        modified = false,
+        previous_cancelled = context.hasOwnProperty('__modification_dict'),
+        modification_dict;
+      if (previous_cancelled) {
+        modification_dict = context.__modification_dict;
+        modified = true;
+      } else {
+        modification_dict = {};
+      }
+      for (key in state_dict) {
+        if (state_dict.hasOwnProperty(key) &&
+            (state_dict[key] !== context.state[key])) {
+          context.state[key] = state_dict[key];
+          modification_dict[key] = state_dict[key];
+          modified = true;
+        }
+      }
+      if (modified && context.__state_change_callback !== undefined) {
+        context.__modification_dict = modification_dict;
+        return new RSVP.Queue()
+          .push(function waitForStateChangeCallback() {
+            return context.__state_change_callback(modification_dict);
           })
-          .push(undefined, function handlePreviousStateChangeError() {
-            // Run callback even if previous failed
-            return;
+          .push(function handleStateChangeSuccess(result) {
+            delete context.__modification_dict;
+            return result;
           });
       }
-      context.__previous_onStateChange = next_onStateChange;
-      return next_onStateChange
-        .push(function checkStateModification() {
-          var key,
-            modified = false,
-            previous_cancelled = context.hasOwnProperty('__modification_dict'),
-            modification_dict;
-          if (previous_cancelled) {
-            modification_dict = context.__modification_dict;
-            modified = true;
-          } else {
-            modification_dict = {};
-          }
-          for (key in state_dict) {
-            if (state_dict.hasOwnProperty(key) &&
-                (state_dict[key] !== context.state[key])) {
-              context.state[key] = state_dict[key];
-              modification_dict[key] = state_dict[key];
-              modified = true;
-            }
-          }
-          if (modified && context.__state_change_callback !== undefined) {
-            context.__modification_dict = modification_dict;
-            return new RSVP.Queue()
-              .push(function waitForStateChangeCallback() {
-                return context.__state_change_callback(modification_dict);
-              })
-              .push(function handleStateChangeSuccess(result) {
-                delete context.__modification_dict;
-                return result;
-              });
-          }
-        });
-    });
+    }, {mutex: 'changestate'});
 
   /////////////////////////////////////////////////////////////////
   // RenderJSGadget.declareAcquiredMethod
@@ -2038,6 +2142,7 @@ if (typeof document.contains !== 'function') {
   /////////////////////////////////////////////////////////////////
   // global
   /////////////////////////////////////////////////////////////////
+  renderJS.Mutex = Mutex;
   window.rJS = window.renderJS = renderJS;
   window.__RenderJSGadget = RenderJSGadget;
   window.__RenderJSEmbeddedGadget = RenderJSEmbeddedGadget;
@@ -2427,4 +2532,4 @@ if (typeof document.contains !== 'function') {
   );
 
 }(document, window, RSVP, DOMParser, Channel, MutationObserver, Node,
-  FileReader, Blob, navigator, Event, URL));
\ No newline at end of file
+  FileReader, Blob, navigator, Event, URL));