text:
/****************************************************************************

  ICPConfig.cc

****************************************************************************/

#include "ts/ink_platform.h"
#include "ts/ink_file.h"
#include "P_EventSystem.h"
#include "P_Cache.h"
#include "P_Net.h"
#include "P_RecProcess.h"
#include "Main.h"
#include "ICP.h"
#include "ICPProcessor.h"
#include "ICPlog.h"
#include "BaseManager.h"
#include "ts/I_Layout.h"

//--------------------------------------------------------------------------
//  Each ICP peer is described in "icp.config" with the
//  following info:
//    hostname (string)         -- hostname, used only if (host_ip_str == 0)
//    host_ip_str (string)      -- decimal dot notation; if null get IP
//                                   addresss via lookup on hostname
//    ctype (int)               -- 1=Parent, 2=Sibling, 3=local
//    proxy_port (int)          -- TCP Port #
//    icp_port (int)            -- UDP Port #
//    multicast_member          -- 0=No 1=Yes
//    multicast_ip_str (string) -- decimal dot notation
//    multicast_ttl (int)       -- (1 - 2; default 1)
//
//#############################################################################
//
//  ICP global configuration options are described in "records.config" using
//  the following entries.
//
//    proxy.config.icp.icp_configuration STRING (default "icp.config")
//    proxy.config.icp.enabled INT (0=No 1=Yes)
//    proxy.config.icp.icp_port INT 3130
//    proxy.config.icp.icp_interface STRING hme0
//    proxy.config.icp.multicast_enabled INT (0=No 1=Yes)
//    proxy.config.icp.query_timeout INT (seconds default is 2 secs)
//    proxy.config.icp.lookup_local INT (default is cluster lookup)
//
//  Example (1 parent and 1 sibling):
//  ============================================
//    proxy.config.icp.enabled INT 1
//    proxy.config.icp.multicast_enabled INT 0
//    proxy.config.icp.query_timeout INT 2
//
//    === "icp.config" entries ===
//
//    hostname:         "host1"
//    host_ip_str:      "209.1.33.10"
//    ctype:            1
//    proxy_port:       8080
//    icp_port:         3130
//    multicast_member  0
//    multicast_ip_str: "0.0.0.0"
//    multicast_ttl:    0
//
//    hostname:         "host2"
//    host_ip_str:      "209.1.33.11"
//    ctype:            2
//    proxy_port:       8080
//    icp_port:         3130
//    multicast_member  0
//    multicast_ip_str: "0.0.0.0"
//    multicast_ttl:    0
//
//  Example (1 parent and 1 sibling using MultiCast):
//  ============================================================
//    proxy.config.icp.enabled INT 1
//    proxy.config.icp.multicast_enabled INT 1
//    proxy.config.icp.query_timeout INT 2
//
//    === "icp.config" entries ===
//
//    hostname:         "host1"
//    host_ip_str:      "209.1.33.10"
//    ctype:            1
//    proxy_port:       8080
//    icp_port:         3130
//    multicast_member  1
//    multicast_ip_str: "239.128.16.128"
//    multicast_ttl:    1
//
//    hostname:         "host2"
//    host_ip_str:      "209.1.33.11"
//    ctype:            2
//    proxy_port:       8080
//    icp_port:         3130
//    multicast_member  1
//    multicast_ip_str: "239.128.16.128"
//    multicast_ttl:    1
//

//------------------------------------
// Class AtomicLock member functions
//------------------------------------
#if !defined(USE_CAS_FOR_ATOMICLOCK)
AtomicLock::AtomicLock()
{
  _mutex = new_ProxyMutex();
}

AtomicLock::~AtomicLock()
{
}

int
AtomicLock::Lock()
{
  EThread *et = this_ethread();
  ink_assert(et != nullptr);
  return MUTEX_TAKE_TRY_LOCK(_mutex, et);
}

int
AtomicLock::HaveLock()
{
  EThread *et = this_ethread();
  ink_assert(et != nullptr);
  return (_mutex->thread_holding == et);
}

void
AtomicLock::Unlock()
{
  EThread *et = this_ethread();
  ink_assert(et != nullptr);
  MUTEX_UNTAKE_LOCK(_mutex, et);
}

#else  // USE_CAS_FOR_ATOMICLOCK
AtomicLock::AtomicLock() : lock_word(0)
{
}

AtomicLock::~AtomicLock()
{
}

int
AtomicLock::Lock()
{
  bool status = ink_atomic_cas(&_lock_word, AtomicLock::UNLOCKED, AtomicLock::LOCKED);
  return status;
}

int
AtomicLock::HaveLock()
{
  return (_lock_word == LOCKED);
}

void
AtomicLock::Unlock()
{
  ink_assert(_lock_word == AtomicLock::LOCKED);
  _lock_word = AtomicLock::UNLOCKED;
}
#endif // USE_CAS_FOR_ATOMICLOCK

//---------------------------------------------------------------------
// Class BitMap -- Member functions.
//                 Generic bitmap management class
//      Note: Bit positions are zero based (0 .. (bitmap_maxsize-1) )
//---------------------------------------------------------------------
BitMap::BitMap(int bitmap_maxsize)
{
  if (bitmap_maxsize <= (int)(STATIC_BITMAP_BYTE_SIZE * BITS_PER_BYTE)) {
    _bitmap           = _static_bitmap;
    _bitmap_size      = bitmap_maxsize;
    _bitmap_byte_size = STATIC_BITMAP_BYTE_SIZE;
  } else {
    _bitmap_byte_size = (bitmap_maxsize + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE;
    _bitmap           = new char[_bitmap_byte_size];
    _bitmap_size      = bitmap_maxsize;
  }
  memset((void *)_bitmap, 0, _bitmap_byte_size);
}

BitMap::~BitMap()
{
  if (_bitmap_size > (int)(STATIC_BITMAP_BYTE_SIZE * BITS_PER_BYTE)) {
    delete[] _bitmap;
  }
}

void
BitMap::SetBit(int bit)
{
  if (bit >= _bitmap_size) {
    return;
  }

  char *pbyte = &_bitmap[bit / BITS_PER_BYTE];
  *pbyte |= (1 << (bit % BITS_PER_BYTE));
}

void
BitMap::ClearBit(int bit)
{
  if (bit >= _bitmap_size) {
    return;
  }

  char *pbyte = &_bitmap[bit / BITS_PER_BYTE];
  *pbyte &= ~(1 << (bit % BITS_PER_BYTE));
}

int
BitMap::IsBitSet(int bit)
{
  if (bit >= _bitmap_size) {
    return 0;
  }

  char *pbyte = &_bitmap[bit / BITS_PER_BYTE];
  if (*pbyte & (1 << (bit % BITS_PER_BYTE))) {
    return 1;
  } else {
    return 0;
  }
}

//-----------------------------------------------------------------------
// Class ICPConfigData member functions
//      Manage global ICP configuration data from the TS configuration.
//      Support class for ICPConfiguration.
//-----------------------------------------------------------------------
int
ICPConfigData::operator==(ICPConfigData &ICPData)
{
  if (ICPData._icp_enabled != _icp_enabled) {
    return 0;
  }
  if (ICPData._icp_port != _icp_port) {
    return 0;
  }
  if (ICPData._icp_interface != _icp_interface) {
    return 0;
  }
  if (ICPData._multicast_enabled != _multicast_enabled) {
    return 0;
  }
  if (ICPData._icp_query_timeout != _icp_query_timeout) {
    return 0;
  }
  if (ICPData._cache_lookup_local != _cache_lookup_local) {
    return 0;
  }
  if (ICPData._stale_lookup != _stale_lookup) {
    return 0;
  }
  if (ICPData._reply_to_unknown_peer != _reply_to_unknown_peer) {
    return 0;
  }
  if (ICPData._default_reply_port != _default_reply_port) {
    return 0;
  }
  return 1;
}

//------------------------------------------------------------------------
// Class PeerConfigData member functions
//      Manage ICP Peer configuration data from the TS configuration.
//      Support class for ICPConfiguration.
//------------------------------------------------------------------------
PeerConfigData::PeerConfigData() : _ctype(CTYPE_NONE), _proxy_port(0), _icp_port(0), _mc_member(0), _mc_ttl(0)
{
  memset(_hostname, 0, HOSTNAME_SIZE);
}

PeerType_t
PeerConfigData::CTypeToPeerType_t(int ctype)
{
  switch (ctype) {
  case (int)CTYPE_PARENT:
    return PEER_PARENT;

  case (int)CTYPE_SIBLING:
    return PEER_SIBLING;

  case (int)CTYPE_LOCAL:
    return PEER_LOCAL;

  default:
    return PEER_NONE;
  }
}

int
PeerConfigData::GetHostIPByName(char *hostname, IpAddr &rip)
{
  // Short circuit NULL hostname case
  if (nullptr == hostname || 0 == *hostname) {
    return 1; // Unable to map to IP address
  }

  addrinfo hints;
  addrinfo *ai;
  sockaddr const *best = nullptr;

  ink_zero(hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_flags  = AI_ADDRCONFIG;
  if (0 == getaddrinfo(hostname, nullptr, &hints, &ai)) {
    for (addrinfo *spot = ai; spot; spot = spot->ai_next) {
      // If current address is valid, and either we don't have one yet
      // or this address is less than our current, set it as current.
      if (ats_is_ip(spot->ai_addr) && (!best || -1 == ats_ip_addr_cmp(spot->ai_addr, best))) {
        best = spot->ai_addr;
      }
    }
    if (best) {
      rip.assign(best);
    }
    freeaddrinfo(ai);
  }
  return best ? 0 : 1;
}

bool
PeerConfigData::operator==(PeerConfigData &PeerData)
{
  if (strncmp(PeerData._hostname, _hostname, PeerConfigData::HOSTNAME_SIZE) != 0) {
    return false;
  }
  if (PeerData._ctype != _ctype) {
    return false;
  }
  if (PeerData._ip_addr != _ip_addr) {
    return false;
  }
  if (PeerData._proxy_port != _proxy_port) {
    return false;
  }
  if (PeerData._icp_port != _icp_port) {
    return false;
  }
  if (PeerData._mc_member != _mc_member) {
    return false;
  }
  if (PeerData._mc_ip_addr != _mc_ip_addr) {
    return false;
  }
  if (PeerData._mc_ttl != _mc_ttl) {
    return false;
  }
  return true;
}

//-----------------------------------------------------------------------
// Class ICPConfigUpdateCont member functions
//      Retry callout to ICPConfiguration::icp_config_change_callback()
//-----------------------------------------------------------------------
ICPConfigUpdateCont::ICPConfigUpdateCont(void *d, void *v) : Continuation(new_ProxyMutex()), _data(d), _value(v)
{
}

int
ICPConfigUpdateCont::RetryICPconfigUpdate(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
{
  ICPConfiguration::icp_config_change_callback(_data, _value);
  delete this;
  return EVENT_DONE;
}

//--------------------------------------------------------------------------
// Class ICPConfiguration member functions
//      Overall manager of ICP configuration data from TS configuration.
//--------------------------------------------------------------------------
typedef int (ICPConfigUpdateCont::*ICPCfgContHandler)(int, void *);
ICPConfiguration::ICPConfiguration() : _icp_config_callouts(0)
{
  //*********************************************************
  // Allocate working and current ICPConfigData structures
  //*********************************************************
  _icp_cdata         = new ICPConfigData();
  _icp_cdata_current = new ICPConfigData();

  //********************************************************************
  // Read ICP config and setup update callbacks for "icp_cdata_current"
  //********************************************************************
  ICP_EstablishStaticConfigInteger(_icp_cdata_current->_icp_enabled, "proxy.config.icp.enabled");
  ICP_EstablishStaticConfigInteger(_icp_cdata_current->_icp_port, "proxy.config.icp.icp_port");
  ICP_EstablishStaticConfigStringAlloc(_icp_cdata_current->_icp_interface, "proxy.config.icp.icp_interface");
  ICP_EstablishStaticConfigInteger(_icp_cdata_current->_multicast_enabled, "proxy.config.icp.multicast_enabled");
  ICP_EstablishStaticConfigInteger(_icp_cdata_current->_icp_query_timeout, "proxy.config.icp.query_timeout");
  ICP_EstablishStaticConfigInteger(_icp_cdata_current->_cache_lookup_local, "proxy.config.icp.lookup_local");
  ICP_EstablishStaticConfigInteger(_icp_cdata_current->_stale_lookup, "proxy.config.icp.stale_icp_enabled");
  ICP_EstablishStaticConfigInteger(_icp_cdata_current->_reply_to_unknown_peer, "proxy.config.icp.reply_to_unknown_peer");
  ICP_EstablishStaticConfigInteger(_icp_cdata_current->_default_reply_port, "proxy.config.icp.default_reply_port");
  REC_EstablishStaticConfigInteger(_icp_cdata_current->_cache_generation, "proxy.config.http.cache.generation");

  UpdateGlobalConfig(); // sync working copy with current

  //**********************************************************
  // Allocate working and current PeerConfigData structures
  //**********************************************************
  for (int n = 0; n <= MAX_DEFINED_PEERS; ++n) {
    _peer_cdata[n]         = new PeerConfigData;
    _peer_cdata_current[n] = new PeerConfigData;
  }

  //*********************************************************
  // Initialize Peer data by simulating an update callout.
  //*********************************************************
  char icp_config_filename[PATH_NAME_MAX] = "";
  ICP_ReadConfigString(icp_config_filename, "proxy.config.icp.icp_configuration", sizeof(icp_config_filename) - 1);
  (void)icp_config_change_callback((void *)this, (void *)icp_config_filename, 1);
  UpdatePeerConfig(); // sync working copy with current

  //***************************************
  // Setup update callout on "icp.config"
  //***************************************
  ICP_RegisterConfigUpdateFunc("proxy.config.icp.icp_configuration", mgr_icp_config_change_callback, (void *)this);
}

ICPConfiguration::~ICPConfiguration()
{
// TBD: Need to disable update callbacks before deallocating data.
//      How do we do this?  For now, this never happens.
#ifdef OMIT
  if (_icp_cdata) {
    // TBD: Make sure _icp_cdata->_icp_interface has been freed
    delete ((void *)_icp_cdata);
  }
  if (_icp_cdata_current)
    delete ((void *)_icp_cdata_current);
  if (_peer_cdata)
    delete ((void *)_peer_cdata);
  if (_peer_cdata_current)
    delete ((void *)_peer_cdata_current);
#endif // OMIT
}

int
ICPConfiguration::GlobalConfigChange()
{
  return (!(*_icp_cdata == *_icp_cdata_current));
}

void
ICPConfiguration::UpdateGlobalConfig()
{
  *_icp_cdata = *_icp_cdata_current;
}

int
ICPConfiguration::PeerConfigChange()
{
  // Note: Entry zero reserved for "localhost"
  for (int i = 1; i <= MAX_DEFINED_PEERS; ++i) {
    if (!(*_peer_cdata[i] == *_peer_cdata_current[i])) {
      return 1;
    }
  }
  return 0;
}

void
ICPConfiguration::UpdatePeerConfig()
{
  // Note: Entry zero reserved for "localhost"
  for (int i = 1; i <= MAX_DEFINED_PEERS; ++i) {
    //
    // Broken on DEC and Solaris x86
    // *_peer_cdata[i] = *_peer_cdata_current[i];
    //
    memcpy(_peer_cdata[i], _peer_cdata_current[i], sizeof(*_peer_cdata[i]));
    // Setup IP address
    if ((_peer_cdata[i]->_ip_addr.isValid()) && _peer_cdata[i]->_hostname[0]) {
      // IP address not specified, lookup using hostname.
      (void)PeerConfigData::GetHostIPByName(_peer_cdata[i]->_hostname, _peer_cdata[i]->_my_ip_addr);
    } else {
      // IP address specified by user, lookup on hostname not required.
      _peer_cdata[i]->_my_ip_addr = _peer_cdata[i]->_ip_addr;
    }
  }
}

int
ICPConfiguration::mgr_icp_config_change_callback(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */,
                                                 RecData data, void *cookie)
{
  //*****************************************************************
  // Callout invoked by Configuration management when changes occur
  // to icp.config
  //*****************************************************************

  // Map this manager configuration callout onto ET_ICP

  ICPConfigUpdateCont *rh = new ICPConfigUpdateCont(cookie, data.rec_string);
  SET_CONTINUATION_HANDLER(rh, (ICPCfgContHandler)&ICPConfigUpdateCont::RetryICPconfigUpdate);
  eventProcessor.schedule_imm(rh, ET_ICP);
  return EVENT_DONE;
}

namespace
{
inline char *
next_field(char *text, char fs)
{
  text = strchr(text, fs);
  // Compress contiguous whitespace by leaving zret pointing at the last space.
  if (text && *text == fs) {
    while (text[1] == fs) {
      ++text;
    }
  }
  return text;
}
}

void *
ICPConfiguration::icp_config_change_callback(void *data, void *value, int startup)
{
  EThread *thread   = this_ethread();
  ProxyMutex *mutex = thread->mutex.get();

  //
  // Cast passed parameters to correct types
  //
  char *filename              = (char *)value;
  ICPConfiguration *ICPconfig = (ICPConfiguration *)data;

  //
  // Determine if data is locked, if so defer update action
  //
  if (!startup && !ICPconfig->Lock()) {
    // Build retry continuation
    ICPConfigUpdateCont *rh = new ICPConfigUpdateCont(data, value);
    SET_CONTINUATION_HANDLER(rh, (ICPCfgContHandler)&ICPConfigUpdateCont::RetryICPconfigUpdate);
    eventProcessor.schedule_in(rh, HRTIME_MSECONDS(ICPConfigUpdateCont::RETRY_INTERVAL), ET_ICP);
    return EVENT_DONE;
  }
  ICP_INCREMENT_DYN_STAT(config_mgmt_callouts_stat);
  ICPconfig->_icp_config_callouts++;

  //
  // Allocate working buffer for PeerConfigData[]
  //
  PeerConfigData *P = new PeerConfigData[MAX_DEFINED_PEERS + 1];

  //
  // Build pathname to "icp.config" and open file
  //
  ink_release_assert(filename != nullptr);

  ats_scoped_str config_path(Layout::get()->relative_to(Layout::get()->sysconfdir, filename));
  int fd = open(config_path, O_RDONLY);
  if (fd < 0) {
    RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, open failed");
    delete[] P;
    return EVENT_DONE;
  }
  //***********************************************************************
  // Parse records in "icp.config"
  //  Each line is formatted as follows with ":" separator for each field
  //    - hostname (string)           -- Identifier for entry
  //    - host_ip_str (string)        -- decimal dot notation
  //    - ctype (int)                 -- 1=Parent, 2=Sibling, 3=Local
  //    - proxy_port (int)            -- TCP Port #
  //    - icp_port (int)              -- UDP Port #
  //    - multicast_member            -- 0=No 1=Yes
  //    - multicast_ip_str (string)   -- decimal dot notation
  //    - multicast_ttl (int)         -- (1 - 2; default 1)
  //***********************************************************************
  const int colons_per_entry = 8; // expected ':' separators per entry

  int error = 0;
  int ln    = 0;
  int n_colons;
  char line[512];
  char *cur;
  char *next;
  char *p;
  char fs = ':'; // field separator.
  int len;       // length of current input line (original).

  int n = 1; // Note: Entry zero reserved for "localhost" data

  //////////////////////////////////////////////////////////////////////
  // Read and parse "icp.config" entries.
  //
  // Note: ink_file_fd_readline() null terminates returned buffer
  //////////////////////////////////////////////////////////////////////
  while ((len = ink_file_fd_readline(fd, sizeof(line) - 1, line)) > 0) {
    ln++;
    cur = line;
    while (isspace(*cur)) {
      ++cur, --len; // skip leading space.
    }
    if (!*cur || *cur == '#') {
      continue;
    }

    if (n >= MAX_DEFINED_PEERS) {
      RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, maximum peer entries exceeded");
      error = 1;
      break;
    }
    //***********************************
    // Verify general syntax of entry
    //***********************************
    /* Ugly. The original field separator was colon, but we can't have that
       if we want to support IPv6. So - since each line is required to have a
       separator at the end of the line, we look there and require it to be
       consistent. It still must be an acceptable character.
    */
    char *last = cur + len - 1; // last character.
    if ('\n' == *last) {
      --last; // back over trailing LF.
    }
    if (nullptr == strchr(" ;:|,", *last)) {
      RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, invalid separator [value %d]", *last);
      error = 1;
      break;
    }
    fs = *last;

    n_colons = 0;
    p        = cur;
    while (nullptr != (p = next_field(p, fs))) {
      ++p;
      ++n_colons;
    }
    if (n_colons != colons_per_entry) {
      RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, invalid syntax, line %d: expected %d fields, found %d", ln,
                       colons_per_entry, n_colons);
      error = 1;
      break;
    }
    //*******************
    // Extract hostname
    //*******************
    next    = next_field(cur, fs);
    *next++ = 0;
    if (cur != (next - 1)) {
      ink_strlcpy(P[n]._hostname, cur, PeerConfigData::HOSTNAME_SIZE);
    } else {
      P[n]._hostname[0] = 0;
    }
    //*********************
    // Extract host_ip_str
    //*********************
    cur     = next;
    next    = next_field(next, fs);
    *next++ = 0;
    if (cur != (next - 1)) {
      if (0 != P[n]._ip_addr.load(cur)) {
        RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, bad host ip_addr, line %d", ln);
        error = 1;
        break;
      }
    } else {
      P[n]._ip_addr.invalidate();
    }

    if (!P[n]._hostname[0] && !P[n]._ip_addr.isValid()) {
      RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, bad hostname, line %d", ln);
      error = 1;
      break;
    }
    //******************
    // Extract ctype
    //******************
    cur     = next;
    next    = next_field(next, fs);
    *next++ = 0;
    if (cur != (next - 1)) {
      P[n]._ctype = atoi(cur);
      if ((P[n]._ctype != PeerConfigData::CTYPE_PARENT) && (P[n]._ctype != PeerConfigData::CTYPE_SIBLING) &&
          (P[n]._ctype != PeerConfigData::CTYPE_LOCAL)) {
        RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, bad ctype, line %d", ln);
        error = 1;
        break;
      }
    } else {
      RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, 2bad ctype, line %d", ln);
      error = 1;
      break;
    }
    //*********************
    // Extract proxy_port
    //*********************
    cur     = next;
    next    = next_field(next, fs);
    *next++ = 0;
    if (cur != (next - 1)) {
      if ((P[n]._proxy_port = atoi(cur)) <= 0) {
        RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, bad proxy_port, line %d", ln);
        error = 1;
        break;
      }
    } else {
      RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, 2bad proxy_port, line %d", ln);
      error = 1;
      break;
    }
    //*********************
    // Extract icp_port
    //*********************
    cur     = next;
    next    = next_field(next, fs);
    *next++ = 0;
    if (cur != (next - 1)) {
      if ((P[n]._icp_port = atoi(cur)) <= 0) {
        RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, bad icp_port, line %d", ln);
        error = 1;
        break;
      }
    } else {
      RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, 2bad icp_port, line %d", ln);
      error = 1;
      break;
    }
    //****************************
    // Extract multicast_member
    //****************************
    cur     = next;
    next    = next_field(next, fs);
    *next++ = 0;
    if (cur != (next - 1)) {
      if ((P[n]._mc_member = atoi(cur)) < 0) {
        RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, bad mc_member, line %d", ln);
        error = 1;
        break;
      }
      if ((P[n]._mc_member != 0) && (P[n]._mc_member != 1)) {
        RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, bad mc_member (2), line %d", ln);
        error = 1;
        break;
      }
    } else {
      RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, 2bad mc_member, line %d", ln);
      error = 1;
      break;
    }
    //****************************
    // Extract multicast_ip_str
    //****************************
    cur     = next;
    next    = next_field(next, fs);
    *next++ = 0;
    if (cur != (next - 1)) {
      P[n]._mc_ip_addr.load(cur);
      // Validate only if "multicast_member" is set.
      if (P[n]._mc_member != 0 && !P[n]._mc_ip_addr.isMulticast()) {
        RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, bad multicast ip_addr, line %d", ln);
        error = 1;
        break;
      }
    } else {
      P[n]._mc_ip_addr.invalidate();
    }
    //************************
    // Extract multicast_ttl
    //************************
    // Note: last entry is always terminated with a ":"
    cur     = next;
    next    = next_field(next, fs);
    *next++ = 0;
    if (cur != (next - 1)) {
      P[n]._mc_ttl = atoi(cur);
      if ((P[n]._mc_ttl = atoi(cur)) <= 0) {
        RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, bad mc_ttl, line %d", ln);
        error = 1;
        break;
      }
    } else {
      RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "read icp.config, 2bad mc_ttl, line %d", ln);
      error = 1;
      break;
    }
    n++; // bump PeerConfigData[] index
  }
  close(fd);

  if (!error) {
    for (int i = 0; i <= MAX_DEFINED_PEERS; i++) {
      *ICPconfig->_peer_cdata_current[i] = P[i];
    }
  }
  delete[] P; // free working buffer
  if (!startup) {
    ICPconfig->Unlock();
  }
  return EVENT_DONE;
}

//-------------------------------------------------------
// Class Peer member functions (abstract base class)
//-------------------------------------------------------
Peer::Peer(PeerType_t t, ICPProcessor *icpPr, bool dynamic_peer)
  : buf(nullptr),
    notFirstRead(0),
    readAction(nullptr),
    writeAction(nullptr),
    _type(t),
    _next(nullptr),
    _ICPpr(icpPr),
    _state(PEER_UP)
{
  notFirstRead = 0;
  if (dynamic_peer) {
    _state |= PEER_DYNAMIC;
  }
  memset((void *)&this->_stats, 0, sizeof(this->_stats));
  ink_zero(fromaddr);
  fromaddrlen = sizeof(fromaddr);
  _id         = 0;
}

void
Peer::LogRecvMsg(ICPMsg_t *m, int valid)
{
  // Note: ICPMsg_t (m) is in native byte order

  // Note numerous stats on a per peer basis
  _stats.last_receive = Thread::get_hrtime();
  if ((m->h.opcode >= ICP_OP_QUERY) && (m->h.opcode <= ICP_OP_LAST)) {
    _stats.recv[m->h.opcode]++;
  } else {
    _stats.recv[ICP_OP_INVALID]++;
  }
  _stats.total_received++;

  if (!valid) {
    // Message arrived, but ICP request no longer on pending list
    _stats.dropped_replies++;
  }
  if ((_state & PEER_UP) == 0) {
    ip_port_text_buffer ipb;
    // Currently marked down so we still send but do not expect reply.
    // Now mark up so we will wait for reply.
    _state |= PEER_UP;
    _stats.total_received = _stats.total_sent; // restart timeout count

    Debug("icp", "Peer [%s] now back online", ats_ip_nptop(this->GetIP(), ipb, sizeof(ipb)));
  }
}

//---------------------------------------------------------------
// Class ParentSiblingPeer (derived from Peer) member functions
//      ICP object describing Parent or Sibling Peers.
//---------------------------------------------------------------
ParentSiblingPeer::ParentSiblingPeer(PeerType_t t, PeerConfigData *p, ICPProcessor *icpPr, bool dynamic_peer)
  : Peer(t, icpPr, dynamic_peer), _pconfig(p)
{
  ats_ip_set(&_ip.sa, _pconfig->GetIPAddr(), htons(_pconfig->GetICPPort()));
}

int
ParentSiblingPeer::GetProxyPort()
{
  return _pconfig->GetProxyPort();
}

int
ParentSiblingPeer::GetICPPort()
{
  return _pconfig->GetICPPort();
}

sockaddr *
ParentSiblingPeer::GetIP()
{
  // The real data is in _pconfig, but I don't think ever changes so
  // it should be OK to have set this in the constructor.
  return &_ip.sa;
}

Action *
ParentSiblingPeer::SendMsg_re(Continuation *cont, void *token, struct msghdr *msg, sockaddr const *to)
{
  // Note: All sends are funneled through the local peer UDP socket.

  Peer *lp = _ICPpr->GetLocalPeer();

  if (to) {
    // Send to specified host
    Peer *p = _ICPpr->FindPeer(IpAddr(to), ntohs(ats_ip_port_cast(to)));
    ink_assert(p);

    msg->msg_name    = &p->GetSendChan()->addr;
    msg->msg_namelen = ats_ip_size(&p->GetSendChan()->addr);
    Action *a        = udpNet.sendmsg_re(cont, token, lp->GetSendFD(), msg);
    return a;
  } else {
    // Send to default host
    msg->msg_name    = &_chan.addr;
    msg->msg_namelen = ats_ip_size(&_chan.addr.sa);
    Action *a        = udpNet.sendmsg_re(cont, token, lp->GetSendFD(), msg);
    return a;
  }
}

Action *
ParentSiblingPeer::RecvFrom_re(Continuation *cont, void *token, IOBufferBlock *bufblock, int size, struct sockaddr *from,
                               socklen_t *fromlen)
{
  // Note: All receives are funneled through the local peer UDP socket.

  Peer *lp  = _ICPpr->GetLocalPeer();
  Action *a = udpNet.recvfrom_re(cont, token, lp->GetRecvFD(), from, fromlen, bufblock, size, true, 0);
  return a;
}

int
ParentSiblingPeer::GetRecvFD()
{
  return _chan.fd;
}

int
ParentSiblingPeer::GetSendFD()
{
  return _chan.fd;
}

int
ParentSiblingPeer::ExpectedReplies(BitMap *expected_replies_list)
{
  if (((_state & PEER_UP) == 0) || ((_stats.total_sent - _stats.total_received) > Peer::OFFLINE_THRESHOLD)) {
    if (_state & PEER_UP) {
      ip_port_text_buffer ipb;
      _state &= ~PEER_UP;
      Debug("icp", "Peer [%s] marked offline", ats_ip_nptop(this->GetIP(), ipb, sizeof(ipb)));
    }
    //
    // We will continue to send messages, but will not wait for a reply
    // until we receive a response.
    //
    return 0;
  } else {
    expected_replies_list->SetBit(this->GetPeerID());
    return 1;
  }
}

int
ParentSiblingPeer::ValidSender(sockaddr *fr)
{
  if (_type == PEER_LOCAL) {
    //
    // We are currently funneling all unicast receives
    // through the local peer UDP socket.  As long as
    // the sender is known within the ICP configuration,
    // consider it valid.
    //
    Peer *p = _ICPpr->FindPeer(fr);
    if (p) {
      return 1; // Valid sender
    } else {
      return 0; // Invalid sender
    }

  } else {
    // Make sure the sockaddr_in corresponds to this peer
    // Need to update once we have support for comparing address
    // and port in a socakddr.
    if (ats_ip_addr_eq(this->GetIP(), fr) && (ats_ip_port_cast(this->GetIP()) == ats_ip_port_cast(fr))) {
      return 1; // Sender is this peer
    } else {
      return 0; // Sender is not this peer
    }
  }
}

void
ParentSiblingPeer::LogSendMsg(ICPMsg_t *m, sockaddr const * /* sa ATS_UNUSED */)
{
  // Note: ICPMsg_t (m) is in network byte order

  // Note numerous stats on a per peer basis
  _stats.last_send = Thread::get_hrtime();
  _stats.sent[m->h.opcode]++;
  _stats.total_sent++;
}

int
ParentSiblingPeer::ExtToIntRecvSockAddr(sockaddr const *in, sockaddr *out)
{
  Peer *p = _ICPpr->FindPeer(IpAddr(in));
  if (p && (p->GetType() != PEER_LOCAL)) {
    // Map from received (ip, port) to defined (ip, port).
    ats_ip_copy(out, p->GetIP());
    return 1;
  } else {
    return 0;
  }
}

//-----------------------------------------------------------
// Class MultiCastPeer (derived from Peer) member functions
//      ICP object describing MultiCast Peers.
//-----------------------------------------------------------
MultiCastPeer::MultiCastPeer(IpAddr const &addr, uint16_t mc_port, int ttl, ICPProcessor *icpPr)
  : Peer(PEER_MULTICAST, icpPr), _mc_ttl(ttl)
{
  ats_ip_set(&_mc_ip.sa, addr, htons(mc_port));
  memset(&this->_mc, 0, sizeof(this->_mc));
}

int
MultiCastPeer::GetTTL()
{
  return _mc_ttl;
}

sockaddr *
MultiCastPeer::GetIP()
{
  return &_mc_ip.sa;
}

Action *
MultiCastPeer::SendMsg_re(Continuation *cont, void *token, struct msghdr *msg, sockaddr const *to)
{
  Action *a;

  if (to) {
    // Send to MultiCast group member (UniCast)
    Peer *p = FindMultiCastChild(IpAddr(to), ats_ip_port_host_order(to));
    ink_assert(p);
    a = ((ParentSiblingPeer *)p)->SendMsg_re(cont, token, msg, nullptr);
  } else {
    // Send to MultiCast group
    msg->msg_name    = (caddr_t)&_send_chan.addr;
    msg->msg_namelen = sizeof(_send_chan.addr);
    a                = udpNet.sendmsg_re(cont, token, _send_chan.fd, msg);
  }
  return a;
}

Action *
MultiCastPeer::RecvFrom_re(Continuation *cont, void *token, IOBufferBlock * /* bufblock ATS_UNUSED */, int len,
                           struct sockaddr *from, socklen_t *fromlen)
{
  Action *a = udpNet.recvfrom_re(cont, token, _recv_chan.fd, from, fromlen, buf.get(), len, true, 0);
  return a;
}

int
MultiCastPeer::GetRecvFD()
{
  return _recv_chan.fd;
}

int
MultiCastPeer::GetSendFD()
{
  return _send_chan.fd;
}

int
MultiCastPeer::ExpectedReplies(BitMap *expected_replies_list)
{
  // TBD: Expected replies should be calculated as a running average
  //      from replies returned from a periodic inquiry message.

  int replies          = 0;
  ParentSiblingPeer *p = (ParentSiblingPeer *)this->_next;
  while (p) {
    replies += p->ExpectedReplies(expected_replies_list);
    p = (ParentSiblingPeer *)p->GetNext();
  }
  return replies;
}

int
MultiCastPeer::ValidSender(sockaddr *sa)
{
  // TBD: Use hash function
  // Make sure sockaddr_in corresponds to a defined peer in the
  //  MultiCast group.
  Peer *P = _next;
  while (P) {
    if (ats_ip_addr_eq(P->GetIP(), sa) && (ats_ip_port_cast(P->GetIP()) == ats_ip_port_cast(sa))) {
      return 1;
    } else {
      P = P->GetNext();
    }
  }
  return 0;
}

void
MultiCastPeer::LogSendMsg(ICPMsg_t *m, sockaddr const *sa)
{
  // Note: ICPMsg_t (m) is in network byte order
  if (sa) {
    // UniCast send on MultiCast interface, only update stats for
    //  target Peer.
    //
    Peer *p;
    p = FindMultiCastChild(IpAddr(sa), ats_ip_port_host_order(sa));
    if (p) {
      ((ParentSiblingPeer *)p)->LogSendMsg(m, sa);
    }

  } else {
    // Note numerous stats on MultiCast peer and each member peer
    _stats.last_send = Thread::get_hrtime();
    _stats.sent[m->h.opcode]++;
    _stats.total_sent++;

    Peer *p = _next;
    while (p) {
      ((ParentSiblingPeer *)p)->LogSendMsg(m, sa);
      p = p->GetNext();
    }
  }
}

int
MultiCastPeer::IsOnline()
{
  return (_ICPpr->GetConfig()->globalConfig()->ICPmulticastConfigured());
}

int
MultiCastPeer::AddMultiCastChild(Peer *P)
{
  // Add (Peer *) to the given MultiCast structure.
  // Make sure child (ip,port) is unique.
  sockaddr const *ip = P->GetIP();
  if (FindMultiCastChild(IpAddr(ip), ats_ip_port_host_order(ip))) {
    ip_text_buffer x;
    Warning("bad icp.config, multiple multicast child definitions for ip=%s", ats_ip_ntop(ip, x, sizeof(x)));
    return 0; // Not added, already exists
  } else {
    P->SetNext(this->_next);
    this->_next = P;
    ++_mc.defined_members;
    return 1; // Added
  }
}

Peer *
MultiCastPeer::FindMultiCastChild(IpAddr const &addr, uint16_t port)
{
  // Locate child (Peer *) with the given (ip,port). This is split out
  // rather than using a sockaddr so we can indicate the port is to not
  // be checked (@a port == 0).
  Peer *curP = this->_next;
  while (curP) {
    sockaddr const *peer_ip = curP->GetIP();
    if (addr == peer_ip && (!port || port == ats_ip_port_host_order(peer_ip))) {
      return curP;
    } else {
      curP = curP->GetNext();
    }
  }
  return nullptr;
}

//-------------------------------------------------------------------------
// Class PeriodicCont member functions (abstract base class)
//      Look for TS ICP configuration changes by periodically looking.
//-------------------------------------------------------------------------
typedef int (ICPPeriodicCont::*ICPPeriodicContHandler)(int, void *);
PeriodicCont::PeriodicCont(ICPProcessor *icpP) : Continuation(nullptr), _ICPpr(icpP)
{
  mutex = new_ProxyMutex();
}

PeriodicCont::~PeriodicCont()
{
  mutex = nullptr;
}

//-----------------------------------------
// Class ICPPeriodicCont member functions
//-----------------------------------------
ICPPeriodicCont::ICPPeriodicCont(ICPProcessor *icpP)
  : PeriodicCont(icpP), _last_icp_config_callouts(0), _global_config_changed(0), _peer_config_changed(0)
{
}

int
ICPPeriodicCont::PeriodicEvent(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
{
  int do_reconfig     = 0;
  ICPConfiguration *C = _ICPpr->GetConfig();

  if (C->GlobalConfigChange()) {
    do_reconfig = 1;
  }

  int configcallouts = C->ICPConfigCallouts();
  if (_last_icp_config_callouts != configcallouts) {
    // We have a "icp.config" change callout which we
    //  have not processed.
    _last_icp_config_callouts = configcallouts;
    do_reconfig               = 1;
  }

  if (do_reconfig) {
    //
    // We have a configuration change, create worker continuation.
    //
    ICPPeriodicCont *rc = new ICPPeriodicCont(_ICPpr);
    SET_CONTINUATION_HANDLER(rc, (ICPPeriodicContHandler)&ICPPeriodicCont::DoReconfigAction);
    eventProcessor.schedule_imm(rc);
  }
  return EVENT_CONT;
}

int
ICPPeriodicCont::DoReconfigAction(int event, Event *e)
{
  //************************************************************
  // Initiate reconfiguration action if any global or peer
  // configuration changes have occured.
  //************************************************************
  ICPConfiguration *C = _ICPpr->GetConfig();

  for (;;) {
    switch (event) {
    case EVENT_IMMEDIATE:
    case EVENT_INTERVAL: {
      ink_assert(!_global_config_changed && !_peer_config_changed);
      if (C->Lock()) {
        ICP_INCREMENT_DYN_STAT(reconfig_polls_stat);
        if (C->GlobalConfigChange()) {
          _global_config_changed = 1;
        }
        //
        // TS Configuration management makes callouts whenever changes
        // are made to "icp.config", which describes the ICP peer
        // configuration.
        //
        if (C->PeerConfigChange()) {
          _peer_config_changed = 1;
        }
        if (_global_config_changed || _peer_config_changed) {
          //
          // Start the reconfiguration sequence.
          //
          ICP_INCREMENT_DYN_STAT(reconfig_events_stat);
          ICPProcessor::ReconfigState_t NextState;

          NextState = _ICPpr->ReconfigureStateMachine(ICPProcessor::RC_RECONFIG, _global_config_changed, _peer_config_changed);
          if (NextState == ICPProcessor::RC_DONE) {
            // Completed all reconfiguration actions.
            // ReconfigureStateMachine() has invoked C->Unlock()
            delete this;
            return EVENT_DONE;
          } else {
            // Delay and restart update.
            _global_config_changed = 0;
            _peer_config_changed   = 0;
            C->Unlock();
            e->schedule_in(HRTIME_MSECONDS(RETRY_INTERVAL_MSECS));
            return EVENT_CONT;
          }

        } else {
          // No configuration changes detected.
          C->Unlock();
        }

      } else {
        // Missed lock, retry later
        e->schedule_in(HRTIME_MSECONDS(RETRY_INTERVAL_MSECS));
        return EVENT_CONT;
      }
      delete this;
      return EVENT_DONE;
    }
    default: {
      ink_release_assert(!"ICPPeriodicCont::DoReconfigAction() bad event");
    }
    } // End of switch
  }   // End of for

  return EVENT_DONE;
}

//----------------------------------------------------------------
// Class ICPlog member functions
//  Basic accessor object used by the new logging subsystem
//  for squid access log data for ICP queries.
//----------------------------------------------------------------
ink_hrtime
ICPlog::GetElapsedTime()
{
  return (Thread::get_hrtime() - _s->_start_time);
}

sockaddr const *
ICPlog::GetClientIP()
{
  return &_s->_sender.sa;
}

in_port_t
ICPlog::GetClientPort()
{
  return _s->_sender.port();
}

SquidLogCode
ICPlog::GetAction()
{
  if (_s->_queryResult == CACHE_EVENT_LOOKUP) {
    return SQUID_LOG_UDP_HIT;
  } else {
    return SQUID_LOG_UDP_MISS;
  }
}

const char *
ICPlog::GetCode()
{
  static const char *const ICPCodeStr = "000";
  return ICPCodeStr;
}

int
ICPlog::GetSize()
{
  return ntohs(_s->_rICPmsg->h.msglen);
}

const char *
ICPlog::GetMethod()
{
  return HTTP_METHOD_ICP_QUERY;
}

const char *
ICPlog::GetURI()
{
  return (const char *)_s->_rICPmsg->un.query.URL;
}

const char *
ICPlog::GetIdent()
{
  static const char *const ICPidentStr = "";
  return ICPidentStr;
}

SquidHierarchyCode
ICPlog::GetHierarchy()
{
  return SQUID_HIER_NONE;
}

const char *
ICPlog::GetFromHost()
{
  static const char *const FromHostStr = "";
  return FromHostStr;
}

const char *
ICPlog::GetContentType()
{
  static const char *const ICPcontentTypeStr = "";
  return ICPcontentTypeStr;
}

//*****************************************************************************
// ICP Debug support.
//*****************************************************************************
//
static const char *ICPstatNames[] = {"icp_stat_def",
                                     "config_mgmt_callouts_stat",
                                     "reconfig_polls_stat",
                                     "reconfig_events_stat",
                                     "invalid_poll_data_stat",
                                     "no_data_read_stat",
                                     "short_read_stat",
                                     "invalid_sender_stat",
                                     "read_not_v2_icp_stat",
                                     "icp_remote_query_requests_stat",
                                     "icp_remote_responses_stat",
                                     "icp_cache_lookup_success_stat",
                                     "icp_cache_lookup_fail_stat",
                                     "query_response_write_stat",
                                     "query_response_partial_write_stat",
                                     "no_icp_request_for_response_stat",
                                     "icp_response_request_nolock_stat",
                                     "icp_start_icpoff_stat",
                                     "send_query_partial_write_stat",
                                     "icp_queries_no_expected_replies_stat",
                                     "icp_query_hits_stat",
                                     "icp_query_misses_stat",
                                     "invalid_icp_query_response_stat",
                                     "icp_query_requests_stat",
                                     "total_icp_response_time_stat",
                                     "total_udp_send_queries_stat",
                                     "total_icp_request_time_stat",
                                     "icp_total_reloads",
                                     "icp_pending_reloads",
                                     "icp_reload_start_aborts",
                                     "icp_reload_connect_aborts",
                                     "icp_reload_read_aborts",
                                     "icp_reload_write_aborts",
                                     "icp_reload_successes",
                                     "icp_stat_count",
                                     ""};

void
dumpICPstatEntry(int i, const char *name)
{
  int l = strlen(name);
  int64_t sval, cval;

  RecRawStat *p = RecGetGlobalRawStatPtr(icp_rsb, i);
  sval          = p->sum;
  cval          = p->count;

  printf("%-32s %12" PRId64 " %16" PRId64 " %17.4f\n", &name[l > 31 ? l - 31 : 0], cval, sval,
         cval ? (((double)sval) / ((double)cval)) : 0.0);
}

void
dumpICPstats()
{
  printf("\n");
  int i;
  for (i = 0; i < icp_stat_count; ++i) {
    dumpICPstatEntry(i, ICPstatNames[i]);
  }
}

void
ICPProcessor::DumpICPConfig()
{
  Peer *P;
  PeerType_t type;
  int id;
  ip_port_text_buffer ipb;

  Debug("icp", "On=%d, MultiCast=%d, Timeout=%d LocalCacheLookup=%d", GetConfig()->globalConfig()->ICPconfigured(),
        GetConfig()->globalConfig()->ICPmulticastConfigured(), GetConfig()->globalConfig()->ICPqueryTimeout(),
        GetConfig()->globalConfig()->ICPLocalCacheLookup());
  Debug("icp", "StaleLookup=%d, ReplyToUnknowPeer=%d, DefaultReplyPort=%d", GetConfig()->globalConfig()->ICPStaleLookup(),
        GetConfig()->globalConfig()->ICPReplyToUnknownPeer(), GetConfig()->globalConfig()->ICPDefaultReplyPort());

  for (int i = 0; i < (_nPeerList + 1); i++) {
    P    = IdToPeer(i);
    id   = P->GetPeerID();
    type = P->GetType();
    const char *str_type;

    switch (type) {
    case PEER_PARENT: {
      str_type = "P";
      break;
    }
    case PEER_SIBLING: {
      str_type = "S";
      break;
    }
    case PEER_LOCAL: {
      str_type = "L";
      break;
    }
    case PEER_MULTICAST: {
      str_type = "M";
      break;
    }
    default: {
      str_type = "N";
      break;
    }
    } // End of switch

    if (*str_type == 'M') {
      Debug("icp", "[%d]: Type=%s IP=%s", id, str_type, ats_ip_nptop(P->GetIP(), ipb, sizeof(ipb)));
    } else {
      ParentSiblingPeer *Pps = static_cast<ParentSiblingPeer *>(P);
      Debug("icp", "[%d]: Type=%s IP=%s PPort=%d Host=%s", id, str_type, ats_ip_nptop(P->GetIP(), ipb, sizeof(ipb)),
            Pps->GetConfig()->GetProxyPort(), Pps->GetConfig()->GetHostname());

      Debug("icp", "[%d]: MC ON=%d MC_IP=%s MC_TTL=%d", id, Pps->GetConfig()->MultiCastMember(),
            Pps->GetConfig()->GetMultiCastIPAddr().toString(ipb, sizeof(ipb)), Pps->GetConfig()->GetMultiCastTTL());
    }
  }
}

//*****************************************************************************

// End of ICPConfig.cc


text:
module MarkControllable
  extend ActiveSupport::Concern
  def self.included(base)
    base.extend(ClassMethods)
  end

  def model_class
    case controller_name
    when "entries"
      Entry
    when "enclosures"
      enclosure_class
    end
  end

  def mark(mark_class)
    respond_to do |format|
      @mark = model_class.try!(mark_class).new(user_item_params)
      if @mark.save
        format.html { redirect_to ({action: :index}), notice: "Successfully liked." }
        format.json { render :show, status: :created, location: @mark }
      else
        format.html { redirect_to ({action: :index}), notice: @mark.errors }
        format.json { render json: @mark.errors, status: :unprocessable_entity }
      end
    end
  end

  def unmark(mark_class)
    respond_to do |format|
      @mark = model_class.try!(mark_class).find_by(user_item_params)
      if @mark.destroy
        format.html { redirect_to ({action: :index}), notice: "Successfully unliked." }
        format.json { head :no_content }
      else
        format.html { redirect_to ({action: :index}), notice: @mark.errors }
        format.json { render json: @mark.errors, status: :unprocessable_entity }
      end
    end
  end

  module ClassMethods
  end
end

redpajama_set_name: RedPajamaGithub


text:
using CTS.Core.Domain.Attr;
using CTS.Core.Domain.Model;
using CTS.W._150901.Models.Domain.Object.Admin.Master;

namespace CTS.W._150901.Models.Domain.Model.Admin.Master.Accoms.List
{
    /// <summary>
    /// FilterDataModel
    /// </summary>
    public class FilterDataModel : PagerInfoModel<AccomObject>
    {
        [InputText(RuleName = "name", MessageParam = "ADM_MA_ACCOMS_00002")]
        public string AccomName { get; set; }
        // [InputText(RuleName = "slug", MessageParam = "P_CM_00027")]
        // public string Slug { get; set; }
        [InputText(RuleName = "boolean", MessageParam = "P_CM_00002")]
        public bool? DeleteFlag { get; set; }
    }
}


text:
<?php
namespace User\Listener;

use Zend\EventManager\ListenerAggregateInterface;
use Zend\EventManager\ListenerAggregateTrait;
use Zend\EventManager\EventManagerInterface;
use Zend\Mvc\MvcEvent;
use Zend\EventManager\EventInterface;
use Zend\Mvc\Router\RouteMatch;

/**
 * 用户登录验证
 * @author lyh
 *
 */
class CheckAuth implements ListenerAggregateInterface
{
    use ListenerAggregateTrait;

    public function attach(EventManagerInterface $event)
    {
        $this->listeners[] = $event->attach(MvcEvent::EVENT_ROUTE, [
            $this,
            'checkAuth'
        ], - 100);
    }

    public function CheckAuth(EventInterface $event)
    {
        $route = $event->getRouteMatch();
        if (! $route instanceof RouteMatch) {
            return;
        }
        $response = $event->getResponse();
        $routeName = $route->getMatchedRouteName();
        $actionName = $route->getParams()['action'];
        //需要进行用户登录验证的后台模块
        $behindRoute = [
            'DH',
            'User',
            'Program'
        ];
        if (! isset($_COOKIE['DH_user'])) {

            if ((in_array($routeName, $behindRoute)) && ($actionName != 'login'&&$actionName!='register'&&$actionName!='refreshcaptcha')) {
                $url = $event->getRouter()->assemble([
                    'controller' => 'user',
                    'action' => 'login'
                ], [
                    'name' => 'User'
                ]);
                $response->getHeaders()->addHeaderLine('Location', $url);
                $response->setStatusCode(302);
                $response->sendHeaders();
                $event->stopPropagation();
                return $response;
            }
        }
        else{
            if ((in_array($routeName, $behindRoute)) && ($actionName == 'login'||$actionName=='register')) {

                $url = $event->getRouter()->assemble([
                    'controller' => 'index',
                    'action' => 'index'
                ], [
                    'name' => 'DH'
                ]);
                $response->getHeaders()->addHeaderLine('Location', $url);
                $response->setStatusCode(302);
                $response->sendHeaders();
                $event->stopPropagation();
                return $response;
            }
        }
    }
}


text:
<?php

namespace MG\UserBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Intl\Intl;

class AdminRegistrationEditType extends AdminRegistrationType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);
        $builder->remove('username')
        ->remove('image');
    }

    public function getParent()
    {
        return 'MG\UserBundle\Form\AdminRegistrationType';
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'MG\UserBundle\Entity\Admin'
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'mg_userbundle_registration_edit_admin';
    }

    public function getName()
    {
        return $this->getBlockPrefix();
    }

}


text:
require_dependency "roper/application_controller"

require 'jwt'
require 'json'
require 'openssl'
require 'time'

module Roper
  class AccessTokenController < ApplicationController
    skip_before_filter :verify_authenticity_token

    before_action :authenticate_client

    # POST /token
    # https://tools.ietf.org/html/rfc6749#section-3.2
    def token
      grant_type = params[:grant_type]
      render :json => create_error("invalid_request"), :status => 400 and return if !grant_type

      case grant_type
      when 'authorization_code'
        # https://tools.ietf.org/html/rfc6749#section-4.1.3
        process_authorization_code_grant
      when 'refresh_token'
        # https://tools.ietf.org/html/rfc6749#section-6
        process_refresh_token_grant
      when 'password'
        # https://tools.ietf.org/html/rfc6749#section-4.3
        process_resource_owner_password_credentials_grant
      when 'client_credentials'
        # https://tools.ietf.org/html/rfc6749#section-4.4
        process_client_credentials_grant
      when 'urn:ietf:params:oauth:grant-type:jwt-bearer'
        # https://tools.ietf.org/html/rfc7523
        process_jwt_bearer_grant
      else
        render :json => create_error("unsupported_grant_type"), :status => 400 and return
      end
    end

    private

    # https://tools.ietf.org/html/rfc6749#section-3.2.1
    def authenticate_client
      auth_header = request.authorization
      if !auth_header.blank? && auth_header.start_with?("Basic ")
        client_id_client_secret = ActionController::HttpAuthentication::Basic::user_name_and_password(request)
        @client = Roper::Repository.for(:client).find_by_client_id(client_id_client_secret[0])
        # https://tools.ietf.org/html/rfc6749#section-5.2
        if !@client || BCrypt::Password.new(@client.client_secret) != client_id_client_secret[1]
          response.headers['WWW-Authenticate'] = "Basic"
          render :json => create_error("invalid_client"), :status => :unauthorized and return
        end
      elsif params[:grant_type] && params[:grant_type] == 'authorization_code' && params[:client_id]
        @client = Roper::Repository.for(:client).find_by_client_id(params[:client_id])
        render :json => create_error("invalid_client"), :status => 400 and return if !@client
      else
        head :unauthorized and return
      end
    end

    def process_authorization_code_grant
      code = params[:code]
      render :json => create_error("invalid_request"), :status => 400 and return if !code
      redirect_uri = params[:redirect_uri]

      validate_authorization_code_result = Roper::ValidateAuthorizationCode.call(:client => @client, :code => code, :redirect_uri => redirect_uri)
      if !validate_authorization_code_result.success?
        Rails.logger.debug "authorization code validation failed: #{validate_authorization_code_result.message}"
        render :json => create_error("invalid_grant"), :status => 400 and return
      end

      access_token_result = Roper::GenerateAccessToken.call(:client => @client)
      if access_token_result.success?
        redeem_authorization_code_result = Roper::RedeemAuthorizationCode.call(:code => code)
        if redeem_authorization_code_result.success?
          render :json => access_token_result.access_token_hash, :status => 200 and return
        else
          render :json => create_error("invalid_grant"), :status => 400 and return
        end
      else
        render :json => create_error("server_error"), :status => 500 and return
      end
    end

    def process_refresh_token_grant
      refresh_token = params[:refresh_token]
      render :json => create_error("invalid_request"), :status => 400 and return if !refresh_token
      scope = params[:scope]

      validate_refresh_token_result = Roper::ValidateRefreshToken.call(:client => @client, :refresh_token => refresh_token)
      if !validate_refresh_token_result.success?
        render :json => create_error("invalid_grant"), :status => 400 and return
      end

      access_token_result = Roper::GenerateAccessToken.call(:client => @client)
      if access_token_result.success?
        render :json => access_token_result.access_token_hash, :status => 200 and return
      else
        render :json => create_error("server_error"), :status => 500 and return
      end
    end

    def process_resource_owner_password_credentials_grant
      username = params[:username]
      render :json => create_error("invalid_request", "username is required"), :status => 400 and return if !username
      password = params[:password]
      render :json => create_error("invalid_request", "password is required"), :status => 400 and return if !password

      if send(Roper.authenticate_resource_owner_method, username, password)
        access_token_result = Roper::GenerateAccessToken.call(:client => @client)
        if access_token_result.success?
          render :json => access_token_result.access_token_hash, :status => 200 and return
        else
          render :json => create_error("server_error"), :status => 500 and return
        end
      else
        render :json => create_error("invalid_grant"), :status => 400 and return
      end
    end

    def process_client_credentials_grant
      access_token_result = Roper::GenerateAccessToken.call(:client => @client)
      if access_token_result.success?
        render :json => access_token_result.access_token_hash, :status => 200 and return
      else
        render :json => create_error("server_error"), :status => 500 and return
      end
    end

    def process_jwt_bearer_grant
      assertion = params[:assertion]
      render :json => create_error("invalid_request", "assertion is required"), :status => 400 and return if !assertion
      render :json => create_error("invalid_request", "invalid JWT assertion"), :status => 400 and return if assertion.count(".") != 2

      begin
        jwt_issuers = @client.jwt_issuers
        render :json => create_error("invalid_grant"), :status => 400 and return if jwt_issuers.blank?
        render :json => create_error("invalid_grant"), :status => 400 and return if jwt_issuers.map {|jwt_issuer| jwt_issuer.jwt_issuer_keys}.flatten.blank?

        header = JSON.parse(JWT.base64url_decode(assertion.split(".")[0]))
        type = header["typ"]
        render :json => create_error("invalid_request", "invalid JWT header"), :status => 400 and return if type.blank?
        render :json => create_error("invalid_request", "unsupported typ value"), :status => 400 and return if type != "JWT"

        algorithm = header["alg"]
        render :json => create_error("invalid_request", "invalid JWT header"), :status => 400 and return if algorithm.blank?
        accepted_algorithms = jwt_issuers.map {|issuer| issuer.jwt_issuer_keys.map {|issuer_key| issuer_key.algorithm}}.flatten
        render :json => create_error("invalid_grant"), :status => 400 and return if !accepted_algorithms.include?(algorithm)

        unverified_assertion = JWT.decode(assertion, nil, false) # we'll verify the assertion below
        payload = unverified_assertion[0]
        issuer = payload['iss']
        render :json => create_error("invalid_request", "issuer claims (iss) are required"), :status => 400 and return if issuer.blank?

        matching_issuer = jwt_issuers.find {|jwt_issuer| jwt_issuer.issuer == issuer}
        render :json => create_error("invalid_grant"), :status => 400 and return if matching_issuer.blank?

        matching_issuer_key = matching_issuer.jwt_issuer_keys.find {|jwt_issuer_key| jwt_issuer_key.algorithm == algorithm}
        if algorithm =~ /^HS/
          verified_assertion = JWT.decode(assertion, matching_issuer_key.hmac_secret, true, {:algorithm => algorithm})
        elsif algorithm =~ /^RS/
          verified_assertion = JWT.decode(assertion, OpenSSL::PKey::RSA.new(matching_issuer_key.public_key), true, {:algorithm => algorithm})
        elsif algorithm =~ /^ES/
          verified_assertion = JWT.decode(assertion, OpenSSL::PKey::EC.new(matching_issuer_key.public_key), true, {:algorithm => algorithm})
        end

        access_token_result = Roper::GenerateAccessToken.call(:client => @client)
        if access_token_result.success?
          render :json => access_token_result.access_token_hash, :status => 200 and return
        else
          render :json => create_error("server_error"), :status => 500 and return
        end
      rescue JWT::DecodeError
        render :json => create_error("invalid_request", "invalid JWT assertion"), :status => 400 and return
      rescue JSON::ParserError => pe
        render :json => create_error("invalid_request", "invalid JWT assertion"), :status => 400 and return
      end
    end
  end
end


text:
using System;
using System.Collections;
using System.Text;
using Xunit;

namespace System.Collections.SortedListTests
{
    public class RemoveTests : IComparer
    {
        public virtual int Compare(object obj1, object obj2)  // ICompare satisfier.
        {
            return string.Compare(obj1.ToString(), obj2.ToString());
        }

        [Fact]
        public void TestRemoveBasic()
        {
            StringBuilder sblMsg = new StringBuilder(99);
            //

            SortedList sl2 = null;

            StringBuilder sbl3 = new StringBuilder(99);
            StringBuilder sbl4 = new StringBuilder(99);
            StringBuilder sblWork1 = new StringBuilder(99);

            string s1 = null;
            string s2 = null;
            string s3 = null;

            int i = 0;

            //
            // 	Constructor: Create SortedList using this as IComparer and default settings.
            //
            sl2 = new SortedList(this);

            //  Verify that the SortedList is not null.
            Assert.NotNull(sl2);

            //  Verify that the SortedList is empty.
            Assert.Equal(0, sl2.Count);

            Assert.Null(s3);

            //   Testcase: add few key-val pairs
            for (i = 0; i < 100; i++)
            {
                sblMsg.Length = 0;
                sblMsg.Append("key_");
                sblMsg.Append(i);
                s1 = sblMsg.ToString();

                sblMsg.Length = 0;
                sblMsg.Append("val_");
                sblMsg.Append(i);
                s2 = sblMsg.ToString();

                sl2.Add(s1, s2);
            }

            //  Verify that the SortedList is empty.
            Assert.Equal(100, sl2.Count);

            //
            //   Testcase: test Remove (Object)
            //
            for (i = 0; i < 100; i++)
            {
                sblMsg.Length = 0;
                sblMsg.Append("key_");
                sblMsg.Append(i);
                s1 = sblMsg.ToString();

                sl2.Remove(s1); // remove the current object
                Assert.Equal(sl2.Count, (100 - (i + 1)));
            }

            //
            // Boundary - Remove a invalid key: No_Such_Key
            //
            sblMsg.Length = 0;
            sblMsg.Append("No_Such_Key");
            s1 = sblMsg.ToString();
            sl2.Remove(s1);

            //
            // Boundary - null key - pk
            //
            Assert.Throws<ArgumentNullException>(() => { sl2.Remove((string)null); });
        }
    }
}


text:
<?php
/**
 * ClickBank product page
 *
 * @package		silverstripe-clickbank
 * @subpackage	code
 * @author 		Richard Sentino <rix@mindginative.com>
 */
class ClickBankProduct extends Page {
	static $db = array (
		'ProductID' => 'Varchar(10)',
		'RedirectToClickBank' => "Boolean"
	);

	static $has_one = array (
		'ProductImage' => 'Image'
	);

	public static $defaults = array (
		'RedirectToClickBank' => true,
	);

	static $default_parent = 'ClickBankHolder';

	static $allowed_children = array();

	static $can_be_root = false;

	/**
	 * Getter for ClickBankLink property
	 *
	 * @param	none
	 * @return	string
	 */
	protected function getClickBankURI() {
		$clickBankSiteConfig = SiteConfig::current_site_config();
		if (!empty($clickBankSiteConfig->ClickBankID)) {
			$cbskin = ($clickBankSiteConfig->ClickBankSkin) ? "/?cbskin={$clickBankSiteConfig->ClickBankSkin}" : "";
			return "http://{$this->ProductID}.{$clickBankSiteConfig->ClickBankID}.pay.clickbank.net" . $cbskin;
		}
		return false;
	}

	public function getCMSFields() {
		$field = parent::getCMSFields();
		$field->addFieldToTab('Root.Content.Main', new LiteralField('CBSettings', _t('ClickBank.PP_SETTINGS_SECTION_TITLE')));
		$field->addFieldToTab('Root.Content.Main', new CheckboxField('RedirectToClickBank', _t('ClickBank.PP_REDIRECT_TO_CLICKBANK')));
		$field->addFieldToTab('Root.Content.Main', new TextField('ProductID', _t('ClickBank.PP_CLICKBANK_PRODUCT_ID')));

		$cb_product_url = '';
		$cb_product_alias = '';
		if (!empty($this->ProductID)) {
			$cb_product_url = $this->getClickBankURI();
			$cb_product_alias = Director::absoluteURL($this->Link());
		}

		$field->addFieldToTab('Root.Content.Main', new ReadonlyField('ClickBankURIAlias', _t('ClickBank.PP_PRODUCT_URL_ALIAS'), $cb_product_alias));
		$field->addFieldToTab('Root.Content.Main', new ReadonlyField('ClickBankURI', _t('ClickBank.PP_CLICKBANK_PRODUCT_URL_ALIAS'), $cb_product_url));

		// Product Image
		$field->addFieldToTab('Root.Content.ProductImage', new ImageField('ProductImage'));

		return $field;
	}

	/**
	 * Flags required fields in the CMS admin
	 *
	 * @param	none
	 * @return	Object	Error message
	 */
	public function getCMSValidator() {
		return new RequiredFields('ProductID');
	}
}

class ClickBankProduct_Controller extends Page_Controller {
	static $allowed_actions = array(
		'index',
		'buy'
	);

	/**
	 * Default function
	 *
	 * @param	none
	 * @return	none	Displays product page or redirect to ClickBank payment page
	 */
	public function index() {
		if($this->RedirectToClickBank) {
			return Director::redirect($this->getClickBankURI());
		} else {
			$data = array (
				'Title' => $this->Title,
				'Content' => $this->Content
			);

			return $this->customise($data)->renderWith(array('ClickBankProductPage', 'Page'));
		}
	}

	/**
	 * Send to ClickBank payment page
	 *
	 * @param	none
	 * @return	none
	 */
	public function buy() {
		return Director::redirect($this->getClickBankURI());
	}
}


text:
use strict;
use warnings;
use Parallel::ForkManager;
use Getopt::Long;

# debug flag:
my $debug;
my $MAX_PROCESSES = 4;
my $cmds_file;
GetOptions('debug'       => \$debug,
           'in=s'        => \$cmds_file,
           'ncpu=i'      => \$MAX_PROCESSES,
        );

my $pm = Parallel::ForkManager->new($MAX_PROCESSES);

open(CMDS, "< $cmds_file");

while(my $line = <CMDS>){

	print $line;

	# Forks and returns the pid for the child:
	my $pid = $pm->start and next;

	chomp $line;
	my $cmd = $line;
	system $cmd;

	$pm->finish; # Terminates the child process
}

close(CMDS);


text:
// -----------------------------------------------------------------------
// <copyright file="OrderSubscriptionItemViewModel.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

namespace Microsoft.Store.PartnerCenter.CustomerPortal.Models
{
    using System.ComponentModel.DataAnnotations;

    /// <summary>
    /// The order view model.
    /// </summary>
    public class OrderSubscriptionItemViewModel
    {
        /// <summary>
        /// Gets or sets the offer Id tied to the order.
        /// </summary>
        public string OfferId { get; set; }

        /// <summary>
        /// Gets or sets the subscription Id (used primarily during update calls).
        /// </summary>
        public string SubscriptionId { get; set; }

        /// <summary>
        /// Gets or sets the quantity of the offer being ordered.
        /// </summary>
        public int Quantity { get; set; }
    }
}


text:
package node

import (
	"fmt"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"

	"k8s.io/api/core/v1"
	"k8s.io/klog/v2"
)

// RecordNodeStatusChange records a event related to a node status change. (Common to lifecycle and ipam)
func RecordNodeStatusChange(recorder record.EventRecorder, node *v1.Node, newStatus string) {
	ref := &v1.ObjectReference{
		APIVersion: "v1",
		Kind:       "Node",
		Name:       node.Name,
		UID:        node.UID,
		Namespace:  "",
	}
	klog.V(2).Infof("Recording status change %s event message for node %s", newStatus, node.Name)
	// TODO: This requires a transaction, either both node status is updated
	// and event is recorded or neither should happen, see issue #6055.
	recorder.Eventf(ref, v1.EventTypeNormal, newStatus, "Node %s status is now: %s", node.Name, newStatus)
}

// CreateAddNodeHandler creates an add node handler.
func CreateAddNodeHandler(f func(node *v1.Node) error) func(obj interface{}) {
	return func(originalObj interface{}) {
		node := originalObj.(*v1.Node).DeepCopy()
		if err := f(node); err != nil {
			utilruntime.HandleError(fmt.Errorf("Error while processing Node Add: %v", err))
		}
	}
}

// CreateUpdateNodeHandler creates a node update handler. (Common to lifecycle and ipam)
func CreateUpdateNodeHandler(f func(oldNode, newNode *v1.Node) error) func(oldObj, newObj interface{}) {
	return func(origOldObj, origNewObj interface{}) {
		node := origNewObj.(*v1.Node).DeepCopy()
		prevNode := origOldObj.(*v1.Node).DeepCopy()

		if err := f(prevNode, node); err != nil {
			utilruntime.HandleError(fmt.Errorf("Error while processing Node Add/Delete: %v", err))
		}
	}
}

// CreateDeleteNodeHandler creates a delete node handler. (Common to lifecycle and ipam)
func CreateDeleteNodeHandler(f func(node *v1.Node) error) func(obj interface{}) {
	return func(originalObj interface{}) {
		originalNode, isNode := originalObj.(*v1.Node)
		// We can get DeletedFinalStateUnknown instead of *v1.Node here and
		// we need to handle that correctly. #34692
		if !isNode {
			deletedState, ok := originalObj.(cache.DeletedFinalStateUnknown)
			if !ok {
				klog.Errorf("Received unexpected object: %v", originalObj)
				return
			}
			originalNode, ok = deletedState.Obj.(*v1.Node)
			if !ok {
				klog.Errorf("DeletedFinalStateUnknown contained non-Node object: %v", deletedState.Obj)
				return
			}
		}
		node := originalNode.DeepCopy()
		if err := f(node); err != nil {
			utilruntime.HandleError(fmt.Errorf("Error while processing Node Add/Delete: %v", err))
		}
	}
}

// GetNodeCondition extracts the provided condition from the given status and returns that.
// Returns nil and -1 if the condition is not present, and the index of the located condition.
func GetNodeCondition(status *v1.NodeStatus, conditionType v1.NodeConditionType) (int, *v1.NodeCondition) {
	if status == nil {
		return -1, nil
	}
	for i := range status.Conditions {
		if status.Conditions[i].Type == conditionType {
			return i, &status.Conditions[i]
		}
	}
	return -1, nil
}


text: @keyframes bpk-keyframe-spin{100%{transform:rotate(1turn)}}.bpk-accordion{margin:0}


text:
package mprog.nl.parkeermij.activities;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.skyfishjy.library.RippleBackground;

import java.util.List;

import javax.inject.Inject;

import butterknife.BindView;
import butterknife.ButterKnife;
import mprog.nl.parkeermij.MVP.presenters.StartUpActivityPresenter;
import mprog.nl.parkeermij.MVP.views.StartUpActivityView;
import mprog.nl.parkeermij.R;
import mprog.nl.parkeermij.dagger.components.DaggerStartUpActivityComponent;
import mprog.nl.parkeermij.dagger.modules.StartUpActivityModule;
import mprog.nl.parkeermij.models.LocationObject;
import mprog.nl.parkeermij.models.RouteObject;

/**
 * Tamme Thijs
 * StartUpActivity, setting up app by retrieving GPS
 */
public class StartUpActivity extends AppCompatActivity implements StartUpActivityView,
        View.OnClickListener, GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener, LocationListener {

    private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
    private static final int GPS_CHECK = 999;

    private LocationManager mLocManager;
    private Boolean mLocationEnabled;
    private Boolean isRipple = false;
    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;
    private Location mLocation;

    @BindView(R.id.location)
    FloatingActionButton mLocationButton;

    @BindView(R.id.ripple)
    RippleBackground mRippleBackground;

    @BindView(R.id.coordinatorlayout)
    CoordinatorLayout mCoordinatorLayout;

    @Inject
    StartUpActivityPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_startup);
        ButterKnife.bind(this);

        init();
        initDependencies();
        gpsCheck();
    }

    /**
     * Binding layers with dagger
     */
    private void initDependencies() {
        DaggerStartUpActivityComponent.builder()
                .startUpActivityModule(new StartUpActivityModule(this))
                .build()
                .inject(this);
    }

    private void init() {
        mLocationButton.setOnClickListener(this);
        mLocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        // Build Google API client
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();

        // Create the LocationRequest object
        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(10 * 1000)        // 10 seconds, in milliseconds
                .setFastestInterval(1000); // 1 second, in milliseconds

        // load first fragment
        dataCheck();
    }

    /**
     * Used for feedback to user that app is handling data
     */
    @Override
    public void toggleRipple() {
        if (!isRipple) {
            mRippleBackground.startRippleAnimation();
            isRipple = true;
        } else {
            mRippleBackground.stopRippleAnimation();
            isRipple = false;
        }
    }

    /**
     * Allert message if GPS is currently not enabled or available.
     */
    private void gpsAlert() {
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("Voor de huidige locatie moet uw GPS aanstaan, wilt u deze nu aanzetten?")
                .setCancelable(false)
                .setPositiveButton("Ja", new DialogInterface.OnClickListener() {
                    public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
                        startActivityForResult(
                                new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS),
                                GPS_CHECK);
                    }
                })
                .setNegativeButton("Nee", new DialogInterface.OnClickListener() {
                    public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
                        dialog.cancel();
                    }
                });
        final AlertDialog alert = builder.create();
        alert.show();
    }

    /**
     * Checks is GPS is available
     */
    @Override
    public void gpsCheck() {
        if (!mLocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            // Dissable button change layout so that user knows its unavailable
            mLocationButton.setAlpha(.5f);
            mLocationEnabled = false;
        } else {
            // Enable button
            mLocationEnabled = true;
            mLocationButton.setAlpha(1f);
        }
    }

    @Override
    public void startBaseActivity(@Nullable List<RouteObject> routeObjects) {

        if (routeObjects != null) {
            Intent intent = BaseActivity.newIntent(this, mLocation, routeObjects);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
            startActivity(intent);
        }
    }

    /**
     * Shows snackbar with custom message     *
     * @param message
     */
    @Override
    public void toggleSnackbar(String message) {
        Snackbar snackbar = Snackbar.make(mCoordinatorLayout, message, Snackbar.LENGTH_LONG);
        View v = snackbar.getView();

        //workaround to use custom text color in snackbar
        TextView tv = (TextView) v.findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(Color.WHITE);

        snackbar.show();
        toggleRipple(); // connection failed so dissable ripple

    }

    @Override
    public void onClick(View v) {
        if (isNetworkAvailable()) { // internet check
            if (!isRipple) { // check if logic is in progress
                mPresenter.onClick(v.getId());
            }
        } else {
            toggleSnackbar(getString(R.string.string_no_internet));
        }
    }

    /**
     * start if all requirements ae met
     */
    @Override
    public void dataCheck() {
        // double check GPS, user might have turned it off after initial check
        gpsCheck();

        if (!mLocationEnabled) {
            gpsAlert();
        } else if (mLocation == null) { // check if location exists
            toggleRipple();
            mGoogleApiClient.connect(); // get location
        } else {
            if (!isRipple) {
                toggleRipple();
            }

            mPresenter.getData(new LocationObject(mLocation.getLatitude(), mLocation.getLongitude()));
        }
    }

    /**
     * Method that checks if device has network acces.
     *
     * @return boolean
     */
    public boolean isNetworkAvailable() {
        final ConnectivityManager connectivityManager = ((ConnectivityManager)
                this.getSystemService(Context.CONNECTIVITY_SERVICE));
        return connectivityManager.getActiveNetworkInfo() != null &&
                connectivityManager.getActiveNetworkInfo().isConnected();
    }

    /**
     * Catches result from GPS activity
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // check result
        if (requestCode == GPS_CHECK && resultCode == Activity.RESULT_OK) {
            gpsCheck();
        }
    }

    /**
     * Is called after connection with GoogleApiClient, checks permissions and if the GPS
     * returned a valid location.
     * @param bundle
     */
    @Override
    public void onConnected(Bundle bundle) {
        // permissions
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                        != PackageManager.PERMISSION_GRANTED) {
            toggleSnackbar(getString(R.string.permission_request));
            mLocationButton.setEnabled(false);

        } else {

            // try to populate location object
            mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
            if (mLocation == null) {
                // keep asking API for location when location is null
                LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
                        mLocationRequest, this);
            } else {
                // start next activity
                dataCheck();
            }
        }
    }

    @Override
    public void onConnectionSuspended(int i) {
        // required method
    }

    /**
     * Called after GoogleAPIClient failed
     * Source: http://stackoverflow.com/questions/17811720/googleplayservicesutil-error-dialog-button-does-nothing     *
     * @param connectionResult
     */
    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        // test connection
        if (connectionResult.hasResolution()) {
            try {
                // Start an Activity that tries to resolve the error
                connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);

            } catch (IntentSender.SendIntentException e) {
                e.printStackTrace();
            }
        } else {
            // Snackbar fail connection GoogleApiClient
            toggleSnackbar(connectionResult.getErrorMessage());
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        // permissioncheck
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                        != PackageManager.PERMISSION_GRANTED) {
            toggleSnackbar(getString(R.string.permission_request));
            return;
        }
        // update locationObject
        mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    }

    /**
     * Disconnect if activity is paused.
     */
    @Override
    protected void onPause() {
        super.onPause();
        if (mGoogleApiClient.isConnected()) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
            mGoogleApiClient.disconnect();
        }

        if (isRipple) {
            toggleRipple();
        }
    }
}


text:
<mat-card>
  <mat-card-title>Popover</mat-card-title>
  <mat-card-content>
    <button mat-icon-button [popoverTriggerFor]="popover">
      <mat-icon>grade</mat-icon>
    </button>
    <stbui-popover #popover="stbuiPopover">
      <stbui-date-picker mode="landscape"></stbui-date-picker>
    </stbui-popover>
  </mat-card-content>
</mat-card>

<mat-card>
  <mat-card-title>Positioning</mat-card-title>
  <mat-card-content>

      <mat-form-field>
        <mat-select [(ngModel)]="horizontalAlign" placeholder="horizontalAlign">
          <mat-option value="before">Before</mat-option>
          <mat-option value="start">Start</mat-option>
          <mat-option value="center">Center</mat-option>
          <mat-option value="end">End</mat-option>
          <mat-option value="after">After</mat-option>
          <mat-option value="octopus">Octopus</mat-option>
        </mat-select>
      </mat-form-field>
      <mat-form-field>
        <mat-select [(ngModel)]="verticalAlign" placeholder="verticalAlign">
          <mat-option value="above">Above</mat-option>
          <mat-option value="start">Start</mat-option>
          <mat-option value="center">Center</mat-option>
          <mat-option value="end">End</mat-option>
          <mat-option value="below">Below</mat-option>
          <mat-option value="aardvark">Aardvark</mat-option>
        </mat-select>
      </mat-form-field>
      <mat-form-field>
        <input matInput type="number" [(ngModel)]="margin" placeholder="anchor's margin-left (px)">
      </mat-form-field>

    <button mat-raised-button color="accent" [style.marginLeft]="margin + 'px'">
      显示
    </button>
  </mat-card-content>
</mat-card>

<mat-card>
  <mat-card-title>Action API</mat-card-title>
  <mat-card-content>
    <button mat-icon-button [popoverTriggerFor]="popover">
      <mat-icon>grade</mat-icon>
    </button>
    <stbui-popover #popover="stbuiPopover">
      <stbui-date-picker mode="landscape"></stbui-date-picker>
    </stbui-popover>

    <button mat-raised-button>popover#open()</button>
    <button mat-raised-button>popover#close()</button>
    <button mat-raised-button>popover#toggle()</button>
  </mat-card-content>
</mat-card>

<mat-card>
  <mat-card-title>Scroll Strategies</mat-card-title>
  <mat-card-content>
    <mat-radio-group>
      <mat-radio-button *ngFor="let scrollOption of scrollOptions" [value]="scrollOption.value">
        {{scrollOption.name}}
      </mat-radio-button>
    </mat-radio-group>

      <button mat-raised-button>显示</button>

  </mat-card-content>
</mat-card>

<mat-card>
  <mat-card-title>Focus Behavior</mat-card-title>
  <mat-card-content>
    <button mat-icon-button [popoverTriggerFor]="popover">
      <mat-icon>grade</mat-icon>
    </button>
    <stbui-popover #popover="stbuiPopover">
      <stbui-date-picker mode="landscape"></stbui-date-picker>
    </stbui-popover>
  </mat-card-content>
</mat-card>

<mat-card>
  <mat-card-title>Custom Transitions</mat-card-title>
  <mat-card-content>
    <button mat-icon-button [popoverTriggerFor]="popover">
      <mat-icon>grade</mat-icon>
    </button>
    <stbui-popover #popover="stbuiPopover">
      <stbui-date-picker mode="landscape"></stbui-date-picker>
    </stbui-popover>
  </mat-card-content>
</mat-card>

<mat-card>
  <mat-card-title>文件上传</mat-card-title>
  <mat-card-content>
    <stbui-file-upload></stbui-file-upload>
  </mat-card-content>
</mat-card>


text:
define(function(require) {

    var VisualMapView = require('./VisualMapView');
    var zrUtil = require('zrender/core/util');
    var graphic = require('../../util/graphic');
    var symbolCreators = require('../../util/symbol');
    var layout = require('../../util/layout');
    var helper = require('./helper');

    var PiecewiseVisualMapView = VisualMapView.extend({

        type: 'visualMap.piecewise',

        /**
         * @protected
         * @override
         */
        doRender: function () {
            var thisGroup = this.group;

            thisGroup.removeAll();

            var visualMapModel = this.visualMapModel;
            var textGap = visualMapModel.get('textGap');
            var textStyleModel = visualMapModel.textStyleModel;
            var textFont = textStyleModel.getFont();
            var textFill = textStyleModel.getTextColor();
            var itemAlign = this._getItemAlign();
            var itemSize = visualMapModel.itemSize;

            var viewData = this._getViewData();
            var showLabel = !viewData.endsText;
            var showEndsText = !showLabel;

            showEndsText && this._renderEndsText(thisGroup, viewData.endsText[0], itemSize);

            zrUtil.each(viewData.pieceList, renderItem, this);

            showEndsText && this._renderEndsText(thisGroup, viewData.endsText[1], itemSize);

            layout.box(
                visualMapModel.get('orient'), thisGroup, visualMapModel.get('itemGap')
            );

            this.renderBackground(thisGroup);

            this.positionGroup(thisGroup);

            function renderItem(item) {
                var itemGroup = new graphic.Group();
                itemGroup.onclick = zrUtil.bind(this._onItemClick, this, item.piece);

                this._createItemSymbol(itemGroup, item.piece, [0, 0, itemSize[0], itemSize[1]]);

                if (showLabel) {
                    itemGroup.add(new graphic.Text({
                        style: {
                            x: itemAlign === 'right' ? -textGap : itemSize[0] + textGap,
                            y: itemSize[1] / 2,
                            text: item.piece.text,
                            textVerticalAlign: 'middle',
                            textAlign: itemAlign,
                            textFont: textFont,
                            fill: textFill
                        }
                    }));
                }

                thisGroup.add(itemGroup);
            }
        },

        /**
         * @private
         */
        _getItemAlign: function () {
            var visualMapModel = this.visualMapModel;
            var modelOption = visualMapModel.option;
            if (modelOption.orient === 'vertical') {
                return helper.getItemAlign(
                    visualMapModel, this.api, visualMapModel.itemSize
                );
            }
            else { // horizontal, most case left unless specifying right.
                var align = modelOption.align;
                if (!align || align === 'auto') {
                    align = 'left';
                }
                return align;
            }
        },

        /**
         * @private
         */
        _renderEndsText: function (group, text, itemSize) {
            if (!text) {
                return;
            }
            var itemGroup = new graphic.Group();
            var textStyleModel = this.visualMapModel.textStyleModel;
            itemGroup.add(new graphic.Text({
                style: {
                    x: itemSize[0] / 2,
                    y: itemSize[1] / 2,
                    textVerticalAlign: 'middle',
                    textAlign: 'center',
                    text: text,
                    textFont: textStyleModel.getFont(),
                    fill: textStyleModel.getTextColor()
                }
            }));

            group.add(itemGroup);
        },

        /**
         * @private
         * @return {Object} {peiceList, endsText} The order is the same as screen pixel order.
         */
        _getViewData: function () {
            var visualMapModel = this.visualMapModel;

            var pieceList = zrUtil.map(visualMapModel.getPieceList(), function (piece, index) {
                return {piece: piece, index: index};
            });
            var endsText = visualMapModel.get('text');

            // Consider orient and inverse.
            var orient = visualMapModel.get('orient');
            var inverse = visualMapModel.get('inverse');

            // Order of pieceList is always [low, ..., high]
            if (orient === 'horizontal' ? inverse : !inverse) {
                pieceList.reverse();
            }
            // Origin order of endsText is [high, low]
            else if (endsText) {
                endsText = endsText.slice().reverse();
            }

            return {pieceList: pieceList, endsText: endsText};
        },

        /**
         * @private
         */
        _createItemSymbol: function (group, piece, shapeParam) {
            var representValue;
            if (this.visualMapModel.isCategory()) {
                representValue = piece.value;
            }
            else {
                if (piece.value != null) {
                    representValue = piece.value;
                }
                else {
                    var pieceInterval = piece.interval || [];
                    representValue = (pieceInterval[0] + pieceInterval[1]) / 2;
                }
            }

            group.add(symbolCreators.createSymbol(
                this.getControllerVisual(representValue, 'symbol'),
                shapeParam[0], shapeParam[1], shapeParam[2], shapeParam[3],
                this.getControllerVisual(representValue, 'color')
            ));
        },

        /**
         * @private
         */
        _onItemClick: function (piece) {
            var visualMapModel = this.visualMapModel;
            var option = visualMapModel.option;
            var selected = zrUtil.clone(option.selected);
            var newKey = visualMapModel.getSelectedMapKey(piece);

            if (option.selectedMode === 'single') {
                selected[newKey] = true;
                zrUtil.each(selected, function (o, key) {
                    selected[key] = key === newKey;
                });
            }
            else {
                selected[newKey] = !selected[newKey];
            }

            this.api.dispatchAction({
                type: 'selectDataRange',
                from: this.uid,
                visualMapId: this.visualMapModel.id,
                selected: selected
            });
        }
    });

    return PiecewiseVisualMapView;
});


text:
{% extends "shop/print/base.html" %}
{% load i18n %}

{% block email-thead %}
	{{ block.super }}
	{% block email-title %}{% trans "Delivery note for" %} {{ data.identifier }}{% endblock %}
{% endblock %}

{% block content %}
	<h4>{% trans "Delivery Note" %}: {{ order.identifier }}</h4>
	{% include "shop/print/order.html" %}
{% endblock %}


text:
import React, { Component } from 'react';
import styles from './DashboardCommunity.scss';
import { Link } from 'react-router-dom';

class DashboardCommunity extends Component {
	render() {
		return (

				<Link to={this.props.url} className="link-unstyled">

{this.props.children}

What is {this.props.communityName}?

{this.props.ourDescription}

Usage Statistics

							{/*
{this.props.stats}
*/}

								{this.props.stats.map(stat => (

{stat}

								))}

				</Link>

		);
	}
}

export default DashboardCommunity;


text:
import React, { useState } from 'react';
import Button from 'react-bootstrap/Button';
import Collapse from 'react-bootstrap/Collapse';

function Example() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button
        onClick={() => setOpen(!open)}
        aria-controls="example-collapse-text"
        aria-expanded={open}
      >
        click
      </Button>
      <Collapse in={open}>
        <div id="example-collapse-text">
          Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus
          terry richardson ad squid. Nihil anim keffiyeh helvetica, craft beer
          labore wes anderson cred nesciunt sapiente ea proident.
        </div>
      </Collapse>
    </>
  );
}

render(<Example />);


text:
<!DOCTYPE html>

    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">

    <title>Beiyi Wu</title>

    <link rel="stylesheet" type="text/css" href="app.css">


text:
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;

require_once __DIR__ . '/../src/autoload.php';

use phpsearch\SearchException;
use phpsearch\SearchOptions;
use phpsearch\SearchSettings;

class SearchOptionsTest extends TestCase
{
    /**
     * @var SearchOptions
     */
    private $searchoptions;

    public function __construct()
    {
        parent::__construct();
        $this->searchoptions = new SearchOptions();
    }

    public function test_no_args()
    {
        $settings = $this->searchoptions->settings_from_args([]);
        $this->assertFalse($settings->archivesonly);
        $this->assertTrue($settings->colorize);
        $this->assertFalse($settings->debug);
        $this->assertTrue($settings->excludehidden);
        $this->assertFalse($settings->firstmatch);
        $this->assertEquals(0, $settings->linesafter);
        $this->assertEquals(0, $settings->linesbefore);
        $this->assertFalse($settings->listdirs);
        $this->assertFalse($settings->listfiles);
        $this->assertFalse($settings->listlines);
        $this->assertEquals(150, $settings->maxlinelength);
        $this->assertFalse($settings->multilinesearch);
        $this->assertTrue($settings->printresults);
        $this->assertFalse($settings->printusage);
        $this->assertFalse($settings->printversion);
        $this->assertTrue($settings->recursive);
        $this->assertFalse($settings->searcharchives);
        $this->assertFalse(isset($settings->startpath));
        $this->assertFalse($settings->uniquelines);
        $this->assertFalse($settings->verbose);
    }

    public function test_valid_args()
    {
        $args = ['-x', 'php,py', '-s', 'Search', '.'];
        $settings = $this->searchoptions->settings_from_args($args);
        $this->assertCount(2, $settings->in_extensions);
        $this->assertTrue(in_array('php', $settings->in_extensions));
        $this->assertTrue(in_array('py', $settings->in_extensions));
        $this->assertCount(1, $settings->searchpatterns);
        $this->assertEquals('Search', $settings->searchpatterns[0]);
        $this->assertEquals('.', $settings->startpath);
    }

    public function test_archivesonly_arg()
    {
        $args = ['--archivesonly'];
        $settings = $this->searchoptions->settings_from_args($args);
        $this->assertTrue($settings->archivesonly);
        $this->assertTrue($settings->searcharchives);
    }

    public function test_debug_arg()
    {
        $args = ['--debug'];
        $settings = $this->searchoptions->settings_from_args($args);
        $this->assertTrue($settings->debug);
        $this->assertTrue($settings->verbose);
    }

    public function test_missing_arg()
    {
        $this->expectException(SearchException::class);
        $args = ['-x', 'php,py', '-s', 'Search', '.', '-D'];
        $this->searchoptions->settings_from_args($args);
    }

    public function test_invalid_arg()
    {
        $this->expectException(SearchException::class);
        $args = ['-x', 'php,py', '-s', 'Search', '.', '-Q'];
        $this->searchoptions->settings_from_args($args);
    }

    public function test_settings_from_json()
    {
        $settings = new SearchSettings();
        $json = <<<"END_JSON"
{
  "startpath": "~/src/xsearch/",
  "in-ext": ["js","ts"],
  "out-dirpattern": "node_module",
  "out-filepattern": ["temp"],
  "searchpattern": "Searcher",
  "linesbefore": 2,
  "linesafter": 2,
  "debug": true,
  "allmatches": false,
  "includehidden": true
}
END_JSON;
        $this->searchoptions->settings_from_json($json, $settings);
        $this->assertEquals('~/src/xsearch/', $settings->startpath);
        $this->assertCount(2, $settings->in_extensions);
        $this->assertTrue(in_array('js', $settings->in_extensions));
        $this->assertTrue(in_array('ts', $settings->in_extensions));
        $this->assertCount(1, $settings->out_dirpatterns);
        $this->assertEquals('node_module', $settings->out_dirpatterns[0]);
        $this->assertCount(1, $settings->out_filepatterns);
        $this->assertEquals('temp', $settings->out_filepatterns[0]);
        $this->assertCount(1, $settings->searchpatterns);
        $this->assertEquals('Searcher', $settings->searchpatterns[0]);
        $this->assertEquals(2, $settings->linesbefore);
        $this->assertEquals(2, $settings->linesafter);
        $this->assertTrue($settings->debug);
        $this->assertTrue($settings->verbose);
        $this->assertTrue($settings->firstmatch);
        $this->assertTrue(!$settings->excludehidden);
    }
}


text:
import { Parser } from "../Parser";
import { ParseTreeVisitor } from "./ParseTreeVisitor";
import { RuleContext } from "../RuleContext";
import { SyntaxTree } from "./SyntaxTree";
/** An interface to access the tree of {@link RuleContext} objects created
 *  during a parse that makes the data structure look like a simple parse tree.
 *  This node represents both internal nodes, rule invocations,
 *  and leaf nodes, token matches.
 *
 *  The payload is either a {@link Token} or a {@link RuleContext} object.
 */
export interface ParseTree extends SyntaxTree {
    readonly parent: ParseTree | undefined;
    /**
     * Set the parent for this node.
     *
     * @since 4.7
     */
    setParent(parent: RuleContext): void;
    getChild(i: number): ParseTree;
    /** The {@link ParseTreeVisitor} needs a double dispatch method. */
    accept<T>(visitor: ParseTreeVisitor<T>): T;
    /** Return the combined text of all leaf nodes. Does not get any
     *  off-channel tokens (if any) so won't return whitespace and
     *  comments if they are sent to parser on hidden channel.
     */
    readonly text: string;
    /** Specialize toStringTree so that it can print out more information
     * 	based upon the parser.
     */
    toStringTree(parser?: Parser): string;
}