text:
package com.streamsets.pipeline.stage.origin.opcua;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.streamsets.datacollector.util.EscapeUtil;
import com.streamsets.pipeline.api.BatchContext;
import com.streamsets.pipeline.api.Field;
import com.streamsets.pipeline.api.PushSource;
import com.streamsets.pipeline.api.Record;
import com.streamsets.pipeline.api.StageException;
import com.streamsets.pipeline.lib.util.ThreadUtil;
import org.apache.directory.api.util.Strings;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfigBuilder;
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaMonitoredItem;
import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscription;
import org.eclipse.milo.opcua.stack.client.UaTcpStackClient;
import org.eclipse.milo.opcua.stack.core.AttributeId;
import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.StatusCodes;
import org.eclipse.milo.opcua.stack.core.channel.ChannelConfig;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UByte;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.ULong;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;
import org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseDirection;
import org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseResultMask;
import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode;
import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.BrowseDescription;
import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResult;
import org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters;
import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;
import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceDescription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;

import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;
import static org.eclipse.milo.opcua.stack.core.util.ConversionUtil.toList;

public class OpcUaClientSource implements PushSource {

  private static final Logger LOG = LoggerFactory.getLogger(OpcUaClientSource.class);
  private static final String SSL_CONFIG_PREFIX = "conf.tlsConfig.";
  private static final String SOURCE_TIME_FIELD_NAME = "sourceTime";
  private static final String SOURCE_PICO_SECONDS_FIELD_NAME = "sourcePicoSeconds";
  private static final String SERVER_TIME_FIELD_NAME = "serverTime";
  private static final String SERVER_PICO_SECONDS_FIELD_NAME = "serverPicoSeconds";
  private static final String STATUS_CODE_FIELD_NAME = "statusCode";
  private static final String STATUS_CODE_STR_FIELD_NAME = "statusCodeStr";
  private static final String VALUE_FIELD_NAME = "value";
  private final OpcUaClientSourceConfigBean conf;
  private Context context;
  private AtomicLong counter = new AtomicLong();
  private BlockingQueue<Exception> errorQueue;
  private List<Exception> errorList;
  private final AtomicLong clientHandles = new AtomicLong(1L);
  private OpcUaClient opcUaClient;
  private List<NodeId> nodeIds;
  private NodeId rootNodeId;
  private volatile boolean destroyed = false;
  private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
  private Stopwatch stopwatch = null;

  OpcUaClientSource(OpcUaClientSourceConfigBean conf) {
    this.conf = conf;
  }

  @Override
  public int getNumberOfThreads() {
    return 1;
  }

  @Override
  public List<ConfigIssue> init(Info info, Context context) {
    List<ConfigIssue> issues = new ArrayList<>();
    this.context = context;
    errorQueue = new ArrayBlockingQueue<>(100);
    errorList = new ArrayList<>(100);

    SecurityPolicy securityPolicy = conf.securityPolicy.getSecurityPolicy();
    if (!securityPolicy.equals(SecurityPolicy.None) && !conf.tlsConfig.isEnabled()) {
      issues.add(
          context.createConfigIssue(
              Groups.SECURITY.name(),
              SSL_CONFIG_PREFIX + "tlsEnabled",
              Errors.OPC_UA_06,
              conf.securityPolicy.getLabel()
          )
      );
      return issues;
    }

    if (conf.tlsConfig.isEnabled()) {
      conf.tlsConfig.init(
          context,
          Groups.SECURITY.name(),
          SSL_CONFIG_PREFIX,
          issues
      );
    }

    try {
      opcUaClient = createClient();
      opcUaClient.connect().get();
    } catch (Exception ex) {
      issues.add(
          context.createConfigIssue(
              Groups.OPC_UA.name(),
              "conf.resourceUrl",
              Errors.OPC_UA_02,
              ex.getLocalizedMessage()
          )
      );
    }

    if (conf.readMode != OpcUaReadMode.BROWSE_NODES) {
      initializeNodeIds(issues);
    }

    if (conf.nodeIdConfigs.isEmpty() && conf.readMode != OpcUaReadMode.BROWSE_NODES) {
      issues.add(
          context.createConfigIssue(
              Groups.NODE_IDS.name(),
              "conf.nodeIdConfigs",
              Errors.OPC_UA_03
          )
      );
    }

    return issues;
  }

  private OpcUaClient createClient() throws Exception {
    SecurityPolicy securityPolicy = conf.securityPolicy.getSecurityPolicy();

    EndpointDescription[] endpoints = UaTcpStackClient.getEndpoints(conf.resourceUrl).get();

    EndpointDescription endpoint = Arrays.stream(endpoints)
        .filter(e -> e.getSecurityPolicyUri().equals(securityPolicy.getSecurityPolicyUri()))
        .findFirst().orElseThrow(() -> new StageException(Errors.OPC_UA_01));

    ChannelConfig channelConfig = new ChannelConfig(
        conf.channelConf.maxChunkSize,
        conf.channelConf.maxChunkCount,
        conf.channelConf.maxMessageSize,
        conf.channelConf.maxArrayLength,
        conf.channelConf.maxStringLength
    );
    OpcUaClientConfigBuilder clientConfigBuilder = OpcUaClientConfig.builder()
        .setApplicationName(LocalizedText.english(conf.applicationName))
        .setApplicationUri(conf.applicationUri)
        .setChannelConfig(channelConfig);

    if (!securityPolicy.equals(SecurityPolicy.None)) {
      KeyStore keyStore = conf.tlsConfig.getKeyStore();
      if (keyStore != null) {
        Key clientPrivateKey = keyStore.getKey(conf.clientKeyAlias, conf.tlsConfig.keyStorePassword.get().toCharArray());
        if (clientPrivateKey instanceof PrivateKey) {
          X509Certificate clientCertificate = (X509Certificate) keyStore.getCertificate(conf.clientKeyAlias);
          PublicKey clientPublicKey = clientCertificate.getPublicKey();
          KeyPair clientKeyPair = new KeyPair(clientPublicKey, (PrivateKey) clientPrivateKey);
          clientConfigBuilder.setCertificate(clientCertificate)
              .setKeyPair(clientKeyPair);
        }
      }
    }

    OpcUaClientConfig config = clientConfigBuilder.setEndpoint(endpoint)
        .setIdentityProvider(new AnonymousProvider())
        .setRequestTimeout(uint(conf.requestTimeoutMillis))
        .setSessionTimeout(uint(conf.sessionTimeoutMillis))
        .build();

    return new OpcUaClient(config);
  }

  @Override
  public void produce(Map<String, String> map, int i) throws StageException {
    try {
      switch (conf.readMode) {
        case POLLING:
          pollForData();
          break;
        case SUBSCRIBE:
          subscribeForData();
          break;
        case BROWSE_NODES:
          browseNodes();
          dispatchReceiverErrors(0);
          return;
      }
      while (!context.isStopped()) {
        dispatchReceiverErrors(100);
      }

    } catch(Exception me) {
      throw new StageException(Errors.OPC_UA_02, me, me);
    }
  }

  private void initializeNodeIds(List<ConfigIssue> issues) {
    try {
      nodeIds = new ArrayList<>();

      if (this.conf.nodeIdFetchMode.equals(NodeIdFetchMode.BROWSE)) {
        rootNodeId = Identifiers.RootFolder;
        switch (conf.rootIdentifierType) {
          case NUMERIC:
            rootNodeId = new NodeId(conf.rootNamespaceIndex, Integer.parseInt(conf.rootIdentifier));
            break;
          case STRING:
            rootNodeId = new NodeId(conf.rootNamespaceIndex, conf.rootIdentifier);
            break;
          case UUID:
            rootNodeId = new NodeId(conf.rootNamespaceIndex, UUID.fromString(conf.rootIdentifier));
            break;
          case OPAQUE:
            rootNodeId = new NodeId(conf.rootNamespaceIndex, new ByteString(conf.rootIdentifier.getBytes()));
            break;
        }
        conf.nodeIdConfigs = new ArrayList<>();
        browseNode(rootNodeId, nodeIds, issues, new HashMap<>());
        if (nodeIds.isEmpty()) {
          issues.add(
              context.createConfigIssue(
                  Groups.NODE_IDS.name(),
                  "conf.rootIdentifier",
                  Errors.OPC_UA_07
              )
          );
        }

      } else {
        if (this.conf.nodeIdFetchMode.equals(NodeIdFetchMode.FILE)) {
          try {
            conf.nodeIdConfigs = Arrays.asList(
                OBJECT_MAPPER.readValue(this.conf.nodeIdConfigsFilePath,NodeIdConfig[].class)
            );
          } catch (Exception ex) {
            issues.add(context.createConfigIssue(
                Groups.NODE_IDS.name(),
                "conf.nodeIdConfigsFilePath",
                Errors.OPC_UA_04,
                ex.getLocalizedMessage()
            ));
            return;
          }
        }

        for (NodeIdConfig nodeIdConfig: conf.nodeIdConfigs) {
          if (this.conf.nodeIdFetchMode.equals(NodeIdFetchMode.FILE)) {
            if (Strings.isEmpty(nodeIdConfig.field) || Strings.isEmpty(nodeIdConfig.identifier)) {
              issues.add(context.createConfigIssue(
                  Groups.NODE_IDS.name(),
                  "conf.nodeIdConfigsFilePath",
                  Errors.OPC_UA_11,
                  nodeIdConfig
              ));
              break;
            }
          }
          switch (nodeIdConfig.identifierType) {
            case NUMERIC:
              nodeIds.add(new NodeId(nodeIdConfig.namespaceIndex, Integer.parseInt(nodeIdConfig.identifier)));
              break;
            case STRING:
              nodeIds.add(new NodeId(nodeIdConfig.namespaceIndex, nodeIdConfig.identifier));
              break;
            case UUID:
              nodeIds.add(new NodeId(nodeIdConfig.namespaceIndex, UUID.fromString(nodeIdConfig.identifier)));
              break;
            case OPAQUE:
              nodeIds.add(new NodeId(nodeIdConfig.namespaceIndex, new ByteString(nodeIdConfig.identifier.getBytes())));
              break;
          }
        }
      }
    } catch (Exception ex) {
      issues.add(
          context.createConfigIssue(
              Groups.NODE_IDS.name(),
              "conf.nodeIdConfigs",
              Errors.OPC_UA_04,
              ex.getLocalizedMessage()
          )
      );
    }
  }

  private void refreshNodeIds() {
    if (this.conf.nodeIdFetchMode.equals(NodeIdFetchMode.BROWSE)) {
      if (stopwatch == null) {
        stopwatch = Stopwatch.createStarted();
      } else if (stopwatch.elapsed(TimeUnit.SECONDS) > conf.refreshNodeIdsInterval) {
        try {
          List<NodeId> newNodeIds = new ArrayList<>();
          conf.nodeIdConfigs = new ArrayList<>();
          browseNode(rootNodeId, newNodeIds, new ArrayList<>(), new HashMap<>());
          if (!newNodeIds.isEmpty()) {
            nodeIds = newNodeIds;
          }
        } catch (Exception ex) {
          errorQueue.offer(new StageException(Errors.OPC_UA_08, ex.getMessage(), ex));
          reConnect();
        } finally {
          stopwatch.reset()
              .start();
        }
      }
    }
  }

  private void reConnect() {
    try {
      opcUaClient.disconnect().get(conf.requestTimeoutMillis, TimeUnit.MILLISECONDS);
      opcUaClient = createClient();
      opcUaClient.connect().get(conf.requestTimeoutMillis, TimeUnit.MILLISECONDS);
    } catch (Exception ex) {
      LOG.error(Errors.OPC_UA_02.getMessage(), ex.getMessage(), ex);
      errorQueue.offer(new StageException(Errors.OPC_UA_02, ex.getMessage(), ex));
    }
  }

  private void pollForData() {
    if (destroyed) {
      return;
    }
    refreshNodeIds();
    opcUaClient.readValues(0.0, TimestampsToReturn.Both, nodeIds)
        .thenAccept(values -> {
          try {
            process(values, System.currentTimeMillis() + "." + counter.getAndIncrement(), null);
          } catch (Exception ex) {
            LOG.error(Errors.OPC_UA_09.getMessage(), ex.getMessage(), ex);
            errorQueue.offer(new StageException(Errors.OPC_UA_09, ex.getMessage(), ex));
          }
          if (ThreadUtil.sleep(conf.pollingInterval)) {
            pollForData();
          }
        })
        .exceptionally(ex -> {
          LOG.warn(Errors.OPC_UA_12.getMessage(), ex.getMessage());
          errorQueue.offer(new StageException(Errors.OPC_UA_12, ex.getMessage(), ex));
          reConnect();
          if (ThreadUtil.sleep(conf.pollingInterval)) {
            pollForData();
          }
          return null;
        });
  }

  private void subscribeForData() {
    try {
      UaSubscription subscription = opcUaClient.getSubscriptionManager()
          .createSubscription(1000.0).get();

      List<MonitoredItemCreateRequest> monitoredItemCreateRequests = new ArrayList<>();
      nodeIds.forEach(nodeId -> {
        ReadValueId readValueId = new ReadValueId(
            nodeId,
            AttributeId.Value.uid(),
            null,
            QualifiedName.NULL_VALUE
        );

        UInteger clientHandle = uint(clientHandles.getAndIncrement());

        MonitoringParameters parameters = new MonitoringParameters(
            clientHandle,
            1000.0,     // sampling interval
            null,       // filter, null means use default
            uint(10),   // queue size
            true        // discard oldest
        );

        MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(
            readValueId, MonitoringMode.Reporting, parameters);

        monitoredItemCreateRequests.add(request);
      });

      BiConsumer<UaMonitoredItem, Integer> onItemCreated =
          (item, id) -> item.setValueConsumer(this::onSubscriptionValue);

      List<UaMonitoredItem> items = subscription.createMonitoredItems(
          TimestampsToReturn.Both,
          monitoredItemCreateRequests,
          onItemCreated
      ).get();

      for (UaMonitoredItem item : items) {
        if (item.getStatusCode().isGood()) {
          LOG.debug("item created for nodeId={}", item.getReadValueId().getNodeId());
        } else {
          LOG.error(Errors.OPC_UA_05.getMessage(), item.getReadValueId().getNodeId(), item.getStatusCode());
          errorQueue.offer(new StageException(Errors.OPC_UA_05, item.getReadValueId().getNodeId(), item.getStatusCode()));
        }
      }

    } catch (InterruptedException | ExecutionException ex) {
      errorQueue.offer(ex);
    }
  }

  private void onSubscriptionValue(UaMonitoredItem item, DataValue value) {
    LOG.debug("subscription value received: item={}, value={}", item.getReadValueId().getNodeId(), value.getValue());
    try {
      String fieldName = EscapeUtil.singleQuoteEscape(item.getReadValueId().getNodeId().getIdentifier().toString());
      process(ImmutableList.of(value), item.getReadValueId().getNodeId() + "." + counter.getAndIncrement(), fieldName);
    } catch (Exception ex) {
      LOG.error(Errors.OPC_UA_09.getMessage(), ex.getMessage(), ex);
      errorQueue.offer(new StageException(Errors.OPC_UA_09, ex.getMessage(), ex));
    }
  }

  private void process(List<DataValue> dataValues, String recordSourceId, String subscribeFieldName) {
    BatchContext batchContext = context.startBatch();
    Record record = context.createRecord(recordSourceId);
    record.set("/", Field.create(new LinkedHashMap<>()));

    int[] idx = { 0 };
    dataValues.forEach((dataValue) -> {
      String fieldName;

      if (conf.readMode.equals(OpcUaReadMode.SUBSCRIBE)) {
        fieldName = subscribeFieldName;
      } else {
        NodeIdConfig nodeIdConfig = conf.nodeIdConfigs.get(idx[0]++);
        fieldName = nodeIdConfig.field;
      }

      if (!fieldName.startsWith("/")) {
        fieldName = "/" + fieldName;
      }

      Field.Type fieldType = Field.Type.STRING;
      Object value = dataValue.getValue().getValue();
      Optional<NodeId> nodeIdOptional =  dataValue.getValue().getDataType();
      int typeId = 12; // default to string type
      if (nodeIdOptional.isPresent()) {
        UInteger identifier = (UInteger)nodeIdOptional.get().getIdentifier();
        typeId = identifier.intValue();
      }

      boolean isArray = false;
      Object [] arrValue = null;
      if (value != null && value.getClass().isArray()) {
        isArray = true;
        arrValue = (Object []) value;
        fieldType = Field.Type.LIST;
      }

      switch (typeId) {
        case 1: // Boolean
          if (isArray) {
            List<Field> boolFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              boolFieldList.add(Field.create(Field.Type.BOOLEAN, anArrValue));
            }
            value = boolFieldList;
          } else {
            fieldType = Field.Type.BOOLEAN;
          }
          break;
        case 2: // SByte
          if (isArray) {
            List<Field> sByteFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              sByteFieldList.add(Field.create(Field.Type.BYTE, anArrValue));
            }
            value = sByteFieldList;
          } else {
            fieldType = Field.Type.BYTE;
          }
          break;
        case 3: // Byte
          if (isArray) {
            List<Field> byteFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              if (anArrValue != null) {
                UByte uByte = (UByte) anArrValue;
                anArrValue = uByte.byteValue();
              }
              byteFieldList.add(Field.create(Field.Type.BYTE, anArrValue));
            }
            value = byteFieldList;
          } else {
            fieldType = Field.Type.BYTE;
            if (value != null) {
              UByte uByte = (UByte) value;
              value = uByte.byteValue();
            }
          }
          break;
        case 4: // Int16
          if (isArray) {
            List<Field> integerFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              integerFieldList.add(Field.create(Field.Type.INTEGER, anArrValue));
            }
            value = integerFieldList;
          } else {
            fieldType = Field.Type.INTEGER;
          }
          break;
        case 5: // UInt16
          if (isArray) {
            List<Field> integerFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              if (anArrValue != null) {
                UShort uShort = (UShort) anArrValue;
                anArrValue = uShort.intValue();
              }
              integerFieldList.add(Field.create(Field.Type.INTEGER, anArrValue));
            }
            value = integerFieldList;
          } else {
            fieldType = Field.Type.INTEGER;
            if (value != null) {
              UShort uShort = (UShort) value;
              value = uShort.intValue();
            }
          }
          break;
        case 6: // Int32
          if (isArray) {
            List<Field> integerFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              integerFieldList.add(Field.create(Field.Type.INTEGER, anArrValue));
            }
            value = integerFieldList;
          } else {
            fieldType = Field.Type.INTEGER;
          }

          break;
        case 7: // UInt32
          if (isArray) {
            List<Field> integerFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              if (anArrValue != null) {
                UInteger uInteger = (UInteger) anArrValue;
                anArrValue = uInteger.intValue();
              }
              integerFieldList.add(Field.create(Field.Type.INTEGER, anArrValue));
            }
            value = integerFieldList;
          } else {
            fieldType = Field.Type.INTEGER;
            if (value != null) {
              UInteger uInteger = (UInteger) value;
              value = uInteger.intValue();
            }
          }
          break;
        case 8: // Int64
          if (isArray) {
            List<Field> longFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              longFieldList.add(Field.create(Field.Type.LONG, anArrValue));
            }
            value = longFieldList;
          } else {
            fieldType = Field.Type.LONG;
          }
          break;
        case 9: // UInt64
          if (isArray) {
            List<Field> longFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              if (anArrValue != null) {
                ULong uLong = (ULong) anArrValue;
                anArrValue = uLong.longValue();
              }
              longFieldList.add(Field.create(Field.Type.LONG, anArrValue));
            }
            value = longFieldList;
          } else {
            fieldType = Field.Type.LONG;
            if (value != null) {
              ULong uLong = (ULong) value;
              value = uLong.longValue();
            }
          }
          break;
        case 10: // Float
          if (isArray) {
            List<Field> floatFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              floatFieldList.add(Field.create(Field.Type.FLOAT, anArrValue));
            }
            value = floatFieldList;
          } else {
            fieldType = Field.Type.FLOAT;
          }
          break;
        case 11: // Double
          if (isArray) {
            List<Field> doubleFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              doubleFieldList.add(Field.create(Field.Type.DOUBLE, anArrValue));
            }
            value = doubleFieldList;
          } else {
            fieldType = Field.Type.DOUBLE;
          }
          break;
        case 12: // String
          if (isArray) {
            List<Field> stringFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              stringFieldList.add(Field.create(Field.Type.STRING, anArrValue));
            }
            value = stringFieldList;
          } else {
            fieldType = Field.Type.STRING;
          }
          break;
        case 13: // DateTime
          if (isArray) {
            List<Field> dateTimeFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              if (anArrValue != null) {
                DateTime dateTime = (DateTime) anArrValue;
                anArrValue = dateTime.getJavaDate();
              }
              dateTimeFieldList.add(Field.create(Field.Type.DATETIME, anArrValue));
            }
            value = dateTimeFieldList;
          } else {
            fieldType = Field.Type.DATETIME;
            if (value != null) {
              DateTime dateTime = (DateTime) value;
              value = dateTime.getJavaDate();
            }
          }
          break;
        case 14: // Guid
          if (isArray) {
            List<Field> guidFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              if (anArrValue != null) {
                anArrValue = anArrValue.toString();
              }
              guidFieldList.add(Field.create(Field.Type.STRING, anArrValue));
            }
            value = guidFieldList;
          } else {
            fieldType = Field.Type.STRING;
            if (value != null) {
              value = value.toString();
            }
          }
          break;
        case 15: // ByteString
          if (isArray) {
            List<Field> byteStringFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              if (anArrValue != null) {
                ByteString byteString = (ByteString)anArrValue;
                anArrValue = byteString.bytes();
              }
              byteStringFieldList.add(Field.create(Field.Type.BYTE_ARRAY, anArrValue));
            }
            value = byteStringFieldList;
          } else {
            fieldType = Field.Type.BYTE_ARRAY;
            if (value != null) {
              ByteString byteString = (ByteString)value;
              value = byteString.bytes();
            }
          }
          break;
        default:
          if (isArray) {
            List<Field> stringFieldList = new ArrayList<>();
            for (Object anArrValue : arrValue) {
              stringFieldList.add(Field.create(Field.Type.STRING, anArrValue));
            }
            value = stringFieldList;
          } else {
            fieldType = Field.Type.STRING;
          }
      }

      LinkedHashMap<String, Field> valueMap = new LinkedHashMap<>();

      if (dataValue.getSourceTime() != null) {
        valueMap.put(SOURCE_TIME_FIELD_NAME, Field.createDatetime(dataValue.getSourceTime().getJavaDate()));
      } else {
        valueMap.put(SOURCE_TIME_FIELD_NAME, Field.create(Field.Type.LONG, null));
      }

      if (dataValue.getSourcePicoseconds() != null) {
        valueMap.put(SOURCE_PICO_SECONDS_FIELD_NAME, Field.create(dataValue.getSourcePicoseconds().longValue()));
      } else {
        valueMap.put(SOURCE_PICO_SECONDS_FIELD_NAME, Field.create(Field.Type.LONG, 0));
      }

      if (dataValue.getServerTime() != null) {
        valueMap.put(SERVER_TIME_FIELD_NAME, Field.createDatetime(dataValue.getServerTime().getJavaDate()));
      } else {
        valueMap.put(SERVER_TIME_FIELD_NAME, Field.create(Field.Type.LONG, null));
      }

      if (dataValue.getServerPicoseconds() != null) {
        valueMap.put(SERVER_PICO_SECONDS_FIELD_NAME, Field.create(dataValue.getServerPicoseconds().longValue()));
      } else {
        valueMap.put(SERVER_PICO_SECONDS_FIELD_NAME, Field.create(Field.Type.LONG, 0));
      }

      if (dataValue.getStatusCode() != null) {
        valueMap.put(STATUS_CODE_FIELD_NAME, Field.create(dataValue.getStatusCode().getValue()));
        StatusCodes.lookup(dataValue.getStatusCode().getValue()).ifPresent(
            nameAndDesc -> valueMap.put(STATUS_CODE_STR_FIELD_NAME, Field.create(nameAndDesc[0])));
      } else {
        valueMap.put(STATUS_CODE_FIELD_NAME, Field.create(Field.Type.LONG, null));
        valueMap.put(STATUS_CODE_STR_FIELD_NAME, Field.create(Field.Type.STRING, null));
      }

      valueMap.put(VALUE_FIELD_NAME, Field.create(fieldType, value));
      record.set(fieldName, Field.createListMap(valueMap));

    });

    batchContext.getBatchMaker().addRecord(record);
    context.processBatch(batchContext);
  }

  private void dispatchReceiverErrors(long intervalMillis) {
    if (intervalMillis > 0) {
      try {
        Thread.sleep(intervalMillis);
      } catch (InterruptedException ignored) {
      }
    }
    errorList.clear();
    errorQueue.drainTo(errorList);
    for (Exception exception : errorList) {
      context.reportError(exception);
    }
  }

  private void browseNode(
      NodeId browseRoot,
      List<NodeId> nodeIdList,
      List<ConfigIssue> issues,
      Map<String, Boolean> visitedMap
  ) {
    if (visitedMap.containsKey(browseRoot.getIdentifier().toString())) {
      return;
    }

    visitedMap.put(browseRoot.getIdentifier().toString(), true);

    BrowseDescription browse = new BrowseDescription(
        browseRoot,
        BrowseDirection.Forward,
        Identifiers.References,
        true,
        uint(NodeClass.Object.getValue() | NodeClass.Variable.getValue()),
        uint(BrowseResultMask.All.getValue())
    );
    try {
      BrowseResult browseResult = opcUaClient.browse(browse).get();
      List<ReferenceDescription> references = toList(browseResult.getReferences());

      for (ReferenceDescription rd : references) {
        if (visitedMap.containsKey(rd.getNodeId().getIdentifier().toString())) {
          continue;
        }

        if (rd.getNodeClass().equals(NodeClass.Variable)) {
          NodeId nodeId = null;
          NodeIdConfig nodeIdConfig = new NodeIdConfig();
          switch (rd.getNodeId().getType()) {
            case Numeric:
              nodeId = new NodeId(
                  rd.getNodeId().getNamespaceIndex().intValue(),
                  Integer.parseInt(rd.getNodeId().getIdentifier().toString())
              );
              nodeIdConfig.field = rd.getBrowseName().getName() + "_" + rd.getNodeId().getIdentifier().toString();
              break;
            case String:
              nodeId = new NodeId(
                  rd.getNodeId().getNamespaceIndex().intValue(),
                  rd.getNodeId().getIdentifier().toString()
              );
              nodeIdConfig.field = rd.getNodeId().getIdentifier().toString();
              break;
            case Guid:
              nodeId = new NodeId(
                  rd.getNodeId().getNamespaceIndex().intValue(),
                  UUID.fromString(rd.getNodeId().getIdentifier().toString())
              );
              nodeIdConfig.field = rd.getBrowseName().getName() + "_" + rd.getNodeId().getIdentifier().toString();
              break;
            case Opaque:
              nodeId = new NodeId(
                  rd.getNodeId().getNamespaceIndex().intValue(),
                  new ByteString(rd.getNodeId().getIdentifier().toString().getBytes())
              );
              nodeIdConfig.field = rd.getBrowseName().getName() + "_" + rd.getNodeId().getIdentifier().toString();
              break;
          }
          nodeIdList.add(nodeId);
          conf.nodeIdConfigs.add(nodeIdConfig);
        }

        rd.getNodeId().local().ifPresent(nodeId -> browseNode(nodeId, nodeIdList, issues, visitedMap));
      }
    } catch (InterruptedException | ExecutionException ex) {
      LOG.error("Browsing nodeId={} failed: {}", browseRoot, ex.getMessage(), ex);
      errorQueue.offer(new StageException(Errors.OPC_UA_08, ex.getMessage(), ex));
      issues.add(
          context.createConfigIssue(
              Groups.NODE_IDS.name(),
              "conf.rootIdentifier",
              Errors.OPC_UA_08,
              ex.getMessage()
          )
      );
    }
  }

  private void browseNodes() {
    LinkedHashMap<String, Field> rootFieldMap = new LinkedHashMap<>();
    Map<String, Boolean> visitedMap = new HashMap<>();
    browseNode(Identifiers.RootFolder, rootFieldMap, visitedMap);
    BatchContext batchContext = context.startBatch();
    String requestId = System.currentTimeMillis() + "." + counter.getAndIncrement();
    Record record = context.createRecord(requestId);
    record.set("/", Field.create(rootFieldMap));
    batchContext.getBatchMaker().addRecord(record);
    context.processBatch(batchContext);
  }

  private void browseNode(
      NodeId browseRoot,
      LinkedHashMap<String, Field> rootFieldMap,
      Map<String, Boolean> visitedMap
  ) {
    if (visitedMap.containsKey(browseRoot.getIdentifier().toString())) {
      return;
    }

    visitedMap.put(browseRoot.getIdentifier().toString(), true);

    BrowseDescription browse = new BrowseDescription(
        browseRoot,
        BrowseDirection.Forward,
        Identifiers.References,
        true,
        uint(NodeClass.Object.getValue() | NodeClass.Variable.getValue()),
        uint(BrowseResultMask.All.getValue())
    );

    try {
      BrowseResult browseResult = opcUaClient.browse(browse).get();
      List<ReferenceDescription> references = toList(browseResult.getReferences());

      for (ReferenceDescription rd : references) {
        if (visitedMap.containsKey(rd.getNodeId().getIdentifier().toString())) {
          continue;
        }
        LinkedHashMap<String, Field> fieldMap = new LinkedHashMap<>();
        fieldMap.put("name", Field.create(rd.getBrowseName().getName()));
        fieldMap.put("nameSpaceIndex", Field.create(rd.getNodeId().getNamespaceIndex().intValue()));
        fieldMap.put("identifierType", Field.create(rd.getNodeId().getType().name()));
        fieldMap.put("identifier", Field.create(rd.getNodeId().getIdentifier().toString()));

        // recursively browse to children
        rd.getNodeId().local().ifPresent(nodeId -> {
          if (!nodeId.equals(browseRoot)) {
            LinkedHashMap<String, Field> childrenMap = new LinkedHashMap<>();
            browseNode(nodeId, childrenMap, visitedMap);
            if (!childrenMap.isEmpty()) {
              fieldMap.put("children",  Field.create(childrenMap));
            }
          }
        });

        rootFieldMap.put(rd.getBrowseName().getName(), Field.create(fieldMap));
      }
    } catch (InterruptedException | ExecutionException ex) {
      LOG.error(Errors.OPC_UA_10.getMessage(), browseRoot, ex.getMessage(), ex);
      errorQueue.offer(new StageException(Errors.OPC_UA_10, browseRoot, ex.getMessage(), ex));
    }
  }

  @Override
  public void destroy() {
    if (opcUaClient != null) {
      try {
        destroyed = true;
        opcUaClient.disconnect().get();
      } catch (InterruptedException | ExecutionException ex) {
        LOG.error("Failed during OPC UA Client disconnect call: {}", ex.getMessage());
      }
    }
  }

}


text:
// Note: the class cannot be used for reading and writing at the same time.
#ifndef WEBRTC_MODULES_MEDIA_FILE_MEDIA_FILE_UTILITY_H_
#define WEBRTC_MODULES_MEDIA_FILE_MEDIA_FILE_UTILITY_H_

#include <stdio.h>

#include "webrtc/common_types.h"
#include "webrtc/modules/media_file/media_file_defines.h"

namespace webrtc {
class InStream;
class OutStream;

class ModuleFileUtility
{
public:

    ModuleFileUtility(const int32_t id);
    ~ModuleFileUtility();

    // Prepare for playing audio from stream.
    // startPointMs and stopPointMs, unless zero, specify what part of the file
    // should be read. From startPointMs ms to stopPointMs ms.
    int32_t InitWavReading(InStream& stream,
                           const uint32_t startPointMs = 0,
                           const uint32_t stopPointMs = 0);

    // Put 10-60ms of audio data from stream into the audioBuffer depending on
    // codec frame size. dataLengthInBytes indicates the size of audioBuffer.
    // The return value is the number of bytes written to audioBuffer.
    // Note: This API only play mono audio but can be used on file containing
    // audio with more channels (in which case the audio will be converted to
    // mono).
    int32_t ReadWavDataAsMono(InStream& stream, int8_t* audioBuffer,
                              const size_t dataLengthInBytes);

    // Put 10-60ms, depending on codec frame size, of audio data from file into
    // audioBufferLeft and audioBufferRight. The buffers contain the left and
    // right channel of played out stereo audio.
    // dataLengthInBytes  indicates the size of both audioBufferLeft and
    // audioBufferRight.
    // The return value is the number of bytes read for each buffer.
    // Note: This API can only be successfully called for WAV files with stereo
    // audio.
    int32_t ReadWavDataAsStereo(InStream& wav,
                                int8_t* audioBufferLeft,
                                int8_t* audioBufferRight,
                                const size_t bufferLength);

    // Prepare for recording audio to stream.
    // codecInst specifies the encoding of the audio data.
    // Note: codecInst.channels should be set to 2 for stereo (and 1 for
    // mono). Stereo is only supported for WAV files.
    int32_t InitWavWriting(OutStream& stream, const CodecInst& codecInst);

    // Write one audio frame, i.e. the bufferLength first bytes of audioBuffer,
    // to file. The audio frame size is determined by the codecInst.pacsize
    // parameter of the last sucessfull StartRecordingAudioFile(..) call.
    // The return value is the number of bytes written to audioBuffer.
    int32_t WriteWavData(OutStream& stream,
                         const int8_t* audioBuffer,
                         const size_t bufferLength);

    // Finalizes the WAV header so that it is correct if nothing more will be
    // written to stream.
    // Note: this API must be called before closing stream to ensure that the
    //       WAVE header is updated with the file size. Don't call this API
    //       if more samples are to be written to stream.
    int32_t UpdateWavHeader(OutStream& stream);

    // Prepare for playing audio from stream.
    // startPointMs and stopPointMs, unless zero, specify what part of the file
    // should be read. From startPointMs ms to stopPointMs ms.
    // freqInHz is the PCM sampling frequency.
    // NOTE, allowed frequencies are 8000, 16000 and 32000 (Hz)
    int32_t InitPCMReading(InStream& stream,
                           const uint32_t startPointMs = 0,
                           const uint32_t stopPointMs = 0,
                           const uint32_t freqInHz = 16000);

    // Put 10-60ms of audio data from stream into the audioBuffer depending on
    // codec frame size. dataLengthInBytes indicates the size of audioBuffer.
    // The return value is the number of bytes written to audioBuffer.
    int32_t ReadPCMData(InStream& stream, int8_t* audioBuffer,
                        const size_t dataLengthInBytes);

    // Prepare for recording audio to stream.
    // freqInHz is the PCM sampling frequency.
    // NOTE, allowed frequencies are 8000, 16000 and 32000 (Hz)
    int32_t InitPCMWriting(OutStream& stream, const uint32_t freqInHz = 16000);

    // Write one 10ms audio frame, i.e. the bufferLength first bytes of
    // audioBuffer, to file. The audio frame size is determined by the freqInHz
    // parameter of the last sucessfull InitPCMWriting(..) call.
    // The return value is the number of bytes written to audioBuffer.
    int32_t WritePCMData(OutStream& stream,
                         const int8_t* audioBuffer,
                         size_t bufferLength);

    // Prepare for playing audio from stream.
    // startPointMs and stopPointMs, unless zero, specify what part of the file
    // should be read. From startPointMs ms to stopPointMs ms.
    int32_t InitCompressedReading(InStream& stream,
                                  const uint32_t startPointMs = 0,
                                  const uint32_t stopPointMs = 0);

    // Put 10-60ms of audio data from stream into the audioBuffer depending on
    // codec frame size. dataLengthInBytes indicates the size of audioBuffer.
    // The return value is the number of bytes written to audioBuffer.
    int32_t ReadCompressedData(InStream& stream,
                               int8_t* audioBuffer,
                               const size_t dataLengthInBytes);

    // Prepare for recording audio to stream.
    // codecInst specifies the encoding of the audio data.
    int32_t InitCompressedWriting(OutStream& stream,
                                  const CodecInst& codecInst);

    // Write one audio frame, i.e. the bufferLength first bytes of audioBuffer,
    // to file. The audio frame size is determined by the codecInst.pacsize
    // parameter of the last sucessfull InitCompressedWriting(..) call.
    // The return value is the number of bytes written to stream.
    // Note: bufferLength must be exactly one frame.
    int32_t WriteCompressedData(OutStream& stream,
                                const int8_t* audioBuffer,
                                const size_t bufferLength);

    // Prepare for playing audio from stream.
    // codecInst specifies the encoding of the audio data.
    int32_t InitPreEncodedReading(InStream& stream,
                                  const CodecInst& codecInst);

    // Put 10-60ms of audio data from stream into the audioBuffer depending on
    // codec frame size. dataLengthInBytes indicates the size of audioBuffer.
    // The return value is the number of bytes written to audioBuffer.
    int32_t ReadPreEncodedData(InStream& stream,
                               int8_t* audioBuffer,
                               const size_t dataLengthInBytes);

    // Prepare for recording audio to stream.
    // codecInst specifies the encoding of the audio data.
    int32_t InitPreEncodedWriting(OutStream& stream,
                                  const CodecInst& codecInst);

    // Write one audio frame, i.e. the bufferLength first bytes of audioBuffer,
    // to stream. The audio frame size is determined by the codecInst.pacsize
    // parameter of the last sucessfull InitPreEncodedWriting(..) call.
   // The return value is the number of bytes written to stream.
    // Note: bufferLength must be exactly one frame.
    int32_t WritePreEncodedData(OutStream& stream,
                                const int8_t* inData,
                                const size_t dataLengthInBytes);

    // Set durationMs to the size of the file (in ms) specified by fileName.
    // freqInHz specifies the sampling frequency of the file.
    int32_t FileDurationMs(const char* fileName,
                           const FileFormats fileFormat,
                           const uint32_t freqInHz = 16000);

    // Return the number of ms that have been played so far.
    uint32_t PlayoutPositionMs();

    // Update codecInst according to the current audio codec being used for
    // reading or writing.
    int32_t codec_info(CodecInst& codecInst);

private:
    // Biggest WAV frame supported is 10 ms at 48kHz of 2 channel, 16 bit audio.
    static const size_t WAV_MAX_BUFFER_SIZE = 480 * 2 * 2;

    int32_t InitWavCodec(uint32_t samplesPerSec,
                         size_t channels,
                         uint32_t bitsPerSample,
                         uint32_t formatTag);

    // Parse the WAV header in stream.
    int32_t ReadWavHeader(InStream& stream);

    // Update the WAV header. freqInHz, bytesPerSample, channels, format,
    // lengthInBytes specify characterists of the audio data.
    // freqInHz is the sampling frequency. bytesPerSample is the sample size in
    // bytes. channels is the number of channels, e.g. 1 is mono and 2 is
    // stereo. format is the encode format (e.g. PCMU, PCMA, PCM etc).
    // lengthInBytes is the number of bytes the audio samples are using up.
    int32_t WriteWavHeader(OutStream& stream,
                           uint32_t freqInHz,
                           size_t bytesPerSample,
                           size_t channels,
                           uint32_t format,
                           size_t lengthInBytes);

    // Put dataLengthInBytes of audio data from stream into the audioBuffer.
    // The return value is the number of bytes written to audioBuffer.
    int32_t ReadWavData(InStream& stream, uint8_t* audioBuffer,
                        size_t dataLengthInBytes);

    // Update the current audio codec being used for reading or writing
    // according to codecInst.
    int32_t set_codec_info(const CodecInst& codecInst);

    struct WAVE_FMTINFO_header
    {
        int16_t formatTag;
        int16_t nChannels;
        int32_t nSamplesPerSec;
        int32_t nAvgBytesPerSec;
        int16_t nBlockAlign;
        int16_t nBitsPerSample;
    };
    // Identifiers for preencoded files.
    enum MediaFileUtility_CodecType
    {
        kCodecNoCodec  = 0,
        kCodecIsac,
        kCodecIsacSwb,
        kCodecIsacLc,
        kCodecL16_8Khz,
        kCodecL16_16kHz,
        kCodecL16_32Khz,
        kCodecPcmu,
        kCodecPcma,
        kCodecIlbc20Ms,
        kCodecIlbc30Ms,
        kCodecG722,
        kCodecG722_1_32Kbps,
        kCodecG722_1_24Kbps,
        kCodecG722_1_16Kbps,
        kCodecG722_1c_48,
        kCodecG722_1c_32,
        kCodecG722_1c_24,
        kCodecAmr,
        kCodecAmrWb,
        kCodecG729,
        kCodecG729_1,
        kCodecG726_40,
        kCodecG726_32,
        kCodecG726_24,
        kCodecG726_16,
        kCodecSpeex8Khz,
        kCodecSpeex16Khz
    };

    // TODO (hellner): why store multiple formats. Just store either codec_info_
    //                 or _wavFormatObj and supply conversion functions.
    WAVE_FMTINFO_header _wavFormatObj;
    size_t _dataSize;      // Chunk size if reading a WAV file
    // Number of bytes to read. I.e. frame size in bytes. May be multiple
    // chunks if reading WAV.
    size_t _readSizeBytes;

    int32_t _id;

    uint32_t _stopPointInMs;
    uint32_t _startPointInMs;
    uint32_t _playoutPositionMs;
    size_t _bytesWritten;

    CodecInst codec_info_;
    MediaFileUtility_CodecType _codecId;

    // The amount of bytes, on average, used for one audio sample.
    size_t _bytesPerSample;
    size_t _readPos;

    // Only reading or writing can be enabled, not both.
    bool _reading;
    bool _writing;

    // Scratch buffer used for turning stereo audio to mono.
    uint8_t _tempData[WAV_MAX_BUFFER_SIZE];
};
}  // namespace webrtc
#endif // WEBRTC_MODULES_MEDIA_FILE_MEDIA_FILE_UTILITY_H_

redpajama_set_name: RedPajamaGithub


text:
<?php

// Deletes all CSS classes and id's, except for those listed in the array below
function custom_wp_nav_menu($var, $item = null) {
	if(is_array($var)) {
		if(in_array('current_page_parent', $var) && is_object($item) && 'post_type' == $item->type && (is_single() && ! is_singular('post') || is_tax() || is_post_type_archive()) && $item->object_id == (int) get_option('page_for_posts')) {
			while (false !== $k = array_search('current_page_parent', $var))
				unset($var[ $k ]);
		}

		$var = array_intersect($var, array(
			// List of allowed menu classes
			// 'current_page_item',
			'current_page_parent',
			'current_page_ancestor',
			'current-menu-item',
			'first',
			'last',
			'vertical',
			'horizontal'
			)
		);
	} else {
		$var = '';
	}

	return $var;
}

add_filter('nav_menu_css_class', 'custom_wp_nav_menu', 10, 2);
add_filter('nav_menu_item_id', 'custom_wp_nav_menu');
add_filter('page_css_class', 'custom_wp_nav_menu');

// Replaces "current-menu-item" with "active"
function current_to_active($text){

	$replace = array(
		// List of menu item classes that should be changed to "active"
		// 'current_page_item' => 'active-page',
		'current_page_parent' => 'parent-active',
		// 'current_page_ancestor' => 'active',
		'current-menu-item' => 'active'
	);

	$text = str_replace(array_keys($replace), $replace, $text);
	return $text;
}

add_filter ('wp_nav_menu','current_to_active');

// Removes empty classes and removes the sub menu class
function strip_empty_classes($menu){

	$menu = preg_replace('/ class=""| class="sub-menu"/','',$menu);
	return $menu;

}

add_filter ('wp_nav_menu','strip_empty_classes');

/**
 * Update options from wp_nav_menu to
 * output cleanest markup possible
 * @param  string $location Theme location of menu required
 * @return string           Markup of menu
 */
function clean_nav_menu($location, $class = null) {

	if($class != null) {
		$items_wrap = '
%3$s
';
	} else {
		$items_wrap = '
%3$s
';
	}

	$args = array(
		'theme_location'  => $location,
		'menu'            => '',
		'container'       => '',
		'container_class' => '',
		'container_id'    => '',
		'menu_class'      => '',
		'menu_id'         => '',
		'items_wrap'      => $items_wrap
	);

	echo wp_nav_menu($args);
}

/**
 * Return raw list of links from a
 * wp_nav_menu by passing theme location
 * @param  string $location Name of the menu
 * @return string           List of anchor tags
 */
function menu_item_links($location, $list_items = true) {
	if(($locations = get_nav_menu_locations()) && isset($locations[$location])) {
		$menu = wp_get_nav_menu_object($locations[$location]);
		$menu_items = wp_get_nav_menu_items($menu->term_id);

		foreach((array) $menu_items as $key => $menu_item) {
			$url = $menu_item->url;
			$title = $menu_item->title;
			if($list_items) { echo '
'; }
			echo ''. $title .'' ."\n";
			if($list_items) { echo '
'; }
		}
	}
}


text:
/**
 * \file hash_table.h
 * \brief Implementation of a generic, opaque hash table data type.
 *
 * \author Ian Romanick <ian.d.romanick@intel.com>
 */

#ifndef HASH_TABLE_H
#define HASH_TABLE_H

struct hash_table;

typedef unsigned (*hash_func_t)(const void *key);
typedef int (*hash_compare_func_t)(const void *key1, const void *key2);

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Hash table constructor
 *
 * Creates a hash table with the specified number of buckets.  The supplied
 * \c hash and \c compare routines are used when adding elements to the table
 * and when searching for elements in the table.
 *
 * \param num_buckets  Number of buckets (bins) in the hash table.
 * \param hash         Function used to compute hash value of input keys.
 * \param compare      Function used to compare keys.
 */
extern struct hash_table *hash_table_ctor(unsigned num_buckets,
    hash_func_t hash, hash_compare_func_t compare);

/**
 * Release all memory associated with a hash table
 *
 * \warning
 * This function cannot release memory occupied either by keys or data.
 */
extern void hash_table_dtor(struct hash_table *ht);

/**
 * Flush all entries from a hash table
 *
 * \param ht  Table to be cleared of its entries.
 */
extern void hash_table_clear(struct hash_table *ht);

/**
 * Search a hash table for a specific element
 *
 * \param ht   Table to be searched
 * \param key  Key of the desired element
 *
 * \return
 * The \c data value supplied to \c hash_table_insert when the element with
 * the matching key was added.  If no matching key exists in the table,
 * \c NULL is returned.
 */
extern void *hash_table_find(struct hash_table *ht, const void *key);

/**
 * Add an element to a hash table
 */
extern void hash_table_insert(struct hash_table *ht, void *data,
    const void *key);

/**
 * Remove a specific element from a hash table.
 */
extern void hash_table_remove(struct hash_table *ht, const void *key);

/**
 * Compute hash value of a string
 *
 * Computes the hash value of a string using the DJB2 algorithm developed by
 * Professor Daniel J. Bernstein.  It was published on comp.lang.c once upon
 * a time.  I was unable to find the original posting in the archives.
 *
 * \param key  Pointer to a NUL terminated string to be hashed.
 *
 * \sa hash_table_string_compare
 */
extern unsigned hash_table_string_hash(const void *key);

/**
 * Compare two strings used as keys
 *
 * This is just a macro wrapper around \c strcmp.
 *
 * \sa hash_table_string_hash
 */
#define hash_table_string_compare ((hash_compare_func_t) strcmp)

/**
 * Compute hash value of a pointer
 *
 * \param key  Pointer to be used as a hash key
 *
 * \note
 * The memory pointed to by \c key is \b never accessed.  The value of \c key
 * itself is used as the hash key
 *
 * \sa hash_table_pointer_compare
 */
unsigned
hash_table_pointer_hash(const void *key);

/**
 * Compare two pointers used as keys
 *
 * \sa hash_table_pointer_hash
 */
int
hash_table_pointer_compare(const void *key1, const void *key2);

void
hash_table_call_foreach(struct hash_table *ht,
			void (*callback)(const void *key,
					 void *data,
					 void *closure),
			void *closure);

#ifdef __cplusplus
}
#endif
#endif /* HASH_TABLE_H */


text:
from PyQt4.QtGui import *

from Action import *
import stellarya

class QuitAction(Action):

    def __init__(self):
        Action.__init__(self)

        style = stellarya._.app.style()
        self.setText("&Ouit")
        self.setIconText("Ouit")
        self.setToolTip("Quit")

    def __call__(self):
        stellarya._.app.quit()


text:
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.git.receive;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.gerrit.server.change.ReviewerModifier.newReviewerInputFromCommitIdentity;
import static com.google.gerrit.server.mail.MailUtil.getRecipientsFromFooters;
import static com.google.gerrit.server.mail.MailUtil.getRecipientsFromReviewers;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import static com.google.gerrit.server.project.ProjectCache.illegalState;
import static java.util.stream.Collectors.joining;
import static org.eclipse.jgit.lib.Constants.R_HEADS;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.PatchSetApproval;
import com.google.gerrit.entities.PatchSetInfo;
import com.google.gerrit.entities.SubmissionId;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.api.changes.ReviewerInput;
import com.google.gerrit.extensions.client.ChangeKind;
import com.google.gerrit.extensions.client.ReviewerState;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.approval.ApprovalCopier;
import com.google.gerrit.server.approval.ApprovalsUtil;
import com.google.gerrit.server.change.ChangeKindCache;
import com.google.gerrit.server.change.EmailNewPatchSet;
import com.google.gerrit.server.change.NotifyResolver;
import com.google.gerrit.server.change.ReviewerModifier;
import com.google.gerrit.server.change.ReviewerModifier.InternalReviewerInput;
import com.google.gerrit.server.change.ReviewerModifier.ReviewerModification;
import com.google.gerrit.server.change.ReviewerModifier.ReviewerModificationList;
import com.google.gerrit.server.change.ReviewerOp;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.extensions.events.CommentAdded;
import com.google.gerrit.server.extensions.events.RevisionCreated;
import com.google.gerrit.server.git.MergedByPushOp;
import com.google.gerrit.server.git.receive.ReceiveCommits.MagicBranchInput;
import com.google.gerrit.server.mail.MailUtil.MailRecipients;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.Context;
import com.google.gerrit.server.update.PostUpdateContext;
import com.google.gerrit.server.update.RepoContext;
import com.google.gerrit.server.util.LabelVote;
import com.google.gerrit.server.util.RequestScopePropagator;
import com.google.gerrit.server.validators.ValidationException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.util.Providers;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.PushCertificate;
import org.eclipse.jgit.transport.ReceiveCommand;

public class ReplaceOp implements BatchUpdateOp {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  public interface Factory {
    ReplaceOp create(
        ProjectState projectState,
        Change change,
        boolean checkMergedInto,
        @Nullable String mergeResultRevId,
        @Assisted("priorPatchSetId") PatchSet.Id priorPatchSetId,
        @Assisted("priorCommitId") ObjectId priorCommit,
        @Assisted("patchSetId") PatchSet.Id patchSetId,
        @Assisted("commitId") ObjectId commitId,
        PatchSetInfo info,
        List<String> groups,
        @Nullable MagicBranchInput magicBranch,
        @Nullable PushCertificate pushCertificate,
        RequestScopePropagator requestScopePropagator);
  }

  private static final String CHANGE_IS_CLOSED = "change is closed";

  private final AccountCache accountCache;
  private final AccountResolver accountResolver;
  private final String anonymousCowardName;
  private final ApprovalsUtil approvalsUtil;
  private final ChangeData.Factory changeDataFactory;
  private final ChangeKindCache changeKindCache;
  private final ChangeMessagesUtil cmUtil;
  private final EmailNewPatchSet.Factory emailNewPatchSetFactory;
  private final RevisionCreated revisionCreated;
  private final CommentAdded commentAdded;
  private final MergedByPushOp.Factory mergedByPushOpFactory;
  private final PatchSetUtil psUtil;
  private final ProjectCache projectCache;
  private final ReviewerModifier reviewerModifier;
  private final DynamicItem<UrlFormatter> urlFormatter;

  private final ProjectState projectState;
  private final Change change;
  private final boolean checkMergedInto;
  private final String mergeResultRevId;
  private final PatchSet.Id priorPatchSetId;
  private final ObjectId priorCommitId;
  private final PatchSet.Id patchSetId;
  private final ObjectId commitId;
  private final PatchSetInfo info;
  private final MagicBranchInput magicBranch;
  private final PushCertificate pushCertificate;
  private final RequestScopePropagator requestScopePropagator;
  private List<String> groups;

  private final Map<String, Short> approvals = new HashMap<>();
  private RevCommit commit;
  private ReceiveCommand cmd;
  private ChangeNotes notes;
  private PatchSet newPatchSet;
  private ChangeKind changeKind;
  private String mailMessage;
  private ApprovalCopier.Result approvalCopierResult;
  private String rejectMessage;
  private MergedByPushOp mergedByPushOp;
  private ReviewerModificationList reviewerAdditions;
  private MailRecipients oldRecipients;

  @Inject
  ReplaceOp(
      AccountCache accountCache,
      AccountResolver accountResolver,
      @AnonymousCowardName String anonymousCowardName,
      ApprovalsUtil approvalsUtil,
      ChangeData.Factory changeDataFactory,
      ChangeKindCache changeKindCache,
      ChangeMessagesUtil cmUtil,
      RevisionCreated revisionCreated,
      CommentAdded commentAdded,
      MergedByPushOp.Factory mergedByPushOpFactory,
      PatchSetUtil psUtil,
      ProjectCache projectCache,
      EmailNewPatchSet.Factory emailNewPatchSetFactory,
      ReviewerModifier reviewerModifier,
      DynamicItem<UrlFormatter> urlFormatter,
      @Assisted ProjectState projectState,
      @Assisted Change change,
      @Assisted boolean checkMergedInto,
      @Assisted @Nullable String mergeResultRevId,
      @Assisted("priorPatchSetId") PatchSet.Id priorPatchSetId,
      @Assisted("priorCommitId") ObjectId priorCommitId,
      @Assisted("patchSetId") PatchSet.Id patchSetId,
      @Assisted("commitId") ObjectId commitId,
      @Assisted PatchSetInfo info,
      @Assisted List<String> groups,
      @Assisted @Nullable MagicBranchInput magicBranch,
      @Assisted @Nullable PushCertificate pushCertificate,
      @Assisted RequestScopePropagator requestScopePropagator) {
    this.accountCache = accountCache;
    this.accountResolver = accountResolver;
    this.anonymousCowardName = anonymousCowardName;
    this.approvalsUtil = approvalsUtil;
    this.changeDataFactory = changeDataFactory;
    this.changeKindCache = changeKindCache;
    this.cmUtil = cmUtil;
    this.revisionCreated = revisionCreated;
    this.commentAdded = commentAdded;
    this.mergedByPushOpFactory = mergedByPushOpFactory;
    this.psUtil = psUtil;
    this.projectCache = projectCache;
    this.emailNewPatchSetFactory = emailNewPatchSetFactory;
    this.reviewerModifier = reviewerModifier;
    this.urlFormatter = urlFormatter;

    this.projectState = projectState;
    this.change = change;
    this.checkMergedInto = checkMergedInto;
    this.mergeResultRevId = mergeResultRevId;
    this.priorPatchSetId = priorPatchSetId;
    this.priorCommitId = priorCommitId.copy();
    this.patchSetId = patchSetId;
    this.commitId = commitId.copy();
    this.info = info;
    this.groups = groups;
    this.magicBranch = magicBranch;
    this.pushCertificate = pushCertificate;
    this.requestScopePropagator = requestScopePropagator;
  }

  @Override
  public void updateRepo(RepoContext ctx) throws Exception {
    commit = ctx.getRevWalk().parseCommit(commitId);
    ctx.getRevWalk().parseBody(commit);
    changeKind =
        changeKindCache.getChangeKind(
            projectState.getNameKey(),
            ctx.getRevWalk(),
            ctx.getRepoView().getConfig(),
            priorCommitId,
            commitId);

    if (checkMergedInto) {
      String mergedInto = findMergedInto(ctx, change.getDest().branch(), commit);
      if (mergedInto != null) {
        mergedByPushOp =
            mergedByPushOpFactory.create(
                requestScopePropagator,
                patchSetId,
                new SubmissionId(change),
                mergedInto,
                mergeResultRevId);
      }
    }

    cmd = new ReceiveCommand(ObjectId.zeroId(), commitId, patchSetId.toRefName());
    ctx.addRefUpdate(cmd);
  }

  @Override
  public boolean updateChange(ChangeContext ctx)
      throws RestApiException, IOException, PermissionBackendException, ConfigInvalidException,
          ValidationException {
    notes = ctx.getNotes();
    Change change = notes.getChange();
    if (change == null || change.isClosed()) {
      rejectMessage = CHANGE_IS_CLOSED;
      return false;
    }
    if (groups.isEmpty()) {
      PatchSet prevPs = psUtil.current(notes);
      groups = prevPs != null ? prevPs.groups() : ImmutableList.of();
    }

    ChangeData cd = changeDataFactory.create(ctx.getNotes());
    oldRecipients = getRecipientsFromReviewers(cd.reviewers());

    ChangeUpdate update = ctx.getUpdate(patchSetId);
    update.setSubjectForCommit("Create patch set " + patchSetId.get());

    String reviewMessage = null;
    String psDescription = null;
    if (magicBranch != null) {
      reviewMessage = magicBranch.message;
      psDescription = magicBranch.message;
      approvals.putAll(magicBranch.labels);
      Set<String> hashtags = magicBranch.hashtags;
      if (hashtags != null && !hashtags.isEmpty()) {
        hashtags.addAll(notes.getHashtags());
        update.setHashtags(hashtags);
      }
      if (magicBranch.topic != null && !magicBranch.topic.equals(ctx.getChange().getTopic())) {
        try {
          update.setTopic(magicBranch.topic);
        } catch (ValidationException ex) {
          throw new BadRequestException(ex.getMessage());
        }
      }
      if (magicBranch.removePrivate) {
        change.setPrivate(false);
        update.setPrivate(false);
      } else if (magicBranch.isPrivate) {
        change.setPrivate(true);
        update.setPrivate(true);
      }
      if (magicBranch.ready) {
        change.setWorkInProgress(false);
        change.setReviewStarted(true);
        update.setWorkInProgress(false);
      } else if (magicBranch.workInProgress) {
        change.setWorkInProgress(true);
        update.setWorkInProgress(true);
      }
      if (magicBranch.ignoreAttentionSet) {
        update.ignoreFurtherAttentionSetUpdates();
      }
    }

    newPatchSet =
        psUtil.insert(
            ctx.getRevWalk(),
            update,
            patchSetId,
            commitId,
            groups,
            pushCertificate != null ? pushCertificate.toTextWithSignature() : null,
            psDescription);

    update.setPsDescription(psDescription);
    MailRecipients fromFooters = getRecipientsFromFooters(accountResolver, commit.getFooterLines());
    approvalsUtil.addApprovalsForNewPatchSet(
        update, projectState.getLabelTypes(), newPatchSet, ctx.getUser(), approvals);

    reviewerAdditions =
        reviewerModifier.prepare(
            ctx.getNotes(),
            ctx.getUser(),
            getReviewerInputs(magicBranch, fromFooters, ctx.getChange(), info),
            true);
    Optional<ReviewerModification> reviewerError =
        reviewerAdditions.getFailures().stream().findFirst();
    if (reviewerError.isPresent()) {
      throw new UnprocessableEntityException(reviewerError.get().result.error);
    }
    reviewerAdditions.updateChange(ctx, newPatchSet);

    // Check if approvals are changing with this update. If so, add the current user (aka the
    // approver) as a reviewers because all approvers must also be reviewers.
    // Note that this is done separately as addReviewers is filtering out the change owner as a
    // reviewer which is needed in several other code paths.
    if (magicBranch != null && !magicBranch.labels.isEmpty()) {
      update.putReviewer(ctx.getAccountId(), REVIEWER);
    }

    approvalCopierResult =
        approvalsUtil.copyApprovalsToNewPatchSet(
            ctx.getNotes(), newPatchSet, ctx.getRevWalk(), ctx.getRepoView().getConfig(), update);

    mailMessage = insertChangeMessage(update, ctx, reviewMessage);
    if (mergedByPushOp == null) {
      resetChange(ctx);
    } else {
      mergedByPushOp.setPatchSetProvider(Providers.of(newPatchSet)).updateChange(ctx);
    }

    return true;
  }

  private ImmutableList<ReviewerInput> getReviewerInputs(
      @Nullable MagicBranchInput magicBranch,
      MailRecipients fromFooters,
      Change change,
      PatchSetInfo psInfo) {
    // Disable individual emails when adding reviewers, as all reviewers will receive the single
    // bulk new change email.
    Stream<ReviewerInput> inputs =
        Streams.concat(
            Streams.stream(
                newReviewerInputFromCommitIdentity(
                    change,
                    psInfo.getCommitId(),
                    psInfo.getAuthor().getAccount(),
                    NotifyHandling.NONE,
                    newPatchSet.uploader())),
            Streams.stream(
                newReviewerInputFromCommitIdentity(
                    change,
                    psInfo.getCommitId(),
                    psInfo.getCommitter().getAccount(),
                    NotifyHandling.NONE,
                    newPatchSet.uploader())));
    if (magicBranch != null) {
      inputs =
          Streams.concat(
              inputs,
              magicBranch.getCombinedReviewers(fromFooters).stream()
                  .map(r -> newReviewerInput(r, ReviewerState.REVIEWER)),
              magicBranch.getCombinedCcs(fromFooters).stream()
                  .map(r -> newReviewerInput(r, ReviewerState.CC)));
    }
    return inputs.collect(toImmutableList());
  }

  private static InternalReviewerInput newReviewerInput(String reviewer, ReviewerState state) {
    // Disable individual emails when adding reviewers, as all reviewers will receive the single
    // bulk new patch set email.
    InternalReviewerInput input =
        ReviewerModifier.newReviewerInput(reviewer, state, NotifyHandling.NONE);

    // Ignore failures for reasons like the reviewer being inactive or being unable to see the
    // change. See discussion in ChangeInserter.
    input.otherFailureBehavior = ReviewerModifier.FailureBehavior.IGNORE_EXCEPT_NOT_FOUND;

    return input;
  }

  private String insertChangeMessage(ChangeUpdate update, ChangeContext ctx, String reviewMessage) {
    String approvalMessage =
        ApprovalsUtil.renderMessageWithApprovals(
            patchSetId.get(), approvals, scanLabels(ctx, approvals));
    String kindMessage = changeKindMessage(changeKind);
    StringBuilder message = new StringBuilder(approvalMessage);
    if (!Strings.isNullOrEmpty(kindMessage)) {
      message.append(kindMessage);
    } else {
      message.append('.');
    }
    if (!Strings.isNullOrEmpty(reviewMessage)) {
      message.append("\n\n").append(reviewMessage);
    }
    approvalsUtil
        .formatApprovalCopierResult(approvalCopierResult, projectState.getLabelTypes())
        .ifPresent(
            msg -> {
              if (Strings.isNullOrEmpty(reviewMessage) || !reviewMessage.endsWith("\n")) {
                message.append("\n");
              }
              message.append("\n").append(msg);
            });
    boolean workInProgress = ctx.getChange().isWorkInProgress();
    if (magicBranch != null && magicBranch.workInProgress) {
      workInProgress = true;
    }
    return cmUtil.setChangeMessage(
        update, message.toString(), ChangeMessagesUtil.uploadedPatchSetTag(workInProgress));
  }

  @Nullable
  private String changeKindMessage(ChangeKind changeKind) {
    switch (changeKind) {
      case MERGE_FIRST_PARENT_UPDATE:
        return ": New merge patch set was added with a new first parent relative to Patch Set "
            + priorPatchSetId.get()
            + ".";
      case TRIVIAL_REBASE:
        return ": Patch Set " + priorPatchSetId.get() + " was rebased.";
      case NO_CHANGE:
        return ": New patch set was added with same tree, parent "
            + (commit.getParentCount() != 1 ? "trees" : "tree")
            + ", and commit message as Patch Set "
            + priorPatchSetId.get()
            + ".";
      case NO_CODE_CHANGE:
        return ": Commit message was updated.";
      case REWORK:
      default:
        return null;
    }
  }

  private Map<String, PatchSetApproval> scanLabels(
      ChangeContext ctx, Map<String, Short> approvals) {
    Map<String, PatchSetApproval> current = new HashMap<>();
    // We optimize here and only retrieve current when approvals provided
    if (!approvals.isEmpty()) {
      for (PatchSetApproval a :
          approvalsUtil.byPatchSetUser(ctx.getNotes(), priorPatchSetId, ctx.getAccountId())) {
        if (a.isLegacySubmit()) {
          continue;
        }

        projectState
            .getLabelTypes()
            .byLabel(a.labelId())
            .ifPresent(l -> current.put(l.getName(), a));
      }
    }
    return current;
  }

  private void resetChange(ChangeContext ctx) {
    Change change = ctx.getChange();
    if (!change.currentPatchSetId().equals(priorPatchSetId)) {
      return;
    }

    if (magicBranch != null && magicBranch.topic != null) {
      change.setTopic(magicBranch.topic);
    }
    change.setStatus(Change.Status.NEW);
    change.setCurrentPatchSet(info);

    List<String> idList = ChangeUtil.getChangeIdsFromFooter(commit, urlFormatter.get());
    change.setKey(Change.key(idList.get(idList.size() - 1).trim()));
  }

  @Override
  public void postUpdate(PostUpdateContext ctx) throws Exception {
    reviewerAdditions.postUpdate(ctx);

    // TODO(dborowitz): Merge email templates so we only have to send one.
    emailNewPatchSetFactory
        .create(
            ctx,
            newPatchSet,
            mailMessage,
            approvalCopierResult.outdatedApprovals().stream()
                .map(ApprovalCopier.Result.PatchSetApprovalData::patchSetApproval)
                .collect(toImmutableSet()),
            Streams.concat(
                    oldRecipients.getReviewers().stream(),
                    reviewerAdditions.flattenResults(ReviewerOp.Result::addedReviewers).stream()
                        .map(PatchSetApproval::accountId))
                .collect(toImmutableSet()),
            Streams.concat(
                    oldRecipients.getCcOnly().stream(),
                    reviewerAdditions.flattenResults(ReviewerOp.Result::addedCCs).stream())
                .collect(toImmutableSet()),
            changeKind,
            notes.getMetaId())
        .setRequestScopePropagator(requestScopePropagator)
        .sendAsync();

    NotifyResolver.Result notify = ctx.getNotify(notes.getChangeId());
    revisionCreated.fire(
        ctx.getChangeData(notes), newPatchSet, ctx.getAccount(), ctx.getWhen(), notify);
    try {
      fireApprovalsEvent(ctx);
    } catch (Exception e) {
      logger.atWarning().withCause(e).log("comment-added event invocation failed");
    }
    if (mergedByPushOp != null) {
      mergedByPushOp.postUpdate(ctx);
    }
  }

  private void fireApprovalsEvent(PostUpdateContext ctx) {
    if (approvals.isEmpty()) {
      return;
    }
    /* For labels that are not set in this operation, show the "current" value
     * of 0, and no oldValue as the value was not modified by this operation.
     * For labels that are set in this operation, the value was modified, so
     * show a transition from an oldValue of 0 to the new value.
     */
    List<LabelType> labels =
        projectCache
            .get(ctx.getProject())
            .orElseThrow(illegalState(ctx.getProject()))
            .getLabelTypes(notes)
            .getLabelTypes();
    Map<String, Short> allApprovals = new HashMap<>();
    Map<String, Short> oldApprovals = new HashMap<>();
    for (LabelType lt : labels) {
      allApprovals.put(lt.getName(), (short) 0);
      oldApprovals.put(lt.getName(), null);
    }
    for (Map.Entry<String, Short> entry : approvals.entrySet()) {
      if (entry.getValue() != 0) {
        allApprovals.put(entry.getKey(), entry.getValue());
        oldApprovals.put(entry.getKey(), (short) 0);
      }
    }
    commentAdded.fire(
        ctx.getChangeData(notes),
        newPatchSet,
        ctx.getAccount(),
        null,
        allApprovals,
        oldApprovals,
        ctx.getWhen());
  }

  public PatchSet getPatchSet() {
    return newPatchSet;
  }

  public Change getChange() {
    return notes.getChange();
  }

  public String getRejectMessage() {
    return rejectMessage;
  }

  public Optional<String> getOutdatedApprovalsMessage() {
    if (approvalCopierResult == null || approvalCopierResult.outdatedApprovals().isEmpty()) {
      return Optional.empty();
    }

    return Optional.of(
        "The following approvals got outdated and were removed:\n"
            + approvalCopierResult.outdatedApprovals().stream()
                .map(ApprovalCopier.Result.PatchSetApprovalData::patchSetApproval)
                .map(
                    outdatedApproval ->
                        String.format(
                            "* %s by %s",
                            LabelVote.create(outdatedApproval.label(), outdatedApproval.value())
                                .format(),
                            getNameFor(outdatedApproval.accountId())))
                .sorted()
                .collect(joining("\n")));
  }

  private String getNameFor(Account.Id accountId) {
    Optional<Account> account = accountCache.get(accountId).map(AccountState::account);
    String name = null;
    if (account.isPresent()) {
      name = account.get().fullName();
      if (name == null) {
        name = account.get().preferredEmail();
      }
    }
    if (name == null) {
      name = anonymousCowardName + " #" + accountId;
    }
    return name;
  }

  public ReceiveCommand getCommand() {
    return cmd;
  }

  @Nullable
  private static String findMergedInto(Context ctx, String first, RevCommit commit) {
    try {
      RevWalk rw = ctx.getRevWalk();
      Optional<ObjectId> firstId = ctx.getRepoView().getRef(first);
      if (firstId.isPresent() && rw.isMergedInto(commit, rw.parseCommit(firstId.get()))) {
        return first;
      }

      for (Map.Entry<String, ObjectId> e : ctx.getRepoView().getRefs(R_HEADS).entrySet()) {
        if (rw.isMergedInto(commit, rw.parseCommit(e.getValue()))) {
          return R_HEADS + e.getKey();
        }
      }
      return null;
    } catch (IOException e) {
      logger.atWarning().withCause(e).log("Can't check for already submitted change");
      return null;
    }
  }
}


text:
'''
Created on Dec 2, 2015

@author: Francis King
'''
import pygame, random

class Collectable():
    def __init__(self, surface):
        self.xPos = random.randint(0,320)
        self.yPos = random.randint(0,240)
        self.color = (0, 255, 0)
        self.sideLength = 15
        self.surface = surface
        self.isHit = False
        pygame.draw.rect(surface, self.color, [self.xPos, self.yPos, self.sideLength, self.sideLength], 0)

    def redraw(self):
        pygame.draw.rect(self.surface, self.color, [self.xPos, self.yPos, self.sideLength, self.sideLength], 0)

    def checkIfPlayerTouched(self, player):
        if self.xPos < player.xPos + player.sideLength and self.xPos + self.sideLength > player.xPos and self.yPos < player.yPos + player.sideLength and self.yPos + self.sideLength > player.yPos:
            self.isHit = True
            player.sideLength += 5


text:
import { todosTypes } from '../constants'

export default {
  fetchTodosRequest,
  setTodos,
  fetchTodosFailure,
  createTodoRequest,
  setTodo,
  createTodoFailure,
  updateTodoRequest,
  updateTodo,
  updateTodoFailure,
  deleteTodoRequest,
  deleteTodo,
  deleteTodoFailure,
  selectTodo,
  toggleAllTodosRequest,
  toggleAllTodos,
  toggleAllTodosFailure,
  deleteAllTodosRequest,
  deleteAllTodos,
  deleteAllTodosFailure
}

export function fetchTodosRequest() {
  return {
    type: todosTypes.FETCH_TODOS_REQUEST
  }
}

export function setTodos(todos) {
  return {
    type: todosTypes.FETCH_TODOS_SUCCESS,
    payload: {
      todos
    }
  }
}

export function fetchTodosFailure() {
  return {
    type: todosTypes.FETCH_TODOS_FAILURE
  }
}

export function createTodoRequest(todo) {
  return {
    type: todosTypes.CREATE_TODO_REQUEST,
    payload: {
      todo
    }
  }
}

export function setTodo(todo) {
  return {
    type: todosTypes.CREATE_TODO_SUCCESS,
    payload: {
      todo
    }
  }
}

export function createTodoFailure() {
  return {
    type: todosTypes.CREATE_TODO_FAILURE
  }
}

export function updateTodoRequest(id, changes) {
  return {
    type: todosTypes.UPDATE_TODO_REQUEST,
    payload: {
      id,
      changes
    }
  }
}

export function updateTodo(todo) {
  return {
    type: todosTypes.UPDATE_TODO_SUCCESS,
    payload: {
      todo
    }
  }
}

export function updateTodoFailure(id) {
  return {
    type: todosTypes.UPDATE_TODO_FAILURE,
    payload: {
      id
    }
  }
}

export function deleteTodoRequest(id) {
  return {
    type: todosTypes.DELETE_TODO_REQUEST,
    payload: {
      id
    }
  }
}

export function deleteTodo(id) {
  return {
    type: todosTypes.DELETE_TODO_SUCCESS,
    payload: {
      id
    }
  }
}

export function deleteTodoFailure(id) {
  return {
    type: todosTypes.DELETE_TODO_FAILURE,
    payload: {
      id
    }
  }
}

export function selectTodo(id) {
  return {
    type: todosTypes.SELECT_TODO,
    payload: {
      id
    }
  }
}

export function toggleAllTodosRequest(ids, completed) {
  return {
    type: todosTypes.TOGGLE_ALL_TODOS_REQUEST,
    payload: {
      ids,
      completed
    }
  }
}

export function toggleAllTodos(todos) {
  return {
    type: todosTypes.TOGGLE_ALL_TODOS_SUCCESS,
    payload: {
      todos
    }
  }
}

export function toggleAllTodosFailure() {
  return {
    type: todosTypes.TOGGLE_ALL_TODOS_FAILURE
  }
}

export function deleteAllTodosRequest(ids) {
  return {
    type: todosTypes.DELETE_ALL_TODOS_REQUEST,
    payload: {
      ids
    }
  }
}

export function deleteAllTodos() {
  return {
    type: todosTypes.DELETE_ALL_TODOS_SUCCESS
  }
}

export function deleteAllTodosFailure() {
  return {
    type: todosTypes.DELETE_ALL_TODOS_FAILURE
  }
}


text:
namespace TwoCheckout
{
    public class CouponList
    {
        public Coupon[] coupon { get; set; }
    }
}


text:
using ArchitectNow.Framework.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using TypeScript.Demo.Data.Models;
using TypeScript.Demo.Data.Repositories;

namespace TypeScript.Demo.Areas.API.Controllers
{
    [AllowAnonymous]
    public class PersonController : BaseDataController<Person>
    {
        public IPersonRepository PersonRepository { get; set; }

        public PersonController(IPersonRepository PersonRepository)
        {
            this.PersonRepository = PersonRepository;
            this.Repository = PersonRepository;
        }

        public Envelope<bool> CheckActive(Guid ID)
        {
            return new Envelope<bool>() { Content = true };
        }
    }
}


text:
from django.template import Library
from django import template
from django.db.models import get_model

from orders.models import Record

register = template.Library()

@register.assignment_tag
def get_last_record(recipient):
    try:
        last_record = Record.objects.filter(recipient = recipient).order_by('issue').last()
        if last_record != None:
            print "last record be %s " % last_record
        return int(last_record.issue + 1)
    except:
        print "last record is none"
        return None

@register.simple_tag
def get_larst_record(recipient, issue):
    return recipient

    # improve fetching last record to account for lapses


text:
namespace loader
{
    /// <!-- description -->
    ///   @brief Used to execute the actual checks. We put the checks in this
    ///     function so that we can validate the tests both at compile-time
    ///     and at run-time. If a bsl::ut_check fails, the tests will either
    ///     fail fast at run-time, or will produce a compile-time error.
    ///
    /// <!-- inputs/outputs -->
    ///   @return Always returns bsl::exit_success.
    ///
    [[nodiscard]] constexpr auto
    tests() noexcept -> bsl::exit_code
    {
        helpers::init_x64();
        constexpr auto func{&map_root_vp_state};

        bsl::ut_scenario{"success"} = [&]() noexcept {
            bsl::ut_given{} = [&]() noexcept {
                root_page_table_t *pmut_mut_rpt{};
                state_save_t *pmut_mut_state{};
                bsl::ut_when{} = [&]() noexcept {
                    helpers::ut_check(alloc_mk_root_page_table(&pmut_mut_rpt));
                    helpers::ut_check(alloc_and_copy_root_vp_state(&pmut_mut_state));
                    bsl::ut_then{} = [&]() noexcept {
                        helpers::ut_check(func(pmut_mut_state, pmut_mut_rpt));
                    };
                    bsl::ut_cleanup{} = [&]() noexcept {
                        free_root_vp_state(&pmut_mut_state);
                        free_mk_root_page_table(&pmut_mut_rpt);
                        helpers::reset_x64();
                    };
                };
            };
        };

        bsl::ut_scenario{"platform_virt_to_phys demote fails"} = [&]() noexcept {
            bsl::ut_given{} = [&]() noexcept {
                root_page_table_t *pmut_mut_rpt{};
                state_save_t *pmut_mut_state{};
                bsl::ut_when{} = [&]() noexcept {
                    helpers::ut_check(alloc_mk_root_page_table(&pmut_mut_rpt));
                    helpers::ut_check(alloc_and_copy_root_vp_state(&pmut_mut_state));
                    helpers::g_mut_platform_virt_to_phys = 1;
                    bsl::ut_then{} = [&]() noexcept {
                        helpers::ut_fails(func(pmut_mut_state, pmut_mut_rpt));
                    };
                    bsl::ut_cleanup{} = [&]() noexcept {
                        free_root_vp_state(&pmut_mut_state);
                        free_mk_root_page_table(&pmut_mut_rpt);
                        helpers::reset_x64();
                    };
                };
            };
        };

        return helpers::fini();
    }
}

/// <!-- description -->
///   @brief Main function for this unit test. If a call to bsl::ut_check() fails
///     the application will fast fail. If all calls to bsl::ut_check() pass, this
///     function will successfully return with bsl::exit_success.
///
/// <!-- inputs/outputs -->
///   @return Always returns bsl::exit_success.
///
[[nodiscard]] auto
main() noexcept -> bsl::exit_code
{
    bsl::enable_color();
    return loader::tests();
}


text:
[![Gem Version](https://badge.fury.io/rb/regressor.svg)](http://badge.fury.io/rb/regressor)
[![Code Climate](https://codeclimate.com/repos/5506977e6956803f8f003bea/badges/946b605251d8ad324625/gpa.svg)](https://codeclimate.com/repos/5506977e6956803f8f003bea/feed)
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/ndea/regressor/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

# Regressor
Regressor is a regression based testing tool.
What is regression testing? [see here](http://en.wikipedia.org/wiki/Regression_testing).
You can generate specs based on your ActiveRecord models.

Made with ♥ at [TUTORize](http://tutorize.info)

# Get Regressor
###### Directly from GitHub
```ruby
gem 'regressor', git: 'https://github.com/ndea/regressor.git', branch: 'master'
```
or
###### Rubygems
```ruby
gem 'regressor', '~> 0.5.5'
```

# Install
```bash
bundle install
rails g regressor:install
```
This will create an initializer in config/initializers. This initializers looks like this:
###### Initializer
```ruby
# If the regressor gem is inside a group wrap your initializer in
# if defined?(Regressor) do .. end
Regressor.configure do |config|
  # Defines the path where the generated files for your models will be placed
  # config.regression_path = 'spec/models/regression'

  # Defines the path where the generated files for your controllers will be placed
  # config.regression_controller_path = 'spec/controllers/regression'

  # Exclude Models for regression spec generation.
  # Provide model names as String (e.g. 'User')
  # config.excluded_models = []

  # Exclude Controllers for regression generation.
  # Provide controller names as String (e.g. 'UsersController').
  # config.excluded_controllers = []

  # If you are using enums in Rails 4 enable this option to generate regression specs for enums.
  # If your Rails version is =< Rails 3 set this option to false.
  # Default this option is set to true.
  # config.include_enums = true
end
```

Then require the gem dependency 'shoulda-matchers' in your rails_helper (or spec_helper if you're using RSpec 2.x):
```ruby
require 'shoulda/matchers'
```
# Usage
###### Run the generator:
##### ActiveRecord
```ruby
rails generate regressor:model # Create Regression specs for your models
rails generate regressor:controller # Create Regression specs for your controllers
```
##### Mongoid
```ruby
rails generate regressor:mongoid:model # Create regression specs for your mongoid models
```

##### Supported Regressions
##### Models

###### ActiveRecord
 - Relations
   - belongs_to
   - has_many
   - has_one
 - Nested Attributes
 - Validations
   - Length
   - Presence
   - Numericality
 - Database
   - Columns
   - Indexes
 - Enums (Rails 4)

###### Mongoid
 - Relations
   - belongs_to
   - has_many
   - has_one
   - embeds_one
   - embeds_many
 - Database
   - Fields
 - Document
   - Includes
   - Versioning

###### Controllers
 - Routing
 - Callbacks
   - Before filter
   - After filter
   - Around filter

# Also see
[Airpair - Generate specs for your Rails application](https://www.airpair.com/rspec/posts/gert)

[Guard for regressor](https://github.com/patrick-nits/guard-regressor)

# Contributing

1. Fork it ( https://github.com/ndea/regressor/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request

# Contribution topics wanted

- Specs
- Documentation
- Bugfixes
- Codestyle
- Anything that improves this gem