text:
package azkaban.executor;

import azkaban.DispatchMethod;
import azkaban.db.DatabaseOperator;
import azkaban.db.EncodingType;
import azkaban.db.SQLTransaction;
import azkaban.utils.GZIPUtils;
import azkaban.utils.JSONUtils;
import azkaban.utils.Pair;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;

@Singleton
public class ExecutionFlowDao {

  private static final Logger logger = Logger.getLogger(ExecutionFlowDao.class);
  private final DatabaseOperator dbOperator;
  private final MysqlNamedLock mysqlNamedLock;

  private static final String POLLING_LOCK_NAME = "execution_flows_polling";
  private static final int GET_LOCK_TIMEOUT_IN_SECONDS = 5;

  @Inject
  public ExecutionFlowDao(final DatabaseOperator dbOperator, final MysqlNamedLock mysqlNamedLock) {
    this.dbOperator = dbOperator;
    this.mysqlNamedLock = mysqlNamedLock;
  }

  public void uploadExecutableFlow(final ExecutableFlow flow)
      throws ExecutorManagerException {

    final String useExecutorParam =
        flow.getExecutionOptions().getFlowParameters().get(ExecutionOptions.USE_EXECUTOR);
    final String executorId = StringUtils.isNotEmpty(useExecutorParam) ? useExecutorParam : null;

    final String flowPriorityParam =
        flow.getExecutionOptions().getFlowParameters().get(ExecutionOptions.FLOW_PRIORITY);
    final int flowPriority = StringUtils.isNotEmpty(flowPriorityParam) ?
        Integer.parseInt(flowPriorityParam) : ExecutionOptions.DEFAULT_FLOW_PRIORITY;

    final String INSERT_EXECUTABLE_FLOW = "INSERT INTO execution_flows "
        + "(project_id, flow_id, version, status, submit_time, submit_user, update_time, "
        + "use_executor, flow_priority, execution_source, dispatch_method) values (?,?,?,?,?,?,?,"
        + "?,?,?,?)";
    final long submitTime = flow.getSubmitTime();
    final String executionSource = flow.getExecutionSource();
    final DispatchMethod dispatchMethod = flow.getDispatchMethod();

    /**
     * Why we need a transaction to get last insert ID?
     * Because "SELECT LAST_INSERT_ID()" needs to have the same connection
     * as inserting the new entry.
     * See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_last-insert-id
     */
    final SQLTransaction<Long> insertAndGetLastID = transOperator -> {
      transOperator.update(INSERT_EXECUTABLE_FLOW, flow.getProjectId(),
          flow.getFlowId(), flow.getVersion(), flow.getStatus().getNumVal(),
          submitTime, flow.getSubmitUser(), submitTime, executorId, flowPriority, executionSource
          , dispatchMethod.getNumVal());
      transOperator.getConnection().commit();
      return transOperator.getLastInsertId();
    };

    try {
      final long id = this.dbOperator.transaction(insertAndGetLastID);
      logger.info("Flow given " + flow.getFlowId() + " given id " + id);
      flow.setExecutionId((int) id);
      updateExecutableFlow(flow);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error creating execution.", e);
    }
  }

  List<ExecutableFlow> fetchFlowHistory(final int skip, final int num)
      throws ExecutorManagerException {
    try {
      return this.dbOperator.query(FetchExecutableFlows.FETCH_ALL_EXECUTABLE_FLOW_HISTORY,
          new FetchExecutableFlows(), skip, num);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching flow History", e);
    }
  }

  List<ExecutableFlow> fetchFlowHistory(final int projectId, final String flowId,
      final int skip, final int num)
      throws ExecutorManagerException {
    try {
      return this.dbOperator.query(FetchExecutableFlows.FETCH_EXECUTABLE_FLOW_HISTORY,
          new FetchExecutableFlows(), projectId, flowId, skip, num);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching flow history", e);
    }
  }

  public List<ExecutableFlow> fetchAgedQueuedFlows(final Duration minAge)
      throws ExecutorManagerException {
    try {
      return this.dbOperator.query(FetchExecutableFlows.FETCH_FLOWS_QUEUED_FOR_LONG_TIME,
          new FetchExecutableFlows(), System.currentTimeMillis() - minAge.toMillis());
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching aged queued flows", e);
    }
  }

  public List<Pair<ExecutionReference, ExecutableFlow>> fetchQueuedFlows(final Status status)
      throws ExecutorManagerException {
    try {
      return this.dbOperator.query(FetchQueuedExecutableFlows.FETCH_QUEUED_EXECUTABLE_FLOW,
          new FetchQueuedExecutableFlows(), status.getNumVal());
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching active flows", e);
    }
  }

  public List<ExecutableFlow> fetchStaleFlowsForStatus(final Status status,
      final ImmutableMap<Status, Pair<Duration, String>> validityMap)
      throws ExecutorManagerException {
    return fetchFlowsForStatusWithTimeValidity(status, validityMap, true);
  }

  public List<ExecutableFlow> fetchFreshFlowsForStatus(final Status status,
      final ImmutableMap<Status, Pair<Duration, String>> validityMap)
      throws ExecutorManagerException {
    return fetchFlowsForStatusWithTimeValidity(status, validityMap, false);
  }

  /**
   *
   * @param status the status of flows you want
   * @param validityMap contains the status as key, the value is a pair, defining timestamp by
   *                    subtracting a duration from now, and what event time (submit/start/update)
   *                    this timestamp is comparing with
   * @param looksForStale if true return flows is stale comparing to this timestamp, else find
   *                      flows fresher than this timestamp
   */
  List<ExecutableFlow> fetchFlowsForStatusWithTimeValidity(
      final Status status,
      final ImmutableMap<Status, Pair<Duration, String>> validityMap,
      boolean looksForStale)
      throws ExecutorManagerException {
    if (!validityMap.containsKey(status)) {
      throw new ExecutorManagerException(
          "Validity duration is not defined for status: " + status.name());
    }
    final Pair<Duration, String> validity = validityMap.get(status);
    final Duration validityDuration = validity.getFirst();
    final String validityFrom = validity.getSecond();
    final long beforeInMillis = System.currentTimeMillis() - validityDuration.toMillis();

    // For status PREPARING (20), to find stale flows, validityDuration is 15 Mins and validityFrom
    // is "submit_time", and they query will be:
    // SELECT ef.exec_id, ef.enc_type, ef.flow_data, ef.status FROM execution_flows ef
    // WHERE status=20 AND submit_time>0 AND submit_time<beforeInMillis
    final StringBuilder query = new StringBuilder()
        .append(FetchExecutableFlows.FETCH_BASE_EXECUTABLE_FLOW_QUERY)
        .append(" WHERE status=? ")
        .append(" AND dispatch_method=?")
        .append(" AND " + validityFrom + ">0")
        .append(" AND " + validityFrom + (looksForStale ? "<" : ">=") + "?");
    try {
      return this.dbOperator.query(query.toString(), new FetchExecutableFlows(),
          status.getNumVal(), DispatchMethod.CONTAINERIZED.getNumVal(), beforeInMillis);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching stale flows", e);
    }
  }

  /**
   * fetch flow execution history with specified {@code projectId}, {@code flowId} and flow start
   * time >= {@code startTime}
   *
   * @return the list of flows meeting the specified criteria
   */
  public List<ExecutableFlow> fetchFlowHistory(final int projectId, final String flowId, final
  long startTime) throws ExecutorManagerException {
    try {
      return this.dbOperator.query(FetchExecutableFlows.FETCH_EXECUTABLE_FLOW_BY_START_TIME,
          new FetchExecutableFlows(), projectId, flowId, startTime);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching historic flows", e);
    }
  }

  List<ExecutableFlow> fetchFlowHistory(final int projectId, final String flowId,
      final int skip, final int num, final Status status)
      throws ExecutorManagerException {
    try {
      return this.dbOperator.query(FetchExecutableFlows.FETCH_EXECUTABLE_FLOW_BY_STATUS,
          new FetchExecutableFlows(), projectId, flowId, status.getNumVal(), skip, num);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching active flows", e);
    }
  }

  List<ExecutableFlow> fetchRecentlyFinishedFlows(final Duration maxAge)
      throws ExecutorManagerException {
    try {
      return this.dbOperator.query(FetchRecentlyFinishedFlows.FETCH_RECENTLY_FINISHED_FLOW,
          new FetchRecentlyFinishedFlows(), System.currentTimeMillis() - maxAge.toMillis(),
          Status.SUCCEEDED.getNumVal(), Status.KILLED.getNumVal(),
          Status.FAILED.getNumVal());
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching recently finished flows", e);
    }
  }

  List<ExecutableFlow> fetchFlowHistory(final String projectNameContains,
      final String flowNameContains, final String userNameContains, final int status,
      final long startTime, final long endTime, final int skip, final int num)
      throws ExecutorManagerException {
    String query = FetchExecutableFlows.FETCH_BASE_EXECUTABLE_FLOW_QUERY;
    final List<Object> params = new ArrayList<>();

    boolean first = true;
    if (projectNameContains != null && !projectNameContains.isEmpty()) {
      query += " JOIN projects p ON ef.project_id = p.id WHERE name LIKE ?";
      params.add('%' + projectNameContains + '%');
      first = false;
    }

    // todo kunkun-tang: we don't need the below complicated logics. We should just use a simple way.
    if (flowNameContains != null && !flowNameContains.isEmpty()) {
      if (first) {
        query += " WHERE ";
        first = false;
      } else {
        query += " AND ";
      }

      query += " flow_id LIKE ?";
      params.add('%' + flowNameContains + '%');
    }

    if (userNameContains != null && !userNameContains.isEmpty()) {
      if (first) {
        query += " WHERE ";
        first = false;
      } else {
        query += " AND ";
      }
      query += " submit_user LIKE ?";
      params.add('%' + userNameContains + '%');
    }

    if (status != 0) {
      if (first) {
        query += " WHERE ";
        first = false;
      } else {
        query += " AND ";
      }
      query += " status = ?";
      params.add(status);
    }

    if (startTime > 0) {
      if (first) {
        query += " WHERE ";
        first = false;
      } else {
        query += " AND ";
      }
      query += " start_time > ?";
      params.add(startTime);
    }

    if (endTime > 0) {
      if (first) {
        query += " WHERE ";
      } else {
        query += " AND ";
      }
      query += " end_time < ?";
      params.add(endTime);
    }

    if (skip > -1 && num > 0) {
      query += "  ORDER BY exec_id DESC LIMIT ?, ?";
      params.add(skip);
      params.add(num);
    }

    try {
      return this.dbOperator.query(query, new FetchExecutableFlows(), params.toArray());
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching active flows", e);
    }
  }

  void updateExecutableFlow(final ExecutableFlow flow) throws ExecutorManagerException {
    updateExecutableFlow(flow, EncodingType.GZIP);
  }

  private void updateExecutableFlow(final ExecutableFlow flow, final EncodingType encType)
      throws ExecutorManagerException {
    final String UPDATE_EXECUTABLE_FLOW_DATA =
        "UPDATE execution_flows "
            + "SET status=?,update_time=?,start_time=?,end_time=?,enc_type=?,flow_data=? "
            + "WHERE exec_id=?";

    byte[] data = null;
    try {
      // If this action fails, the execution must be failed.
      final String json = JSONUtils.toJSON(flow.toObject());
      final byte[] stringData = json.getBytes("UTF-8");
      data = stringData;
      // Todo kunkun-tang: use a common method to transform stringData to data.
      if (encType == EncodingType.GZIP) {
        data = GZIPUtils.gzipBytes(stringData);
      }
    } catch (final IOException e) {
      flow.setStatus(Status.FAILED);
      updateExecutableFlowStatusInDB(flow);
      throw new ExecutorManagerException("Error encoding the execution flow. Execution Id  = "
          + flow.getExecutionId());
    } catch (final RuntimeException re) {
      flow.setStatus(Status.FAILED);
      // Likely due to serialization error
      if ( data == null && re instanceof NullPointerException) {
        logger.warn("Failed to serialize executable flow for " + flow.getExecutionId());
        logger.warn("NPE stacktrace" + ExceptionUtils.getStackTrace(re));
      }
      updateExecutableFlowStatusInDB(flow);
      throw new ExecutorManagerException("Error encoding the execution flow due to "
          + "RuntimeException. Execution Id  = " + flow.getExecutionId(), re);
    }

    try {
      this.dbOperator.update(UPDATE_EXECUTABLE_FLOW_DATA, flow.getStatus()
          .getNumVal(), flow.getUpdateTime(), flow.getStartTime(), flow
          .getEndTime(), encType.getNumVal(), data, flow.getExecutionId());
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error updating flow.", e);
    }
  }

  private void updateExecutableFlowStatusInDB(final ExecutableFlow flow)
    throws ExecutorManagerException {
    final String UPDATE_FLOW_STATUS = "UPDATE execution_flows SET status = ?, update_time = ? "
        + "where exec_id = ?";

    try {
      this.dbOperator.update(UPDATE_FLOW_STATUS, flow.getStatus().getNumVal(),
          System.currentTimeMillis(), flow.getExecutionId());
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error updating flow.", e);
    }
  }

  public ExecutableFlow fetchExecutableFlow(final int execId) throws ExecutorManagerException {
    final FetchExecutableFlows flowHandler = new FetchExecutableFlows();
    try {
      final List<ExecutableFlow> properties = this.dbOperator
          .query(FetchExecutableFlows.FETCH_EXECUTABLE_FLOW, flowHandler, execId);
      if (properties.isEmpty()) {
        return null;
      } else {
        return properties.get(0);
      }
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error fetching flow id " + execId, e);
    }
  }

  /**
   * set executor id to null for the execution id
   */
  public void unsetExecutorIdForExecution(final int executionId) throws ExecutorManagerException {
    final String UNSET_EXECUTOR = "UPDATE execution_flows SET executor_id = null, update_time = ? where exec_id = ?";

    final SQLTransaction<Integer> unsetExecutor =
        transOperator -> transOperator.update(UNSET_EXECUTOR, System.currentTimeMillis(),
            executionId);

    try {
      this.dbOperator.transaction(unsetExecutor);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error unsetting executor id for execution " + executionId,
          e);
    }
  }

  public int selectAndUpdateExecution(final int executorId, final boolean isActive,
      final DispatchMethod dispatchMethod)
      throws ExecutorManagerException {
    final String UPDATE_EXECUTION = "UPDATE execution_flows SET executor_id = ?, update_time = ? "
        + "where exec_id = ?";
    final String selectExecutionForUpdate = isActive ?
        SelectFromExecutionFlows.SELECT_EXECUTION_FOR_UPDATE_ACTIVE :
        SelectFromExecutionFlows.SELECT_EXECUTION_FOR_UPDATE_INACTIVE;

    final SQLTransaction<Integer> selectAndUpdateExecution = transOperator -> {
      transOperator.getConnection().setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

      final List<Integer> execIds = transOperator.query(selectExecutionForUpdate,
          new SelectFromExecutionFlows(), Status.PREPARING.getNumVal(), dispatchMethod.getNumVal(),
              executorId);

      int execId = -1;
      if (!execIds.isEmpty()) {
        execId = execIds.get(0);
        transOperator.update(UPDATE_EXECUTION, executorId, System.currentTimeMillis(), execId);
      }
      transOperator.getConnection().commit();
      return execId;
    };

    try {
      return this.dbOperator.transaction(selectAndUpdateExecution);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error selecting and updating execution with executor "
          + executorId, e);
    }
  }

  public int selectAndUpdateExecutionWithLocking(final int executorId, final boolean isActive,
      final DispatchMethod dispatchMethod)
      throws ExecutorManagerException {
    final String UPDATE_EXECUTION = "UPDATE execution_flows SET executor_id = ?, update_time = ? "
        + "where exec_id = ?";
    final String selectExecutionForUpdate = isActive ?
        SelectFromExecutionFlows.SELECT_EXECUTION_FOR_UPDATE_ACTIVE :
        SelectFromExecutionFlows.SELECT_EXECUTION_FOR_UPDATE_INACTIVE;

    final SQLTransaction<Integer> selectAndUpdateExecution = transOperator -> {
      int execId = -1;
      final boolean hasLocked = this.mysqlNamedLock.getLock(transOperator, POLLING_LOCK_NAME, GET_LOCK_TIMEOUT_IN_SECONDS);
      logger.info("ExecutionFlow polling lock value: " + hasLocked + " for executorId: " + executorId);
      if (hasLocked) {
        try {
          final List<Integer> execIds = transOperator.query(selectExecutionForUpdate,
              new SelectFromExecutionFlows(), Status.PREPARING.getNumVal(), dispatchMethod.getNumVal(),
              executorId);
          if (CollectionUtils.isNotEmpty(execIds)) {
            execId = execIds.get(0);
            transOperator.update(UPDATE_EXECUTION, executorId, System.currentTimeMillis(), execId);
          }
        } finally {
          this.mysqlNamedLock.releaseLock(transOperator, POLLING_LOCK_NAME);
          logger.info("Released polling lock for executorId: " + executorId);
        }
      } else {
        logger.info("Could not acquire polling lock for executorId: " + executorId);
      }
      return execId;
    };

    try {
      return this.dbOperator.transaction(selectAndUpdateExecution);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error selecting and updating execution with executor "
          + executorId, e);
    }
  }

  /**
   * This method is used to select executions in batch. It will apply lock and fetch executions.
   * It will also update the status of those executions as mentioned in updatedStatus field.
   * @param batchEnabled If set to true, fetch the executions in batch
   * @param limit Limit in case of batch fetch
   * @param updatedStatus Update the status of executions as mentioned in this field. It can be
   *                      READY of PREPARING based on whichever is the starting state for any
   *                      dispatch method.
   * @return Set of execution ids
   * @throws ExecutorManagerException
   */
  public Set<Integer> selectAndUpdateExecutionWithLocking(final boolean batchEnabled,
      final int limit,
      final Status updatedStatus,
      final DispatchMethod dispatchMethod)
      throws ExecutorManagerException {
    final String UPDATE_EXECUTION = "UPDATE execution_flows SET status = ?, update_time = ? "
        + "where exec_id = ?";
    final SQLTransaction<Set<Integer>> selectAndUpdateExecution = transOperator -> {
      final Set<Integer> executions = new HashSet<>();
      final boolean hasLocked = this.mysqlNamedLock
          .getLock(transOperator, POLLING_LOCK_NAME, GET_LOCK_TIMEOUT_IN_SECONDS);
      logger.debug("ExecutionFlow polling lock value: " + hasLocked);
      if (hasLocked) {
        try {
          final List<Integer> execIds;
          if (batchEnabled) {
            execIds = transOperator.query(String
                    .format(SelectFromExecutionFlows.SELECT_EXECUTION_IN_BATCH_FOR_UPDATE_FORMAT, ""),
                new SelectFromExecutionFlows(), Status.READY.getNumVal(), dispatchMethod.getNumVal(), limit);
          } else {
            execIds = transOperator.query(
                String.format(SelectFromExecutionFlows.SELECT_EXECUTION_FOR_UPDATE_FORMAT, ""),
                new SelectFromExecutionFlows(), Status.READY.getNumVal(),
                dispatchMethod.getNumVal());
          }
          if (CollectionUtils.isNotEmpty(execIds)) {
            executions.addAll(execIds);
            //TODO: Currently transOperator.getConnection().createArrayOf is not supported so
            //update statement can not have {exec_id in (?)} in where clause. Use below
            //mentioned code instead of for look for update statement when createArrayOf is
            //supported
            //Array executionsToUpdate = transOperator.getConnection().createArrayOf("INTEGER",
            //    execIds.toArray());
            //transOperator
            //      .update(UPDATE_EXECUTION, updatedStatus.getNumVal(), System.currentTimeMillis(),
            //          executionsToUpdate);
            for (final Integer execId : execIds) {
              transOperator
                  .update(UPDATE_EXECUTION, updatedStatus.getNumVal(), System.currentTimeMillis(),
                      execId);
            }
          }
        } finally {
          this.mysqlNamedLock.releaseLock(transOperator, POLLING_LOCK_NAME);
          logger.debug("Released polling lock");
        }
      } else {
        logger.info("Could not acquire polling lock");
      }
      return executions;
    };

    try {
      return this.dbOperator.transaction(selectAndUpdateExecution);
    } catch (final SQLException e) {
      throw new ExecutorManagerException("Error selecting and updating execution", e);
    }
  }

  /**
   * Updates version set id for the given executionId
   *
   * @param executionId
   * @param versionSetId
   * @return int
   * @throws ExecutorManagerException
   */
  public int updateVersionSetId(final int executionId, final int versionSetId)
      throws ExecutorManagerException {
    final String UPDATE_VERSION_SET_ID = "UPDATE execution_flows SET version_set_id = ?, "
        + "update_time = ? where exec_id = ?";
    try {
      return this.dbOperator.update(UPDATE_VERSION_SET_ID, versionSetId,
          System.currentTimeMillis(), executionId);
    } catch (final SQLException e) {
      throw new ExecutorManagerException(String.format("Error while updating version set id for "
          + "execId: %d", executionId), e);
    }
  }

  public static class SelectFromExecutionFlows implements
      ResultSetHandler<List<Integer>> {

    private static final String SELECT_EXECUTION_FOR_UPDATE_FORMAT =
        "SELECT exec_id from execution_flows WHERE exec_id = (SELECT exec_id from execution_flows"
            + " WHERE status = ? and dispatch_method = ?"
            + " and executor_id is NULL and flow_data is NOT NULL %s"
            + " ORDER BY flow_priority DESC, update_time ASC, exec_id ASC LIMIT 1) and "
            + "executor_id is NULL FOR UPDATE";

    private static final String SELECT_EXECUTION_IN_BATCH_FOR_UPDATE_FORMAT =
        "SELECT exec_id from execution_flows WHERE exec_id in (SELECT exec_id from execution_flows"
            + " WHERE status = ? and dispatch_method = ?"
            + " and executor_id is NULL and flow_data is NOT NULL %s ) "
            + " ORDER BY flow_priority DESC, update_time ASC, exec_id ASC "
            + " LIMIT ? FOR UPDATE";

    public static final String SELECT_EXECUTION_FOR_UPDATE_ACTIVE =
        String.format(SELECT_EXECUTION_FOR_UPDATE_FORMAT,
            "and (use_executor is NULL or use_executor = ?)");

    public static final String SELECT_EXECUTION_FOR_UPDATE_INACTIVE =
        String.format(SELECT_EXECUTION_FOR_UPDATE_FORMAT, "and use_executor = ?");

    @Override
    public List<Integer> handle(final ResultSet rs) throws SQLException {
      if (!rs.next()) {
        return Collections.emptyList();
      }
      final List<Integer> execIds = new ArrayList<>();
      do {
        final int execId = rs.getInt(1);
        execIds.add(execId);
      } while (rs.next());

      return execIds;
    }
  }

  public static class FetchExecutableFlows implements
      ResultSetHandler<List<ExecutableFlow>> {

    static String FETCH_EXECUTABLE_FLOW_BY_START_TIME =
        "SELECT ef.exec_id, ef.enc_type, ef.flow_data, ef.status FROM execution_flows ef WHERE "
            + "project_id=? AND flow_id=? AND start_time >= ? ORDER BY start_time DESC";
    static String FETCH_BASE_EXECUTABLE_FLOW_QUERY =
        "SELECT ef.exec_id, ef.enc_type, ef.flow_data, ef.status FROM execution_flows ef";
    private static final String FETCH_FLOWS_STARTED_BEFORE = FETCH_BASE_EXECUTABLE_FLOW_QUERY +
        " WHERE start_time < ?";
    static String FETCH_EXECUTABLE_FLOW =
        "SELECT exec_id, enc_type, flow_data, status FROM execution_flows "
            + "WHERE exec_id=?";
    static String FETCH_ALL_EXECUTABLE_FLOW_HISTORY =
        "SELECT exec_id, enc_type, flow_data, status FROM execution_flows "
            + "ORDER BY exec_id DESC LIMIT ?, ?";
    static String FETCH_EXECUTABLE_FLOW_HISTORY =
        "SELECT exec_id, enc_type, flow_data, status FROM execution_flows "
            + "WHERE project_id=? AND flow_id=? "
            + "ORDER BY exec_id DESC LIMIT ?, ?";
    static String FETCH_EXECUTABLE_FLOW_BY_STATUS =
        "SELECT exec_id, enc_type, flow_data, status FROM execution_flows "
            + "WHERE project_id=? AND flow_id=? AND status=? "
            + "ORDER BY exec_id DESC LIMIT ?, ?";
    // Fetch flows that are in preparing state for more than a certain duration.
    private static final String FETCH_FLOWS_QUEUED_FOR_LONG_TIME =
        "SELECT exec_id, enc_type, flow_data, status FROM execution_flows"
            + " WHERE submit_time < ? AND status = "
            + Status.PREPARING.getNumVal();

    @Override
    public List<ExecutableFlow> handle(final ResultSet rs) throws SQLException {
      if (!rs.next()) {
        return Collections.emptyList();
      }

      final List<ExecutableFlow> execFlows = new ArrayList<>();
      do {
        final int id = rs.getInt(1);
        final int encodingType = rs.getInt(2);
        final byte[] data = rs.getBytes(3);

        if (data != null) {
          final EncodingType encType = EncodingType.fromInteger(encodingType);
          final Status status = Status.fromInteger(rs.getInt(4));
          try {
            final ExecutableFlow exFlow =
                ExecutableFlow.createExecutableFlow(
                    GZIPUtils.transformBytesToObject(data, encType), status);
            execFlows.add(exFlow);
          } catch (final IOException e) {
            throw new SQLException("Error retrieving flow data " + id, e);
          }
        }
      } while (rs.next());

      return execFlows;
    }
  }

  /**
   * JDBC ResultSetHandler to fetch queued executions
   */
  private static class FetchQueuedExecutableFlows implements
      ResultSetHandler<List<Pair<ExecutionReference, ExecutableFlow>>> {

    // Select queued unassigned flows
    private static final String FETCH_QUEUED_EXECUTABLE_FLOW =
        "SELECT exec_id, enc_type, flow_data, status FROM execution_flows"
            + " WHERE executor_id is NULL AND status = ?";

    @Override
    public List<Pair<ExecutionReference, ExecutableFlow>> handle(final ResultSet rs)
        throws SQLException {
      if (!rs.next()) {
        return Collections.emptyList();
      }

      final List<Pair<ExecutionReference, ExecutableFlow>> execFlows =
          new ArrayList<>();
      do {
        final int id = rs.getInt(1);
        final int encodingType = rs.getInt(2);
        final byte[] data = rs.getBytes(3);

        if (data == null) {
          ExecutionFlowDao.logger.error("Found a flow with empty data blob exec_id: " + id);
        } else {
          final EncodingType encType = EncodingType.fromInteger(encodingType);
          final Status status = Status.fromInteger(rs.getInt(4));
          try {
            final ExecutableFlow exFlow =
                ExecutableFlow.createExecutableFlow(
                    GZIPUtils.transformBytesToObject(data, encType), status);
            final ExecutionReference ref = new ExecutionReference(id, exFlow.getDispatchMethod());
            execFlows.add(new Pair<>(ref, exFlow));
          } catch (final IOException e) {
            throw new SQLException("Error retrieving flow data " + id, e);
          }
        }
      } while (rs.next());

      return execFlows;
    }
  }

  private static class FetchRecentlyFinishedFlows implements
      ResultSetHandler<List<ExecutableFlow>> {

    // Execution_flows table is already indexed by end_time
    private static final String FETCH_RECENTLY_FINISHED_FLOW =
        "SELECT exec_id, enc_type, flow_data, status FROM execution_flows "
            + "WHERE end_time > ? AND status IN (?, ?, ?)";

    @Override
    public List<ExecutableFlow> handle(
        final ResultSet rs) throws SQLException {
      if (!rs.next()) {
        return Collections.emptyList();
      }

      final List<ExecutableFlow> execFlows = new ArrayList<>();
      do {
        final int id = rs.getInt(1);
        final int encodingType = rs.getInt(2);
        final byte[] data = rs.getBytes(3);

        if (data != null) {
          final EncodingType encType = EncodingType.fromInteger(encodingType);
          final Status status = Status.fromInteger(rs.getInt(4));
          try {
            final ExecutableFlow exFlow =
                ExecutableFlow.createExecutableFlow(
                    GZIPUtils.transformBytesToObject(data, encType), status);
            execFlows.add(exFlow);
          } catch (final IOException e) {
            throw new SQLException("Error retrieving flow data " + id, e);
          }
        }
      } while (rs.next());
      return execFlows;
    }
  }
}


text:
LoginState.getCustomData = function() {
  var data = {
    loginToken: Meteor._localStorage.getItem('Meteor.loginToken')
  };

  return data;
};

redpajama_set_name: RedPajamaGithub


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <title>Class: KerningLibrary</title>

    <meta property="og:title" content=""/>
    <meta property="og:type" content="website"/>
    <meta property="og:image" content=""/>

    <meta property="og:url" content=""/>

    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
    <link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css">
    <link type="text/css" rel="stylesheet" href="styles/jaguar.css">

Type

        <input id="search" type="text" class="form-control input-sm" placeholder="Search Documentations">

                KerningLibrary

                type.text.HorizontalModule

            Members

_height

_spaceBetweenLines

_spaceBetweenWords

_textAlign

_textLeftToRight

_textTopToBottom

_width

            Methods

_alignLines

_arrangeLines

_centerAlignLRDU

_centerAlignLRUD

_centerAlignRLDU

_centerAlignRLUD

_justifyAlignLRDU

_justifyAlignLRUD

_justifyAlignRLDU

_justifyAlignRLUD

_leftAlignLRDU

_leftAlignLRUD

_leftAlignRLDU

_leftAlignRLUD

_relocate

_rightAlignLRDU

_rightAlignLRUD

_rightAlignRLDU

_rightAlignRLUD

                type.text.TextField

            Members

align

alignHorizontalPriority

spaceBetweenLines

spaceBetweenWords

textLeftToRight

textTopToBottom

            Methods

reset

setStyle

setText

setWordStyle

                type.text.VerticalModule

            Members

_height

_spaceBetweenLines

_spaceBetweenWords

_textAlign

_textLeftToRight

_textTopToBottom

_width

            Methods

_alignLines

_arrangeLinesVertical

_bottomAlignDULR

_bottomAlignDURL

_bottomAlignUDLR

_bottomAlignUDRL

_centerAlignDULR

_centerAlignDURL

_centerAlignUDLR

_centerAlignUDRL

_justifyAlignDULR

_justifyAlignDURL

_justifyAlignUDLR

_justifyAlignUDRL

_relocate

_topAlignDULR

_topAlignDURL

_topAlignUDLR

_topAlignUDRL

Class: KerningLibrary

    KerningLibrary

            new KerningLibrary()

            char/KerningLibrary.js, line 4

<<<<<<< HEAD
            Documentation generated by JSDoc 3.4.0 on Mon Jul 25 2016 15:14:23 GMT-0300 (Hora oficial do Brasil)
=======
<<<<<<< Updated upstream
<<<<<<< Updated upstream
            Documentation generated by JSDoc 3.4.0 on Mon Jul 25 2016 14:19:31 GMT-0300 (Hora oficial do Brasil)
=======
            Documentation generated by JSDoc 3.4.0 on Mon Jul 25 2016 13:10:04 GMT-0300 (Hora oficial do Brasil)
>>>>>>> Stashed changes
=======
            Documentation generated by JSDoc 3.4.0 on Mon Jul 25 2016 13:10:04 GMT-0300 (Hora oficial do Brasil)
>>>>>>> Stashed changes
>>>>>>> master


text:
import edu.princeton.cs.algs4.In;  // library of algs4
import edu.princeton.cs.algs4.StdOut; //library of algs4
import edu.princeton.cs.algs4.Stack;  //library of algs4
import java.util.ArrayList;
import java.util.HashSet;

public class BoggleSolver{
    private Node root;
    private Paths fourByFourPaths;
    public BoggleSolver(String[] dictionary){

        //create a root for the structure
        root = new Node(new char[0], false);
        //read each word from the dictionary into the data structure
        for (int i = 0; i < dictionary.length; i++){
            if (dictionary[i].length() > 2){
                char [] charArray = dictionary[i].toCharArray();
                Node.entry(charArray, 0, root);
            }
        }
    }

    public Iterable <String> getAllValidWords(BoggleBoard board){
        // create a map of boxId to alphabet of the board using char []
        int idCounter = 0;
        int boardRows = board.rows();
        int boardCols = board.cols();
        char [] numAlpha = new char[boardRows * boardCols];
        for (int r = 0; r < boardRows; r++){
            for (int c = 0; c < boardCols; c++){
                numAlpha[idCounter] = board.getLetter(r, c);
                idCounter++;
            }
        }
        Pathfinder findPaths = new Pathfinder(boardRows, boardCols, numAlpha, root, fourByFourPaths);
        return (HashSet<String>) findPaths.pathfinder();

    }

    // a nested class that does the DFS
    private class Pathfinder{
        private char[] numLetter; //mapping from number to alphabet
        private int dimR, dimC;
        private Paths paths;
        private Node rt; //root Node

        public Pathfinder(int r, int c, char[] numAlphabet, Node theRoot, Paths cachedPaths){
            //find all possibly legal directions of each box
            dimR = r;
            dimC = c;
            rt = theRoot;
            numLetter= numAlphabet;
            if (cachedPaths == null || dimR != 4 || dimC !=4){ //use cached paths for a 4x4 board
                paths = new Paths(r, c);
            }
            else{
                paths = cachedPaths;
            }
        }

        public Iterable<String> pathfinder(){
            // create an empty set of valid words
            // no duplicate
            HashSet<String> validWordList = new HashSet<String>();
            // create an empty stack for each state
            Stack <Tuple> idStack = new Stack <Tuple>();
            // iterate each boxId as first character
            for (int j = 0; j < dimR * dimC; j++){
                //create one list for each boxId, with the boxId as its first element
                //elements in the trail cannot be reused
                Node thisNode = rt.returnNode(numLetter[j]);
                if (thisNode != null){ //check if the corresponding first letter is a valid prefix
                    ArrayList<Integer> intTrail = new ArrayList<Integer>();
                    intTrail.add(j);
                    idStack.push(new Tuple(thisNode, intTrail, new char[0], numLetter[j]));
                }
            }
            // Depth First Search
            while (!idStack.isEmpty()){
                // pop the stack to get the first state
                Tuple thisTuple = idStack.pop();
                // get the last boxId on the trail
                Node currentNode = thisTuple.node;
                // caching variables
                int wordLength = thisTuple.prefix.length;
                int trailLength = thisTuple.trail.size();
                int currentId = thisTuple.trail.get(trailLength - 1);
                ArrayList<Integer> currentIdTrail = thisTuple.trail;
                char[] potentialValidWord = thisTuple.prefix;
                char[] potentialValidWordU = new char[wordLength + 1];
                // check if node is a valid terminator
                if(Node.isValidWord(currentNode)){
                    String confirmedValidWord = new String(potentialValidWord);
                    validWordList.add(confirmedValidWord);
                }
                // not a valid word; check if a 'Q' is detected, if so add a 'U' and and recheck
                if (currentNode.isQ()){
                    currentNode = currentNode.returnNode('U');
                    System.arraycopy(potentialValidWord, 0, potentialValidWordU, 0, wordLength);
                    potentialValidWordU[wordLength] = 'U';
                    if(Node.isValidWord(currentNode)){
                        //means valid word
                        String confirmedValidWordU = new String(potentialValidWordU);
                        validWordList.add(confirmedValidWordU);
                    }
                    potentialValidWord = potentialValidWordU;
                }
                ArrayList<Integer> currentPaths = paths.returnPathSets().get(currentId);
                // iterate the legal directions to find the first unused one
                for (int id: currentPaths){
                    Node nextNode = currentNode.returnNode(numLetter[id]);
                    if (!currentIdTrail.contains(id) && nextNode != null){
                        ArrayList<Integer> temporaryIdTrail = new ArrayList<Integer> (currentIdTrail);
                        temporaryIdTrail.add(id);
                        idStack.push(new Tuple(nextNode, temporaryIdTrail, potentialValidWord, numLetter[id]));
                    }
                }
            }
            return  validWordList;
        }
    }

    public int scoreOf(String word){ //validity of a word needs to be checked regardless of the board
        int score = 0;
        int index = 0;
        int wordLength = word.length();
        char [] charArray = word.toCharArray();
        Node currentNode = root;
        // keep going down from root until all characters are counted and see if
        // the node at that point can be the last character
        while (index < wordLength){
            char prefix = charArray[index];
            Node nextNode = currentNode.returnNode(prefix);
            if (nextNode != null){
                if (index == wordLength - 1){
                    if (nextNode.isTerminated()){ //valid
                        break;
                    }
                    else{ // no more character and the word is not valid
                        return 0;}
                    }
                else{
                    currentNode = nextNode;
                }
            }
            else{// next character doesn't match
                return 0;
            }
            index++;
        }
        // count word's score
        if (word.length() > 2 && wordLength < 5){score = 1;}
        else if (word.length() == 5){score = 2;}
        else if (word.length() == 6){score = 3;}
        else if (word.length() == 7){score = 5;}
        else if (word.length() >= 8){score = 11;}

        return score;
    }

    public static void main (String[] args){
        In in = new In(args[0]);
        String[] dictionary = in.readAllStrings();
        BoggleSolver solver = new BoggleSolver(dictionary);
        BoggleBoard board =new BoggleBoard(args[1]);

        int score = 0;

        for (String word:solver.getAllValidWords(board)){
          StdOut.println(word);
          score += solver.scoreOf(word);
        }
        StdOut.println("Score = " + score);
    }

}


text:
/* See LICENSE for licensing information */

/**
 * \file rendcommon.c
 * \brief Rendezvous implementation: shared code between
 * introducers, services, clients, and rendezvous points.
 **/

#include "or.h"
#include "circuitbuild.h"
#include "config.h"
#include "control.h"
#include "rendclient.h"
#include "rendcommon.h"
#include "rendmid.h"
#include "rendservice.h"
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
#include "networkstatus.h"

/** Return 0 if one and two are the same service ids, else -1 or 1 */
int
rend_cmp_service_ids(const char *one, const char *two)
{
  return strcasecmp(one,two);
}

/** Free the storage held by the service descriptor desc.
 */
void
rend_service_descriptor_free(rend_service_descriptor_t *desc)
{
  if (!desc)
    return;
  if (desc->pk)
    crypto_pk_free(desc->pk);
  if (desc->intro_nodes) {
    SMARTLIST_FOREACH(desc->intro_nodes, rend_intro_point_t *, intro,
      rend_intro_point_free(intro););
    smartlist_free(desc->intro_nodes);
  }
  if (desc->successful_uploads) {
    SMARTLIST_FOREACH(desc->successful_uploads, char *, c, tor_free(c););
    smartlist_free(desc->successful_uploads);
  }
  tor_free(desc);
}

/** Length of the descriptor cookie that is used for versioned hidden
 * service descriptors. */
#define REND_DESC_COOKIE_LEN 16

/** Length of the replica number that is used to determine the secret ID
 * part of versioned hidden service descriptors. */
#define REND_REPLICA_LEN 1

/** Compute the descriptor ID for service_id of length
 * REND_SERVICE_ID_LEN and secret_id_part of length
 * DIGEST_LEN, and write it to descriptor_id_out of length
 * DIGEST_LEN. */
void
rend_get_descriptor_id_bytes(char *descriptor_id_out,
                             const char *service_id,
                             const char *secret_id_part)
{
  crypto_digest_t *digest = crypto_digest_new();
  crypto_digest_add_bytes(digest, service_id, REND_SERVICE_ID_LEN);
  crypto_digest_add_bytes(digest, secret_id_part, DIGEST_LEN);
  crypto_digest_get_digest(digest, descriptor_id_out, DIGEST_LEN);
  crypto_digest_free(digest);
}

/** Compute the secret ID part for time_period,
 * a descriptor_cookie of length
 * REND_DESC_COOKIE_LEN which may also be NULL if no
 * descriptor_cookie shall be used, and replica, and write it to
 * secret_id_part of length DIGEST_LEN. */
static void
get_secret_id_part_bytes(char *secret_id_part, uint32_t time_period,
                         const char *descriptor_cookie, uint8_t replica)
{
  crypto_digest_t *digest = crypto_digest_new();
  time_period = htonl(time_period);
  crypto_digest_add_bytes(digest, (char*)&time_period, sizeof(uint32_t));
  if (descriptor_cookie) {
    crypto_digest_add_bytes(digest, descriptor_cookie,
                            REND_DESC_COOKIE_LEN);
  }
  crypto_digest_add_bytes(digest, (const char *)&replica, REND_REPLICA_LEN);
  crypto_digest_get_digest(digest, secret_id_part, DIGEST_LEN);
  crypto_digest_free(digest);
}

/** Return the time period for time now plus a potentially
 * intended deviation of one or more periods, based on the first byte
 * of service_id. */
static uint32_t
get_time_period(time_t now, uint8_t deviation, const char *service_id)
{
  /* The time period is the number of REND_TIME_PERIOD_V2_DESC_VALIDITY
   * intervals that have passed since the epoch, offset slightly so that
   * each service's time periods start and end at a fraction of that
   * period based on their first byte. */
  return (uint32_t)
    (now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256)
    / REND_TIME_PERIOD_V2_DESC_VALIDITY + deviation;
}

/** Compute the time in seconds that a descriptor that is generated
 * now for service_id will be valid. */
static uint32_t
get_seconds_valid(time_t now, const char *service_id)
{
  uint32_t result = REND_TIME_PERIOD_V2_DESC_VALIDITY -
    ((uint32_t)
     (now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256)
     % REND_TIME_PERIOD_V2_DESC_VALIDITY);
  return result;
}

/** Compute the binary desc_id_out (DIGEST_LEN bytes long) for a given
 * base32-encoded service_id and optional unencoded
 * descriptor_cookie of length REND_DESC_COOKIE_LEN,
 * at time now for replica number
 * replica. desc_id needs to have DIGEST_LEN bytes
 * free. Return 0 for success, -1 otherwise. */
int
rend_compute_v2_desc_id(char *desc_id_out, const char *service_id,
                        const char *descriptor_cookie, time_t now,
                        uint8_t replica)
{
  char service_id_binary[REND_SERVICE_ID_LEN];
  char secret_id_part[DIGEST_LEN];
  uint32_t time_period;
  if (!service_id ||
      strlen(service_id) != REND_SERVICE_ID_LEN_BASE32) {
    log_warn(LD_REND, "Could not compute v2 descriptor ID: "
                      "Illegal service ID: %s",
             safe_str(service_id));
    return -1;
  }
  if (replica >= REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS) {
    log_warn(LD_REND, "Could not compute v2 descriptor ID: "
                      "Replica number out of range: %d", replica);
    return -1;
  }
  /* Convert service ID to binary. */
  if (base32_decode(service_id_binary, REND_SERVICE_ID_LEN,
                    service_id, REND_SERVICE_ID_LEN_BASE32) < 0) {
    log_warn(LD_REND, "Could not compute v2 descriptor ID: "
                      "Illegal characters in service ID: %s",
             safe_str_client(service_id));
    return -1;
  }
  /* Calculate current time-period. */
  time_period = get_time_period(now, 0, service_id_binary);
  /* Calculate secret-id-part = h(time-period | desc-cookie | replica). */
  get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie,
                           replica);
  /* Calculate descriptor ID: H(permanent-id | secret-id-part) */
  rend_get_descriptor_id_bytes(desc_id_out, service_id_binary, secret_id_part);
  return 0;
}

/** Encode the introduction points in desc and write the result to a
 * newly allocated string pointed to by encoded. Return 0 for
 * success, -1 otherwise. */
static int
rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc)
{
  size_t unenc_len;
  char *unenc = NULL;
  size_t unenc_written = 0;
  int i;
  int r = -1;
  /* Assemble unencrypted list of introduction points. */
  unenc_len = smartlist_len(desc->intro_nodes) * 1000; /* too long, but ok. */
  unenc = tor_malloc_zero(unenc_len);
  for (i = 0; i < smartlist_len(desc->intro_nodes); i++) {
    char id_base32[REND_INTRO_POINT_ID_LEN_BASE32 + 1];
    char *onion_key = NULL;
    size_t onion_key_len;
    crypto_pk_t *intro_key;
    char *service_key = NULL;
    char *address = NULL;
    size_t service_key_len;
    int res;
    rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i);
    /* Obtain extend info with introduction point details. */
    extend_info_t *info = intro->extend_info;
    /* Encode introduction point ID. */
    base32_encode(id_base32, sizeof(id_base32),
                  info->identity_digest, DIGEST_LEN);
    /* Encode onion key. */
    if (crypto_pk_write_public_key_to_string(info->onion_key, &onion_key,
                                             &onion_key_len) < 0) {
      log_warn(LD_REND, "Could not write onion key.");
      goto done;
    }
    /* Encode intro key. */
    intro_key = intro->intro_key;
    if (!intro_key ||
      crypto_pk_write_public_key_to_string(intro_key, &service_key,
                                           &service_key_len) < 0) {
      log_warn(LD_REND, "Could not write intro key.");
      tor_free(onion_key);
      goto done;
    }
    /* Assemble everything for this introduction point. */
    address = tor_dup_addr(&info->addr);
    res = tor_snprintf(unenc + unenc_written, unenc_len - unenc_written,
                         "introduction-point %s\n"
                         "ip-address %s\n"
                         "onion-port %d\n"
                         "onion-key\n%s"
                         "service-key\n%s",
                       id_base32,
                       address,
                       info->port,
                       onion_key,
                       service_key);
    tor_free(address);
    tor_free(onion_key);
    tor_free(service_key);
    if (res < 0) {
      log_warn(LD_REND, "Not enough space for writing introduction point "
                        "string.");
      goto done;
    }
    /* Update total number of written bytes for unencrypted intro points. */
    unenc_written += res;
  }
  /* Finalize unencrypted introduction points. */
  if (unenc_len < unenc_written + 2) {
    log_warn(LD_REND, "Not enough space for finalizing introduction point "
                      "string.");
    goto done;
  }
  unenc[unenc_written++] = '\n';
  unenc[unenc_written++] = 0;
  *encoded = unenc;
  r = 0;
 done:
  if (r<0)
    tor_free(unenc);
  return r;
}

/** Encrypt the encoded introduction points in encoded using
 * authorization type  'basic' with client_cookies and write the
 * result to a newly allocated string pointed to by encrypted_out of
 * length encrypted_len_out. Return 0 for success, -1 otherwise. */
static int
rend_encrypt_v2_intro_points_basic(char **encrypted_out,
                                   size_t *encrypted_len_out,
                                   const char *encoded,
                                   smartlist_t *client_cookies)
{
  int r = -1, i, pos, enclen, client_blocks;
  size_t len, client_entries_len;
  char *enc = NULL, iv[CIPHER_IV_LEN], *client_part = NULL,
       session_key[CIPHER_KEY_LEN];
  smartlist_t *encrypted_session_keys = NULL;
  crypto_digest_t *digest;
  crypto_cipher_t *cipher;
  tor_assert(encoded);
  tor_assert(client_cookies && smartlist_len(client_cookies) > 0);

  /* Generate session key. */
  crypto_rand(session_key, CIPHER_KEY_LEN);

  /* Determine length of encrypted introduction points including session
   * keys. */
  client_blocks = 1 + ((smartlist_len(client_cookies) - 1) /
                       REND_BASIC_AUTH_CLIENT_MULTIPLE);
  client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
                       REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
  len = 2 + client_entries_len + CIPHER_IV_LEN + strlen(encoded);
  if (client_blocks >= 256) {
    log_warn(LD_REND, "Too many clients in introduction point string.");
    goto done;
  }
  enc = tor_malloc_zero(len);
  enc[0] = 0x01; /* type of authorization. */
  enc[1] = (uint8_t)client_blocks;

  /* Encrypt with random session key. */
  enclen = crypto_cipher_encrypt_with_iv(session_key,
      enc + 2 + client_entries_len,
      CIPHER_IV_LEN + strlen(encoded), encoded, strlen(encoded));

  if (enclen < 0) {
    log_warn(LD_REND, "Could not encrypt introduction point string.");
    goto done;
  }
  memcpy(iv, enc + 2 + client_entries_len, CIPHER_IV_LEN);

  /* Encrypt session key for cookies, determine client IDs, and put both
   * in a smartlist. */
  encrypted_session_keys = smartlist_new();
  SMARTLIST_FOREACH_BEGIN(client_cookies, const char *, cookie) {
    client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
    /* Encrypt session key. */
    cipher = crypto_cipher_new(cookie);
    if (crypto_cipher_encrypt(cipher, client_part +
                                  REND_BASIC_AUTH_CLIENT_ID_LEN,
                              session_key, CIPHER_KEY_LEN) < 0) {
      log_warn(LD_REND, "Could not encrypt session key for client.");
      crypto_cipher_free(cipher);
      tor_free(client_part);
      goto done;
    }
    crypto_cipher_free(cipher);

    /* Determine client ID. */
    digest = crypto_digest_new();
    crypto_digest_add_bytes(digest, cookie, REND_DESC_COOKIE_LEN);
    crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
    crypto_digest_get_digest(digest, client_part,
                             REND_BASIC_AUTH_CLIENT_ID_LEN);
    crypto_digest_free(digest);

    /* Put both together. */
    smartlist_add(encrypted_session_keys, client_part);
  } SMARTLIST_FOREACH_END(cookie);

  /* Add some fake client IDs and encrypted session keys. */
  for (i = (smartlist_len(client_cookies) - 1) %
           REND_BASIC_AUTH_CLIENT_MULTIPLE;
       i < REND_BASIC_AUTH_CLIENT_MULTIPLE - 1; i++) {
    client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
    crypto_rand(client_part, REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
    smartlist_add(encrypted_session_keys, client_part);
  }
  /* Sort smartlist and put elements in result in order. */
  smartlist_sort_digests(encrypted_session_keys);
  pos = 2;
  SMARTLIST_FOREACH(encrypted_session_keys, const char *, entry, {
    memcpy(enc + pos, entry, REND_BASIC_AUTH_CLIENT_ENTRY_LEN);
    pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
  });
  *encrypted_out = enc;
  *encrypted_len_out = len;
  enc = NULL; /* prevent free. */
  r = 0;
 done:
  tor_free(enc);
  if (encrypted_session_keys) {
    SMARTLIST_FOREACH(encrypted_session_keys, char *, d, tor_free(d););
    smartlist_free(encrypted_session_keys);
  }
  return r;
}

/** Encrypt the encoded introduction points in encoded using
 * authorization type 'stealth' with descriptor_cookie of length
 * REND_DESC_COOKIE_LEN and write the result to a newly allocated string
 * pointed to by encrypted_out of length encrypted_len_out.
 * Return 0 for success, -1 otherwise. */
static int
rend_encrypt_v2_intro_points_stealth(char **encrypted_out,
                                     size_t *encrypted_len_out,
                                     const char *encoded,
                                     const char *descriptor_cookie)
{
  int r = -1, enclen;
  char *enc;
  tor_assert(encoded);
  tor_assert(descriptor_cookie);

  enc = tor_malloc_zero(1 + CIPHER_IV_LEN + strlen(encoded));
  enc[0] = 0x02; /* Auth type */
  enclen = crypto_cipher_encrypt_with_iv(descriptor_cookie,
                                         enc + 1,
                                         CIPHER_IV_LEN+strlen(encoded),
                                         encoded, strlen(encoded));
  if (enclen < 0) {
    log_warn(LD_REND, "Could not encrypt introduction point string.");
    goto done;
  }
  *encrypted_out = enc;
  *encrypted_len_out = enclen;
  enc = NULL; /* prevent free */
  r = 0;
 done:
  tor_free(enc);
  return r;
}

/** Attempt to parse the given desc_str and return true if this
 * succeeds, false otherwise. */
static int
rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc)
{
  rend_service_descriptor_t *test_parsed = NULL;
  char test_desc_id[DIGEST_LEN];
  char *test_intro_content = NULL;
  size_t test_intro_size;
  size_t test_encoded_size;
  const char *test_next;
  int res = rend_parse_v2_service_descriptor(&test_parsed, test_desc_id,
                                         &test_intro_content,
                                         &test_intro_size,
                                         &test_encoded_size,
                                         &test_next, desc->desc_str, 1);
  rend_service_descriptor_free(test_parsed);
  tor_free(test_intro_content);
  return (res >= 0);
}

/** Free the storage held by an encoded v2 service descriptor. */
void
rend_encoded_v2_service_descriptor_free(
  rend_encoded_v2_service_descriptor_t *desc)
{
  if (!desc)
    return;
  tor_free(desc->desc_str);
  tor_free(desc);
}

/** Free the storage held by an introduction point info. */
void
rend_intro_point_free(rend_intro_point_t *intro)
{
  if (!intro)
    return;

  extend_info_free(intro->extend_info);
  crypto_pk_free(intro->intro_key);

  if (intro->accepted_intro_rsa_parts != NULL) {
    replaycache_free(intro->accepted_intro_rsa_parts);
  }

  tor_free(intro);
}

/** Encode a set of rend_encoded_v2_service_descriptor_t's for desc
 * at time now using service_key, depending on
 * auth_type a descriptor_cookie and a list of
 * client_cookies (which are both NULL if no client
 * authorization is performed), and period (e.g. 0 for the current
 * period, 1 for the next period, etc.) and add them to the existing list
 * descs_out; return the number of seconds that the descriptors will
 * be found by clients, or -1 if the encoding was not successful. */
int
rend_encode_v2_descriptors(smartlist_t *descs_out,
                           rend_service_descriptor_t *desc, time_t now,
                           uint8_t period, rend_auth_type_t auth_type,
                           crypto_pk_t *client_key,
                           smartlist_t *client_cookies)
{
  char service_id[DIGEST_LEN];
  char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1];
  uint32_t time_period;
  char *ipos_base64 = NULL, *ipos = NULL, *ipos_encrypted = NULL,
       *descriptor_cookie = NULL;
  size_t ipos_len = 0, ipos_encrypted_len = 0;
  int k;
  uint32_t seconds_valid;
  crypto_pk_t *service_key;
  if (!desc) {
    log_warn(LD_BUG, "Could not encode v2 descriptor: No desc given.");
    return -1;
  }
  service_key = (auth_type == REND_STEALTH_AUTH) ? client_key : desc->pk;
  tor_assert(service_key);
  if (auth_type == REND_STEALTH_AUTH) {
    descriptor_cookie = smartlist_get(client_cookies, 0);
    tor_assert(descriptor_cookie);
  }
  /* Obtain service_id from public key. */
  crypto_pk_get_digest(service_key, service_id);
  /* Calculate current time-period. */
  time_period = get_time_period(now, period, service_id);
  /* Determine how many seconds the descriptor will be valid. */
  seconds_valid = period * REND_TIME_PERIOD_V2_DESC_VALIDITY +
                  get_seconds_valid(now, service_id);
  /* Assemble, possibly encrypt, and encode introduction points. */
  if (smartlist_len(desc->intro_nodes) > 0) {
    if (rend_encode_v2_intro_points(&ipos, desc) < 0) {
      log_warn(LD_REND, "Encoding of introduction points did not succeed.");
      return -1;
    }
    switch (auth_type) {
      case REND_NO_AUTH:
        ipos_len = strlen(ipos);
        break;
      case REND_BASIC_AUTH:
        if (rend_encrypt_v2_intro_points_basic(&ipos_encrypted,
                                               &ipos_encrypted_len, ipos,
                                               client_cookies) < 0) {
          log_warn(LD_REND, "Encrypting of introduction points did not "
                            "succeed.");
          tor_free(ipos);
          return -1;
        }
        tor_free(ipos);
        ipos = ipos_encrypted;
        ipos_len = ipos_encrypted_len;
        break;
      case REND_STEALTH_AUTH:
        if (rend_encrypt_v2_intro_points_stealth(&ipos_encrypted,
                                                 &ipos_encrypted_len, ipos,
                                                 descriptor_cookie) < 0) {
          log_warn(LD_REND, "Encrypting of introduction points did not "
                            "succeed.");
          tor_free(ipos);
          return -1;
        }
        tor_free(ipos);
        ipos = ipos_encrypted;
        ipos_len = ipos_encrypted_len;
        break;
      default:
        log_warn(LD_REND|LD_BUG, "Unrecognized authorization type %d",
                 (int)auth_type);
        tor_free(ipos);
        return -1;
    }
    /* Base64-encode introduction points. */
    ipos_base64 = tor_calloc(ipos_len, 2);
    if (base64_encode(ipos_base64, ipos_len * 2, ipos, ipos_len,
                      BASE64_ENCODE_MULTILINE)<0) {
      log_warn(LD_REND, "Could not encode introduction point string to "
               "base64. length=%d", (int)ipos_len);
      tor_free(ipos_base64);
      tor_free(ipos);
      return -1;
    }
    tor_free(ipos);
  }
  /* Encode REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS descriptors. */
  for (k = 0; k < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; k++) {
    char secret_id_part[DIGEST_LEN];
    char secret_id_part_base32[REND_SECRET_ID_PART_LEN_BASE32 + 1];
    char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
    char *permanent_key = NULL;
    size_t permanent_key_len;
    char published[ISO_TIME_LEN+1];
    int i;
    char protocol_versions_string[16]; /* max len: "0,1,2,3,4,5,6,7\0" */
    size_t protocol_versions_written;
    size_t desc_len;
    char *desc_str = NULL;
    int result = 0;
    size_t written = 0;
    char desc_digest[DIGEST_LEN];
    rend_encoded_v2_service_descriptor_t *enc =
      tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
    /* Calculate secret-id-part = h(time-period | cookie | replica). */
    get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie,
                             k);
    base32_encode(secret_id_part_base32, sizeof(secret_id_part_base32),
                  secret_id_part, DIGEST_LEN);
    /* Calculate descriptor ID. */
    rend_get_descriptor_id_bytes(enc->desc_id, service_id, secret_id_part);
    base32_encode(desc_id_base32, sizeof(desc_id_base32),
                  enc->desc_id, DIGEST_LEN);
    /* PEM-encode the public key */
    if (crypto_pk_write_public_key_to_string(service_key, &permanent_key,
                                             &permanent_key_len) < 0) {
      log_warn(LD_BUG, "Could not write public key to string.");
      rend_encoded_v2_service_descriptor_free(enc);
      goto err;
    }
    /* Encode timestamp. */
    format_iso_time(published, desc->timestamp);
    /* Write protocol-versions bitmask to comma-separated value string. */
    protocol_versions_written = 0;
    for (i = 0; i < 8; i++) {
      if (desc->protocols & 1 <intro_nodes) * 1000; /* far too long,
                                                                  but okay.*/
    enc->desc_str = desc_str = tor_malloc_zero(desc_len);
    result = tor_snprintf(desc_str, desc_len,
             "rendezvous-service-descriptor %s\n"
             "version 2\n"
             "permanent-key\n%s"
             "secret-id-part %s\n"
             "publication-time %s\n"
             "protocol-versions %s\n",
        desc_id_base32,
        permanent_key,
        secret_id_part_base32,
        published,
        protocol_versions_string);
    tor_free(permanent_key);
    if (result < 0) {
      log_warn(LD_BUG, "Descriptor ran out of room.");
      rend_encoded_v2_service_descriptor_free(enc);
      goto err;
    }
    written = result;
    /* Add introduction points. */
    if (ipos_base64) {
      result = tor_snprintf(desc_str + written, desc_len - written,
                            "introduction-points\n"
                            "-----BEGIN MESSAGE-----\n%s"
                            "-----END MESSAGE-----\n",
                            ipos_base64);
      if (result < 0) {
        log_warn(LD_BUG, "could not write introduction points.");
        rend_encoded_v2_service_descriptor_free(enc);
        goto err;
      }
      written += result;
    }
    /* Add signature. */
    strlcpy(desc_str + written, "signature\n", desc_len - written);
    written += strlen(desc_str + written);
    if (crypto_digest(desc_digest, desc_str, written) < 0) {
      log_warn(LD_BUG, "could not create digest.");
      rend_encoded_v2_service_descriptor_free(enc);
      goto err;
    }
    if (router_append_dirobj_signature(desc_str + written,
                                       desc_len - written,
                                       desc_digest, DIGEST_LEN,
                                       service_key) < 0) {
      log_warn(LD_BUG, "Couldn't sign desc.");
      rend_encoded_v2_service_descriptor_free(enc);
      goto err;
    }
    written += strlen(desc_str+written);
    if (written+2 > desc_len) {
        log_warn(LD_BUG, "Could not finish desc.");
        rend_encoded_v2_service_descriptor_free(enc);
        goto err;
    }
    desc_str[written++] = 0;
    /* Check if we can parse our own descriptor. */
    if (!rend_desc_v2_is_parsable(enc)) {
      log_warn(LD_BUG, "Could not parse my own descriptor: %s", desc_str);
      rend_encoded_v2_service_descriptor_free(enc);
      goto err;
    }
    smartlist_add(descs_out, enc);
    /* Add the uploaded descriptor to the local service's descriptor cache */
    rend_cache_store_v2_desc_as_service(enc->desc_str);
    base32_encode(service_id_base32, sizeof(service_id_base32),
          service_id, REND_SERVICE_ID_LEN);
    control_event_hs_descriptor_created(service_id_base32, desc_id_base32, k);
  }

  log_info(LD_REND, "Successfully encoded a v2 descriptor and "
                    "confirmed that it is parsable.");
  goto done;

 err:
  SMARTLIST_FOREACH(descs_out, rend_encoded_v2_service_descriptor_t *, d,
                    rend_encoded_v2_service_descriptor_free(d););
  smartlist_clear(descs_out);
  seconds_valid = -1;

 done:
  tor_free(ipos_base64);
  return seconds_valid;
}

/** Sets out to the first 10 bytes of the digest of pk,
 * base32 encoded.  NUL-terminates out.  (We use this string to
 * identify services in directory requests and .onion URLs.)
 */
int
rend_get_service_id(crypto_pk_t *pk, char *out)
{
  char buf[DIGEST_LEN];
  tor_assert(pk);
  if (crypto_pk_get_digest(pk, buf) < 0)
    return -1;
  base32_encode(out, REND_SERVICE_ID_LEN_BASE32+1, buf, REND_SERVICE_ID_LEN);
  return 0;
}

/** Return true iff query is a syntactically valid service ID (as
 * generated by rend_get_service_id).  */
int
rend_valid_service_id(const char *query)
{
  if (strlen(query) != REND_SERVICE_ID_LEN_BASE32)
    return 0;

  if (strspn(query, BASE32_CHARS) != REND_SERVICE_ID_LEN_BASE32)
    return 0;

  return 1;
}

/** Return true iff query is a syntactically valid descriptor ID.
 * (as generated by rend_get_descriptor_id_bytes). */
int
rend_valid_descriptor_id(const char *query)
{
  if (strlen(query) != REND_DESC_ID_V2_LEN_BASE32) {
    goto invalid;
  }
  if (strspn(query, BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) {
    goto invalid;
  }

  return 1;

 invalid:
  return 0;
}

/** Called when we get a rendezvous-related relay cell on circuit
 * circ.  Dispatch on rendezvous relay command. */
void
rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
                        int command, size_t length,
                        const uint8_t *payload)
{
  or_circuit_t *or_circ = NULL;
  origin_circuit_t *origin_circ = NULL;
  int r = -2;
  if (CIRCUIT_IS_ORIGIN(circ)) {
    origin_circ = TO_ORIGIN_CIRCUIT(circ);
    if (!layer_hint || layer_hint != origin_circ->cpath->prev) {
      log_fn(LOG_PROTOCOL_WARN, LD_APP,
             "Relay cell (rend purpose %d) from wrong hop on origin circ",
             command);
      origin_circ = NULL;
    }
  } else {
    or_circ = TO_OR_CIRCUIT(circ);
  }

  switch (command) {
    case RELAY_COMMAND_ESTABLISH_INTRO:
      if (or_circ)
        r = rend_mid_establish_intro(or_circ,payload,length);
      break;
    case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
      if (or_circ)
        r = rend_mid_establish_rendezvous(or_circ,payload,length);
      break;
    case RELAY_COMMAND_INTRODUCE1:
      if (or_circ)
        r = rend_mid_introduce(or_circ,payload,length);
      break;
    case RELAY_COMMAND_INTRODUCE2:
      if (origin_circ)
        r = rend_service_receive_introduction(origin_circ,payload,length);
      break;
    case RELAY_COMMAND_INTRODUCE_ACK:
      if (origin_circ)
        r = rend_client_introduction_acked(origin_circ,payload,length);
      break;
    case RELAY_COMMAND_RENDEZVOUS1:
      if (or_circ)
        r = rend_mid_rendezvous(or_circ,payload,length);
      break;
    case RELAY_COMMAND_RENDEZVOUS2:
      if (origin_circ)
        r = rend_client_receive_rendezvous(origin_circ,payload,length);
      break;
    case RELAY_COMMAND_INTRO_ESTABLISHED:
      if (origin_circ)
        r = rend_service_intro_established(origin_circ,payload,length);
      break;
    case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
      if (origin_circ)
        r = rend_client_rendezvous_acked(origin_circ,payload,length);
      break;
    default:
      tor_fragile_assert();
  }

  if (r == -2)
    log_info(LD_PROTOCOL, "Dropping cell (type %d) for wrong circuit type.",
             command);
}

/** Allocate and return a new rend_data_t with the same
 * contents as query. */
rend_data_t *
rend_data_dup(const rend_data_t *data)
{
  rend_data_t *data_dup;
  tor_assert(data);
  data_dup = tor_memdup(data, sizeof(rend_data_t));
  data_dup->hsdirs_fp = smartlist_new();
  SMARTLIST_FOREACH(data->hsdirs_fp, char *, fp,
                    smartlist_add(data_dup->hsdirs_fp,
                                  tor_memdup(fp, DIGEST_LEN)));
  return data_dup;
}

/** Compute descriptor ID for each replicas and save them. A valid onion
 * address must be present in the rend_data.
 *
 * Return 0 on success else -1. */
static int
compute_desc_id(rend_data_t *rend_data)
{
  int ret = 0;
  unsigned replica;
  time_t now = time(NULL);

  tor_assert(rend_data);

  /* Compute descriptor ID for each replicas. */
  for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id);
       replica++) {
    ret = rend_compute_v2_desc_id(rend_data->descriptor_id[replica],
                                  rend_data->onion_address,
                                  rend_data->descriptor_cookie,
                                  now, replica);
    if (ret < 0) {
      goto end;
    }
  }

 end:
  return ret;
}

/** Allocate and initialize a rend_data_t object for a service using the
 * given arguments. Only the onion_address is not optional.
 *
 * Return a valid rend_data_t pointer. */
rend_data_t *
rend_data_service_create(const char *onion_address, const char *pk_digest,
                         const uint8_t *cookie, rend_auth_type_t auth_type)
{
  rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));

  /* We need at least one else the call is wrong. */
  tor_assert(onion_address != NULL);

  if (pk_digest) {
    memcpy(rend_data->rend_pk_digest, pk_digest,
           sizeof(rend_data->rend_pk_digest));
  }
  if (cookie) {
    memcpy(rend_data->rend_cookie, cookie,
           sizeof(rend_data->rend_cookie));
  }

  strlcpy(rend_data->onion_address, onion_address,
          sizeof(rend_data->onion_address));
  rend_data->auth_type = auth_type;
  /* Won't be used but still need to initialize it for rend_data dup and
   * free. */
  rend_data->hsdirs_fp = smartlist_new();

  return rend_data;
}

/** Allocate and initialize a rend_data_t object for a client request using
 * the given arguments.  Either an onion address or a descriptor ID is
 * needed. Both can be given but only the onion address will be used to make
 * the descriptor fetch.
 *
 * Return a valid rend_data_t pointer or NULL on error meaning the
 * descriptor IDs couldn't be computed from the given data. */
rend_data_t *
rend_data_client_create(const char *onion_address, const char *desc_id,
                        const char *cookie, rend_auth_type_t auth_type)
{
  rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));

  /* We need at least one else the call is wrong. */
  tor_assert(onion_address != NULL || desc_id != NULL);

  if (cookie) {
    memcpy(rend_data->descriptor_cookie, cookie,
           sizeof(rend_data->descriptor_cookie));
  }
  if (desc_id) {
    memcpy(rend_data->desc_id_fetch, desc_id,
           sizeof(rend_data->desc_id_fetch));
  }
  if (onion_address) {
    strlcpy(rend_data->onion_address, onion_address,
            sizeof(rend_data->onion_address));
    if (compute_desc_id(rend_data) < 0) {
      goto error;
    }
  }

  rend_data->auth_type = auth_type;
  rend_data->hsdirs_fp = smartlist_new();

  return rend_data;

 error:
  rend_data_free(rend_data);
  return NULL;
}

/** Determine the routers that are responsible for id (binary) and
 * add pointers to those routers' routerstatus_t to responsible_dirs.
 * Return -1 if we're returning an empty smartlist, else return 0.
 */
int
hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
                                     const char *id)
{
  int start, found, n_added = 0, i;
  networkstatus_t *c = networkstatus_get_latest_consensus();
  if (!c || !smartlist_len(c->routerstatus_list)) {
    log_warn(LD_REND, "We don't have a consensus, so we can't perform v2 "
             "rendezvous operations.");
    return -1;
  }
  tor_assert(id);
  start = networkstatus_vote_find_entry_idx(c, id, &found);
  if (start == smartlist_len(c->routerstatus_list)) start = 0;
  i = start;
  do {
    routerstatus_t *r = smartlist_get(c->routerstatus_list, i);
    if (r->is_hs_dir) {
      smartlist_add(responsible_dirs, r);
      if (++n_added == REND_NUMBER_OF_CONSECUTIVE_REPLICAS)
        return 0;
    }
    if (++i == smartlist_len(c->routerstatus_list))
      i = 0;
  } while (i != start);

  /* Even though we don't have the desired number of hidden service
   * directories, be happy if we got any. */
  return smartlist_len(responsible_dirs) ? 0 : -1;
}


text:
<h1 class="title">
    {{title}}
</h1>
<graph-component></graph-component>


text:
/**
 * @provides changeset-view-manager
 * @requires javelin-dom
 *           javelin-util
 *           javelin-stratcom
 *           javelin-install
 *           javelin-workflow
 *           javelin-router
 *           javelin-behavior-device
 *           javelin-vector
 */

JX.install('ChangesetViewManager', {

  construct : function(node) {
    this._node = node;

    var data = this._getNodeData();
    this._renderURI = data.renderURI;
    this._ref = data.ref;
    this._whitespace = data.whitespace;
    this._renderer = data.renderer;
    this._highlight = data.highlight;
    this._encoding = data.encoding;
  },

  members: {
    _node: null,
    _loaded: false,
    _sequence: 0,
    _stabilize: false,

    _renderURI: null,
    _ref: null,
    _whitespace: null,
    _renderer: null,
    _highlight: null,
    _encoding: null,

    /**
     * Has the content of this changeset been loaded?
     *
     * This method returns `true` if a request has been fired, even if the
     * response has not returned yet.
     *
     * @return bool True if the content has been loaded.
     */
    isLoaded: function() {
      return this._loaded;
    },

    /**
     * Configure stabilization of the document position on content load.
     *
     * When we dump the changeset into the document, we can try to stabilize
     * the document scroll position so that the user doesn't feel like they
     * are jumping around as things load in. This is generally useful when
     * populating initial changes.
     *
     * However, if a user explicitly requests a content load by clicking a
     * "Load" link or using the dropdown menu, this stabilization generally
     * feels unnatural, so we don't use it in response to explicit user action.
     *
     * @param bool  True to stabilize the next content fill.
     * @return this
     */
    setStabilize: function(stabilize) {
      this._stabilize = stabilize;
      return this;
    },

    /**
     * Should this changeset load immediately when the page loads?
     *
     * Normally, changes load immediately, but if a diff or commit is very
     * large we stop doing this and have the user load files explicitly, or
     * choose to load everything.
     *
     * @return bool True if the changeset should load automatically when the
     *   page loads.
     */
    shouldAutoload: function() {
      return this._getNodeData().autoload;
    },

    /**
     * Load this changeset, if it isn't already loading.
     *
     * This fires a request to fill the content of this changeset, provided
     * there isn't already a request in flight. To force a reload, use
     * @{method:reload}.
     *
     * @return this
     */
    load: function() {
      if (this._loaded) {
        return this;
      }

      return this.reload();
    },

    /**
     * Reload the changeset content.
     *
     * This method always issues a request, even if the content is already
     * loading. To load conditionally, use @{method:load}.
     *
     * @return this
     */
    reload: function() {
      this._loaded = true;
      this._sequence++;

      var params = {
        ref: this._ref,
        whitespace: this._whitespace || '',
        renderer: this.getRenderer() || '',
        highlight: this._highlight || '',
        encoding: this._encoding || ''
      };

      var workflow = new JX.Workflow(this._renderURI, params)
        .setHandler(JX.bind(this, this._onresponse, this._sequence));

      var routable = workflow.getRoutable();

      routable
        .setPriority(500)
        .setType('content')
        .setKey(this._getRoutableKey());

      JX.Router.getInstance().queue(routable);

      JX.DOM.setContent(
        this._getContentFrame(),
        JX.$N(
          'div',
          {className: 'differential-loading'},
          'Loading...'));

      return this;
    },

    /**
     * Get the active @{class:JX.Routable} for this changeset.
     *
     * After issuing a request with @{method:load} or @{method:reload}, you
     * can adjust routable settings (like priority) by querying the routable
     * with this method. Note that there may not be a current routable.
     *
     * @return JX.Routable|null Active routable, if one exists.
     */
    getRoutable: function() {
      return JX.Router.getInstance().getRoutableByKey(this._getRoutableKey());
    },

    setRenderer: function(renderer) {
      this._renderer = renderer;
      return this;
    },

    getRenderer: function() {
      if (this._renderer !== null) {
        return this._renderer;
      }

      // TODO: This is a big pile of TODOs.

      // NOTE: If you load the page at one device resolution and then resize to
      // a different one we don't re-render the diffs, because it's a
      // complicated mess and you could lose inline comments, cursor positions,
      // etc.
      var renderer = (JX.Device.getDevice() == 'desktop') ? '2up' : '1up';

      // TODO: Once 1up works better, figure out when to show it.
      renderer = '2up';

      return renderer;
    },

    setEncoding: function(encoding) {
      this._encoding = encoding;
      return this;
    },

    getEncoding: function() {
      return this._encoding;
    },

    setHighlight: function(highlight) {
      this._highlight = highlight;
      return this;
    },

    getHighlight: function() {
      return this._highlight;
    },

    _getNodeData: function() {
      return JX.Stratcom.getData(this._node);
    },

    _onresponse: function(sequence, response) {
      if (sequence != this._sequence) {
        // If this isn't the most recent request, ignore it. This normally
        // means the user changed view settings between the time the page loaded
        // and the content filled.
        return;
      }

      // As we populate the changeset list, we try to hold the document scroll
      // position steady, so that, e.g., users who want to leave a comment on a
      // diff with a large number of changes don't constantly have the text
      // area scrolled off the bottom of the screen until the entire diff loads.
      //
      // There are two three major cases here:
      //
      //  - If we're near the top of the document, never scroll.
      //  - If we're near the bottom of the document, always scroll.
      //  - Otherwise, scroll if the changes were above the midline of the
      //    viewport.

      var target = this._node;

      var old_pos = JX.Vector.getScroll();
      var old_view = JX.Vector.getViewport();
      var old_dim = JX.Vector.getDocument();

      // Number of pixels away from the top or bottom of the document which
      // count as "nearby".
      var sticky = 480;

      var near_top = (old_pos.y <= sticky);
      var near_bot = ((old_pos.y + old_view.y) >= (old_dim.y - sticky));

      var target_pos = JX.Vector.getPos(target);
      var target_dim = JX.Vector.getDim(target);
      var target_mid = (target_pos.y + (target_dim.y / 2));

      var view_mid = (old_pos.y + (old_view.y / 2));
      var above_mid = (target_mid < view_mid);

      var frame = this._getContentFrame();
      JX.DOM.setContent(frame, JX.$H(response.changeset));

      if (this._stabilize) {
        if (!near_top) {
          if (near_bot || above_mid) {
            // Figure out how much taller the document got.
            var delta = (JX.Vector.getDocument().y - old_dim.y);
            JX.DOM.scrollToPosition(old_pos.x, old_pos.y + delta);
          }
        }
        this._stabilize = false;
      }

      if (response.coverage) {
        for (var k in response.coverage) {
          try {
            JX.DOM.replace(JX.$(k), JX.$H(response.coverage[k]));
          } catch (ignored) {
            // Not terribly important.
          }
        }
      }
    },

    _getContentFrame: function() {
      return JX.DOM.find(this._node, 'div', 'changeset-view-content');
    },

    _getRoutableKey: function() {
      return 'changeset-view.' + this._ref + '.' + this._sequence;
    }

  },

  statics: {
    getForNode: function(node) {
      var data = JX.Stratcom.getData(node);
      if (!data.changesetViewManager) {
        data.changesetViewManager = new JX.ChangesetViewManager(node);
      }
      return data.changesetViewManager;
    }
  }
});


text:
import del from 'del'
import gulp from 'gulp'
import nodemon from 'gulp-nodemon'
import webpack from 'webpack-stream'
import less from 'gulp-less'
import watch from 'gulp-watch'
import sourcemaps from 'gulp-sourcemaps'

gulp.task('clean', () =>
  del(['dist/'])
)

gulp.task('server', ['clean'], () =>
  nodemon({
    script: 'index.js',
    ignore: ['dist/**'],
    ext: 'js,jsx'
  })
)

gulp.task('webpack', ['clean'], () =>
  gulp.src('client.js')
    .pipe(webpack({
      module: {
        loaders: [
          { test: /\.css$/, loader: 'style!css' },
          { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }
        ]
      },
      output: { filename: 'bundle.js' },
      devtool: 'source-map',
      watch: true
    }))
    .pipe(gulp.dest('dist/'))
)

gulp.task('styles', ['clean'], () =>
  gulp.src('assets/styles/**/*.less')
    .pipe(watch('assets/styles/**/*.less', { verbose: true }))
    .pipe(sourcemaps.init())
    .pipe(less())
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('dist/styles/'))
)

gulp.task('default', ['server', 'webpack', 'styles'])


text:
[![Build Status](https://travis-ci.org/avarteqgmbh/bankleitzahl.png?branch=master)](https://travis-ci.org/avarteqgmbh/bankleitzahl)

# Bankleitzahl

- fetch Bankleitzahlendatei from bundesbank.de
- load and parse Bankleitzahlendatei

## Installation

Add this line to your application's Gemfile:

    gem 'bankleitzahl'

## Bankleitzahldatei

Get the current Bankleitzahldatei from
http://www.bundesbank.de/Navigation/DE/Kerngeschaeftsfelder/Unbarer_Zahlungsverkehr/Bankleitzahlen/bankleitzahlen.html

There is a *Merkblatt Bankleitzahlendatei* describing the file format.

## Examples

``` ruby
content_lines = Bankleitzahl::Fetcher.current_lines # remote http request

bank = Bankleitzahl::Parser.new(content_lines).all_banks.first
bank.blz #=> "10000001"
bank.name #=> "Bundesbank"
bank.short_name #=> "BBk Berlin"
bank.zip #=> "10591"
bank.city #=> "Berlin"
bank.bic #=> "MARKDEF1100"
```


text:
package de.vandermeer.skb.interfaces.strategies.collections.list;

import java.util.Collection;
import java.util.Vector;

import de.vandermeer.skb.interfaces.strategies.collections.IsListStrategy;

/**
 * Strategy for a vector.
 *
 * @author     Sven van der Meer <vdmeer.sven@mykolab.com>
 * @version    v0.0.2 build 170502 (02-May-17) for Java 1.8
 * @since      v0.0.1
 */
public interface VectorStrategy<T> extends IsListStrategy<Vector<T>, T> {

	@Override
	default Vector<T> get(Collection<T> collection) {
		Vector<T> ret = new Vector<T>();
		if(collection!=null){
			ret.addAll(collection);
		}
		return ret;
	}

	@Override
	default Vector<T> get(){
		return  new Vector<T>();
	}

	/**
	 * Creates a new vector strategy.
	 * @param <T> type for the objects in the list
	 * @return new vector strategy
	 */
	static <T> VectorStrategy<T> create(){
		return new VectorStrategy<T>(){};
	}
}


text:
@interface MONFriendTrendsViewController : UIViewController

@end


text:
<?php

namespace Proto\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Proto\Mapper\SuppliesMapper;

/**
 * Factory to create a supplies mapper
 */
class SuppliesMapperFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        /* @var \Proto\Options\ModuleOptions $moduleOptions */
        $moduleOptions = $serviceLocator->get('Proto\Options\ModuleOptions');

        $entityManager = $serviceLocator->get('doctrine.entitymanager.orm_default');

        /* @var \Proto\Mapper\SuppliesMapper $mapper */
        $mapper = new SuppliesMapper($entityManager);

        $mapper->setModuleOptions($moduleOptions);
        return $mapper;
    }
}


text:
FROM david/centos7-base-mongodb-3-server

MAINTAINER David Cuellar, davidokun99@gmail.com

ENTRYPOINT mongod


text:
"use strict";
var TestFixture = require('./support'),
    r = TestFixture.r,
    expect = require('chai').expect;

var test = new TestFixture();
describe('String Manipulation', function() {
  before(function() { return test.setup(); });
  after(function() { return test.teardown(); });

  describe('#match', function() {
    it('should work', function() {
      return r.expr("hello").match("hello")
        .then(function(result) {
          expect(result).to.eql({ end: 5, groups: [], start: 0, str: 'hello' });
        });
    });

    it('should throw if no arguments are passed', function() {
      var invalid = function() { return r.expr("foo").match(); };
      expect(invalid).to.throw(/takes 1 argument, 0 provided/);
    });
  });

  describe('#split', function() {
    it('should work', function() {
      return r.expr("foo  bar bax").split()
        .then(function(result) { expect(result).to.eql(['foo', 'bar', 'bax']); });
    });

    it('should support specifying a separator', function() {
      return r.expr('12,37,,22,').split(',')
        .then(function(result) { expect(result).to.eql(['12', '37', '', '22', '']); });
    });

    it('should support specifying a separator and max occurances', function() {
      return r.expr('foo  bar bax').split(null, 1)
        .then(function(result) { expect(result).to.eql(['foo', 'bar bax']); });
    });
  });

  describe('#upcase', function() {
    it('should work', function() {
      return r.expr("helLo").upcase()
        .then(function(result) { expect(result).to.equal('HELLO'); });
    });
  });

  describe('#downcase', function() {
    it('should work', function() {
      return r.expr("HElLo").downcase()
        .then(function(result) { expect(result).to.equal('hello'); });
    });
  });

});


text:
import stainless.lang._
import stainless.proof._
import stainless.collection._

object Lists5 {
  sealed abstract class Option[T]
  case class Some[T](value: T) extends Option[T]
  case class None[T]() extends Option[T]

  def find[T](f: T => Boolean, list: List[T]): Option[T] = list match {
    case Cons(head, tail) => if (f(head)) Some(head) else find(f, tail)
    case Nil() => None()
  }

  def exists[T](f: T => Boolean, list: List[T]): Boolean = list match {
    case Cons(head, tail) => f(head) || exists(f, tail)
    case Nil() => false
  }

  def equivalence_lemma[T](f: T => Boolean, list: List[T]): Boolean = {
    find(f, list) match {
      case Some(e) => exists(f, list)
      case None() => !exists(f, list)
    }
  }

  def equivalence_lemma_induct[T](f: T => Boolean, list: List[T]): Boolean = {
    equivalence_lemma(f, list) because (list match {
      case Cons(head, tail) => equivalence_lemma_induct(f, tail)
      case Nil() => true
    })
  }.holds
}


text:
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

using System;
using System.Reactive.Disposables;
using System.Reactive.PlatformServices;
using System.Globalization;

namespace System.Reactive.Concurrency
{
    /// <summary>
    /// Provides a set of static properties to access commonly used schedulers.
    /// </summary>
    public static partial class Scheduler
    {
        // TODO - Review whether this is too eager.
        // Make first use of Scheduler trigger access to and initialization of the CAL.
        private static DefaultScheduler s_default = DefaultScheduler.Instance;

        /// <summary>
        /// Gets the current time according to the local machine's system clock.
        /// </summary>
        public static DateTimeOffset Now
        {
            get
            {
                return SystemClock.UtcNow;
            }
        }

        /// <summary>
        /// Normalizes the specified TimeSpan value to a positive value.
        /// </summary>
        /// <param name="timeSpan">The TimeSpan value to normalize.</param>
        /// <returns>The specified TimeSpan value if it is zero or positive; otherwise, TimeSpan.Zero.</returns>
        public static TimeSpan Normalize(TimeSpan timeSpan)
        {
            if (timeSpan.Ticks < 0)
                return TimeSpan.Zero;
            return timeSpan;
        }

        /// <summary>
        /// Gets a scheduler that schedules work immediately on the current thread.
        /// </summary>
        public static ImmediateScheduler Immediate
        {
            get
            {
                return ImmediateScheduler.Instance;
            }
        }

        /// <summary>
        /// Gets a scheduler that schedules work as soon as possible on the current thread.
        /// </summary>
        public static CurrentThreadScheduler CurrentThread
        {
            get
            {
                return CurrentThreadScheduler.Instance;
            }
        }

        /// <summary>
        /// Gets a scheduler that schedules work on the platform's default scheduler.
        /// </summary>
        public static DefaultScheduler Default
        {
            get
            {
                return s_default;
            }
        }

        //
        // Notice we include all of the scheduler properties below, unconditionally. In Rx v2.0
        // beta and RC, we limited this a la carte menu to reflect the platform's capabilities.
        // However, this caused different builds for Windows 8, .NET 4.5, and Portable Library
        // to be required. In the RTM timeframe, we opted for unifying all of this based on a
        // single Portable Library build of the core set of assemblies. As such, we're presented
        // with a choice of either locking down those properties to the intersection, or keeping
        // compatibility for those who upgrade from.NET 4.0 to .NET 4.5. We chose the latter, so
        // we need to keep properties like NewThread here, even though they'll be obsolete from
        // day 0 of Rx v2.0 (including our Portable Library story). Also, the NewThread one will
        // be non-functional for Windows 8, causing a runtime exception to be thrown.
        //

        private static Lazy<IScheduler> s_threadPool = new Lazy<IScheduler>(() => Initialize("ThreadPool"));

        /// <summary>
        /// Gets a scheduler that schedules work on the thread pool.
        /// </summary>
        [Obsolete(Constants_Core.OBSOLETE_SCHEDULER_THREADPOOL)]
        public static IScheduler ThreadPool
        {
            get
            {
                return s_threadPool.Value;
            }
        }

        private static Lazy<IScheduler> s_newThread = new Lazy<IScheduler>(() => Initialize("NewThread"));

        /// <summary>
        /// Gets a scheduler that schedules work on a new thread using default thread creation options.
        /// </summary>
        [Obsolete(Constants_Core.OBSOLETE_SCHEDULER_NEWTHREAD)]
        public static IScheduler NewThread
        {
            get
            {
                return s_newThread.Value;
            }
        }

#if !NO_TPL
        private static Lazy<IScheduler> s_taskPool = new Lazy<IScheduler>(() => Initialize("TaskPool"));

        /// <summary>
        /// Gets a scheduler that schedules work on Task Parallel Library (TPL) task pool using the default TaskScheduler.
        /// </summary>
        [Obsolete(Constants_Core.OBSOLETE_SCHEDULER_TASKPOOL)]
        public static IScheduler TaskPool
        {
            get
            {
                return s_taskPool.Value;
            }
        }
#endif

        private static IScheduler Initialize(string name)
        {
            var res = PlatformEnlightenmentProvider.Current.GetService<IScheduler>(name);
            if (res == null)
                throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings_Core.CANT_OBTAIN_SCHEDULER, name));
            return res;
        }
    }
}


text:
<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>

	<name>SpringBootBasics</name>
	<url>https://github.com/ldebello/javacuriosities/tree/master/Spring/SpringBootBasics</url>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.4.RELEASE</version>
	</parent>

	<groupId>ar.com.javacuriosities</groupId>
	<artifactId>SpringBootBasics</artifactId>
	<version>1.0.0-SNAPSHOT</version>

	<properties>
		<java.version>1.8</java.version>
		<mysql.connector.java>8.0.22</mysql.connector.java>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

		<dependency>
			<groupId>org.flywaydb</groupId>
			<artifactId>flyway-core</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.connector.java}</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<!-- Package as an executable jar/war -->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>