text:
#ifndef WILDDOG_PORT_TYPE_ESP
#include <stdio.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "option.h"
#include "wilddog_payload.h"

#include "utlist.h"
#include "wilddog_config.h"
#include "wilddog.h"
#include "wilddog_endian.h"
#include "wilddog_protocol.h"
#include "wilddog_protocol_coap.h"
#include "wilddog_debug.h"
#include "wilddog_common.h"
#include "wilddog_sec.h"
#include "test_lib.h"

#include "wilddog_conn.h"

#define  COAP_CODE_GET(code)   ((code >> 5) * 100 + (code & 0x1F))
#define WILDDOG_RECONNECT_TIMES (3) //reconnect retry time

typedef struct _WILDDOG_COAP_OBSERVE_DATA{
    u32 last_index;
    u32 last_recv_time;
    u32 maxage;
}_Wilddog_Coap_Observe_Data_T;

/*
 * Function:    _wilddog_conn_mallocRecvBuffer
 * Description: conn layer malloc the buffer which used for recv
 *
 * Input:       N/A
 * Output:      N/A
 * Return:      the buffer's pointer
*/
STATIC u8* WD_SYSTEM _wilddog_coap_mallocRecvBuffer(Wilddog_Protocol_T *proto)
{
    int i = 0;
    u8* buffer = NULL;

    wilddog_assert(proto, NULL);

    for(i = 0; i < WILDDOG_PROTO_RECV_BUF_NUM; i++){
        if(proto->recv_buf[i].isused == FALSE)
        {
            buffer = proto->recv_buf[i].data;
            proto->recv_buf[i].isused = TRUE;
            memset(buffer, 0, WILDDOG_PROTO_MAXSIZE);
        }
    }

    return buffer;
}

/*
 * Function:    _wilddog_conn_freeRecvBuffer
 * Description: conn layer free the buffer which used for recv
 *
 * Input:       ptr: the buffer's pointer
 * Output:      N/A
 * Return:      N/A
*/
STATIC void WD_SYSTEM _wilddog_coap_freeRecvBuffer(Wilddog_Protocol_T *proto,u8* ptr)
{
    int i;

    if(!ptr || !proto)
        return;

    for(i = 0; i < WILDDOG_PROTO_RECV_BUF_NUM; i++){
        if(proto->recv_buf[i].data == ptr && TRUE == proto->recv_buf[i].isused){
            proto->recv_buf[i].isused = FALSE;
        }
    }

    return;
}

/*
 * Function:    _wilddog_coap_ntoh
 * Description: Convert the byte order
 * Input:       src: The pointer of the source byte
 *              srcLen: src max bytes
 *              dstLen: The length of the source byte
 * Output:      dst: The pointer of the destination byte
 * Return:      N/A
*/
STATIC INLINE void WD_SYSTEM  _wilddog_coap_ntoh
    (
    u8 *dst,
    const u16 dstLen,
    const u8 *src,
    const u16 srcLen
    )
{
    u16 i;
    u16 len = srcLen > dstLen ? dstLen:srcLen;
    // if srcLen > dstLen, copy lsb
#if WILDDOG_LITTLE_ENDIAN == 1
    // lsb is from head
    for(i = 0; i < len; i++){
        dst[i] = src[srcLen - i - 1];
    }
#else
    //lsb is from tail
    for(i = 0; i < len; i++){
        if(dstLen - srcLen + i < 0)
            continue;
        dst[dstLen - srcLen + i] = src[i];
    }
#endif
}

/*
 * Function:    _wilddog_coap_random
 * Description: Get a rand number
 * Input:       N/A
 * Output:      N/A
 * Return:      A rand number
*/
STATIC INLINE u32 WD_SYSTEM _wilddog_coap_random(void)
{
    srand(_wilddog_getTime());
    return (u32)rand();
}
//not thread safe
STATIC INLINE u16 WD_SYSTEM _wilddog_coap_getMid(void)
{
    //Do not need to care about endian, because we send what, will receive the same.
    //Only we need is to make sure it will not conflict in short time.
    STATIC u16 mid = 1;
    return mid++;
}
/*
 * Function:    _wilddog_coap_getToken
 * Description: get index, not thread safe
 * Input:       N/A
 * Output:      N/A
 * Return:      A rand number
*/
STATIC u32 WD_SYSTEM _wilddog_coap_getToken(u16 mid)
{
    //Do not need to care about endian, because we send what, will receive the same.
    //Only we need is to sure it is randomable.
    u32 token = _wilddog_coap_random();
    return (u32)(((token & (~0xff)) | (mid & 0xff)) & 0xffffffff);
}
STATIC coap_opt_t* WD_SYSTEM _wilddog_coap_getSendSessionOption(coap_pdu_t * pdu){
    //FIXME: We used a simple method, we assume .cs query is the head,
    // so coap_check_option's return is .cs query option.
    //But we have more than 1 query, such as disconnect , so fix it!!!
    coap_opt_iterator_t d_oi;

    wilddog_assert(pdu, NULL);

    return coap_check_option(pdu,COAP_OPTION_URI_QUERY,&d_oi);
}
/*
 * Function:    _wilddog_coap_getRecvCode
 * Description: Convert the coap code to http return code
 * Input:       pdu: The coap pkt
 * Output:      N/A
 * Return:      The http return code
*/
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_getRecvCode(coap_pdu_t * pdu)
{
    u32 rec_code;

    wilddog_assert(pdu, WILDDOG_ERR_NULL);

    rec_code = COAP_CODE_GET(pdu->hdr->code);

    switch(rec_code)
    {
        case 201:   return WILDDOG_HTTP_CREATED;
        case 202:   return WILDDOG_HTTP_NO_CONTENT;
        case 203:   return WILDDOG_HTTP_NOT_MODIFIED;
        case 204:   return WILDDOG_HTTP_NO_CONTENT;
        case 205:   return WILDDOG_HTTP_OK;
    }
    return rec_code;
}
/*
 * Function:    _wilddog_coap_addPath
 * Description: add path to coap packages.
 * Input:       pdu: coap pdu.
 *              path: path string.
 * Output:      N/A
 * Return:      WILDDOG_ERR_NOERR or WILDDOG_ERR_NULL.
 * Other:       path can be : 1. "/" 2. "/a" 3. "/a/b" 4. "/a/b/(maybe)"
 *                            5. "a" (maybe) 6. "a/b" (maybe)
*/
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_addPath(coap_pdu_t *pdu,char *path)
{
    char *p_subpath_start = NULL;
    char *p_subpath_end = NULL;
    unsigned int total_len = 0;

    wilddog_assert(pdu, WILDDOG_ERR_NULL);

    if(NULL == path){
        coap_add_option(pdu, COAP_OPTION_URI_PATH,0, NULL);
        return WILDDOG_ERR_NOERR;
    }
    total_len = strlen((const char*)path);
    if('/' == path[0] && 1 == total_len){
        // handle condition 1
        //coap_add_option(pdu,COAP_OPTION_URI_PATH,total_len, (u8*)path);
        coap_add_option(pdu, COAP_OPTION_URI_PATH,0, NULL);
        return WILDDOG_ERR_NOERR;
    }

    p_subpath_start = path;
    //change condition 2/3/4 to 5 or 6
    if('/' == p_subpath_start[0])
        p_subpath_start++;

    //now we only need handle condition 5/6
    while(p_subpath_start){
        p_subpath_end = _wilddog_strchar(p_subpath_start, '/');
        if(!p_subpath_end){
            // path has no / anymore, maybe condition 5 or condition 6's step 2
            coap_add_option(pdu,COAP_OPTION_URI_PATH,strlen(p_subpath_start),(u8*)p_subpath_start);
            return WILDDOG_ERR_NOERR;
        }
        // now we find /, such as "a" in "a/b", length is end - start.
        coap_add_option(pdu,COAP_OPTION_URI_PATH,p_subpath_end - p_subpath_start,(u8*)p_subpath_start);
        //jump "/"
        p_subpath_start = p_subpath_end + 1;
    }
    return WILDDOG_ERR_NOERR;
}
/*
 * Function:    _wilddog_coap_addQuery
 * Description: add query to coap packages.
 * Input:       pdu: coap pdu.
 *              query: query string.
 * Output:      N/A
 * Return:      WILDDOG_ERR_NOERR or WILDDOG_ERR_NULL.
 * Other:       path can be : 1. "a" 2. "a&b"
*/
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_addQuery(coap_pdu_t *pdu,char *query)
{
    char *p_subquery_start = NULL;
    char *p_subquery_end = NULL;

    wilddog_assert(pdu, WILDDOG_ERR_NULL);

    if(NULL == query){
        coap_add_option(pdu, COAP_OPTION_URI_QUERY,0, NULL);
        return WILDDOG_ERR_NOERR;
    }

    p_subquery_start = query;

    while(p_subquery_start){
        p_subquery_end = _wilddog_strchar(p_subquery_start, '&');
        if(!p_subquery_end){
            // query has no & anymore, maybe condition 1 or condition 2's step 2
            coap_add_option(pdu,COAP_OPTION_URI_QUERY,strlen(p_subquery_start),(u8*)p_subquery_start);
            return WILDDOG_ERR_NOERR;
        }
        // now we find &, such as "a" in "a&b", length is end - start.
        coap_add_option(pdu,COAP_OPTION_URI_QUERY,p_subquery_end - p_subquery_start,(u8*)p_subquery_start);
        //jump "&"
        p_subquery_start = p_subquery_end + 1;
    }
    return WILDDOG_ERR_NOERR;
}

/*notice, observe_index may not be continually, and may be fallback to
  little index.
  from RFC 7641: https://tools.ietf.org/html/rfc7641#section-3.4
   V1 is last index, V2 is recv index, T1 is last recv time
   T2 is now recv time. Condition 3 we do not care , only care 1 and 2

  (V1 < V2 and V2 - V1 < 2^23) or
  (V1 > V2 and V1 - V2 > 2^23) or
  (T2 > T1 + 128 seconds)
*/
STATIC BOOL WD_SYSTEM _wilddog_coap_isObserveNew(u32 old_index, u32 new_index){
    if(((old_index < new_index) && (new_index - old_index < (1<<23))) || \
        ((old_index > new_index) && (old_index - new_index > (1<<23))))
        return TRUE;

    return FALSE;
}
/*
+-----+---+---+---+---+---------+--------+--------+---------+
| No. | C | U | N | R | Name    | Format | Length | Default |
+-----+---+---+---+---+---------+--------+--------+---------+
|   6 |   | x | - |   | Observe | uint   | 0-3 B  | (none)  |
+-----+---+---+---+---+---------+--------+--------+---------+
*/
STATIC u32 WD_SYSTEM _wilddog_coap_getRecvObserveIndex(coap_pdu_t * pdu)
{
    u32 observe = 0;
    u16 len;
    coap_opt_t *p_op =NULL;
    coap_opt_iterator_t d_oi;
    u8 *option_value = NULL;

    wilddog_assert(pdu, WILDDOG_ERR_NULL);

    p_op = coap_check_option(pdu,COAP_OPTION_OBSERVE,&d_oi);

    if(p_op){
        len = coap_opt_length(p_op);
        // max observe data is 3 bytes.
        if(len == 0 || len > 3){
            wilddog_debug_level(WD_DEBUG_ERROR, "Get an maxage option but length is %d!",len);
            return 0;
        }
        option_value = coap_opt_value(p_op);
        if(NULL == option_value){
            wilddog_debug_level(WD_DEBUG_ERROR, \
                     "Get an option length is %d but no value!",len);

            return 0;
        }
        //observe option is in big endian.
        _wilddog_coap_ntoh((u8*)&observe,sizeof(observe),option_value,len);
    }
    return observe;
}

/*
+-----+---+---+---+---+----------------+--------+--------+----------+
| No. | C | U | N | R |      Name      | Format | Length |  Default |
+-----+---+---+---+---+----------------+--------+--------+----------+
| 14  |   | x | - |   |     Max-Age    | uint   | 0-4    |  60      |
+-----+---+---+---+---+----------------+--------+--------+----------+
*/
STATIC u32 WD_SYSTEM _wilddog_coap_getRecvMaxage(coap_pdu_t * pdu)
{
    u32 maxage = 0;
    u16 len;
    coap_opt_t *p_op =NULL;
    coap_opt_iterator_t d_oi;
    u8 *option_value = NULL;

    wilddog_assert(pdu, WILDDOG_ERR_NULL);

    p_op = coap_check_option(pdu,COAP_OPTION_MAXAGE,&d_oi);

    if(p_op){
        len = coap_opt_length(p_op);
        // max maxage data is 4 bytes.
        if(len == 0 || len > 4){
            wilddog_debug_level(WD_DEBUG_ERROR, "Get an maxage option but length is %d!",len);
            return 0;
        }
        option_value = coap_opt_value(p_op);
        if(NULL == option_value){
            wilddog_debug_level(WD_DEBUG_ERROR, \
                     "Get an option length is %d but no value!",len);

            return 0;
        }
        //maxage option is in big endian.
        _wilddog_coap_ntoh((u8*)&maxage,sizeof(maxage),option_value,len);
    }
    return maxage;
}

/*
 * Function:    _wilddog_coap_countChar
 * Description: count the number of  char 'c' exist in  the string buffer.
 * Input:       c: The char.
 *              p_buf: The pointer of the string buffer.
 * Output:      N/A
 * Return:      The number.
*/
STATIC int WD_SYSTEM _wilddog_coap_countChar(const char c,const char *p_buf)
{
    int res = 0 ;
    u32 i;
    for(i=0;p_buf[i] != 0;i++)
    {
        if(p_buf[i] == c)
            res++;
    }
    return res;
}

/*
coap header.
 |       0       |       1       |       2       |       3       |
 |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |Ver| T |  TKL  |      Code     |          Message ID           |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |   Token (if any, TKL bytes) ...
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |   Options (if any) ...
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |1 1 1 1 1 1 1 1|    Payload (if any) ...
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

option max header will be 5 bytes.
 7   6   5   4   3   2   1   0
+---------------+---------------+
|  Option Delta | Option Length |   1 byte
+---------------+---------------+
/         Option Delta          /   0-2 bytes
\          (extended)           \
+-------------------------------+
/         Option Length         /   0-2 bytes
\          (extended)           \
+-------------------------------+
/         Option Value          /   0 or more bytes
+-------------------------------+
*/
//Try to count this coap packet's size, so we can malloc less buffer.
STATIC int WD_SYSTEM _wilddog_coap_countSize(Wilddog_Coap_Pkt_T pkt){
    int size = 0;

    wilddog_assert(pkt.url, -1);

    // 4 bytes header and token
    size += 4 + pkt.token_length;

    //host option, option max head length is 5
    if(pkt.url->p_url_host){
        size += 5 + strlen((const char*)pkt.url->p_url_host) + 1;
    }
    //path option
    if(pkt.url->p_url_path){
        // path will be separated into some options by '/', it may be more than 1 option
        int num = 0;
        num = _wilddog_coap_countChar('/', (const char *)pkt.url->p_url_path);
        // max option number is "number of /" + 1
        num++;
        size += num * 5 + strlen((const char*)pkt.url->p_url_path) + 1;
    }
    else{
        //a null path, also will be in coap, but no data
        size += 5;
    }
    //query option
    if(pkt.url->p_url_query){
        //query will be separated into some options by '&', it may be more than 1 option
        int num = 0;
        num = _wilddog_coap_countChar('&', (const char *)pkt.url->p_url_query);
        // max option number is "number of &" + 1
        num++;
        size += num * 5 + strlen((const char*)pkt.url->p_url_query) + 1;
    }
    //may be observe option, observe 0
    size += 5 + 1;

    //payload, with 0xff ahead.
    size += pkt.data_len + 1;
    return size;
}
//now we only care one packet, do not thinking about partition.
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_sendPkt(Wilddog_Coap_Sendpkt_Arg_T arg,BOOL isNeedCs, Wilddog_Coap_Observe_Stat_T observeStat)
{
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Pkt_T pkt;
    u32 token = 0;
    coap_pdu_t *pdu = NULL;
    Wilddog_Str_T *new_query = NULL;
    int query_len = 0;
    Wilddog_Str_T *tmp = NULL;

    wilddog_assert(arg.protocol&&arg.url&&arg.token&&arg.send_pkt, WILDDOG_ERR_NULL);

    //add information for coap header
    pkt.type = COAP_MESSAGE_CON;
    pkt.code = arg.code;
    pkt.version = COAP_DEFAULT_VERSION;
    pkt.mid = _wilddog_coap_getMid();

    //get coap token, donot use hdr.token, use pkt.token instead
    pkt.token_length = WILDDOG_COAP_TOKEN_LEN;
    token = _wilddog_coap_getToken(pkt.mid);
    memcpy(pkt.token,(u8*)&token,WILDDOG_COAP_TOKEN_LEN);

    *arg.token = token;

    //get user data.
    pkt.data = arg.data;
    pkt.data_len = arg.data_len;

    pkt.url = arg.url;

    if(TRUE == isNeedCs){
        //combine the short token with .cs query option, ".cs=<short token>", etc.
        if(NULL != arg.url->p_url_query){
            //query string length  =
            //(pkt.url->p_url_query) + (&) + (.cs) + (=) + (short token length) + '\0'
            query_len = strlen((const char*)arg.url->p_url_query) + 1 + strlen(WILDDOG_COAP_SESSION_QUERY) + 1 + arg.d_session_len + 1;
        }else{
            //query string length  = (.cs) + (=) + (short token length) + '\0'
            query_len = strlen(WILDDOG_COAP_SESSION_QUERY) + 1 + arg.d_session_len + 1;
        }
        new_query = (Wilddog_Str_T*)wmalloc(query_len);
        wilddog_assert(new_query, WILDDOG_ERR_NULL);
        if(NULL != arg.url->p_url_query){
            sprintf((char*)new_query, "%s&%s=%s",(const char*)arg.url->p_url_query,WILDDOG_COAP_SESSION_PATH,(const char*)arg.p_session_info);
        }else{
            sprintf((char*)new_query, "%s=%s",WILDDOG_COAP_SESSION_PATH,(const char*)arg.p_session_info);
        }
        //store old query
        tmp = arg.url->p_url_query;
        arg.url->p_url_query = new_query;
    }

    //count pkt size.
    pkt.size = _wilddog_coap_countSize(pkt);

    //make a coap packet
    pdu = coap_pdu_init(pkt.type, pkt.code, pkt.mid, pkt.size);
    if(NULL == pdu){
        //restore query
        wilddog_debug_level(WD_DEBUG_ERROR, "Malloc failed!");
        ret = WILDDOG_ERR_NULL;
        goto END;
    }

    //add token
    coap_add_token(pdu, pkt.token_length, pkt.token);
    //add host
    coap_add_option(pdu,COAP_OPTION_URI_HOST,strlen((const char*)pkt.url->p_url_host),pkt.url->p_url_host);
    if(WILDDOG_COAP_OBSERVE_NOOBSERVE != observeStat){
        u8 observe_value = (WILDDOG_COAP_OBSERVE_ON == observeStat)?0:1;
        coap_add_option(pdu,COAP_OPTION_OBSERVE,sizeof(observe_value),&observe_value);
    }
    //add path
    _wilddog_coap_addPath(pdu,(char*)pkt.url->p_url_path);
    //add query
    if(pkt.url->p_url_query)
        _wilddog_coap_addQuery(pdu, (char*)pkt.url->p_url_query);
    //add data
    if(pkt.data)
        coap_add_data(pdu,pkt.data_len, pkt.data);

    ret = WILDDOG_ERR_NOERR;
    if(TRUE == arg.isSend){
        ret = _wilddog_sec_send(arg.protocol, pdu->hdr, pdu->length);
        if(ret < 0){
            //coap_delete_pdu(pdu);
            //pdu = NULL;
            wilddog_debug_level(WD_DEBUG_ERROR, "Send Packet %x failed.",(unsigned int)token);
            ret = WILDDOG_ERR_SENDERR;
        }else{
            ret = WILDDOG_ERR_NOERR;
        }
    }
    if(pdu){
        Wilddog_Conn_Pkt_Data_T *out_pkt = *arg.send_pkt;
        out_pkt->next = NULL;
        out_pkt->data = (u8*)pdu;
        out_pkt->len = (u32)(pdu->length&0xffff);
    }
END:
    if(isNeedCs){
        //resume old query
        arg.url->p_url_query = tmp;
        if(new_query)
            wfree(new_query);
    }
    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_initSession(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Str_T* tmp_path = NULL;
    Wilddog_Str_T* new_path = NULL;
#ifdef WILDDOG_AUTH_2_0
    Wilddog_Str_T* tmp_query = NULL;
    Wilddog_Str_T* new_query = NULL;
    int query_len = 0;
#endif

    int finalPathLen = 0;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;
    //now we only care one packet, do not thinking about partition.
    wilddog_assert(data&&arg->protocol&&arg->p_url&&arg->p_out_data, WILDDOG_ERR_NULL);

    //merge session init path with path .cs, assert pkt.url->p_url_path is null
    finalPathLen = strlen(WILDDOG_COAP_SESSION_PATH) + 1;
    new_path = (Wilddog_Str_T*)wmalloc(finalPathLen);
    wilddog_assert(new_path, WILDDOG_ERR_NULL);
    if(NULL == new_path){
        wilddog_debug_level(WD_DEBUG_ERROR, "Malloc failed!");
        return WILDDOG_ERR_NULL;
    }
    sprintf((char*)new_path, "%s", WILDDOG_COAP_SESSION_PATH);
    //store old path
    tmp_path = arg->p_url->p_url_path;
    arg->p_url->p_url_path = new_path;

#ifdef WILDDOG_AUTH_2_0
    //auth 2.0, url is like coap://1.wilddogio.com/.cs?v=2
    if(NULL != arg->p_url->p_url_query){
        //query string length  = (pkt.url->p_url_query) + (&) + (v=2) + '\0'
        query_len = strlen((const char*)arg->p_url->p_url_query) + 1 + strlen(WILDDOG_COAP_SESSION_AUTH_QUERY_2_0) + 1;
    }else{
        //query string length  = (v=2) + '\0'
        query_len = strlen(WILDDOG_COAP_SESSION_AUTH_QUERY_2_0) + 1;
    }
    new_query = (Wilddog_Str_T*)wmalloc(query_len);
    if(NULL == new_query){
        wfree(new_path);
        return WILDDOG_ERR_NULL;
    }
    if(NULL != arg->p_url->p_url_query){
        sprintf((char*)new_query, "%s&%s",(const char*)arg->p_url->p_url_query,WILDDOG_COAP_SESSION_AUTH_QUERY_2_0);
    }else{
        sprintf((char*)new_query, "%s",WILDDOG_COAP_SESSION_AUTH_QUERY_2_0);
    }
    //store old query
    tmp_query = arg->p_url->p_url_query;
    arg->p_url->p_url_query = new_query;
#endif

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_POST;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = arg->p_data;
    send_arg.data_len = arg->d_data_len;
    send_arg.isSend = TRUE;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;

    ret = _wilddog_coap_send_sendPkt(send_arg, FALSE, WILDDOG_COAP_OBSERVE_NOOBSERVE);
    //resume old path
    arg->p_url->p_url_path = tmp_path;
    if(new_path)
        wfree(new_path);
#ifdef WILDDOG_AUTH_2_0
    //resume old query
    arg->p_url->p_url_query = tmp_query;
    if(new_query)
        wfree(new_query);
#endif

    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_reconnect(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    wilddog_assert(arg->protocol, WILDDOG_ERR_NULL);
    //retry WILDDOG_RECONNECT_TIMES times
    return _wilddog_sec_reconnect(arg->protocol, WILDDOG_RECONNECT_TIMES);
}
/*
    Ping policy:
    1. Short: Send GET coap://<appid>.wilddogio.com/.ping?.cs=<short token>
    2. Long:  Send POST coap://<appid>.wilddogio.com/.rst, payload is long token
*/
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_ping(void* data, int flag){
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Str_T *new_query = NULL, *new_path = NULL;
    Wilddog_Str_T *tmp_query = NULL, *tmp_path = NULL;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;

    wilddog_assert(data&&arg->protocol&&arg->p_url&&arg->p_message_id&&arg->p_session_info&&arg->p_out_data, WILDDOG_ERR_NULL);

    //change url and data
    if(FALSE == flag){
        //coap://<appid>.wilddogio.com/.ping?.cs=<short token>
        int query_len = 0;
        //query = ".cs" + "=" + "<short token>"
        query_len = strlen(WILDDOG_COAP_SESSION_QUERY) + 1 + arg->d_session_len + 1;
        new_query = (Wilddog_Str_T*)wmalloc(query_len);
        if(NULL == new_query){
            wilddog_debug_level(WD_DEBUG_ERROR, "Malloc failed");
            return WILDDOG_ERR_NULL;
        }
        sprintf((char*)new_query, "%s=%s",WILDDOG_COAP_SESSION_QUERY,(const char*)arg->p_session_info);
        new_path = (Wilddog_Str_T*)wmalloc(strlen((const char*)WILDDOG_COAP_SESSION_PING_PATH) + 1);
        if(NULL == new_path){
            wfree(new_query);
            wilddog_debug_level(WD_DEBUG_ERROR, "Malloc failed");
            return WILDDOG_ERR_NULL;
        }
        sprintf((char*)new_path, "%s",WILDDOG_COAP_SESSION_PING_PATH);
        send_arg.data = NULL;
        send_arg.data_len = 0;
    }else{
        //coap://<appid>.wilddogio.com/.rst  payload = <long token>
        new_path = (Wilddog_Str_T*)wmalloc(strlen((const char*)WILDDOG_COAP_SESSION_RST_PATH) + 1);
        if(NULL == new_path){
            wfree(new_query);
            wilddog_debug_level(WD_DEBUG_ERROR, "Malloc failed");
            return WILDDOG_ERR_NULL;
        }
        sprintf((char*)new_path, "%s",WILDDOG_COAP_SESSION_RST_PATH);
        send_arg.data = arg->p_session_info;
        send_arg.data_len = arg->d_session_len;
    }

    //store old query
    tmp_query = arg->p_url->p_url_query;
    arg->p_url->p_url_query = new_query;
    tmp_path = arg->p_url->p_url_path;
    arg->p_url->p_url_path = new_path;

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = (FALSE == flag) ? (COAP_REQUEST_GET):(COAP_REQUEST_POST);
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.isSend = TRUE;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;

    ret = _wilddog_coap_send_sendPkt(send_arg, FALSE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    //resume old query
    arg->p_url->p_url_query = tmp_query;
    if(new_query){
        wfree(new_query);
    }
    arg->p_url->p_url_path = tmp_path;
    if(new_path){
        wfree(new_path);
    }

    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_retransmit(void* data, int flag){
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    coap_pdu_t *pdu = NULL;
    coap_opt_t *opt = NULL;

    wilddog_assert(arg&&arg->p_data&&arg->protocol, WILDDOG_ERR_NULL);

    pdu = (coap_pdu_t *)arg->p_data;
    if(arg->d_session_len == WILDDOG_CONN_SESSION_SHORT_LEN - 1){
        //we must change short session key
        //find .cs query, change the value to newer
        opt  = _wilddog_coap_getSendSessionOption(pdu);
        if(opt){
            //reflash session data
            //data = ".cs" + "=" + "<short token>"
            int query_len;
            query_len = strlen(WILDDOG_COAP_SESSION_QUERY) + 1 + arg->d_session_len;
            if(query_len != coap_opt_length(opt)){
                //not match!
                wilddog_debug_level(WD_DEBUG_WARN,"Session not match!!!, real is %d, want %d",
                                    coap_opt_length(opt),query_len);
            }else{
                //matched, change old short token to new
                u8* value = coap_opt_value(opt);
                wilddog_assert(value, WILDDOG_ERR_NULL);
                //check again, because _wilddog_coap_getSendSessionOption maybe fail now.
                if(0 == strncmp((const char*)value, WILDDOG_COAP_SESSION_QUERY, strlen(WILDDOG_COAP_SESSION_QUERY))){
                    //ignore ".cs=", so value add 4, copy new sort token to query.
                    memcpy((char*)(value + 4),arg->p_session_info, arg->d_session_len);
                }
            }
        }
        //observe special operation
        if(arg->p_proto_data && *(arg->p_proto_data)){
            _Wilddog_Coap_Observe_Data_T * observe_data = *(_Wilddog_Coap_Observe_Data_T**)arg->p_proto_data;
            observe_data->last_index = 0;
            observe_data->last_recv_time = 0;
            observe_data->maxage = 0;
        }
    }else if(arg->d_session_len == WILDDOG_CONN_SESSION_LONG_LEN - 1){
        //change long session key
        //FIXME: now we do not need to change long token, let it go.
        //If send old token, we only need to reauth.
        wilddog_debug_level(WD_DEBUG_WARN, "Can not be here!");
    }
    ret = _wilddog_sec_send(arg->protocol, pdu->hdr, pdu->length);
    return (ret < 0) ? (WILDDOG_ERR_SENDERR):(WILDDOG_ERR_NOERR);
}

/*
    coap get packet like coap://  a.b.cn / path  ? query=1&query=2
                         [scheme] [host]  [path]   [     query   ]
*/
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_getValue(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;

    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data, WILDDOG_ERR_NULL);

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_GET;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = NULL;
    send_arg.data_len = 0;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    return ret;
}

STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_setValue(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;

    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data && \
                   arg->p_data&&arg->d_data_len, WILDDOG_ERR_NULL);

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_PUT;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = arg->p_data;
    send_arg.data_len = arg->d_data_len;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_push(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;

    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data && \
                   arg->p_data&&arg->d_data_len, WILDDOG_ERR_NULL);

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_POST;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = arg->p_data;
    send_arg.data_len = arg->d_data_len;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_remove(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;

    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data, WILDDOG_ERR_NULL);

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_DELETE;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = arg->p_data;
    send_arg.data_len = arg->d_data_len;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_addObserver(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;
    _Wilddog_Coap_Observe_Data_T *observe_data = NULL;
    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data, WILDDOG_ERR_NULL);

    observe_data = (_Wilddog_Coap_Observe_Data_T*)wmalloc(sizeof(_Wilddog_Coap_Observe_Data_T));
    wilddog_assert(observe_data, WILDDOG_ERR_NULL);

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_GET;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = NULL;
    send_arg.data_len = 0;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_ON);

    //add proto_data
    if(WILDDOG_ERR_NOERR == ret){
        *arg->p_proto_data = (u8*)observe_data;
    }else{
        wfree(observe_data);
    }
    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_removeObserver(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;
    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data, WILDDOG_ERR_NULL);

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_GET;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = NULL;
    send_arg.data_len = 0;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_OFF);

    return ret;
}

STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_disSetValue(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;
    Wilddog_Str_T *new_query = NULL;
    int query_len = 0;
    Wilddog_Str_T *tmp = NULL;

    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data && \
                   arg->p_data&&arg->d_data_len, WILDDOG_ERR_NULL);

    //add disconnect function with query .dis=add
    if(NULL != arg->p_url->p_url_query){
        //query string length  =
        //(pkt.url->p_url_query) + (&) + (.dis=add) + '\0'
        query_len = strlen((const char*)arg->p_url->p_url_query) + 1 + strlen(WILDDOG_COAP_ADD_DIS_QUERY) + 1;
    }else{
        //query string length  = (.dis=add) + '\0'
        query_len = strlen(WILDDOG_COAP_ADD_DIS_QUERY) + 1;
    }
    new_query = (Wilddog_Str_T*)wmalloc(query_len);
    wilddog_assert(new_query, WILDDOG_ERR_NULL);

    if(NULL != arg->p_url->p_url_query){
        sprintf((char*)new_query, "%s&%s",(const char*)arg->p_url->p_url_query,WILDDOG_COAP_ADD_DIS_QUERY);
    }else{
        sprintf((char*)new_query, "%s",WILDDOG_COAP_ADD_DIS_QUERY);
    }
    //store old query
    tmp = arg->p_url->p_url_query;
    arg->p_url->p_url_query = new_query;

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_PUT;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = arg->p_data;
    send_arg.data_len = arg->d_data_len;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    //resume old query
    arg->p_url->p_url_query = tmp;
    if(new_query)
        wfree(new_query);

    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_disPush(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;
    Wilddog_Str_T *new_query = NULL;
    int query_len = 0;
    Wilddog_Str_T *tmp = NULL;

    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data && \
                   arg->p_data&&arg->d_data_len, WILDDOG_ERR_NULL);

    //add disconnect function with query .dis=add
    if(NULL != arg->p_url->p_url_query){
        //query string length  =
        //(pkt.url->p_url_query) + (&) + (.dis=add) + '\0'
        query_len = strlen((const char*)arg->p_url->p_url_query) + 1 + strlen(WILDDOG_COAP_ADD_DIS_QUERY) + 1;
    }else{
        //query string length  = (.dis=add) + '\0'
        query_len = strlen(WILDDOG_COAP_ADD_DIS_QUERY) + 1;
    }
    new_query = (Wilddog_Str_T*)wmalloc(query_len);
    wilddog_assert(new_query, WILDDOG_ERR_NULL);

    if(NULL != arg->p_url->p_url_query){
        sprintf((char*)new_query, "%s&%s",(const char*)arg->p_url->p_url_query,WILDDOG_COAP_ADD_DIS_QUERY);
    }else{
        sprintf((char*)new_query, "%s",WILDDOG_COAP_ADD_DIS_QUERY);
    }
    //store old query
    tmp = arg->p_url->p_url_query;
    arg->p_url->p_url_query = new_query;

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_POST;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = arg->p_data;
    send_arg.data_len = arg->d_data_len;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    //resume old query
    arg->p_url->p_url_query = tmp;
    if(new_query)
        wfree(new_query);

    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_disRemove(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;
    Wilddog_Str_T *new_query = NULL;
    int query_len = 0;
    Wilddog_Str_T *tmp = NULL;

    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data, WILDDOG_ERR_NULL);
    //add disconnect function with query .dis=add
    if(NULL != arg->p_url->p_url_query){
        //query string length  =
        //(pkt.url->p_url_query) + (&) + (.dis=add) + '\0'
        query_len = strlen((const char*)arg->p_url->p_url_query) + 1 + strlen(WILDDOG_COAP_ADD_DIS_QUERY) + 1;
    }else{
        //query string length  = (.dis=add) + '\0'
        query_len = strlen(WILDDOG_COAP_ADD_DIS_QUERY) + 1;
    }
    new_query = (Wilddog_Str_T*)wmalloc(query_len);
    wilddog_assert(new_query, WILDDOG_ERR_NULL);

    if(NULL != arg->p_url->p_url_query){
        sprintf((char*)new_query, "%s&%s",(const char*)arg->p_url->p_url_query,WILDDOG_COAP_ADD_DIS_QUERY);
    }else{
        sprintf((char*)new_query, "%s",WILDDOG_COAP_ADD_DIS_QUERY);
    }
    //store old query
    tmp = arg->p_url->p_url_query;
    arg->p_url->p_url_query = new_query;

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_DELETE;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = arg->p_data;
    send_arg.data_len = arg->d_data_len;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    //resume old query
    arg->p_url->p_url_query = tmp;
    if(new_query)
        wfree(new_query);

    return ret;
}
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_disCancel(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;
    Wilddog_Str_T *new_query = NULL;
    int query_len = 0;
    Wilddog_Str_T *tmp = NULL;

    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data, WILDDOG_ERR_NULL);
    //add disconnect function with query .dis=add
    if(NULL != arg->p_url->p_url_query){
        //query string length  =
        //(pkt.url->p_url_query) + (&) + (.dis=rm) + '\0'
        query_len = strlen((const char*)arg->p_url->p_url_query) + 1 + strlen(WILDDOG_COAP_CANCEL_DIS_QUERY) + 1;
    }else{
        //query string length  = (.dis=add) + '\0'
        query_len = strlen(WILDDOG_COAP_CANCEL_DIS_QUERY) + 1;
    }
    new_query = (Wilddog_Str_T*)wmalloc(query_len);
    wilddog_assert(new_query, WILDDOG_ERR_NULL);

    if(NULL != arg->p_url->p_url_query){
        sprintf((char*)new_query, "%s&%s",(const char*)arg->p_url->p_url_query,WILDDOG_COAP_CANCEL_DIS_QUERY);
    }else{
        sprintf((char*)new_query, "%s",WILDDOG_COAP_CANCEL_DIS_QUERY);
    }
    //store old query
    tmp = arg->p_url->p_url_query;
    arg->p_url->p_url_query = new_query;

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_DELETE;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = arg->p_data;
    send_arg.data_len = arg->d_data_len;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    //resume old query
    arg->p_url->p_url_query = tmp;
    if(new_query)
        wfree(new_query);

    return ret;
}
//send GET coap://<appId>.wilddogio.com/.off
STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_send_offline(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    Wilddog_Return_T ret = WILDDOG_ERR_INVALID;
    Wilddog_Coap_Sendpkt_Arg_T send_arg;
    Wilddog_Str_T *new_path = NULL;
    int path_len = 0;
    Wilddog_Str_T *tmp = NULL;

    wilddog_assert(data&&arg->protocol&& \
                   arg->p_url&&arg->p_session_info&& \
                   arg->d_session_len&&arg->p_out_data, WILDDOG_ERR_NULL);
    //add disconnect function with query .dis=add
    if(NULL != arg->p_url->p_url_path){
        //path string length  =
        //(pkt.url->p_url_path) + (/) + (.off) + '\0'
        path_len = strlen((const char*)arg->p_url->p_url_path) + 1 + strlen(WILDDOG_COAP_OFFLINE_PATH) + 1;
    }else{
        //query string length  = (.off) + '\0'
        path_len = strlen(WILDDOG_COAP_OFFLINE_PATH) + 1;
    }
    new_path = (Wilddog_Str_T*)wmalloc(path_len);
    wilddog_assert(new_path, WILDDOG_ERR_NULL);

    if(NULL != arg->p_url->p_url_path){
        sprintf((char*)new_path, "%s&%s",(const char*)arg->p_url->p_url_path,WILDDOG_COAP_OFFLINE_PATH);
    }else{
        sprintf((char*)new_path, "%s",WILDDOG_COAP_OFFLINE_PATH);
    }
    //store old path
    tmp = arg->p_url->p_url_path;
    arg->p_url->p_url_path = new_path;

    send_arg.protocol = arg->protocol;
    send_arg.url = arg->p_url;
    send_arg.code = COAP_REQUEST_GET;
    send_arg.p_session_info = arg->p_session_info;
    send_arg.d_session_len = arg->d_session_len;
    send_arg.data = arg->p_data;
    send_arg.data_len = arg->d_data_len;
    send_arg.isSend = flag;
    send_arg.token = arg->p_message_id;
    send_arg.send_pkt = (Wilddog_Conn_Pkt_Data_T**)arg->p_out_data;
    ret = _wilddog_coap_send_sendPkt(send_arg, TRUE, WILDDOG_COAP_OBSERVE_NOOBSERVE);

    //resume old query
    arg->p_url->p_url_path = tmp;
    if(new_path)
        wfree(new_path);

    return ret;
}

STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_recv_handlePkt(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    u32 error_code = WILDDOG_ERR_NOTAUTH;
    u32 maxage = 0;
    u32 observe_index = 0;
    coap_pdu_t * pdu;
    u32 payload_len = 0;
    u8 *payload = NULL;
    _Wilddog_Coap_Observe_Data_T *observe_data;

    wilddog_assert(data, WILDDOG_ERR_NULL);

    /* we may get the following:
     * 1. error code,
     * 2. token(already got in getPkt),
     * 3. maxage
     * 4. observe index(the 3&4 were used by observer),
     * 5. path,
     * 6. blockNum(used by block),
     * 7. payload
    */

    //pdu stored in p_data
    pdu = (coap_pdu_t *)arg->p_data;

    wilddog_assert(pdu, WILDDOG_ERR_NULL);

    //1. get error code
    error_code = _wilddog_coap_getRecvCode(pdu);

    //2. get token, we already got it, pass.
    //3. get maxage
    maxage = _wilddog_coap_getRecvMaxage(pdu);
    //4. get observe index
    observe_index = _wilddog_coap_getRecvObserveIndex(pdu);
    //5. get path, only observer may be use path to find the root path, we assume
    //   when root firstly sended, do not send child, when child firstly sended,
    //   send root again, and remove child observe.
    //6. get block number, FIXME: we do not support block [rfc7959]
    //7. get payload
    coap_get_data(pdu,&payload_len,&payload);

    //from observe index, check if the pkt is new or not.
    if(observe_index){
        observe_data = *(_Wilddog_Coap_Observe_Data_T**)arg->p_proto_data;

        wilddog_assert(observe_data, WILDDOG_ERR_NULL);

        if(TRUE == _wilddog_coap_isObserveNew(observe_data->last_index,observe_index)){
            //get new observe, handle it.
            observe_data->last_index = observe_index;
            //FIXME: we do not use maxage to flash observe packet, only store.
            if(maxage)
                observe_data->maxage = maxage;
            observe_data->last_recv_time = _wilddog_getTime();
        }else{
            //get old observe, ignore it.
            wilddog_debug_level(WD_DEBUG_WARN,"Received old observe index: last index is %ld, current index is %ld",observe_data->last_index,observe_index);
            error_code = WILDDOG_ERR_IGNORE;
        }
    }
    //error code and payload must tell connect layer
    //send payload to connect layer.
    *(arg->p_out_data) = (u8*)payload;
    *(arg->p_out_data_len) = payload_len;
    return error_code;
}

STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_recv_freePkt(void* data, int flag){
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;
    coap_pdu_t* pdu = (coap_pdu_t*)arg->p_data;
    coap_pdu_t  *toSend = NULL;
    u8 type = flag?(COAP_MESSAGE_ACK):(COAP_MESSAGE_RST);
    wilddog_assert(data && pdu, WILDDOG_ERR_NULL);

    //1. if need, send ack to the src of recvPkt
    //2. release recvPkt

    //if is con, match send ack ,other send rst
    if(COAP_MESSAGE_CON == pdu->hdr->type){
        toSend = coap_pdu_init(type,0,pdu->hdr->id,WILDDOG_PROTO_MAXSIZE);
        if(toSend){
            coap_add_token(toSend,pdu->hdr->token_length,pdu->hdr->token);
            //we don't care send success or not
            _wilddog_sec_send(arg->protocol,toSend->hdr,toSend->length);
            coap_delete_pdu(toSend);
        }
    }

    //we free recvPkt
    coap_delete_pdu(pdu);

    return WILDDOG_ERR_NOERR;
}

STATIC Wilddog_Return_T WD_SYSTEM _wilddog_coap_recv_getPkt(void* data, int flag){
    u8* recv_data = NULL;
    int res = 0;
    coap_pdu_t * pdu;
    int len;
    Wilddog_Proto_Cmd_Arg_T * arg = (Wilddog_Proto_Cmd_Arg_T*)data;

    wilddog_assert(data, WILDDOG_ERR_NULL);
    //1. recv from socket
    recv_data = _wilddog_coap_mallocRecvBuffer(arg->protocol);
    wilddog_assert(recv_data, WILDDOG_ERR_NULL);
    res = _wilddog_sec_recv(arg->protocol,(void*)recv_data,(s32)WILDDOG_PROTO_MAXSIZE);
    if(res <= 0 || res > WILDDOG_PROTO_MAXSIZE){
        _wilddog_coap_freeRecvBuffer(arg->protocol,recv_data);
        //wilddog_debug_level(WD_DEBUG_LOG, "Receive failed, error = %d",res);
        return WILDDOG_ERR_RECVTIMEOUT;
    }
    //2. malloc coap buffer, handle coap, get token
    pdu = coap_new_pdu();
    if(NULL == pdu){
        _wilddog_coap_freeRecvBuffer(arg->protocol,recv_data);
        wilddog_debug_level(WD_DEBUG_ERROR, "Malloc pdu failed!");
        return WILDDOG_ERR_NULL;
    }
    if(0 == coap_pdu_parse(recv_data, res,pdu)){
        coap_delete_pdu(pdu);
        _wilddog_coap_freeRecvBuffer(arg->protocol,recv_data);
        wilddog_debug_level(WD_DEBUG_ERROR, "Parse pdu failed!");
        return WILDDOG_ERR_INVALID;
    }
    if(pdu->hdr->version != COAP_DEFAULT_VERSION){
        coap_delete_pdu(pdu);
        _wilddog_coap_freeRecvBuffer(arg->protocol,recv_data);
        wilddog_debug_level(WD_DEBUG_ERROR, "Parse pdu failed!");
        return WILDDOG_ERR_INVALID;
    }
    //3. send pkt to connect layer.
    //!!!Notice, we assume token is WILDDOG_COAP_TOKEN_LEN bytes!
    //more than WILDDOG_COAP_TOKEN_LEN bytes will be ignored!
    len = pdu->hdr->token_length > WILDDOG_COAP_TOKEN_LEN? \
            (WILDDOG_COAP_TOKEN_LEN):(pdu->hdr->token_length);
    memcpy((u8*)arg->p_message_id,pdu->hdr->token, len);
    _wilddog_coap_freeRecvBuffer(arg->protocol,recv_data);
    //send pdu to connect layer to store.
    *(arg->p_out_data) = (u8*)pdu;
    *(arg->p_out_data_len) = pdu->length;
    return WILDDOG_ERR_NOERR;
}

/* protocol :: coap  interface */
Wilddog_Func_T _wilddog_protocol_funcTable[WD_PROTO_CMD_MAX + 1] =
{
    (Wilddog_Func_T) _wilddog_coap_initSession,//init
    (Wilddog_Func_T)_wilddog_coap_reconnect,
    (Wilddog_Func_T)_wilddog_coap_send_ping,//ping
    (Wilddog_Func_T)_wilddog_coap_send_retransmit,//retransmit
    (Wilddog_Func_T)_wilddog_coap_send_getValue,//get
    (Wilddog_Func_T)_wilddog_coap_send_setValue,//set
    (Wilddog_Func_T)_wilddog_coap_send_push,//push
    (Wilddog_Func_T)_wilddog_coap_send_remove,//remove
    (Wilddog_Func_T)_wilddog_coap_send_addObserver,//on
    (Wilddog_Func_T)_wilddog_coap_send_removeObserver,//off
    (Wilddog_Func_T)_wilddog_coap_send_disSetValue,//dis set
    (Wilddog_Func_T)_wilddog_coap_send_disPush,//dis push
    (Wilddog_Func_T)_wilddog_coap_send_disRemove,//dis remove
    (Wilddog_Func_T)_wilddog_coap_send_disCancel,//dis cancel
    (Wilddog_Func_T)NULL,//online, the same as init
    (Wilddog_Func_T)_wilddog_coap_send_offline,//offline
    (Wilddog_Func_T)_wilddog_coap_recv_getPkt,//get pkt
    (Wilddog_Func_T)_wilddog_coap_recv_freePkt,//free pkt
    (Wilddog_Func_T)_wilddog_coap_recv_handlePkt,//handle pkt
    NULL
};

/*
 * Function:    _wilddog_protocol_ioctl
 * Description: the ioctl function  of protocol
 * Input:       cmd:  command
 *              arg: the arg
 *              flags: the flag, not used
 * Output:      N/A
 * Return:      if success, return WILDDOG_ERR_NOERR
*/
size_t WD_SYSTEM _wilddog_protocol_ioctl
    (
    Wilddog_Proto_Cmd_T cmd,
    void *p_args,
    int flags
    )
{
    if( cmd >= WD_PROTO_CMD_MAX ||
        cmd < 0)
        return WILDDOG_ERR_INVALID;

    if(_wilddog_protocol_funcTable[cmd]){
        return (_wilddog_protocol_funcTable[cmd])(p_args,flags);
    }
    else{
        wilddog_debug_level(WD_DEBUG_ERROR, "Cannot find function %d!",cmd);
        return WILDDOG_ERR_NULL;
    }
}

/*
 * Function:    _wilddog_protocol_init.
 * Description: init protocol.
 *
 * Input:       p_conn : connect layer pointer.
 *
 * Output:      N/A.
 * Return:      Wilddog_Protocol_T type.
*/
Wilddog_Protocol_T * WD_SYSTEM _wilddog_protocol_init(void *data)
{
    Wilddog_Protocol_T *protocol;
    Wilddog_Conn_T* p_conn = data;

    wilddog_assert(p_conn, NULL);

    protocol = (Wilddog_Protocol_T*)wmalloc(sizeof(Wilddog_Protocol_T));

    wilddog_assert(protocol, NULL);

    protocol->socketFd = -1;
    protocol->host = p_conn->p_conn_repo->p_rp_url->p_url_host;
    protocol->addr.port = WILDDOG_PORT;
    protocol->callback = _wilddog_protocol_ioctl;
    //init socket and ip
    if(WILDDOG_ERR_NOERR != _wilddog_sec_init(protocol)){
        wfree(protocol);
        wilddog_debug_level(WD_DEBUG_ERROR, "Init secure failed!");
        return NULL;
    }

    return protocol;
}

/*
 * Function:    _wilddog_protocol_deInit.
 * Description: DeInit protocol.
 *
 * Input:       N/A.
 * Output:      N/A.
 * Return:      Wilddog_Return_T type .
*/
Wilddog_Return_T WD_SYSTEM _wilddog_protocol_deInit(void *data)
{
    Wilddog_Conn_T *p_conn = (Wilddog_Conn_T*)data;
    _wilddog_sec_deinit(p_conn->p_protocol);
    p_conn->p_protocol->host = NULL;
    p_conn->p_protocol->user_data = NULL;

    wfree(p_conn->p_protocol);
    return WILDDOG_ERR_NOERR;
}


text:
package techreborn.init.recipes;

import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import reborncore.api.recipe.RecipeHandler;
import techreborn.api.recipe.machines.ExtractorRecipe;
import techreborn.init.ModBlocks;
import techreborn.items.DynamicCell;

/**
 * Created by Prospector
 */
public class ExtractorRecipes extends RecipeMethods {
	public static void init() {
		register(getStack(ModBlocks.RUBBER_SAPLING), getMaterial("rubber", Type.PART), false);
		register(getStack(ModBlocks.RUBBER_LOG),  getMaterial("rubber", Type.PART), false);
		register(getStack(Items.SLIME_BALL), getMaterial("rubber", 2, Type.PART));
		register(getMaterial("sap", Type.PART), getMaterial("rubber", 3, Type.PART));
		register(getStack(Blocks.RED_FLOWER), getStack(Items.DYE, 2, 1), false);
		register(getStack(Blocks.YELLOW_FLOWER), getStack(Items.DYE, 2, 11), false);
		register(getStack(Blocks.RED_FLOWER, 1, 1), getStack(Items.DYE, 2, 12), false);
		register(getStack(Blocks.RED_FLOWER, 1, 2), getStack(Items.DYE, 2, 13), false);
		register(getStack(Blocks.RED_FLOWER, 1, 3), getStack(Items.DYE, 2, 7), false);
		register(getStack(Blocks.RED_FLOWER, 1, 4), getStack(Items.DYE, 2, 1), false);
		register(getStack(Blocks.RED_FLOWER, 1, 5), getStack(Items.DYE, 2, 14), false);
		register(getStack(Blocks.RED_FLOWER, 1, 6), getStack(Items.DYE, 2, 7), false);
		register(getStack(Blocks.RED_FLOWER, 1, 7), getStack(Items.DYE, 2, 9), false);
		register(getStack(Blocks.RED_FLOWER, 1, 8), getStack(Items.DYE, 2, 7), false);
		register(getStack(Blocks.DOUBLE_PLANT), getStack(Items.DYE, 4, 11), false);
		register(getStack(Blocks.DOUBLE_PLANT, 1, 1), getStack(Items.DYE, 4, 13), false);
		register(getStack(Blocks.DOUBLE_PLANT, 1, 4), getStack(Items.DYE, 4, 1), false);
		register(getStack(Blocks.DOUBLE_PLANT, 1, 5), getStack(Items.DYE, 4, 9), false);
		register(getStack(Blocks.TALLGRASS, 1, 1), getStack(Items.WHEAT_SEEDS), false);
		register(getStack(Blocks.TALLGRASS, 1, 2), getStack(Items.WHEAT_SEEDS), false);
		register(getStack(Blocks.DOUBLE_PLANT, 1, 2), getStack(Items.WHEAT_SEEDS, 2), false);
		register(getStack(Blocks.DOUBLE_PLANT, 1, 3), getStack(Items.WHEAT_SEEDS, 2), false);
		register(getStack(Blocks.DEADBUSH, 1, 0), getStack(Items.STICK));
		for (int i = 1; i < 15; i++)
			register(getStack(Blocks.WOOL, 1, i), getStack(Blocks.WOOL, 1, 0), false);
		for (Fluid fluid : FluidRegistry.getRegisteredFluids().values()) {
			register(DynamicCell.getCellWithFluid(fluid), DynamicCell.getEmptyCell(1), false);
		}
	}

	static void register(ItemStack input, ItemStack output) {
		register(input,  output, true);
	}

	static void register(ItemStack input, ItemStack output, boolean oreDict) {
		RecipeHandler.addRecipe(new ExtractorRecipe(input, output, 400, 2, oreDict));
	}
}

redpajama_set_name: RedPajamaGithub


text:
@implementation NSFileWrapper (TFEasyCoder)

+( NSFileWrapper *)easyCoder:(NSFileWrapperEasyCoderBlock)block{
    return [NSObject tf_execute:[self class] back:^(id ins) {
        if (block) {
            block(( NSFileWrapper *)ins);
        }
    }];
}

-( NSFileWrapper *)easyCoder:(NSFileWrapperEasyCoderBlock)block{
    if (block) {
        __weak typeof(self) weakSelf = self;
        block(weakSelf);
    }
    return self;
}

-(NSFileWrapper  *(^)(NSString *  preferredFilename))set_preferredFilename{
    __weak typeof(self) weakSelf = self;
    return ^(NSString *  preferredFilename){
        weakSelf.preferredFilename = preferredFilename;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(NSString *  filename))set_filename{
    __weak typeof(self) weakSelf = self;
    return ^(NSString *  filename){
        weakSelf.filename = filename;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(NSDictionary *  fileAttributes))set_fileAttributes{
    __weak typeof(self) weakSelf = self;
    return ^(NSDictionary *  fileAttributes){
        weakSelf.fileAttributes = fileAttributes;
        return weakSelf;
    };
}

//superclass pros NSObject
-(NSFileWrapper  *(^)(NSArray *  accessibilityElements))set_accessibilityElements{
    __weak typeof(self) weakSelf = self;
    return ^(NSArray *  accessibilityElements){
        weakSelf.accessibilityElements = accessibilityElements;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(NSArray *  accessibilityCustomActions))set_accessibilityCustomActions{
    __weak typeof(self) weakSelf = self;
    return ^(NSArray *  accessibilityCustomActions){
        weakSelf.accessibilityCustomActions = accessibilityCustomActions;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(BOOL  isAccessibilityElement))set_isAccessibilityElement{
    __weak typeof(self) weakSelf = self;
    return ^(BOOL  isAccessibilityElement){
        weakSelf.isAccessibilityElement = isAccessibilityElement;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(NSString *  accessibilityLabel))set_accessibilityLabel{
    __weak typeof(self) weakSelf = self;
    return ^(NSString *  accessibilityLabel){
        weakSelf.accessibilityLabel = accessibilityLabel;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(NSString *  accessibilityHint))set_accessibilityHint{
    __weak typeof(self) weakSelf = self;
    return ^(NSString *  accessibilityHint){
        weakSelf.accessibilityHint = accessibilityHint;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(NSString *  accessibilityValue))set_accessibilityValue{
    __weak typeof(self) weakSelf = self;
    return ^(NSString *  accessibilityValue){
        weakSelf.accessibilityValue = accessibilityValue;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(unsigned long long  accessibilityTraits))set_accessibilityTraits{
    __weak typeof(self) weakSelf = self;
    return ^(unsigned long long  accessibilityTraits){
        weakSelf.accessibilityTraits = accessibilityTraits;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(UIBezierPath *  accessibilityPath))set_accessibilityPath{
    __weak typeof(self) weakSelf = self;
    return ^(UIBezierPath *  accessibilityPath){
        weakSelf.accessibilityPath = accessibilityPath;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(CGPoint  accessibilityActivationPoint))set_accessibilityActivationPoint{
    __weak typeof(self) weakSelf = self;
    return ^(CGPoint  accessibilityActivationPoint){
        weakSelf.accessibilityActivationPoint = accessibilityActivationPoint;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(NSString *  accessibilityLanguage))set_accessibilityLanguage{
    __weak typeof(self) weakSelf = self;
    return ^(NSString *  accessibilityLanguage){
        weakSelf.accessibilityLanguage = accessibilityLanguage;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(BOOL  accessibilityElementsHidden))set_accessibilityElementsHidden{
    __weak typeof(self) weakSelf = self;
    return ^(BOOL  accessibilityElementsHidden){
        weakSelf.accessibilityElementsHidden = accessibilityElementsHidden;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(BOOL  accessibilityViewIsModal))set_accessibilityViewIsModal{
    __weak typeof(self) weakSelf = self;
    return ^(BOOL  accessibilityViewIsModal){
        weakSelf.accessibilityViewIsModal = accessibilityViewIsModal;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(BOOL  shouldGroupAccessibilityChildren))set_shouldGroupAccessibilityChildren{
    __weak typeof(self) weakSelf = self;
    return ^(BOOL  shouldGroupAccessibilityChildren){
        weakSelf.shouldGroupAccessibilityChildren = shouldGroupAccessibilityChildren;
        return weakSelf;
    };
}

-(NSFileWrapper  *(^)(long long  accessibilityNavigationStyle))set_accessibilityNavigationStyle{
    __weak typeof(self) weakSelf = self;
    return ^(long long  accessibilityNavigationStyle){
        weakSelf.accessibilityNavigationStyle = accessibilityNavigationStyle;
        return weakSelf;
    };
}

-(NSFileWrapper *(^)(id value,NSString *key))set_ValueKey{
    __weak typeof(self) weakSelf = self;
    return ^(id value,NSString *key){
        [NSObject tf_setTargetValue:weakSelf withValue:value forKey:key];
        return weakSelf;
    };
}

@end


text:
const fs = require('fs');
const path = require('path');
const { assert } = require('chai');
const MailosaurClient = require('../lib/mailosaur');
const MailosaurError = require('../lib/models/mailosaurError');
const mailer = require('./mailer');

const isoDateString = new Date().toISOString().slice(0, 10);

const validateHtml = (email) => {
  // Body
  assert.match(email.html.body, /^
/, 'HTML body should match');

  // Links
  assert.equal(email.html.links.length, 3, 'Should have HTML links');
  assert.equal(email.html.links[0].href, 'https://mailosaur.com/', 'First link should have href');
  assert.equal(email.html.links[0].text, 'mailosaur', 'First link should have text');
  assert.equal(email.html.links[1].href, 'https://mailosaur.com/', 'Second link should have href');
  assert.isNull(email.html.links[1].text, 'Second link should have no text');
  assert.equal(email.html.links[2].href, 'http://invalid/', 'Third link should have href');
  assert.equal(email.html.links[2].text, 'invalid', 'Third link should have text');

  // Codes
  assert.equal(email.html.codes.length, 2, 'Should have verification codes');
  assert.equal(email.html.codes[0].value, '123456');
  assert.equal(email.html.codes[1].value, 'G3H1Y2');

  // Images
  assert.match(email.html.images[1].src, /cid:/);
  assert.equal(email.html.images[1].alt, 'Inline image 1', 'Second image should have alt text');
};

const validateText = (email) => {
  // Body
  assert.match(email.text.body, /^this is a test/);

  // Links
  assert.equal(email.text.links.length, 2, 'Should have Text links');
  assert.equal(email.text.links[0].href, 'https://mailosaur.com/', 'First link should have href');
  assert.equal(email.text.links[0].text, email.text.links[0].href, 'First text link href & text should match');
  assert.equal(email.text.links[1].href, 'https://mailosaur.com/', 'Second link should have href');
  assert.equal(email.text.links[1].text, email.text.links[1].href, 'Second text link href & text should match');

  // Codes
  assert.equal(email.text.codes.length, 2, 'Should have verification codes');
  assert.equal(email.text.codes[0].value, '654321');
  assert.equal(email.text.codes[1].value, '5H0Y2');
};

const validateHeaders = (email) => {
  const expectedFromHeader = `${email.from[0].name} <${email.from[0].email}>`;
  const expectedToHeader = `${email.to[0].name} <${email.to[0].email}>`;
  const { headers } = email.metadata;

  assert.equal(headers.find(h => h.field.toLowerCase() === 'from').value, expectedFromHeader, 'From header should be accurate');
  assert.equal(headers.find(h => h.field.toLowerCase() === 'to').value, expectedToHeader, 'To header should be accurate');
  assert.equal(headers.find(h => h.field.toLowerCase() === 'subject').value, email.subject, 'Subject header should be accurate');
};

const validateMetadata = (email) => {
  assert.equal(email.type, 'Email');
  assert.equal(email.from.length, 1);
  assert.equal(email.to.length, 1);
  assert.isNotEmpty(email.from[0].email);
  assert.isNotEmpty(email.from[0].name);
  assert.isNotEmpty(email.to[0].email);
  assert.isNotEmpty(email.to[0].name);
  assert.isNotEmpty(email.subject);
  assert.isNotEmpty(email.server);

  assert.equal(email.received.toISOString().slice(0, 10), isoDateString);
};

const validateAttachments = (email) => {
  assert.equal(email.attachments.length, 2, 'Should have attachments');

  const file1 = email.attachments[0];
  assert.isOk(file1.id, 'First attachment should have file id');
  assert.isOk(file1.url);
  assert.equal(file1.length, 82138, 'First attachment should be correct size');
  assert.equal(file1.fileName, 'cat.png', 'First attachment should have filename');
  assert.equal(file1.contentType, 'image/png', 'First attachment should have correct MIME type');

  const file2 = email.attachments[1];
  assert.isOk(file2.id, 'Second attachment should have file id');
  assert.isOk(file2.url);
  assert.equal(file2.length, 212080, 'Second attachment should be correct size');
  assert.equal(file2.fileName, 'dog.png', 'Second attachment should have filename');
  assert.equal(file2.contentType, 'image/png', 'Second attachment should have correct MIME type');
};

const validateEmail = (email) => {
  validateMetadata(email);
  validateAttachments(email);
  validateHtml(email);
  validateText(email);
  assert.isOk(email.metadata.ehlo, 'ehlo is empty');
  assert.isOk(email.metadata.mailFrom, 'mailFrom is empty');
  assert.equal(email.metadata.rcptTo.length, 1);
};

const validateEmailSummary = (email) => {
  validateMetadata(email);
  assert.isNotEmpty(email.summary);
  assert.equal(email.attachments, 2);
};

describe('emails', () => {
  const apiKey = process.env.MAILOSAUR_API_KEY;
  const server = process.env.MAILOSAUR_SERVER;
  const baseUrl = process.env.MAILOSAUR_BASE_URL || 'https://mailosaur.com/';
  const verifiedDomain = process.env.MAILOSAUR_VERIFIED_DOMAIN;
  let client;
  let emails;

  before(async () => {
    if (!apiKey || !server) {
      throw new Error('Missing necessary environment variables - refer to README.md');
    }

    client = new MailosaurClient(apiKey, baseUrl);

    await client.messages.deleteAll(server);
    await mailer.sendEmails(mailer, client, server, 5);
    const result = await client.messages.list(server);
    emails = result.items;
    emails.forEach(validateEmailSummary);
  });

  describe('list', () => {
    it('should filter on older received after date', async () => {
      const pastDate = new Date();
      pastDate.setMinutes(pastDate.getMinutes() - 10);
      const result = await client.messages.list(server, { receivedAfter: pastDate });
      assert.isTrue(result.items.length > 0);
    });

    it('should filter on received after date', async () => {
      const d = new Date();
      d.setSeconds(d.getSeconds() + 60);
      const result = await client.messages.list(server, { receivedAfter: d });
      assert.equal(result.items.length, 0);
    });
  });

  describe('get', () => {
    it('should return a match once found', async () => {
      const host = process.env.MAILOSAUR_SMTP_HOST || 'mailosaur.net';
      const testEmailAddress = `wait_for_test@${server}.${host}`;
      await mailer.sendEmail(client, server, testEmailAddress);
      const email = await client.messages.get(server, {
        sentTo: testEmailAddress
      });
      validateEmail(email);
    });
  });

  describe('getById', async () => {
    it('should return a single email', async () => {
      const email = await client.messages.getById(emails[0].id);
      validateEmail(email);
      validateHeaders(email);
    });

    it('should throw an error if email not found', async () => {
      try {
        await client.messages.getById('efe907e9-74ed-4113-a3e0-a3d41d914765');
      } catch (err) {
        assert.instanceOf(err, MailosaurError);
      }
    });
  });

  describe('search', () => {
    it('should throw an error if no criteria', async () => {
      try {
        await client.messages.search(server, {});
      } catch (err) {
        assert.instanceOf(err, MailosaurError);
      }
    });

    it('should throw a meaningful error if the timeout is reached', async () => {
      const testFromEmail = 'zzyy@test.com';

      try {
        await client.messages.search(server, {
          sentFrom: testFromEmail
        }, {
          timeout: 1,
        });
      } catch (err) {
        assert.instanceOf(err, MailosaurError);
        assert.equal(err.message, `No matching messages found in time. By default, only messages received in the last hour are checked (use receivedAfter to override this). The search criteria used for this query was [{"sentFrom":"${testFromEmail}"}] which timed out after 1ms`);
      }
    });

    it('should return empty array if errors suppressed', async () => {
      const result = await client.messages.search(server, {
        sentTo: 'neverfound@example.com'
      }, {
        timeout: 1,
        errorOnTimeout: false
      });

      assert.equal(result.items.length, 0);
    });

    describe('by sentFrom', () => {
      it('should return matching results', async () => {
        const targetEmail = emails[1];
        const result = await client.messages.search(server, {
          sentFrom: targetEmail.from[0].email
        });
        assert.equal(result.items.length, 1);
        assert.equal(result.items[0].from[0].email, targetEmail.from[0].email);
        assert.equal(result.items[0].subject, targetEmail.subject);
      });
    });

    describe('by sentTo', () => {
      it('should return matching results', async () => {
        const targetEmail = emails[1];
        const result = await client.messages.search(server, {
          sentTo: targetEmail.to[0].email
        });
        assert.equal(result.items.length, 1);
        assert.equal(result.items[0].to[0].email, targetEmail.to[0].email);
        assert.equal(result.items[0].subject, targetEmail.subject);
      });
    });

    describe('by body', () => {
      it('should return matching results', async () => {
        const targetEmail = emails[1];
        const uniqueString = targetEmail.subject.substr(0, targetEmail.subject.indexOf(' subject'));
        const result = await client.messages.search(server, {
          body: `${uniqueString} html`
        });
        assert.equal(result.items.length, 1);
        assert.equal(result.items[0].to[0].email, targetEmail.to[0].email);
        assert.equal(result.items[0].subject, targetEmail.subject);
      });
    });

    describe('by subject', () => {
      it('should return matching results', async () => {
        const targetEmail = emails[1];
        const uniqueString = targetEmail.subject.substr(0, targetEmail.subject.indexOf(' subject'));
        const result = await client.messages.search(server, {
          subject: uniqueString
        });
        assert.equal(result.items.length, 1);
        assert.equal(result.items[0].to[0].email, targetEmail.to[0].email);
        assert.equal(result.items[0].subject, targetEmail.subject);
      });
    });

    describe('with match all', () => {
      it('should return matching results', async () => {
        const targetEmail = emails[1];
        const uniqueString = targetEmail.subject.substr(0, targetEmail.subject.indexOf(' subject'));
        const result = await client.messages.search(server, {
          subject: uniqueString,
          body: 'this is a link',
          match: 'ALL'
        });
        assert.equal(result.items.length, 1);
      });
    });

    describe('with match any', () => {
      it('should return matching results', async () => {
        const targetEmail = emails[1];
        const uniqueString = targetEmail.subject.substr(0, targetEmail.subject.indexOf(' subject'));
        const result = await client.messages.search(server, {
          subject: uniqueString,
          body: 'this is a link',
          match: 'ANY'
        });
        assert.equal(result.items.length, 6);
      });
    });

    describe('with special characters', () => {
      it('should support special characters', async () => {
        const result = await client.messages.search(server, {
          subject: 'Search with ellipsis … and emoji 👨🏿🚒'
        });
        assert.equal(result.items.length, 0);
      });
    });
  });

  describe('spamAnalysis', () => {
    it('should perform a spam analysis on an email', async () => {
      const targetId = emails[0].id;
      const result = await client.analysis.spam(targetId);
      result.spamFilterResults.spamAssassin.forEach((rule) => {
        assert.isNumber(rule.score);
        assert.isOk(rule.rule);
        assert.isOk(rule.description);
      });
    });
  });

  describe('del', () => {
    it('should delete an email', async () => {
      const targetEmailId = emails[4].id;
      await client.messages.del(targetEmailId);
    });

    it('should fail if attempting to delete again', async () => {
      const targetEmailId = emails[4].id;

      try {
        await client.messages.del(targetEmailId);
      } catch (err) {
        assert.instanceOf(err, MailosaurError);
      }
    });
  });

  (verifiedDomain ? describe : describe.skip)('create and send', () => {
    it('send with text content', async () => {
      const subject = 'New message';
      const message = await client.messages.create(server, {
        to: `anything@${verifiedDomain}`,
        send: true,
        subject,
        text: 'This is a new email'
      });
      assert.isNotEmpty(message.id);
      assert.equal(message.subject, subject);
    });

    it('send with HTML content', async () => {
      const subject = 'New HTML message';
      const message = await client.messages.create(server, {
        to: `anything@${verifiedDomain}`,
        send: true,
        subject,
        html: '
This is a new email.
'
      });
      assert.isNotEmpty(message.id);
      assert.equal(message.subject, subject);
    });

    it('send with attachment', async () => {
      const subject = 'New message with attachment';

      const buffer = fs.readFileSync(path.join(__dirname, '/resources/cat.png'));
      const attachment = {
        fileName: 'cat.png',
        content: buffer.toString('base64'),
        contentType: 'image/png'
      };

      const message = await client.messages.create(server, {
        to: `anything@${verifiedDomain}`,
        send: true,
        subject,
        html: '
This is a new email.
',
        attachments: [attachment]
      });
      assert.equal(message.attachments.length, 1, 'Should have attachment');
      const file1 = message.attachments[0];
      assert.isOk(file1.id, 'First attachment should have file id');
      assert.isOk(file1.url);
      assert.equal(file1.length, 82138, 'First attachment should be correct size');
      assert.equal(file1.fileName, 'cat.png', 'First attachment should have filename');
      assert.equal(file1.contentType, 'image/png', 'First attachment should have correct MIME type');
    });
  });

  (verifiedDomain ? describe : describe.skip)('forward', () => {
    it('forward with text content', async () => {
      const targetEmailId = emails[0].id;
      const body = 'Forwarded message';

      const message = await client.messages.forward(targetEmailId, {
        to: `anything@${verifiedDomain}`,
        text: body
      });
      assert.isNotEmpty(message.id);
      assert.isTrue(message.text.body.indexOf(body) >= 0);
    });

    it('forward with HTML content', async () => {
      const targetEmailId = emails[0].id;
      const body = '
Forwarded HTML message.
';

      const message = await client.messages.forward(targetEmailId, {
        to: `anything@${verifiedDomain}`,
        html: body
      });
      assert.isNotEmpty(message.id);
      assert.isTrue(message.html.body.indexOf(body) >= 0);
    });
  });

  (verifiedDomain ? describe : describe.skip)('reply', () => {
    it('reply with text content', async () => {
      const targetEmailId = emails[0].id;
      const body = 'Reply message';

      const message = await client.messages.reply(targetEmailId, {
        text: body
      });
      assert.isNotEmpty(message.id);
      assert.isTrue(message.text.body.indexOf(body) >= 0);
    });

    it('reply with HTML content', async () => {
      const targetEmailId = emails[0].id;
      const body = '
Reply HTML message.
';

      const message = await client.messages.reply(targetEmailId, {
        html: body
      });
      assert.isNotEmpty(message.id);
      assert.isTrue(message.html.body.indexOf(body) >= 0);
    });

    it('reply with attachment', async () => {
      const targetEmailId = emails[0].id;

      const buffer = fs.readFileSync(path.join(__dirname, '/resources/cat.png'));
      const attachment = {
        fileName: 'cat.png',
        content: buffer.toString('base64'),
        contentType: 'image/png'
      };

      const message = await client.messages.reply(targetEmailId, {
        html: '
This is a reply with attachment.
',
        attachments: [attachment]
      });
      assert.equal(message.attachments.length, 1, 'Should have attachment');
      const file1 = message.attachments[0];
      assert.isOk(file1.id, 'First attachment should have file id');
      assert.isOk(file1.url);
      assert.equal(file1.length, 82138, 'First attachment should be correct size');
      assert.equal(file1.fileName, 'cat.png', 'First attachment should have filename');
      assert.equal(file1.contentType, 'image/png', 'First attachment should have correct MIME type');
    });
  });
});


text:
package org.diirt.datasource.extra;

import org.diirt.vtype.VNumberArray;
import org.diirt.vtype.VNumber;
import org.diirt.datasource.vtype.DataTypeSupport;
import java.util.List;
import org.diirt.datasource.BasicTypeSupport;
import org.diirt.datasource.expression.DesiredRateExpression;
import org.diirt.datasource.expression.DesiredRateExpressionList;
import org.diirt.datasource.expression.SourceRateExpression;
import org.diirt.datasource.expression.SourceRateExpressionList;
import static org.diirt.datasource.ExpressionLanguage.*;

/**
 * PVManager expression language support for additional operations.
 *
 * @author carcassi
 */
public class ExpressionLanguage {
    private ExpressionLanguage() {}

    static {
        // Add support for Epics types.
        DataTypeSupport.install();
        // Add support for Basic types
        BasicTypeSupport.install();
    }

    /**
     * Aggregates the sample at the scan rate and takes the average.
     *
     * @param arrayPv the expression to take the average of; can't be null
     * @return an expression representing the average of the expression
     */
    public static <T extends VNumberArray> WaterfallPlot  waterfallPlotOf(SourceRateExpression<T> arrayPv) {
        DesiredRateExpression<List<T>> queue = newValuesOf(arrayPv);
        return new WaterfallPlot(queue, "waterfallOf(" + arrayPv.getName() + ")");
    }

    /**
     * Creates a waterfall plot from a series of scalar pvs.
     *
     * @param vDoubles the expression to take the average of; can't be null
     * @return an expression representing the average of the expression
     */
    public static <T extends VNumber> WaterfallPlot waterfallPlotOf(SourceRateExpressionList<T> vDoubles) {
        DesiredRateExpressionList<List<T>> queue = newValuesOf(vDoubles);
        return new WaterfallPlot(queue, "waterfallOf");
    }

    /**
     * Creates a group of dynamically managed expressions.
     *
     * @return a new group
     */
    public static DynamicGroup group() {
        return new DynamicGroup();
    }

}


text:
namespace base {
class Clock;
}  // namespace base

namespace segmentation_platform {

struct Config;
class ModelExecutionScheduler;
class SegmentationResultPrefs;
class SegmentInfoDatabase;
class SignalStorageConfig;

namespace proto {
class SegmentInfo;
}  // namespace proto

class SegmentSelectorImpl : public SegmentSelector {
 public:
  SegmentSelectorImpl(SegmentInfoDatabase* segment_database,
                      SignalStorageConfig* signal_storage_config,
                      SegmentationResultPrefs* result_prefs,
                      const Config* config,
                      base::Clock* clock,
                      const PlatformOptions& platform_options);

  ~SegmentSelectorImpl() override;

  // SegmentSelector overrides.
  void GetSelectedSegment(SegmentSelectionCallback callback) override;

  // ModelExecutionScheduler::Observer overrides.

  // Called whenever a model eval completes. Runs segment selection to find the
  // best segment, and writes it to the pref.
  void OnModelExecutionCompleted(OptimizationTarget segment_id) override;

 private:
  // For testing.
  friend class SegmentSelectorTest;

  // Helper method to run segment selection if possible.
  void RunSegmentSelection(
      std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
          all_segments);

  // Determines whether segment selection can be run based on whether all
  // segments have met signal collection requirement, have valid results, and
  // segment selection TTL has expired.
  bool CanComputeSegmentSelection(
      const std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>&
          all_segments);

  // Loops through all segments, performs discrete mapping, honors finch
  // supplied tie-breakers, TTL, inertia etc, and finds the highest score.
  // Ignores the segments that have no results.
  OptimizationTarget FindBestSegment(
      const std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>&
          all_segments);

  // Helper function to update the selected segment in the prefs. Auto-extends
  // the selection if the new result is unknown.
  void UpdateSelectedSegment(OptimizationTarget new_selection);

  // The database storing metadata and results.
  raw_ptr<SegmentInfoDatabase> segment_database_;

  // The database to determine whether the signal storage requirements are met.
  raw_ptr<SignalStorageConfig> signal_storage_config_;

  // Helper class to read/write results to the prefs.
  raw_ptr<SegmentationResultPrefs> result_prefs_;

  // The config for providing configuration params.
  raw_ptr<const Config> config_;

  // The time provider.
  raw_ptr<base::Clock> clock_;

  const PlatformOptions platform_options_;

  // Segment selection result is read from prefs on init and used for serving
  // the clients in the current session.
  SegmentSelectionResult selected_segment_last_session_;

  base::WeakPtrFactory<SegmentSelectorImpl> weak_ptr_factory_{this};
};

}  // namespace segmentation_platform

#endif  // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SELECTION_SEGMENT_SELECTOR_IMPL_H_


text:
<md-card>
  <md-list>
    <md-subheader>Automatic Payments</md-subheader>
    <md-list-item class="md-2-line">
      <md-button class="md-icon-button" aria-label="Change card" ng-click="cardCtrl.changeCard()">
        <md-icon md-font-set="material-icons">credit_card</md-icon>
      </md-button>

          Card: {{student.card}}
          No Card

          {{student.email}}
          Tap the icon to setup

    </md-list-item>
  </md-list>
</md-card>


text:
"""
Created on Thu Aug  3 11:58:21 2017

@author: lewismoffat

This script runs an AutoEncoder netowork on all the data for a specified Feat.
Engineering methods

"""

#==============================================================================
# Module Imports
#==============================================================================

import numpy as np
import matplotlib.pyplot as plt
import dataProcessing as dp
import pdb
import seaborn as sns
import sklearn as sk

from collections import defaultdict
from collections import Counter

from sklearn.manifold import TSNE
from sklearn.cluster import KMeans
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder

from matplotlib import pylab

from hmmlearn import hmm

#==============================================================================
# Get the data
#==============================================================================

method = "Li" #"tuple"
tupsize=3

# are we doing the full set
singlePatient=False

# which patient to get data from
patient=['Complete']
chain = "beta"

if singlePatient:
    print('Patient: '+patient[0])
    delim = ["naive",chain]+patient #other delimiters
else:
    print('Patient: All')
    delim = ["naive",chain] #other delimiters

seqs, vj = dp.loadAllPatients(delim) # these gets all the sequences and vj values

# filter out joint sequences
seqs[0], seqs[1], vj[0], vj[1], joint = dp.removeDup(seqs[0], seqs[1], vj[0], vj[1])

#integerize
seqs[0]=dp.char2int(seqs[0], 14, pad=False)
seqs[1]=dp.char2int(seqs[1], 14, pad=False)

for idx0,seqz in enumerate(seqs):
    for idx, seq in enumerate(seqz):
        seqs[idx0][idx].append(21)
cd4t,cd4v=train_test_split(seqs[0], test_size=0.2)
cd8t,cd8v=train_test_split(seqs[1], test_size=0.2)

# need to make 21 the end token

#==============================================================================
#  Calculate transition matrix
#==============================================================================

az=cd4t
b = np.zeros((21,21)) # empty matrix to be filled

for a in az: # go through each sequence
    for (x,y), c in Counter(zip(a, a[1:])).items(): # go through each counter a
        b[x-1,y-1] += c
# normalize the rows
row_sums = b.sum(axis=1)
new_matrix = b / row_sums[:, np.newaxis]

print(b)


text:
import * as React from 'react';
import { unstable_useControlled as useControlled, unstable_useId as useId } from '@mui/utils';

export interface UseTabsParameters {
  /**
   * The value of the currently selected `Tab`.
   * If you don't want any selected `Tab`, you can set this prop to `false`.
   */
  value?: string | number | false;
  /**
   * The default value. Use when the component is not controlled.
   */
  defaultValue?: string | number | false;
  /**
   * The component orientation (layout flow direction).
   * @default 'horizontal'
   */
  orientation?: 'horizontal' | 'vertical';
  /**
   * The direction of the text.
   * @default 'ltr'
   */
  direction?: 'ltr' | 'rtl';
  /**
   * Callback invoked when new value is being set.
   */
  onChange?: (event: React.SyntheticEvent, value: number | string) => void;
  /**
   * If `true` the selected tab changes on focus. Otherwise it only
   * changes on activation.
   */
  selectionFollowsFocus?: boolean;
}

const useTabs = (parameters: UseTabsParameters) => {
  const {
    value: valueProp,
    defaultValue,
    onChange,
    orientation,
    direction,
    selectionFollowsFocus,
  } = parameters;

  const [value, setValue] = useControlled({
    controlled: valueProp,
    default: defaultValue,
    name: 'Tabs',
    state: 'value',
  });

  const idPrefix = useId();

  const onSelected = React.useCallback(
    (e, newValue) => {
      setValue(newValue);
      if (onChange) {
        onChange(e, newValue);
      }
    },
    [onChange, setValue],
  );

  const tabsContextValue = React.useMemo(() => {
    return { idPrefix, value, onSelected, orientation, direction, selectionFollowsFocus };
  }, [idPrefix, value, onSelected, orientation, direction, selectionFollowsFocus]);

  return {
    tabsContextValue,
  };
};

export default useTabs;