code: function(scope, attrs) {
        var events = {};
        var toLowercaseFunc = function($1){
          return "_"+$1.toLowerCase();
        };
        var EventFunc = function(attrValue) {
          // funcName(argsStr)
          var matches = attrValue.match(/([^\(]+)\(([^\)]*)\)/);
          var funcName = matches[1];
          var argsStr = matches[2].replace(/event[ ,]*/,'');  //remove string 'event'
          var argsExpr = $parse("["+argsStr+"]"); //for perf when triggering event
          return function(event) {
            var args = argsExpr(scope); //get args here to pass updated model values
            function index(obj,i) {return obj[i];}
            var f = funcName.split('.').reduce(index, scope);
            f && f.apply(this, [event].concat(args));
            $timeout( function() {
              scope.$apply();
            });
          };
        };
  
        for(var key in attrs) {
          if (attrs[key]) {
            if (!key.match(/^on[A-Z]/)) { //skip if not events
              continue;
            }
  
            //get event name as underscored. i.e. zoom_changed
            var eventName = key.replace(/^on/,'');
            eventName = eventName.charAt(0).toLowerCase() + eventName.slice(1);
            eventName = eventName.replace(/([A-Z])/g, toLowercaseFunc);
  
            var attrValue = attrs[key];
            events[eventName] = new EventFunc(attrValue);
          }
        }
        return events;
      }
docs: converts attributes hash to scope-specific event function
  @memberof Attr2MapOptions
  @param {scope} scope angularjs scope
  @param {Hash} attrs tag attributes
  @returns {Hash} events converted events