             createScriptElement(loadURL);
         }
 
-        private function createScriptElement(loadURL:String):void {
+        protected function createScriptElement(loadURL:String):void {
             var js:Array = [];
             js.push("var script = document.createElement('script');");
             js.push("script.charset = '" + encoding + "';");

    import flash.events.TimerEvent;
    import flash.events.IOErrorEvent;
    import flash.utils.Timer;

    public class JSONPLoader extends EventDispatcher {
        public static var callbackObjects:Object = {};

        public var url:String;
        public var encoding:String = 'UTF-8';
        public var callbackQueryName:String = 'callback';
        public var data:Object;
        public var timeout:Number = 30;

        public static var inited:Boolean = false;

        public function JSONPLoader(url:String = ''):void {
            if (!ExternalInterface.available) throw (new IllegalOperationError('ExternalInterface.available should be true.'));
            if (!inited) init();

            this.url = url;
        }

        private function init():void {
            inited = true;
            ExternalInterface.addCallback('jsonpCallbacks', jsonpCallbacks);

        }

        public function load(url:String = undefined):void {
            url ||= this.url;
            var callbackFuncName:String = '_' + (new Date()).getTime().toString();
            jsAddCallback(callbackFuncName);

            var loadURL:String = url + ((url.indexOf('?') > 0) ?  '&' : '?') + 

            execExternalInterface(js.join("\n"));
        }

        protected static function jsonpCallbacks(callbackFuncName:String, obj:Object):void {
            var target:JSONPLoader = callbackObjects[callbackFuncName] as JSONPLoader;
            if (target) {
                target.data = obj;
                target.dispatchEvent(new Event(Event.COMPLETE));
                target.clearObserveTimer();
            } else {
                new Error("Don't found callback(" + callbackFuncName + ").");
            }
        }

        protected static function execExternalInterface(cmd:String):* {
            cmd = "(function() {" + cmd + ";})";
            return ExternalInterface.call(cmd);
        }

        protected function jsAddCallback(callbackFuncName:String):void {
            var js:String = 'if (!window.as3callbacks) window.as3callbacks = {};window.as3callbacks["' + callbackFuncName + 
                '"] = function(obj) { document.getElementsByName("' + 
                ExternalInterface.objectID + '")[0].jsonpCallbacks("' + callbackFuncName + '",obj) };';
            execExternalInterface(js);
        }

        protected function jsRemoveCallback(callbackFuncName:String):void {
            var js:String = 'if (window.as3callbacks) window.as3callbacks["' + callbackFuncName + '"] = function() {};';
            execExternalInterface(js);
        }

        protected var observeTimer:Timer;
        protected function observeTimeout(sec:Number, callbackFuncName:String):void
        {
            observeTimer = new Timer(sec * 1000, 1);
            observeTimer.addEventListener(TimerEvent.TIMER, timeoutErrorHandlerBind(callbackFuncName), false, 1, true);
            observeTimer.start();
        }

        protected function timeoutErrorHandlerBind(callbackFuncName:String):Function {
            return function(e:TimerEvent):void {
                jsRemoveCallback(callbackFuncName);
                timeoutErrorHandler(e);
            }
        }

        protected function timeoutErrorHandler(e:TimerEvent):void 
        {
            dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR, false, false, 'Request timeout'));
            clearObserveTimer();
        }

        // FIXME: Public namespace should be protected.
        public function clearObserveTimer():void {
            observeTimer.removeEventListener(TimerEvent.TIMER, timeoutErrorHandler);
            observeTimer.stop();
            observeTimer = null;
