Tabnine Logo
AlertStreamEvent
Code IndexAdd Tabnine to your IDE (free)

How to use
AlertStreamEvent
in
org.apache.eagle.alert.engine.model

Best Java code snippets using org.apache.eagle.alert.engine.model.AlertStreamEvent (Showing top 20 results out of 315)

origin: apache/eagle

private AlertStreamEvent mockAlertEvent (String policyId) {
  AlertStreamEvent event = new AlertStreamEvent();
  event.setSiteId("test");
  event.setCreatedBy("junit");
  event.setCreatedTime(1480491075923L);
  event.setPolicyId(policyId);
  event.setStreamId("ALERT_STREAM");
  event.setSchema(mockAlertStreamDefinition("ALERT_STREAM"));
  event.setMetaVersion("SAMPLE_META_VERSION");
  event.setTimestamp(1480491075923L);
  event.setData(new Object[]{"test_cluster", "cpu.usage", "localhost", "hadoop", 0.98});
  event.ensureAlertId();
  return event;
}
origin: apache/eagle

public static AlertPublishEvent createAlertPublishEvent(AlertStreamEvent event) {
  Preconditions.checkNotNull(event.getAlertId(), "alertId is not initialized before being published: " + event.toString());
  AlertPublishEvent alertEvent = new AlertPublishEvent();
  alertEvent.setAlertId(event.getAlertId());
  alertEvent.setPolicyId(event.getPolicyId());
  alertEvent.setAlertTimestamp(event.getCreatedTime());
  alertEvent.setStreamId(event.getStreamId());
  alertEvent.setCreatedBy(event.getCreatedBy());
  alertEvent.setCreatedTime(event.getCreatedTime());
  alertEvent.setAlertSubject(event.getSubject());
  alertEvent.setAlertBody(event.getBody());
  if (event.getContext() != null && !event.getContext().isEmpty()) {
    if (event.getContext().containsKey(SITE_ID_KEY)) {
      alertEvent.setSiteId(event.getContext().get(SITE_ID_KEY).toString());
    }
    if (event.getContext().containsKey(POLICY_VALUE_KEY)) {
      alertEvent.setPolicyValue(event.getContext().get(POLICY_VALUE_KEY).toString());
    }
    if (event.getContext().containsKey(APP_IDS_KEY)) {
      alertEvent.setAppIds((List<String>) event.getContext().get(APP_IDS_KEY));
    }
  }
  alertEvent.setAlertData(event.getDataMap());
  return alertEvent;
}
origin: apache/eagle

public AlertStreamEvent(AlertStreamEvent event) {
  this.siteId = event.getSiteId();
  this.alertId = event.getAlertId();
  this.policyId = event.policyId;
  this.schema = event.schema;
  this.createdBy = event.createdBy;
  this.createdTime = event.createdTime;
  this.setTimestamp(event.getTimestamp());
  this.setData(new Object[event.data.length]);
  System.arraycopy(event.data, 0, this.data, 0, event.data.length);
  this.setStreamId(event.getStreamId());
  this.setMetaVersion(event.getMetaVersion());
}
origin: apache/eagle

private String getAlertBody(AlertStreamEvent event) {
  if (event.getBody() == null) {
    return String.format("Alert policy \"%s\" was triggered: %s", event.getPolicyId(), generateAlertDataDesc(event));
  } else {
    return event.getBody();
  }
}
origin: apache/eagle

@Override
public String toString() {
  List<String> dataStrings = new ArrayList<>(this.getData().length);
  for (Object obj : this.getData()) {
    if (obj != null) {
      dataStrings.add(obj.toString());
    } else {
      dataStrings.add(null);
    }
  }
  return String.format("Alert {site=%s, stream=%s,timestamp=%s,data=%s, policyId=%s, createdBy=%s, metaVersion=%s}",
    this.getSiteId(),
    this.getStreamId(), DateTimeUtil.millisecondsToHumanDateWithMilliseconds(this.getTimestamp()),
    this.getDataMap(), this.getPolicyId(), this.getCreatedBy(), this.getMetaVersion());
}
origin: apache/eagle

private AlertStreamEvent mergeEventWithDedupValue(AlertStreamEvent originalEvent,
                         DedupValue dedupValue, String dedupStateField) {
  AlertStreamEvent event = new AlertStreamEvent();
  Object[] newdata = new Object[originalEvent.getData().length];
  for (int i = 0; i < originalEvent.getData().length; i++) {
    newdata[i] = originalEvent.getData()[i];
  event.setData(newdata);
  event.setStreamId(originalEvent.getStreamId());
  event.setSchema(originalEvent.getSchema());
  event.setPolicyId(originalEvent.getPolicyId());
  event.setCreatedTime(originalEvent.getCreatedTime());
  event.setCreatedBy(originalEvent.getCreatedBy());
  event.setTimestamp(originalEvent.getTimestamp());
  StreamDefinition streamDefinition = event.getSchema();
  for (int i = 0; i < event.getData().length; i++) {
    String colName = streamDefinition.getColumns().get(i).getName();
    if (Objects.equal(colName, dedupStateField)) {
      event.getData()[i] = dedupValue.getStateFieldValue();
      event.getData()[i] = dedupValue.getCount();
      event.getData()[i] = dedupValue.getFirstOccurrence();
      event.getData()[i] = dedupValue.getDocId();
origin: apache/eagle

public static AlertStreamEvent createEvent(StreamDefinition stream, PolicyDefinition policy, Object[] data) {
  AlertStreamEvent event = new AlertStreamEvent();
  event.setPolicyId(policy.getName());
  event.setSchema(stream);
  event.setStreamId(stream.getStreamId());
  event.setTimestamp(System.currentTimeMillis());
  event.setCreatedTime(System.currentTimeMillis());
  event.setSubject("Namenode Disk Used 98%");
  event.setBody("Disk Usage of Test cluster's name node (<a href=\"#\">namenode.hostname.domain</a>) is <strong style=\"color: red\">98%</strong> at <strong>2016-11-30 12:30:45</strong>, exceeding alert threshold <strong>90</strong>%");
  event.setData(data);
  event.ensureAlertId();
  event.setSeverity(AlertSeverity.CRITICAL);
  event.setCategory("HDFS");
  event.setContext(new HashMap<String,Object>(){{
    put(AlertPublishEvent.SITE_ID_KEY,"TestCluster");
  }});
  Assert.assertNotNull(event.getAlertId());
  return event;
}
origin: apache/eagle

if (event.getContext() != null) {
  for (Map.Entry<String, Object> entry : event.getContext().entrySet()) {
    if (entry.getValue() == null) {
      alertContext.put(entry.getKey(), "N/A");
alertContext.put(PublishConstants.ALERT_EMAIL_SUBJECT, event.getSubject());
alertContext.put(PublishConstants.ALERT_EMAIL_BODY, getAlertBody(event));
alertContext.put(PublishConstants.ALERT_EMAIL_POLICY_ID, event.getPolicyId());
alertContext.put(PublishConstants.ALERT_EMAIL_ALERT_ID, event.getAlertId());
alertContext.put(PublishConstants.ALERT_EMAIL_ALERT_DATA, event.getDataMap().toString());
alertContext.put(PublishConstants.ALERT_EMAIL_ALERT_DATA_DESC, generateAlertDataDesc(event));
alertContext.put(PublishConstants.ALERT_EMAIL_ALERT_CATEGORY, event.getCategory());
alertContext.put(PublishConstants.ALERT_EMAIL_ALERT_SEVERITY, event.getSeverity().toString());
alertContext.put(PublishConstants.ALERT_EMAIL_TIME, String.format("%s %s",
    DateTimeUtil.millisecondsToHumanDateWithSeconds(event.getCreatedTime()),
    DateTimeUtil.CURRENT_TIME_ZONE.getID()));
alertContext.put(PublishConstants.ALERT_EMAIL_STREAM_ID, event.getStreamId());
alertContext.put(PublishConstants.ALERT_EMAIL_CREATOR, event.getCreatedBy());
alertContext.put(PublishConstants.ALERT_EMAIL_VERSION, Version.version);
try {
  alertContext.put(PublishConstants.ALERT_EMAIL_ALERT_DETAIL_URL,
    String.format("%s/#/site/%s/alert/detail/%s?timestamp=%s", rootUrl, event.getSiteId(), URIUtil.encodeQuery(event.getAlertId(), "UTF-8"), event.getTimestamp()));
  alertContext.put(PublishConstants.ALERT_EMAIL_POLICY_DETAIL_URL,
    String.format("%s/#/site/%s/policy/detail/%s", rootUrl, event.getSiteId(), URIUtil.encodeQuery(event.getPolicyId(), "UTF-8")));
} catch (URIException e) {
  LOG.warn(e.getMessage(), e);
  alertContext.put(PublishConstants.ALERT_EMAIL_ALERT_DETAIL_URL,
    String.format("%s/#/site/%s/alert/detail/%s?timestamp=%s", rootUrl, event.getSiteId(), event.getAlertId(), event.getTimestamp()));
origin: apache/eagle

public AlertEntity convertAlertEvent(AlertStreamEvent event) {
  Preconditions.checkNotNull(event.getAlertId(), "alertId is not initialized before being published: " + event.toString());
  AlertEntity alertEvent = new AlertEntity();
  Map<String, String> tags = new HashMap<>();
  tags.put(POLICY_ID_KEY, event.getPolicyId());
  tags.put(ALERT_ID_KEY, event.getAlertId());
  tags.put(ALERT_CATEGORY, event.getCategory());
  tags.put(ALERT_SEVERITY, event.getSeverity().toString());
  String host = event.getDataMap().getOrDefault("host", "null").toString();
  String hostname = event.getDataMap().getOrDefault("hostname", "null").toString();
  if (host != "null") {
    tags.put(ALERT_HOST, host);
  } else {
    tags.put(ALERT_HOST, hostname);
  }
  if (event.getContext() != null && !event.getContext().isEmpty()) {
    tags.put(SITE_ID_KEY, event.getContext().get(SITE_ID_KEY).toString());
    alertEvent.setPolicyValue(event.getContext().get(POLICY_VALUE_KEY).toString());
    alertEvent.setAppIds((List<String>) event.getContext().get(APP_IDS_KEY));
  }
  alertEvent.setTimestamp(event.getCreatedTime());
  alertEvent.setAlertData(event.getDataMap());
  alertEvent.setAlertSubject(event.getSubject());
  alertEvent.setAlertBody(event.getBody());
  alertEvent.setTags(tags);
  return alertEvent;
}
origin: apache/eagle

public String streamEventToJson(AlertStreamEvent event) {
  Map<String, Object> jsonMap = new HashMap<String, Object>();
  jsonMap.put("policyId", event.getPolicyId());
  jsonMap.put("streamId", event.getStreamId());
  jsonMap.put("createBy", event.getCreatedBy());
  jsonMap.put("createTime", event.getCreatedTime());
  // data
  int size = event.getData().length;
  List<StreamColumn> columns = event.getSchema().getColumns();
  for (int i = 0; i < size; i++) {
    if (columns.size() < i) {
      // redundant check to log inconsistency
      LOG.error(" stream event data have different lenght compare to column definition! ");
    } else {
      jsonMap.put(columns.get(i).getName(), event.getData()[i]);
    }
  }
  return JsonUtils.writeValueAsString(jsonMap);
}
origin: apache/eagle

  private static VelocityContext buildAlertContext(PolicyDefinition policyDefinition, AlertStreamEvent event) {
    VelocityContext context = new VelocityContext();
    context.put(AlertContextFields.SITE_ID, event.getSiteId());
    context.put(AlertContextFields.STREAM_ID, event.getStreamId());
    context.put(AlertContextFields.ALERT_ID, event.getAlertId());
    context.put(AlertContextFields.CREATED_BY, event.getCreatedBy());
    context.put(AlertContextFields.CREATED_TIMESTAMP, event.getCreatedTime());
    context.put(AlertContextFields.CREATED_TIME,  String.format("%s %s",
        DateTimeUtil.millisecondsToHumanDateWithSeconds(event.getCreatedTime()),
        DateTimeUtil.CURRENT_TIME_ZONE.getID()));
    context.put(AlertContextFields.ALERT_TIMESTAMP, event.getTimestamp());
    context.put(AlertContextFields.ALERT_TIME,  String.format("%s %s",
        DateTimeUtil.millisecondsToHumanDateWithSeconds(event.getTimestamp()),
        DateTimeUtil.CURRENT_TIME_ZONE.getID()));
    context.put(AlertContextFields.ALERT_SCHEMA, event.getSchema());
    context.put(AlertContextFields.ALERT_EVENT, event);

    context.put(AlertContextFields.POLICY_ID, policyDefinition.getName());
    context.put(AlertContextFields.POLICY_DESC, policyDefinition.getDescription());
    context.put(AlertContextFields.POLICY_TYPE, policyDefinition.getDefinition().getType());
    context.put(AlertContextFields.POLICY_DEFINITION, policyDefinition.getDefinition().getValue());
    context.put(AlertContextFields.POLICY_HANDLER, policyDefinition.getDefinition().getHandlerClass());

    for (Map.Entry<String, Object> entry : event.getDataMap().entrySet()) {
      context.put(entry.getKey(), entry.getValue());
    }
    return context;
  }
}
origin: apache/eagle

AlertStreamEvent alertStreamEvent = new AlertStreamEvent();
alertStreamEvent.setData(new Object[]{"namevalue", "hostvalue", "1", 10, 0.1, -0.2, "{\"name\":\"heap.COMMITTED\", \"Value\":\"175636480\"}", 1});
alertStreamEvent.setSchema(streamDefinition);
alertStreamEvent.setPolicyId("setPolicyId");
alertStreamEvent.setCreatedTime(1234);
alertStreamEvent.ensureAlertId();
AlertPublishEvent alertPublishEvent = AlertPublishEvent.createAlertPublishEvent(alertStreamEvent);
Assert.assertEquals(null, alertPublishEvent.getSiteId());
extraData.put(AlertPublishEvent.POLICY_VALUE_KEY, "POLICY_VALUE_KEY");
extraData.put(AlertPublishEvent.APP_IDS_KEY, Arrays.asList("appId1", "appId2"));
alertStreamEvent.setContext(extraData);
origin: apache/eagle

  /**
   * TODO: Refactor wrapAlertPublishEvent into alertTemplateEngine and remove extraData from AlertStreamEvent.
   */
  @Override
  public AlertStreamEvent filter(AlertStreamEvent event) {
    event.ensureAlertId();
    Map<String, Object> extraData = new HashMap<>();
    List<String> appIds = new ArrayList<>();
    if (alertPublisherBolt.policyDefinitionMap == null || alertPublisherBolt.streamDefinitionMap == null) {
      LOG.warn("policyDefinitions or streamDefinitions in publisher bolt have not been initialized");
    } else {
      PolicyDefinition policyDefinition = alertPublisherBolt.policyDefinitionMap.get(event.getPolicyId());
      if (alertPublisherBolt.policyDefinitionMap != null && policyDefinition != null) {
        for (String inputStreamId : policyDefinition.getInputStreams()) {
          StreamDefinition sd = alertPublisherBolt.streamDefinitionMap.get(inputStreamId);
          if (sd != null) {
            extraData.put(AlertPublishEvent.SITE_ID_KEY, sd.getSiteId());
            appIds.add(sd.getStreamSource());
          }
        }
        extraData.put(AlertPublishEvent.APP_IDS_KEY, appIds);
        extraData.put(AlertPublishEvent.POLICY_VALUE_KEY, policyDefinition.getDefinition().getValue());
        event.setSeverity(policyDefinition.getAlertSeverity());
        event.setCategory(policyDefinition.getAlertCategory());
      }
      event.setContext(extraData);
    }
    return event;
  }
}
origin: apache/eagle

@Override
public void send(StreamEvent event) throws Exception {
  AlertStreamEvent alert = new AlertStreamEvent();
  alert.setPolicyId(context.getPolicyDefinition().getName());
  alert.setSchema(sds.get(event.getStreamId()));
  this.collector.emit(alert);
}
origin: apache/eagle

@Override
public void emit(AlertStreamEvent event) {
  if (event == null) {
    return;
  }
  event.ensureAlertId();
  Set<PublishPartition> clonedPublishPartitions = new HashSet<>(publishPartitions);
  for (PublishPartition publishPartition : clonedPublishPartitions) {
    // skip the publish partition which is not belong to this policy and also check streamId
    PublishPartition cloned = publishPartition.clone();
    Optional.ofNullable(event)
        .filter(x -> x != null
            && x.getSchema() != null
            && cloned.getPolicyId().equalsIgnoreCase(x.getPolicyId())
            && (cloned.getStreamId().equalsIgnoreCase(x.getSchema().getStreamId())
            || cloned.getStreamId().equalsIgnoreCase(Publishment.STREAM_NAME_DEFAULT)))
        .ifPresent(x -> {
          cloned.getColumns().stream()
              .filter(y -> event.getSchema().getColumnIndex(y) >= 0
                  && event.getSchema().getColumnIndex(y) < event.getSchema().getColumns().size())
              .map(y -> event.getData()[event.getSchema().getColumnIndex(y)])
              .filter(y -> y != null)
              .forEach(y -> cloned.getColumnValues().add(y));
          synchronized (outputLock) {
            streamContext.counter().incr("alert_count");
            delegate.emit(Arrays.asList(cloned, event));
          }
        });
  }
}
origin: apache/eagle

  @Test
  public void testAlertStreamEvent() {
    List<StreamColumn> streamColumns = new ArrayList<>();
    streamColumns.add(new StreamColumn.Builder().name("name").type(StreamColumn.Type.STRING).build());
    streamColumns.add(new StreamColumn.Builder().name("host").type(StreamColumn.Type.STRING).build());
    streamColumns.add(new StreamColumn.Builder().name("flag").type(StreamColumn.Type.BOOL).build());
    streamColumns.add(new StreamColumn.Builder().name("value").type(StreamColumn.Type.DOUBLE).build());
    streamColumns.add(new StreamColumn.Builder().name("data").type(StreamColumn.Type.LONG).build());
    streamColumns.add(new StreamColumn.Builder().name("salary").type(StreamColumn.Type.FLOAT).build());
    streamColumns.add(new StreamColumn.Builder().name("object").type(StreamColumn.Type.OBJECT).build());
    streamColumns.add(new StreamColumn.Builder().name("int").type(StreamColumn.Type.INT).build());

    StreamDefinition streamDefinition = new StreamDefinition();
    streamDefinition.setColumns(streamColumns);
    AlertStreamEvent alertStreamEvent = new AlertStreamEvent();
    alertStreamEvent.setSchema(streamDefinition);
    alertStreamEvent.setData(new Object[]{"namevalue", "hostvalue", "1", 10, 0.1, -0.2, "{\"name\":\"heap.COMMITTED\", \"Value\":\"175636480\"}", 1});
    AlertStreamEvent alertStreamEvent1 = new AlertStreamEvent(alertStreamEvent);
    Assert.assertFalse(alertStreamEvent1 == alertStreamEvent);
    Assert.assertTrue(alertStreamEvent1.equals(alertStreamEvent));
    Assert.assertTrue(alertStreamEvent1.hashCode() == alertStreamEvent.hashCode());
  }
}
origin: apache/eagle

@Test
public void testVelocityAlertTemplateWithoutTemplate () {
  AlertTemplateEngine templateEngine = new VelocityAlertTemplateEngine();
  templateEngine.init(ConfigFactory.load());
  templateEngine.register(mockPolicyWithoutTemplate("testPolicyName"));
  AlertStreamEvent event = templateEngine.filter(mockAlertEvent("testPolicyName"));
  Assert.assertEquals("Message: Alert {site=test, stream=ALERT_STREAM,timestamp=2016-11-30 07:31:15,923," +
    "data={site=test_cluster, role=hadoop, metric=cpu.usage, host=localhost, value=0.98}, " +
    "policyId=testPolicyName, createdBy=junit, metaVersion=SAMPLE_META_VERSION} " +
    "(Auto-generated alert message as template not defined in policy testPolicyName)", event.getBody());
  Assert.assertEquals("testPolicyName", event.getSubject());
}
origin: apache/eagle

  @Override
  public void emit(Object o) {
    AlertStreamEvent e = (AlertStreamEvent) o;
    Object[] data = e.getData();
    Assert.assertEquals("host2", data[1]);
    LOG.info(e.toString());
  }
}
origin: apache/eagle

@Test
public void testSlackPublishment() throws Exception {
  Config config = ConfigFactory.load("application-test.conf");
  AlertPublisher publisher = new AlertPublisherImpl("alertPublishBolt");
  publisher.init(config, new HashMap());
  List<Publishment> pubs = loadEntities("/router/publishments-slack.json", Publishment.class);
  publisher.onPublishChange(pubs, null, null, null);
  AlertStreamEvent event1 = createSeverityWithStreamDef("switch1", "testapp1", "Memory 1 inconsistency detected", "WARNING", "docId1", "ed01", "distribution switch", "us");
  AlertStreamEvent event2 = createSeverityWithStreamDef("switch2", "testapp2", "Memory 2 inconsistency detected", "CRITICAL", "docId2", "ed02", "distribution switch", "us");
  AlertStreamEvent event3 = createSeverityWithStreamDef("switch2", "testapp2", "Memory 3 inconsistency detected", "WARNING", "docId3", "ed02", "distribution switch", "us");
  publisher.nextEvent(new PublishPartition(event1.getStreamId(), event1.getPolicyId(),
    pubs.get(0).getName(), pubs.get(0).getPartitionColumns()), event1);
  publisher.nextEvent(new PublishPartition(event2.getStreamId(), event2.getPolicyId(),
    pubs.get(0).getName(), pubs.get(0).getPartitionColumns()), event2);
  publisher.nextEvent(new PublishPartition(event3.getStreamId(), event3.getPolicyId(),
    pubs.get(0).getName(), pubs.get(0).getPartitionColumns()), event3);
}
origin: apache/eagle

@Override
public synchronized AlertStreamEvent filter(AlertStreamEvent event) {
  Preconditions.checkArgument(this.policyDefinitionRepository.containsKey(event.getPolicyId()), "Unknown policyId " + event.getPolicyId());
  PolicyDefinition policyDefinition = this.policyDefinitionRepository.get(event.getPolicyId());
  StringWriter bodyWriter = new StringWriter();
  StringWriter subjectWriter = new StringWriter();
  try {
    VelocityContext alertContext = buildAlertContext(policyDefinition, event);
    Template template = engine.getTemplate(getAlertBodyTemplateName(event.getPolicyId()));
    template.merge(alertContext, bodyWriter);
    event.setBody(bodyWriter.toString());
    template = engine.getTemplate(getAlertSubjectTemplateName(event.getPolicyId()));
    template.merge(alertContext, subjectWriter);
    event.setSubject(subjectWriter.toString());
  } finally {
    try {
      bodyWriter.close();
    } catch (IOException e) {
      LOG.warn(e.getMessage(), e);
    }
    try {
      subjectWriter.close();
    } catch (IOException e) {
      LOG.warn(e.getMessage(), e);
    }
  }
  return event;
}
org.apache.eagle.alert.engine.modelAlertStreamEvent

Javadoc

streamId stands for alert type instead of source event streamId.

Most used methods

  • ensureAlertId
  • getAlertId
  • getBody
  • getCreatedTime
  • getPolicyId
  • getSubject
  • setData
  • toString
  • <init>
  • getContext
  • getData
  • getDataMap
  • getData,
  • getDataMap,
  • getStreamId,
  • setContext,
  • setCreatedTime,
  • setPolicyId,
  • setSchema,
  • setStreamId,
  • setTimestamp,
  • getCategory

Popular in Java

  • Updating database using SQL prepared statement
  • putExtra (Intent)
  • getSystemService (Context)
  • startActivity (Activity)
  • InputStreamReader (java.io)
    A class for turning a byte stream into a character stream. Data read from the source input stream is
  • Selector (java.nio.channels)
    A controller for the selection of SelectableChannel objects. Selectable channels can be registered w
  • Date (java.sql)
    A class which can consume and produce dates in SQL Date format. Dates are represented in SQL as yyyy
  • DecimalFormat (java.text)
    A concrete subclass of NumberFormat that formats decimal numbers. It has a variety of features desig
  • TimeZone (java.util)
    TimeZone represents a time zone offset, and also figures out daylight savings. Typically, you get a
  • UUID (java.util)
    UUID is an immutable representation of a 128-bit universally unique identifier (UUID). There are mul
  • Sublime Text for Python
Tabnine Logo
  • Products

    Search for Java codeSearch for JavaScript code
  • IDE Plugins

    IntelliJ IDEAWebStormVisual StudioAndroid StudioEclipseVisual Studio CodePyCharmSublime TextPhpStormVimAtomGoLandRubyMineEmacsJupyter NotebookJupyter LabRiderDataGripAppCode
  • Company

    About UsContact UsCareers
  • Resources

    FAQBlogTabnine AcademyStudentsTerms of usePrivacy policyJava Code IndexJavascript Code Index
Get Tabnine for your IDE now