text:
#include "nsconfig.h"
#include "ns_types.h"
#include "string.h"
#include "ns_trace.h"
#include "randLIB.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "RPL/rpl_control.h"
#ifdef HAVE_RPL
#include "RPL/rpl_data.h"
#endif
#include "RPL/rpl_protocol.h"
#ifdef HAVE_MPL
#include "MPL/mpl.h"
#endif
#include "Common_Protocols/icmpv6.h"
#include "Common_Protocols/icmpv6_prefix.h"
#include "Common_Protocols/icmpv6_radv.h"
#include "Common_Protocols/ip.h"
#include "Common_Protocols/ipv6.h"
#include "Common_Protocols/mld.h"
#include "Core/include/socket.h"
#include "ipv6_stack/protocol_ipv6.h"
#include "ipv6_stack/ipv6_routing_table.h"
#include "ip_fsc.h"
#include "ipv6_stack/ipv6_routing_table.h"
#include "Service_Libs/nd_proxy/nd_proxy.h"
#include "NWK_INTERFACE/Include/protocol_stats.h"
#include "common_functions.h"
#include "6LoWPAN/ND/nd_router_object.h"
#include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
#include "6LoWPAN/ws/ws_common_defines.h"
#include "6LoWPAN/ws/ws_common.h"

#define TRACE_GROUP "icmp"

static buffer_t *icmpv6_echo_request_handler(struct buffer *buf);

/* Check to see if a message is recognisable ICMPv6, and if so, fill in code/type */
/* This used ONLY for the e.1 + e.2 tests in RFC 4443, to try to avoid ICMPv6 error loops */
/* Packet may be ill-formed, because we are considering an ICMPv6 error response. */
static bool is_icmpv6_msg(buffer_t *buf)
{
    const uint8_t *ptr = buffer_data_pointer(buf);
    uint16_t len = buffer_data_length(buf);

    /* IP header format:
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |Version| Traffic Class |           Flow Label                  |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     * |         Payload Length        |  Next Header  |   Hop Limit   |
     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *    + Source Address (16) + Destination Address (16), total 40
     */
    if (len < IPV6_HDRLEN) {
        return false;
    }
    uint16_t ip_len = common_read_16_bit(ptr + IPV6_HDROFF_PAYLOAD_LENGTH);
    uint8_t nh = ptr[IPV6_HDROFF_NH];
    ptr += IPV6_HDRLEN;
    len -= IPV6_HDRLEN;
    if (ip_len > len) {
        return false;
    }
    len = ip_len;
    while (len) {
        uint16_t hdrlen;
        switch (nh) {
            case IPV6_NH_ICMPV6:
                if (len < 4) {
                    return false;
                }
                buf->options.type = ptr[0];
                buf->options.code = ptr[1];
                return true;
            case IPV6_NH_HOP_BY_HOP:
            case IPV6_NH_DEST_OPT:
            case IPV6_NH_ROUTING:
            case IPV6_NH_MOBILITY:
            case IPV6_NH_HIP:
            case IPV6_NH_SHIM6:
                if (len < 8) {
                    return false;
                }
                nh = ptr[0];
                hdrlen = (ptr[1] + 1) * 8;
                break;
            case IPV6_NH_AUTH:
                if (len < 8) {
                    return false;
                }
                nh = ptr[0];
                hdrlen = (ptr[1] + 2) * 4;
                break;
            default:
                return false;
        }
        if (hdrlen > len || (hdrlen & 7)) {
            return false;
        }
        ptr += hdrlen;
        len -= hdrlen;
    }
    return false;
}

buffer_t *icmpv6_error(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t type, uint8_t code, uint32_t aux)
{
    uint8_t *ptr;

    /* Don't send ICMP errors to improperly-secured packets (they either reach MLE etc successfully, or we just drop) */
    if (buf->options.ll_security_bypass_rx) {
        return buffer_free(buf);
    }

    if (cur == NULL) {
        cur = buf->interface;
    }

    /* Any ICMPv6 error in response to an UP packet implies an RX drop... */
    if ((buf->info & B_DIR_MASK) == B_DIR_UP) {
        protocol_stats_update(STATS_IP_RX_DROP, 1);
    }

    /* RFC 4443 processing rules e.1-2: don't send errors for ICMPv6 errors or redirects */
    if (is_icmpv6_msg(buf) && (buf->options.type < 128 || buf->options.type == ICMPV6_TYPE_INFO_REDIRECT)) {
        return buffer_free(buf);
    }

    /* RFC 4443 processing rules e.3-5: don't send errors for IP multicasts or link-layer multicasts+broadcasts (with exceptions) */
    if (addr_is_ipv6_multicast(buf->dst_sa.address) || buf->options.ll_broadcast_rx || buf->options.ll_multicast_rx) {
        if (!(type == ICMPV6_TYPE_ERROR_PACKET_TOO_BIG ||
                (type == ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM && code == ICMPV6_CODE_PARAM_PRB_UNREC_IPV6_OPT))) {
            return buffer_free(buf);
        }
    }

    /* RFC 4443 processing rule e.6 - source doesn't identify a single node */
    if (addr_is_ipv6_unspecified(buf->src_sa.address) || addr_is_ipv6_multicast(buf->src_sa.address)) {
        return buffer_free(buf);
    }

    if (addr_interface_address_compare(cur, buf->dst_sa.address) == 0) {
        // RFC 4443 2.2 - if addressed to us, use that address as source
        memswap(buf->dst_sa.address, buf->src_sa.address, 16);
    } else {
        // Otherwise we will use normal address selection rule
        buf->dst_sa = buf->src_sa;

        // This makes buffer_route choose the address
        buf->src_sa.addr_type = ADDR_NONE;
    }

    buffer_turnaround(buf);

    if (!ipv6_buffer_route(buf)) {
        return buffer_free(buf);
    }
    cur = buf->interface;

    /* Token-bucket rate limiting */
    if (!cur->icmp_tokens) {
        return buffer_free(buf);
    }
    cur->icmp_tokens--;

    /* Include as much of the original packet as possible, without exceeding
     * minimum MTU of 1280. */
    uint16_t max_payload = ipv6_max_unfragmented_payload(buf, IPV6_MIN_LINK_MTU);
    if (buffer_data_length(buf) > max_payload - 8) {
        buffer_data_length_set(buf, max_payload - 8);
    }

    if ((buf = buffer_headroom(buf, 4)) == NULL) {
        return NULL;
    }
    ptr = buffer_data_reserve_header(buf, 4);
    ptr = common_write_32_bit(aux, ptr);
    buf->options.traffic_class = 0;
    buf->options.type = type;
    buf->options.code = code;
    buf->options.hop_limit = cur->cur_hop_limit;
    buf->info = (buffer_info_t)(B_FROM_ICMP | B_TO_ICMP | B_DIR_DOWN);

    return (buf);
}

#ifndef NO_IPV6_PMTUD
/* Look at a (potentially-partial) packet that should be a copy of
 * something we sent from an ICMP error. Identify final destination if we can.
 */
static bool icmpv6_identify_final_destination(buffer_t *buf, uint8_t *dest)
{
    const uint8_t *ptr = buffer_data_pointer(buf);

    /* Start with destination in IP header */
    memcpy(dest, ptr + 24, 16);
#ifdef HAVE_RPL
    /* Have to look for routing header */
    uint8_t nh = ptr[6];
    uint16_t hlen = 40;
    uint16_t len = buffer_data_length(buf);
    ptr += 40;
    len -= 40;
    for (;;) {
        if (len < hlen) {
            return false;
        }
        ptr += hlen;
        len -= hlen;

        /* Only need to process stuff we can send... */
        switch (nh) {
            case IPV6_NH_HOP_BY_HOP:
            case IPV6_NH_DEST_OPT:
                if (len < 2) {
                    return false;
                }
                hlen = (ptr[1] + 1) * 8;
                nh = ptr[0];
                break;
            case IPV6_NH_ROUTING:
                if (len < 4) {
                    return false;
                }
                /* If segments left is zero, IP dest is okay */
                if (ptr[3] == 0) {
                    return true;
                }
                if (ptr[2] != IPV6_ROUTING_TYPE_RPL) {
                    return false;
                }
                hlen = (ptr[1] + 1) * 8;
                if (len < hlen) {
                    return false;
                }
                return rpl_data_get_srh_last_address(ptr, dest);
            case IPV6_NH_FRAGMENT:
            case IPV6_NH_IPV6:
            case IPV6_NH_ICMPV6:
            case IPV6_NH_UDP:
            case IPV6_NH_TCP:
                /* If we've reached this header, it's too late for routing */
                return true;
            default:
                /* Unrecognised header - can't have come from us... */
                return false;
        }
    }
#else
    return true;
#endif
}

buffer_t *icmpv6_packet_too_big_handler(buffer_t *buf)
{
    tr_info("ICMP packet too big from: %s", trace_ipv6(buf->src_sa.address));

    /* Need 4 for MTU, plus at least the IP header */
    if (buffer_data_length(buf) < 4 + 40) {
        return buffer_free(buf);
    }

    protocol_interface_info_entry_t *cur = buf->interface;

    const uint8_t *ptr = buffer_data_pointer(buf);
    uint32_t mtu = common_read_32_bit(ptr);

    /* RFC 8201 - ignore MTU smaller than minimum */
    if (mtu < IPV6_MIN_LINK_MTU) {
        return buffer_free(buf);
    }

    ptr = buffer_data_strip_header(buf, 4);

    /* Check source is us */
    if (addr_interface_address_compare(cur, ptr + 8)) {
        return buffer_free(buf);
    }

    uint8_t final_dest[16];
    if (!icmpv6_identify_final_destination(buf, final_dest)) {
        return buffer_free(buf);
    }

    ipv6_destination_t *dest = ipv6_destination_lookup_or_create(final_dest, cur->id);

    if (dest && mtu < dest->pmtu) {

        tr_info("Reducing PMTU to %"PRIu32" for: %s", mtu, trace_ipv6(final_dest));
        dest->pmtu = mtu;
        dest->pmtu_lifetime = cur->pmtu_lifetime;
    }

    return buffer_free(buf);
}
#endif

static buffer_t *icmpv6_echo_request_handler(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur = buf->interface;
    if (!cur) {
        return buffer_free(buf);
    }

    buf->info = (buffer_info_t)(B_FROM_ICMP | B_TO_ICMP | B_DIR_DOWN);
    buf->options.type = ICMPV6_TYPE_INFO_ECHO_REPLY;
    buf->options.code = 0x00;
    buf->options.hop_limit = cur->cur_hop_limit;

    if (addr_is_ipv6_multicast(buf->dst_sa.address)) {
        const uint8_t *ipv6_ptr;
        ipv6_ptr = addr_select_source(cur, buf->dst_sa.address, 0);
        if (!ipv6_ptr) {
            tr_debug("No address");
            return buffer_free(buf);
        }
        memcpy(buf->dst_sa.address, buf->src_sa.address, 16);
        memcpy(buf->src_sa.address, ipv6_ptr, 16);
    } else {
        memswap(buf->dst_sa.address, buf->src_sa.address, 16);
    }

    return buffer_turnaround(buf);
}

#ifdef HAVE_IPV6_ND
static void icmpv6_na_aro_handler(protocol_interface_info_entry_t *cur_interface, const uint8_t *dptr, const uint8_t *dst_addr)
{
    (void)dst_addr;
    dptr += 2;
    uint16_t life_time;
    uint8_t nd_status  = *dptr;
    dptr += 4;
    life_time = common_read_16_bit(dptr);
    dptr += 2;
    if (memcmp(dptr, cur_interface->mac, 8) != 0) {
        return;
    }

    /* Failure responses go to LL64, and they thus don't actually indicate the
     * address that we were trying to register. So we have to rely on having
     * "current DAD address" stored. We don't get it from the packet in any case.
     */
    if (!cur_interface->if_6lowpan_dad_process.active) {
        return;
    }

    if_address_entry_t *addr_entry = addr_get_entry(cur_interface, cur_interface->if_6lowpan_dad_process.address);
    if (!addr_entry) {
        return;
    }

    switch (nd_status) {
        case ARO_SUCCESS:
            addr_cb(cur_interface, addr_entry, ADDR_CALLBACK_DAD_COMPLETE);
            if (addr_entry->cb) {
                /* Lifetime is in minutes, state_timer in 1/10 s: a factor of 600 */
                /* Set renewal to 75-85% of full lifetime by multiplying by [450..510] */
                addr_entry->state_timer = life_time * randLIB_get_random_in_range(450, 510);
            }

            break;

        case ARO_DUPLICATE:
            addr_duplicate_detected(cur_interface, addr_entry->address);
            break;

        case ARO_FULL:
            addr_cb(cur_interface, addr_entry, ADDR_CALLBACK_PARENT_FULL);
            break;
    }
}

/*
 *      Neighbor Solicitation Message Format
 *
 *        0                   1                   2                   3
 *        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *       |     Type      |     Code      |          Checksum             |
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *       |                           Reserved                            |
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *       |                                                               |
 *       +                                                               +
 *       |                                                               |
 *       +                       Target Address                          +
 *       |                                                               |
 *       +                                                               +
 *       |                                                               |
 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *       |   Options ...
 *       +-+-+-+-+-+-+-+-+-+-+-+-
 *
 *
 *      Source/Target Link-layer Address
 *
 *       0                   1                   2                   3
 *       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *      |     Type      |    Length     |    Link-Layer Address ...
 *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 */
static buffer_t *icmpv6_ns_handler(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur;
    uint8_t target[16];
    uint8_t dummy_sllao[16];
    bool proxy = false;
    const uint8_t *sllao;
    const uint8_t *aro;
    uint8_t *dptr = buffer_data_pointer(buf);
    aro_t aro_out = { .present = false };

    cur = buf->interface;

    if (buf->options.code != 0 || buf->options.hop_limit != 255) {
        goto drop;
    }

    if (!icmpv6_options_well_formed_in_buffer(buf, 20)) {
        goto drop;
    }

    sllao = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_SRC_LL_ADDR, 0);

    /* If no SLLAO, ignore ARO (RFC 6775 6.5) */
    /* This rule can be bypassed by setting flag "use_eui64_as_slla_in_aro" to true */
    if (cur->ipv6_neighbour_cache.recv_addr_reg &&
            (cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro || sllao)) {
        aro = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_ADDR_REGISTRATION, 0);
    } else {
        aro = NULL;
    }

    /* ARO's length must be 2 and status must be 0 */
    if (aro && (aro[1] != 2 || aro[2] != 0)) {
        goto drop;
    }

    /* If there was no SLLAO on ARO, use mac address to create dummy one... */
    if (aro && !sllao && cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro) {
        dummy_sllao[0] = ICMPV6_OPT_SRC_LL_ADDR;    // Type
        dummy_sllao[1] = 2;                         // Length = 2x8 bytes
        memcpy(dummy_sllao + 2, aro + 8, 8);        // EUI-64
        memset(dummy_sllao + 10, 0, 6);             // Padding

        sllao = dummy_sllao;
    }
    // Skip the 4 reserved bytes
    dptr += 4;

    // Copy the target IPv6 address
    memcpy(target, dptr, 16);
    dptr += 16;

    if (addr_is_ipv6_multicast(target)) {
        goto drop;
    }

    if (addr_is_ipv6_unspecified(buf->src_sa.address)) {
        /* Dest must be to solicited-node multicast, without source LL-addr */
        if (sllao || memcmp(buf->dst_sa.address, ADDR_MULTICAST_SOLICITED, 13) != 0) {
            goto drop;
        }

        /* If unspecified source, ignore ARO (RFC 6775 6.5) */
        aro = NULL;
    }

    /* See RFC 4862 5.4.3 - hook for Duplicate Address Detection */
    if (addr_is_tentative_for_interface(cur, target)) {
        if (addr_is_ipv6_unspecified(buf->src_sa.address)) {
            tr_debug("Received DAD NS for our tentative address");
            /* Someone else is performing DAD */
            addr_duplicate_detected(cur, target);
        }
        goto drop;
    }

    /* This first check's a bit dodgy - it responds to our address on the other
     * interface, which we should only do in the whiteboard case.
     */
    if (addr_interface_address_compare(cur, target) != 0) {
        //tr_debug("Received  NS for proxy %s", trace_ipv6(target));

        proxy = true;
        //Filter Link Local scope
        if (addr_is_ipv6_link_local(target)) {
            goto drop;
        }

        if (!nd_proxy_enabled_for_downstream(cur->id) || !nd_proxy_target_address_validation(cur->id, target)) {
            goto drop;
        }
    }

    if (aro) {
        /* If it had an ARO, and we're paying attention to it, possibilities:
         * 1) No reply to NS now, we need to contact border router (false return)
         * 2) Reply to NS now, with ARO (true return, aro_out.present true)
         * 3) Reply to NS now, without ARO (true return, aro_out.present false)
         */
        if (!nd_ns_aro_handler(cur, aro, sllao, buf->src_sa.address, &aro_out)) {
            goto drop;
        }
    }

    /* If we're returning an ARO, then we assume the ARO handler has done the
     * necessary to the Neighbour Cache. Otherwise, normal RFC 4861 processing. */
    if (!aro_out.present &&
            sllao && cur->if_llao_parse(cur, sllao, &buf->dst_sa)) {
        ipv6_neighbour_update_unsolicited(&cur->ipv6_neighbour_cache, buf->src_sa.address, buf->dst_sa.addr_type, buf->dst_sa.address);
    }

    buffer_t *na_buf = icmpv6_build_na(cur, true, !proxy, addr_is_ipv6_multicast(buf->dst_sa.address), target, aro_out.present ? &aro_out : NULL, buf->src_sa.address);

    buffer_free(buf);

    return na_buf;

drop:
    buf = buffer_free(buf);

    return buf;

}

int icmpv6_slaac_prefix_update(struct protocol_interface_info_entry *cur, const uint8_t *prefix_ptr, uint8_t prefix_len, uint32_t valid_lifetime, uint32_t preferred_lifetime)
{
    int ret_val = -1;

    //Validate first current list If prefix is already defined adress
    ns_list_foreach_safe(if_address_entry_t, e, &cur->ip_addresses) {
        if (e->source == ADDR_SOURCE_SLAAC && (e->prefix_len == prefix_len) && bitsequal(e->address, prefix_ptr, prefix_len)) {
            //Update Current lifetimes (see RFC 4862 for rules detail)
            if (valid_lifetime > (2 * 60 * 60) || valid_lifetime > e->valid_lifetime) {
                addr_set_valid_lifetime(cur, e, valid_lifetime);
            } else if (e->valid_lifetime <= (2 * 60 * 60)) {
                //NOT Update Valid Lifetime
            } else {
                addr_set_valid_lifetime(cur, e, 2 * 60 * 60);
            }

            addr_set_preferred_lifetime(cur, e, preferred_lifetime);
            ret_val = 0;
        }
    }
    return ret_val;
}

void icmpv6_slaac_prefix_register_trig(struct protocol_interface_info_entry *cur, uint8_t *prefix_ptr, uint8_t prefix_len)
{

    //Validate first current list If prefix is already defined adress
    ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) {
        if (e->source == ADDR_SOURCE_SLAAC && (e->prefix_len == prefix_len) && bitsequal(e->address, prefix_ptr, prefix_len)) {
            e->state_timer = 150;
        }
    }
}
#endif // HAVE_IPV6_ND

if_address_entry_t *icmpv6_slaac_address_add(protocol_interface_info_entry_t *cur, const uint8_t *prefix_ptr, uint8_t prefix_len, uint32_t valid_lifetime, uint32_t preferred_lifetime, bool skip_dad, slaac_src_e slaac_src)
{
    if_address_entry_t *address_entry;
    uint8_t ipv6_address[16];
    //define Autonomous address generation

    if (prefix_len != 64) {
        return NULL;
    }

    if (slaac_src == SLAAC_IID_DEFAULT && cur->opaque_slaac_iids && addr_opaque_iid_key_is_set()) {
        slaac_src = SLAAC_IID_OPAQUE;
    }

    memcpy(ipv6_address, prefix_ptr, 8);
    switch (slaac_src) {
        case SLAAC_IID_DEFAULT:
        case SLAAC_IID_FIXED:
            memcpy(ipv6_address + 8, cur->iid_slaac, 8);
            break;
        case SLAAC_IID_EUI64:
            memcpy(ipv6_address + 8, cur->iid_eui64, 8);
            break;
        case SLAAC_IID_OPAQUE:
            addr_generate_opaque_iid(cur, ipv6_address);
            break;
         case SLAAC_IID_6LOWPAN_SHORT:
            if (cur->nwk_id != IF_6LoWPAN || !cur->mac_parameters) {
                return NULL;
            }
            memcpy(ipv6_address + 8, ADDR_SHORT_ADR_SUFFIC, 6);
            common_write_16_bit(cur->lowpan_desired_short_address, ipv6_address + 14);
            break;

        default:
            return NULL;
    }

    //tr_debug("Add add: %s", trace_ipv6(ipv6_address));

    address_entry = addr_add(cur, ipv6_address, 64, ADDR_SOURCE_SLAAC, valid_lifetime, preferred_lifetime, skip_dad);
    if (address_entry) {
        address_entry->cb = NULL;
    }
    return address_entry;
}

#ifdef HAVE_IPV6_ND
static buffer_t *icmpv6_ra_handler(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur;
    uint8_t flags, hoplimit;
    uint32_t reachable_time, retrans_timer;
    uint16_t data_len, router_lifetime;
    uint8_t *dptr;
    ipv6_neighbour_t *ncache_entry = NULL;
    int_fast8_t preference = 0;
    uint32_t longest_route_lifetime = 0;

    if (!buf) {
        return NULL;
    }

    cur = buf->interface;

    // If both route and prefix receive are disabled do not process any RA options
    if (!cur->recv_ra_routes && !cur->recv_ra_prefixes) {
        return buffer_free(buf);
    }

    // Drop RA If LL address generation is not ready
    if (addr_interface_get_ll_address(cur, NULL, 0) < 0) {
        return buffer_free(buf);
    }

    if (cur->nwk_id == IF_6LoWPAN) {
        // XXX this check needs to be for host bootstrap only
        if ((cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) == 0) {
            if (protocol_6lowpan_interface_compare_cordinator_netid(cur, &(buf->src_sa.address[8])) != 0) {
                return buffer_free(buf);
            }
        }
    }

    if (!addr_is_ipv6_link_local(buf->src_sa.address) || buf->options.hop_limit != 255 || buf->options.code != 0) {
        return buffer_free(buf);
    }

    if (!icmpv6_options_well_formed_in_buffer(buf, 12)) {
        tr_debug("Malformed RA");
        return buffer_free(buf);
    }

    /* Token-bucket rate limiting */
    if (!cur->icmp_ra_tokens) {
        return buffer_free(buf);
    }
    cur->icmp_ra_tokens--;

    data_len = buffer_data_length(buf);
    dptr = buffer_data_pointer(buf);
    //tr_debug("RX RA: %s", trace_ipv6(buf->src_sa.address));

    /* XXX we always set variables based on RAs; fine for a host,
     * but wrong/iffy for a router. But then so is doing SLAAC as a
     * router...
     */
    hoplimit = *dptr++;
    if (hoplimit) {
        cur->cur_hop_limit = hoplimit;
    }

    //Read Flags
    flags = *dptr++;
    router_lifetime = common_read_16_bit(dptr);
    dptr += 2;

    reachable_time = common_read_32_bit(dptr);
    dptr += 4;
    if (reachable_time != 0 && reachable_time != cur->base_reachable_time) {
        protocol_stack_interface_set_reachable_time(cur, reachable_time);
    }

    retrans_timer = common_read_32_bit(dptr);
    dptr += 4;
    if (retrans_timer != 0) {
        cur->ipv6_neighbour_cache.retrans_timer = retrans_timer;
    }

    const uint8_t *mtu_option = icmpv6_find_option_in_buffer(buf, 12, ICMPV6_OPT_MTU, 1);
    uint32_t mtu = mtu_option ? common_read_32_bit(mtu_option + 4) : 0;

    sockaddr_t ll_addr = { .addr_type = ADDR_NONE };
    const uint8_t *sllao = icmpv6_find_option_in_buffer(buf, 12, ICMPV6_OPT_SRC_LL_ADDR, 0);
    if (sllao) {
        if (cur->if_llao_parse(cur, sllao, &ll_addr)) {
            ncache_entry = ipv6_neighbour_update_unsolicited(&cur->ipv6_neighbour_cache, buf->src_sa.address, ll_addr.addr_type, ll_addr.address);
        }
    }

    buffer_data_strip_header(buf, 12);
    data_len -= 12;

    if (cur->nwk_id == IF_6LoWPAN) {
        const uint8_t *abro;
        bool uptodate;

        /* ABRO processing - aiming to separate this from standard processing; only 6LRs need to use ABROs */
        abro = icmpv6_find_option_in_buffer(buf, 0, ICMPV6_OPT_AUTHORITATIVE_BORDER_RTR, 3);
        if (abro) {
            uptodate = nd_ra_process_abro(cur, buf, abro + 2, flags, router_lifetime);
            /* If ABRO processing indicated stale info, skip normal processing */
            if (!uptodate) {
                goto drop;
            }
#ifndef NO_RADV_TX
            if (hoplimit != 0) {
                cur->adv_cur_hop_limit = hoplimit;
            }
            if (reachable_time != 0) {
                cur->adv_reachable_time = reachable_time;
            }
            if (retrans_timer != 0) {
                cur->adv_retrans_timer = retrans_timer;
            }
            if (mtu != 0) {
                cur->adv_link_mtu = mtu;
            }
#endif
        }
    }
    if (cur->recv_ra_routes) {
        if (router_lifetime) {
            tr_debug("Possible Default Router");
            switch (flags & RA_PRF_MASK) {
                case RA_PRF_LOW:
                    preference = -1;
                    break;
                case RA_PRF_HIGH:
                    preference = +1;
                    break;
                default:
                    preference =  0;
                    break; // invalid is treated as 0
            }
            if (router_lifetime > longest_route_lifetime) {
                longest_route_lifetime = router_lifetime;
            }
        }
        ipv6_route_add(NULL, 0, cur->id, buf->src_sa.address, ROUTE_RADV, router_lifetime, preference);
    }

    if (mtu >= IPV6_MIN_LINK_MTU && mtu <= cur->max_link_mtu) {
        cur->ipv6_neighbour_cache.link_mtu = mtu;
    }

    //Scan All options
    while (data_len) {
        uint8_t type = *dptr++;
        uint16_t length = *dptr++ * 8;

        if (type == ICMPV6_OPT_PREFIX_INFO && cur->recv_ra_prefixes && length == 32) {
            uint8_t *ptr = dptr;
            uint8_t prefix_length = *ptr++;
            uint8_t prefix_flags = *ptr++;

            uint32_t valid_lifetime = common_read_32_bit(ptr);
            ptr += 4;
            uint32_t preferred_lifetime = common_read_32_bit(ptr);
            ptr += 8; //Update 32-bit time and reserved 32-bit
            const uint8_t *prefix_ptr = ptr;

            //Check is L Flag active
            if (prefix_flags & PIO_L) {
                //define ONLink Route Information
                //tr_debug("Register On Link Prefix to routing table");
                ipv6_route_add(prefix_ptr, prefix_length, cur->id, NULL, ROUTE_RADV, valid_lifetime, 0);
            }

            //Check if A-Flag
            if (prefix_flags & PIO_A) {
                if (icmpv6_slaac_prefix_update(cur, prefix_ptr, prefix_length, valid_lifetime, preferred_lifetime) != 0) {
                    ipv6_interface_slaac_handler(cur, prefix_ptr, prefix_length, valid_lifetime, preferred_lifetime);
                }

                //tr_debug("Prefix: %s", trace_ipv6(prefix_ptr));
            }

            // If the R flag is set and we have SLLAO, let's add a neighbour cache entry.
            // This helps reduce RPL noise with source routing - may otherwise be good.
            // Note that existence of a neighbour cache entry doesn't affect routing - we
            // won't use it unless we otherwise decide they're on-link, eg from a source
            // routing header directing to them
            if ((prefix_flags & PIO_R) && ll_addr.addr_type != ADDR_NONE) {
                ipv6_neighbour_update_unsolicited(&cur->ipv6_neighbour_cache, prefix_ptr, ll_addr.addr_type, ll_addr.address);
            }
        } else if (type == ICMPV6_OPT_ROUTE_INFO && cur->recv_ra_routes) {
            uint8_t prefix_length = dptr[0];
            uint8_t route_flags = dptr[1];
            uint32_t route_lifetime = common_read_32_bit(dptr + 2);
            uint8_t *prefix_ptr = dptr + 6;
            // Check option is long enough for prefix
            if (length < 8 + (prefix_length + 7u) / 8) {
                goto next_option;
            }
            switch (route_flags & RA_PRF_MASK) {
                case RA_PRF_LOW:
                    preference = -1;
                    break;
                case RA_PRF_MEDIUM:
                    preference =  0;
                    break;
                case RA_PRF_HIGH:
                    preference = +1;
                    break;
                default:
                    goto next_option; // invalid not accepted
            }
            if (route_lifetime > longest_route_lifetime) {
                longest_route_lifetime = route_lifetime;
            }

            //Call route Update
            tr_info("Route: %s Lifetime: %lu Pref: %d", trace_ipv6_prefix(prefix_ptr, prefix_length), (unsigned long) route_lifetime, preference);
            if (route_lifetime) {
                ipv6_route_add(prefix_ptr, prefix_length, cur->id, buf->src_sa.address, ROUTE_RADV, route_lifetime, preference);
            } else {
                ipv6_route_delete(prefix_ptr, prefix_length, cur->id, buf->src_sa.address, ROUTE_RADV);
            }
        } else if (type == ICMPV6_OPT_6LOWPAN_CONTEXT) {
            nd_ra_process_lowpan_context_option(cur, dptr - 2);
        }
    next_option:
        //UPdate length and
        data_len -= length;
        dptr += length - 2;
    }

    /* RFC 4861 says to always set IsRouter on receipt of any RA, but this
     * seems to make more sense - a shutting-down router (sending the final
     * MAX_FINAL_RTR_ADVERTISEMENTS), or a router advertising only prefixes
     * shouldn't really be marked as a router. So only set IsRouter if
     * a route was advertised (with non-0 lifetime).
     */
    if (longest_route_lifetime) {
        if (!ncache_entry) {
            ncache_entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, buf->src_sa.address);
        }

        if (ncache_entry) {
            ncache_entry->is_router = true;
        }
    }

drop:
    return buffer_free(buf);
}

void icmpv6_recv_ra_routes(protocol_interface_info_entry_t *cur, bool enable)
{
    if (cur->recv_ra_routes != enable) {
        cur->recv_ra_routes = enable;
        if (!enable) {
            ipv6_route_table_remove_info(cur->id, ROUTE_RADV, NULL);
        }
    }
}

void icmpv6_recv_ra_prefixes(protocol_interface_info_entry_t *cur, bool enable)
{
    if (cur->recv_ra_prefixes != enable) {
        cur->recv_ra_prefixes = enable;
        if (!enable) {
            addr_set_non_preferred(cur, ADDR_SOURCE_SLAAC);
        }
    }
}

static buffer_t *icmpv6_redirect_handler(buffer_t *buf, protocol_interface_info_entry_t *cur)
{
    const uint8_t *ptr = buffer_data_pointer(buf);
    const uint8_t *tgt = ptr + 4;
    const uint8_t *dest = ptr + 20;
    sockaddr_t tgt_ll = { .addr_type = ADDR_NONE };

    if (buf->options.hop_limit != 255) {
        goto drop;
    }

    if (!addr_is_ipv6_link_local(buf->src_sa.address)) {
        goto drop;
    }

    if (buf->options.code != 0) {
        goto drop;
    }

    if (!icmpv6_options_well_formed_in_buffer(buf, 36)) {
        goto drop;
    }

    if (addr_is_ipv6_multicast(dest)) {
        goto drop;
    }

    const uint8_t *tllao = icmpv6_find_option_in_buffer(buf, 36, ICMPV6_OPT_TGT_LL_ADDR, 0);
    if (tllao) {
        cur->if_llao_parse(cur, tllao, &tgt_ll);
    }
    ipv6_destination_redirect(tgt, buf->src_sa.address, dest, buf->interface->id, tgt_ll.addr_type, tgt_ll.address);
    return buffer_free(buf);

drop:
    tr_warn("Redirect drop");
    return buffer_free(buf);
}

static buffer_t *icmpv6_na_handler(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur;
    uint8_t *dptr = buffer_data_pointer(buf);
    uint8_t flags;
    const uint8_t *target;
    const uint8_t *tllao;
    if_address_entry_t *addr_entry;
    ipv6_neighbour_t *neighbour_entry;

    //"Parse NA at IPv6\n");

    if (buf->options.code != 0 || buf->options.hop_limit != 255) {
        goto drop;
    }

    if (!icmpv6_options_well_formed_in_buffer(buf, 20)) {
        goto drop;
    }

    // Skip the 4 reserved bytes
    flags = *dptr;
    dptr += 4;

    // Note the target IPv6 address
    target = dptr;

    if (addr_is_ipv6_multicast(target)) {
        goto drop;
    }

    /* Solicited flag must be clear if sent to a multicast address */
    if (addr_is_ipv6_multicast(buf->dst_sa.address) && (flags & NA_S)) {
        goto drop;
    }

    cur = buf->interface;

    /* RFC 4862 5.4.4 DAD checks */
    addr_entry = addr_get_entry(cur, target);
    if (addr_entry) {
        if (addr_entry->tentative) {
            tr_debug("Received NA for our tentative address");
            addr_duplicate_detected(cur, target);
        } else {
            tr_debug("NA received for our own address: %s", trace_ipv6(target));
        }
        goto drop;
    }

    if (cur->ipv6_neighbour_cache.recv_na_aro) {
        const uint8_t *aro = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_ADDR_REGISTRATION, 2);
        if (aro) {
            icmpv6_na_aro_handler(cur, aro, buf->dst_sa.address);
        }
    }

    /* No need to create a neighbour cache entry if one doesn't already exist */
    neighbour_entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, target);
    if (!neighbour_entry) {
        goto drop;
    }

    tllao = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_TGT_LL_ADDR, 0);
    if (!tllao || !cur->if_llao_parse(cur, tllao, &buf->dst_sa)) {
        buf->dst_sa.addr_type = ADDR_NONE;
    }

    ipv6_neighbour_update_from_na(&cur->ipv6_neighbour_cache, neighbour_entry, flags, buf->dst_sa.addr_type, buf->dst_sa.address);
    if (ws_info(cur) && neighbour_entry->state == IP_NEIGHBOUR_REACHABLE) {
        tr_debug("NA neigh update");
        ws_common_neighbor_update(cur, target);
    }

drop:
    return buffer_free(buf);
}
#endif // HAVE_IPV6_ND

buffer_t *icmpv6_up(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur = NULL;
    uint8_t *dptr = buffer_data_pointer(buf);
    uint16_t data_len = buffer_data_length(buf);

    cur = buf->interface;

    if (buf->options.ll_security_bypass_rx) {
        tr_debug("ICMP: Drop by EP");
        goto drop;
    }

    if (data_len < 4) {
        //tr_debug("Ic1");
        goto drop;

    }

    buf->options.type = *dptr++;
    buf->options.code = *dptr++;

    /* Check FCS first */
    if (buffer_ipv6_fcf(buf, IPV6_NH_ICMPV6)) {
        tr_warn("ICMP cksum error!");
        protocol_stats_update(STATS_IP_CKSUM_ERROR, 1);
        goto drop;
    }

    //Skip ICMP Header Static 4 bytes length
    buffer_data_strip_header(buf, 4);

    if (cur->if_icmp_handler) {
        bool bounce = false;
        buf = cur->if_icmp_handler(cur, buf, &bounce);
        if (!buf || bounce) {
            return buf;
        }
    }

    switch (buf->options.type) {
#ifdef HAVE_IPV6_ND
        case ICMPV6_TYPE_INFO_RS:
            buf = icmpv6_rs_handler(buf, cur);
            break;

        case ICMPV6_TYPE_INFO_RA:
            buf = icmpv6_ra_handler(buf);
            break;

        case ICMPV6_TYPE_INFO_NS:
            buf = icmpv6_ns_handler(buf);
            break;

        case ICMPV6_TYPE_INFO_NA:
            buf = icmpv6_na_handler(buf);
            break;

        case ICMPV6_TYPE_INFO_REDIRECT:
            buf = icmpv6_redirect_handler(buf, cur);
            break;
#endif

        case ICMPV6_TYPE_INFO_ECHO_REQUEST:
            tr_debug("ICMP echo request from: %s", trace_ipv6(buf->src_sa.address));
            buf = icmpv6_echo_request_handler(buf);
            break;

        case ICMPV6_TYPE_INFO_ECHO_REPLY:
            ipv6_neighbour_reachability_confirmation(buf->src_sa.address, buf->interface->id);
            /* fall through */

        case ICMPV6_TYPE_ERROR_DESTINATION_UNREACH:
#ifdef HAVE_RPL_ROOT
            if (buf->options.type == ICMPV6_TYPE_ERROR_DESTINATION_UNREACH && buf->options.code == ICMPV6_CODE_DST_UNREACH_SRC_RTE_HDR_ERR) {
                buf = rpl_control_source_route_error_handler(buf, cur);
            }
#endif
            /* no break */

        default:
            if (buf) {
                buf->info = (buffer_info_t)(B_FROM_ICMP | B_TO_APP | B_DIR_UP);
                buf->options.type = (uint8_t) SOCKET_FAMILY_IPV6;
                buf->options.code = IPV6_NH_ICMPV6;
                buf->dst_sa.port = 0xffff;
                /* Put back ICMP header */
                buffer_data_reserve_header(buf, 4);
            }
            break;

        case ICMPV6_TYPE_INFO_MCAST_LIST_REPORT:
            buf = mld_report_handler(buf, cur);
            break;

        case ICMPV6_TYPE_INFO_MCAST_LIST_QUERY:
            buf = mld_query_handler(buf, cur);
            break;

#ifndef NO_IPV6_PMTUD
        case ICMPV6_TYPE_ERROR_PACKET_TOO_BIG:
            buf = icmpv6_packet_too_big_handler(buf);
            break;
#endif

#ifdef HAVE_RPL
        case ICMPV6_TYPE_INFO_RPL_CONTROL:
            buf = rpl_control_handler(buf);
            break;
#endif

#ifdef HAVE_MPL
        case ICMPV6_TYPE_INFO_MPL_CONTROL:
            buf = mpl_control_handler(buf, cur);
            break;
#endif

#ifdef HAVE_6LOWPAN_BORDER_ROUTER
        case ICMPV6_TYPE_INFO_DAR:

            if (cur->nwk_id == IF_6LoWPAN) {
                if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
                    buf = nd_dar_parse(buf, cur);
                    break;
                }
            }
            goto drop;
#endif
#ifdef HAVE_6LOWPAN_ROUTER
        case ICMPV6_TYPE_INFO_DAC:
            if (cur->nwk_id == IF_6LoWPAN) {
                if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY) {
                    buf = nd_dac_handler(buf, cur);
                    break;
                }
            }
            goto drop;
#endif

    }

    return buf;

drop:
    return buffer_free(buf);
}

buffer_t *icmpv6_down(buffer_t *buf)
{
    protocol_interface_info_entry_t *cur = buf->interface;

    buf = buffer_headroom(buf, 4);
    if (buf) {
        uint8_t *dptr;
        dptr = buffer_data_reserve_header(buf, 4);
        buf->info = (buffer_info_t)(B_FROM_ICMP | B_TO_IPV6 | B_DIR_DOWN);

        if (buf->src_sa.addr_type != ADDR_IPV6) {
            if (addr_interface_select_source(cur, buf->src_sa.address, buf->dst_sa.address, 0) != 0) {
                tr_err("ICMP:InterFace Address Get Fail--> free Buffer");
                return buffer_free(buf);
            } else {
                buf->src_sa.addr_type = ADDR_IPV6;
            }

        }

        *dptr++ = buf->options.type;
        *dptr++ = buf->options.code;
        common_write_16_bit(0, dptr);
        common_write_16_bit(buffer_ipv6_fcf(buf, IPV6_NH_ICMPV6), dptr);
        buf->options.type = IPV6_NH_ICMPV6;
        buf->options.code = 0;
        buf->options.traffic_class &= ~IP_TCLASS_ECN_MASK;
    }
    return (buf);
}

#ifdef HAVE_IPV6_ND
buffer_t *icmpv6_build_rs(protocol_interface_info_entry_t *cur, const uint8_t *dest)
{

    buffer_t *buf = buffer_get(127);
    if (!buf) {
        return NULL;
    }

    const uint8_t *src_address;
    uint8_t *ptr = buffer_data_pointer(buf);

    memcpy(buf->dst_sa.address, dest ? dest : ADDR_LINK_LOCAL_ALL_ROUTERS, 16);
    buf->dst_sa.addr_type = ADDR_IPV6;

    //select Address by Interface pointer and destination
    src_address = addr_select_source(cur, buf->dst_sa.address, 0);
    if (!src_address) {
        tr_debug("No source address defined");
        return buffer_free(buf);
    }

    memcpy(buf->src_sa.address, src_address, 16);
    buf->src_sa.addr_type = ADDR_IPV6;

    buf->options.type = ICMPV6_TYPE_INFO_RS;
    buf->options.code = 0;
    buf->options.hop_limit = 255;
    ptr = common_write_32_bit(0, ptr);

    /* RFC 6775 mandates SLLAO in RS */
    ptr = icmpv6_write_icmp_lla(cur, ptr, ICMPV6_OPT_SRC_LL_ADDR, true, src_address);

    buf->buf_end = ptr - buf->buf;
    buf->interface = cur;
    buf->info = (buffer_info_t)(B_FROM_ICMP | B_TO_ICMP | B_DIR_DOWN);

    return buf;
}

uint8_t *icmpv6_write_icmp_lla(protocol_interface_info_entry_t *cur, uint8_t *dptr, uint8_t icmp_opt, bool must, const uint8_t *ip_addr)
{
    dptr += cur->if_llao_write(cur, dptr, icmp_opt, must, ip_addr);

    return dptr;
}

/*
 * Write either an ICMPv6 Prefix Information Option for a Router Advertisement
 * (RFC4861+6275), or an RPL Prefix Information Option (RFC6550).
 * Same payload, different type/len.
 */
uint8_t *icmpv6_write_prefix_option(const prefix_list_t *prefixes,  uint8_t *dptr, uint8_t rpl_prefix, protocol_interface_info_entry_t *cur)
{
    uint8_t flags;

    ns_list_foreach(prefix_entry_t, prefix_ptr, prefixes) {
        flags = prefix_ptr->options;
        if (prefix_ptr->prefix_len == 64) {
            /* XXX this seems dubious - shouldn't get_address_with_prefix be called every time? What if the address changes or is deleted? */
            if (prefix_ptr->options & PIO_R) {
                const uint8_t *addr = addr_select_with_prefix(cur, prefix_ptr->prefix, prefix_ptr->prefix_len, 0);
                if (addr) {
                    memcpy(prefix_ptr->prefix, addr, 16);
                } else {
                    flags &= ~PIO_R;
                }
            }
        }
        if (rpl_prefix) {
            *dptr++ = RPL_PREFIX_INFO_OPTION;
            *dptr++ = 30; // Length in bytes, excluding these 2
        } else {
            *dptr++ = ICMPV6_OPT_PREFIX_INFO;
            *dptr++ = 4; // Length in 8-byte units
        }

        *dptr++ = prefix_ptr->prefix_len; //length
        *dptr++ = flags; //Flags
        dptr = common_write_32_bit(prefix_ptr->lifetime, dptr);
        dptr = common_write_32_bit(prefix_ptr->preftime, dptr);
        dptr = common_write_32_bit(0, dptr); // Reserved2
        memcpy(dptr, prefix_ptr->prefix, 16);
        dptr += 16;
    }
    return dptr;
}

/* 0                   1                   2                   3
 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |     Type      |    Length     |           Reserved            |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |                              MTU                              |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
uint8_t *icmpv6_write_mtu_option(uint32_t mtu, uint8_t *dptr)
{
    *dptr++ = ICMPV6_OPT_MTU;
    *dptr++ = 1; // length
    dptr = common_write_16_bit(0, dptr);
    dptr = common_write_32_bit(mtu, dptr);
    return dptr;
}

buffer_t *icmpv6_build_ns(protocol_interface_info_entry_t *cur, const uint8_t target_addr[16], const uint8_t *prompting_src_addr, bool unicast, bool unspecified_source, const aro_t *aro)
{
    if (!cur || addr_is_ipv6_multicast(target_addr)) {
        return NULL;
    }

    buffer_t *buf = buffer_get(127);
    if (!buf) {
        return buf;
    }

    buf->options.type = ICMPV6_TYPE_INFO_NS;
    buf->options.code = 0;
    buf->options.hop_limit = 255;

    uint8_t *ptr = buffer_data_pointer(buf);
    ptr = common_write_32_bit(0, ptr);
    memcpy(ptr, target_addr, 16);
    ptr += 16;

    if (aro) {
        *ptr++ = ICMPV6_OPT_ADDR_REGISTRATION;
        *ptr++ = 2;
        *ptr++ = aro->status; /* Should be ARO_SUCCESS in an NS */
        *ptr++ = 0;
        ptr = common_write_16_bit(0, ptr);
        ptr = common_write_16_bit(aro->lifetime, ptr);
        memcpy(ptr, aro->eui64, 8);
        ptr += 8;
    }

    if (unicast) {
        memcpy(buf->dst_sa.address, target_addr, 16);
    } else {
        memcpy(buf->dst_sa.address, ADDR_MULTICAST_SOLICITED, 13);
        memcpy(buf->dst_sa.address + 13, target_addr + 13, 3);
    }
    buf->dst_sa.addr_type = ADDR_IPV6;

    if (unspecified_source) {
        memset(buf->src_sa.address, 0, 16);
    } else {
        /* RFC 4861 7.2.2. says we should use the source of traffic prompting the NS, if possible */
        /* This is also used to specify the address for ARO messages */
        if (aro || (prompting_src_addr && addr_is_assigned_to_interface(cur, prompting_src_addr))) {
            memcpy(buf->src_sa.address, prompting_src_addr, 16);
        } else {
            /* Otherwise, according to RFC 4861, we could use any address.
             * But there is a 6LoWPAN/RPL hiccup - a node may have registered
             * to us with an ARO, and we might send it's global address a NUD
             * probe. But it doesn't know _our_ global address, which default
             * address selection would favour.
             * If it was still a host, we'd get away with using our global
             * address, as we'd be its default route, so its reply comes to us.
             * But if it's switched to being a RPL router, it would send its
             * globally-addressed reply packet up the RPL DODAG.
             * Avoid the problem by using link-local source.
             * This will still leave us with an asymmetrical connection - its
             * global address on-link for us, and we send to it directly (and
             * can NUD probe it), whereas it regards us as off-link and will
             * go via RPL (and won't probe us). But it will work fine.
             */
            if (addr_interface_get_ll_address(cur, buf->src_sa.address, 0) < 0) {
                tr_debug("No address for NS");
                return buffer_free(buf);
            }
        }
        /* SLLAO is required if we're sending an ARO */
        /* This rule can be bypassed with flag use_eui64_as_slla_in_aro */
        if (!cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro) {
            ptr = icmpv6_write_icmp_lla(cur, ptr, ICMPV6_OPT_SRC_LL_ADDR, aro, buf->src_sa.address);
        }
        /* If ARO Success sending is omitted, MAC ACK is used instead */
        /* Setting callback for receiving ACK from adaptation layer */
        if (aro && cur->ipv6_neighbour_cache.omit_aro_success) {
            buf->ack_receive_cb = rpl_control_address_register_done;
        }
    }
    buf->src_sa.addr_type = ADDR_IPV6;

    /* NS packets are implicitly on-link. If we ever find ourselves sending an
     * NS to a global address, it's because we are in some way regarding
     * it as on-link. (eg, redirect, RPL source routing header). We force
     * transmission as on-link here, regardless of routing table, to avoid any
     * potential oddities.
     */
    ipv6_buffer_route_to(buf, buf->dst_sa.address, cur);

    buffer_data_end_set(buf, ptr);
    buf->interface = cur;
    buf->info = (buffer_info_t)(B_FROM_ICMP | B_TO_ICMP | B_DIR_DOWN);

    return buf;
}
#endif // HAVE_IPV6_ND

void icmpv6_build_echo_req(protocol_interface_info_entry_t *cur, const uint8_t target_addr[16])
{
    const uint8_t *src;
    buffer_t *buf = buffer_get(127);
    if (!buf) {
        return;
    }

    buf->options.type = ICMPV6_TYPE_INFO_ECHO_REQUEST;
    buf->options.code = 0;
    buf->options.hop_limit = 255;

    uint8_t *ptr = buffer_data_pointer(buf);
    memcpy(ptr, target_addr, 16);
    ptr += 16;

    memcpy(buf->dst_sa.address, target_addr, 16);
    buf->dst_sa.addr_type = ADDR_IPV6;
    //Select Address By Destination
    src = addr_select_source(cur, buf->dst_sa.address, 0);
    if (src) {
        memcpy(buf->src_sa.address, src, 16);
    } else {
        tr_debug("No address for NS");
        buffer_free(buf);
        return;
    }
    buf->src_sa.addr_type = ADDR_IPV6;
    buffer_data_end_set(buf, ptr);
    buf->interface = cur;
    buf->info = (buffer_info_t)(B_FROM_ICMP | B_TO_ICMP | B_DIR_DOWN);
    protocol_push(buf);
}

#ifdef HAVE_6LOWPAN_ROUTER
buffer_t *icmpv6_build_dad(protocol_interface_info_entry_t *cur, buffer_t *buf, uint8_t type, const uint8_t dest_addr[16], const uint8_t eui64[8], const uint8_t reg_addr[16], uint8_t status, uint16_t lifetime)
{
    if (!cur) {
        return NULL;
    }

    if (!buf) {
        buf = buffer_get(4 + 8 + 16);
        if (!buf) {
            return buf;
        }
    }

    uint8_t *ptr = buffer_data_pointer(buf);
    buf->options.type = type;
    buf->options.code = 0;
    buf->options.hop_limit = 64; /* RFC 6775 MULTIHOP_HOPLIMIT */

    *ptr++ = status;
    *ptr++ = 0;
    ptr = common_write_16_bit(lifetime, ptr);
    memcpy(ptr, eui64, 8);
    ptr += 8;
    memcpy(ptr, reg_addr, 16);
    ptr += 16;
    buffer_data_end_set(buf, ptr);

    memcpy(buf->dst_sa.address, dest_addr, 16);
    buf->dst_sa.addr_type = ADDR_IPV6;

    const uint8_t *src = addr_select_source(cur, buf->dst_sa.address, 0);
    if (src && !addr_is_ipv6_link_local(src)) {
        memcpy(buf->src_sa.address, src, 16);
    } else {
        tr_debug("No address for DAD");
        return buffer_free(buf);
    }
    buf->src_sa.addr_type = ADDR_IPV6;
    buf->interface = cur;
    buf->info = (buffer_info_t)(B_FROM_ICMP | B_TO_ICMP | B_DIR_DOWN);

    return buf;
}
#endif // HAVE_6LOWPAN_ROUTER

#ifdef HAVE_IPV6_ND
/*
 * Neighbor Advertisement Message Format
 *
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |     Type      |     Code      |          Checksum             |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |R|S|O|                     Reserved                            |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |                                                               |
 *  +                                                               +
 *  |                                                               |
 *  +                       Target Address                          +
 *  |                                                               |
 *  +                                                               +
 *  |                                                               |
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |   Options ...
 *  +-+-+-+-+-+-+-+-+-+-+-+-
 *
 *    R              Router flag.
 *    S              Solicited flag.
 *    O              Override flag.
 */

buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited, bool override, bool tllao_required, const uint8_t target[static 16], const aro_t *aro, const uint8_t src_addr[static 16])
{
    uint8_t *ptr;
    uint8_t flags;

    tr_debug("Build NA");

    /* Check if ARO status == success, then sending can be omitted with flag */
    if (aro && cur->ipv6_neighbour_cache.omit_aro_success && aro->status == ARO_SUCCESS) {
        tr_debug("Omit success reply");
        return NULL;
    }

    buffer_t *buf = buffer_get(8 + 16 + 16 + 16); /* fixed, target addr, target ll addr, aro */
    if (!buf) {
        return NULL;
    }

    ptr = buffer_data_pointer(buf);
    buf->options.hop_limit = 255;

    // Set the ICMPv6 NA type and code fields as per RFC4861
    buf->options.type = ICMPV6_TYPE_INFO_NA;
    buf->options.code = 0x00;

    // If we're sending RAs, then we have to set the Router bit here
    // (RFC 4861 makes host trigger action when they see the IsRouter flag
    // go from true to false - RAs from us imply "IsRouter", apparently even if
    // Router Lifetime is 0. So keep R set as long as we're sending RAs)
    flags = icmpv6_radv_is_enabled(cur) ? NA_R : 0;

    if (override) {
        flags |= NA_O;
    }

    if (addr_is_ipv6_unspecified(src_addr)) {
        // Solicited flag must be 0 if responding to DAD
        memcpy(buf->dst_sa.address, ADDR_LINK_LOCAL_ALL_NODES, 16);
    } else {
        if (solicited) {
            flags |= NA_S;
        }

        /* See RFC 6775 6.5.2 - errors are sent to LL64 address
         * derived from EUI-64, success to IP source address */
        if (aro && aro->status != ARO_SUCCESS) {
            memcpy(buf->dst_sa.address, ADDR_LINK_LOCAL_PREFIX, 8);
            memcpy(buf->dst_sa.address + 8, aro->eui64, 8);
            buf->dst_sa.address[8] ^= 2;
        } else {
            memcpy(buf->dst_sa.address, src_addr, 16);
        }
    }
    buf->dst_sa.addr_type = ADDR_IPV6;

    /* In theory we could just use addr_select_source(), as RFC 4861 allows
     * any address assigned to the interface as source. But RFC 6775 shows LL64
     * as the source in its appendix, sending NA to a global address, and our
     * lower layers go a bit funny with RPL during bootstrap if we send from a
     * global address to a global address. By favouring the target address as
     * source, we catch that 6LoWPAN case (the target is LL), as well as making
     * it look neater anyway.
     */
    if (addr_is_assigned_to_interface(cur, target)) {
        memcpy(buf->src_sa.address, target, 16);
    } else {
        const uint8_t *src = addr_select_source(cur, buf->dst_sa.address, 0);
        if (!src) {
            tr_debug("No address");
            return buffer_free(buf);
        }
        memcpy(buf->src_sa.address, src, 16);
    }
    buf->src_sa.addr_type = ADDR_IPV6;

    ptr = common_write_32_bit((uint32_t) flags << 24, ptr);
    // Set the target IPv6 address
    memcpy(ptr, target, 16);
    ptr += 16;

    // Set the target Link-Layer address
    ptr = icmpv6_write_icmp_lla(cur, ptr, ICMPV6_OPT_TGT_LL_ADDR, tllao_required, target);

    if (aro) {
        *ptr++ = ICMPV6_OPT_ADDR_REGISTRATION;
        *ptr++ = 2;
        *ptr++ = aro->status;
        *ptr++ = 0;
        ptr = common_write_16_bit(0, ptr);
        ptr = common_write_16_bit(aro->lifetime, ptr);
        memcpy(ptr, aro->eui64, 8);
        ptr += 8;
    }
    //Force Next Hop is destination
    ipv6_buffer_route_to(buf, buf->dst_sa.address, cur);

    buffer_data_end_set(buf, ptr);
    buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_ICMP | B_TO_ICMP);
    buf->interface = cur;

    return (buf);
}

#endif // HAVE_IPV6_ND

#ifdef HAVE_IPV6_ND
/* Check whether the options section of an ICMPv6 message is well-formed */
bool icmpv6_options_well_formed(const uint8_t *dptr, uint_fast16_t dlen)
{
    if (dlen % 8) {
        return false;
    }

    while (dlen) {
        uint_fast16_t opt_len = dptr[1] * 8;
        if (opt_len == 0 || opt_len > dlen) {
            return false;
        }
        dptr += opt_len;
        dlen -= opt_len;
    }

    return true;
}

bool icmpv6_options_well_formed_in_buffer(const buffer_t *buf, uint16_t offset)
{
    if (buffer_data_length(buf) < offset) {
        return false;
    }

    return icmpv6_options_well_formed(buffer_data_pointer(buf) + offset,
                                      buffer_data_length(buf) - offset);
}

/*
 * Search for the first option of the specified type (and optionally length).
 * Caller must have already checked the options are well-formed.
 * If optlen is non-zero, then options with different lengths are ignored.
 * Note that optlen is in 8-octet units.
 */
const uint8_t *icmpv6_find_option(const uint8_t *dptr, uint_fast16_t dlen, uint8_t option, uint8_t optlen)
{
    while (dlen) {
        uint8_t type = dptr[0];
        uint8_t len  = dptr[1];

        if (type == option && (optlen == 0 || optlen == len)) {
            return dptr;
        } else {
            dptr += len * 8;
            dlen -= len * 8;
        }
    }
    return NULL;

}

const uint8_t *icmpv6_find_option_in_buffer(const buffer_t *buf, uint_fast16_t offset, uint8_t option, uint8_t optlen)
{
    return icmpv6_find_option(buffer_data_pointer(buf) + offset,
                              buffer_data_length(buf) - offset, option, optlen);
}
#endif // HAVE_IPV6_ND


text:
import six
from rip.schema.base_field import BaseField, FieldTypes
from rip.schema.sub_resource_field import SubResourceField

class ApiSchemaOptions(object):
    def __init__(self, meta_options, fields, declared_fields):
        if meta_options:
            for override_name in dir(meta_options):
                override = getattr(meta_options, override_name)
                setattr(self, override_name, override)

        self.fields = fields
        self.declared_fields = declared_fields

class ApiSchemaMetaClass(type):
    def __new__(cls, name, bases, attrs):
        fields = {}
        declared_fields = {}

        # Inherit any fields from parent(s).
        try:
            parents = [b for b in bases if issubclass(b, ApiSchema)]
            # Simulate the MRO.
            parents.reverse()

            for p in parents:
                meta_on_parent = getattr(p, '_meta', None)
                fields_declared_on_parent = meta_on_parent.fields if meta_on_parent else {}

                for field_name, field in fields_declared_on_parent.items():
                    fields[field_name] = field
        except NameError:
            pass

        for field_name, field in attrs.copy().items():
            # Runs only once during class construction.
            # Copy should not be a performance hit.
            if isinstance(field, BaseField):
                field = attrs.pop(field_name)
                declared_fields[field_name] = field

        fields.update(declared_fields)
        new_class = super(ApiSchemaMetaClass, cls).__new__(cls, name, bases,
                                                           attrs)

        for field_name, field in fields.items():
            field.schema_cls = new_class

        meta = getattr(new_class, 'Meta', None)
        new_class._meta = ApiSchemaOptions(meta, fields, declared_fields)

        return new_class

class ApiSchema(six.with_metaclass(ApiSchemaMetaClass)):
    def __new__(cls, *args, **kwargs):

        if not hasattr(cls._meta, 'schema_name'):
            raise TypeError(
                'Missing meta property `schema_name` on Schema `{schema_cls}`'
                .format(schema_cls=cls.__name__))

        obj = super(ApiSchema, cls).__new__(cls, *args, **kwargs)
        return obj

    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)

    def __eq__(self, value):
        for field_name, field_object in self._meta.fields.items():
            if getattr(self, field_name) != getattr(value, field_name):
                return False
        return True

    @classmethod
    def non_readonly_fields(cls):
        return {field_name: field for field_name, field in
                cls._meta.fields.items()
                if field.field_type != FieldTypes.READONLY}

    @classmethod
    def updatable_fields(cls):
        return {field_name: field for field_name, field in
                cls._meta.fields.items()
                if field.field_type == FieldTypes.DEFAULT}

    @classmethod
    def sub_resource_fields(cls):
        return {field_name: field for field_name, field in
                cls._meta.fields.items()
                if isinstance(field, SubResourceField)}

    @classmethod
    def list_fields(cls):
        return {field_name: field for field_name, field in
                cls._meta.fields.items()
                if field.show_in_list}

redpajama_set_name: RedPajamaGithub


text:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>max_k</title>
    <link rel="stylesheet" type="text/css" href="csound.css" />
    <meta name="generator" content="DocBook XSL Stylesheets V1.78.1" />
    <link rel="home" href="index.html" title="The Canonical Csound Reference Manual" />
    <link rel="up" href="OpcodesTop.html" title="Orchestra Opcodes and Operators" />
    <link rel="prev" href="maxalloc.html" title="maxalloc" />
    <link rel="next" href="maxarray.html" title="maxarray" />

          max_k

          Prev
          Orchestra Opcodes and Operators
           Next

          max_k

max_k —
      Local maximum (or minimum) value of an incoming asig signal

Description

      max_k outputs the local maximum (or minimum) value of  the incoming asig signal, checked in the time interval between ktrig has become true twice.

Syntax

knumkout max_k asig, ktrig, itype

Initialization

      itype - itype determinates the behaviour of max_k (see below)

Performance

      asig - incoming (input) signal

      ktrig - trigger signal

      max_k outputs the local maximum (or minimum) value of  the incoming asig signal, checked in the time interval between ktrig has become true twice. itype determinates the behaviour of max_k:

      1 - absolute maximum (sign of negative values is changed to positive before evaluation).

      2 - actual maximum.

      3 - actual minimum.

      4 - calculate average value of asig in the
      time interval since the last trigger.

      This opcode can be useful in several situations, for example to implement a vu-meter.

Examples

      Here is an example of the max_k opcode. It uses the file max_k.csd.

            Example 500. Example of the max_k opcode.

See the sections Real-time Audio and Command Line Flags for more information on using command line flags.

<CsoundSynthesizer>
<CsOptions>
; Select audio/midi flags here according to platform
-odac  -Ma   ;;;realtime audio out and midi in (on all inputs)
;-iadc    ;;;uncomment -iadc if RT audio input is needed too
; For Non-realtime ouput leave only the line below:
; -o max_k.wav -W ;;; for file output any platform
</CsOptions>
<CsInstruments>

sr = 44100
ksmps = 32
nchnls = 2
0dbfs  = 1

	FLpanel	"This Panel contains VU-meter",300,100
gk1,gih1 FLslider "VU-meter", 0,1,0,1, -1, 250,30, 30,30
	FLsetColor2 50, 50, 255,  gih1
	FLpanel_end
	FLrun

ga1 init 0

instr 1

kenv	linsegr	0,.5,.7,.5,.5,.2,0
ifreq	cpsmidi
a1	poscil	0dbfs*kenv, ifreq, 1
ga1	=	ga1+a1

endin

instr 2

	outs	ga1, ga1
ktrig	metro	25					;refresh 25 times per second
kval	max_k	ga1, ktrig, 1
	FLsetVal ktrig, kval, gih1
ga1	=	0

endin

</CsInstruments>
<CsScore>
f1 0 1024 10 1

i2 0 3600
f0 3600

e
</CsScore>
</CsoundSynthesizer>

Credits

Written by Gabriel Maldonado.

New in Csound 5 (Previously available only on
    CsoundAV)

Fixed to agree with documentation in 5.15

          Prev

            Up

           Next

          maxalloc

            Home

           maxarray


text:
import Command = require("leadfoot/Command");
import Element = require("leadfoot/Element");
import Session = require("leadfoot/Session");

var session: Session;
var command: Command<any> = new Command(session);

command
    .findByXpath("some xpath")
    .click()
    .end();


text:
///////////////////////////////////////////////////////////////////////////////
//
//  Now we'll introduce boolean expressions and control structures.
//  Is it obvious now what we are up to? ;-)
//
//  [ JDG April 9, 2007 ]       spirit2
//  [ JDG February 18, 2011 ]   Pure attributes. No semantic actions.
//
///////////////////////////////////////////////////////////////////////////////

#include "statement.hpp"
#include "vm.hpp"
#include "compiler.hpp"

///////////////////////////////////////////////////////////////////////////////
//  Main program
///////////////////////////////////////////////////////////////////////////////
int
main()
{
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Statement parser...\n\n";
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Type some statements... ";
    std::cout << "An empty line ends input, compiles, runs and prints results\n\n";
    std::cout << "Example:\n\n";
    std::cout << "    var a = 123;\n";
    std::cout << "    var b = 456;\n";
    std::cout << "    var c = a + b * 2;\n\n";
    std::cout << "-------------------------\n";

    std::string str;
    std::string source;
    while (std::getline(std::cin, str))
    {
        if (str.empty())
            break;
        source += str + '\n';
    }

    typedef std::string::const_iterator iterator_type;
    iterator_type iter = source.begin();
    iterator_type end = source.end();

    client::vmachine vm;                        // Our virtual machine
    client::code_gen::program program;          // Our VM program
    client::ast::statement_list ast;            // Our AST

    client::error_handler<iterator_type>
        error_handler(iter, end);               // Our error handler
    client::parser::statement<iterator_type>
        parser(error_handler);                  // Our parser
    client::code_gen::compiler
        compile(program, error_handler);       // Our compiler

    boost::spirit::ascii::space_type space;
    bool success = phrase_parse(iter, end, parser, space, ast);

    std::cout << "-------------------------\n";

    if (success && iter == end)
    {
        if (compile.start(ast))
        {
            std::cout << "Success\n";
            std::cout << "-------------------------\n";
            vm.execute(program());

            std::cout << "-------------------------\n";
            std::cout << "Assembler----------------\n\n";
            program.print_assembler();

            std::cout << "-------------------------\n";
            std::cout << "Results------------------\n\n";
            program.print_variables(vm.stack);
        }
        else
        {
            std::cout << "Compile failure\n";
        }
    }
    else
    {
        std::cout << "Parse failure\n";
    }

    std::cout << "-------------------------\n\n";
    return 0;
}


text:
ENV["RACK_ENV"] = "production" if ENV["RACK_ENV"].to_s.empty?

require "json"
require "bunto"
require "base64"
require "webrick"
require "sinatra"
require "fileutils"
require "sinatra/base"
require "sinatra/json"
require "addressable/uri"
require "sinatra/reloader"
require "sinatra/namespace"

module BuntoAdmin
  autoload :APIable,          "bunto-admin/apiable"
  autoload :DataFile,         "bunto-admin/data_file"
  autoload :Directory,        "bunto-admin/directory"
  autoload :FileHelper,       "bunto-admin/file_helper"
  autoload :PageWithoutAFile, "bunto-admin/page_without_a_file"
  autoload :PathHelper,       "bunto-admin/path_helper"
  autoload :Server,           "bunto-admin/server"
  autoload :StaticServer,     "bunto-admin/static_server"
  autoload :URLable,          "bunto-admin/urlable"
  autoload :Version,          "bunto-admin/version"

  def self.site
    @site ||= begin
      site = Bunto.sites.first
      site.future = true
      site
    end
  end
end

# Monkey Patches
require_relative "./bunto/commands/serve"
require_relative "./bunto/commands/build"

[Bunto::Page, Bunto::Document, Bunto::StaticFile, Bunto::Collection].each do |klass|
  klass.include BuntoAdmin::APIable
  klass.include BuntoAdmin::URLable
end


text:
{template 'common/header'}

	参数设置

		借用权限

		支付参数

		微信通知设置

		邮件通知参数

		uc站点整合

		上传js接口文件

		<col width="200px " />
		<col />
		<col width="100px" />

			设置通知模板

				{{ tpl.name }}

				{{ tpl.tpl }}

修改

					<button type="button" class="close" data-dismiss="modal">×Close</button>

{{ tplList[active]['name'] }}

						<input type="" name="" id="" ng-model="activetpl" class="form-control" placeholder="{{ tplList[active]['name'] }}" />
						{{ tplList[active]['help'] }}

					<button type="button" class="btn btn-primary" ng-click="saveTpl()">确定</button>
					<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>

{template 'common/footer'}


text:
//////////////////////////////////////////////////////////////////////////////////////////////
//
// Declarations for all conditionals / conditional values we support.
//
#pragma once

#include <string>
#include <cstring>

#include "ts/ts.h"
#include "tscore/ink_string.h"

#include "condition.h"
#include "matcher.h"
#include "value.h"
#include "lulu.h"
//#include <mdbm.h>

///////////////////////////////////////////////////////////////////////////////
// Condition declarations.
//

// Always true
class ConditionTrue : public Condition
{
public:
  ConditionTrue() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionTrue"); }

  // noncopyable
  ConditionTrue(const ConditionTrue &) = delete;
  void operator=(const ConditionTrue &) = delete;

  void
  append_value(std::string &s, const Resources & /* res ATS_UNUSED */) override
  {
    s += "TRUE";
  }

protected:
  bool
  eval(const Resources & /* res ATS_UNUSED */) override
  {
    TSDebug(PLUGIN_NAME, "Evaluating TRUE()");
    return true;
  }
};

// Always false
class ConditionFalse : public Condition
{
public:
  ConditionFalse() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionFalse"); }

  // noncopyable
  ConditionFalse(const ConditionFalse &) = delete;
  void operator=(const ConditionFalse &) = delete;

  void
  append_value(std::string &s, const Resources & /* res ATS_UNUSED */) override
  {
    s += "FALSE";
  }

protected:
  bool
  eval(const Resources & /* res ATS_UNUSED */) override
  {
    TSDebug(PLUGIN_NAME, "Evaluating FALSE()");
    return false;
  }
};

// Check the HTTP return status
class ConditionStatus : public Condition
{
  typedef Matchers<TSHttpStatus> MatcherType;

public:
  ConditionStatus() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionStatus"); }

  // noncopyable
  ConditionStatus(const ConditionStatus &) = delete;
  void operator=(const ConditionStatus &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;
  void initialize_hooks() override; // Return status only valid in certain hooks
};

// Check the HTTP method
class ConditionMethod : public Condition
{
  typedef Matchers<std::string> MatcherType;

public:
  ConditionMethod() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionMethod"); }

  // noncopyable
  ConditionMethod(const ConditionMethod &) = delete;
  void operator=(const ConditionMethod &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;
};

// Random 0 to (N-1)
class ConditionRandom : public Condition
{
  typedef Matchers<unsigned int> MatcherType;

public:
  ConditionRandom() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionRandom"); }

  // noncopyable
  ConditionRandom(const ConditionRandom &) = delete;
  void operator=(const ConditionRandom &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  unsigned int _seed = 0;
  unsigned int _max  = 0;
};

// access(file)
class ConditionAccess : public Condition
{
public:
  ConditionAccess() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionAccess"); }

  // noncopyable
  ConditionAccess(const ConditionAccess &) = delete;
  void operator=(const ConditionAccess &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  time_t _next = 0;
  bool _last   = false;
};

// cookie(name)
class ConditionCookie : public Condition
{
  typedef Matchers<std::string> MatcherType;

public:
  ConditionCookie() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionCookie"); }

  // noncopyable
  ConditionCookie(const ConditionCookie &) = delete;
  void operator=(const ConditionCookie &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  // Nginx-style cookie parsing:
  //   nginx/src/http/ngx_http_parse.c:ngx_http_parse_multi_header_lines()
  inline int
  get_cookie_value(const char *buf, int buf_len, const char *name, int name_len, const char **value, int *value_len)
  {
    const char *start, *last, *end;

    // Sanity
    if (buf == nullptr || name == nullptr || value == nullptr || value_len == nullptr) {
      return TS_ERROR;
    }

    start = buf;
    end   = buf + buf_len;

    while (start < end) {
      if (strncasecmp(start, name, name_len) != 0) {
        goto skip;
      }

      for (start += name_len; start < end && *start == ' '; start++) {
      }

      if (start == end || *start++ != '=') {
        goto skip;
      }

      while (start < end && *start == ' ') {
        start++;
      }

      for (last = start; last < end && *last != ';'; last++) {
      }

      *value_len = last - start;
      *value     = start;
      return TS_SUCCESS;
    skip:
      while (start < end) {
        char ch = *start++;
        if (ch == ';' || ch == ',') {
          break;
        }
      }
      while (start < end && *start == ' ') {
        start++;
      }
    }
    return TS_ERROR;
  }
};

// header
class ConditionHeader : public Condition
{
  typedef Matchers<std::string> MatcherType;

public:
  explicit ConditionHeader(bool client = false) : _client(client)
  {
    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionHeader, client %d", client);
  }

  // noncopyable
  ConditionHeader(const ConditionHeader &) = delete;
  void operator=(const ConditionHeader &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  bool _client;
};

// url
class ConditionUrl : public Condition
{
  typedef Matchers<std::string> MatcherType;

public:
  enum UrlType { CLIENT, URL, FROM, TO };

  explicit ConditionUrl(const UrlType type) : _type(type) { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionUrl"); }

  // noncopyable
  ConditionUrl(const ConditionUrl &) = delete;
  void operator=(const ConditionUrl &) = delete;

  void initialize(Parser &p) override;
  void set_qualifier(const std::string &q) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  UrlQualifiers _url_qual = URL_QUAL_NONE;
  UrlType _type;
};

// DBM lookups
class ConditionDBM : public Condition
{
  typedef Matchers<std::string> MatcherType;

public:
  ConditionDBM()
    : //_dbm(NULL),
      _file(""),
      _mutex(TSMutexCreate())
  {
    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionDBM");
  }

  ~ConditionDBM() override
  {
    // if (_dbm) {
    //   mdbm_close(_dbm);
    //   _dbm = NULL;
    // }
  }

  // noncopyable
  ConditionDBM(const ConditionDBM &) = delete;
  void operator=(const ConditionDBM &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  // MDBM* _dbm;
  std::string _file;
  Value _key;
  TSMutex _mutex;
};

class ConditionInternalTxn : public Condition
{
  typedef Matchers<std::string> MatcherType;

public:
  void
  append_value(std::string & /* s ATS_UNUSED */, const Resources & /* res ATS_UNUSED */) override
  {
  }

protected:
  bool eval(const Resources &res) override;
};

class ConditionIp : public Condition
{
  typedef Matchers<std::string> MatcherType;
  typedef Matchers<const sockaddr *> MatcherTypeIp;

public:
  explicit ConditionIp() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionIp"); };

  // noncopyable
  ConditionIp(const ConditionIp &) = delete;
  void operator=(const ConditionIp &) = delete;

  void initialize(Parser &p) override;
  void set_qualifier(const std::string &q) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  IpQualifiers _ip_qual = IP_QUAL_CLIENT;
};

// Transact Count
class ConditionTransactCount : public Condition
{
  typedef Matchers<int> MatcherType;

public:
  ConditionTransactCount() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionTransactCount"); }

  // noncopyable
  ConditionTransactCount(const ConditionTransactCount &) = delete;
  void operator=(const ConditionTransactCount &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;
};

// now: Keeping track of current time / day / hour etc.
class ConditionNow : public Condition
{
  typedef Matchers<int64_t> MatcherType;

public:
  explicit ConditionNow() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionNow"); }

  // noncopyable
  ConditionNow(const ConditionNow &) = delete;
  void operator=(const ConditionNow &) = delete;

  void initialize(Parser &p) override;
  void set_qualifier(const std::string &q) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  int64_t get_now_qualified(NowQualifiers qual) const;
  NowQualifiers _now_qual = NOW_QUAL_EPOCH;
};

// GeoIP class for the "integer" based Geo information pieces
class ConditionGeo : public Condition
{
public:
  explicit ConditionGeo() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionGeo"); }

  // noncopyable
  ConditionGeo(const ConditionGeo &) = delete;
  void operator=(const ConditionGeo &) = delete;

  void initialize(Parser &p) override;
  void set_qualifier(const std::string &q) override;
  void append_value(std::string &s, const Resources &res) override;

  // Make sure we know if the type is an int-type or a string.
  bool
  is_int_type() const
  {
    return _int_type;
  }

  void
  is_int_type(bool flag)
  {
    _int_type = flag;
  }

private:
  virtual int64_t get_geo_int(const sockaddr *addr) const;
  virtual std::string get_geo_string(const sockaddr *addr) const;

protected:
  bool eval(const Resources &res) override;
  GeoQualifiers _geo_qual = GEO_QUAL_COUNTRY;
  bool _int_type          = false;
};

// id: Various identifiers for the requests, server process etc.
class ConditionId : public Condition
{
public:
  explicit ConditionId() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionId"); };

  // noncopyable
  ConditionId(const ConditionId &) = delete;
  void operator=(const ConditionId &) = delete;

  void initialize(Parser &p) override;
  void set_qualifier(const std::string &q) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  IdQualifiers _id_qual = ID_QUAL_UNIQUE;
};

// cidr: A CIDR masked string representation of the Client's IP.
class ConditionCidr : public Condition
{
  using MatcherType = Matchers<std::string>;
  using self        = ConditionCidr;

public:
  explicit ConditionCidr()
  {
    _create_masks(); // This must be called here, because we might not have parameters specified
    TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionCidr");
  };

  ConditionCidr(self &) = delete;
  self &operator=(self &) = delete;

  void initialize(Parser &p) override;
  void set_qualifier(const std::string &q) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;

private:
  void _create_masks();
  int _v4_cidr = 24;
  int _v6_cidr = 48;
  struct in_addr _v4_mask; // We do a 32-bit & using this mask, for efficiency
  unsigned char _v6_mask;  // Only need one byte here, since we memset the rest (see next)
  int _v6_zero_bytes;      // How many initial bytes to memset to 0
};

/// Information about the inbound (client) session.
class ConditionInbound : public Condition
{
  using MatcherType   = Matchers<std::string>;
  using MatcherTypeIp = Matchers<const sockaddr *>;
  using self          = ConditionInbound;

public:
  explicit ConditionInbound() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionInbound"); };
  ConditionInbound(self &) = delete;
  self &operator=(self &) = delete;

  void initialize(Parser &p) override;
  void set_qualifier(const std::string &q) override;
  void append_value(std::string &s, const Resources &res) override;
  static void append_value(std::string &s, const Resources &res, NetworkSessionQualifiers qual);

  static constexpr const char *TAG = "INBOUND";

protected:
  bool eval(const Resources &res) override;

private:
  NetworkSessionQualifiers _net_qual = NET_QUAL_STACK;
};

class ConditionStringLiteral : public Condition
{
  typedef Matchers<std::string> MatcherType;

public:
  explicit ConditionStringLiteral(const std::string &v);

  // noncopyable
  ConditionStringLiteral(const ConditionStringLiteral &) = delete;
  void operator=(const ConditionStringLiteral &) = delete;

  void append_value(std::string &s, const Resources & /* res ATS_UNUSED */) override;

protected:
  bool eval(const Resources & /* res ATS_UNUSED */) override;

private:
  std::string _literal;
};

// Single Session Transaction Count
class ConditionSessionTransactCount : public Condition
{
  typedef Matchers<int> MatcherType;

public:
  ConditionSessionTransactCount() { TSDebug(PLUGIN_NAME_DBG, "ConditionSessionTransactCount()"); }

  // noncopyable
  ConditionSessionTransactCount(const ConditionSessionTransactCount &) = delete;
  void operator=(const ConditionSessionTransactCount &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;
};

// Tcp Info
class ConditionTcpInfo : public Condition
{
  typedef Matchers<int> MatcherType;

public:
  ConditionTcpInfo() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionTcpInfo"); }

  // noncopyable
  ConditionTcpInfo(const ConditionTcpInfo &) = delete;
  void operator=(const ConditionTcpInfo &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;
  void initialize_hooks() override; // Return status only valid in certain hooks
};

// Cache Lookup Results
class ConditionCache : public Condition
{
  using MatcherType = Matchers<std::string>;

public:
  ConditionCache() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionCache"); }

  // noncopyable
  ConditionCache(const ConditionCache &) = delete;
  void operator=(const ConditionCache &) = delete;

  void initialize(Parser &p) override;
  void append_value(std::string &s, const Resources &res) override;

protected:
  bool eval(const Resources &res) override;
};


text:
"""Chromium presubmit script for src/extensions/common.

See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details on the presubmit API built into depot_tools.
"""

import sys

def _CheckExterns(input_api, output_api):
  original_sys_path = sys.path

  join = input_api.os_path.join
  api_root = input_api.PresubmitLocalPath()
  src_root = join(api_root, '..', '..', '..', '..')
  try:
    sys.path.append(join(src_root, 'extensions', 'common', 'api'))
    from externs_checker import ExternsChecker
  finally:
    sys.path = original_sys_path

  externs_root = join(src_root, 'third_party', 'closure_compiler', 'externs')

  api_pair_names = {
    'autofill_private.idl': 'autofill_private.js',
    'developer_private.idl': 'developer_private.js',
    'bookmark_manager_private.json': 'bookmark_manager_private.js',
    'command_line_private.json': 'command_line_private.js',
    'file_manager_private.idl': 'file_manager_private.js',
    'language_settings_private.idl': 'language_settings_private.js',
    'passwords_private.idl': 'passwords_private.js',
    'system_private.json': 'system_private.js',
    'users_private.idl': 'users_private.js',
    # TODO(rdevlin.cronin): Add more!
  }
  normpath = input_api.os_path.normpath
  api_pairs = {
      normpath(join(api_root, k)):
          normpath(join(externs_root, v)) for k, v in api_pair_names.items()
  }

  return ExternsChecker(input_api, output_api, api_pairs).RunChecks()

def CheckChangeOnUpload(input_api, output_api):
  return _CheckExterns(input_api, output_api)


text:
#ifndef NANA_PAINT_IMAGE_PROCESS_INTERFACE_HPP
#define NANA_PAINT_IMAGE_PROCESS_INTERFACE_HPP

#include <nana/basic_types.hpp>
#include <nana/paint/pixel_buffer.hpp>

namespace nana
{
	namespace paint
	{                       /// Image Processing Algorithm Interfaces
		namespace image_process
		{           /// The interface of stretch algorithm.
			class stretch_interface
			{
			public:
				virtual ~stretch_interface() = default;
                    /// Copies the image from a source rectangle into a destination rectangle, stretching or compressing the image to fit the dimensions of the destination rectangle in destination(d_pixbuf).
				virtual void process(const paint::pixel_buffer & s_pixbuf,
                                      const nana::rectangle& source_rectangle,
                                      paint::pixel_buffer & d_pixbuf,
                                      const nana::rectangle& destination_rectangle
                                      ) const = 0;
			};

			class alpha_blend_interface
			{
			public:
				virtual ~alpha_blend_interface() = default;
				virtual void process(const paint::pixel_buffer& s_pixbuf, const nana::rectangle& s_r, paint::pixel_buffer& d_pixbuf, const point& d_pos) const = 0;
			};
                    /// The interface of a blend algorithm.
			class blend_interface
			{
			public:
				virtual ~blend_interface() = default;
                    /// \brief  Blends two images with specified area and blend rate.
                    ///
                    /// Semantics: \code  dest_pixbuf = dest_pixbuf * fade_rate + scr_pixbuf * (1 - fade_rate); \endcode
                    /// The area is always valid, it is calculated by Nana before passing to the algorithm. So the area could be applied without a check.
				virtual void process( const paint::pixel_buffer& src_pixbuf,
                                      const nana::rectangle& src_area,
                                      paint::pixel_buffer& dest_pixbuf,
                                      const nana::point& dest_pos,
                                      double fade_rate              ///< blend rate in the range of [0, 1]
                                      ) const = 0;
			};
                    /// The interface of line algorithm.
			class line_interface
			{
			public:
				virtual ~line_interface() = default;

				    /// \brief   Draws a line
                    ///
                    /// Semantics: \code    pixbuf = pixbuf * (1 - fade_rate) + color * fade_rate    \endcode
                    /// The two points are calculated by Nana, they are always valid, and pos_beg.x <= pos_end.x
				virtual void process(paint::pixel_buffer & pixbuf,
                                      const point& pos_beg,    ///<  left point
                                      const point& pos_end,    ///<  right point
                                      const ::nana::color&,
                                      double fade_rate              ///< blend rate in the range of [0, 1] If not 0, the line is blended to the pixbuf
                                      ) const = 0;
			};

			class blur_interface
			{
			public:
				virtual ~blur_interface() = default;
				virtual void process(paint::pixel_buffer&, const nana::rectangle& r, std::size_t radius) const = 0;
			};
		}
	}//end namespace paint
}//end namespace nana
#endif


text:
import fs from 'fs'
import path from 'path'
import glob from 'glob'
import { assert } from 'chai'
import { transformFileSync } from 'babel-core'
import plugin from '../src/index'

function trim (str) {
  return str.replace(/(\r\n|\n|\r|\t)/gm, '')
}

function createTestName (fixturePath) {
  return path.basename(fixturePath).split('-').join(' ')
}

describe('babel-plugin-react-pug fixture tests', () => {

  const fixturePaths = glob.sync(path.join(__dirname, 'fixtures/*/'))

  fixturePaths.forEach((fixturePath) => {

    const testName = createTestName(fixturePath)
    const actualPath = path.join(fixturePath, 'actual.js')
    const expectedPath = path.join(fixturePath, 'expected.js')

    it(`should transform to react function call(s) from ${ testName }`, () => {

      const expected = fs.readFileSync(expectedPath, 'utf8')
      const actual = transformFileSync(actualPath, {
        'plugins': [ plugin ]
      }).code

      assert.strictEqual(trim(actual), trim(expected))

    })

  })

})

describe('babel-plugin-react-pug error fixture tests', () => {

  const fixturePaths = glob.sync(path.join(__dirname, 'error-fixtures/*/'))

  fixturePaths.forEach((fixturePath) => {

    const testName = createTestName(fixturePath)
    const codePath = path.join(fixturePath, 'code.js')

    it(`should fail when ${ testName }`, () => {

      assert.throws(function() {
        transformFileSync(codePath, { 'plugins': [ plugin ]})
      })

    })

  })

})


text:
import React from "react";
import "./Logo.scss";

const AppLogo = () => {
  return (

          NanUI

  );
};

export default AppLogo;


text:
from unittest import TestCase

from uw_wheniwork.account import Accounts
from uw_wheniwork.util import fdao_wheniwork_override

@fdao_wheniwork_override
class WhenIWorkTestAccounts(TestCase):

    def test_accounts(self):
        wheniwork = Accounts()

        account = wheniwork.get_account()
        self.assertEquals(account.account_id, 11)
        self.assertEquals(account.company, '123 Company')


text:
#include <stdio.h>

#include <iostream>

#include "d3d8imports.hpp"
#include "d3dshader.hpp"
#include "d3dstate.hpp"
#include "json.hpp"

namespace d3dstate {

typedef HRESULT (STDMETHODCALLTYPE IDirect3DDevice8::*GetShaderFunctionMethod)(DWORD Handle, void* pData, DWORD* pSizeOfData);

struct VertexShaderGetter
{
    HRESULT GetShader(IDirect3DDevice8 *pDevice, DWORD *pHandle) {
        return pDevice->GetVertexShader(pHandle);
    }
    HRESULT GetShaderFunction(IDirect3DDevice8 *pDevice, DWORD Handle, void* pData, DWORD* pSizeOfData) {
        return pDevice->GetVertexShaderFunction(Handle, pData, pSizeOfData);
    }
};

struct PixelShaderGetter
{
    HRESULT GetShader(IDirect3DDevice8 *pDevice, DWORD *pHandle) {
        return pDevice->GetPixelShader(pHandle);
    }
    HRESULT GetShaderFunction(IDirect3DDevice8 *pDevice, DWORD Handle, void* pData, DWORD* pSizeOfData) {
        return pDevice->GetPixelShaderFunction(Handle, pData, pSizeOfData);
    }
};

template<class Getter>
inline void
dumpShader(JSONWriter &json, IDirect3DDevice8 *pDevice, const char *name) {
    Getter getter;
    HRESULT hr;

    DWORD dwShader = 0;
    hr = getter.GetShader(pDevice, &dwShader);
    if (FAILED(hr) || !dwShader) {
        return;
    }

    DWORD SizeOfData = 0;

    hr = getter.GetShaderFunction(pDevice, dwShader, NULL, &SizeOfData);
    if (SUCCEEDED(hr)) {
        void *pData;
        pData = malloc(SizeOfData);
        if (pData) {
            hr = getter.GetShaderFunction(pDevice, dwShader, pData, &SizeOfData);
            if (SUCCEEDED(hr)) {
                IDisassemblyBuffer *pDisassembly = NULL;
                hr = DisassembleShader((const DWORD *)pData, &pDisassembly);
                if (SUCCEEDED(hr)) {
                    json.beginMember(name);
                    json.writeString((const char *)pDisassembly->GetBufferPointer() /*, pDisassembly->GetBufferSize() */);
                    json.endMember();
                    pDisassembly->Release();
                }

            }
            free(pData);
        }
    }
}

static void
dumpShaders(JSONWriter &json, IDirect3DDevice8 *pDevice)
{
    json.beginMember("shaders");
    json.beginObject();

    dumpShader<VertexShaderGetter>(json, pDevice, "vertex");
    dumpShader<PixelShaderGetter>(json, pDevice, "pixel");

    json.endObject();
    json.endMember(); // shaders
}

void
dumpDevice(std::ostream &os, IDirect3DDevice8 *pDevice)
{
    JSONWriter json(os);

    /* TODO */
    json.beginMember("parameters");
    json.beginObject();
    json.endObject();
    json.endMember(); // parameters

    dumpShaders(json, pDevice);

    json.beginMember("textures");
    json.beginObject();
    json.endObject();
    json.endMember(); // textures

    dumpFramebuffer(json, pDevice);
}

} /* namespace d3dstate */


text:
![](grouped_stacked_full.png)

Example:

```
/// Example of a bar chart with grouped, stacked series oriented vertically.
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;

class GroupedStackedBarChart extends StatelessWidget {
  final List<charts.Series> seriesList;
  final bool animate;

  GroupedStackedBarChart(this.seriesList, {this.animate});

  factory GroupedStackedBarChart.withSampleData() {
    return new GroupedStackedBarChart(
      createSampleData(),
      // Disable animations for image tests.
      animate: false,
    );
  }

  @override
  Widget build(BuildContext context) {
    return new charts.BarChart(
      seriesList,
      animate: animate,
      barGroupingType: charts.BarGroupingType.groupedStacked,
    );
  }

  /// Create series list with multiple series
  static List<charts.Series<OrdinalSales, String>> createSampleData() {
    final desktopSalesDataA = [
      new OrdinalSales('2014', 5),
      new OrdinalSales('2015', 25),
      new OrdinalSales('2016', 100),
      new OrdinalSales('2017', 75),
    ];

    final tableSalesDataA = [
      new OrdinalSales('2014', 25),
      new OrdinalSales('2015', 50),
      new OrdinalSales('2016', 10),
      new OrdinalSales('2017', 20),
    ];

    final mobileSalesDataA = [
      new OrdinalSales('2014', 10),
      new OrdinalSales('2015', 15),
      new OrdinalSales('2016', 50),
      new OrdinalSales('2017', 45),
    ];

    final desktopSalesDataB = [
      new OrdinalSales('2014', 5),
      new OrdinalSales('2015', 25),
      new OrdinalSales('2016', 100),
      new OrdinalSales('2017', 75),
    ];

    final tableSalesDataB = [
      new OrdinalSales('2014', 25),
      new OrdinalSales('2015', 50),
      new OrdinalSales('2016', 10),
      new OrdinalSales('2017', 20),
    ];

    final mobileSalesDataB = [
      new OrdinalSales('2014', 10),
      new OrdinalSales('2015', 15),
      new OrdinalSales('2016', 50),
      new OrdinalSales('2017', 45),
    ];

    return [
      new charts.Series<OrdinalSales, String>(
        id: 'Desktop A',
        seriesCategory: 'A',
        domainFn: (OrdinalSales sales, _) => sales.year,
        measureFn: (OrdinalSales sales, _) => sales.sales,
        data: desktopSalesDataA,
      ),
      new charts.Series<OrdinalSales, String>(
        id: 'Tablet A',
        seriesCategory: 'A',
        domainFn: (OrdinalSales sales, _) => sales.year,
        measureFn: (OrdinalSales sales, _) => sales.sales,
        data: tableSalesDataA,
      ),
      new charts.Series<OrdinalSales, String>(
        id: 'Mobile A',
        seriesCategory: 'A',
        domainFn: (OrdinalSales sales, _) => sales.year,
        measureFn: (OrdinalSales sales, _) => sales.sales,
        data: mobileSalesDataA,
      ),
      new charts.Series<OrdinalSales, String>(
        id: 'Desktop B',
        seriesCategory: 'B',
        domainFn: (OrdinalSales sales, _) => sales.year,
        measureFn: (OrdinalSales sales, _) => sales.sales,
        data: desktopSalesDataB,
      ),
      new charts.Series<OrdinalSales, String>(
        id: 'Tablet B',
        seriesCategory: 'B',
        domainFn: (OrdinalSales sales, _) => sales.year,
        measureFn: (OrdinalSales sales, _) => sales.sales,
        data: tableSalesDataB,
      ),
      new charts.Series<OrdinalSales, String>(
        id: 'Mobile B',
        seriesCategory: 'B',
        domainFn: (OrdinalSales sales, _) => sales.year,
        measureFn: (OrdinalSales sales, _) => sales.sales,
        data: mobileSalesDataB,
      ),
    ];
  }
}

/// Sample ordinal data type.
class OrdinalSales {
  final String year;
  final int sales;

  OrdinalSales(this.year, this.sales);
}
```