text: ///////////////////////////////////////////////////////////////////////////
  // Copyright © 2014 Esri. All Rights Reserved.
  //
  // Licensed under the Apache License Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //    http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  ///////////////////////////////////////////////////////////////////////////
  
  define([
    'dojo/_base/lang',
    'dojo/_base/array',
    'dojo/aspect',
    'dojo/Deferred',
    'dojo/cookie',
    'dojo/json',
    'dojo/topic',
    'dojo/request/script',
    'esri/kernel',
    'esri/config',
    'esri/request',
    'esri/urlUtils',
    'esri/IdentityManager',
    'esri/arcgis/OAuthInfo',
    'jimu/portalUrlUtils',
    'jimu/utils'
  ],
  function(lang, array, aspect, Deferred, cookie, json, topic, dojoScript, esriNS, esriConfig,
    esriRequest, esriUrlUtils, IdentityManager, OAuthInfo, portalUrlUtils, jimuUtils) {
    /*jshint -W069 */
  
    //patch for JS API 3.10
    var hasMethod = typeof cookie.getAll === 'function';
    if(!hasMethod){
      cookie.getAll = function(e){
        var result = [];
        var v = cookie(e);
        if(v){
          result.push(v);
        }
        return result;
      };
    }
  
    //events:
    //anyUserSignIn: any user sign in, including portal user and arcgis server user
    //userSignIn: current portal user sign in
    //userSignOut: current portal user sign out
  
    var mo = {
      portalUrl: null,
      cookiePath: '/',
      _started: false,
      webTierPortalUrls: [],
  
      //public methods:
      //isInBuilderWindow
      //isInConfigOrPreviewWindow
      //signInPortal
      //userHaveSignInPortal
      //isValidCredential
      //isValidPortalCredentialOfPortalUrl
      //isWebTierPortal
      //addAuthorizedCrossOriginDomains
      //addWithCredentialDomain
      //getPortalCredential
      //getUserIdByToken
      //xtGetCredentialFromCookie
      //isStart
      //startup
  
      isInBuilderWindow: function(){
        return !!(window.isBuilder);
      },
  
      isInConfigOrPreviewWindow: function(){
        var b = false;
        try{
          b = !window.isBuilder && window.parent && window.parent !== window &&
          window.parent.isBuilder;
        }catch(e){
          console.log(e);
          b = false;
        }
        return !!b;
      },
  
      isStringStartWith: function(str, prefix){
        return str.substr(0, prefix.length) === prefix;
      },
  
      getCookiePath: function() {
        return this.cookiePath;
      },
  
      setPortalUrl: function(_portalUrl) {
        var thePortalUrl = portalUrlUtils.getStandardPortalUrl(_portalUrl);
        if (thePortalUrl) {
          thePortalUrl += '/';
        }
        this.portalUrl = thePortalUrl;
      },
  
      getPortalUrl: function() {
        return this.portalUrl;
      },
  
      isWebTierPortal: function(_portalUrl){
        var def = new Deferred();
        var thePortalUrl = portalUrlUtils.getStandardPortalUrl(_portalUrl);
        var sharingUrl = thePortalUrl + "/sharing";
        var tokenUrl = thePortalUrl + "/sharing/rest/generateToken?f=json";
        var httpsTokenUrl = portalUrlUtils.setHttpsProtocol(tokenUrl);
        var httpsSharingUrl = portalUrlUtils.setHttpsProtocol(sharingUrl);
  
        dojoScript.get(httpsTokenUrl, {
          jsonp: 'callback'
        }).then(lang.hitch(this, function(response){
          //if web-tier(iwa/pki), the response is {expires,ssl,token}
          //else the response is :
          // {
          //   "error": {
          //     "code": 400,
          //     "message": "Unable to generate token.",
          //     "details": ["'username' must be specified.",
          //                 "'password' must be specified.",
          //                 "'referer' must be specified."]
          //   }
          // }
          if(response.token){
            //web-tier authorization
  
            this.webTierPortalUrls.push(thePortalUrl);
  
            //we should not save cookie of web-tier authorization
            this.removeWabAuthCookie();
  
            //if portal uses LDAP authorization and HTTPS-Only enabled,
            //esriNS.id.getCredential will fail if uses http protocol
            //so we should use https sharing url here
            esriNS.id.getCredential(httpsSharingUrl).then(lang.hitch(this, function(credential){
              if(!credential.token){
                credential.token = response.token;
              }
  
              //#releated issue 4096
              /*****************************************
               * Workaround to fix API 3.14 bug that doesn't use withCredentials when web-tier.
               *****************************************/
              //var portalInfo = esriNS.id.findServerInfo(credential.server);
  
              // If the portal uses web-tier authentication, add the server host
              // to cors list and specify that withCredentials flag must be enabled.
              //if (portalInfo.webTierAuth) {//portalInfo.webTierAuth should be true here
  
              // REMOVE the current entry in CORS list for this portal.
              var corsListIndex = esriUrlUtils.canUseXhr(credential.server, true);
              if (corsListIndex > -1) {
                esriConfig.defaults.io.corsEnabledServers.splice(corsListIndex, 1);
              }
  
              // ADD a new entry for this portal in CORS list.
              // esriConfig.defaults.io.corsEnabledServers.push({
              //   host: portalUrlUtils.getServerByUrl(thePortalUrl),
              //   withCredentials: true
              // });
              this._pushCorsEnabledServerInfo({
                host: portalUrlUtils.getServerByUrl(thePortalUrl),
                withCredentials: true
              });
              //}
              /*****************************************/
  
              //should not save credential of iwa to cookie because the cookie is not useful
              def.resolve(true);
            }), lang.hitch(this, function(){
              def.resolve(true);
            }));
          }
          else{
            //normal authorization
            def.resolve(false);
          }
        }), lang.hitch(this, function(err){
          //network error
          console.error(err);
          def.reject(err);
        }));
  
        return def;
      },
  
      addAuthorizedCrossOriginDomains: function(domains){
        if(domains && domains.length > 0){
          for(var i = 0; i < domains.length; i++) {
            this.addWithCredentialDomain(domains[i]);
          }
        }
      },
  
      addWithCredentialDomain: function(domain){
        // add if trusted host is not null, undefined, or empty string
        if(domain && typeof domain === 'string'){
          var corsEnabledServers = esriConfig.defaults.io.corsEnabledServers;
  
          var server = portalUrlUtils.getServerByUrl(domain);
          var serverWithProtocol = portalUrlUtils.getServerWithProtocol(domain);
          if(!serverWithProtocol){
            serverWithProtocol = "http://" + server;
          }
  
          // REMOVE the current entry in CORS list
          var corsListIndex = esriUrlUtils.canUseXhr(serverWithProtocol, true);
          if (corsListIndex > -1) {
            corsEnabledServers.splice(corsListIndex, 1);
          }
  
          // ADD a new entry for this portal in CORS list.
          // corsEnabledServers.push({
          //   host: server,
          //   withCredentials: true
          // });
          this._pushCorsEnabledServerInfo({
            host: server,
            withCredentials: true
          });
        }
      },
  
      _pushCorsEnabledServerInfo: function(serverInfo){
        /*jshint -W083 */
        if(!serverInfo){
          return;
        }
  
        var corsEnabledServers = esriConfig.defaults.io.corsEnabledServers;
        var methodNames = ["charAt", "charCodeAt", "concat", "endsWith", "indexOf",
          "lastIndexOf", "localeCompare", "match", "replace", "search", "slice", "split",
          "startsWith", "substr", "substring", "toLocaleLowerCase", "toLocaleUpperCase",
          "toLowerCase", "toString", "toUpperCase", "trim", "trimLeft", "trimRight", "valueOf"];
  
        if(typeof serverInfo === "object" && typeof serverInfo.host === "string"){
          //object
          for(var key1 in serverInfo.host){
            if(typeof serverInfo.host[key1] === 'function'){
              serverInfo[key1] = function(){
                return serverInfo.host[key1].apply(serverInfo.host, arguments);
              };
            }else{
              serverInfo[key1] = serverInfo.host[key1];
            }
          }
  
          serverInfo.length = serverInfo.host.length;
  
          array.forEach(methodNames, function(methodName){
            if(typeof serverInfo.host[methodName] === 'function'){
              serverInfo[methodName] = function(){
                return serverInfo.host[methodName].apply(serverInfo.host, arguments);
              };
            }
          });
        }
  
        corsEnabledServers.push(serverInfo);
      },
  
      tryRegisterCredential: function( /* esri.Credential */ credential) {
        if(!this.isValidCredential(credential)){
          return false;
        }
  
        var isExist = array.some(esriNS.id.credentials, lang.hitch(this, function(c) {
          return credential.token === c.token;
        }));
  
        if (!isExist) {
          esriNS.id.credentials.push(credential);
          return true;
        }
  
        return false;
      },
  
      registerToken: function(token){
        var sharingRest = portalUrlUtils.getSharingUrl(this.portalUrl);
        var cre = esriNS.id.findCredential(sharingRest);
        if(cre){
          //remove the exists credential
          array.some(esriNS.id.credentials, lang.hitch(this, function(c, i) {
            if(this.isValidPortalCredentialOfPortalUrl(this.portalUrl, c)){
              esriNS.id.credentials.splice(i, 1);
              return true;
            }
          }));
        }
  
        return this._getTokenInfo(token).then(function(tokenInfo){
          esriNS.id.registerToken(tokenInfo);
        });
      },
  
      _getTokenInfo: function(token){
        var portalSelfUrl = portalUrlUtils.getPortalSelfInfoUrl(this.portalUrl);
        portalSelfUrl += '?f=json&token=' + token;
        return dojoScript.get(portalSelfUrl, {
          jsonp: 'callback'
        }).then(lang.hitch(this, function(res){
          if(res.user){
            return {
              server: portalUrlUtils.getSharingUrl(this.portalUrl),
              ssl: res.allSSL,
              token: token,
              userId: res.user.username
            };
          }else{
            throw Error(window.jimuNls.urlParams.invalidToken);
          }
        }), function(err){
          console.error(err);
          throw Error(window.jimuNls.urlParams.validateTokenError);
        });
      },
  
      _isInvalidPortalUrl: function(s){
        return s && typeof s === 'string' && lang.trim(s);
      },
  
      signInPortal: function(_portalUrl){
        var def = new Deferred();
  
        if(!this._isInvalidPortalUrl(_portalUrl)){
          setTimeout(lang.hitch(this, function(){
            def.reject("Invalid portalurl.");
          }), 0);
        }
        else{
          var thePortalUrl = portalUrlUtils.getStandardPortalUrl(_portalUrl);
          var sharingUrl = portalUrlUtils.getSharingUrl(thePortalUrl);
          var credential = this.getPortalCredential(thePortalUrl);
          if(credential){
            setTimeout(lang.hitch(this, function(){
              def.resolve(credential);
            }), 0);
          }
          else{
            def = esriNS.id.getCredential(sharingUrl);
          }
        }
  
        return def;
      },
  
      _loadPortalSelfInfo: function(_portalUrl){
        var portalSelfUrl = portalUrlUtils.getPortalSelfInfoUrl(_portalUrl);
        return esriRequest({
          url: portalSelfUrl,
          handleAs: 'json',
          content: {f:'json'},
          callbackParamName: 'callback'
        });
      },
  
      registerOAuthInfo: function(portalUrl, appId){
        var validParams = portalUrl && typeof portalUrl === 'string' &&
         appId && typeof appId === 'string';
        if(!validParams){
          return null;
        }
        var oAuthInfo = esriNS.id.findOAuthInfo(portalUrl);
        if(!oAuthInfo){
          var oauthReturnUrl = window.location.protocol + "//" + window.location.host +
           require.toUrl("jimu") + "/oauth-callback.html";
          oAuthInfo = new OAuthInfo({
            appId: appId,
            expiration: 14 * 24 * 60,
            portalUrl: portalUrl,
            authNamespace: '/',
            popup: true,
            popupCallbackUrl: oauthReturnUrl
          });
          esriNS.id.registerOAuthInfos([oAuthInfo]);
        }
        oAuthInfo.appId = appId;
        return oAuthInfo;
      },
  
      signOutAll: function(){
        var portalUrl = portalUrlUtils.getStandardPortalUrl(this.portalUrl);
        var sharingRest = portalUrl + '/sharing/rest';
        var cre = esriNS.id.findCredential(sharingRest);
        var isPublishEvent = !!cre;
        if(window.appInfo.isRunInPortal){
          this.removeEsriAuthCookieStorage();
        }
        else{
          this.removeWabAuthCookie();
        }
        esriNS.id.destroyCredentials();
        //if sign in portal with oAuth, esriNS.id._oAuthHash will not be null
        esriNS.id._oAuthHash = null;
        if(isPublishEvent){
          this._publishCurrentPortalUserSignOut(portalUrl);
        }
      },
  
      userHaveSignInPortal: function(_portalUrl) {
        return !!this.getPortalCredential(lang.trim(_portalUrl || ''));
      },
  
      isValidCredential: function(/* esri.Credential */ credential){
        var isValid = false;
  
        if(credential){
          var token = credential.token;
          var server = credential.server;
          var theScope = credential['scope'];
          var isValidToken = token && typeof token === "string" && lang.trim(token);
          var isValidServer = server && typeof server === "string" && lang.trim(server);
          var isValidScope = theScope === 'portal' || theScope === "server";
          var isValidExpires = true;
          if (credential.expires) {
            var expireTime = parseInt(credential.expires, 10);
            var nowDate = new Date();
            var nowTime = nowDate.getTime();
            isValidExpires = expireTime > nowTime;
          }
          isValid = isValidToken && isValidServer && isValidScope && isValidExpires;
        }
  
        return isValid;
      },
  
      isValidPortalCredentialOfPortalUrl: function(thePortalUrl, credential){
        var isValid = false;
  
        if(this.isValidCredential(credential)){
          var isPortalScope = credential['scope'] === 'portal';
          var isSameServer = portalUrlUtils.isSameServer(thePortalUrl, credential.server);
          isValid = isPortalScope && isSameServer;
        }
  
        return isValid;
      },
  
      getPortalCredential: function(_portalUrl) {
        var credential = null;
        var thePortalUrl = lang.trim(_portalUrl || '');
        if (!thePortalUrl) {
          return null;
        }
        thePortalUrl = portalUrlUtils.getStandardPortalUrl(thePortalUrl);
        //var credentials =[];
  
        //var sharingUrl = thePortalUrl + '/sharing';
        //c = esriNS.id.findCredential(sharingUrl);
  
        //find portal credential from esriNS.id.credentials
        credential = this._filterPortalCredential(thePortalUrl, esriNS.id.credentials);
  
        return credential;
      },
  
      //save wab_auth cookie, register token, return credential
      saveAndRegisterCookieToCredential: function(cookieValue){
        //server,token,userId,expires
        var wabAuth = lang.clone(cookieValue);
        wabAuth.referer = window.location.host;
        wabAuth.scope = 'portal';
        wabAuth.isAdmin = !!wabAuth.isAdmin;
  
        this.saveWabCookie(wabAuth);
  
        var sharingRest = wabAuth.server + "/sharing/rest";
        wabAuth.server = sharingRest;
        esriNS.id.registerToken(wabAuth);
        var cre = esriNS.id.findCredential(sharingRest, wabAuth.userId);
        //cre.resources = ["http://portalUrl/sharing/rest"]
        return cre;
      },
  
      //save wab_auth cookie, register token, return credential
      registerAuth2Hash: function(_authHash){
        var authHash = lang.clone(_authHash);
        //{access_token,expires_in,persist,username,state}
  
        //check expires
        var expiresInS = parseInt(authHash.expires_in, 10); //seconds
        var expiresInMS = expiresInS * 1000; //milliseconds
        var dateNow = new Date();
        var expiresTime = dateNow.getTime() + expiresInMS;
        var server = portalUrlUtils.getStandardPortalUrl(authHash.state.portalUrl);
  
        var wabAuth = {
          referer: window.location.host,
          server: server,
          token: authHash.access_token,
          expires: expiresTime,
          userId: authHash.username,
          scope: 'portal',
          isAdmin: !!authHash.isAdmin
        };
  
        var cre = this.saveAndRegisterCookieToCredential(wabAuth);
        return cre;
      },
  
      saveWabCookie: function(wabAuth){
        var cookieName = "wab_auth";
        this.removeCookie(cookieName);
        cookie(cookieName, json.stringify(wabAuth), {
          expires: new Date(wabAuth.expires),
          path: '/'
        });
      },
  
      removeWabAuthCookie: function(){
        this.removeCookie("wab_auth");
      },
  
      removeEsriAuthCookieStorage: function() {
        this.removeCookie('esri_auth');
  
        var itemName = "esriJSAPIOAuth";
        if (window.localStorage) {
          window.localStorage.removeItem(itemName);
        }
        if (window.sessionStorage) {
          window.sessionStorage.removeItem(itemName);
        }
      },
  
      _filterPortalCredential: function(thePortalUrl, credentials){
        var credential = null;
  
        if(credentials && credentials.length > 0){
          var filterCredentials = array.filter(credentials, lang.hitch(this, function(c){
            return this.isValidPortalCredentialOfPortalUrl(thePortalUrl, c);
          }));
  
          //return the last valid credential
          if(filterCredentials.length > 0){
            var lastIndex = filterCredentials.length - 1;
            credential = filterCredentials[lastIndex];
          }
        }
  
        return credential;
      },
  
      _removePortalCredential: function(_portalUrl) {
        var thePortalUrl = lang.trim(_portalUrl || '');
        if (!thePortalUrl) {
          return;
        }
        thePortalUrl = portalUrlUtils.getStandardPortalUrl(thePortalUrl);
  
        var filterCredentials = array.filter(esriNS.id.credentials, lang.hitch(this, function(c) {
          return this.isValidPortalCredentialOfPortalUrl(thePortalUrl, c);
        }));
  
        while (filterCredentials.length > 0) {
          var c = filterCredentials[0];
          //if c has attribute _oAuthCred,
          // c._oAuthCred will also destroy and remove relevant info from storage
          c.destroy();
          filterCredentials.splice(0, 1);
        }
  
        esriNS.id.credentials = array.filter(esriNS.id.credentials, lang.hitch(this, function(c) {
          return !this.isValidPortalCredentialOfPortalUrl(thePortalUrl, c);
        }));
      },
  
      getUserIdByToken: function(token, _portalUrl) {
        var def = new Deferred();
        var validToken = token && typeof token === 'string';
        var validPortalUrl = _portalUrl && typeof _portalUrl === 'string';
        if (validToken && validPortalUrl) {
          var thePortalUrl = portalUrlUtils.getStandardPortalUrl(_portalUrl);
          var cs = array.filter(esriNS.id.credentials, lang.hitch(this, function(credential) {
            var b = credential.token === token && credential.userId;
            var isSameServer = portalUrlUtils.isSameServer(thePortalUrl, credential.server);
            return b && isSameServer;
          }));
  
          if(cs.length > 0){
            var c = cs[0];
            setTimeout(lang.hitch(this, function(){
              def.resolve(c.userId);
            }), 0);
            return def;
          }
  
          var url = portalUrlUtils.getCommunitySelfUrl(thePortalUrl);
          esriRequest({
            url: url,
            handleAs: 'json',
            content: {
              f: 'json'
            },
            callbackParamName: 'callback'
          }).then(lang.hitch(this, function(response) {
            var username = (response && response.username) || '';
            def.resolve(username);
          }), lang.hitch(this, function(err) {
            console.error(err);
            def.reject('fail to get userId by token');
          }));
          return def;
        } else {
          setTimeout(lang.hitch(this, function(){
            def.reject('invalid parameters');
          }), 0);
          return def;
        }
      },
  
      xtGetCredentialFromCookie: function(portalUrl){
        //{referer,server,scope,token,expires,userId,isAdmin}
        var strAuth = cookie("wab_auth");
        var wabAuth = null;
  
        if(strAuth){
          try{
            wabAuth = json.parse(strAuth);
          }
          catch(e){
            console.error(e);
          }
        }
  
        if(!(wabAuth && typeof wabAuth === 'object')){
          return null;
        }
  
        //check server
        var server = wabAuth.server;
        var isValidServer = portalUrlUtils.isSameServer(portalUrl, server);
        if(!isValidServer){
          return null;
        }
  
        //check referer
        var isValidReferer = window.location.host === wabAuth.referer;
        if (!isValidReferer) {
          return null;
        }
  
        //check expires
        wabAuth.expires = parseInt(wabAuth.expires, 10);
        var dateNow = new Date();
        var timeNow = dateNow.getTime();
        var isValidExpires = wabAuth.expires > timeNow;
        if (!isValidExpires) {
          this.removeCookie("wab_auth");
          return null;
        }
  
        //var sharingUrl = portalUrlUtils.getSharingUrl(portalUrl);
        //wabAuth.resources = [sharingUrl];
  
        //expires,isAdmin,server,ssl,token,userId,scope
        //var cre = new Credential(wabAuth);
        //return cre;
  
        //Note: server must include '/sharing'
        var restUrl = portalUrl + '/sharing/rest';
        wabAuth.server = restUrl;
        var cre = esriNS.id.findCredential(restUrl);
        if(!cre){
          esriNS.id.registerToken(wabAuth);
        }
  
        cre = esriNS.id.findCredential(restUrl);
  
        return cre;
      },
  
      removeCookie: function(cookieName) {
        var path = this.getCookiePath();
        jimuUtils.removeCookie(cookieName, path);
      },
  
      _getDomainsByServerName: function(serverName){
        var splits = serverName.split('.');
        var length = splits.length;
        var domains = array.map(splits, lang.hitch(this, function(v, index){
          /*jshint unused:false*/
          var arr = splits.slice(index, length);
          var str = "";
          var lastIndex = arr.length - 1;
          array.forEach(arr, lang.hitch(this, function(s, idx){
            str += s;
            if(idx !== lastIndex){
              str += '.';
            }
          }));
          return str;
        }));
        return domains;
      },
  
      _publishCurrentPortalUserSignIn: function(/* esri.Credential */ credential){
        if(!this.isValidCredential(credential)){
          return;
        }
  
        try{
          topic.publish('userSignIn', credential);
        }
        catch(e){
          console.error(e);
        }
      },
  
      _publishAnyUserSignIn: function(/* esri.Credential */ credential){
        if(!this.isValidCredential(credential)){
          return;
        }
  
        try{
          topic.publish('anyUserSignIn', credential);
        }
        catch(e){
          console.error(e);
        }
      },
  
      _publishCurrentPortalUserSignOut: function(thePortalUrl){
        try {
          topic.publish('userSignOut', thePortalUrl);
        } catch (e) {
          console.error(e);
        }
      },
  
      _signInSuccess: function(/* esri.Credential */ credential /*, persist*/) {
        try{
          var isCreOfCurrentPortal = this.isValidPortalCredentialOfPortalUrl(this.portalUrl,
                                                                             credential);
  
          if(isCreOfCurrentPortal){
            this._publishCurrentPortalUserSignIn(credential);
          }
  
          this._publishAnyUserSignIn(credential);
        }
        catch(e){
          console.error(e);
        }
      },
  
      _bindEvents: function(){
        //signIn event
        aspect.after(esriNS.id, 'signIn', lang.hitch(this, function(def , signInInputParams){
          // var url = signInInputParams[0];
          var serverInfo = signInInputParams[1];
          console.log(serverInfo);
          aspect.after(def, 'callback', lang.hitch(this, function(returnValue, callbackInputParams){
            /*jshint unused:false*/
            var credential = callbackInputParams[0];
            //esriNS.id._isRESTService
            this._signInSuccess(credential, false);
          }));
          return def;
        }));
      },
  
      isStart: function(){
        return this._started;
      },
  
      startup: function(){
        if(this._started){
          return;
        }
  
        if(this.isInConfigOrPreviewWindow()){
          var builderWindow = window.parent;
          if(builderWindow){
            var builderIM = builderWindow.esri && builderWindow.esri.id;
            if(builderIM){
              IdentityManager = builderIM;
              //use builder's IdentityManager
              esriNS.id = builderIM;
              var currentIO = window.esriConfig.defaults.io;
              var builderIO = builderWindow.esriConfig.defaults.io;
              //need to sync properties of defaults.io between curent window and builder window
              currentIO.corsEnabledServers = builderIO.corsEnabledServers;
              currentIO.webTierAuthServers = builderIO.webTierAuthServers;
              //for 3.11 and lower api
              currentIO._processedCorsServers = builderIO._processedCorsServers;
              //for 3.12 and higher api
              currentIO.corsStatus = builderIO.corsStatus;
            }
          }
        }
  
        this._bindEvents();
        this._started = true;
      }
    };
  
    mo.startup();
  
    return mo;
  });