limits: finalizing rate-based limits
diff --git a/bindings/modulegen__gcc_ILP32.py b/bindings/modulegen__gcc_ILP32.py
index 92de4db..1b1c512 100644
--- a/bindings/modulegen__gcc_ILP32.py
+++ b/bindings/modulegen__gcc_ILP32.py
@@ -100,8 +100,6 @@
     module.add_class('Tag', import_from_module='ns.network', parent=root_module['ns3::ObjectBase'])
     ## tag-buffer.h (module 'network'): ns3::TagBuffer [class]
     module.add_class('TagBuffer', import_from_module='ns.network')
-    ## traced-value.h (module 'core'): ns3::TracedValue<double> [class]
-    module.add_class('TracedValue', import_from_module='ns.core', template_parameters=['double'])
     ## random-variable.h (module 'core'): ns3::TriangularVariable [class]
     module.add_class('TriangularVariable', import_from_module='ns.core', parent=root_module['ns3::RandomVariable'])
     ## type-id.h (module 'core'): ns3::TypeId [class]
@@ -516,7 +514,6 @@
     register_Ns3SpringMobilityHelper_methods(root_module, root_module['ns3::SpringMobilityHelper'])
     register_Ns3Tag_methods(root_module, root_module['ns3::Tag'])
     register_Ns3TagBuffer_methods(root_module, root_module['ns3::TagBuffer'])
-    register_Ns3TracedValue__Double_methods(root_module, root_module['ns3::TracedValue< double >'])
     register_Ns3TriangularVariable_methods(root_module, root_module['ns3::TriangularVariable'])
     register_Ns3TypeId_methods(root_module, root_module['ns3::TypeId'])
     register_Ns3TypeIdAttributeInformation_methods(root_module, root_module['ns3::TypeId::AttributeInformation'])
@@ -2223,40 +2220,6 @@
                    [param('uint8_t', 'v')])
     return
 
-def register_Ns3TracedValue__Double_methods(root_module, cls):
-    ## traced-value.h (module 'core'): ns3::TracedValue<double>::TracedValue() [constructor]
-    cls.add_constructor([])
-    ## traced-value.h (module 'core'): ns3::TracedValue<double>::TracedValue(ns3::TracedValue<double> const & o) [copy constructor]
-    cls.add_constructor([param('ns3::TracedValue< double > const &', 'o')])
-    ## traced-value.h (module 'core'): ns3::TracedValue<double>::TracedValue(double const & v) [constructor]
-    cls.add_constructor([param('double const &', 'v')])
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::Connect(ns3::CallbackBase const & cb, std::basic_string<char,std::char_traits<char>,std::allocator<char> > path) [member function]
-    cls.add_method('Connect', 
-                   'void', 
-                   [param('ns3::CallbackBase const &', 'cb'), param('std::string', 'path')])
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::ConnectWithoutContext(ns3::CallbackBase const & cb) [member function]
-    cls.add_method('ConnectWithoutContext', 
-                   'void', 
-                   [param('ns3::CallbackBase const &', 'cb')])
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::Disconnect(ns3::CallbackBase const & cb, std::basic_string<char,std::char_traits<char>,std::allocator<char> > path) [member function]
-    cls.add_method('Disconnect', 
-                   'void', 
-                   [param('ns3::CallbackBase const &', 'cb'), param('std::string', 'path')])
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::DisconnectWithoutContext(ns3::CallbackBase const & cb) [member function]
-    cls.add_method('DisconnectWithoutContext', 
-                   'void', 
-                   [param('ns3::CallbackBase const &', 'cb')])
-    ## traced-value.h (module 'core'): double ns3::TracedValue<double>::Get() const [member function]
-    cls.add_method('Get', 
-                   'double', 
-                   [], 
-                   is_const=True)
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::Set(double const & v) [member function]
-    cls.add_method('Set', 
-                   'void', 
-                   [param('double const &', 'v')])
-    return
-
 def register_Ns3TriangularVariable_methods(root_module, cls):
     ## random-variable.h (module 'core'): ns3::TriangularVariable::TriangularVariable(ns3::TriangularVariable const & arg0) [copy constructor]
     cls.add_constructor([param('ns3::TriangularVariable const &', 'arg0')])
@@ -5836,13 +5799,23 @@
     cls.add_constructor([param('ns3::ndn::Limits const &', 'arg0')])
     ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::Limits() [constructor]
     cls.add_constructor([])
+    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::BorrowLimit() [member function]
+    cls.add_method('BorrowLimit', 
+                   'void', 
+                   [], 
+                   is_pure_virtual=True, is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetCurrentLimit() const [member function]
     cls.add_method('GetCurrentLimit', 
                    'double', 
                    [], 
-                   is_const=True)
-    ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetMaxLimit() const [member function]
-    cls.add_method('GetMaxLimit', 
+                   is_pure_virtual=True, is_const=True, is_virtual=True)
+    ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetMaxDelay() const [member function]
+    cls.add_method('GetMaxDelay', 
+                   'double', 
+                   [], 
+                   is_const=True, is_virtual=True)
+    ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetMaxRate() const [member function]
+    cls.add_method('GetMaxRate', 
                    'double', 
                    [], 
                    is_const=True, is_virtual=True)
@@ -5861,15 +5834,21 @@
                    'bool', 
                    [], 
                    is_const=True, is_virtual=True)
-    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::SetMaxLimit(double max) [member function]
-    cls.add_method('SetMaxLimit', 
+    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::ReturnLimit() [member function]
+    cls.add_method('ReturnLimit', 
                    'void', 
-                   [param('double', 'max')], 
+                   [], 
+                   is_pure_virtual=True, is_virtual=True)
+    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::SetLimits(double rate, double delay) [member function]
+    cls.add_method('SetLimits', 
+                   'void', 
+                   [param('double', 'rate'), param('double', 'delay')], 
                    is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::UpdateCurrentLimit(double limit) [member function]
     cls.add_method('UpdateCurrentLimit', 
                    'void', 
-                   [param('double', 'limit')])
+                   [param('double', 'limit')], 
+                   is_pure_virtual=True, is_virtual=True)
     return
 
 def register_Ns3NdnNameComponents_methods(root_module, cls):
diff --git a/bindings/modulegen__gcc_LP64.py b/bindings/modulegen__gcc_LP64.py
index 92de4db..1b1c512 100644
--- a/bindings/modulegen__gcc_LP64.py
+++ b/bindings/modulegen__gcc_LP64.py
@@ -100,8 +100,6 @@
     module.add_class('Tag', import_from_module='ns.network', parent=root_module['ns3::ObjectBase'])
     ## tag-buffer.h (module 'network'): ns3::TagBuffer [class]
     module.add_class('TagBuffer', import_from_module='ns.network')
-    ## traced-value.h (module 'core'): ns3::TracedValue<double> [class]
-    module.add_class('TracedValue', import_from_module='ns.core', template_parameters=['double'])
     ## random-variable.h (module 'core'): ns3::TriangularVariable [class]
     module.add_class('TriangularVariable', import_from_module='ns.core', parent=root_module['ns3::RandomVariable'])
     ## type-id.h (module 'core'): ns3::TypeId [class]
@@ -516,7 +514,6 @@
     register_Ns3SpringMobilityHelper_methods(root_module, root_module['ns3::SpringMobilityHelper'])
     register_Ns3Tag_methods(root_module, root_module['ns3::Tag'])
     register_Ns3TagBuffer_methods(root_module, root_module['ns3::TagBuffer'])
-    register_Ns3TracedValue__Double_methods(root_module, root_module['ns3::TracedValue< double >'])
     register_Ns3TriangularVariable_methods(root_module, root_module['ns3::TriangularVariable'])
     register_Ns3TypeId_methods(root_module, root_module['ns3::TypeId'])
     register_Ns3TypeIdAttributeInformation_methods(root_module, root_module['ns3::TypeId::AttributeInformation'])
@@ -2223,40 +2220,6 @@
                    [param('uint8_t', 'v')])
     return
 
-def register_Ns3TracedValue__Double_methods(root_module, cls):
-    ## traced-value.h (module 'core'): ns3::TracedValue<double>::TracedValue() [constructor]
-    cls.add_constructor([])
-    ## traced-value.h (module 'core'): ns3::TracedValue<double>::TracedValue(ns3::TracedValue<double> const & o) [copy constructor]
-    cls.add_constructor([param('ns3::TracedValue< double > const &', 'o')])
-    ## traced-value.h (module 'core'): ns3::TracedValue<double>::TracedValue(double const & v) [constructor]
-    cls.add_constructor([param('double const &', 'v')])
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::Connect(ns3::CallbackBase const & cb, std::basic_string<char,std::char_traits<char>,std::allocator<char> > path) [member function]
-    cls.add_method('Connect', 
-                   'void', 
-                   [param('ns3::CallbackBase const &', 'cb'), param('std::string', 'path')])
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::ConnectWithoutContext(ns3::CallbackBase const & cb) [member function]
-    cls.add_method('ConnectWithoutContext', 
-                   'void', 
-                   [param('ns3::CallbackBase const &', 'cb')])
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::Disconnect(ns3::CallbackBase const & cb, std::basic_string<char,std::char_traits<char>,std::allocator<char> > path) [member function]
-    cls.add_method('Disconnect', 
-                   'void', 
-                   [param('ns3::CallbackBase const &', 'cb'), param('std::string', 'path')])
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::DisconnectWithoutContext(ns3::CallbackBase const & cb) [member function]
-    cls.add_method('DisconnectWithoutContext', 
-                   'void', 
-                   [param('ns3::CallbackBase const &', 'cb')])
-    ## traced-value.h (module 'core'): double ns3::TracedValue<double>::Get() const [member function]
-    cls.add_method('Get', 
-                   'double', 
-                   [], 
-                   is_const=True)
-    ## traced-value.h (module 'core'): void ns3::TracedValue<double>::Set(double const & v) [member function]
-    cls.add_method('Set', 
-                   'void', 
-                   [param('double const &', 'v')])
-    return
-
 def register_Ns3TriangularVariable_methods(root_module, cls):
     ## random-variable.h (module 'core'): ns3::TriangularVariable::TriangularVariable(ns3::TriangularVariable const & arg0) [copy constructor]
     cls.add_constructor([param('ns3::TriangularVariable const &', 'arg0')])
@@ -5836,13 +5799,23 @@
     cls.add_constructor([param('ns3::ndn::Limits const &', 'arg0')])
     ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::Limits() [constructor]
     cls.add_constructor([])
+    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::BorrowLimit() [member function]
+    cls.add_method('BorrowLimit', 
+                   'void', 
+                   [], 
+                   is_pure_virtual=True, is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetCurrentLimit() const [member function]
     cls.add_method('GetCurrentLimit', 
                    'double', 
                    [], 
-                   is_const=True)
-    ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetMaxLimit() const [member function]
-    cls.add_method('GetMaxLimit', 
+                   is_pure_virtual=True, is_const=True, is_virtual=True)
+    ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetMaxDelay() const [member function]
+    cls.add_method('GetMaxDelay', 
+                   'double', 
+                   [], 
+                   is_const=True, is_virtual=True)
+    ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetMaxRate() const [member function]
+    cls.add_method('GetMaxRate', 
                    'double', 
                    [], 
                    is_const=True, is_virtual=True)
@@ -5861,15 +5834,21 @@
                    'bool', 
                    [], 
                    is_const=True, is_virtual=True)
-    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::SetMaxLimit(double max) [member function]
-    cls.add_method('SetMaxLimit', 
+    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::ReturnLimit() [member function]
+    cls.add_method('ReturnLimit', 
                    'void', 
-                   [param('double', 'max')], 
+                   [], 
+                   is_pure_virtual=True, is_virtual=True)
+    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::SetLimits(double rate, double delay) [member function]
+    cls.add_method('SetLimits', 
+                   'void', 
+                   [param('double', 'rate'), param('double', 'delay')], 
                    is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::UpdateCurrentLimit(double limit) [member function]
     cls.add_method('UpdateCurrentLimit', 
                    'void', 
-                   [param('double', 'limit')])
+                   [param('double', 'limit')], 
+                   is_pure_virtual=True, is_virtual=True)
     return
 
 def register_Ns3NdnNameComponents_methods(root_module, cls):
diff --git a/utils/ndn-limits-rate.cc b/utils/ndn-limits-rate.cc
index 215250e..1bf0af4 100644
--- a/utils/ndn-limits-rate.cc
+++ b/utils/ndn-limits-rate.cc
@@ -23,6 +23,8 @@
 #include "ns3/log.h"
 #include "ns3/simulator.h"
 #include "ns3/random-variable.h"
+#include "ns3/ndn-face.h"
+#include "ns3/node.h"
 
 NS_LOG_COMPONENT_DEFINE ("ndn.Limits.Rate");
 
@@ -44,6 +46,26 @@
 }
 
 void
+LimitsRate::NotifyNewAggregate ()
+{
+  super::NotifyNewAggregate ();
+
+  if (!m_isLeakScheduled)
+    {
+      if (GetObject<Face> () != 0)
+        {
+          NS_ASSERT_MSG (GetObject<Face> ()->GetNode () != 0, "Node object should exist on the face");
+          
+          m_isLeakScheduled = true;
+          UniformVariable r (0,1);
+          Simulator::ScheduleWithContext (GetObject<Face> ()->GetNode ()->GetId (),
+                                          Seconds (r.GetValue ()), &LimitsRate::LeakBucket, this, 0.0);
+        }
+    }
+}
+
+
+void
 LimitsRate::UpdateCurrentLimit (double limit)
 {
   NS_ASSERT_MSG (limit >= 0.0, "Limit should be greater or equal to zero");
@@ -80,7 +102,23 @@
 {
   const double leak = m_bucketLeak * interval;
 
+#ifdef NS3_LOG_ENABLE  
+  if (m_bucket>1)
+    {
+      NS_LOG_DEBUG ("Leak from " << m_bucket << " to " << std::max (0.0, m_bucket - leak));
+    }
+#endif
+  
   m_bucket = std::max (0.0, m_bucket - leak);
+
+  // calculate interval so next time we will leak by 1.001, unless such interval would be more than 1 second
+  double newInterval = 1.0;
+  if (m_bucketLeak > 1.0)
+    {
+      newInterval = 1.001 / m_bucketLeak;
+    }
+  
+  Simulator::Schedule (Seconds (newInterval), &LimitsRate::LeakBucket, this, newInterval);
 }
 
 } // namespace ndn
diff --git a/utils/ndn-limits-rate.h b/utils/ndn-limits-rate.h
index 4050bb2..15344c6 100644
--- a/utils/ndn-limits-rate.h
+++ b/utils/ndn-limits-rate.h
@@ -44,8 +44,9 @@
    * \param prefix smart pointer to the prefix for the FIB entry
    */
   LimitsRate ()
-    : m_bucketMax (0)
-    , m_bucketLeak (0)
+    : m_isLeakScheduled (false)
+    , m_bucketMax (0)
+    , m_bucketLeak (1)
     , m_bucket (0)
   { }
 
@@ -96,6 +97,11 @@
     return m_bucketLeak;
   }
 
+protected:
+  // from Node
+  void
+  NotifyNewAggregate ();
+    
 private:
   /**
    * @brief Leak bucket, assuming `interval' seconds between leakages
@@ -106,6 +112,8 @@
   LeakBucket (double interval);
 
 private:
+  bool m_isLeakScheduled;
+  
   double m_bucketMax;   ///< \brief Maximum Interest allowance for this face (maximum tokens that can be issued at the same time)
   double m_bucketLeak;  ///< \brief Normalized amount that should be leaked every second (token bucket leak rate)
   double m_bucket;      ///< \brief Value representing current size of the Interest allowance for this face (current size of token bucket)