// Generated by CoffeeScript 1.12.7
var Connector,
  extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  hasProp = {}.hasOwnProperty,
  indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

Connector = (function(superClass) {
  extend(Connector, superClass);

  function Connector() {
    return Connector.__super__.constructor.apply(this, arguments);
  }

  Connector.prototype.api = {
    search: null,
    suggest: null,
    eas: null
  };

  Connector.prototype.init = function() {
    var baseConfig, connector, deferred, pluginUrl;
    this.__unreachableEasydbs = [];
    deferred = new CUI.Deferred();
    if (ez5.session.getPref("connector")) {
      connector = CUI.util.copyObject(ez5.session.getPref("connector"), true);
      if (!CUI.util.isArray(connector != null ? connector.easydbs : void 0)) {
        connector = void 0;
      }
    } else {
      connector = void 0;
    }
    baseConfig = ez5.session.getBaseConfig("plugin", "easydb-connector-plugin");
    baseConfig = baseConfig.system || baseConfig;
    this.__base_config_fylr = (baseConfig != null ? baseConfig.fylr_url : void 0) || {};
    pluginUrl = ez5.pluginManager.getPlugin("easydb-connector-plugin").getPluginURL();
    if (CUI.util.isEmpty(pluginUrl)) {
      console.warn("Connector::init -> The connect was not initialized because the 'plugin url' is empty.");
      return CUI.rejectedPromise();
    }
    ez5.server({
      url: ez5.getAbsoluteURL(pluginUrl) + "/list?gettokens=1",
      handle_error: (function(_this) {
        return function() {
          return true;
        };
      })(this)
    }).done((function(_this) {
      return function(data) {
        var _easydb, active, easydb, i, idx, j, l, len, len1, len2, reasydb, ref1, ref2, ref3, url;
        ref1 = (data != null ? data.easydbs : void 0) || [];
        for (idx = i = 0, len = ref1.length; i < len; idx = ++i) {
          easydb = ref1[idx];
          if (!easydb.token && !easydb.error) {
            continue;
          }
          if (connector !== void 0) {
            active = false;
            ref2 = connector.easydbs || [];
            for (j = 0, len1 = ref2.length; j < len1; j++) {
              _easydb = ref2[j];
              if (_easydb.name === easydb.name && _easydb.active) {
                active = true;
                break;
              }
            }
          } else {
            active = true;
          }
          url = easydb.url;
          if (url.endsWith("/")) {
            url = url.substr(0, url.length - 1);
          }
          _this.__config.easydbs.push({
            idx: idx,
            active: active,
            name: easydb.name,
            url: url,
            version: easydb.version,
            token: easydb.token,
            error: easydb.error
          });
        }
        if (!_this.isEnabled()) {
          return deferred.resolve();
        }
        ref3 = _this.__config.easydbs;
        for (idx = l = 0, len2 = ref3.length; l < len2; idx = ++l) {
          easydb = ref3[idx];
          reasydb = new RemoteEasydb({
            easydb: easydb
          });
          if (!easydb.token && !CUI.util.isEmpty(easydb.error) && easydb.active) {
            _this.addUnrecheableEasydb(reasydb);
            continue;
          }
          console.info("Remote easydb:", reasydb.getServerUrl(), "active:", reasydb.isActive());
          if (!reasydb.isActive()) {
            continue;
          }
          _this.__easydbs.push(reasydb);
        }
        if (_this.getActiveEasydbs().length > 0) {
          ez5.connector.wrapServerRequestApi();
        }
        return deferred.resolve();
      };
    })(this)).fail((function(_this) {
      return function(xhr) {
        var ref1;
        if (((ref1 = xhr.responseJSON) != null ? ref1.code : void 0) === "error.user.no_system_right") {
          console.warn("Connector::init - No rights to use connector.");
          return deferred.resolve();
        }
        console.error("Connector::init - Error getting the tokens of the instances.", xhr);
        return deferred.reject();
      };
    })(this));
    return deferred.promise();
  };

  Connector.prototype.getActiveEasydbs = function() {
    return this.__easydbs || [];
  };

  Connector.prototype.addUnrecheableEasydb = function(easydb) {
    if (!this.__unreachableEasydbs) {
      this.__unreachableEasydbs = [];
    }
    return CUI.util.pushOntoArray(easydb, this.__unreachableEasydbs);
  };

  Connector.prototype.getAvailableEasydbs = function() {
    return this.__config.easydbs || [];
  };

  Connector.prototype.isEnabled = function() {
    if (!this.hasRights()) {
      return false;
    }
    return true;
  };

  Connector.prototype.hasRights = function() {
    return ez5.session.hasSystemRight("root", "plugin.easydb-connector-plugin.allow_use");
  };

  Connector.prototype.isAvailable = function() {
    return this.isEnabled() && this.getAvailableEasydbs().length > 0;
  };

  Connector.prototype.logout = function() {
    var easydb, i, len, promises, ref1;
    promises = [];
    ref1 = this.__easydbs || [];
    for (i = 0, len = ref1.length; i < len; i++) {
      easydb = ref1[i];
      promises.push(easydb.logout());
    }
    return CUI.when(promises);
  };

  Connector.prototype.readOpts = function() {
    Connector.__super__.readOpts.call(this);
    return this.__easydb_by_instance = {};
  };

  Connector.prototype.showConfiguration = function() {
    var data, dfr, easydb, i, j, l, len, len1, len2, mod, reasydb, ref1, ref2, ref3, save_btn, tbl;
    data = CUI.util.copyObject(this.__config, true);
    ref1 = data.easydbs;
    for (i = 0, len = ref1.length; i < len; i++) {
      easydb = ref1[i];
      if (easydb.active) {
        ref2 = this.__easydbs;
        for (j = 0, len1 = ref2.length; j < len1; j++) {
          reasydb = ref2[j];
          if (reasydb._easydb.idx === easydb.idx) {
            easydb.status = $$("connector.configuration.status.connected");
            easydb.__class = "ez5-connector--active";
          }
        }
        ref3 = this.__unreachableEasydbs;
        for (l = 0, len2 = ref3.length; l < len2; l++) {
          reasydb = ref3[l];
          if (reasydb._easydb.idx === easydb.idx) {
            easydb.status = reasydb.getLastError() || $$("remote.easydb.connect.unknown_error");
            easydb.__class = "ez5-connector--error";
          }
        }
      } else {
        easydb.status = $$("connector.configuration.status.inactive");
        easydb.__class = "ez5-connector--inactive";
      }
      easydb.internet_address = "[" + easydb.url + "](" + easydb.url + ")";
      delete easydb.url;
      delete easydb.login;
      delete easydb.password;
    }
    tbl = new CUI.DataTable({
      data: data,
      maximize: true,
      "class": "ez5-connector-config-table",
      name: "easydbs",
      new_rows: "none",
      fields: [
        {
          type: CUI.Checkbox,
          group: "connector",
          name: "active",
          form: {
            label: $$("connector.configuration.label.active")
          }
        }, {
          type: CUI.Output,
          name: "name",
          form: {
            label: $$("connector.configuration.label.name")
          }
        }, {
          type: CUI.Output,
          name: "internet_address",
          markdown: true,
          form: {
            label: $$("connector.configuration.label.internet_address")
          }
        }, {
          type: CUI.Output,
          name: "status",
          markdown: true,
          multiline: true,
          tooltip: {
            markdown: true,
            content: function(tooltip) {
              var msg, ref4;
              data = CUI.dom.data(tooltip.getElement(), "element").getData();
              if (data) {
                msg = ((ref4 = data.error) != null ? ref4.msg : void 0) || data.status;
                if (CUI.util.isPlainObject(msg)) {
                  msg = CUI.util.dump(msg);
                }
              }
              return new CUI.Label({
                text: "" + msg,
                multiline: true
              });
            }
          },
          form: {
            column: "maximize",
            label: $$("connector.configuration.label.status")
          }
        }
      ]
    });
    tbl.start();
    save_btn = new LocaButton({
      loca_key: "connector.save.button",
      left: true,
      onClick: (function(_this) {
        return function(ev, btn) {
          if (ev.hasModifierKey()) {
            console.debug(CUI.util.dump(data));
            return;
          }
          btn.disable();
          btn.startSpinner();
          return ez5.session.savePref("connector", data).always(function() {
            btn.enable();
            return btn.stopSpinner();
          }).done(function() {
            mod.destroy();
            return dfr.resolve();
          });
        };
      })(this)
    });
    mod = new CUI.Modal({
      cancel: true,
      onCancel: (function(_this) {
        return function() {
          dfr.reject();
        };
      })(this),
      pane: {
        header_left: new LocaLabel({
          loca_key: "connector.configuration.title"
        }),
        content: [
          tbl, new LocaLabel({
            multiline: true,
            appearance: "secondary",
            padded: true,
            markdown: true,
            loca_key: "connector.configuration.hint.md"
          })
        ],
        footer_right: save_btn
      }
    });
    mod.show();
    dfr = new CUI.Deferred();
    return dfr.promise();
  };

  Connector.prototype.displaynameByInstance = function(instance) {
    return this.getRemoteEasydbByInstance(instance).getDisplayname();
  };

  Connector.prototype.getRemoteEasydbByInstance = function(instance) {
    return this.__easydb_by_instance[instance];
  };

  Connector.prototype.get_user_key = function(realm, key) {
    var idx, instance, loca_key;
    idx = key.indexOf('@');
    if (idx === -1 || realm !== 'CURRENT') {
      return null;
    }
    instance = key.substr(idx + 1, 36);
    loca_key = this.replaceInstance(key, instance);
    return this.__easydb_by_instance[instance].get_user_key_CURRENT(loca_key);
  };

  Connector.prototype.getCollectionTools = function(collection) {
    var tools;
    tools = [];
    if (!this.isAvailable()) {
      return tools;
    }
    tools.push(new ToolboxTool({
      group: collection.getToolGroup(),
      name: collection.getToolNamePrefix() + ".replace_easydb4_objects",
      sort: "J:1",
      disabled: collection.getCount() > 1000,
      run: (function(_this) {
        return function() {
          return _this.replaceEasydb4Objects(collection);
        };
      })(this)
    }));
    return tools;
  };

  Connector.idRegexp = /^([0-9]{2})([0-9]{2})([0-9]{7})@easydb4$/;

  Connector.prototype.replaceEasydb4Objects = function(collection) {
    var do_search, load_objects, objects, show_error;
    console.error("replace connector objects", collection);
    show_error = (function(_this) {
      return function() {
        CUI.problem({
          text: $$("connector.replace_easydb4_objects.problem.getting_info")
        });
      };
    })(this);
    objects = null;
    load_objects = (function(_this) {
      return function() {
        ez5.splash.show("connector.replace_easydb4_objects.searching");
        return collection.loadObjects().always(function() {
          return ez5.splash.hide();
        }).fail(show_error).done(function(_objects) {
          var _, easydb, easydb4_id, easydb_idx, ez4info, i, j, len, len1, match, not_searchable_ids, obj, object_id, ref1, ref2, searchable_count, searchable_ids, table_id;
          objects = _objects;
          searchable_ids = {};
          searchable_count = 0;
          not_searchable_ids = [];
          for (i = 0, len = objects.length; i < len; i++) {
            obj = objects[i];
            if (!obj._global_object_id.endsWith("@easydb4")) {
              continue;
            }
            ref1 = Connector.idRegexp.exec(obj._global_object_id), _ = ref1[0], easydb4_id = ref1[1], table_id = ref1[2], object_id = ref1[3];
            match = null;
            ref2 = _this.__easydbs;
            for (easydb_idx = j = 0, len1 = ref2.length; j < len1; easydb_idx = ++j) {
              easydb = ref2[easydb_idx];
              ez4info = easydb.getEasydb4Info();
              if (!ez4info) {
                continue;
              }
              if (ez4info.easydb_id === easydb4_id && ez4info.table_id === table_id) {
                match = ez4info;
                break;
              }
            }
            if (match === null) {
              not_searchable_ids.push(obj._global_object_id);
              continue;
            }
            if (!searchable_ids[easydb_idx]) {
              searchable_ids[easydb_idx] = [];
            }
            searchable_ids[easydb_idx].push(parseInt(object_id));
            searchable_count = searchable_count + 1;
          }
          console.debug("objects:", objects, searchable_ids, not_searchable_ids);
          if (CUI.util.isEmptyObject(searchable_ids) && not_searchable_ids.length === 0) {
            return CUI.alert({
              text: $$("collection.replace_easydb4_objects.alert.no_objects.md"),
              markdown: true
            });
          } else if (CUI.util.isEmptyObject(searchable_ids)) {
            return CUI.alert({
              text: $$("collection.replace_easydb4_objects.alert.no_matching_easydb4.md", {
                count_not_searchable: not_searchable_ids.length,
                not_searchable_ids: not_searchable_ids.slice(0, 10)
              }),
              markdown: true
            });
          } else if (not_searchable_ids.length > 0) {
            return CUI.confirm({
              text: $$("collection.replace_easydb4_objects.alert.partial_matching_easydb4.md", {
                count_not_searchable: not_searchable_ids.length,
                count_searchable: searchable_count,
                not_searchable_ids: not_searchable_ids.slice(0, 10)
              }),
              markdown: true
            }).done(function() {
              return do_search(searchable_ids);
            });
          } else {
            return CUI.confirm({
              text: $$("collection.replace_easydb4_objects.alert.all_matching_easydb4.md", {
                count_searchable: searchable_count
              }),
              markdown: true
            }).done(function() {
              return do_search(searchable_ids);
            });
          }
        });
      };
    })(this);
    do_search = (function(_this) {
      return function(searchable_ids) {
        var easydb, easydb4, easydb_idx, field_name, inst, object_id, object_ids, results;
        results = [];
        for (easydb_idx in searchable_ids) {
          object_ids = searchable_ids[easydb_idx];
          easydb = _this.__easydbs[easydb_idx];
          easydb4 = easydb.getEasydb4Info();
          console.debug(easydb, easydb4, object_ids);
          inst = easydb.getInstance();
          field_name = easydb4.objecttype + "@" + inst + "." + easydb4.table_ref_col;
          results.push(ez5.api.search({
            json_data: {
              type: "object",
              objecttypes: [easydb4.objecttype + "@" + inst],
              include_fields: [field_name],
              generate_rights: false,
              format: "short",
              search: [
                {
                  type: "in",
                  fields: [field_name],
                  "in": (function() {
                    var i, len, results1;
                    results1 = [];
                    for (i = 0, len = object_ids.length; i < len; i++) {
                      object_id = object_ids[i];
                      results1.push(easydb4.table_name + ":" + object_id);
                    }
                    return results1;
                  })()
                }
              ]
            }
          }).done(function(data) {
            var co, easydb4_id, gid, i, j, k, l, len, len1, len2, len3, m, map, obj, object_id, ref, ref1, ref2, ref3, ref4, ref5, ref6, sd, slide;
            map = {};
            ref1 = data.objects;
            for (i = 0, len = ref1.length; i < len; i++) {
              obj = ref1[i];
              easydb = _this.getRemoteEasydbByInstance(obj._instance);
              easydb4 = easydb.getEasydb4Info();
              ref = obj[obj._objecttype][easydb4.table_ref_col];
              object_id = parseInt(ref.split(":")[1]);
              easydb4_id = easydb4.easydb_id * Math.pow(10, 9) + easydb4.table_id * Math.pow(10, 7) + object_id;
              console.debug(ref, object_id, easydb4, easydb4_id);
              map[easydb4_id + "@easydb4"] = obj._global_object_id;
            }
            console.debug("received data from remote", data, map);
            sd = collection.getSaveData();
            sd.collection._version = sd.collection._version + 1;
            ref3 = ((ref2 = sd.collection.webfrontend_props.presentation) != null ? ref2.slides : void 0) || [];
            for (j = 0, len1 = ref3.length; j < len1; j++) {
              slide = ref3[j];
              ref4 = ["left", "center", "right"];
              for (l = 0, len2 = ref4.length; l < len2; l++) {
                k = ref4[l];
                gid = (ref5 = slide[k]) != null ? ref5.global_object_id : void 0;
                if (gid && map[gid]) {
                  slide[k].global_object_id = map[gid];
                }
              }
            }
            sd._objects = CUI.util.copyObject(objects, true);
            ref6 = sd._objects;
            for (m = 0, len3 = ref6.length; m < len3; m++) {
              co = ref6[m];
              if (map[co._global_object_id]) {
                co._global_object_id = map[co._global_object_id];
              }
            }
            ez5.api.collection({
              type: "POST",
              api: "/" + collection.getId(),
              json_data: sd
            }).done(function() {
              CUI.alert({
                text: $$("collection.replace_easydb4_objects.alert.success.md"),
                markdown: true
              });
              return collection.refresh();
            });
          }));
        }
        return results;
      };
    })(this);
    collection.loadFromDb().fail(show_error).done(load_objects);
  };

  Connector.prototype.startDownload = function(_opts) {
    var dfr, eas_config, eas_info, easydb, fields, go_on, go_on2, info, instance, lbl, manager, opts, ref1, show_warning;
    opts = CUI.Element.readOpts(_opts, "Connector.startDownload", {
      manager: {
        mandatory: true,
        check: DownloadManager
      }
    });
    dfr = new CUI.Deferred();
    manager = opts.manager;
    eas_info = manager.getEASColumnsInfo();
    fields = [];
    show_warning = false;
    ref1 = eas_info.counts.by_instance;
    for (instance in ref1) {
      info = ref1[instance];
      if (instance === 'local') {
        eas_config = ez5.session.getEASConfig();
        lbl = ez5.session.getEasydbName();
        easydb = null;
      } else {
        easydb = this.getRemoteEasydbByInstance(instance);
        lbl = easydb.getDisplayname();
        eas_config = easydb.getSession().getEASConfig();
        if (!easydb.getSession().hasSystemRight("root", "frontend_features[download]")) {
          console.info("Connector: Download not allowed for:", easydb.getDisplayname());
          show_warning = true;
          continue;
        }
      }
      fields.push({
        type: CUI.Form,
        name: instance,
        fields: manager.getFormFieldsFromStats(info.by_class, eas_config, "connector.download.manager."),
        form: {
          label: lbl
        },
        _easydb: easydb
      });
    }
    fields.sort((function(_this) {
      return function(a, b) {
        return CUI.util.compareIndex(CUI.util.idxInArray(a._easydb, _this.__easydbs), CUI.util.idxInArray(b._easydb, _this.__easydbs));
      };
    })(this));
    console.debug(instance, "INFO:", info, eas_config);
    go_on2 = (function(_this) {
      return function() {
        var btn_download, events_by_instance, form, form_data, mod, mod_info, set_state, urls;
        form_data = {};
        form = new CUI.Form({
          fields: fields,
          data: form_data,
          onDataChanged: function() {
            return set_state();
          }
        });
        form.start();
        dfr = new CUI.Deferred();
        urls = null;
        events_by_instance = null;
        set_state = function() {
          var asset, bytes, cls, data, filename, i, j, k, len, len1, obj, parts, prefix, ref2, ref3, url, v, version, versionName, versionNames, versions, vinfo;
          bytes = 0;
          urls = [];
          events_by_instance = {
            local: []
          };
          for (instance in form_data) {
            data = form_data[instance];
            for (cls in data) {
              versionNames = data[cls];
              if (versionNames === false) {
                continue;
              }
              versions = [];
              for (i = 0, len = versionNames.length; i < len; i++) {
                versionName = versionNames[i];
                vinfo = eas_info.counts.by_instance[instance].by_class[cls].versions[versionName];
                bytes += vinfo.acc_filesize;
                versions = versions.concat(vinfo.versions);
              }
              for (j = 0, len1 = versions.length; j < len1; j++) {
                version = versions[j];
                obj = version.__object_data;
                asset = version.__asset.getValue();
                if (!events_by_instance[instance]) {
                  events_by_instance[instance] = [];
                }
                if ((ref2 = (easydb = _this.getRemoteEasydbByInstance(instance))) != null ? ref2.isFylr() : void 0) {
                  url = easydb.addTokenToUrl(version.url) + "&disposition=attachment";
                } else {
                  url = version.download_url;
                }
                if (!(easydb != null ? easydb.isFylr() : void 0)) {
                  filename = ez5.basename(url);
                  if (instance !== 'local') {
                    prefix = _this.getRemoteEasydbByInstance(instance).getDisplayname() + '-';
                  } else {
                    prefix = ez5.session.getEasydbName() + '-';
                  }
                  if (filename.indexOf(".") === -1) {
                    filename = prefix + ez5.loca.getBestDatabaseValue(obj._standard[1].text) + "-" + asset._id + "." + asset.extension;
                    filename = filename.replace(/[|\/\\<>*?":!]/g, "_");
                    url = url + '/' + encodeURIComponent(filename);
                  } else {
                    parts = url.split("/");
                    filename = parts[parts.length - 1];
                    parts[parts.length - 1] = prefix + ez5.bareBasename(filename) + "-" + asset._id + "." + ez5.extension(filename);
                    url = parts.join("/");
                  }
                }
                if (url.startsWith("/")) {
                  urls.push(ez5.getAbsoluteURL(url));
                } else {
                  urls.push(url);
                }
                info = Connector.getSessionInfoForEvent();
                ref3 = {
                  original_filename: asset.original_filename,
                  filename: filename,
                  filesize: asset.filesize,
                  "class": asset["class"],
                  extension: asset.extension,
                  version: version.version,
                  system_object_id: obj._system_object_id
                };
                for (k in ref3) {
                  v = ref3[k];
                  info[k] = v;
                }
                events_by_instance[instance].push({
                  object_id: parseInt((asset._id + "").replace('@' + instance, '')),
                  schema: "BASE",
                  basetype: "asset",
                  type: "ASSET_CONNECTOR_DOWNLOAD",
                  pollable: false,
                  info: info
                });
                if (instance !== 'local') {
                  info = CUI.util.copyObject(info, true);
                  info.system_object_id = obj._system_object_id + "@" + instance;
                  events_by_instance["local"].push({
                    schema: "BASE",
                    basetype: "asset",
                    type: "ASSET_CONNECTOR_REMOTE_DOWNLOAD",
                    pollable: false,
                    info: info
                  });
                }
              }
            }
          }
          if (urls.length > 0) {
            console.debug("save events?", events_by_instance);
            mod_info.setText($$("connector.download.info", {
              size: ez5.format_filesize(bytes),
              count: urls.length
            }));
            return btn_download.enable();
          } else {
            mod_info.setText("");
            return btn_download.disable();
          }
        };
        mod_info = new CUI.Label({
          text: ""
        });
        btn_download = new LocaButton({
          loca_key: "connector.download.button.download",
          left: true,
          disabled: true,
          onClick: function(ev, btn) {
            var event, events, i, len, promises;
            btn.disable();
            btn.startSpinner();
            promises = [];
            for (instance in events_by_instance) {
              events = events_by_instance[instance];
              if (instance !== "local") {
                easydb = _this.getRemoteEasydbByInstance(instance);
              } else {
                easydb = null;
              }
              for (i = 0, len = events.length; i < len; i++) {
                event = events[i];
                promises.push(EventPoller.saveEvent(event, easydb));
              }
            }
            CUI.when(promises).done(function() {
              var files, ref2, url;
              if (urls.length === 1) {
                return ez5.download_file({
                  href: urls[0]
                });
              } else {
                if (ez5.version("6")) {
                  files = (function() {
                    var j, len1, results;
                    results = [];
                    for (j = 0, len1 = urls.length; j < len1; j++) {
                      url = urls[j];
                      results.push({
                        href: url
                      });
                    }
                    return results;
                  })();
                  return ez5.download_files(files);
                }
                if (!((ref2 = _this.__base_config_fylr.url) != null ? ref2.endsWith("/zip") : void 0)) {
                  CUI.problem({
                    text: $$("connector.download.fylr_url_not_properly_configured")
                  });
                  return;
                }
                files = (function() {
                  var j, len1, results;
                  results = [];
                  for (j = 0, len1 = urls.length; j < len1; j++) {
                    url = urls[j];
                    results.push({
                      href: url
                    });
                  }
                  return results;
                })();
                return ez5.download_multiple_files(files, _this.__base_config_fylr.url, $$("connector.download.zip_download_name", {
                  count: files.length
                }));
              }
            }).fail(function() {
              btn.stopSpinner();
              return btn.enable();
            });
            return mod.destroy();
          }
        });
        mod = new CUI.ConfirmationDialog({
          icon: $$("download.manager.modal.icon"),
          title: manager.getTitle(eas_info.total),
          "class": "ez5-download-manager-confirmation-dialog ez5-event-poller",
          footer_left: mod_info,
          content: form,
          buttons: [btn_download],
          cancel: true,
          onCancel: function() {
            dfr.reject("user_rejected");
          }
        });
        mod.show();
      };
    })(this);
    go_on = (function(_this) {
      return function() {
        var idx, next_field;
        idx = 0;
        next_field = function() {
          var field;
          if (idx === fields.length) {
            go_on2();
            return;
          }
          field = fields[idx];
          return manager.showUserAdminMessages(field._easydb).done(function() {
            idx = idx + 1;
            return next_field();
          }).fail(dfr.reject);
        };
        return next_field();
      };
    })(this);
    if (show_warning) {
      CUI.problem({
        text: $$("connector.download.remote_not_allowed")
      }).done((function(_this) {
        return function() {
          if (fields.length === 0) {
            return dfr.reject();
          } else {
            return go_on();
          }
        };
      })(this));
    } else {
      go_on();
    }
    return dfr.promise();
  };

  Connector.prototype.get_user_key_localized = function(realm, key, _default) {
    var idx, instance, v;
    idx = key.indexOf('@');
    if (idx === -1 || realm !== 'CURRENT') {
      return null;
    }
    v = ez5.loca.getBestFrontendValue(this.get_user_key(realm, key));
    if (CUI.util.isEmpty(v)) {
      instance = key.substr(idx + 1, 36);
      return this.replaceInstance(_default, instance);
    } else {
      return v;
    }
  };

  Connector.prototype.replaceInstance = function(str, instance) {
    return str != null ? str.replace(new RegExp(CUI.util.escapeRegExp('@' + instance), 'g'), '') : void 0;
  };

  Connector.prototype.load = function() {
    var deferred;
    this.__config = {
      easydbs: []
    };
    this.__easydbs = [];
    if (!this.hasRights()) {
      return CUI.resolvedPromise();
    }
    deferred = new CUI.Deferred();
    this.init().done((function(_this) {
      return function() {
        var easydb, fn, i, len, promises, ref1;
        promises = [];
        ref1 = _this.__easydbs;
        fn = function(easydb) {
          var dfr;
          dfr = new CUI.Deferred();
          promises.push(dfr.promise());
          easydb.load().fail(dfr.reject).done(function() {
            _this.__easydb_by_instance[easydb.getInstance()] = easydb;
            return easydb.loadSchema().fail(dfr.reject).done(function() {
              var j, l, len1, len2, len3, m, mask, ref2, ref3, ref4, table;
              ref2 = easydb.mask.CURRENT.masks;
              for (j = 0, len1 = ref2.length; j < len1; j++) {
                mask = ref2[j];
                if (!ez5.mask.CURRENT._masks_by_table_id[mask.table_id]) {
                  ez5.mask.CURRENT._masks_by_table_id[mask.table_id] = [];
                }
                ez5.mask.CURRENT._masks_by_table_id[mask.table_id].push(mask);
                ez5.mask.CURRENT.masks.push(mask);
                ez5.mask.CURRENT._mask_by_id[mask.mask_id] = mask;
                ez5.mask.CURRENT._mask_by_name[mask.name] = mask;
              }
              ref3 = easydb.schema.CURRENT.tables;
              for (l = 0, len2 = ref3.length; l < len2; l++) {
                table = ref3[l];
                ez5.schema.CURRENT.tables.push(table);
                ez5.schema.CURRENT._table_by_id[table.table_id] = table;
                ez5.schema.CURRENT._table_by_name[table.name] = table;
                if (!table.owned_by) {
                  ez5.schema.CURRENT._objecttypes.push(table);
                  ez5.schema.CURRENT._objecttype_by_name[table.name] = table;
                }
              }
              ref4 = easydb.mask.CURRENT.masks;
              for (m = 0, len3 = ref4.length; m < len3; m++) {
                mask = ref4[m];
                ez5.mask.CURRENT._mask_instance_by_name[mask.name] = new Mask('CURRENT', null, mask);
              }
              dfr.resolve();
            });
          });
        };
        for (i = 0, len = ref1.length; i < len; i++) {
          easydb = ref1[i];
          fn(easydb);
        }
        return CUI.whenAll(promises).done(function() {
          CUI.util.removeFromArray(null, _this.__easydbs, function(easydb) {
            if (easydb.isReachable()) {
              return false;
            }
            _this.addUnrecheableEasydb(easydb);
            return true;
          });
          return deferred.resolve();
        });
      };
    })(this)).fail(deferred.resolve);
    return deferred.promise();
  };

  Connector.prototype.checkRemoval = function(v, instance) {
    if (!instance) {
      return v.indexOf('@') > -1;
    } else {
      return v.indexOf('@' + instance) === -1;
    }
  };

  Connector.prototype.wrapServerRequestApi = function() {
    console.info("Connector: Wrapping Server Request API.");
    this.wrapSearchApi();
    this.wrapEASApi();
    return this.wrapSuggestApi();
  };

  Connector.prototype.wrapSuggestApi = function() {
    return ez5.api.suggest = (function(_this) {
      return function(opts) {
        var i, json_data, k, len, promise, ref1;
        if (opts.data.BODY && opts.data.BODY.indexOf('@') > -1) {
          json_data = JSON.parse(opts.data.BODY);
          ref1 = ['linked_objecttypes', 'objecttypes', 'fields'];
          for (i = 0, len = ref1.length; i < len; i++) {
            k = ref1[i];
            if (!json_data[k]) {
              continue;
            }
            CUI.util.removeFromArray(null, json_data[k], function(v) {
              return v.indexOf('@') > -1;
            });
          }
          if (json_data.objecttypes.length === 0) {
            promise = CUI.resolvedPromise({
              suggestions: {
                tokens: [],
                fields: [],
                linked_objects: []
              }
            });
            promise.abort = function() {};
            return promise;
          }
          opts.data.BODY = JSON.stringify(json_data);
        }
        return _this.api.suggest(opts);
      };
    })(this);
  };

  Connector.prototype.cleanSearch = function(search, instance, level) {
    var clean, i, idx, item, item_idx, j, l, len, len1, len2, len3, m, ref1, ref2, ref3, ref4, ref5, regexp, remove, repl_regexp, use_instance, use_int, v;
    if (level == null) {
      level = 0;
    }
    for (item_idx = i = 0, len = search.length; i < len; item_idx = ++i) {
      item = search[item_idx];
      if ((ref1 = item.type) === 'complex' || ref1 === 'nested') {
        if (item.type === "nested") {
          regexp = new RegExp(CUI.util.escapeRegExp("@" + instance), "g");
          item.path = item.path.replace(regexp, "");
        }
        this.cleanSearch(item.search, instance, level + 1);
        if (((ref2 = item.search) != null ? ref2.length : void 0) === 0 && item.__filter === "SearchInput" && search.length > 1) {
          item.search.push({
            type: "in",
            bool: "must",
            fields: ["_system_object_id"],
            "in": [-1]
          });
        }
        continue;
      }
      if (!item.fields) {
        continue;
      }
      if (item.fields && item["in"]) {
        item.__instance = instance;
        remove = false;
        clean = false;
        use_instance = instance;
        use_int = false;
        switch (item.fields[0]) {
          case '_global_object_id':
            remove = true;
            clean = false;
            if (!instance) {
              use_instance = ez5.session.getInstanceGlobalName();
            }
            break;
          case '_objecttype':
          case '_mask':
            remove = true;
            clean = true;
            break;
          default:
            if (item.fields[0].endsWith("_pool.pool._id") || item.fields[0].endsWith("_pool._path.pool._id")) {
              remove = true;
              clean = true;
              use_int = true;
            }
        }
        if (remove) {
          CUI.util.removeFromArray(null, item["in"], (function(_this) {
            return function(v) {
              return _this.checkRemoval(v + "", use_instance);
            };
          })(this));
          if (clean && use_instance) {
            ref3 = item["in"];
            for (idx = j = 0, len1 = ref3.length; j < len1; idx = ++j) {
              v = ref3[idx];
              item["in"][idx] = v.replace('@' + instance, '');
              if (use_int) {
                item["in"][idx] = parseInt(item["in"][idx]);
              }
            }
          }
          if (item["in"].length === 0) {
            if (item.bool === "must_not" || item.__filter === "Facet") {
              if (use_int) {
                item["in"].push(-1);
              } else {
                item["in"].push("__non_existing_object");
              }
            } else {
              item.fields = [];
            }
          }
        }
        CUI.util.removeFromArray(null, item.fields, (function(_this) {
          return function(v) {
            if (v.startsWith('_') && v !== "_collections._id" && v !== "_system_object_id") {
              return false;
            }
            return _this.checkRemoval(v, instance);
          };
        })(this));
        if (item.fields.length === 0 && item.__filter === "Facet") {
          item.fields = ["_system_object_id"];
          item["in"] = [-1];
        }
        if (instance) {
          ref4 = item.fields;
          for (idx = l = 0, len2 = ref4.length; l < len2; idx = ++l) {
            v = ref4[idx];
            if (v.startsWith('_') && !v.startsWith("_path.")) {
              continue;
            }
            repl_regexp = new RegExp(CUI.util.escapeRegExp("@" + instance), "g");
            item.fields[idx] = v.replace(repl_regexp, '');
          }
        }
      } else {
        CUI.util.removeFromArray(null, item.fields, (function(_this) {
          return function(v) {
            if (v.startsWith('_')) {
              return false;
            }
            return _this.checkRemoval(v, instance);
          };
        })(this));
        if (instance) {
          ref5 = item.fields;
          for (idx = m = 0, len3 = ref5.length; m < len3; idx = ++m) {
            v = ref5[idx];
            if (v.startsWith('_') && !v.startsWith("_path.")) {
              continue;
            }
            repl_regexp = new RegExp(CUI.util.escapeRegExp("@" + instance), "g");
            item.fields[idx] = v.replace(repl_regexp, '');
          }
        }
      }
    }
    CUI.util.removeFromArray(null, search, function(item) {
      if (item.fields && item.fields.length === 0) {
        return true;
      } else if (item.type === "complex" && item.search.length === 0) {
        return true;
      } else {
        return false;
      }
    });
  };

  Connector.prototype.splitRequest = function(opts) {
    var _ot, agg, debugObject, def, easydb, ex_field, filterParentInstance, hasTags, i, idx, inst, instance, j, k, l, len, len1, len2, len3, len4, len5, len6, len7, len8, m, n, o, ot, otm, pool_ok, q, r, ref1, ref10, ref11, ref12, ref13, ref14, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, repl_regexp, req, reqs, s, sort, sortObject, t, v;
    reqs = [];
    for (idx = i = 0, ref1 = this.getActiveEasydbs().length; i <= ref1; idx = i += 1) {
      debugObject = opts.debug;
      delete opts.debug;
      if ((ref2 = opts.data) != null ? ref2.instances : void 0) {
        inst = idx > 0 ? this.__easydbs[idx - 1].getInstance() : "local";
        if (indexOf.call(opts.data.instances, inst) < 0) {
          reqs[idx] = null;
          continue;
        }
      }
      req = reqs[idx] = CUI.util.copyObject(opts, true);
      req.debug = debugObject;
      if (((ref3 = req.json_data) != null ? ref3.objecttypes : void 0) && req.json_data.objecttypes.length === 0) {
        delete req.json_data.objecttypes;
      }
      if (opts.error) {
        req.error = (function(_this) {
          return function() {};
        })(this);
      }
      if (opts.success) {
        req.success = (function(_this) {
          return function() {};
        })(this);
      }
      if (idx > 0) {
        easydb = this.__easydbs[idx - 1];
        instance = easydb.getInstance();
        repl_regexp = new RegExp(CUI.util.escapeRegExp("@" + instance), "g");
        req.remoteEasydb = easydb;
      } else {
        repl_regexp = null;
        instance = null;
      }
      req.__instance = instance;
      if (instance && !(typeof easydb.isFylr === "function" ? easydb.isFylr() : void 0)) {
        if (req.json_data.format === "long_inheritance") {
          req.json_data.format = "long";
        }
      }
      if (req.json_data.sort) {
        sort = [];
        ref4 = req.json_data.sort;
        for (j = 0, len = ref4.length; j < len; j++) {
          sortObject = ref4[j];
          if (sortObject.field.startsWith("_")) {
            sort.push(sortObject);
            continue;
          }
          if (!this.checkRemoval(sortObject.field, instance)) {
            if (instance) {
              sortObject.field = sortObject.field.replace(repl_regexp, '');
            }
            sort.push(sortObject);
          }
        }
        if (sort.length > 0) {
          req.json_data.sort = sort;
        } else {
          delete req.json_data.sort;
        }
      }
      if (req.json_data.fields) {
        if (instance) {
          ref5 = req.json_data.fields;
          for (l = 0, len1 = ref5.length; l < len1; l++) {
            v = ref5[l];
            if (v.field === "_objecttype" || v.field === "_pool") {
              v.key = v.key + "@" + instance;
            }
          }
        }
        CUI.util.removeFromArray(null, req.json_data.fields, (function(_this) {
          return function(v) {
            if (v.field.startsWith("_")) {
              return false;
            }
            return _this.checkRemoval(v.field, instance);
          };
        })(this));
        if (instance) {
          ref6 = req.json_data.fields;
          for (idx = m = 0, len2 = ref6.length; m < len2; idx = ++m) {
            def = ref6[idx];
            req.json_data.fields[idx].field = def.field.replace(repl_regexp, '');
          }
        }
      }
      if (req.json_data.objecttypes) {
        CUI.util.removeFromArray(null, req.json_data.objecttypes, (function(_this) {
          return function(v) {
            return _this.checkRemoval(v, instance);
          };
        })(this));
        if (instance) {
          ref7 = req.json_data.objecttypes;
          for (idx = n = 0, len3 = ref7.length; n < len3; idx = ++n) {
            ot = ref7[idx];
            req.json_data.objecttypes[idx] = ot.replace('@' + instance, '');
          }
        }
      }
      ref8 = ["exclude_fields", "include_fields"];
      for (o = 0, len4 = ref8.length; o < len4; o++) {
        k = ref8[o];
        if (!req.json_data[k]) {
          continue;
        }
        ref9 = req.json_data[k].splice(0);
        for (q = 0, len5 = ref9.length; q < len5; q++) {
          ex_field = ref9[q];
          if (ex_field.indexOf(".") === -1) {
            req.json_data[k].push(ex_field);
          } else if (instance === null) {
            if (ex_field.indexOf("@") === -1) {
              req.json_data[k].push(ex_field);
            }
          } else {
            if (ex_field.indexOf("@" + instance) > -1) {
              req.json_data[k].push(ex_field.replace(repl_regexp, ""));
            }
          }
        }
      }
      if (req.json_data.aggregations) {
        ref10 = req.json_data.aggregations;
        for (agg in ref10) {
          def = ref10[agg];
          if (agg.startsWith("_pool")) {
            pool_ok = false;
            ref11 = req.json_data.objecttypes || [];
            for (r = 0, len6 = ref11.length; r < len6; r++) {
              _ot = ref11[r];
              if (instance) {
                ot = _ot + '@' + instance;
              } else {
                ot = _ot;
              }
              if (ez5.schema.CURRENT._objecttype_by_name[ot].pool_link) {
                pool_ok = true;
                if (CUI.util.isString(def.filter_parent)) {
                  filterParentInstance = def.filter_parent.substring(def.filter_parent.indexOf("@") + 1);
                  if (filterParentInstance !== instance) {
                    pool_ok = false;
                  }
                }
                break;
              }
            }
            if (!pool_ok) {
              delete req.json_data.aggregations[agg];
              continue;
            }
          }
          if (agg === '_tags') {
            if (idx === 0 && ez5.version("6")) {
              hasTags = false;
              ref12 = ez5.schema.CURRENT._objecttypes;
              for (s = 0, len7 = ref12.length; s < len7; s++) {
                ot = ref12[s];
                if (ot._instance) {
                  continue;
                }
                if (ot.has_tags) {
                  hasTags = true;
                  break;
                }
              }
              if (!hasTags) {
                delete req.json_data.aggregations[agg];
              }
              continue;
            }
            if (instance && !(typeof easydb.hasTags === "function" ? easydb.hasTags() : void 0)) {
              delete req.json_data.aggregations[agg];
            }
            continue;
          }
          if (instance && agg === "_eas") {
            req.json_data.aggregations[agg].type = (typeof easydb.isFylr === "function" ? easydb.isFylr() : void 0) ? "term" : "asset";
            req.json_data.aggregations[agg].field = req.json_data.aggregations[agg].field.replace("_linked._asset.", "");
            if (typeof easydb.isFylr === "function" ? easydb.isFylr() : void 0) {
              req.json_data.aggregations[agg].field = "_linked._asset." + req.json_data.aggregations[agg].field;
            }
          }
          if (agg === '_asset' || agg === '_asset_class_version_status') {
            if (instance && ez5.version("6") && !(typeof easydb.isFylr === "function" ? easydb.isFylr() : void 0)) {
              req.json_data.aggregations[agg].type = "asset";
              req.json_data.aggregations[agg].field = req.json_data.aggregations[agg].field.replace("_linked._asset.", "");
              continue;
            }
            if (instance && !ez5.version("6") && (typeof easydb.isFylr === "function" ? easydb.isFylr() : void 0)) {
              req.json_data.aggregations[agg].type = "term";
              req.json_data.aggregations[agg].field = "_linked._asset." + req.json_data.aggregations[agg].field;
            }
            if ((!instance && ez5.version("6")) || (instance && (typeof easydb.isFylr === "function" ? easydb.isFylr() : void 0))) {
              otm = new ObjecttypeManager();
              otm.addObjecttypes((function(_this) {
                return function(table) {
                  var ref13;
                  if (!instance) {
                    return ref13 = table.name(), indexOf.call(req.json_data.objecttypes, ref13) >= 0;
                  } else {
                    return req.json_data.objecttypes.some(function(ot) {
                      return table.name() === ot + "@" + instance;
                    });
                  }
                };
              })(this));
              if (!otm.getEASFields().length > 0) {
                delete req.json_data.aggregations[agg];
              }
            }
            continue;
          }
          if (agg.startsWith('_eas')) {
            continue;
          }
          if (instance && agg === "_system_tags" && ez5.version("6") && !(typeof easydb.isFylr === "function" ? easydb.isFylr() : void 0)) {
            delete req.json_data.aggregations[agg];
            continue;
          }
          if (def.field === "_pool") {
            if (instance) {
              if (CUI.util.isString(def.filter_parent)) {
                if (def.filter_parent.indexOf('@') > -1) {
                  def.filter_parent = parseInt(def.filter_parent);
                }
              }
            }
          }
          ref13 = ["field", "objecttype"];
          for (t = 0, len8 = ref13.length; t < len8; t++) {
            k = ref13[t];
            if (!def[k]) {
              continue;
            }
            if (def[k].startsWith('_')) {
              continue;
            }
            if (!instance) {
              if (def[k].indexOf('@') > -1) {
                delete req.json_data.aggregations[agg];
              }
            } else {
              if (def[k].indexOf('@' + instance) === -1) {
                delete req.json_data.aggregations[agg];
              } else {
                def[k] = def[k].replace(repl_regexp, '');
              }
            }
          }
        }
      }
      if (((ref14 = req.json_data.search) != null ? ref14.length : void 0) > 0) {
        this.cleanSearch(req.json_data.search, instance);
        if (req.json_data.search.length === 0) {
          req.json_data.objecttypes = [];
        }
      }
    }
    return reqs;
  };

  Connector.LOCAL_INSTANCE = "local";

  Connector.prototype.wrapEASApi = function() {
    return ez5.api.eas = (function(_this) {
      return function(opts) {
        var _opts, dataPerInstance, dfr, i, id, idSplitted, ids, instance, instances, j, len, len1, promises, ref1, ref2, ref3, ref4, ref5, remoteEasydb, remoteOpts;
        if (!((ref1 = opts.data) != null ? ref1.ids : void 0) || !((ref2 = _this.__easydbs) != null ? ref2.length : void 0) || opts.skip_connector) {
          return _this.api.eas(opts);
        }
        dfr = new CUI.Deferred();
        if (opts.handle_error) {
          dfr.fail(function(responses) {
            var i, len, response;
            for (i = 0, len = responses.length; i < len; i++) {
              response = responses[i];
              if (response.state === "rejected") {
                opts.handle_error.call(opts.handle_error, response.args[0]);
                return;
              }
            }
            return opts.handle_error.call(opts.handle_error);
          });
        }
        dataPerInstance = {};
        ids = JSON.parse(opts.data.ids);
        for (i = 0, len = ids.length; i < len; i++) {
          id = ids[i];
          if (CUI.util.isString(id)) {
            idSplitted = id.split("@");
            instance = idSplitted[1];
            id = idSplitted[0];
          } else {
            instance = Connector.LOCAL_INSTANCE;
          }
          if (!dataPerInstance[instance]) {
            dataPerInstance[instance] = {
              ids: []
            };
          }
          dataPerInstance[instance].ids.push(parseInt(id));
        }
        promises = [];
        instances = [];
        if (dataPerInstance[Connector.LOCAL_INSTANCE]) {
          _opts = CUI.util.copyObject(opts);
          _opts.data.ids = JSON.stringify(dataPerInstance[Connector.LOCAL_INSTANCE].ids);
          promises.push(_this.api.eas(_opts));
          instances.push(Connector.LOCAL_INSTANCE);
        }
        ref3 = _this.__easydbs;
        for (j = 0, len1 = ref3.length; j < len1; j++) {
          remoteEasydb = ref3[j];
          remoteOpts = dataPerInstance[remoteEasydb.getInstance()];
          if (!remoteOpts) {
            continue;
          }
          _opts = CUI.util.copyObject(opts);
          _opts.data.ids = JSON.stringify(remoteOpts.ids);
          _opts.remoteEasydb = remoteEasydb;
          if (((ref4 = _opts.data) != null ? ref4.format : void 0) && _opts.data.format === "standard" && !(typeof remoteEasydb.isFylr === "function" ? remoteEasydb.isFylr() : void 0)) {
            _opts.data.format = "short";
          } else if (((ref5 = _opts.data) != null ? ref5.format : void 0) && _opts.data.format === "short" && (typeof remoteEasydb.isFylr === "function" ? remoteEasydb.isFylr() : void 0)) {
            _opts.data.format = "standard";
          }
          promises.push(_this.api.eas(_opts));
          instances.push(remoteEasydb.getInstance());
        }
        CUI.whenAll(promises).done(function() {
          var data, idObject, index, l, len2, object, response, responseData, responses;
          responses = arguments;
          data = {};
          for (index = l = 0, len2 = responses.length; l < len2; index = ++l) {
            response = responses[index];
            responseData = response.args[0];
            if (response.state === 'rejected') {
              continue;
            }
            instance = instances[index];
            if (instance === "local") {
              Object.assign(data, responseData);
              continue;
            }
            for (idObject in responseData) {
              object = responseData[idObject];
              id = idObject + "@" + instance;
              object._id = id;
              data[id] = object;
            }
          }
          return dfr.resolve(data);
        });
        return dfr.promise();
      };
    })(this);
  };

  Connector.prototype.wrapSearchApi = function() {
    var isFakeSearch;
    isFakeSearch = function(search) {
      var ref1, ref2;
      if ((search != null ? search.length : void 0) === 1) {
        return search[0]["type"] === "in" && ((ref1 = search[0]["fields"]) != null ? ref1[0] : void 0) === "_global_object_id" && ((ref2 = search[0]) != null ? ref2["in"][0] : void 0) === "-1";
      }
      return false;
    };
    ez5.api.search = (function(_this) {
      return function(opts) {
        var debugData, dfr, fn, i, idx, len, promises, ref1, req, reqs, requestSorts;
        if (!opts.json_data || !((ref1 = _this.__easydbs) != null ? ref1.length : void 0) || opts.skip_connector || isFakeSearch(opts.json_data.search)) {
          return _this.api.search(opts);
        }
        if (opts.json_data.type && opts.json_data.type !== "object") {
          return _this.api.search(opts);
        }
        dfr = new CUI.Deferred();
        if (opts.debug) {
          debugData = opts.debug;
        }
        if (opts.error) {
          dfr.fail(function(responses) {
            var i, len, response;
            console.error("failed:", responses);
            for (i = 0, len = responses.length; i < len; i++) {
              response = responses[i];
              if (response.state === "rejected") {
                opts.error.call(opts.error, response.args[0]);
                return;
              }
            }
            opts.error.call(opts.error);
          });
        }
        if (opts.success) {
          dfr.done(function() {
            return opts.success.apply(opts.success, arguments);
          });
        }
        reqs = _this.splitRequest(opts);
        promises = [];
        requestSorts = {};
        fn = function(req, idx) {
          var easydb, instance, promise, remoteEasyDb;
          if (idx === 0) {
            easydb = instance = "local";
          } else {
            remoteEasyDb = _this.__easydbs[idx - 1];
            easydb = remoteEasyDb.getDisplayname();
            instance = remoteEasyDb.getInstance();
          }
          requestSorts[instance] = req.json_data.sort;
          if (req.json_data.objecttypes && req.json_data.objecttypes.length === 0) {
            console.debug("Skip no objecttypes:", idx, easydb);
            promise = CUI.resolvedPromise("skipped");
          } else {
            promise = _this.api.search(req);
          }
          return promises.push(promise);
        };
        for (idx = i = 0, len = reqs.length; i < len; idx = ++i) {
          req = reqs[idx];
          if (!req) {
            continue;
          }
          fn(req, idx);
        }
        CUI.whenAll(promises).done(function() {
          var _term, aTerm, data, easydb, event, have_data, info, instance, j, k, k2, key, l, len1, len10, len11, len2, len3, len4, len5, len6, len7, len8, len9, linked_object, m, n, o, obj, ot, p, parts, q, r, ref10, ref11, ref12, ref13, ref14, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, response, responseData, responses, s, sd, t, term, term_ok, terms, u, value, values, w;
          responses = arguments;
          data = {
            count: 0,
            limit: 0,
            offset: 0,
            countByInstance: {},
            __instances: []
          };
          have_data = false;
          for (idx = j = 0, len1 = responses.length; j < len1; idx = ++j) {
            response = responses[idx];
            if (response.args[0] === "skipped") {
              continue;
            }
            if (response.state === 'rejected') {
              continue;
            }
            have_data = true;
            if (idx === 0) {
              data = response.args[0];
              data.__instances = ["local"];
              continue;
            }
            easydb = _this.__easydbs[idx - 1];
            instance = easydb.getInstance();
            responseData = response.args[0];
            if (instance !== "local") {
              event = {
                info: {
                  instance: instance,
                  version: {
                    schema: ez5.schema.CURRENT.version,
                    save_data: Search.storeDataVersion
                  },
                  request: reqs[idx].json_data,
                  response: {
                    count: responseData.count,
                    timings: {
                      request_time: responseData.request_time,
                      client: responseData.clientTook
                    }
                  }
                }
              };
              if (debugData != null ? debugData.search : void 0) {
                try {
                  sd = debugData.search.getStoreData();
                  if (sd != null ? (ref2 = sd.SearchInput) != null ? (ref3 = ref2.query) != null ? ref3.length : void 0 : void 0 : void 0) {
                    easydb = _this.getRemoteEasydbByInstance(instance);
                    if (easydb.version("5.94")) {
                      event.type = "CONNECTOR_SEARCH";
                      promises.push(EventPoller.saveEvent(event, easydb));
                    }
                    event.type = "CONNECTOR_REMOTE_SEARCH";
                    promises.push(EventPoller.saveEvent(event));
                    console.log("EVENT LOG");
                  }
                } catch (error) {}
              }
            }
            data.__instances.push(instance);
            if (responseData.objecttypes) {
              if (!data.objecttypes) {
                data.objecttypes = [];
              }
              ref4 = responseData.objecttypes;
              for (l = 0, len2 = ref4.length; l < len2; l++) {
                ot = ref4[l];
                data.objecttypes.push(ot + '@' + instance);
              }
            }
            ref5 = ["count", "limit", "offset"];
            for (m = 0, len3 = ref5.length; m < len3; m++) {
              k = ref5[m];
              if (responseData[k]) {
                data[k] = data[k] + responseData[k];
              }
            }
            if (!data.countByInstance) {
              data.countByInstance = {};
            }
            data.countByInstance[instance] = responseData["count"];
            if (responseData.objects) {
              if (!data.objects) {
                data.objects = [];
              }
              ref6 = responseData.objects;
              for (n = 0, len4 = ref6.length; n < len4; n++) {
                obj = ref6[n];
                data.objects.push(obj);
                obj._generated_rights = {};
                if (obj._fields) {
                  ref7 = obj._fields;
                  for (k in ref7) {
                    values = ref7[k];
                    if (k.indexOf('@') > -1) {
                      parts = k.split('@');
                      k2 = parts[0];
                      for (idx = o = 0, len5 = values.length; o < len5; idx = ++o) {
                        value = values[idx];
                        values[idx] = value + '@' + parts[1];
                      }
                      obj._fields[k2] = values;
                      delete obj._fields[k];
                    }
                  }
                }
                Connector.addInstanceToObject(obj, easydb);
              }
            }
            if (responseData.aggregations) {
              if (!data.aggregations) {
                data.aggregations = {};
              }
              ref8 = responseData.aggregations;
              for (key in ref8) {
                info = ref8[key];
                if (key.startsWith('_eas')) {
                  if (!data.aggregations[key]) {
                    data.aggregations[key] = {
                      terms: []
                    };
                  }
                  ref9 = responseData.aggregations[key].terms;
                  for (q = 0, len6 = ref9.length; q < len6; q++) {
                    term = ref9[q];
                    term_ok = false;
                    ref10 = data.aggregations[key].terms;
                    for (r = 0, len7 = ref10.length; r < len7; r++) {
                      _term = ref10[r];
                      if (_term.term === term.term) {
                        _term.count += term.count;
                        term_ok = true;
                        break;
                      }
                    }
                    if (!term_ok) {
                      data.aggregations[key].terms.push(CUI.util.copyObject(term, true));
                    }
                  }
                  responseData.aggregations[key].terms.sort(function(a, b) {
                    return CUI.util.compareIndex(b.count, a.count);
                  });
                  continue;
                }
                switch (key) {
                  case '_objecttype':
                  case '_mask':
                  case '_result_table_masks':
                    if (!data.aggregations[key]) {
                      data.aggregations[key] = {
                        terms: []
                      };
                    }
                    ref11 = responseData.aggregations[key].terms;
                    for (s = 0, len8 = ref11.length; s < len8; s++) {
                      term = ref11[s];
                      term.term = term.term + '@' + instance;
                      term._instance = instance;
                      data.aggregations[key].terms.push(term);
                    }
                    break;
                  case '_asset':
                    if (!data.aggregations[key]) {
                      data.aggregations[key] = {
                        terms: []
                      };
                    }
                    terms = data.aggregations[key].terms;
                    ref12 = responseData.aggregations[key].terms;
                    for (t = 0, len9 = ref12.length; t < len9; t++) {
                      term = ref12[t];
                      aTerm = terms.filter(function(_term) {
                        return _term.term === term.term;
                      })[0];
                      if (!aTerm) {
                        aTerm = {
                          term: term.term,
                          count: 0
                        };
                        terms.push(aTerm);
                      }
                      aTerm.count += term.count;
                    }
                    break;
                  default:
                    if (key.startsWith('_pool')) {
                      if (!data.aggregations[key]) {
                        data.aggregations[key] = {
                          count: 0,
                          linked_objects: []
                        };
                      } else {
                        data.aggregations[key].count = data.aggregations[key].count + responseData.aggregations[key].count;
                      }
                      ref13 = responseData.aggregations[key].linked_objects;
                      for (u = 0, len10 = ref13.length; u < len10; u++) {
                        linked_object = ref13[u];
                        linked_object._instance = instance;
                        linked_object._id = linked_object._id + '@' + instance;
                        ref14 = linked_object._path;
                        for (w = 0, len11 = ref14.length; w < len11; w++) {
                          p = ref14[w];
                          p._id = p._id + '@' + instance;
                        }
                        data.aggregations[key].linked_objects.push(linked_object);
                      }
                    } else {
                      data.aggregations[key] = info;
                    }
                }
              }
            }
          }
          if (!have_data) {
            console.warn("Connector received no data.", opts);
            dfr.reject(responses);
            return;
          }
          _this.__sort(data, requestSorts);
          return dfr.resolve(data);
        });
        return dfr.promise();
      };
    })(this);
  };

  Connector.prototype.__sort = function(data, requestSorts) {
    var compare, getSortDirection;
    getSortDirection = function(instance, level) {
      var sort, sorts;
      if (instance == null) {
        instance = "local";
      }
      sorts = requestSorts[instance];
      if (sorts.length === 1) {
        return sorts[0].order;
      }
      sort = sorts.filter(function(_sort) {
        return _sort._level === level;
      })[0];
      return (sort != null ? sort.order : void 0) || "ASC";
    };
    compare = function(objectOne, objectTwo, level) {
      var compareValue, sortDirection, valueOne, valueTwo;
      if (level == null) {
        level = 0;
      }
      valueOne = objectOne._sort[level];
      valueTwo = objectTwo._sort[level];
      if (!valueOne && !valueTwo) {
        return 0;
      }
      compareValue = CUI.util.compareIndex(valueOne, valueTwo);
      if (compareValue === 0) {
        return compare(objectOne, objectTwo, ++level);
      }
      sortDirection = getSortDirection(objectOne._instance, level);
      if (sortDirection === "DESC") {
        return -compareValue;
      }
      return compareValue;
    };
    return data.objects.sort((function(_this) {
      return function(objectOne, objectTwo) {
        var ref1, ref2;
        objectTwo._sort = (ref1 = objectTwo._sort) != null ? ref1.filter(function(val) {
          return val !== null;
        }) : void 0;
        objectOne._sort = (ref2 = objectOne._sort) != null ? ref2.filter(function(val) {
          return val !== null;
        }) : void 0;
        if (!objectOne._sort && !objectTwo._sort) {
          return 0;
        }
        if (!objectOne._sort) {
          return -1;
        }
        if (!objectTwo._sort) {
          return 1;
        }
        return compare(objectOne, objectTwo);
      };
    })(this));
  };

  Connector.wrap = 0;

  Connector.global_counter = 0;

  Connector.addInstanceToObject = function(obj, easydb, level) {
    var i, instance, j, k, l, len, len1, len2, nested, ref1, ref2, tag, v;
    if (level == null) {
      level = 0;
    }
    instance = easydb.getInstance();
    if (!obj) {
      return;
    }
    if (level === 0) {
      obj._instance = instance;
    }
    if (obj._objecttype) {
      if (obj[obj._objecttype]) {
        obj[obj._objecttype + '@' + instance] = obj[obj._objecttype];
        delete obj[obj._objecttype];
      }
      obj._objecttype = obj._objecttype + '@' + instance;
      obj._mask = obj._mask + '@' + instance;
    }
    if (obj._tags && CUI.util.isArray(obj._tags)) {
      ref1 = obj._tags;
      for (i = 0, len = ref1.length; i < len; i++) {
        tag = ref1[i];
        tag._id = tag._id + "@" + instance;
      }
    }
    if (obj["class"] && obj.extension) {
      if (obj.technical_metadata) {
        obj._id = obj._id + '@' + instance;
      }
      ref2 = ["url", "download_url"];
      for (j = 0, len1 = ref2.length; j < len1; j++) {
        k = ref2[j];
        if (!CUI.util.isString(obj[k])) {
          continue;
        }
        if (obj[k].startsWith("/")) {
          obj[k] = easydb.getServerUrl() + obj[k];
        }
      }
    }
    for (k in obj) {
      v = obj[k];
      if (CUI.isArray(v)) {
        if (k.startsWith("_nested:")) {
          delete obj[k];
          obj[k + "@" + instance] = v;
        }
        for (l = 0, len2 = v.length; l < len2; l++) {
          nested = v[l];
          Connector.addInstanceToObject(nested, easydb, level + 1);
        }
      } else if (CUI.isPlainObject(v)) {
        Connector.addInstanceToObject(v, easydb, level + 1);
      }
    }
  };

  Connector.getSessionInfoForEvent = function() {
    var info;
    info = {
      easydb: ez5.session.getEasydbName(),
      session_token: ez5.session.token,
      instance: ez5.session.getInstanceGlobalName()
    };
    if (ez5.session.user) {
      info.user_displayname = ez5.session.user.getDisplayText();
      info.user_id = ez5.session.user.getId();
      info.user_displayname = ez5.session.user.getDisplayText();
      info.user_email = ez5.session.user.getPrimaryEmail();
    }
    return info;
  };

  return Connector;

})(CUI.Element);

ez5.connector = new Connector();

ez5.connector.api.search = ez5.api.search;

ez5.connector.api.suggest = ez5.api.suggest;

ez5.connector.api.eas = ez5.api.eas;

ez5.load_defaults((function(_this) {
  return function() {
    return ez5.connector.load();
  };
})(this));
// Generated by CoffeeScript 1.12.7
var RemoteEasydb,
  extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  hasProp = {}.hasOwnProperty;

RemoteEasydb = (function(superClass) {
  extend(RemoteEasydb, superClass);

  function RemoteEasydb() {
    return RemoteEasydb.__super__.constructor.apply(this, arguments);
  }

  RemoteEasydb.prototype.initOpts = function() {
    RemoteEasydb.__super__.initOpts.call(this);
    return this.addOpts({
      easydb: {
        check: {
          idx: {
            mandatory: true,
            check: "Integer"
          },
          active: {
            mandatory: true,
            check: Boolean
          },
          url: {
            mandatory: true,
            check: String
          },
          name: {
            check: String
          },
          version: {
            check: String,
            "default": ""
          },
          token: {
            check: String
          },
          error: {
            check: "PlainObject",
            "default": {}
          }
        }
      }
    });
  };

  RemoteEasydb.prototype.readOpts = function() {
    RemoteEasydb.__super__.readOpts.call(this);
    this.__schema = {};
    this.__session = null;
    this.user_keys = {};
    this.__lastError = null;
  };

  RemoteEasydb.prototype.isFylr = function() {
    if (CUI.util.isEmpty(this._easydb.version)) {
      return false;
    }
    return parseFloat(this._easydb.version.replace("v", "")) >= 6.0;
  };

  RemoteEasydb.prototype.hasTags = function() {
    return this.__tags && !CUI.util.isEmpty(this.__tags);
  };

  RemoteEasydb.prototype.getEasydb4Info = function() {
    var baseConfig, easydb4;
    baseConfig = ez5.session.getBaseConfig("plugin", "easydb-connector-plugin");
    baseConfig = baseConfig.system || baseConfig;
    easydb4 = baseConfig.connector_easydb4 || null;
    if (easydb4) {
      console.info("Remote easydb '" + this.getDisplayname() + "' has easydb 4 configuration: ", easydb4);
    } else {
      console.warn("Remote easydb '" + this.getDisplayname() + "' contains no easydb 4 configuration.");
    }
    return easydb4;
  };

  RemoteEasydb.prototype.getServerUrl = function() {
    return this._easydb.url;
  };

  RemoteEasydb.prototype.getServerToken = function() {
    return this.__session.token;
  };

  RemoteEasydb.prototype.getSession = function() {
    return this.__session;
  };

  RemoteEasydb.prototype.getInstance = function() {
    return this.__instance;
  };

  RemoteEasydb.prototype.addTokenToUrl = function(url) {
    if (!url) {
      return url;
    }
    if (url.indexOf("?") > -1) {
      return url + "&access_token=" + this.__session.token;
    } else {
      return url + "?access_token=" + this.__session.token;
    }
  };

  RemoteEasydb.prototype.getExportVersionGroups = function() {
    return Asset.getExportVersionGroups(this.__session.getEASConfig());
  };

  RemoteEasydb.prototype.getDisplayname = function() {
    return this._easydb.name;
  };

  RemoteEasydb.prototype.isActive = function() {
    return this._easydb.active;
  };

  RemoteEasydb.prototype.isReachable = function() {
    return !!this.__instance;
  };

  RemoteEasydb.prototype.getLastError = function() {
    return this.__lastError;
  };

  RemoteEasydb.prototype.load = function() {
    var dfr, loc;
    dfr = new CUI.Deferred();
    dfr.fail((function(_this) {
      return function(loca_key, loca_key_attrs) {
        var err;
        if (loca_key_attrs == null) {
          loca_key_attrs = {};
        }
        err = loca_key != null ? loca_key.responseJSON : void 0;
        if (err) {
          loca_key_attrs = err.parameters;
          loca_key = err.code;
        }
        _this.__instance = null;
        if (CUI.util.isString(loca_key)) {
          _this.__lastError = $$(loca_key, loca_key_attrs);
        } else {
          _this.__lastError = $$("remote.easydb.connect.unknown_error");
        }
      };
    })(this));
    dfr.done((function(_this) {
      return function() {
        return _this.__lastError = null;
      };
    })(this));
    if (!CUI.util.isEmptyObject(this._easydb.error)) {
      if (this._easydb.error.code) {
        return dfr.reject(this._easydb.error.code, this._easydb.error.parameters);
      } else {
        this.__lastError = this._easydb.error.msg;
        return CUI.rejectedPromise();
      }
    }
    if (this._easydb.url.startsWith("https://") || this._easydb.url.startsWith("http://")) {
      loc = CUI.parseLocation(this._easydb.url);
    } else {
      loc = null;
    }
    if (!loc) {
      console.warn("Remote easydb has an invalid url: ", this._easydb.url);
      dfr.reject("remote.easydb.connect.invalid_url", {
        url: this._easydb.url
      });
      return dfr.promise();
    }
    this.__session = new Session({
      remoteEasydb: this
    });
    this.__session.get(this._easydb.token).fail(dfr.reject).done((function(_this) {
      return function() {
        var l10nDeferred, l10nPromise, login_event, settingsPromise, tagsPromise;
        if (_this.__session.pendingTasks.length > 0) {
          console.warn("Remote easydb has pending tasks. This is currently not supported.", _this._easydb);
          dfr.reject("remote.easydb.connect.pending_tasks");
          return;
        }
        if (!_this.__session.hasSystemRight("root", "plugin.easydb-connector-plugin.allow_use_as_server")) {
          dfr.reject("remote.easydb.connect.no_right_to_use");
          return;
        }
        login_event = {
          type: "CONNECTOR_LOGIN",
          pollable: false,
          info: Connector.getSessionInfoForEvent()
        };
        _this.__instance = _this.__session.getInstance().name;
        settingsPromise = ez5.api.settings({
          timeout: 15000,
          remoteEasydb: _this,
          handle_error: function() {
            return true;
          }
        }).fail(function(xhr, status) {
          return _this.tellProblem(status);
        }).done(function(settings) {
          _this.setEasydbVersion(settings.version);
        });
        tagsPromise = ez5.api.tags({
          remoteEasydb: _this,
          withCredentials: true
        }).done(function(data) {
          var _tag, i, j, len, len1, ref, ref1, tagGroup;
          if (CUI.util.isEmpty(data)) {
            return;
          }
          for (i = 0, len = data.length; i < len; i++) {
            tagGroup = data[i];
            ref = tagGroup._tags;
            for (j = 0, len1 = ref.length; j < len1; j++) {
              _tag = ref[j];
              if (!((ref1 = _tag.tag) != null ? ref1._id : void 0)) {
                continue;
              }
              _tag.tag._id += "@" + _this.__instance;
            }
          }
          _this.__tags = data;
          ez5.tagForm.addTagGroupsFromData(data);
        });
        l10nDeferred = new CUI.Deferred();
        ez5.api.l10n({
          remoteEasydb: _this,
          withCredentials: true,
          api: "/user/CURRENT"
        }).fail(l10nDeferred.reject).done(function(data) {
          ez5.loca.set_user_keys.call(_this, 'CURRENT', data);
          EventPoller.saveEvent(login_event, _this, true).fail(function() {
            if (typeof _this.isFylr === "function" ? _this.isFylr() : void 0) {
              l10nDeferred.reject();
              _this.__lastError = $$("remote.easydb.connect.remote_connector_not_available");
              return;
            }
            return _this.__session.deauthenticate().always(function() {
              l10nDeferred.reject();
              _this.__lastError = $$("remote.easydb.connect.remote_connector_not_available");
            });
          }).done(function() {
            return l10nDeferred.resolve();
          });
        });
        l10nPromise = l10nDeferred.promise();
        CUI.whenAllReject(l10nPromise, tagsPromise, settingsPromise).done(dfr.resolve).fail(dfr.reject);
      };
    })(this));
    return dfr.promise();
  };

  RemoteEasydb.prototype.logout = function() {
    var dfr, info, logout_event, ref;
    if (!((ref = this.__session) != null ? ref.isAuthenticated() : void 0)) {
      return CUI.resolvedPromise();
    }
    info = Connector.getSessionInfoForEvent();
    info.duration = ez5.format_seconds(this.__session.getDuration() / 1000);
    logout_event = {
      type: "CONNECTOR_LOGOUT",
      pollable: false,
      info: info
    };
    dfr = new CUI.Deferred();
    EventPoller.saveEvent(logout_event, this, true).always((function(_this) {
      return function() {
        if (typeof _this.isFylr === "function" ? _this.isFylr() : void 0) {
          dfr.resolve();
          return;
        }
        return _this.__session.deauthenticate().done(dfr.resolve).fail(dfr.reject);
      };
    })(this));
    return dfr.promise();
  };

  RemoteEasydb.prototype.loadSchema = function() {
    this.__schema_inst = new Schema({
      remoteEasydb: this
    });
    this.__schema = {};
    return this.__schema_inst.load(null, this.__schema, ["CURRENT"], ["mask", "schema"]).done((function(_this) {
      return function() {
        _this.mask = {
          CURRENT: _this.__schema.mask.CURRENT
        };
        _this.schema = {
          CURRENT: _this.__schema.schema.CURRENT
        };
        ez5.bind_schema_funcs(_this.schema);
        _this.setInstanceInMaskAndSchema();
        _this.schema.enrich_schema(_this.schema.CURRENT, 'CURRENT');
        _this.schema.enrich_mask_schema(_this.mask.CURRENT, 'CURRENT');
        return _this.__schema_inst.initPreferredMask('CURRENT', _this.__schema);
      };
    })(this));
  };

  RemoteEasydb.prototype.get_user_key_CURRENT = function(key) {
    var ref;
    return (ref = this.user_keys.CURRENT) != null ? ref[key] : void 0;
  };

  RemoteEasydb.prototype.setInstanceInMaskAndSchema = function() {
    var col, i, j, k, len, len1, len2, mask, ref, ref1, ref2, set_ids_in_mask, table;
    set_ids_in_mask = (function(_this) {
      return function(mask) {
        var field, i, len, ref, results;
        mask._instance = _this.__instance;
        if (mask.mask_id) {
          mask.mask_id = mask.mask_id + '@' + _this.__instance;
        }
        if (mask.name) {
          mask.name = mask.name + '@' + _this.__instance;
        }
        if (mask.table_id) {
          mask.table_id = mask.table_id + '@' + _this.__instance;
        }
        ref = mask.fields;
        results = [];
        for (i = 0, len = ref.length; i < len; i++) {
          field = ref[i];
          if (field.other_table_id) {
            field.other_table_id = field.other_table_id + '@' + _this.__instance;
          }
          if (field.mask_id && field.mask_id !== 'PREFERRED') {
            field.mask_id = field.mask_id + '@' + _this.__instance;
          }
          if (field.mask) {
            results.push(set_ids_in_mask(field.mask));
          } else {
            results.push(void 0);
          }
        }
        return results;
      };
    })(this);
    ref = this.mask.CURRENT.masks;
    for (i = 0, len = ref.length; i < len; i++) {
      mask = ref[i];
      set_ids_in_mask(mask);
    }
    ref1 = this.schema.CURRENT.tables;
    for (j = 0, len1 = ref1.length; j < len1; j++) {
      table = ref1[j];
      table.table_id = table.table_id + '@' + this.__instance;
      table.name = table.name + '@' + this.__instance;
      table._instance = this.__instance;
      ref2 = table.columns;
      for (k = 0, len2 = ref2.length; k < len2; k++) {
        col = ref2[k];
        if (col.other_table_id) {
          col.other_table_id = col.other_table_id + '@' + this.__instance;
        }
      }
    }
  };

  RemoteEasydb.prototype.setEasydbVersion = function(version) {
    this.__easydbVersion = version;
  };

  RemoteEasydb.prototype.version = function(exp_version) {
    var i, idx, len, part_exp, parts_exp, parts_v, v;
    v = this.__easydbVersion;
    if (v) {
      v = v.replace(/^v/, "");
    }
    if (CUI.util.isEmpty(exp_version)) {
      return v;
    }
    if (v === null) {
      return false;
    }
    parts_v = v.split(".").map((function(_this) {
      return function(v) {
        return parseInt(v);
      };
    })(this));
    parts_exp = exp_version.split(".").map((function(_this) {
      return function(v) {
        return parseInt(v);
      };
    })(this));
    for (idx = i = 0, len = parts_exp.length; i < len; idx = ++i) {
      part_exp = parts_exp[idx];
      if (parts_v[idx] > part_exp) {
        return true;
      }
      if (part_exp > parts_v[idx]) {
        return false;
      }
    }
    return true;
  };

  return RemoteEasydb;

})(CUI.Element);
