lib/Ext/core/Ext-more.js
function(config) {
        var defaultSetupConfig = Ext.defaultSetupConfig,
            emptyFn = Ext.emptyFn,
            onReady = config.onReady || emptyFn,
            onUpdated = config.onUpdated || emptyFn,
            scope = config.scope,
            requires = Ext.Array.from(config.requires),
            extOnReady = Ext.onReady,
            head = Ext.getHead(),
            callback, viewport, precomposed;

        Ext.setup = function() {
            throw new Error("Ext.setup has already been called before");
        };

        delete config.requires;
        delete config.onReady;
        delete config.onUpdated;
        delete config.scope;

        Ext.require(['Ext.event.Dispatcher']);

        callback = function() {
            var listeners = Ext.setupListeners,
                ln = listeners.length,
                i, listener;

            delete Ext.setupListeners;
            Ext.isSetup = true;

            for (i = 0; i < ln; i++) {
                listener = listeners[i];
                listener.fn.call(listener.scope);
            }

            Ext.onReady = extOnReady;
            Ext.onReady(onReady, scope);
        };

        Ext.onUpdated = onUpdated;
        Ext.onReady = function(fn, scope) {
            var origin = onReady;

            onReady = function() {
                origin();
                Ext.onReady(fn, scope);
            };
        };

        config = Ext.merge({}, defaultSetupConfig, config);

        Ext.onDocumentReady(function() {
            Ext.factoryConfig(config, function(data) {
                Ext.event.Dispatcher.getInstance().setPublishers(data.eventPublishers);

                if (data.logger) {
                    Ext.Logger = data.logger;
                }

                if (data.animator) {
                    Ext.Animator = data.animator;
                }

                if (data.viewport) {
                    Ext.Viewport = viewport = data.viewport;

                    if (!scope) {
                        scope = viewport;
                    }

                    Ext.require(requires, function() {
                        Ext.Viewport.on('ready', callback, null, {single: true});
                    });
                }
                else {
                    Ext.require(requires, callback);
                }
            });

            if (!Ext.microloaded && navigator.userAgent.match(/IEMobile\/10\.0/)) {
                var msViewportStyle = document.createElement("style");
                msViewportStyle.appendChild(
                    document.createTextNode(
                        "@media screen and (orientation: portrait) {" +
                            "@-ms-viewport {width: 320px !important;}" +
                        "}" +
                        "@media screen and (orientation: landscape) {" +
                            "@-ms-viewport {width: 560px !important;}" +
                        "}"
                    )
                );
                head.appendChild(msViewportStyle);
            }
        });

        function addMeta(name, content) {
            var meta = document.createElement('meta');

            meta.setAttribute('name', name);
            meta.setAttribute('content', content);
            head.append(meta);
        }

        function addIcon(href, sizes, precomposed) {
            var link = document.createElement('link');
            link.setAttribute('rel', 'apple-touch-icon' + (precomposed ? '-precomposed' : ''));
            link.setAttribute('href', href);
            if (sizes) {
                link.setAttribute('sizes', sizes);
            }
            head.append(link);
        }

        function addStartupImage(href, media) {
            var link = document.createElement('link');
            link.setAttribute('rel', 'apple-touch-startup-image');
            link.setAttribute('href', href);
            if (media) {
                link.setAttribute('media', media);
            }
            head.append(link);
        }

        var icon = config.icon,
            isIconPrecomposed = Boolean(config.isIconPrecomposed),
            startupImage = config.startupImage || {},
            statusBarStyle = config.statusBarStyle || 'black',
            devicePixelRatio = window.devicePixelRatio || 1;


        if (navigator.standalone) {
            addMeta('viewport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0');
        }
        else {
            addMeta('viewport', 'initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, minimum-ui');
        }
        addMeta('apple-mobile-web-app-capable', 'yes');
        addMeta('apple-touch-fullscreen', 'yes');
        if (Ext.browser.is.ie) {
            addMeta('msapplication-tap-highlight', 'no');
        }

        // status bar style
        if (statusBarStyle) {
            addMeta('apple-mobile-web-app-status-bar-style', statusBarStyle);
        }

        if (Ext.isString(icon)) {
            icon = {
                57: icon,
                72: icon,
                114: icon,
                144: icon
            };
        }
        else if (!icon) {
            icon = {};
        }

        //<deprecated product=touch since=2.0.1>
        if ('phoneStartupScreen' in config) {
            //<debug warn>
            Ext.Logger.deprecate("[Ext.setup()] 'phoneStartupScreen' config is deprecated, please use 'startupImage' " +
                "config instead. Refer to the latest API docs for more details");
            //</debug>
            config['320x460'] = config.phoneStartupScreen;
        }

        if ('tabletStartupScreen' in config) {
            //<debug warn>
            Ext.Logger.deprecate("[Ext.setup()] 'tabletStartupScreen' config is deprecated, please use 'startupImage' " +
                "config instead. Refer to the latest API docs for more details");
            //</debug>
            config['768x1004'] = config.tabletStartupScreen;
        }

        if ('glossOnIcon' in config) {
            //<debug warn>
            Ext.Logger.deprecate("[Ext.setup()] 'glossOnIcon' config is deprecated, please use 'isIconPrecomposed' " +
                "config instead. Refer to the latest API docs for more details");
            //</debug>
            isIconPrecomposed = Boolean(config.glossOnIcon);
        }
        //</deprecated>

        if (Ext.os.is.iPad) {
            if (devicePixelRatio >= 2) {
                // Retina iPad - Landscape
                if ('1496x2048' in startupImage) {
                    addStartupImage(startupImage['1496x2048'], '(orientation: landscape)');
                }
                // Retina iPad - Portrait
                if ('1536x2008' in startupImage) {
                    addStartupImage(startupImage['1536x2008'], '(orientation: portrait)');
                }

                // Retina iPad
                if ('144' in icon) {
                    addIcon(icon['144'], '144x144', isIconPrecomposed);
                }
            }
            else {
                // Non-Retina iPad - Landscape
                if ('748x1024' in startupImage) {
                    addStartupImage(startupImage['748x1024'], '(orientation: landscape)');
                }
                // Non-Retina iPad - Portrait
                if ('768x1004' in startupImage) {
                    addStartupImage(startupImage['768x1004'], '(orientation: portrait)');
                }

                // Non-Retina iPad
                if ('72' in icon) {
                    addIcon(icon['72'], '72x72', isIconPrecomposed);
                }
            }
        }
        else {
            // Retina iPhone, iPod touch with iOS version >= 4.3
            if (devicePixelRatio >= 2 && Ext.os.version.gtEq('4.3')) {
                if (Ext.os.is.iPhone5) {
                    addStartupImage(startupImage['640x1096']);
                } else {
                    addStartupImage(startupImage['640x920']);
                }

                // Retina iPhone and iPod touch
                if ('114' in icon) {
                    addIcon(icon['114'], '114x114', isIconPrecomposed);
                }
            }
            else {
                addStartupImage(startupImage['320x460']);

                // Non-Retina iPhone, iPod touch, and Android devices
                if ('57' in icon) {
                    addIcon(icon['57'], null, isIconPrecomposed);
                }
            }
        }
    }
function(config) {
        var defaultSetupConfig = Ext.defaultSetupConfig,
            emptyFn = Ext.emptyFn,
            onReady = config.onReady || emptyFn,
            onUpdated = config.onUpdated || emptyFn,
            scope = config.scope,
            requires = Ext.Array.from(config.requires),
            extOnReady = Ext.onReady,
            head = Ext.getHead(),
            callback, viewport, precomposed;

        Ext.setup = function() {
            throw new Error("Ext.setup has already been called before");
        };

        delete config.requires;
        delete config.onReady;
        delete config.onUpdated;
        delete config.scope;

        Ext.require(['Ext.event.Dispatcher']);

        callback = function() {
            var listeners = Ext.setupListeners,
                ln = listeners.length,
                i, listener;

            delete Ext.setupListeners;
            Ext.isSetup = true;

            for (i = 0; i < ln; i++) {
                listener = listeners[i];
                listener.fn.call(listener.scope);
            }

            Ext.onReady = extOnReady;
            Ext.onReady(onReady, scope);
        };

        Ext.onUpdated = onUpdated;
        Ext.onReady = function(fn, scope) {
            var origin = onReady;

            onReady = function() {
                origin();
                Ext.onReady(fn, scope);
            };
        };

        config = Ext.merge({}, defaultSetupConfig, config);

        Ext.onDocumentReady(function() {
            Ext.factoryConfig(config, function(data) {
                Ext.event.Dispatcher.getInstance().setPublishers(data.eventPublishers);

                if (data.logger) {
                    Ext.Logger = data.logger;
                }

                if (data.animator) {
                    Ext.Animator = data.animator;
                }

                if (data.viewport) {
                    Ext.Viewport = viewport = data.viewport;

                    if (!scope) {
                        scope = viewport;
                    }

                    Ext.require(requires, function() {
                        Ext.Viewport.on('ready', callback, null, {single: true});
                    });
                }
                else {
                    Ext.require(requires, callback);
                }
            });

            if (!Ext.microloaded && navigator.userAgent.match(/IEMobile\/10\.0/)) {
                var msViewportStyle = document.createElement("style");
                msViewportStyle.appendChild(
                    document.createTextNode(
                        "@media screen and (orientation: portrait) {" +
                            "@-ms-viewport {width: 320px !important;}" +
                        "}" +
                        "@media screen and (orientation: landscape) {" +
                            "@-ms-viewport {width: 560px !important;}" +
                        "}"
                    )
                );
                head.appendChild(msViewportStyle);
            }
        });

        function addMeta(name, content) {
            var meta = document.createElement('meta');

            meta.setAttribute('name', name);
            meta.setAttribute('content', content);
            head.append(meta);
        }

        function addIcon(href, sizes, precomposed) {
            var link = document.createElement('link');
            link.setAttribute('rel', 'apple-touch-icon' + (precomposed ? '-precomposed' : ''));
            link.setAttribute('href', href);
            if (sizes) {
                link.setAttribute('sizes', sizes);
            }
            head.append(link);
        }

        function addStartupImage(href, media) {
            var link = document.createElement('link');
            link.setAttribute('rel', 'apple-touch-startup-image');
            link.setAttribute('href', href);
            if (media) {
                link.setAttribute('media', media);
            }
            head.append(link);
        }

        var icon = config.icon,
            isIconPrecomposed = Boolean(config.isIconPrecomposed),
            startupImage = config.startupImage || {},
            statusBarStyle = config.statusBarStyle || 'black',
            devicePixelRatio = window.devicePixelRatio || 1;


        if (navigator.standalone) {
            addMeta('viewport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0');
        }
        else {
            addMeta('viewport', 'initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, minimum-ui');
        }
        addMeta('apple-mobile-web-app-capable', 'yes');
        addMeta('apple-touch-fullscreen', 'yes');
        if (Ext.browser.is.ie) {
            addMeta('msapplication-tap-highlight', 'no');
        }

        // status bar style
        if (statusBarStyle) {
            addMeta('apple-mobile-web-app-status-bar-style', statusBarStyle);
        }

        if (Ext.isString(icon)) {
            icon = {
                57: icon,
                72: icon,
                114: icon,
                144: icon
            };
        }
        else if (!icon) {
            icon = {};
        }

        //<deprecated product=touch since=2.0.1>
        if ('phoneStartupScreen' in config) {
            //<debug warn>
            Ext.Logger.deprecate("[Ext.setup()] 'phoneStartupScreen' config is deprecated, please use 'startupImage' " +
                "config instead. Refer to the latest API docs for more details");
            //</debug>
            config['320x460'] = config.phoneStartupScreen;
        }

        if ('tabletStartupScreen' in config) {
            //<debug warn>
            Ext.Logger.deprecate("[Ext.setup()] 'tabletStartupScreen' config is deprecated, please use 'startupImage' " +
                "config instead. Refer to the latest API docs for more details");
            //</debug>
            config['768x1004'] = config.tabletStartupScreen;
        }

        if ('glossOnIcon' in config) {
            //<debug warn>
            Ext.Logger.deprecate("[Ext.setup()] 'glossOnIcon' config is deprecated, please use 'isIconPrecomposed' " +
                "config instead. Refer to the latest API docs for more details");
            //</debug>
            isIconPrecomposed = Boolean(config.glossOnIcon);
        }
        //</deprecated>

        if (Ext.os.is.iPad) {
            if (devicePixelRatio >= 2) {
                // Retina iPad - Landscape
                if ('1496x2048' in startupImage) {
                    addStartupImage(startupImage['1496x2048'], '(orientation: landscape)');
                }
                // Retina iPad - Portrait
                if ('1536x2008' in startupImage) {
                    addStartupImage(startupImage['1536x2008'], '(orientation: portrait)');
                }

                // Retina iPad
                if ('144' in icon) {
                    addIcon(icon['144'], '144x144', isIconPrecomposed);
                }
            }
            else {
                // Non-Retina iPad - Landscape
                if ('748x1024' in startupImage) {
                    addStartupImage(startupImage['748x1024'], '(orientation: landscape)');
                }
                // Non-Retina iPad - Portrait
                if ('768x1004' in startupImage) {
                    addStartupImage(startupImage['768x1004'], '(orientation: portrait)');
                }

                // Non-Retina iPad
                if ('72' in icon) {
                    addIcon(icon['72'], '72x72', isIconPrecomposed);
                }
            }
        }
        else {
            // Retina iPhone, iPod touch with iOS version >= 4.3
            if (devicePixelRatio >= 2 && Ext.os.version.gtEq('4.3')) {
                if (Ext.os.is.iPhone5) {
                    addStartupImage(startupImage['640x1096']);
                } else {
                    addStartupImage(startupImage['640x920']);
                }

                // Retina iPhone and iPod touch
                if ('114' in icon) {
                    addIcon(icon['114'], '114x114', isIconPrecomposed);
                }
            }
            else {
                addStartupImage(startupImage['320x460']);

                // Non-Retina iPhone, iPod touch, and Android devices
                if ('57' in icon) {
                    addIcon(icon['57'], null, isIconPrecomposed);
                }
            }
        }
    }
Ext.setup() is the entry-point to initialize a Sencha Touch application. Note that if your application makes
use of MVC architecture, use {@link Ext#application} instead.

This method accepts one single argument in object format. The most basic use of Ext.setup() is as follows:

Ext.setup({
onReady: function() {
// ...
}
});

This sets up the viewport, initializes the event system, instantiates a default animation runner, and a default
logger (during development). When all of that is ready, it invokes the callback function given to the `onReady` key.

The default scope (`this`) of `onReady` is the main viewport. By default the viewport instance is stored in
{@link Ext.Viewport}. For example, this snippet adds a 'Hello World' button that is centered on the screen:

Ext.setup({
onReady: function() {
this.add({
xtype: 'button',
centered: true,
text: 'Hello world!'
}); // Equivalent to Ext.Viewport.add(...)
}
});

@param {Object} config An object with the following config options:

@param {Function} config.onReady
A function to be called when the application is ready. Your application logic should be here.

@param {Object} config.viewport
A custom config object to be used when creating the global {@link Ext.Viewport} instance. Please refer to the
{@link Ext.Viewport} documentation for more information.

Ext.setup({
viewport: {
width: 500,
height: 500
},
onReady: function() {
// ...
}
});

@param {String/Object} config.icon
Specifies a set of URLs to the application icon for different device form factors. This icon is displayed
when the application is added to the device's Home Screen.

Ext.setup({
icon: {
57: 'resources/icons/Icon.png',
72: 'resources/icons/Icon~ipad.png',
114: 'resources/icons/Icon@2x.png',
144: 'resources/icons/Icon~ipad@2x.png'
},
onReady: function() {
// ...
}
});

Each key represents the dimension of the icon as a square shape. For example: '57' is the key for a 57 x 57
icon image. Here is the breakdown of each dimension and its device target:

- 57: Non-retina iPhone, iPod touch, and all Android devices
- 72: Retina iPhone and iPod touch
- 114: Non-retina iPad (first and second generation)
- 144: Retina iPad (third generation)

Note that the dimensions of the icon images must be exactly 57x57, 72x72, 114x114 and 144x144 respectively.

It is highly recommended that you provide all these different sizes to accommodate a full range of
devices currently available. However if you only have one icon in one size, make it 57x57 in size and
specify it as a string value. This same icon will be used on all supported devices.

Ext.setup({
icon: 'resources/icons/Icon.png',
onReady: function() {
// ...
}
});

@param {Object} config.startupImage
Specifies a set of URLs to the application startup images for different device form factors. This image is
displayed when the application is being launched from the Home Screen icon. Note that this currently only applies
to iOS devices.

Ext.setup({
startupImage: {
'320x460': 'resources/startup/320x460.jpg',
'640x920': 'resources/startup/640x920.png',
'640x1096': 'resources/startup/640x1096.png',
'768x1004': 'resources/startup/768x1004.png',
'748x1024': 'resources/startup/748x1024.png',
'1536x2008': 'resources/startup/1536x2008.png',
'1496x2048': 'resources/startup/1496x2048.png'
},
onReady: function() {
// ...
}
});

Each key represents the dimension of the image. For example: '320x460' is the key for a 320px x 460px image.
Here is the breakdown of each dimension and its device target:

- 320x460: Non-retina iPhone, iPod touch, and all Android devices
- 640x920: Retina iPhone and iPod touch
- 640x1096: iPhone 5 and iPod touch (fifth generation)
- 768x1004: Non-retina iPad (first and second generation) in portrait orientation
- 748x1024: Non-retina iPad (first and second generation) in landscape orientation
- 1536x2008: Retina iPad (third generation) in portrait orientation
- 1496x2048: Retina iPad (third generation) in landscape orientation

Please note that there's no automatic fallback mechanism for the startup images. In other words, if you don't specify
a valid image for a certain device, nothing will be displayed while the application is being launched on that device.

@param {Boolean} config.isIconPrecomposed
True to not having a glossy effect added to the icon by the OS, which will preserve its exact look. This currently
only applies to iOS devices.

@param {String} config.statusBarStyle
The style of status bar to be shown on applications added to the iOS home screen. Valid options are:

* `default`
* `black`
* `black-translucent`

@param {String[]} config.requires
An array of required classes for your application which will be automatically loaded before `onReady` is invoked.
Please refer to {@link Ext.Loader} and {@link Ext.Loader#require} for more information.

Ext.setup({
requires: ['Ext.Button', 'Ext.tab.Panel'],
onReady: function() {
// ...
}
});

@param {Object} config.eventPublishers
Sencha Touch, by default, includes various {@link Ext.event.recognizer.Recognizer} subclasses to recognize events fired
in your application. The list of default recognizers can be found in the documentation for
{@link Ext.event.recognizer.Recognizer}.

To change the default recognizers, you can use the following syntax:

Ext.setup({
eventPublishers: {
touchGesture: {
recognizers: {
swipe: {
// this will include both vertical and horizontal swipe recognizers
xclass: 'Ext.event.recognizer.Swipe'
}
}
}
},
onReady: function() {
// ...
}
});

You can also disable recognizers using this syntax:

Ext.setup({
eventPublishers: {
touchGesture: {
recognizers: {
swipe: null,
pinch: null,
rotate: null
}
}
},
onReady: function() {
// ...
}
});