angular.module('SmoothScrollbar', [])
    .service('ScrollbarService', class ScrollbarService{
        static $inject = ['$q'];

        constructor($q) {
            this.scrollbarInstances = {};
            this.deferreds = {};
            this.$q = $q;
        }

        /**
         * @method
         * Get scrollbar instance
         * If instance isn't existed,
         * callback wiil be invoked after instance is created
         *
         * @param {String} name: scrollbar name
         */
        getInstance(name) {
            const { scrollbarInstances, deferreds, $q } = this;

            if (scrollbarInstances.hasOwnProperty(name)) {
                return ($q.resolve || $q.when)(scrollbarInstances[name]);
            }

            let deferred = deferreds[name] = deferreds[name] || $q.defer();

            return deferred.promise;
        }

        /**
         * @method
         * Create scrollbar instance
         *
         * @param {String} name: scrollbar name
         * @param {Element} elem: container element
         * @param {Object} options: as is explained in scrollbar constructor
         *
         * @return {Scrollbar} scrollbar instance
         */
        createInstance(name, elem, options) {
            const { scrollbarInstances, deferreds } = this;

            if (scrollbarInstances.hasOwnProperty(name)) {
                return scrollbarInstances[name];
            }

            let instance = scrollbarInstances[name] = new Scrollbar(elem, options);

            if (deferreds.hasOwnProperty(name)) {
                deferreds[name].resolve(instance);
            }

            return instance;
        }

        /**
         * @method
         * Destroy scrollbar instance
         *
         * @param {String} name: scrollbar name
         */
        destroyInstance(name) {
            let { scrollbarInstances, deferreds } = this;
            let instance = scrollbarInstances[name];

            if (instance) {
                instance.destroy();
                delete scrollbarInstances[name];
                delete deferreds[name];
            }
        }
    })
    .directive('scrollbar', ['ScrollbarService', (ScrollbarService) => {
        return {
            restrict: 'AE',
            transclude: true,
            template: `
                <article class="scroll-content" ng-transclude></article>
                <aside class="scrollbar-track scrollbar-track-x">
                    <div class="scrollbar-thumb scrollbar-thumb-x"></div>
                </aside>
                <aside class="scrollbar-track scrollbar-track-y">
                    <div class="scrollbar-thumb scrollbar-thumb-y"></div>
                </aside>
            `,
            scope: {
                speed: '@',
                stepLength: '@',
                easingDuration: '@',
                easingCurve: '@',
                propagation: '='
            },
            link(scope, elem, attrs) {
                const name = attrs.scrollbar || attrs.name || Date.now().toString(32);

                const scrollbar = ScrollbarService.createInstance(name, elem[0], scope);

                let original = {
                    update: ::scrollbar.update,
                    scrollTo: ::scrollbar.scrollTo,
                    addListener: ::scrollbar.addListener,
                    infiniteScroll: ::scrollbar.infiniteScroll
                };

                let applyChange = (cb) => {
                    if (typeof cb !== 'function') return;

                    return (...args) => {
                        cb(...args);
                        scope.$apply();
                    };
                };

                scrollbar.update = (cb) => {
                    original.update(applyChange(cb));
                };

                scrollbar.scrollTo = (x, y, duration, cb) => {
                    original.scrollTo(x, y, duration, applyChange(cb));
                };

                scrollbar.addListener = (cb) => {
                    if (typeof cb !== 'function') return;

                    original.addListener(applyChange(cb));
                };

                scrollbar.infiniteScroll = (cb, threshold) => {
                    if (typeof cb !== 'function') return;

                    original.infiniteScroll(applyChange(cb), threshold);
                };

                scope.$on('$destroy', () => {
                    ScrollbarService.destroyInstance(name);
                });
            }
        };
    }]);
@@ -31,16 +31,70 @@
 r', %5B%5D)%0A
+    .constant('SCROLLBAR_VERSION', Scrollbar.version)%0A
     .ser
@@ -142,16 +142,16 @@
 ervice%7B%0A
-
         
@@ -1532,12 +1532,8 @@
 e%5D =
- new
  Scr
@@ -1538,16 +1538,21 @@
 crollbar
+.init
 (elem, o
@@ -2337,450 +2337,8 @@
 ue,%0A
-            template: %60%0A                %3Carticle class=%22scroll-content%22 ng-transclude%3E%3C/article%3E%0A                %3Caside class=%22scrollbar-track scrollbar-track-x%22%3E%0A                    %3Cdiv class=%22scrollbar-thumb scrollbar-thumb-x%22%3E%3C/div%3E%0A                %3C/aside%3E%0A                %3Caside class=%22scrollbar-track scrollbar-track-y%22%3E%0A                    %3Cdiv class=%22scrollbar-thumb scrollbar-thumb-y%22%3E%3C/div%3E%0A                %3C/aside%3E%0A            %60,%0A
     
@@ -2569,19 +2569,119 @@
 m, attrs
-) %7B
+, ctrl, transclude) %7B%0A                const %7B speed, stepLength, easingDuration, easingCurve %7D = scope;
 %0A       
@@ -4110,24 +4110,24 @@
 y', () =%3E %7B%0A
-
             
@@ -4193,16 +4193,213 @@
      %7D);
+%0A%0A                const $scrollContent = angular.element(scrollbar.targets.content);%0A%0A                transclude((clones) =%3E %7B%0A                    $scrollContent.append(clones);%0A                %7D);
 %0A       

use Scrollbar.init() to build instance