Automatycznie modyfikuj Zdalną konfigurację

W tym dokumencie opisano, jak odczytywać i modyfikować za pomocą kodu zestaw parametrów i warunków w formacie JSON, czyli tzw. szablon Remote Config. Dzięki temu możesz wprowadzać zmiany w szablonach w backendzie, które aplikacja klienta może pobrać za pomocą biblioteki klienta.

Korzystając z interfejsu Remote Config REST API lub Admin SDK opisanych w tym przewodniku, możesz pominąć zarządzanie szablonem w konsoli Firebase, aby bezpośrednio zintegrować zmiany Remote Config ze swoimi procesami. Za pomocą interfejsów API back-end, takich jak Remote Config, możesz na przykład:

  • Planowanie aktualizacji Remote Config. Za pomocą wywołań interfejsu API w połączeniu z zadaniem crona możesz zmieniać wartości Remote Config według regularnego harmonogramu.
  • Importuj zbiorczo wartości konfiguracji, aby sprawnie przejść z własnego systemu na Firebase Remote Config.
  • Używaj funkcji Remote Config w połączeniu z funkcją Cloud Functions for Firebase, aby zmieniać wartości w aplikacji na podstawie zdarzeń występujących po stronie serwera. Możesz na przykład użyć Remote Config, aby promować nową funkcję w aplikacji, a potem automatycznie wyłączyć tę promocję, gdy wykryjesz, że wystarczająca liczba osób skorzystała z tej funkcji.

    Schemat przedstawiający backend Zdalnej konfiguracji w interakcji z niestandardowymi narzędziami i serwerami

W następnych sekcjach tego przewodnika opisujemy operacje, które możesz wykonywać za pomocą interfejsów backendowych Remote Config. Aby sprawdzić kod, który wykonuje te czynności za pomocą interfejsu REST API, otwórz jedną z tych przykładowych aplikacji:

Modyfikowanie Zdalnej konfiguracji za pomocą pakietu Firebase Admin SDK

Admin SDK to zestaw bibliotek serwera, które umożliwiają interakcję z Firebase z prywatnych środowisk. Oprócz wykonywania operacji aktualizacji w Remote Config usługa Admin SDK umożliwia też generowanie i weryfikowanie tokenów uwierzytelniania Firebase, odczytywanie i zapisywanie danych z Realtime Database itp. Więcej informacji o Admin SDK wymaganiach wstępnych i konfiguracji znajdziesz w artykule Dodawanie pakietu Firebase Admin SDK do serwera.

W typowym procesie Remote Config możesz pobrać bieżący szablon, zmodyfikować niektóre parametry lub grupy parametrów i warunki, sprawdzić szablon, a następnie go opublikować. Zanim wykonasz te wywołania interfejsu API, musisz autoryzować żądania z pakietu SDK.

Inicjowanie pakietu SDK i autoryzowanie żądań interfejsu API

Gdy inicjujesz Admin SDK bez parametrów, pakiet SDK używa domyślnych danych logowania aplikacji Google i odczytuje opcje z zmiennej środowiskowej FIREBASE_CONFIG. Jeśli zawartość zmiennej FIREBASE_CONFIG zaczyna się od {, zostanie zanalizowana jako obiekt JSON. W przeciwnym razie SDK zakłada, że ciąg znaków to nazwa pliku JSON zawierającego opcje.

Przykład:

Node.js

const admin = require('firebase-admin');
admin.initializeApp();

Java

FileInputStream serviceAccount = new FileInputStream("service-account.json");
FirebaseOptions options = FirebaseOptions.builder()
        .setCredentials(GoogleCredentials.fromStream(serviceAccount))
        .build();
FirebaseApp.initializeApp(options);

Pobieranie bieżącego szablonu Zdalnej konfiguracji

Podczas pracy z szablonami Remote Config pamiętaj, że są one wersjonowane, a każda wersja ma ograniczony czas istnienia od momentu jej utworzenia do momentu zastąpienia przez aktualizację: 90 dni. Ogólny limit przechowywanych wersji to 300. Więcej informacji znajdziesz w artykule Szablony i wersje.

Za pomocą interfejsów API backendu możesz pobrać bieżącą aktywną wersję szablonu Remote Config w formacie JSON.

Parametry i ich wartości utworzone jako warianty w eksperymencie A/B Testing nie są uwzględniane w eksportowanych szablonach.

Aby uzyskać szablon:

Node.js

function getTemplate() {
  var config = admin.remoteConfig();
  config.getTemplate()
      .then(function (template) {
        console.log('ETag from server: ' + template.etag);
        var templateStr = JSON.stringify(template);
        fs.writeFileSync('config.json', templateStr);
      })
      .catch(function (err) {
        console.error('Unable to get template');
        console.error(err);
      });
}

Java

Template template = FirebaseRemoteConfig.getInstance().getTemplateAsync().get();
// See the ETag of the fetched template.
System.out.println("ETag from server: " + template.getETag());
.

Modyfikowanie parametrów Zdalnej konfiguracji

Możesz je modyfikować i dodawać za pomocą kodu oraz dodawać grupy parametrów.Remote Config Możesz np. dodać do istniejącej grupy parametrów o nazwie „new_menu” parametr, który będzie kontrolować wyświetlanie informacji sezonowych:

Node.js

function addParameterToGroup(template) {
  template.parameterGroups['new_menu'].parameters['spring_season'] = {
    defaultValue: {
      useInAppDefault: true
    },
    description: 'spring season menu visibility.',
  };
}

Java

template.getParameterGroups().get("new_menu").getParameters()
        .put("spring_season", new Parameter()
                .setDefaultValue(ParameterValue.inAppDefault())
                .setDescription("spring season menu visibility.")
        );

Interfejs API umożliwia tworzenie nowych parametrów i ich grup oraz modyfikowanie wartości domyślnych, wartości warunkowych i opisów. W każdym przypadku po wprowadzeniu zmian musisz wyraźnie opublikować szablon.

Zmienianie warunków Zdalnej konfiguracji

Możesz je modyfikować i dodawać za pomocą kodu.Remote Config Aby na przykład dodać nowy warunek:

Node.js

function addNewCondition(template) {
  template.conditions.push({
    name: 'android_en',
    expression: 'device.os == \'android\' && device.country in [\'us\', \'uk\']',
    tagColor: 'BLUE',
  });
}

Java

template.getConditions().add(new Condition("android_en",
        "device.os == 'android' && device.country in ['us', 'uk']", TagColor.BLUE));

W każdym przypadku po wprowadzeniu zmian musisz wyraźnie opublikować szablon.

Interfejsy API zaplecza Remote Config udostępniają kilka warunków i operatorów porównań, których możesz używać do zmiany działania i wyglądu aplikacji. Więcej informacji o warunkach i operatorach obsługiwanych przez te warunki znajdziesz w przewodniku po wyrażeniach warunkowych.

Weryfikacja szablonu Zdalnej konfiguracji

Opcjonalnie możesz zweryfikować aktualizacje przed ich opublikowaniem:

Node.js

function validateTemplate(template) {
  admin.remoteConfig().validateTemplate(template)
      .then(function (validatedTemplate) {
        // The template is valid and safe to use.
        console.log('Template was valid and safe to use');
      })
      .catch(function (err) {
        console.error('Template is invalid and cannot be published');
        console.error(err);
      });
}

Java

try {
  Template validatedTemplate = FirebaseRemoteConfig.getInstance()
          .validateTemplateAsync(template).get();
  System.out.println("Template was valid and safe to use");
} catch (ExecutionException e) {
  if (e.getCause() instanceof FirebaseRemoteConfigException) {
    FirebaseRemoteConfigException rcError = (FirebaseRemoteConfigException) e.getCause();
    System.out.println("Template is invalid and cannot be published");
    System.out.println(rcError.getMessage());
  }
}

Podczas tego procesu weryfikacji sprawdzane są błędy takie jak zduplikowane klucze parametrów i warunków, nieprawidłowe nazwy warunków lub nieistniejące warunki albo nieprawidłowo sformatowane etagi. Na przykład żądanie zawierające więcej niż dozwoloną liczbę kluczy (2000) zwróci komunikat o błędzie Param count too large.

Publikowanie szablonu Zdalnej konfiguracji

Po pobraniu szablonu i wprowadzeniu w nim odpowiednich zmian możesz go opublikować. Opublikowanie szablonu zgodnie z opisem w tej sekcji powoduje zastąpienie całego dotychczasowego szablonu konfiguracji zaktualizowanym plikiem, a nowemu aktywnemu szablonowi zostanie przypisany numer wersji o jeden wyższy niż numer wersji zastępowanego szablonu.

W razie potrzeby możesz użyć interfejsu REST API, aby przywrócić poprzednią wersję. Aby zmniejszyć ryzyko wystąpienia błędów w aktualizacji, możesz potwierdzić ją przed opublikowaniem.

Remote ConfigW pobieranych szablonach uwzględniono personalizację i warunki, dlatego podczas próby opublikowania w innym projekcie należy wziąć pod uwagę te ograniczenia:

  • Personalizacji nie można importować z jednego projektu do drugiego.

    Jeśli na przykład masz w projekcie włączoną personalizację i pobierasz oraz edytujesz szablon, możesz go opublikować w tym samym projekcie, ale nie możesz opublikować go w innym projekcie, chyba że usuniesz z niego personalizację.

  • Warunki można importować z jednego projektu do drugiego, ale pamiętaj, że przed opublikowaniem w projekcie docelowym powinny znajdować się w nim odpowiednie wartości warunkowe (np. identyfikatory aplikacji lub listy odbiorców).

    Jeśli np. masz parametr Remote Config, który używa warunku określającego wartość platformy iOS, możesz opublikować szablon w innym projekcie, ponieważ wartości platform są takie same w przypadku każdego projektu. Jeśli jednak zawiera on warunek, który zależy od określonego identyfikatora aplikacji lub listy odbiorców, która nie istnieje w docelowym projekcie, weryfikacja się nie powiedzie.

  • Jeśli szablon, który zamierzasz opublikować, zawiera warunki oparte na elemencie Google Analytics, w projekcie docelowym musisz włączyć element Analytics.

Node.js

function publishTemplate() {
  var config = admin.remoteConfig();
  var template = config.createTemplateFromJSON(
      fs.readFileSync('config.json', 'UTF8'));
  config.publishTemplate(template)
      .then(function (updatedTemplate) {
        console.log('Template has been published');
        console.log('ETag from server: ' + updatedTemplate.etag);
      })
      .catch(function (err) {
        console.error('Unable to publish template.');
        console.error(err);
      });
}

Java

try {
  Template publishedTemplate = FirebaseRemoteConfig.getInstance()
          .publishTemplateAsync(template).get();
  System.out.println("Template has been published");
  // See the ETag of the published template.
  System.out.println("ETag from server: " + publishedTemplate.getETag());
} catch (ExecutionException e) {
  if (e.getCause() instanceof FirebaseRemoteConfigException) {
    FirebaseRemoteConfigException rcError = (FirebaseRemoteConfigException) e.getCause();
    System.out.println("Unable to publish template.");
    System.out.println(rcError.getMessage());
  }
}
.

Modyfikowanie Zdalnej konfiguracji za pomocą interfejsu API REST

W tej sekcji opisano główne możliwości interfejsu API typu REST Remote Config (https://firebaseremoteconfig.googleapis.com). Pełne informacje znajdziesz w dokumentacji interfejsu API.

Uzyskiwanie tokena dostępu do uwierzytelniania i autoryzowania żądań do interfejsu API

Projekty Firebase obsługują konta usługi Google, których możesz używać do wywoływania interfejsów API serwera Firebase z serwera aplikacji lub z zaufanego środowiska. Jeśli kod tworzysz lokalnie lub wdrażasz aplikację lokalnie, możesz użyć danych logowania uzyskanych za pomocą tego konta usługi, aby autoryzować żądania serwera.

Aby uwierzytelnić konto usługi i zezwolić mu na dostęp do usług Firebase, musisz wygenerować plik klucza prywatnego w formacie JSON.

Aby wygenerować plik klucza prywatnego dla konta usługi:

  1. W konsoli Firebase otwórz Ustawienia > Konta usługi.

  2. Kliknij Wygeneruj nowy klucz prywatny, a następnie potwierdź, klikając Wygeneruj klucz.

  3. Bezpiecznie przechowuj plik JSON zawierający klucz.

Podczas autoryzacji za pomocą konta usługi masz 2 możliwości przekazania danych logowania do aplikacji. Możesz ustawić zmienną środowiskową GOOGLE_APPLICATION_CREDENTIALS lub w kodzie wyraźnie podać ścieżkę do klucza konta usługi. Pierwsza opcja jest bezpieczniejsza i zdecydowanie zalecana.

Aby ustawić zmienną środowiskową:

Ustaw zmienną środowiskową GOOGLE_APPLICATION_CREDENTIALS na ścieżkę do pliku JSON zawierającego klucz konta usługi. Ta zmienna dotyczy tylko bieżącej sesji powłoki, więc jeśli otworzysz nową sesję, musisz ponownie ustawić tę zmienną.

Linux lub macOS

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

Windows

W PowerShell:

$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"

Po wykonaniu powyższych czynności aplikacja może domyślnie określać Twoje dane logowania, co pozwala używać danych logowania konta usługi podczas testowania lub uruchamiania w środowiskach innych niż Google.

Aby pobrać krótkotrwały token dostępu OAuth 2.0, użyj danych logowania Firebase wraz z biblioteką Google Auth Library w preferowanym języku:

node.js

 function getAccessToken() {
  return admin.credential.applicationDefault().getAccessToken()
      .then(accessToken => {
        return accessToken.access_token;
      })
      .catch(err => {
        console.error('Unable to get access token');
        console.error(err);
      });
}

W tym przykładzie biblioteka klienta interfejsu Google API uwierzytelnia żądanie za pomocą tokena sieciowego JSON (JWT). Więcej informacji znajdziesz w artykule Tokeny sieciowe JSON.

Python

def _get_access_token():
  """Retrieve a valid access token that can be used to authorize requests.

  :return: Access token.
  """
  credentials = ServiceAccountCredentials.from_json_keyfile_name(
      'service-account.json', SCOPES)
  access_token_info = credentials.get_access_token()
  return access_token_info.access_token

Java

public static String getAccessToken() throws IOException {
  GoogleCredentials googleCredentials = GoogleCredentials
          .fromStream(new FileInputStream("service-account.json"))
          .createScoped(Arrays.asList(SCOPES));
  googleCredentials.refreshAccessToken();
  return googleCredentials.getAccessToken().getTokenValue();
}

Gdy token dostępu wygaśnie, metoda odświeżania tokena zostanie wywołana automatycznie, aby pobrać zaktualizowany token dostępu.

Aby autoryzować dostęp do Remote Config, poproś o zakres https://www.googleapis.com/auth/firebase.remoteconfig.

Modyfikowanie szablonu Zdalnej konfiguracji

Podczas pracy z szablonami Remote Config pamiętaj, że są one wersjonowane i że każda wersja ma ograniczony czas istnienia od momentu jej utworzenia do momentu zastąpienia przez aktualizację: 90 dni, przy łącznym limicie 300 przechowywanych wersji. Więcej informacji znajdziesz w artykule Szablony i wersje.

Pobieranie bieżącego szablonu Zdalnej konfiguracji

Za pomocą interfejsów API backendu możesz pobrać bieżącą aktywną wersję szablonu Remote Config w formacie JSON.

Parametry i ich wartości utworzone jako warianty w eksperymencie A/B Testing nie są uwzględniane w eksportowanych szablonach.

Użyj tych poleceń:

cURL

curl --compressed -D headers -H "Authorization: Bearer token" -X GET https://firebaseremoteconfig.googleapis.com/v1/projects/my-project-id/remoteConfig -o filename

To polecenie wyprowadza ładunek JSON do jednego pliku, a nagłówki (w tym Etag) do osobnego pliku.

Żądanie HTTP w postaci zwykłego tekstu

Host: firebaseremoteconfig.googleapis.com

GET /v1/projects/my-project-id/remoteConfig HTTP/1.1
Authorization: Bearer token
Accept-Encoding: gzip

To wywołanie interfejsu API zwraca następujący ciąg znaków JSON wraz z osobnym nagłówkiem zawierającym eTag, którego używasz w kolejnych żądaniach.

Weryfikacja szablonu Zdalnej konfiguracji

Opcjonalnie możesz zweryfikować aktualizacje przed ich opublikowaniem. Sprawdź poprawność zmian w szablonie, dodając do żądania publikacji parametr URL ?validate_only=true. W odpowiedzi kod stanu 200 i zaktualizowany tag etag z sufiksem -0 oznaczają, że aktualizacja została pomyślnie zweryfikowana. Każda odpowiedź inna niż 200 wskazuje, że dane JSON zawierają błędy, które należy poprawić przed opublikowaniem.

Aktualizowanie szablonu Zdalnej konfiguracji

Po pobraniu szablonu i zmodyfikowaniu zawartości pliku JSON zgodnie z pożądanymi zmianami możesz go opublikować. Opublikowanie szablonu zgodnie z opisem w tej sekcji powoduje zastąpienie całego dotychczasowego szablonu konfiguracji zaktualizowanym plikiem, a nowemu aktywnemu szablonowi zostanie przypisany numer wersji o jeden wyższy niż numer wersji zastępowanego szablonu.

W razie potrzeby możesz użyć interfejsu REST API, aby przywrócić poprzednią wersję. Aby zmniejszyć ryzyko wystąpienia błędów w aktualizacji, możesz potwierdzić ją przed opublikowaniem.

Remote ConfigW pobieranych szablonach uwzględniono personalizację i warunki, dlatego podczas próby opublikowania w innym projekcie należy wziąć pod uwagę te ograniczenia:

  • Personalizacji nie można importować z jednego projektu do drugiego.

    Jeśli na przykład masz w projekcie włączoną personalizację i pobierasz oraz edytujesz szablon, możesz go opublikować w tym samym projekcie, ale nie możesz opublikować go w innym projekcie, chyba że usuniesz z niego personalizację.

  • Warunki można importować z jednego projektu do drugiego, ale pamiętaj, że przed opublikowaniem w projekcie docelowym powinny znajdować się w nim odpowiednie wartości warunkowe (np. identyfikatory aplikacji lub listy odbiorców).

    Jeśli np. masz parametr Remote Config, który używa warunku określającego wartość platformy iOS, możesz opublikować szablon w innym projekcie, ponieważ wartości platform są takie same w przypadku każdego projektu. Jeśli jednak zawiera on warunek, który zależy od określonego identyfikatora aplikacji lub listy odbiorców, która nie istnieje w docelowym projekcie, weryfikacja się nie powiedzie.

  • Jeśli szablon, który zamierzasz opublikować, zawiera warunki oparte na elemencie Google Analytics, w projekcie docelowym musisz włączyć element Analytics.

cURL

curl --compressed -H "Content-Type: application/json; UTF8" -H "If-Match: last-returned-etag" -H "Authorization: Bearer token" -X PUT https://firebaseremoteconfig.googleapis.com/v1/projects/my-project-id/remoteConfig -d @filename

W tym poleceniu curl możesz określić zawartość, używając znaku „@”, a następnie nazwy pliku.

Żądanie HTTP w postaci zwykłego tekstu

Host: firebaseremoteconfig.googleapis.com
PUT /v1/projects/my-project-id/remoteConfig HTTP/1.1
Content-Length: size
Content-Type: application/json; UTF8
Authorization: Bearer token
If-Match: expected ETag
Accept-Encoding: gzip
JSON_HERE

Ponieważ jest to żądanie zapisu, pole ETag zostaje zmodyfikowane przez to polecenie, a zaktualizowana wartość ETag jest podawana w nagłówkach odpowiedzi kolejnego polecenia PUT.

Zmienianie warunków Zdalnej konfiguracji

Możesz programowo modyfikować warunki Remote Config i wartości warunkowe. W przypadku interfejsu REST API musisz bezpośrednio edytować szablon, aby zmodyfikować warunki przed jego opublikowaniem.

{
  "conditions": [{
    "name": "android_english",
    "expression": "device.os == 'android' && device.country in ['us', 'uk']",
    "tagColor": "BLUE"
  }, {
    "name": "tenPercent",
    "expression": "percent <= 10",
    "tagColor": "BROWN"
  }],
  "parameters": {
    "welcome_message": {
      "defaultValue": {
        "value": "Welcome to this sample app"
      },
      "conditionalValues": {
        "tenPercent": {
          "value": "Welcome to this new sample app"
        }
      },
      "description": "The sample app's welcome message"
    },
    "welcome_message_caps": {
      "defaultValue": {
        "value": "false"
      },
      "conditionalValues": {
        "android_english": {
          "value": "true"
        }
      },
      "description": "Whether the welcome message should be displayed in all capital letters."
    }
  }
}

Opisane wyżej modyfikacje najpierw definiują zestaw warunków, a następnie wartości domyślne i wartości parametrów opartych na warunkach (wartości warunkowe) dla każdego parametru. Dodaje też opcjonalny opis każdego elementu. Podobnie jak komentarze do kodu, są one przeznaczone dla deweloperów i nie są wyświetlane w aplikacji. W celu kontroli wersji jest też dodawany tag E.

Interfejsy API zaplecza Remote Config udostępniają kilka warunków i operatorów porównań, których możesz używać do zmiany działania i wyglądu aplikacji. Więcej informacji o warunkach i operatorach obsługiwanych przez te warunki znajdziesz w przewodniku po wyrażeniach warunkowych.

Kody błędów HTTP

Kod stanu Znaczenie
200 Zaktualizowano
400 Wystąpił błąd weryfikacji. Na przykład żądanie zawierające więcej niż dozwoloną liczbę kluczy (2000) zwróci kod 400 (Nieprawidłowe żądanie) z komunikatem o błędzie Param count too large. Ten kod stanu HTTPS może też wystąpić w tych 2 sytuacjach:
  • Wystąpił błąd niezgodności wersji, ponieważ od ostatniego pobrania wartości ETag zmienił się zestaw wartości i warunków. Aby rozwiązać ten problem, użyj polecenia GET, aby uzyskać nowy szablon i wartość ETag, zaktualizuj szablon, a potem prześlij go, używając tego szablonu i nowej wartości ETag.
  • Polecenie PUT (prośba o zaktualizowanie szablonu Remote Config) zostało wykonane bez podania nagłówka If-Match.
401 Wystąpił błąd autoryzacji (nie podano tokena dostępu lub interfejs API REST Firebase Remote Config nie został dodany do projektu w konsoli administracyjnej Cloud)
403 Wystąpił błąd uwierzytelniania (podano nieprawidłowy token dostępu)
500 Wystąpił błąd wewnętrzny. Jeśli wystąpi ten błąd, złóż zgłoszenie do zespołu pomocy Firebase.

Kod stanu 200 oznacza, że szablon Remote Config (parametry, wartości i warunki projektu) został zaktualizowany i jest teraz dostępny dla aplikacji, które korzystają z tego projektu. Inne kody stanu wskazują, że wcześniej istniejący szablon Remote Confignadal jest aktywny.

Po przesłaniu aktualizacji szablonu otwórz konsolę Firebase, aby sprawdzić, czy zmiany są widoczne zgodnie z oczekiwaniami. Jest to bardzo ważne, ponieważ kolejność warunków wpływa na sposób ich oceny (pierwszy warunek, który spełnia kryterium true, wchodzi w życie).

Używanie e-tagów i wymuszanie aktualizacji

Interfejs API REST Remote Config używa tagu elementu (ETag), aby zapobiegać sytuacjom wyścigu i nakładaniu się aktualizacji zasobów. Więcej informacji o tagach ETag znajdziesz w artykule Tag ETag – HTTP.

W przypadku interfejsu API REST zalecamy zapisanie w pamięci podręcznej znacznika ETag z najnowszego polecenia GET i używanie tej wartości w nagłówku If-Match podczas wydawania poleceń PUT. Jeśli polecenie PUT zwraca kod stanu HTTPS 409, musisz wydać nowe polecenie GET, aby uzyskać nowy tag ETag i szablon do użycia w kolejnych poleceniach PUT.

Możesz obejść tag ETag i zapewnianą przez niego ochronę, wymuszając aktualizację szablonu Remote Config w ten sposób: If-Match: *Nie zalecamy jednak stosowania tej metody, ponieważ może ona spowodować utratę aktualizacji szablonu Remote Config, jeśli szablon Remote Config aktualizuje wielu klientów. Taki konflikt może wystąpić w przypadku wielu klientów korzystających z interfejsu API lub sprzecznych aktualizacji ze strony klientów interfejsu API i użytkowników konsoli Firebase.

Wskazówki dotyczące zarządzania wersjami Remote Config szablonów znajdziesz w artykule Szablony konfiguracji zdalnej i wersjonowanie.