text:
/*
 * SChannel is designed to encrypt and decrypt data in place.  So a
 * given buffer is expected to sometimes contain encrypted data,
 * sometimes decrypted data, and occasionally both.  Outgoing buffers
 * need to reserve space for the TLS header and trailer.  Read
 * operations need to ignore the same headers and trailers from
 * incoming buffers.  Outgoing is simple because we choose record
 * boundaries.  Incoming is complicated by handling incomplete TLS
 * records, and buffering contiguous data for the app layer that may
 * span many records.  A lazy double buffering system is used for
 * the latter.
 */

#include <proton/ssl.h>
#include <proton/engine.h>
#include "engine/engine-internal.h"
#include "platform.h"
#include "util.h"

#include <assert.h>

// security.h needs to see this to distinguish from kernel use.
#include <windows.h>
#define SECURITY_WIN32
#include <security.h>
#include <Schnlsp.h>
#undef SECURITY_WIN32

/** @file
 * SSL/TLS support API.
 *
 * This file contains an SChannel-based implemention of the SSL/TLS API for Windows platforms.
 */

#define SSL_DATA_SIZE 16384
#define SSL_BUF_SIZE (SSL_DATA_SIZE + 5 + 2048 + 32)

typedef enum { UNKNOWN_CONNECTION, SSL_CONNECTION, CLEAR_CONNECTION } connection_mode_t;
typedef struct pn_ssl_session_t pn_ssl_session_t;

struct pn_ssl_domain_t {
  int ref_count;
  pn_ssl_mode_t mode;
  bool has_ca_db;       // true when CA database configured
  bool has_certificate; // true when certificate configured
  char *keyfile_pw;

  // settings used for all connections
  pn_ssl_verify_mode_t verify_mode;
  bool allow_unsecured;

  // SChannel
  HCERTSTORE cert_store;
  PCCERT_CONTEXT cert_context;
  SCHANNEL_CRED credential;
};

typedef enum { CREATED, CLIENT_HELLO, NEGOTIATING,
               RUNNING, SHUTTING_DOWN, SSL_CLOSED } ssl_state_t;

struct pn_ssl_t {
  pn_transport_t   *transport;
  pn_io_layer_t    *io_layer;
  pn_ssl_domain_t  *domain;
  const char    *session_id;
  const char *peer_hostname;
  ssl_state_t state;

  bool queued_shutdown;
  bool ssl_closed;            // shutdown complete, or SSL error
  ssize_t app_input_closed;   // error code returned by upper layer process input
  ssize_t app_output_closed;  // error code returned by upper layer process output

  // OpenSSL hides the protocol envelope bytes, SChannel has them in-line.
  char *sc_outbuf;     // SChannel output buffer
  size_t sc_out_size;
  size_t sc_out_count;
  char *network_outp;   // network ready bytes within sc_outbuf
  size_t network_out_pending;

  char *sc_inbuf;      // SChannel input buffer
  size_t sc_in_size;
  size_t sc_in_count;
  bool sc_in_incomplete;

  char *inbuf_extra;    // Still encrypted data from following Record(s)
  size_t extra_count;

  char *in_data;          // Just the plaintext data part of sc_inbuf, decrypted in place
  size_t in_data_size;
  size_t in_data_count;
  bool decrypting;
  size_t max_data_size;  // computed in the handshake

  pn_bytes_t app_inbytes; // Virtual decrypted datastream, presented to app layer

  pn_buffer_t *inbuf2;    // Second input buf if longer contiguous bytes needed
  bool double_buffered;

  bool sc_input_shutdown;

  pn_trace_t trace;

  CredHandle cred_handle;
  CtxtHandle ctxt_handle;
  SecPkgContext_StreamSizes sc_sizes;
};

struct pn_ssl_session_t {
  const char       *id;
// TODO
  pn_ssl_session_t *ssn_cache_next;
  pn_ssl_session_t *ssn_cache_prev;
};

static ssize_t process_input_ssl( pn_io_layer_t *io_layer, const char *input_data, size_t len);
static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *input_data, size_t len);
static ssize_t process_input_unknown( pn_io_layer_t *io_layer, const char *input_data, size_t len);
static ssize_t process_output_unknown( pn_io_layer_t *io_layer, char *input_data, size_t len);
static ssize_t process_input_done(pn_io_layer_t *io_layer, const char *input_data, size_t len);
static ssize_t process_output_done(pn_io_layer_t *io_layer, char *input_data, size_t len);
static connection_mode_t check_for_ssl_connection( const char *data, size_t len );
static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *, const char * );
static void ssl_session_free( pn_ssl_session_t *);
static size_t buffered_output( pn_io_layer_t *io_layer );
static size_t buffered_input( pn_io_layer_t *io_layer );
static void start_ssl_shutdown(pn_ssl_t *ssl);
static void rewind_sc_inbuf(pn_ssl_t *ssl);
static bool grow_inbuf2(pn_ssl_t *ssl, size_t minimum_size);

// @todo: used to avoid littering the code with calls to printf...
static void ssl_log_error(const char *fmt, ...)
{
  va_list ap;
  va_start(ap, fmt);
  vfprintf(stderr, fmt, ap);
  va_end(ap);
  fflush(stderr);
}

// @todo: used to avoid littering the code with calls to printf...
static void ssl_log(pn_ssl_t *ssl, const char *fmt, ...)
{
  if (PN_TRACE_DRV & ssl->trace) {
    va_list ap;
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fflush(stderr);
  }
}

static void ssl_log_error_status(HRESULT status, const char *fmt, ...)
{
  char buf[512];
  va_list ap;

  if (fmt) {
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
  }

  if (FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
                    0, status, 0, buf, sizeof(buf), 0))
    ssl_log_error("%s\n", buf);
  else
    fprintf(stderr, "pn internal Windows error: %lu\n", GetLastError());

  fflush(stderr);
}

static void ssl_log_clear_data(pn_ssl_t *ssl, const char *data, size_t len)
{
  if (PN_TRACE_RAW & ssl->trace) {
    fprintf(stderr, "SSL decrypted data: \"");
    pn_fprint_data( stderr, data, len );
    fprintf(stderr, "\"\n");
  }
}

static size_t _pni_min(size_t a, size_t b)
{
  return (a < b) ? a : b;
}

// unrecoverable SSL failure occured, notify transport and generate error code.
static int ssl_failed(pn_ssl_t *ssl, const char *reason)
{
  char buf[512] = "Unknown error.";
  if (!reason) {
    HRESULT status = GetLastError();

    FormatMessage(FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM,
                  0, status, 0, buf, sizeof(buf), 0);
    reason = buf;
  }
  ssl->ssl_closed = true;
  ssl->app_input_closed = ssl->app_output_closed = PN_EOS;
  ssl->state = SSL_CLOSED;
  pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: %s", reason);
  return PN_EOS;
}

/* match the DNS name pattern from the peer certificate against our configured peer
   hostname */
static bool match_dns_pattern( const char *hostname,
                               const char *pattern, int plen )
{
  return false; // TODO
}

static pn_ssl_session_t *ssn_cache_find( pn_ssl_domain_t *domain, const char *id )
{
// TODO:
  return NULL;
}

static void ssl_session_free( pn_ssl_session_t *ssn)
{
  if (ssn) {
    if (ssn->id) free( (void *)ssn->id );
    free( ssn );
  }
}

/** Public API - visible to application code */

pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode )
{
  if (mode == PN_SSL_MODE_SERVER)
    return NULL;  // Temporary: not ready for ctest, hide from isSSLPresent()
  pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t));
  if (!domain) return NULL;

  memset(domain, 0, sizeof(domain));
  domain->credential.dwVersion = SCHANNEL_CRED_VERSION;
  domain->credential.dwFlags = SCH_CRED_NO_DEFAULT_CREDS;

  domain->ref_count = 1;
  domain->mode = mode;
  switch(mode) {
  case PN_SSL_MODE_CLIENT:
    // TODO
    break;

  case PN_SSL_MODE_SERVER:
    // TODO
    break;

  default:
    ssl_log_error("Invalid mode for pn_ssl_mode_t: %d\n", mode);
    free(domain);
    return NULL;
  }

  return domain;
}

void pn_ssl_domain_free( pn_ssl_domain_t *domain )
{
  if (!domain) return;

  if (--domain->ref_count == 0) {
    if (domain->cert_context)
      CertFreeCertificateContext(domain->cert_context);
    if (domain->cert_store)
      CertCloseStore(domain->cert_store, CERT_CLOSE_STORE_FORCE_FLAG);

    if (domain->keyfile_pw) free(domain->keyfile_pw);
    free(domain);
  }
}

int pn_ssl_domain_set_credentials( pn_ssl_domain_t *domain,
                               const char *certificate_file,
                               const char *private_key_file,
                               const char *password)
{
  if (!domain) return -1;

  // TODO:

  return 0;
}

int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain,
                                    const char *certificate_db)
{
  if (!domain) return -1;
  // TODO: support for alternate ca db? or just return -1
  domain->has_ca_db = true;
  return 0;
}

int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain,
                                          const pn_ssl_verify_mode_t mode,
                                          const char *trusted_CAs)
{
  if (!domain) return -1;

  switch (mode) {
  case PN_SSL_VERIFY_PEER:
  case PN_SSL_VERIFY_PEER_NAME:
    // TODO
    break;

  case PN_SSL_ANONYMOUS_PEER:   // hippie free love mode... :)
    // TODO
    break;

  default:
    ssl_log_error( "Invalid peer authentication mode given.\n" );
    return -1;
  }

  domain->verify_mode = mode;
  return 0;
}

int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_domain_t *domain, const char *session_id)
{
  if (!ssl || !domain || ssl->domain) return -1;
  if (ssl->state != CREATED) return -1;

  ssl->domain = domain;
  domain->ref_count++;
  if (domain->allow_unsecured) {
    ssl->io_layer->process_input = process_input_unknown;
    ssl->io_layer->process_output = process_output_unknown;
  } else {
    ssl->io_layer->process_input = process_input_ssl;
    ssl->io_layer->process_output = process_output_ssl;
  }

  if (session_id && domain->mode == PN_SSL_MODE_CLIENT)
    ssl->session_id = pn_strdup(session_id);

  TimeStamp cred_expiry;
  SECURITY_STATUS status = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND,
                               NULL, &domain->credential, NULL, NULL, &ssl->cred_handle,
                               &cred_expiry);
  if (status != SEC_E_OK) {
    ssl_log_error_status(status, "AcquireCredentialsHandle");
    return -1;
  }

  ssl->state = (domain->mode == PN_SSL_MODE_CLIENT) ? CLIENT_HELLO : NEGOTIATING;
  return 0;
}

int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain)
{
  if (!domain) return -1;
  if (domain->mode != PN_SSL_MODE_SERVER) {
    ssl_log_error("Cannot permit unsecured clients - not a server.\n");
    return -1;
  }
  domain->allow_unsecured = true;
  return 0;
}

bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *buffer, size_t size )
{
  *buffer = '\0';
  snprintf( buffer, size, "%s", "TODO: cipher_name" );
  return true;
}

bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *buffer, size_t size )
{
  *buffer = '\0';
  snprintf( buffer, size, "%s", "TODO: protocol name" );
  return true;
}

void pn_ssl_free( pn_ssl_t *ssl)
{
  if (!ssl) return;
  ssl_log( ssl, "SSL socket freed.\n" );
  // clean up Windows per TLS session data before releasing the domain count
  if (SecIsValidHandle(&ssl->ctxt_handle))
    DeleteSecurityContext(&ssl->ctxt_handle);
  if (SecIsValidHandle(&ssl->cred_handle))
    FreeCredentialsHandle(&ssl->cred_handle);

  if (ssl->domain) pn_ssl_domain_free(ssl->domain);
  if (ssl->session_id) free((void *)ssl->session_id);
  if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
  if (ssl->sc_inbuf) free((void *)ssl->sc_inbuf);
  if (ssl->sc_outbuf) free((void *)ssl->sc_outbuf);
  if (ssl->inbuf2) pn_buffer_free(ssl->inbuf2);
  free(ssl);
}

pn_ssl_t *pn_ssl(pn_transport_t *transport)
{
  if (!transport) return NULL;
  if (transport->ssl) return transport->ssl;

  pn_ssl_t *ssl = (pn_ssl_t *) calloc(1, sizeof(pn_ssl_t));
  if (!ssl) return NULL;
  ssl->sc_out_size = ssl->sc_in_size = SSL_BUF_SIZE;

  ssl->sc_outbuf = (char *)malloc(ssl->sc_out_size);
  if (!ssl->sc_outbuf) {
    free(ssl);
    return NULL;
  }
  ssl->sc_inbuf = (char *)malloc(ssl->sc_in_size);
  if (!ssl->sc_inbuf) {
    free(ssl->sc_outbuf);
    free(ssl);
    return NULL;
  }

  ssl->inbuf2 = pn_buffer(0);
  if (!ssl->inbuf2) {
    free(ssl->sc_inbuf);
    free(ssl->sc_outbuf);
    free(ssl);
    return NULL;
  }

  ssl->transport = transport;
  transport->ssl = ssl;

  ssl->io_layer = &transport->io_layers[PN_IO_SSL];
  ssl->io_layer->context = ssl;
  ssl->io_layer->process_input = pn_io_layer_input_passthru;
  ssl->io_layer->process_output = pn_io_layer_output_passthru;
  ssl->io_layer->process_tick = pn_io_layer_tick_passthru;
  ssl->io_layer->buffered_output = buffered_output;
  ssl->io_layer->buffered_input = buffered_input;

  ssl->trace = (transport->disp) ? transport->disp->trace : PN_TRACE_OFF;
  SecInvalidateHandle(&ssl->cred_handle);
  SecInvalidateHandle(&ssl->ctxt_handle);
  ssl->state = CREATED;
  ssl->decrypting = true;

  return ssl;
}

void pn_ssl_trace(pn_ssl_t *ssl, pn_trace_t trace)
{
  ssl->trace = trace;
}

pn_ssl_resume_status_t pn_ssl_resume_status( pn_ssl_t *ssl )
{
  // TODO
  return PN_SSL_RESUME_UNKNOWN;
}

int pn_ssl_set_peer_hostname( pn_ssl_t *ssl, const char *hostname )
{
  if (!ssl) return -1;

  if (ssl->peer_hostname) free((void *)ssl->peer_hostname);
  ssl->peer_hostname = NULL;
  if (hostname) {
    ssl->peer_hostname = pn_strdup(hostname);
    if (!ssl->peer_hostname) return -2;
  }
  return 0;
}

int pn_ssl_get_peer_hostname( pn_ssl_t *ssl, char *hostname, size_t *bufsize )
{
  if (!ssl) return -1;
  if (!ssl->peer_hostname) {
    *bufsize = 0;
    if (hostname) *hostname = '\0';
    return 0;
  }
  unsigned len = strlen(ssl->peer_hostname);
  if (hostname) {
    if (len >= *bufsize) return -1;
    strcpy( hostname, ssl->peer_hostname );
  }
  *bufsize = len;
  return 0;
}

/** SChannel specific: */

const char *tls_version_check(pn_ssl_t *ssl)
{
  SecPkgContext_ConnectionInfo info;
  QueryContextAttributes(&ssl->ctxt_handle, SECPKG_ATTR_CONNECTION_INFO, &info);
  // Ascending bit patterns denote newer SSL/TLS protocol versions.
  // SP_PROT_TLS1_0_SERVER is not defined until VS2010.
  return (info.dwProtocol < SP_PROT_TLS1_SERVER) ?
    "peer does not support TLS 1.0 security" : NULL;
}

static void ssl_encrypt(pn_ssl_t *ssl, char *app_data, size_t count)
{
  // Get SChannel to encrypt exactly one Record.
  SecBuffer buffs[4];
  buffs[0].cbBuffer = ssl->sc_sizes.cbHeader;
  buffs[0].BufferType = SECBUFFER_STREAM_HEADER;
  buffs[0].pvBuffer = ssl->sc_outbuf;
  buffs[1].cbBuffer = count;
  buffs[1].BufferType = SECBUFFER_DATA;
  buffs[1].pvBuffer = app_data;
  buffs[2].cbBuffer = ssl->sc_sizes.cbTrailer;
  buffs[2].BufferType = SECBUFFER_STREAM_TRAILER;
  buffs[2].pvBuffer = &app_data[count];
  buffs[3].cbBuffer = 0;
  buffs[3].BufferType = SECBUFFER_EMPTY;
  buffs[3].pvBuffer = 0;
  SecBufferDesc buff_desc;
  buff_desc.ulVersion = SECBUFFER_VERSION;
  buff_desc.cBuffers = 4;
  buff_desc.pBuffers = buffs;
  SECURITY_STATUS status = EncryptMessage(&ssl->ctxt_handle, 0, &buff_desc, 0);
  assert(status == SEC_E_OK);

  // EncryptMessage encrypts the data in place. The header and trailer
  // areas were reserved previously and must now be included in the updated
  // count of bytes to write to the peer.
  ssl->sc_out_count = buffs[0].cbBuffer + buffs[1].cbBuffer + buffs[2].cbBuffer;
  ssl->network_outp = ssl->sc_outbuf;
  ssl->network_out_pending = ssl->sc_out_count;
  ssl_log(ssl, "ssl_encrypt %d network bytes\n", ssl->network_out_pending);
}

// Returns true if decryption succeeded (even for empty content)
static bool ssl_decrypt(pn_ssl_t *ssl)
{
  // Get SChannel to decrypt input.  May have an incomplete Record,
  // exactly one, or more than one.  Check also for session ending,
  // session renegotiation.

  SecBuffer recv_buffs[4];
  recv_buffs[0].cbBuffer = ssl->sc_in_count;
  recv_buffs[0].BufferType = SECBUFFER_DATA;
  recv_buffs[0].pvBuffer = ssl->sc_inbuf;
  recv_buffs[1].BufferType = SECBUFFER_EMPTY;
  recv_buffs[2].BufferType = SECBUFFER_EMPTY;
  recv_buffs[3].BufferType = SECBUFFER_EMPTY;
  SecBufferDesc buff_desc;
  buff_desc.ulVersion = SECBUFFER_VERSION;
  buff_desc.cBuffers = 4;
  buff_desc.pBuffers = recv_buffs;
  SECURITY_STATUS status = ::DecryptMessage(&ssl->ctxt_handle, &buff_desc, 0, NULL);

  if (status == SEC_E_INCOMPLETE_MESSAGE) {
    // Less than a full Record, come back later with more network data
    ssl->sc_in_incomplete = true;
    return false;
  }

  ssl->decrypting = false;

  if (status != SEC_E_OK) {
    rewind_sc_inbuf(ssl);
    switch (status) {
    case SEC_I_CONTEXT_EXPIRED:
      // TLS shutdown alert record.  Ignore all subsequent input.
      ssl->state = SHUTTING_DOWN;
      ssl->sc_input_shutdown = true;
      return false;

    case SEC_I_RENEGOTIATE:
      // TODO.  Fall through for now.
    default:
      ssl_failed(ssl, 0);
      return false;
    }
  }

  ssl->decrypting = false;
  // have a decrypted Record and possible (still-encrypted) data of
  // one (or more) later Recordss.  Adjust pointers accordingly.
  for (int i = 0; i < 4; i++) {
    switch (recv_buffs[i].BufferType) {
    case SECBUFFER_DATA:
      ssl->in_data = (char *) recv_buffs[i].pvBuffer;
      ssl->in_data_size = ssl->in_data_count = recv_buffs[i].cbBuffer;
      break;
    case SECBUFFER_EXTRA:
      ssl->inbuf_extra = (char *)recv_buffs[i].pvBuffer;
      ssl->extra_count = recv_buffs[i].cbBuffer;
      break;
    default:
      // SECBUFFER_STREAM_HEADER:
      // SECBUFFER_STREAM_TRAILER:
      break;
    }
  }
  return true;
}

static void client_handshake_init(pn_ssl_t *ssl)
{
  // Tell SChannel to create the first handshake token (ClientHello)
  // and place it in sc_outbuf
  SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
  ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS;
  ULONG ctxt_attrs;

  SecBuffer send_buffs[2];
  send_buffs[0].cbBuffer = ssl->sc_out_size;
  send_buffs[0].BufferType = SECBUFFER_TOKEN;
  send_buffs[0].pvBuffer = ssl->sc_outbuf;
  send_buffs[1].cbBuffer = 0;
  send_buffs[1].BufferType = SECBUFFER_EMPTY;
  send_buffs[1].pvBuffer = 0;
  SecBufferDesc send_buff_desc;
  send_buff_desc.ulVersion = SECBUFFER_VERSION;
  send_buff_desc.cBuffers = 2;
  send_buff_desc.pBuffers = send_buffs;
  SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
                               NULL, host, ctxt_requested, 0, 0, NULL, 0,
                               &ssl->ctxt_handle, &send_buff_desc,
                               &ctxt_attrs, NULL);

  if (status == SEC_I_CONTINUE_NEEDED) {
    ssl->sc_out_count = send_buffs[0].cbBuffer;
    ssl->network_out_pending = ssl->sc_out_count;
    // the token is the whole quantity to send
    ssl->network_outp = ssl->sc_outbuf;
    ssl_log(ssl, "Sending client hello %d bytes\n", ssl->network_out_pending);
  } else {
    ssl_log_error_status(status, "InitializeSecurityContext failed");
    ssl_failed(ssl, 0);
  }
}

static void client_handshake( pn_ssl_t* ssl) {
  // Feed SChannel ongoing responses from the server until the handshake is complete.
  SEC_CHAR *host = const_cast<SEC_CHAR *>(ssl->peer_hostname);
  ULONG ctxt_requested = ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS;
  ULONG ctxt_attrs;
  size_t max = 0;

  // token_buffs describe the buffer that's coming in. It should have
  // a token from the SSL server, or empty if sending final shutdown alert.
  bool shutdown = ssl->state == SHUTTING_DOWN;
  SecBuffer token_buffs[2];
  token_buffs[0].cbBuffer = shutdown ? 0 : ssl->sc_in_count;
  token_buffs[0].BufferType = SECBUFFER_TOKEN;
  token_buffs[0].pvBuffer = shutdown ? 0 : ssl->sc_inbuf;
  token_buffs[1].cbBuffer = 0;
  token_buffs[1].BufferType = SECBUFFER_EMPTY;
  token_buffs[1].pvBuffer = 0;
  SecBufferDesc token_buff_desc;
  token_buff_desc.ulVersion = SECBUFFER_VERSION;
  token_buff_desc.cBuffers = 2;
  token_buff_desc.pBuffers = token_buffs;

  // send_buffs will hold information to forward to the peer.
  SecBuffer send_buffs[2];
  send_buffs[0].cbBuffer = ssl->sc_out_size;
  send_buffs[0].BufferType = SECBUFFER_TOKEN;
  send_buffs[0].pvBuffer = ssl->sc_outbuf;
  send_buffs[1].cbBuffer = 0;
  send_buffs[1].BufferType = SECBUFFER_EMPTY;
  send_buffs[1].pvBuffer = 0;
  SecBufferDesc send_buff_desc;
  send_buff_desc.ulVersion = SECBUFFER_VERSION;
  send_buff_desc.cBuffers = 2;
  send_buff_desc.pBuffers = send_buffs;

  SECURITY_STATUS status = InitializeSecurityContext(&ssl->cred_handle,
                               &ssl->ctxt_handle, host, ctxt_requested, 0, 0,
                               &token_buff_desc, 0, NULL, &send_buff_desc,
                               &ctxt_attrs, NULL);
  switch (status) {
  case SEC_E_INCOMPLETE_MESSAGE:
    // Not enough - get more data from the server then try again.
    // Leave input buffers untouched.
    ssl_log(ssl, "client handshake: incomplete record\n");
    ssl->sc_in_incomplete = true;
    return;

  case SEC_I_CONTINUE_NEEDED:
    // Successful handshake step, requiring data to be sent to peer.
    // TODO: check if server has requested a client certificate
    ssl->sc_out_count = send_buffs[0].cbBuffer;
    // the token is the whole quantity to send
    ssl->network_out_pending = ssl->sc_out_count;
    ssl->network_outp = ssl->sc_outbuf;
    ssl_log(ssl, "client handshake token %d bytes\n", ssl->network_out_pending);
    break;

  case SEC_E_OK:
    // Handshake complete.
    if (shutdown) {
      if (send_buffs[0].cbBuffer > 0) {
        ssl->sc_out_count = send_buffs[0].cbBuffer;
        // the token is the whole quantity to send
        ssl->network_out_pending = ssl->sc_out_count;
        ssl->network_outp = ssl->sc_outbuf;
        ssl_log(ssl, "client shutdown token %d bytes\n", ssl->network_out_pending);
      } else {
        ssl->state = SSL_CLOSED;
      }
      // we didn't touch sc_inbuf, no need to reset
      return;
    }
    if (send_buffs[0].cbBuffer != 0) {
      ssl_failed(ssl, "unexpected final server token");
      break;
    }
    if (const char *err = tls_version_check(ssl)) {
      ssl_failed(ssl, err);
      break;
    }
    if (token_buffs[1].BufferType == SECBUFFER_EXTRA && token_buffs[1].cbBuffer > 0) {
      // This seems to work but not documented, plus logic differs from decrypt message
      // since the pvBuffer value is not set.  Grrr.
      ssl->extra_count = token_buffs[1].cbBuffer;
      ssl->inbuf_extra = ssl->sc_inbuf + (ssl->sc_in_count - ssl->extra_count);
    }

    QueryContextAttributes(&ssl->ctxt_handle,
                             SECPKG_ATTR_STREAM_SIZES, &ssl->sc_sizes);
    max = ssl->sc_sizes.cbMaximumMessage + ssl->sc_sizes.cbHeader + ssl->sc_sizes.cbTrailer;
    if (max > ssl->sc_out_size) {
      ssl_log_error("Buffer size mismatch have %d, need %d\n", (int) ssl->sc_out_size, (int) max);
      ssl->state = SHUTTING_DOWN;
      ssl->app_input_closed = ssl->app_output_closed = PN_ERR;
      start_ssl_shutdown(ssl);
      pn_do_error(ssl->transport, "amqp:connection:framing-error", "SSL Failure: buffer size");
      break;
    }

    ssl->state = RUNNING;
    ssl->max_data_size = max - ssl->sc_sizes.cbHeader - ssl->sc_sizes.cbTrailer;
    ssl_log(ssl, "client handshake successful %d max record size\n", max);
    break;

  case SEC_I_CONTEXT_EXPIRED:
    // ended before we got going
  default:
    ssl_log(ssl, "client handshake failed %d\n", (int) status);
    ssl_failed(ssl, 0);
    break;
  }
  ssl->decrypting = false;
  rewind_sc_inbuf(ssl);
}

static void ssl_handshake(pn_ssl_t* ssl) {
  if (ssl->domain->mode == PN_SSL_MODE_CLIENT)
    client_handshake(ssl);
  else {
    ssl_log( ssl, "TODO: server handshake.\n" );
    ssl_failed(ssl, "internal runtime error, not yet implemented");
  }
}

static bool grow_inbuf2(pn_ssl_t *ssl, size_t minimum_size) {
  size_t old_capacity = pn_buffer_capacity(ssl->inbuf2);
  size_t new_capacity = old_capacity ? old_capacity * 2 : 1024;

  while (new_capacity < minimum_size)
    new_capacity *= 2;

  uint32_t max_frame = pn_transport_get_max_frame(ssl->transport);
  if (max_frame != 0) {
    if (old_capacity >= max_frame) {
      //  already big enough
      ssl_log(ssl, "Application expecting %d bytes (> negotiated maximum frame)\n", new_capacity);
      ssl_failed(ssl, "TLS: transport maximimum frame size error");
      return false;
    }
  }

  size_t extra_bytes = new_capacity - pn_buffer_size(ssl->inbuf2);
  int err = pn_buffer_ensure(ssl->inbuf2, extra_bytes);
  if (err) {
    ssl_log(ssl, "TLS memory allocation failed for %d bytes\n", max_frame);
    ssl_failed(ssl, "TLS memory allocation failed");
    return false;
  }
  return true;
}

// Peer initiated a session end by sending us a shutdown alert (and we should politely
// reciprocate), or else we are initiating the session end (and will not bother to wait
// for the peer shutdown alert). Stop processing input immediately, and stop processing
// output once this is sent.

static void start_ssl_shutdown(pn_ssl_t *ssl)
{
  assert(ssl->network_out_pending == 0);
  if (ssl->queued_shutdown)
    return;
  ssl->queued_shutdown = true;
  ssl_log(ssl, "Shutting down SSL connection...\n");

  DWORD shutdown = SCHANNEL_SHUTDOWN;
  SecBuffer shutBuff;
  shutBuff.cbBuffer = sizeof(DWORD);
  shutBuff.BufferType = SECBUFFER_TOKEN;
  shutBuff.pvBuffer = &shutdown;
  SecBufferDesc desc;
  desc.ulVersion = SECBUFFER_VERSION;
  desc.cBuffers = 1;
  desc.pBuffers = &shutBuff;
  ::ApplyControlToken(&ssl->ctxt_handle, &desc);

  // Next handshake will generate the shudown alert token
  ssl_handshake(ssl);
}

static int setup_ssl_connection(pn_ssl_t *ssl)
{
  ssl_log( ssl, "SSL connection detected.\n");
  ssl->io_layer->process_input = process_input_ssl;
  ssl->io_layer->process_output = process_output_ssl;
  return 0;
}

static void rewind_sc_inbuf(pn_ssl_t *ssl)
{
  // Decrypted bytes have been drained or double buffered.  Prepare for the next SSL Record.
  assert(ssl->in_data_count == 0);
  if (ssl->decrypting)
    return;
  ssl->decrypting = true;
  if (ssl->inbuf_extra) {
    // A previous read picked up more than one Record.  Move it to the beginning.
    memmove(ssl->sc_inbuf, ssl->inbuf_extra, ssl->extra_count);
    ssl->sc_in_count = ssl->extra_count;
    ssl->inbuf_extra = 0;
    ssl->extra_count = 0;
  } else {
    ssl->sc_in_count = 0;
  }
}

static void app_inbytes_add(pn_ssl_t *ssl)
{
  if (!ssl->app_inbytes.start) {
    ssl->app_inbytes.start = ssl->in_data;
    ssl->app_inbytes.size = ssl->in_data_count;
    return;
  }

  if (ssl->double_buffered) {
    if (pn_buffer_available(ssl->inbuf2) == 0) {
      if (!grow_inbuf2(ssl, 1024))
        // could not add room
        return;
    }
    size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
    pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
    ssl->in_data += count;
    ssl->in_data_count -= count;
    ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
  } else {
    assert(ssl->app_inbytes.size == 0);
    ssl->app_inbytes.start = ssl->in_data;
    ssl->app_inbytes.size = ssl->in_data_count;
  }
}

static void app_inbytes_progress(pn_ssl_t *ssl, size_t minimum)
{
  // Make more decrypted data available, if possible.  Otherwise, move
  // unread bytes to front of inbuf2 to make room for next bulk decryption.
  // SSL may have chopped up data that app layer expects to be
  // contiguous.  Start, continue or stop double buffering here.
  if (ssl->double_buffered) {
    if (ssl->app_inbytes.size == 0) {
      // no straggler bytes, optimistically stop for now
      ssl->double_buffered = false;
      pn_buffer_clear(ssl->inbuf2);
      ssl->app_inbytes.start = ssl->in_data;
      ssl->app_inbytes.size = ssl->in_data_count;
    } else {
      pn_bytes_t ib2 = pn_buffer_bytes(ssl->inbuf2);
      assert(ssl->app_inbytes.size <= ib2.size);
      size_t consumed = ib2.size - ssl->app_inbytes.size;
      if (consumed > 0) {
          memmove((void *)ib2.start, ib2.start + consumed, consumed);
        pn_buffer_trim(ssl->inbuf2, 0, consumed);
      }
      if (!pn_buffer_available(ssl->inbuf2)) {
        if (!grow_inbuf2(ssl, minimum))
          // could not add room
          return;
      }
      size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
      pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
      ssl->in_data += count;
      ssl->in_data_count -= count;
      ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
    }
  } else {
    if (ssl->app_inbytes.size) {
      // start double buffering the left over bytes
      ssl->double_buffered = true;
      pn_buffer_clear(ssl->inbuf2);
      if (!pn_buffer_available(ssl->inbuf2)) {
        if (!grow_inbuf2(ssl, minimum))
          // could not add room
          return;
      }
      size_t count = _pni_min(ssl->in_data_count, pn_buffer_available(ssl->inbuf2));
      pn_buffer_append(ssl->inbuf2, ssl->in_data, count);
      ssl->in_data += count;
      ssl->in_data_count -= count;
      ssl->app_inbytes = pn_buffer_bytes(ssl->inbuf2);
    } else {
      // already pointing at all available bytes until next decrypt
    }
  }
  if (ssl->in_data_count == 0)
    rewind_sc_inbuf(ssl);
}

static void app_inbytes_advance(pn_ssl_t *ssl, size_t consumed)
{
  if (consumed == 0) {
    // more contiguous bytes required
    app_inbytes_progress(ssl, ssl->app_inbytes.size + 1);
    return;
  }
  assert(consumed <= ssl->app_inbytes.size);
  ssl->app_inbytes.start += consumed;
  ssl->app_inbytes.size -= consumed;
  if (!ssl->double_buffered) {
    ssl->in_data += consumed;
    ssl->in_data_count -= consumed;
  }
  if (ssl->app_inbytes.size == 0)
    app_inbytes_progress(ssl, 0);
}

static void read_closed(pn_ssl_t *ssl, ssize_t error)
{
  if (ssl->app_input_closed)
    return;
  if (ssl->state == RUNNING && !error) {
    pn_io_layer_t *io_next = ssl->io_layer->next;
    // Signal end of stream
    ssl->app_input_closed = io_next->process_input(io_next, ssl->app_inbytes.start, 0);
  }
  if (!ssl->app_input_closed)
    ssl->app_input_closed = error ? error : PN_ERR;

  if (ssl->app_output_closed) {
    // both sides of app closed, and no more app output pending:
    ssl->state = SHUTTING_DOWN;
    if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
      start_ssl_shutdown(ssl);
    }
  }
}

// Read up to "available" bytes from the network, decrypt it and pass plaintext to application.

static ssize_t process_input_ssl(pn_io_layer_t *io_layer, const char *input_data, size_t available)
{
  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
  ssl_log( ssl, "process_input_ssl( data size=%d )\n",available );
  ssize_t consumed = 0;
  ssize_t forwarded = 0;
  bool new_app_input;

  if (available == 0) {
    // No more inbound network data
    read_closed(ssl,0);
    return 0;
  }

  do {
    if (ssl->sc_input_shutdown) {
      // TLS protocol shutdown detected on input
      read_closed(ssl,0);
      return consumed;
    }

    // sc_inbuf should be ready for new or additional network encrypted bytes.
    // i.e. no straggling decrypted bytes pending.
    assert(ssl->in_data_count == 0 && ssl->decrypting);
    new_app_input = false;
    size_t count;

    if (ssl->state != RUNNING) {
      count = _pni_min(ssl->sc_in_size - ssl->sc_in_count, available);
    } else {
      // look for TLS record boundaries
      if (ssl->sc_in_count < 5) {
        ssl->sc_in_incomplete = true;
        size_t hc = _pni_min(available, 5 - ssl->sc_in_count);
        memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, hc);
        ssl->sc_in_count += hc;
        input_data += hc;
        available -= hc;
        consumed += hc;
        if (ssl->sc_in_count < 5 || available == 0)
          break;
      }

      // Top up sc_inbuf from network input_data hoping for a complete TLS Record
      // We try to guess the length as an optimization, but let SChannel
      // ultimately decide if there is spoofing going on.
      unsigned char low = (unsigned char) ssl->sc_inbuf[4];
      unsigned char high = (unsigned char) ssl->sc_inbuf[3];
      size_t rec_len = high * 256 + low + 5;
      if (rec_len < 5 || rec_len == ssl->sc_in_count || rec_len > ssl->sc_in_size)
        rec_len = ssl->sc_in_size;

      count = _pni_min(rec_len - ssl->sc_in_count, available);
    }

    if (count > 0) {
      memmove(ssl->sc_inbuf + ssl->sc_in_count, input_data, count);
      ssl->sc_in_count += count;
      input_data += count;
      available -= count;
      consumed += count;
      ssl->sc_in_incomplete = false;
    }

    // Try to decrypt another TLS Record.

    if (ssl->sc_in_count > 0 && ssl->state <= SHUTTING_DOWN) {
      if (ssl->state == NEGOTIATING) {
        ssl_handshake(ssl);
      } else {
        if (ssl_decrypt(ssl)) {
          // Ignore TLS Record with 0 length data (does not mean EOS)
          if (ssl->in_data_size > 0) {
            new_app_input = true;
            app_inbytes_add(ssl);
          } else {
            assert(ssl->decrypting == false);
            rewind_sc_inbuf(ssl);
          }
        }
        ssl_log(ssl, "Next decryption, %d left over\n", available);
      }
    }

    if (ssl->state == SHUTTING_DOWN) {
      if (ssl->network_out_pending == 0 && !ssl->queued_shutdown) {
        start_ssl_shutdown(ssl);
      }
    } else if (ssl->state == SSL_CLOSED) {
      return consumed ? consumed : -1;
    }

    // Consume or discard the decrypted bytes
    if (new_app_input && (ssl->state == RUNNING || ssl->state == SHUTTING_DOWN)) {
      // present app_inbytes to io_next only if it has new content
      while (ssl->app_inbytes.size > 0) {
        if (!ssl->app_input_closed) {
          pn_io_layer_t *io_next = ssl->io_layer->next;
          ssize_t count = io_next->process_input(io_next, ssl->app_inbytes.start, ssl->app_inbytes.size);
          if (count > 0) {
            forwarded += count;
            // advance() can increase app_inbytes.size if double buffered
            app_inbytes_advance(ssl, count);
            ssl_log(ssl, "Application consumed %d bytes from peer\n", (int) count);
          } else if (count == 0) {
            size_t old_size = ssl->app_inbytes.size;
            app_inbytes_advance(ssl, 0);
            if (ssl->app_inbytes.size == old_size) {
              break;  // no additional contiguous decrypted data available, get more network data
            }
          } else {
            // count < 0
            ssl_log(ssl, "Application layer closed its input, error=%d (discarding %d bytes)\n",
                 (int) count, (int)ssl->app_inbytes.size);
            app_inbytes_advance(ssl, ssl->app_inbytes.size);    // discard
            read_closed(ssl, count);
          }
        } else {
          ssl_log(ssl, "Input closed discard %d bytes\n",
               (int)ssl->app_inbytes.size);
          app_inbytes_advance(ssl, ssl->app_inbytes.size);      // discard
        }
      }
    }
  } while (available || (ssl->sc_in_count && !ssl->sc_in_incomplete));

  if (ssl->app_input_closed && ssl->state >= SHUTTING_DOWN) {
    consumed = ssl->app_input_closed;
    ssl->io_layer->process_input = process_input_done;
  }
  ssl_log(ssl, "process_input_ssl() returning %d, forwarded %d\n", (int) consumed, (int) forwarded);
  return consumed;
}

static ssize_t process_output_ssl( pn_io_layer_t *io_layer, char *buffer, size_t max_len)
{
  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
  if (!ssl) return PN_EOS;
  ssl_log( ssl, "process_output_ssl( max_len=%d )\n",max_len );

  ssize_t written = 0;
  ssize_t total_app_bytes = 0;
  bool work_pending;

  if (ssl->state == CLIENT_HELLO) {
    // output buffers eclusively for internal handshake use until negotiation complete
    client_handshake_init(ssl);
    if (ssl->state == SSL_CLOSED)
      return PN_EOS;
    ssl->state = NEGOTIATING;
  }

  do {
    work_pending = false;

    if (ssl->network_out_pending > 0) {
      size_t wcount = _pni_min(ssl->network_out_pending, max_len);
      memmove(buffer, ssl->network_outp, wcount);
      ssl->network_outp += wcount;
      ssl->network_out_pending -= wcount;
      buffer += wcount;
      max_len -= wcount;
      written += wcount;
    }

    if (ssl->network_out_pending == 0 && ssl->state == RUNNING  && !ssl->app_output_closed) {
      // refill the buffer with app data and encrypt it

      char *app_data = ssl->sc_outbuf + ssl->sc_sizes.cbHeader;
      char *app_outp = app_data;
      size_t remaining = ssl->max_data_size;
      ssize_t app_bytes;
      do {
        pn_io_layer_t *io_next = ssl->io_layer->next;
        app_bytes = io_next->process_output(io_next, app_outp, remaining);
        if (app_bytes > 0) {
          app_outp += app_bytes;
          remaining -= app_bytes;
          ssl_log( ssl, "Gathered %d bytes from app to send to peer\n", app_bytes );
        } else {
          if (app_bytes < 0) {
            ssl_log(ssl, "Application layer closed its output, error=%d (%d bytes pending send)\n",
                 (int) app_bytes, (int) ssl->network_out_pending);
            ssl->app_output_closed = app_bytes;
            if (ssl->app_input_closed)
              ssl->state = SHUTTING_DOWN;
          } else if (total_app_bytes == 0 && ssl->app_input_closed) {
            // We've drained all the App layer can provide
            ssl_log(ssl, "Application layer blocked on input, closing\n");
            ssl->state = SHUTTING_DOWN;
            ssl->app_output_closed = PN_ERR;
          }
        }
      } while (app_bytes > 0);
      if (app_outp > app_data) {
        work_pending = (max_len > 0);
        ssl_encrypt(ssl, app_data, app_outp - app_data);
      }
    }

    if (ssl->network_out_pending == 0 && ssl->state == SHUTTING_DOWN) {
      if (!ssl->queued_shutdown) {
        start_ssl_shutdown(ssl);
        work_pending = true;
      } else {
        ssl->state = SSL_CLOSED;
      }
    }
  } while (work_pending);

  if (written == 0 && ssl->state == SSL_CLOSED) {
    written = ssl->app_output_closed ? ssl->app_output_closed : PN_EOS;
    ssl->io_layer->process_output = process_output_done;
  }
  ssl_log(ssl, "process_output_ssl() returning %d\n", (int) written);
  return written;
}

static int setup_cleartext_connection( pn_ssl_t *ssl )
{
  ssl_log( ssl, "Cleartext connection detected.\n");
  ssl->io_layer->process_input = pn_io_layer_input_passthru;
  ssl->io_layer->process_output = pn_io_layer_output_passthru;
  return 0;
}

// until we determine if the client is using SSL or not:

static ssize_t process_input_unknown(pn_io_layer_t *io_layer, const char *input_data, size_t len)
{
  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
  switch (check_for_ssl_connection( input_data, len )) {
  case SSL_CONNECTION:
    setup_ssl_connection( ssl );
    return ssl->io_layer->process_input( ssl->io_layer, input_data, len );
  case CLEAR_CONNECTION:
    setup_cleartext_connection( ssl );
    return ssl->io_layer->process_input( ssl->io_layer, input_data, len );
  default:
    return 0;
  }
}

static ssize_t process_output_unknown(pn_io_layer_t *io_layer, char *input_data, size_t len)
{
  // do not do output until we know if SSL is used or not
  return 0;
}

static connection_mode_t check_for_ssl_connection( const char *data, size_t len )
{
  if (len >= 5) {
    const unsigned char *buf = (unsigned char *)data;
    /*
     * SSLv2 Client Hello format
     * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html
     *
     * Bytes 0-1: RECORD-LENGTH
     * Byte    2: MSG-CLIENT-HELLO (1)
     * Byte    3: CLIENT-VERSION-MSB
     * Byte    4: CLIENT-VERSION-LSB
     *
     * Allowed versions:
     * 2.0 - SSLv2
     * 3.0 - SSLv3
     * 3.1 - TLS 1.0
     * 3.2 - TLS 1.1
     * 3.3 - TLS 1.2
     *
     * The version sent in the Client-Hello is the latest version supported by
     * the client. NSS may send version 3.x in an SSLv2 header for
     * maximum compatibility.
     */
    int isSSL2Handshake = buf[2] == 1 &&   // MSG-CLIENT-HELLO
      ((buf[3] == 3 && buf[4] <= 3) ||    // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)
       (buf[3] == 2 && buf[4] == 0));     // SSL 2

    /*
     * SSLv3/TLS Client Hello format
     * RFC 2246
     *
     * Byte    0: ContentType (handshake - 22)
     * Bytes 1-2: ProtocolVersion {major, minor}
     *
     * Allowed versions:
     * 3.0 - SSLv3
     * 3.1 - TLS 1.0
     * 3.2 - TLS 1.1
     * 3.3 - TLS 1.2
     */
    int isSSL3Handshake = buf[0] == 22 &&  // handshake
      (buf[1] == 3 && buf[2] <= 3);       // SSL 3.0 & TLS 1.0-1.2 (v3.1-3.3)

    if (isSSL2Handshake || isSSL3Handshake) {
      return SSL_CONNECTION;
    } else {
      return CLEAR_CONNECTION;
    }
  }
  return UNKNOWN_CONNECTION;
}

static ssize_t process_input_done(pn_io_layer_t *io_layer, const char *input_data, size_t len)
{
  return PN_EOS;
}

static ssize_t process_output_done(pn_io_layer_t *io_layer, char *input_data, size_t len)
{
  return PN_EOS;
}

// return # output bytes sitting in this layer
static size_t buffered_output(pn_io_layer_t *io_layer)
{
  size_t count = 0;
  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
  if (ssl) {
    count += ssl->network_out_pending;
    if (count == 0 && ssl->state == SHUTTING_DOWN && ssl->queued_shutdown)
      count++;
  }
  return count;
}

// return # input bytes sitting in this layer
static size_t buffered_input( pn_io_layer_t *io_layer )
{
  size_t count = 0;
  pn_ssl_t *ssl = (pn_ssl_t *)io_layer->context;
  if (ssl) {
    count += ssl->in_data_count;
  }
  return count;
}


text:
package com.fangxuele.tool.push.dao;

import com.fangxuele.tool.push.domain.TMsgSms;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface TMsgSmsMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(TMsgSms record);

    int insertSelective(TMsgSms record);

    TMsgSms selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(TMsgSms record);

    int updateByPrimaryKey(TMsgSms record);

    List<TMsgSms> selectByMsgTypeAndMsgName(@Param("msgType") int msgType, @Param("msgName") String msgName);

    int updateByMsgTypeAndMsgName(TMsgSms tMsgSms);

    List<TMsgSms> selectByMsgType(int msgType);

    int deleteByMsgTypeAndName(@Param("msgType") int msgType, @Param("msgName") String msgName);
}

redpajama_set_name: RedPajamaGithub


text:
package com.fit2cloud.aliyun.bss.model.request;

import com.fit2cloud.aliyun.PageableRequest;

public class DescribeCouponListRequest extends PageableRequest {

	private String Status = "Enable";

	public String getStatus() {
		return Status;
	}

	public void setStatus(String status) {
		Status = status;
	}

	public DescribeCouponListRequest() {
	}

}


text:
/* global __dirname */
import webpack from 'webpack';
import config from './webpack.config';
import OfflinePlugin from 'offline-plugin';
import ExtractTextPlugin from 'extract-text-webpack-plugin';

export default config({

  devtool: 'source-map',

  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    }),

    new webpack.LoaderOptionsPlugin({
      minimize: true,
      debug: false
    }),

    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
        drop_console: false
      }
    }),

    new ExtractTextPlugin('[name].css'),

    new OfflinePlugin({
      AppCache: false,
      ServiceWorker: {
          events: true
      }
    })
  ]
});


text:
layout: global
title: Alluxio Storage Management
nickname: Alluxio Storage Management
group: Advanced
priority: 0
---

* Table of Contents
{:toc}

## Alluxio Storage Overview

The purpose of this documentation is to introduce users to the concepts behind Alluxio storage and
the operations that can be performed within Alluxio storage space. For metadata related operations
such as syncing and namespaces, refer to the
[page on namespace management]({{ '/en/advanced/Namespace-Management.html' | relativize_url }})

Alluxio helps unify users' data across a variety of platforms while also helping to increase
overall I/O throughput from a user's perspective. Alluxio accomplishes this by splitting storage
into two distinct categories.

- **UFS (Under File Storage, also referred to as the under storage)**
    - This storage is represented as the space which is not managed by Alluxio.
    UFS storage may come from an external file system, including HDFS or S3.
    Alluxio may connect to one or more of these UFSs and expose them within a single namespace.
    - Typically, UFS storage is aimed at storing large amounts of data persistently for extended
    periods of time.
- **Alluxio storage**
    - Alluxio manages the local storage, including memory, of Alluxio workers to act as a
    distributed buffer cache. This fast data layer between user applications and the various under
    storages results in vastly improved I/O performance.
    - Alluxio storage is mainly aimed at storing hot, transient data and is not focused on long term
    persistence.
    - The amount and type of storage for each Alluxio node to manage is determined by user
    configuration.
    - Even if data is not currently within Alluxio storage, files within a connected UFS are still
    visible to Alluxio clients. The data is copied into Alluxio storage when a client attempts to
    read a file that is only available from a UFS.

![Alluxio storage diagram]({{ '/img/stack.png' | relativize_url }})

Alluxio storage improves performance by storing data in memory co-located with compute nodes.
Data in Alluxio storage can be replicated to make "hot" data more readily available for
I/O operations to consume in parallel.

Replicas of data within Alluxio are independent of the replicas that may exist within a UFS.
The number of data replicas within Alluxio storage is determined dynamically by cluster activity.
Due to the fact that Alluxio relies on the under file storage for a majority of data storage,
Alluxio does not need to keep copies of data that are not being used.

Alluxio also supports tiered storage, which makes the system storage media aware, enabling data
storage optimizations similar to L1/L2 cpu caches.

## Configuring Alluxio Storage

### Single-Tier Storage

The easiest way to configure Alluxio storage is to use the default single-tier mode.

Note that this page refers to local storage and terms like `mount` refer to mounting in the local
filesystem, not to be confused with Alluxio's `mount` concept for external under storages.

On startup, Alluxio will provision a ramdisk on every worker and take a percentage of the
system's total memory. This ramdisk will be used as the only storage medium allocated to each
Alluxio worker.

Alluxio storage is configured through Alluxio's configuration in `alluxio-site.properties`. See
[configuration settings]({{ '/en/basic/Configuration-Settings.html' | relativize_url }}) for detailed
information.

A common modification to the default is to explicitly set the ramdisk size. For example, to set the
ramdisk size to be 16GB on each worker:

```
alluxio.worker.memory.size=16GB
```

Another common change is to specify multiple storage media, such as ramdisk and SSDs. We will need
to update `alluxio.worker.tieredstore.level0.dirs.path` to take specify each storage medium we want
to use as a storage directory. For example, to use the ramdisk (mounted at `/mnt/ramdisk`) and two
SSDs (mounted at `/mnt/ssd1` and `/mnt/ssd2`):

```
alluxio.worker.tieredstore.level0.dirs.path=/mnt/ramdisk,/mnt/ssd1,/mnt/ssd2
```

The paths provided should point to paths in the local filesystem mounting the appropriate storage
media. To enable short circuit operations, the permissions of these paths should be permissive for the
client user to read, write, and execute on the path. For example, `770` permissions is needed for
the client user who is among the same group of the user that starts the Alluxio service.

After updating the storage media, we need to indicate how much storage is allocated for each storage
directory. For example, if we wanted to use 16 GB on the ramdisk and 100 GB on each SSD:

```
alluxio.worker.tieredstore.level0.dirs.quota=16GB,100GB,100GB
```

Note that the ordering of the quotas must match with the ordering of the paths.

There is a subtle difference between `alluxio.worker.memory.size` and
`alluxio.worker.tieredstore.level0.dirs.quota`, which defaults to the former. Alluxio will
provision and mount a ramdisk when started with the `Mount` or `SudoMount` options. This ramdisk
will have its size determined by `alluxio.worker.memory.size` regardless of the value set in
`alluxio.worker.tieredstore.level0.dirs.quota`. Similarly, the quota should be set independently
of the memory size if devices other than the default Alluxio provisioned ramdisk are to be used.

### Multiple-Tier Storage

It is typically recommended to use a single storage tier with heterogeneous storage media.
In certain environments, workloads will benefit from explicit ordering of storage media based on
I/O speed. When tiered storage is enabled, the eviction process intelligently accounts for the
ordering of tiers. Alluxio assumes that tiers are ordered from top to bottom based on I/O performance.
For example, users often specify the following tiers:

 * MEM (Memory)
 * SSD (Solid State Drives)
 * HDD (Hard Disk Drives)

#### Writing Data

When a user writes a new block, it is written to the top tier by default. If eviction cannot free up
space in the top tier, the write will fail. If the file size exceeds the size of the top tier, the
write will also fail.

The user can also specify the tier that the data will be written to via
[configuration settings](#configure-tiered-storage).

When reading data with the `ReadType.CACHE` or `ReadType.CACHE_PROMOTE`,
the data written into Alluxio is always written to the top tier.
When writing data using the load command, the data is also written to the top tier.

#### Reading Data

If the data is already in Alluxio, the client will simply read the block from where it is already stored.
If Alluxio is configured with multiple tiers, the block may not be necessarily read from the top tier,
since it could have been moved to a lower tier transparently.

Reading data with the `ReadType.CACHE_PROMOTE` will ensure the data is first transferred to the
top tier before it is read from the worker. This can also be used as a data management strategy by
explicitly moving hot data to higher tiers.

#### Configuring Tiered Storage

Tiered storage can be enabled in Alluxio using
[configuration parameters]({{ '/en/basic/Configuration-Settings.html' | relativize_url }}).
To specify additional tiers for Alluxio, use the following configuration parameters:

```
alluxio.worker.tieredstore.levels
alluxio.worker.tieredstore.level{x}.alias
alluxio.worker.tieredstore.level{x}.dirs.quota
alluxio.worker.tieredstore.level{x}.dirs.path
alluxio.worker.tieredstore.level{x}.watermark.high.ratio
alluxio.worker.tieredstore.level{x}.watermark.low.ratio
```

For example, if you wanted to configure Alluxio to have two tiers, memory and hard disk drive,
you could use a configuration similar to:

```
# configure 2 tiers in Alluxio
alluxio.worker.tieredstore.levels=2
# the first (top) tier to be a memory tier
alluxio.worker.tieredstore.level0.alias=MEM
# defined `/mnt/ramdisk` to be the file path to the first tier
alluxio.worker.tieredstore.level0.dirs.path=/mnt/ramdisk
# set the quota for the ramdisk to be `100GB`
alluxio.worker.tieredstore.level0.dirs.quota=100GB
# set the ratio of high watermark on top layer to be 90%
alluxio.worker.tieredstore.level0.watermark.high.ratio=0.9
# set the ratio of low watermark on top layer to be 70%
alluxio.worker.tieredstore.level0.watermark.low.ratio=0.7
# configure the second tier to be a hard disk tier
alluxio.worker.tieredstore.level1.alias=HDD
# configured 3 separate file paths for the second tier
alluxio.worker.tieredstore.level1.dirs.path=/mnt/hdd1,/mnt/hdd2,/mnt/hdd3
# define the quota for each of the 3 file paths of the second tier
alluxio.worker.tieredstore.level1.dirs.quota=2TB,5TB,500GB
# set the ratio of high watermark on the second layer to be 90%
alluxio.worker.tieredstore.level1.watermark.high.ratio=0.9
# set the ratio of low watermark on the second layer to be 70%
alluxio.worker.tieredstore.level1.watermark.low.ratio=0.7
```

There are no restrictions to how many tiers can be configured
but each tier must be identified with a unique alias.
A typical configuration will have three tiers for Memory, SSD, and HDD.
To use multiple hard drives in the HDD tier, specify multiple paths when configuring
`alluxio.worker.tieredstore.level{x}.dirs.path`.

## Evicting Stale Data

When Alluxio storage is full, Alluxio frees up space for new data as its storage is designed to be
volatile. Eviction is the mechanism that removes old data.

There are two modes of eviction in Alluxio: asynchronous and synchronous.

Asynchronous eviction is the default implementation of eviction. It relies on a periodic space
reserver thread in each worker to evict data. When the worker storage utilization reaches a
maximum threshold, it evicts data until the usage reaches a minimum threshold. The two thresholds
are configurable, labeled as the high and low watermarks respectively. In the case where we have
216 GB of storage on a worker, eviction can be triggered at about 200 GB to reduce storage
utilization to 160 GB by setting the high watermark to 90% and the low watermark to 75%.

```properties
alluxio.worker.tieredstore.level0.watermark.high.ratio=0.9
alluxio.worker.tieredstore.level0.watermark.low.ratio=0.75
```

Asynchronous eviction is particularly useful for write or read-cache heavy workloads.

Synchronous eviction waits for a client to request more space than is currently available on the
worker and then kicks off the eviction process to free up enough space to serve that request. This
leads to many small eviction attempts, which is less efficient, but maximizes the utilization of
available Alluxio space. Synchronous eviction is enabled by configuring the setting:

```
alluxio.worker.tieredstore.reserver.enabled=false
```

In general, it is recommended to use the default asynchronous eviction.

### Eviction Policies

Alluxio uses evictors to decide which blocks to remove from Alluxio storage.
Users can specify different Alluxio evictors to better control the eviction process.

Out-of-the-box evictor implementations include:

- **LRUEvictor**: Evicts the least-recently-used blocks until the required space is freed.
**This is Alluxio's default evictor**.
- **GreedyEvictor**: Evicts arbitrary blocks until the required space is freed.
- **LRFUEvictor**: Evicts blocks based on least-recently-used and least-frequently-used with a
configurable weight.
    - If the weight is completely biased toward least-recently-used, the behavior will be the same
    as the LRUEvictor.
    - The applicable configuration properties are `alluxio.worker.evictor.lrfu.step.factor` and
    `alluxio.worker.evictor.lrfu.attenuation.factor` which can be found in
    [configuration properties]({{ '/en/reference/Properties-List.html' | relativize_url }}#alluxio.worker.evictor.lrfu.step.factor)
- **PartialLRUEvictor** : Evicts based on a least-recently-used policy but will choose one configured
storage directory on the local worker with maximum free space and only evict from that directory.

The evictor utilized by workers is determined by the Alluxio property
[`alluxio.worker.evictor.class`]({{ '/en/reference/Properties-List.html' | relativize_url }}#alluxio.worker.evictor.class).
The property should specify the fully qualified class name within the configuration. Currently
available options are:

- `alluxio.worker.block.evictor.LRUEvictor`
- `alluxio.worker.block.evictor.GreedyEvictor`
- `alluxio.worker.block.evictor.LRFUEvictor`
- `alluxio.worker.block.evictor.PartialLRUEvictor`

When using synchronous eviction, it is recommended to use smaller block sizes (around 64-128MB),
to reduce the latency of block eviction. The block size has no effect for asynchronous eviction.

Alluxio also supports custom evictors for more fine-grained control over the eviction behavior.
Evictors must implement the
[Evictor interface](https://github.com/Alluxio/alluxio/blob/master/core/server/worker/src/main/java/alluxio/worker/block/evictor/Evictor.java).
Sample evictor implementations can be found under the `alluxio.worker.block.evictor` package.
For Alluxio to use the custom evictor, the fully qualified class name must be specified in the
`alluxio.worker.evictor.class` property. After compiling the class to a JAR file, the JAR file
needs to be accessible and added to the Alluxio worker's java classpath.

## Managing Data in Alluxio

Users should understanding the following concepts to properly utilize available resources:

- **free**: Freeing data means removing data from the Alluxio cache, but not the
underlying UFS. Data is still available to users after a free operation, but performance may be
degraded for clients who attempt to access a file after it has been freed from Alluxio.
- **load**: Loading data means copying it from a UFS into Alluxio cache. If Alluxio is using
memory-based storage, users will likely see I/O performance improvements after loading.
- **persist**: Persisting data means writing data which may or may not have
been modified within Alluxio storage back to a UFS. By writing data back to a UFS, data is
guaranteed to be recoverable if an Alluxio node goes down.
- **TTL (Time to Live)**: The TTL property sets an expiration duration on files and directories to
remove them from Alluxio space when the data exceeds its lifetime. It is also possible to configure
TTL to remove the corresponding data stored in a UFS.

### Freeing Data from Alluxio Storage

In order to manually free data in Alluxio, you can use the `./bin/alluxio` file system command
line interface.

```bash
$ ./bin/alluxio fs free ${PATH_TO_UNUSED_DATA}
```

This will remove the data at the given path from Alluxio storage. The data is still accessible if
it is persisted to a UFS. For more information refer to the
[command line interface documentation]({{ '/en/basic/Command-Line-Interface.html' | relativize_url }}#free)

Note that a user typically should not need to manually free data from Alluxio as the
configured [eviction policy](#eviction-policies) will take care of removing unused or old data.

### Loading Data into Alluxio Storage

If the data is already in a UFS, use
[`alluxio fs load`]({{ '/en/basic/Command-Line-Interface.html' | relativize_url }}#load)

```bash
$ ./bin/alluxio fs load ${PATH_TO_FILE}
```

To load data from the local file system, use the
[command `copyFromLocal`]({{ '/en/basic/Command-Line-Interface.html' | relativize_url }}#copyfromlocal).
This will only load the file into Alluxio storage, but may not persist the data to a UFS.
Setting the write type to `MUST_CACHE` write type will _not_ persist data to a UFS,
whereas `CACHE` and `CACHE_THROUGH` will. Manually loading data is not recommended as Alluxio
will automatically load data into the Alluxio cache when a file is used for the first time.

### Persisting Data in Alluxio

[The `alluxio fs persist`]({{ '/en/basic/Command-Line-Interface.html' | relativize_url }}#persist)
command allows a user to push data from the Alluxio cache to a UFS.

```bash
$ ./bin/alluxio fs persist ${PATH_TO_FILE}
```

This command is useful if you have data which you loaded into Alluxio which did not originate from
a configured UFS. Users should not need to worry about manually persisting data in most cases.

### Setting Time to Live (TTL)

Alluxio supports a `Time to Live (TTL)` setting on each file and directory in its namespace. This
feature can be used to effectively manage the Alluxio cache, especially in environments with strict
guarantees on the data access patterns. For example, if analytics is run on the last week of
ingested data, the TTL feature can be used to explicitly flush old data to free the cache for new
files.

Alluxio has TTL attributes associated with each file or directory. These attributes are saved as
part of the journal and persist across cluster restarts. The active master node is responsible for
holding the metadata in memory when Alluxio is serving. Internally, the master runs a background
thread which periodically checks if files have reached their TTL expiration.

Note that the background thread runs on a configurable period, which is set to an hour by default.
Data that has reached its TTL expiration immediately after a check will not be removed until the
next check interval an hour later.

To set the interval to 10 minutes, add the following to `alluxio-site.properties`:

```
alluxio.master.ttl.checker.interval=10m
```

Refer to the [configuration page]({{ '/en/basic/Configuration-Settings.html' | relativize_url }})
for more details on setting Alluxio configurations.

#### APIs

There are two ways to set the TTL attributes of a path.

1. Through the Alluxio shell command line
1. Passively on each load metadata or create file

The TTL API is as follows:

```
SetTTL(path, duration, action)
`path`          the path in the Alluxio namespace
`duration`      the number of milliseconds before the TTL action goes into effect, this overrides
                any previous value
`action`        the action to take when duration has elapsed. `FREE` will cause the file to be
                evicted from Alluxio storage, regardless of the pin status. `DELETE` will cause the
                file to be deleted from the Alluxio namespace and under store.
                NOTE: `DELETE` is the default for certain commands and will cause the file to be
                permanently removed.
```

#### Command Line Usage

See the detailed
[command line documentation]({{ '/en/basic/Command-Line-Interface.html' | relativize_url }}#setttl)
to see how to use the `setTtl` command within the Alluxio shell to modify TTL attribute.

#### Passively on load metadata or create file

The Alluxio client can be configured to add TTL attributes whenever it adds a new file to the
Alluxio namespace. Passive TTL is useful in cases where files accessed by the user are expected to
be temporarily used, but it is not flexible because all requests from the same client will inherit
the same TTL attributes.

Passive TTL works with the following configuration options:

* `alluxio.user.file.load.ttl` - The TTL duration to set on any file newly loaded into Alluxio
from an under store. By default, no TTL duration is set.
* `alluxio.user.file.load.ttl.action` - The TTL action to set on any file newly loaded into Alluxio
from an under store. By default, this action is `DELETE`.
* `alluxio.user.file.create.ttl` - The TTL duration to set on any file newly created in Alluxio.
By default, no TTL duration is set.
* `alluxio.user.file.create.ttl.action` - The TTL action to set on any file newly created
in Alluxio. By default, this action is `DELETE`.

There are two pairs of options, one for `load` and one for `create`. `Load` refers to files which
are discovered by Alluxio from the under store. `Create` refers to new files or directories created
in Alluxio.

Both options are disabled by default and should only be enabled by clients which have strict data
access patterns.

For example, to delete the files created by the `runTests` after 3 minutes:

```bash
$ bin/alluxio runTests -Dalluxio.user.file.create.ttl=3m -Dalluxio.user.file.create.ttl
.action=DELETE
```

For this example, ensure the `alluxio.master.ttl.checker.interval` is set to a short
duration, such as a minute, in order for the the master to quickly identify the expired files.

## Checking Alluxio Cache Capacity and Usage

The Alluxio shell command `fsadmin report` provides a short summary of space availability,
along with other useful information. A sample output is shown below:

```bash
$ ./bin/alluxio fsadmin report
Alluxio cluster summary:
    Master Address: localhost/127.0.0.1:19998
    Web Port: 19999
    Rpc Port: 19998
    Started: 09-28-2018 12:52:09:486
    Uptime: 0 day(s), 0 hour(s), 0 minute(s), and 26 second(s)
    Version: 1.8.0
    Safe Mode: true
    Zookeeper Enabled: false
    Live Workers: 1
    Lost Workers: 0
    Total Capacity: 10.67GB
        Tier: MEM  Size: 10.67GB
    Used Capacity: 0B
        Tier: MEM  Size: 0B
    Free Capacity: 10.67GB
```

The Alluxio shell also allows a user to check how much space is available and in use within
the Alluxio cache.

To get the total used bytes in the Alluxio cache:

```bash
$ ./bin/alluxio fs getUsedBytes
```

To get the total capacity of the Alluxio cache in bytes:

```bash
$ ./bin/alluxio fs getCapacityBytes
```

The Alluxio master web interface gives the user a visual overview of the cluster and how much
storage space is used. It can be found at `http:/{MASTER_IP}:${alluxio.master.web.port}/`.
More detailed information about the Alluxio web interface can be
[found in our documentation]({{ '/en/basic/Web-Interface.html' | relativize_url }}).


text:
package db_gui.envpage;

import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
import javafx.stage.DirectoryChooser;
import db_gui.BDBInitializable;
import db_gui.BDBState;

/**
 * BDBEnvInitializeable is the parent class of all the controllers of the
 * Environment Page.  It implements operations that are part of all or most of
 * each environment tab, such as a field to enter an encryption key, and the
 * directory chooser for the environment home.
 */
class BDBEnvInitializable extends BDBInitializable {
    @FXML
    protected TextField DirectoryTextField;
    @FXML
    protected TextField EncryptionPasswordField;
    protected EnvConfig config;

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        config = new EnvConfig();
    }

    /**
     * Clears all the fields when the Clear button is pressed.
     */
    @Override
    public void clearAllFields() {
        DirectoryTextField.clear();
        if (EncryptionPasswordField != null)
            EncryptionPasswordField.clear();
        config = new EnvConfig();
    }

    /**
     * Implements the Environment Home directory chooser.  When a new directory
     * is chosen, it is displayed in the DirectoryTextField.
     *
     * @param event - Unused.
     */
    @FXML
    protected void selectEnvironmentHome(ActionEvent event) {
        DirectoryChooser homeDir = new DirectoryChooser();
        File home = homeDir.showDialog(bdbState.getMainStage());
        if (home != null) {
            config.setHome(home);
            DirectoryTextField.setText(home.getAbsolutePath());
        }
    }

    /**
     * Reads the text in DirectoryTextField and converts it to a directory and
     * sets it as the environment home in the EnvironmentConfig.
     *
     * @return True on success, false on error.
     */
    protected boolean getEnvironmentHome() {
        String home = DirectoryTextField.getText();
        if (home == null || home.isEmpty())
            return false;
        File file = new File(home);
        if (!file.exists() || !file.isDirectory())
            return false;
        config.setHome(file);
        return true;
    }

    /**
     * Implements the EncryptionPasswordField.
     *
     * @param event - Unused.
     */
    protected boolean getEncryptionKey() {
        String key = EncryptionPasswordField.getText();
        if (key != null && key.length() > 0)
            config.setEncryptionKey(key);
        return true;
    }

    /**
     * Implements the CacheSizeTextField.
     *
     * @param event - Unused.
     */
    protected boolean getCacheSize(TextField CacheSizeTextField) {
        String cacheString = CacheSizeTextField.getText();
        if (cacheString == null || cacheString.length() == 0)
            return true;
        try {
            long cacheBytes = Long.parseLong(cacheString);
            config.setCacheSize(cacheBytes);
        } catch (NumberFormatException ex) {
            bdbState.printFeedback(
                    "Invalid value for cache size: " + cacheString);
            CacheSizeTextField.clear();
            return false;
        }
        return true;
    }

    /**
     * Handles the Log directory chooser.  When a new directory
     * is chosen, it is displayed in LogDirectoryTextField.
     *
     * @param event - Unused.
     */
    protected void selectLogDirectory(TextField LogDirectoryTextField) {
        DirectoryChooser logDir = new DirectoryChooser();
        File dir = logDir.showDialog(bdbState.getMainStage());
        if (dir != null) {
            config.setLogDir(dir);
            LogDirectoryTextField.setText(dir.getAbsolutePath());
        }
    }

    /**
     * Reads the text in the test field and converts it to a directory and
     * sets it as the log directory in the EnvironmentConfig.
     *
     * @param LogDirectoryTextField - TextField in which to read the path to
     * the
     * log directory.
     * @return True on success, false on error.
     */
    protected boolean getLogDirectory(TextField LogDirectoryTextField) {
        String home = LogDirectoryTextField.getText();
        if (home == null || home.isEmpty())
            return true;
        home = home.trim();
        File file = new File(home);
        File origFile = file;
        if (!file.isAbsolute()) {
            home = config.home + File.separator + home;
            file = new File(home);
        }
        if (!file.exists() || !file.isDirectory()) {
            BDBState.getBDBState().printFeedback(
                    "Error, cannot find directory:" + home);
            return false;
        }
        config.setLogDir(origFile);
        return true;
    }

    /**
     * Handles the External File directory chooser.  When a new directory
     * is chosen, it is displayed in ExtFileDirectoryTextField.
     *
     * @param event - Unused.
     */
    protected void selectExternalFileDirectory(
            TextField ExtFileDirectoryTextField) {
        DirectoryChooser extDir = new DirectoryChooser();
        File dir = extDir.showDialog(bdbState.getMainStage());
        if (dir != null) {
            config.setExternalDir(dir);
            ExtFileDirectoryTextField.setText(dir.getAbsolutePath());
        }
    }

    /**
     * Reads the text in the test field and converts it to a directory and
     * sets it as the external file directory in the EnvironmentConfig.
     *
     * @param ExtFileDirectoryTextField - TextField in which to read the path
     * to
     * the external file directory.
     * @return - True on success, false on error.
     */
    protected boolean getExtFileDirectory(TextField ExtFileDirectoryTextField) {
        String home = ExtFileDirectoryTextField.getText();
        if (home == null || home.isEmpty())
            return true;
        home = home.trim();
        File file = new File(home);
        File origFile = file;
        if (!file.isAbsolute()) {
            home = config.home + File.separator + home;
            file = new File(home);
        }
        if (!file.exists() || !file.isDirectory()) {
            BDBState.getBDBState().printFeedback(
                    "Error, cannot find directory:" + home);
            return false;
        }
        config.setExternalDir(origFile);
        return true;
    }

    /**
     * Handles the Data Directories directory chooser.  When a new directory
     * is chosen, it is appended to the text displayed in
     * DataDirectoryTextField.
     *
     * @param event - Unused.
     */
    protected void selectDataDirectories(TextField DataDirectoriesTextField) {
        DirectoryChooser dataDirs = new DirectoryChooser();
        File dataDir = dataDirs.showDialog(bdbState.getMainStage());
        if (dataDir != null) {
            config.addDataDir(dataDir);
            File[] dirs = config.getDataDirs();
            String names = "";
            for (File dir : dirs) {
                names = names + dir.getName() + " ";
            }
            DataDirectoriesTextField.setText(names);
        }
    }

    /**
     * Reads the text in the test field and converts it to directories and
     * sets it as the data directory in the EnvironmentConfig.
     *
     * @param DataFileDirectoryTextField - TextField in which to read the paths
     * the data directories.
     * @return - True on success, false on error.
     */
    protected boolean getDataDirectories(TextField DataDirectoriesTextField) {
        String home = DataDirectoriesTextField.getText();
        if (home == null || home.isEmpty())
            return true;
        String[] dirs = home.split(",");
        for (String dir : dirs) {
            dir = dir.trim();
            File file = new File(dir);
            File origFile = file;
            if (!file.isAbsolute()) {
                dir = config.home + File.separator + dir;
                file = new File(dir);
            }
            if (!file.exists() || !file.isDirectory()) {
                BDBState.getBDBState().printFeedback(
                        "Error, cannot find directory:" + dir);
                return false;
            }
            config.addDataDir(origFile);
        }
        return true;
    }

}


text:
using Microsoft.Xna.Framework;
using MonoGame.Extended;

namespace MonoGame.ExtendedUI.Controls
{
    public class GuiCanvas : GuiLayoutControl
    {
        public GuiCanvas()
            : base(null)
        {
        }

        public GuiCanvas(GuiSkin skin)
            : base(skin)
        {
        }

        /*
        public override void Layout(IGuiContext context, RectangleF rectangle)
        {
            foreach (var control in Controls)
            {
                var desiredSize = control.GetDesiredSize(context, rectangle.Size);
                PlaceControl(context, control, control.Position.X, control.Position.Y, desiredSize.Width, desiredSize.Height);
            }
        }*/

        public override void Update(GameTime gameTime)
        {
        }
    }
}


text:
package com.hero.logic.payments;

import android.content.Context;
import android.net.Uri;
import android.util.Log;

import com.hero.R;
import com.hero.config.API;
import com.hero.config.Logging;
import com.hero.model.request.common.AuthenticatedRequest;
import com.hero.model.request.payment.PledgeMoneyRequest;
import com.hero.model.response.common.BasicResponse;
import com.hero.model.response.payment.ClientTokenResponse;
import com.hero.utils.Settings;
import com.hero.utils.caching.Singleton;
import com.hero.utils.networking.HTTP;

public class Braintree
{
    public static void pledgeChallenge(String challengeId, String nonce, double amount, Context context) throws Exception
    {
        // Log to logcat
        Log.d(Logging.TAG, "Pledging money");

        // Grab user auth key
        String userKey = Settings.getUserKey(context);

        // Create login request
        PledgeMoneyRequest request = new PledgeMoneyRequest(userKey);

        // Set up some basic data
        request.amount = amount;
        request.nonce = nonce;

        // Send the request to our API
        String json = HTTP.post(API.ENDPOINT + "/challenges/" + Uri.encode(challengeId) + "/pledge", request);

        // Convert JSON to object
        BasicResponse response = Singleton.getJackson().readValue(json, BasicResponse.class);

        // Failed?
        if ( ! response.success )
        {
            throw new Exception(context.getString(R.string.pledgeFailed));
        }
    }

    public static String getClientToken(Context context) throws Exception
    {
        // Log to logcat
        Log.d(Logging.TAG, "Fetching client token");

        // Grab user auth key
        String userKey = Settings.getUserKey(context);

        // Create login request
        AuthenticatedRequest request = new AuthenticatedRequest(userKey);

        // Send the request to our API
        String json = HTTP.post(API.ENDPOINT + "/payment/client_token", request);

        // Convert JSON to object
        ClientTokenResponse response = Singleton.getJackson().readValue(json, ClientTokenResponse.class);

        // Return actual token
        return response.token;
    }
}


text:
@interface IBTextIndexDataProvider : IDETextIndexDataProvider
{
}

- (id)findableForFilePath:(id)arg1;
- (id)textRepresentationOfContentsAtPath:(id)arg1;

@end


text:
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey, Boolean
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm import sessionmaker, relationship, backref, scoped_session
from sqlalchemy import event
from sqlalchemy.sql import func, case

import os

Base = declarative_base()
Session = sessionmaker()

class Config(Base):
    __tablename__ = 'config'
    key = Column('key', String, primary_key=True)
    value = Column('value', String)

class Document(Base):
    __tablename__ = 'documents'
    id = Column('id', Integer, primary_key = True)
    path = Column('path', String, index = True, unique = True)
    title = Column('title', String)

    tags = relationship("Tag", backref = "document", cascade='all, delete-orphan')

    @property
    def context(self):
        return [tag for tag in self.tags if tag.as_context]

    @property
    def links(self):
        return [tag for tag in self.tags if tag.as_link]

    @classmethod
    def find_or_new(cls,session, path, tags = []):
        return session.query(cls).filter_by(path = path).first() or cls(path, tags)

    def __init__(self, path, tags = []):
        self.path = path
        self.tags = tags

    def __repr__(self):
        return '<Document(%s)>' % self.path

class Keyword(Base):
    __tablename__ = 'keywords'
    id = Column('id', Integer, primary_key = True)
    name = Column('name', String, index = True, unique = True)

    @classmethod
    def find_or_new(cls, session, name):
        return session.query(Keyword).filter_by(name = name).first() or cls(name)

    def __init__(self, name):
            self.name = name

    def __repr__(self):
        return '<Keyword(%s)>' % self.name

class Tag(Base):
    __tablename__ = 'tags'
    keyword_id = Column(Integer, ForeignKey('keywords.id'), primary_key = True)
    document_id = Column(Integer, ForeignKey('documents.id'), primary_key = True)
    as_context = Column(Boolean, default = False)
    as_link = Column(Boolean, default = False)

    keyword = relationship("Keyword")

    def __init__(self, keyword = None, document = None, as_context = None, as_link = None):
        self.keyword = keyword
        self.document = document
        self.as_context = as_context
        self.as_link = as_link

    def __repr__(self):
        document = "None"
        if (self.document != None):
            document = self.document.path

        keyword = "None"
        if (self.keyword != None):
            keyword = self.keyword.name

        return '<Tag(%s,%s)>' % (keyword, document)

class Tagi:

    @classmethod
    def find_database(cls,dbname):
        cwd = os.getcwd()
        calling_dir = os.getcwd()
        while True:
            # try to find the database file
            dbpath = os.path.join(cwd,dbname)
            if os.path.isfile(dbpath):
                return dbpath

            # prepare to go up a level
            nwd = os.path.dirname(cwd)

            # could not go up (probably at root)
            if (nwd == cwd or not os.path.isdir(nwd)):
                return calling_dir

            # go up and try again
            cwd = nwd

    def create_document(self, path,tags = [], context = [], links = []):
        doc = Document.find_or_new(self.session, path)
        self.session.add(doc)
        self.add_tags(doc,tags)
        self.set_context(doc,context)
        self.set_links(doc,links)

        self.session.commit() # this needs to be at the end otherwise some documents get lost, why?
        return doc

    def add_tags(self, document, tags):
        current_tags = [tag.keyword.name for tag in document.tags]
        for tag in tags:
            if tag not in current_tags:
                keyword = Keyword.find_or_new(self.session, tag)
                document.tags.append(Tag(keyword = keyword))

    def remove_tags(self, document, tags):
        current_tags = [tag for tag in document.tags if tag.keyword.name in tags]
        for tag in current_tags:
            document.tags.remove(tag)

    def set_tags(self, document, tags):
        document.tags = []
        self.add_tags(document, tags)

    def set_context(self, document, context = []):
        self.add_tags(document, context)
        for tag in document.tags:
            if tag.keyword.name in context:
                tag.as_context = True
            else:
                tag.as_context = False

    def set_links(self, document, context = []):
        self.add_tags(document, context)
        for tag in document.tags:
            if tag.keyword.name in context:
                tag.as_link = True
            else:
                tag.as_link = False

    def find_document(self, path = None, tags = [], context = []):
        documents = self.find_documents(path = path, tags = tags, context = context)
        if documents != None and len(documents) > 0:
            return documents[0]
        else:
            return None

    def find_documents(self, path = None, tags = [], context = []):

        query = self.session.query(Document)

        if path != None:
            query = query.filter_by(path=path)

        if len(tags) > 0:
            query = query.join(Document.tags).\
            join(Tag.keyword).\
            filter(Keyword.name.in_(tags)).\
            group_by(Document.id).\
            having(func.count(Document.id) == len(tags))

        documents = query.order_by(Document.id).all()

        if len(context) > 0:
            # calculate the weight for a document based off the number of context tags the document has
            # this is done in python as it is simpler to retrieve the set of documents that match the tags
            # and then check them agains the context, then doing it in one swoop (the having clause would need to be a lot smarter)

            for doc in documents:
                doc.weight = len(set([tag.keyword.name for tag in doc.tags]) & set(context))

            # sort the most appropriate to the top
            documents.sort(key=lambda x: x.weight, reverse=True)

        return documents

    def __init__(self, dbname = 'tagi.db'):
        self.dbpath = self.find_database(dbname)
        self.wiki_root = os.path.dirname(self.dbpath)
        self.engine = create_engine('sqlite:///%s' % dbname)
        Base.metadata.create_all(self.engine)
        Session.configure(bind=self.engine)
        self.session = Session()


text:
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/web_apps/frame_toolbar/terminal_system_app_menu_button_chromeos.h"

#include <memory>

#include "base/metrics/user_metrics.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/web_applications/terminal_system_app_menu_model_chromeos.h"
#include "ui/views/controls/menu/menu_runner.h"

TerminalSystemAppMenuButton::TerminalSystemAppMenuButton(
    BrowserView* browser_view)
    : WebAppMenuButton(browser_view) {}

TerminalSystemAppMenuButton::~TerminalSystemAppMenuButton() = default;

void TerminalSystemAppMenuButton::ButtonPressed(const ui::Event& event) {
  Browser* browser = browser_view()->browser();
  RunMenu(std::make_unique<TerminalSystemAppMenuModel>(browser_view(), browser),
          browser,
          event.IsKeyEvent() ? views::MenuRunner::SHOULD_SHOW_MNEMONICS
                             : views::MenuRunner::NO_FLAGS,
          /*alert_reopen_tab_items=*/false);

  base::RecordAction(
      base::UserMetricsAction("TerminalSystemAppMenuButtonButton_Clicked"));
}


text:
package org.incode.platform.dom.classification.integtests;

import java.util.Set;

import javax.inject.Inject;
import javax.xml.bind.annotation.XmlRootElement;

import com.google.common.collect.Sets;

import org.apache.isis.applib.ModuleAbstract;

import org.isisaddons.module.fakedata.FakeDataModule;
import org.isisaddons.module.fakedata.dom.FakeDataService;

import org.incode.module.classification.dom.impl.classification.T_classifications;
import org.incode.module.classification.dom.impl.classification.T_classify;
import org.incode.module.classification.dom.impl.classification.T_unclassify;
import org.incode.platform.dom.classification.integtests.app.ClassificationAppModule;
import org.incode.platform.dom.classification.integtests.dom.classification.ClassificationModuleIntegrationSubmodule;

import org.estatio.module.base.integtests.BaseModuleIntegTestAbstract;

public abstract class ClassificationModuleIntegTestAbstract extends BaseModuleIntegTestAbstract {

    @XmlRootElement(name = "module")
    public static class MyModule extends ClassificationModuleIntegrationSubmodule {
        @Override
        public Set<org.apache.isis.applib.Module> getDependencies() {
            final Set<org.apache.isis.applib.Module> dependencies = super.getDependencies();
            dependencies.addAll(Sets.newHashSet(
                    new ClassificationAppModule(),
                    new FakeDataModule()
            ));
            return dependencies;
        }
    }

    public static ModuleAbstract module() {
        return new MyModule();
    }

    protected ClassificationModuleIntegTestAbstract() {
        super(module());
    }

    @Inject
    protected FakeDataService fakeData;

    protected T_classify mixinClassify(final Object classifiable) {
        return mixin(T_classify.class, classifiable);
    }
    protected T_unclassify mixinUnclassify(final Object classifiable) {
        return mixin(T_unclassify.class, classifiable);
    }
    protected T_classifications mixinClassifications(final Object classifiable) {
        return mixin(T_classifications.class, classifiable);
    }

}


text:
using BudgetCalculator.Core.Enum;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BudgetCalculator.Core.Interface
{
    public interface IAccomodationExpenses
    {
        AccomodationExpenseType AccomodationType { get; }
    }
}


text:
package org.notninja.verifier.type;

import org.notninja.verifier.type.base.BaseComparableVerifier;
import org.notninja.verifier.type.base.BaseNumberVerifier;
import org.notninja.verifier.type.base.BaseTruthVerifier;
import org.notninja.verifier.verification.Verification;

/**
 *

 * An implementation of {@link BaseComparableVerifier} and {@link BaseNumberVerifier} which can be used to verify a
 * {@code Byte} value.
 *

 *

 * In accordance with {@link BaseNumberVerifier}, all of the {@link BaseTruthVerifier} methods are implemented so that
 * {@literal null} and {@code 0} are always considered to be falsy and {@code 1} is always considered to
 * be truthy.
 *

 *
 * @author Alasdair Mercer
 */
public final class ByteVerifier extends BaseComparableVerifier<Byte, ByteVerifier> implements BaseNumberVerifier<Byte, ByteVerifier> {

    /**
     *

     * Creates an instance of {@link ByteVerifier} based on the {@code verification} provided.
     *

     *
     * @param verification
     *         the {@link Verification} to be used
     */
    public ByteVerifier(final Verification<Byte> verification) {
        super(verification);
    }

    @Override
    public ByteVerifier even() {
        final Byte value = verification().getValue();
        final boolean result = value != null && value % 2 == 0;

        verification().report(result, BaseNumberVerifier.MessageKeys.EVEN);

        return this;
    }

    @Override
    public ByteVerifier falsy() {
        final Byte value = verification().getValue();
        final boolean result = value == null || value == 0;

        verification().report(result, BaseTruthVerifier.MessageKeys.FALSY);

        return this;
    }

    @Override
    public ByteVerifier negative() {
        final Byte value = verification().getValue();
        final boolean result = value != null && value < 0;

        verification().report(result, BaseNumberVerifier.MessageKeys.NEGATIVE);

        return this;
    }

    @Override
    public ByteVerifier odd() {
        final Byte value = verification().getValue();
        final boolean result = value != null && value % 2 != 0;

        verification().report(result, BaseNumberVerifier.MessageKeys.ODD);

        return this;
    }

    @Override
    public ByteVerifier one() {
        final Byte value = verification().getValue();
        final boolean result = value != null && value == 1;

        verification().report(result, BaseNumberVerifier.MessageKeys.ONE);

        return this;
    }

    @Override
    public ByteVerifier positive() {
        final Byte value = verification().getValue();
        final boolean result = value != null && value >= 0;

        verification().report(result, BaseNumberVerifier.MessageKeys.POSITIVE);

        return this;
    }

    @Override
    public ByteVerifier truthy() {
        final Byte value = verification().getValue();
        final boolean result = value != null && value == 1;

        verification().report(result, BaseTruthVerifier.MessageKeys.TRUTHY);

        return this;
    }

    @Override
    public ByteVerifier zero() {
        final Byte value = verification().getValue();
        final boolean result = value != null && value == 0;

        verification().report(result, BaseNumberVerifier.MessageKeys.ZERO);

        return this;
    }
}