text:
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*  Fluent Bit
 *  ==========
 *  Copyright (C) 2015-2022 The Fluent Bit Authors
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <fluent-bit/flb_info.h>
#include <fluent-bit/flb_filter.h>
#include <fluent-bit/flb_filter_plugin.h>
#include <fluent-bit/flb_mem.h>
#include <fluent-bit/flb_kv.h>
#include <fluent-bit/flb_str.h>
#include <fluent-bit/flb_utils.h>
#include <fluent-bit/flb_pack.h>
#include <fluent-bit/flb_regex.h>
#include <fluent-bit/flb_sds.h>
#include <fluent-bit/flb_record_accessor.h>
#include <fluent-bit/flb_ra_key.h>
#include <msgpack.h>

#include "modify.h"

#include <stdio.h>
#include <sys/types.h>

static void condition_free(struct modify_condition *condition)
{
    flb_sds_destroy(condition->a);
    flb_free(condition->b);
    flb_free(condition->raw_k);
    flb_free(condition->raw_v);

    if (condition->a_is_regex) {
        flb_regex_destroy(condition->a_regex);
    }
    if (condition->b_is_regex) {
        flb_regex_destroy(condition->b_regex);
    }
    if (condition->ra_a) {
        flb_ra_destroy(condition->ra_a);
        condition->ra_a = NULL;
    }
    flb_free(condition);
}

static void teardown(struct filter_modify_ctx *ctx)
{
    struct mk_list *tmp;
    struct mk_list *head;

    struct modify_rule *rule;
    struct modify_condition *condition;

    mk_list_foreach_safe(head, tmp, &ctx->conditions) {
        condition = mk_list_entry(head, struct modify_condition, _head);
        mk_list_del(&condition->_head);
        condition_free(condition);
    }

    mk_list_foreach_safe(head, tmp, &ctx->rules) {
        rule = mk_list_entry(head, struct modify_rule, _head);
        flb_free(rule->key);
        flb_free(rule->val);
        flb_free(rule->raw_k);
        flb_free(rule->raw_v);
        flb_regex_destroy(rule->key_regex);
        flb_regex_destroy(rule->val_regex);
        mk_list_del(&rule->_head);
        flb_free(rule);
    }
}

static void helper_pack_string(struct filter_modify_ctx *ctx,
                               msgpack_packer *packer, const char *str,
                               int len)
{

    if (str == NULL) {
        flb_plg_error(ctx->ins, "helper_pack_string : NULL passed");
        msgpack_pack_nil(packer);
    }
    else {
        msgpack_pack_str(packer, len);
        msgpack_pack_str_body(packer, str, len);
    }
}

static int setup(struct filter_modify_ctx *ctx,
                 struct flb_filter_instance *f_ins, struct flb_config *config)
{
    struct mk_list *head;
    struct mk_list *split;
    struct flb_kv *kv;
    struct flb_split_entry *sentry;
    struct modify_rule *rule = NULL;
    struct modify_condition *condition;

    int list_size;

    // Split list
    // - Arg 1 is condition?
    // --> Setup Condition
    //   - Malloc Condition
    //   - Switch list size
    // --> Setup Rule
    //   - Malloc Rule
    //   - Switch list size

    if (flb_filter_config_map_set(f_ins, ctx) < 0) {
        flb_errno();
        flb_plg_error(f_ins, "configuration error");
        return -1;
    }

    mk_list_foreach(head, &f_ins->properties) {
        kv = mk_list_entry(head, struct flb_kv, _head);

        split = flb_utils_split(kv->val, ' ', 3);
        list_size = mk_list_size(split);

        // Conditions are,
        // CONDITION CONDITIONTYPE VAL_A VAL_B

        if (list_size == 0 || list_size > 3) {
            flb_plg_error(ctx->ins, "Invalid config for %s", kv->key);
            teardown(ctx);
            flb_utils_split_free(split);
            return -1;
        }
        else if (strcasecmp(kv->key, "condition") == 0) {

            //
            // Build a condition
            //

            condition = flb_calloc(1, sizeof(struct modify_condition));
            if (!condition) {
                flb_errno();
                flb_plg_error(ctx->ins, "Unable to allocate memory for "
                              "condition");
                teardown(ctx);
                flb_utils_split_free(split);
                return -1;
            }

            condition->a_is_regex = false;
            condition->b_is_regex = false;
            condition->ra_a = NULL;
            condition->raw_k = flb_strndup(kv->key, flb_sds_len(kv->key));
            if (condition->raw_k == NULL) {
                flb_errno();
                flb_plg_error(ctx->ins, "Unable to allocate memory for "
                              "condition->raw_k");
                teardown(ctx);
                condition_free(condition);
                flb_utils_split_free(split);
                return -1;
            }
            condition->raw_v = flb_strndup(kv->val, flb_sds_len(kv->val));
            if (condition->raw_v == NULL) {
                flb_errno();
                flb_plg_error(ctx->ins, "Unable to allocate memory for "
                              "condition->raw_v");
                teardown(ctx);
                condition_free(condition);
                flb_utils_split_free(split);
                return -1;
            }

            sentry =
                mk_list_entry_first(split, struct flb_split_entry, _head);

            if (strcasecmp(sentry->value, "key_exists") == 0) {
                condition->conditiontype = KEY_EXISTS;
            }
            else if (strcasecmp(sentry->value, "key_does_not_exist") == 0) {
                condition->conditiontype = KEY_DOES_NOT_EXIST;
            }
            else if (strcasecmp(sentry->value, "a_key_matches") == 0) {
                condition->conditiontype = A_KEY_MATCHES;
                condition->a_is_regex = true;
            }
            else if (strcasecmp(sentry->value, "no_key_matches") == 0) {
                condition->conditiontype = NO_KEY_MATCHES;
                condition->a_is_regex = true;
            }
            else if (strcasecmp(sentry->value, "key_value_equals") == 0) {
                condition->conditiontype = KEY_VALUE_EQUALS;
            }
            else if (strcasecmp(sentry->value, "key_value_does_not_equal") ==
                     0) {
                condition->conditiontype = KEY_VALUE_DOES_NOT_EQUAL;
            }
            else if (strcasecmp(sentry->value, "key_value_matches") == 0) {
                condition->conditiontype = KEY_VALUE_MATCHES;
                condition->b_is_regex = true;
            }
            else if (strcasecmp(sentry->value, "key_value_does_not_match") ==
                     0) {
                condition->conditiontype = KEY_VALUE_DOES_NOT_MATCH;
                condition->b_is_regex = true;
            }
            else if (strcasecmp
                     (sentry->value,
                      "matching_keys_have_matching_values") == 0) {
                condition->conditiontype = MATCHING_KEYS_HAVE_MATCHING_VALUES;
                condition->a_is_regex = true;
                condition->b_is_regex = true;
            }
            else if (strcasecmp
                     (sentry->value,
                      "matching_keys_do_not_have_matching_values") == 0) {
                condition->conditiontype =
                    MATCHING_KEYS_DO_NOT_HAVE_MATCHING_VALUES;
                condition->a_is_regex = true;
                condition->b_is_regex = true;
            }
            else {
                flb_plg_error(ctx->ins, "Invalid config for %s : %s",
                              kv->key, kv->val);
                teardown(ctx);
                condition_free(condition);
                flb_utils_split_free(split);
                return -1;
            }

            sentry =
                mk_list_entry_next(&sentry->_head, struct flb_split_entry,
                                   _head, split);
            condition->a = flb_sds_create_len(sentry->value, sentry->len);
            condition->a_len = sentry->len;
            condition->ra_a = flb_ra_create(condition->a, FLB_FALSE);
            if (list_size == 3) {
                sentry =
                    mk_list_entry_last(split, struct flb_split_entry, _head);
                condition->b = flb_strndup(sentry->value, sentry->len);
                if (condition->b == NULL) {
                    flb_errno();
                    flb_plg_error(ctx->ins, "Unable to allocate memory for "
                                  "condition->b");
                    teardown(ctx);
                    condition_free(condition);
                    flb_utils_split_free(split);
                    return -1;
                }
                condition->b_len = sentry->len;
            }
            else {
                condition->b = NULL;
                condition->b_len = 0;
            }

            if (condition->a_is_regex) {
                if (condition->a_len < 1) {
                    flb_plg_error(ctx->ins, "Unable to create regex for "
                                  "condition %s %s",
                                  condition->raw_k, condition->raw_v);
                    condition_free(condition);
                    flb_utils_split_free(split);
                    return -1;
                }
                else {
                    flb_plg_debug(ctx->ins, "Creating regex for condition A : "
                                  "%s %s : %s",
                                  condition->raw_k, condition->raw_v,
                                  condition->a);
                    condition->a_regex =
                        flb_regex_create(condition->a);
                }
            }

            if (condition->b_is_regex) {
                if (condition->b_len < 1) {
                    flb_plg_error(ctx->ins, "Unable to create regex "
                                  "for condition %s %s",
                                  condition->raw_k, condition->raw_v);
                    condition_free(condition);
                    flb_utils_split_free(split);
                    return -1;
                }
                else {
                    flb_plg_debug(ctx->ins, "Creating regex for condition B : %s "
                                  "%s : %s",
                                  condition->raw_k, condition->raw_v, condition->b);
                    condition->b_regex =
                        flb_regex_create(condition->b);
                }
            }

            flb_utils_split_free(split);

            mk_list_add(&condition->_head, &ctx->conditions);
            ctx->conditions_cnt++;
        }
        else {

            //
            // Build a rule
            //

            rule = flb_malloc(sizeof(struct modify_rule));
            if (!rule) {
                flb_plg_error(ctx->ins, "Unable to allocate memory for rule");
                teardown(ctx);
                flb_utils_split_free(split);
                return -1;
            }

            rule->key_is_regex = false;
            rule->val_is_regex = false;
            rule->raw_k = flb_strndup(kv->key, flb_sds_len(kv->key));
            if (rule->raw_k == NULL) {
                flb_errno();
                flb_plg_error(ctx->ins, "Unable to allocate memory for rule->raw_k");
                teardown(ctx);
                flb_free(rule);
                flb_utils_split_free(split);
                return -1;
            }
            rule->raw_v = flb_strndup(kv->val, flb_sds_len(kv->val));
            if (rule->raw_v == NULL) {
                flb_errno();
                flb_plg_error(ctx->ins, "Unable to allocate memory for rule->raw_v");
                teardown(ctx);
                flb_free(rule->raw_k);
                flb_free(rule);
                flb_utils_split_free(split);
                return -1;
            }

            sentry =
                mk_list_entry_first(split, struct flb_split_entry, _head);
            rule->key = flb_strndup(sentry->value, sentry->len);
            if (rule->key == NULL) {
                flb_errno();
                flb_plg_error(ctx->ins, "Unable to allocate memory for rule->key");
                teardown(ctx);
                flb_free(rule->raw_v);
                flb_free(rule->raw_k);
                flb_free(rule);
                flb_utils_split_free(split);
                return -1;
            }
            rule->key_len = sentry->len;

            sentry = mk_list_entry_last(split, struct flb_split_entry, _head);
            rule->val = flb_strndup(sentry->value, sentry->len);
            if (rule->val == NULL) {
                flb_errno();
                flb_plg_error(ctx->ins, "Unable to allocate memory for rule->val");
                teardown(ctx);
                flb_free(rule->key);
                flb_free(rule->raw_v);
                flb_free(rule->raw_k);
                flb_free(rule);
                flb_utils_split_free(split);
                return -1;
            }
            rule->val_len = sentry->len;

            flb_utils_split_free(split);

            if (list_size == 1) {
                if (strcasecmp(kv->key, "remove") == 0) {
                    rule->ruletype = REMOVE;
                }
                else if (strcasecmp(kv->key, "remove_wildcard") == 0) {
                    rule->ruletype = REMOVE_WILDCARD;
                }
                else if (strcasecmp(kv->key, "remove_regex") == 0) {
                    rule->ruletype = REMOVE_REGEX;
                    rule->key_is_regex = true;
                }
                else if (strcasecmp(kv->key, "move_to_start") == 0) {
                    rule->ruletype = MOVE_TO_START;
                }
                else if (strcasecmp(kv->key, "move_to_end") == 0) {
                    rule->ruletype = MOVE_TO_END;
                }
                else {
                    flb_plg_error(ctx->ins, "Invalid operation %s : %s in "
                                  "configuration", kv->key, kv->val);
                    teardown(ctx);
                    flb_free(rule);
                    return -1;
                }
            }
            else if (list_size == 2) {
                if (strcasecmp(kv->key, "rename") == 0) {
                    rule->ruletype = RENAME;
                }
                else if (strcasecmp(kv->key, "hard_rename") == 0) {
                    rule->ruletype = HARD_RENAME;
                }
                else if (strcasecmp(kv->key, "add") == 0) {
                    rule->ruletype = ADD;
                }
                else if (strcasecmp(kv->key, "add_if_not_present") == 0) {
                    flb_plg_info(ctx->ins, "DEPRECATED : Operation "
                                 "'add_if_not_present' has been replaced "
                                 "by 'add'.");
                    rule->ruletype = ADD;
                }
                else if (strcasecmp(kv->key, "set") == 0) {
                    rule->ruletype = SET;
                }
                else if (strcasecmp(kv->key, "copy") == 0) {
                    rule->ruletype = COPY;
                }
                else if (strcasecmp(kv->key, "hard_copy") == 0) {
                    rule->ruletype = HARD_COPY;
                }
                else {
                    flb_plg_error(ctx->ins, "Invalid operation %s : %s in "
                                  "configuration", kv->key, kv->val);
                    teardown(ctx);
                    flb_free(rule);
                    return -1;
                }
            }

            if (rule->key_is_regex && rule->key_len == 0) {
                flb_plg_error(ctx->ins, "Unable to create regex for rule %s %s",
                              rule->raw_k, rule->raw_v);
                teardown(ctx);
                flb_free(rule);
                return -1;
            }
            else {
                rule->key_regex =
                    flb_regex_create(rule->key);
            }

            if (rule->val_is_regex && rule->val_len == 0) {
                flb_plg_error(ctx->ins, "Unable to create regex for rule %s %s",
                              rule->raw_k, rule->raw_v);
                return -1;
            }
            else {
                rule->val_regex =
                    flb_regex_create(rule->val);
            }

            mk_list_add(&rule->_head, &ctx->rules);
            ctx->rules_cnt++;
        }

    }

    flb_plg_debug(ctx->ins, "Initialized modify filter with %d conditions "
                  "and %d rules",
                  ctx->conditions_cnt, ctx->rules_cnt);
    return 0;
}

/* Regex matchers */
static inline bool helper_msgpack_object_matches_regex(msgpack_object * obj,
                                                       struct flb_regex
                                                       *regex)
{
    int len;
    const char *key;

    if (obj->type == MSGPACK_OBJECT_BIN) {
        return false;
    }
    else if (obj->type == MSGPACK_OBJECT_STR) {
        key = obj->via.str.ptr;
        len = obj->via.str.size;
    }
    else {
        return false;
    }

    return flb_regex_match(regex, (unsigned char *) key, len) > 0;
}

static inline bool kv_key_matches_regex(msgpack_object_kv * kv,
                                        struct flb_regex *regex)
{
    return helper_msgpack_object_matches_regex(&kv->key, regex);
}

static inline bool kv_val_matches_regex(msgpack_object_kv * kv,
                                        struct flb_regex *regex)
{
    return helper_msgpack_object_matches_regex(&kv->val, regex);
}

static inline bool kv_key_matches_regex_rule_key(msgpack_object_kv * kv,
                                                 struct modify_rule *rule)
{
    return kv_key_matches_regex(kv, rule->key_regex);
}

static inline bool kv_key_does_not_match_regex_rule_key(msgpack_object_kv *
                                                        kv,
                                                        struct modify_rule
                                                        *rule)
{
    return !kv_key_matches_regex_rule_key(kv, rule);
}

static inline int map_count_keys_matching_regex(msgpack_object * map,
                                                struct flb_regex *regex)
{
    int i;
    int count = 0;

    for (i = 0; i < map->via.map.size; i++) {
        if (kv_key_matches_regex(&map->via.map.ptr[i], regex)) {
            count++;
        }
    }
    return count;
}

/*
 * Wildcard matchers
 */

static inline bool helper_msgpack_object_matches_wildcard(msgpack_object *
                                                          obj, char *str,
                                                          int len)
{
    const char *key;

    if (obj->type == MSGPACK_OBJECT_BIN) {
        key = obj->via.bin.ptr;
    }
    else if (obj->type == MSGPACK_OBJECT_STR) {
        key = obj->via.str.ptr;
    }
    else {
        return false;
    }

    return (strncmp(str, key, len) == 0);
}

static inline bool kv_key_matches_wildcard(msgpack_object_kv * kv,
                                           char *str, int len)
{
    return helper_msgpack_object_matches_wildcard(&kv->key, str, len);
}

static inline bool kv_key_matches_wildcard_rule_key(msgpack_object_kv * kv,
                                                    struct modify_rule *rule)
{
    return kv_key_matches_wildcard(kv, rule->key, rule->key_len);
}

static inline bool kv_key_does_not_match_wildcard_rule_key(msgpack_object_kv *
                                                           kv,
                                                           struct modify_rule
                                                           *rule)
{
    return !kv_key_matches_wildcard_rule_key(kv, rule);
}

static inline int map_count_keys_matching_wildcard(msgpack_object * map,
                                                   char *str, int len)
{
    int i;
    int count = 0;

    for (i = 0; i < map->via.map.size; i++) {
        if (kv_key_matches_wildcard(&map->via.map.ptr[i], str, len)) {
            count++;
        }
    }
    return count;
}

//
// String matchers
//

static inline bool helper_msgpack_object_matches_str(msgpack_object * obj,
                                                     char *str, int len)
{

    const char *key;
    int klen;

    if (obj->type == MSGPACK_OBJECT_BIN) {
        key = obj->via.bin.ptr;
        klen = obj->via.bin.size;
    }
    else if (obj->type == MSGPACK_OBJECT_STR) {
        key = obj->via.str.ptr;
        klen = obj->via.str.size;
    }
    else {
        return false;
    }

    return ((len == klen) && (strncmp(str, key, klen) == 0)
        );
}

static inline bool kv_key_matches_str(msgpack_object_kv * kv,
                                      char *str, int len)
{
    return helper_msgpack_object_matches_str(&kv->key, str, len);
}

static inline bool kv_val_matches_str(msgpack_object_kv * kv,
                                      char *str, int len)
{
    return helper_msgpack_object_matches_str(&kv->val, str, len);
}

static inline bool kv_key_matches_str_rule_key(msgpack_object_kv * kv,
                                               struct modify_rule *rule)
{
    return kv_key_matches_str(kv, rule->key, rule->key_len);
}

static inline bool kv_key_does_not_match_str_rule_key(msgpack_object_kv * kv,
                                                      struct modify_rule
                                                      *rule)
{
    return !kv_key_matches_str_rule_key(kv, rule);
}

static inline bool kv_key_matches_str_rule_val(msgpack_object_kv * kv,
                                               struct modify_rule *rule)
{
    return kv_key_matches_str(kv, rule->val, rule->val_len);
}

static inline int map_count_keys_matching_str(msgpack_object * map,
                                              char *str, int len)
{
    int i;
    int count = 0;

    for (i = 0; i < map->via.map.size; i++) {
        if (kv_key_matches_str(&map->via.map.ptr[i], str, len)) {
            count++;
        }
    }
    return count;
}

static inline void map_pack_each(msgpack_packer * packer,
                                 msgpack_object * map)
{
    int i;

    for (i = 0; i < map->via.map.size; i++) {
        msgpack_pack_object(packer, map->via.map.ptr[i].key);
        msgpack_pack_object(packer, map->via.map.ptr[i].val);
    }
}

static inline void map_pack_each_fn(msgpack_packer * packer,
                                    msgpack_object * map,
                                    struct modify_rule *rule,
                                    bool(*f) (msgpack_object_kv * kv,
                                              struct modify_rule * rule)
    )
{
    int i;

    for (i = 0; i < map->via.map.size; i++) {
        if ((*f) (&map->via.map.ptr[i], rule)) {
            msgpack_pack_object(packer, map->via.map.ptr[i].key);
            msgpack_pack_object(packer, map->via.map.ptr[i].val);
        }
    }
}

static inline bool evaluate_condition_KEY_EXISTS(msgpack_object * map,
                                                 struct modify_condition
                                                 *condition)
{
    msgpack_object *skey = NULL;
    msgpack_object *okey = NULL;
    msgpack_object *oval = NULL;

    flb_ra_get_kv_pair(condition->ra_a, *map, &skey, &okey, &oval);
    if (skey == NULL || okey == NULL || oval == NULL) {
        return false;
    }
    return true;
}

static inline bool evaluate_condition_KEY_DOES_NOT_EXIST(msgpack_object * map,
                                                         struct
                                                         modify_condition
                                                         *condition)
{
    return !evaluate_condition_KEY_EXISTS(map, condition);
}

static inline bool evaluate_condition_A_KEY_MATCHES(msgpack_object * map,
                                                    struct modify_condition
                                                    *condition)
{
    return (map_count_keys_matching_regex(map, condition->a_regex) > 0);
}

static inline bool evaluate_condition_NO_KEY_MATCHES(msgpack_object * map,
                                                     struct
                                                     modify_condition
                                                     *condition)
{
    return !evaluate_condition_A_KEY_MATCHES(map, condition);
}

static inline bool evaluate_condition_KEY_VALUE_EQUALS(struct filter_modify_ctx *ctx,
                                                       msgpack_object * map,
                                                       struct
                                                       modify_condition
                                                       *condition)
{
    msgpack_object *skey = NULL;
    msgpack_object *okey = NULL;
    msgpack_object *oval = NULL;
    bool ret = false;

    flb_ra_get_kv_pair(condition->ra_a, *map, &skey, &okey, &oval);
    if (skey == NULL || okey == NULL || oval == NULL) {
        return false;
    }
    ret = helper_msgpack_object_matches_str(oval, condition->b, condition->b_len);
    if (ret) {
        flb_plg_debug(ctx->ins, "Match for condition KEY_VALUE_EQUALS %s",
                      condition->b);
    }
    return ret;
}

static inline
bool evaluate_condition_KEY_VALUE_DOES_NOT_EQUAL(struct filter_modify_ctx *ctx,
                                                 msgpack_object
                                                 *map,
                                                 struct
                                                 modify_condition
                                                 *condition)
{
    if (!evaluate_condition_KEY_EXISTS(map, condition)) {
        return false;
    }
    return !evaluate_condition_KEY_VALUE_EQUALS(ctx, map, condition);
}

static inline bool evaluate_condition_KEY_VALUE_MATCHES(struct filter_modify_ctx *ctx,
                                                        msgpack_object *map,
                                                        struct
                                                        modify_condition
                                                        *condition)
{
    msgpack_object *skey = NULL;
    msgpack_object *okey = NULL;
    msgpack_object *oval = NULL;
    bool ret = false;

    flb_ra_get_kv_pair(condition->ra_a, *map, &skey, &okey, &oval);
    if (skey == NULL || okey == NULL || oval == NULL) {
        return false;
    }
    ret = helper_msgpack_object_matches_regex(oval, condition->b_regex);
    if (ret) {
        flb_plg_debug(ctx->ins, "Match for condition KEY_VALUE_MATCHES "
                      "%s", condition->b);
    }
    return ret;
}

static inline
bool evaluate_condition_KEY_VALUE_DOES_NOT_MATCH(struct filter_modify_ctx *ctx,
                                                 msgpack_object
                                                 * map,
                                                 struct
                                                 modify_condition
                                                 *condition)
{
    if (!evaluate_condition_KEY_EXISTS(map, condition)) {
        return false;
    }
    return !evaluate_condition_KEY_VALUE_MATCHES(ctx, map, condition);
}

static inline bool
evaluate_condition_MATCHING_KEYS_HAVE_MATCHING_VALUES(struct filter_modify_ctx *ctx,
                                                      msgpack_object *map,
                                                      struct modify_condition
                                                      *condition)
{
    int i;
    bool match = true;
    msgpack_object_kv *kv;

    for (i = 0; i < map->via.map.size; i++) {
        kv = &map->via.map.ptr[i];
        if (kv_key_matches_regex(kv, condition->a_regex)) {
            if (!kv_val_matches_regex(kv, condition->b_regex)) {
                flb_plg_debug(ctx->ins, "Match MISSED for condition "
                              "MATCHING_KEYS_HAVE_MATCHING_VALUES %s",
                              condition->b);
                match = false;
                break;
            }
        }
    }
    return match;
}

static inline bool
evaluate_condition_MATCHING_KEYS_DO_NOT_HAVE_MATCHING_VALUES(struct filter_modify_ctx *ctx,
                                                             msgpack_object *
                                                             map,
                                                             struct
                                                             modify_condition
                                                             *condition)
{
    return !evaluate_condition_MATCHING_KEYS_HAVE_MATCHING_VALUES(ctx,
                                                                  map,
                                                                  condition);
}

static inline bool evaluate_condition(struct filter_modify_ctx *ctx,
                                      msgpack_object * map,
                                      struct modify_condition *condition)
{
    switch (condition->conditiontype) {
    case KEY_EXISTS:
        return evaluate_condition_KEY_EXISTS(map, condition);
    case KEY_DOES_NOT_EXIST:
        return evaluate_condition_KEY_DOES_NOT_EXIST(map, condition);
    case A_KEY_MATCHES:
        return evaluate_condition_A_KEY_MATCHES(map, condition);
    case NO_KEY_MATCHES:
        return evaluate_condition_NO_KEY_MATCHES(map, condition);
    case KEY_VALUE_EQUALS:
        return evaluate_condition_KEY_VALUE_EQUALS(ctx, map, condition);
    case KEY_VALUE_DOES_NOT_EQUAL:
        return evaluate_condition_KEY_VALUE_DOES_NOT_EQUAL(ctx, map, condition);
    case KEY_VALUE_MATCHES:
        return evaluate_condition_KEY_VALUE_MATCHES(ctx, map, condition);
    case KEY_VALUE_DOES_NOT_MATCH:
        return evaluate_condition_KEY_VALUE_DOES_NOT_MATCH(ctx, map, condition);
    case MATCHING_KEYS_HAVE_MATCHING_VALUES:
        return evaluate_condition_MATCHING_KEYS_HAVE_MATCHING_VALUES(ctx,
                                                                     map,
                                                                     condition);
    case MATCHING_KEYS_DO_NOT_HAVE_MATCHING_VALUES:
        return
            evaluate_condition_MATCHING_KEYS_DO_NOT_HAVE_MATCHING_VALUES(ctx,
                                                                         map,
                                                                         condition);
    default:
        flb_plg_warn(ctx->ins, "Unknown conditiontype for condition %s : %s, "
                     "assuming result FAILED TO MEET CONDITION",
                     condition->raw_k, condition->raw_v);
    }
    return false;
}

static inline bool evaluate_conditions(msgpack_object * map,
                                       struct filter_modify_ctx *ctx)
{
    bool ok = true;

    struct mk_list *tmp;
    struct mk_list *head;
    struct modify_condition *condition;

    mk_list_foreach_safe(head, tmp, &ctx->conditions) {
        condition = mk_list_entry(head, struct modify_condition, _head);
        if (!evaluate_condition(ctx, map, condition)) {
            flb_plg_debug(ctx->ins, "Condition not met : %s",
                          condition->raw_v);
            ok = false;
        }
    }

    return ok;
}

static inline int apply_rule_RENAME(struct filter_modify_ctx *ctx,
                                    msgpack_packer *packer,
                                    msgpack_object *map,
                                    struct modify_rule *rule)
{
    int i;

    int match_keys =
        map_count_keys_matching_str(map, rule->key, rule->key_len);
    int conflict_keys =
        map_count_keys_matching_str(map, rule->val, rule->val_len);

    if (match_keys == 0) {
        flb_plg_debug(ctx->ins, "Rule RENAME %s TO %s : No keys matching %s "
                      "found, not applying rule",
                      rule->key, rule->val, rule->key);
        return FLB_FILTER_NOTOUCH;
    }
    else if (conflict_keys > 0) {
        flb_plg_debug(ctx->ins, "Rule RENAME %s TO %s : Existing key %s found, "
                      "not applying rule",
                      rule->key, rule->val, rule->key);
        return FLB_FILTER_NOTOUCH;
    }
    else {
        msgpack_pack_map(packer, map->via.map.size);
        for (i = 0; i < map->via.map.size; i++) {
            if (kv_key_matches_str_rule_key(&map->via.map.ptr[i], rule)) {
                helper_pack_string(ctx, packer, rule->val, rule->val_len);
            }
            else {
                msgpack_pack_object(packer, map->via.map.ptr[i].key);
            }
            msgpack_pack_object(packer, map->via.map.ptr[i].val);
        }
        return FLB_FILTER_MODIFIED;
    }
}

static inline int apply_rule_HARD_RENAME(struct filter_modify_ctx *ctx,
                                         msgpack_packer *packer,
                                         msgpack_object *map,
                                         struct modify_rule *rule)
{
    int i;

    int match_keys =
        map_count_keys_matching_str(map, rule->key, rule->key_len);
    int conflict_keys =
        map_count_keys_matching_str(map, rule->val, rule->val_len);
    msgpack_object_kv *kv;

    if (match_keys == 0) {
        flb_plg_debug(ctx->ins, "Rule HARD_RENAME %s TO %s : No keys matching "
                      "%s found, not applying rule",
                      rule->key, rule->val, rule->key);
        return FLB_FILTER_NOTOUCH;
    }
    else if (conflict_keys == 0) {
        msgpack_pack_map(packer, map->via.map.size);
        for (i = 0; i < map->via.map.size; i++) {
            kv = &map->via.map.ptr[i];
            if (kv_key_matches_str_rule_key(kv, rule)) {
                helper_pack_string(ctx, packer, rule->val, rule->val_len);
            }
            else {
                msgpack_pack_object(packer, kv->key);
            }
            msgpack_pack_object(packer, kv->val);
        }
        return FLB_FILTER_MODIFIED;
    }
    else {
        msgpack_pack_map(packer, map->via.map.size - conflict_keys);

        for (i = 0; i < map->via.map.size; i++) {
            kv = &map->via.map.ptr[i];
            // If this kv->key matches rule->val it's a conflict source key and
            // will be skipped
            if (!kv_key_matches_str_rule_val(kv, rule)) {
                if (kv_key_matches_str_rule_key(kv, rule)) {
                    helper_pack_string(ctx, packer, rule->val, rule->val_len);
                }
                else {
                    msgpack_pack_object(packer, kv->key);
                }

                msgpack_pack_object(packer, kv->val);
            }
        }
        return FLB_FILTER_MODIFIED;
    }
}

static inline int apply_rule_COPY(struct filter_modify_ctx *ctx,
                                  msgpack_packer *packer,
                                  msgpack_object *map,
                                  struct modify_rule *rule)
{
    int match_keys =
        map_count_keys_matching_str(map, rule->key, rule->key_len);
    int conflict_keys =
        map_count_keys_matching_str(map, rule->val, rule->val_len);
    int i;
    msgpack_object_kv *kv;

    if (match_keys < 1) {
        flb_plg_debug(ctx->ins, "Rule COPY %s TO %s : No keys matching %s "
                      "found, not applying rule",
                      rule->key, rule->val, rule->key);
        return FLB_FILTER_NOTOUCH;
    }
    else if (match_keys > 1) {
        flb_plg_debug(ctx->ins, "Rule COPY %s TO %s : Multiple keys matching "
                      "%s found, not applying rule",
                      rule->key, rule->val, rule->key);
        return FLB_FILTER_NOTOUCH;
    }
    else if (conflict_keys > 0) {
        flb_plg_debug(ctx->ins, "Rule COPY %s TO %s : Existing keys matching "
                      "target %s found, not applying rule",
                      rule->key, rule->val, rule->key);
        return FLB_FILTER_NOTOUCH;
    }
    else {
        msgpack_pack_map(packer, map->via.map.size + 1);
        for (i = 0; i < map->via.map.size; i++) {
            kv = &map->via.map.ptr[i];

            msgpack_pack_object(packer, kv->key);
            msgpack_pack_object(packer, kv->val);

            if (kv_key_matches_str_rule_key(kv, rule)) {
                helper_pack_string(ctx, packer, rule->val, rule->val_len);
                msgpack_pack_object(packer, kv->val);
            }
        }
        return FLB_FILTER_MODIFIED;
    }
}

static inline int apply_rule_HARD_COPY(struct filter_modify_ctx *ctx,
                                       msgpack_packer *packer,
                                       msgpack_object *map,
                                       struct modify_rule *rule)
{
    int i;

    int match_keys =
        map_count_keys_matching_str(map, rule->key, rule->key_len);
    int conflict_keys =
        map_count_keys_matching_str(map, rule->val, rule->val_len);
    msgpack_object_kv *kv;

    if (match_keys < 1) {
        flb_plg_debug(ctx->ins, "Rule HARD_COPY %s TO %s : No keys matching %s "
                      "found, not applying rule",
                      rule->key, rule->val, rule->key);
        return FLB_FILTER_NOTOUCH;
    }
    else if (match_keys > 1) {
        flb_plg_warn(ctx->ins, "Rule HARD_COPY %s TO %s : Multiple keys "
                     "matching %s found, not applying rule",
                     rule->key, rule->val, rule->key);
        return FLB_FILTER_NOTOUCH;
    }
    else if (conflict_keys > 1) {
        flb_plg_warn(ctx->ins, "Rule HARD_COPY %s TO %s : Multiple target keys "
                     "matching %s found, not applying rule",
                     rule->key, rule->val, rule->val);
        return FLB_FILTER_NOTOUCH;
    }
    else if (conflict_keys == 0) {
        msgpack_pack_map(packer, map->via.map.size + 1);
        for (i = 0; i < map->via.map.size; i++) {
            kv = &map->via.map.ptr[i];
            msgpack_pack_object(packer, kv->key);
            msgpack_pack_object(packer, kv->val);

            // This is our copy
            if (kv_key_matches_str_rule_key(kv, rule)) {
                helper_pack_string(ctx, packer, rule->val, rule->val_len);
                msgpack_pack_object(packer, kv->val);
            }
        }
        return FLB_FILTER_MODIFIED;
    }
    else {
        msgpack_pack_map(packer, map->via.map.size);

        for (i = 0; i < map->via.map.size; i++) {
            kv = &map->via.map.ptr[i];

            // Skip the conflict key, we will create a new one
            if (!kv_key_matches_str_rule_val(kv, rule)) {
                msgpack_pack_object(packer, kv->key);
                msgpack_pack_object(packer, kv->val);

                // This is our copy
                if (kv_key_matches_str_rule_key(kv, rule)) {
                    helper_pack_string(ctx, packer, rule->val, rule->val_len);
                    msgpack_pack_object(packer, kv->val);
                }
            }
        }

        return FLB_FILTER_MODIFIED;
    }
}

static inline int apply_rule_ADD(struct filter_modify_ctx *ctx,
                                 msgpack_packer *packer,
                                 msgpack_object *map,
                                 struct modify_rule *rule)
{
    if (map_count_keys_matching_str(map, rule->key, rule->key_len) == 0) {
        msgpack_pack_map(packer, map->via.map.size + 1);
        map_pack_each(packer, map);
        helper_pack_string(ctx, packer, rule->key, rule->key_len);
        helper_pack_string(ctx, packer, rule->val, rule->val_len);
        return FLB_FILTER_MODIFIED;
    }
    else {
        flb_plg_debug(ctx->ins, "Rule ADD %s : this key already exists, "
                      "skipping", rule->key);
        return FLB_FILTER_NOTOUCH;
    }
}

static inline int apply_rule_SET(struct filter_modify_ctx *ctx,
                                 msgpack_packer * packer,
                                 msgpack_object * map,
                                 struct modify_rule *rule)
{
    int matches = map_count_keys_matching_str(map, rule->key, rule->key_len);

    msgpack_pack_map(packer, map->via.map.size - matches + 1);

    if (matches == 0) {
        map_pack_each(packer, map);
        helper_pack_string(ctx, packer, rule->key, rule->key_len);
        helper_pack_string(ctx, packer, rule->val, rule->val_len);
    }
    else {
        map_pack_each_fn(packer, map, rule,
                         kv_key_does_not_match_str_rule_key);
        helper_pack_string(ctx, packer, rule->key, rule->key_len);
        helper_pack_string(ctx, packer, rule->val, rule->val_len);
    }

    return FLB_FILTER_MODIFIED;
}

static inline int apply_rule_REMOVE(msgpack_packer *packer,
                                    msgpack_object *map,
                                    struct modify_rule *rule)
{
    int matches = map_count_keys_matching_str(map, rule->key, rule->key_len);

    if (matches == 0) {
        return FLB_FILTER_NOTOUCH;
    }
    else {
        msgpack_pack_map(packer, map->via.map.size - matches);
        map_pack_each_fn(packer, map, rule,
                         kv_key_does_not_match_str_rule_key);
        return FLB_FILTER_MODIFIED;
    }
}

static inline int apply_rule_REMOVE_WILDCARD(msgpack_packer * packer,
                                             msgpack_object * map,
                                             struct modify_rule *rule)
{
    int matches =
        map_count_keys_matching_wildcard(map, rule->key, rule->key_len);

    if (matches == 0) {
        return FLB_FILTER_NOTOUCH;
    }
    else {
        msgpack_pack_map(packer, map->via.map.size - matches);
        map_pack_each_fn(packer, map, rule,
                         kv_key_does_not_match_wildcard_rule_key);
        return FLB_FILTER_MODIFIED;
    }
}

static inline int apply_rule_REMOVE_REGEX(msgpack_packer * packer,
                                          msgpack_object * map,
                                          struct modify_rule *rule)
{
    int matches = map_count_keys_matching_regex(map, rule->key_regex);

    if (matches == 0) {
        return FLB_FILTER_NOTOUCH;
    }
    else {
        msgpack_pack_map(packer, map->via.map.size - matches);
        map_pack_each_fn(packer, map, rule,
                         kv_key_does_not_match_regex_rule_key);
        return FLB_FILTER_MODIFIED;
    }
}

static inline int apply_rule_MOVE_TO_END(struct filter_modify_ctx *ctx,
                                         msgpack_packer *packer,
                                         msgpack_object *map,
                                         struct modify_rule *rule)
{

    int match_keys =
        map_count_keys_matching_wildcard(map, rule->key, rule->key_len);

    if (match_keys == 0) {
        return FLB_FILTER_NOTOUCH;
    }
    else {
        msgpack_pack_map(packer, map->via.map.size);
        map_pack_each_fn(packer, map, rule,
                         kv_key_does_not_match_wildcard_rule_key);
        map_pack_each_fn(packer, map, rule,
                         kv_key_matches_wildcard_rule_key);
        return FLB_FILTER_MODIFIED;
    }
}

static inline int apply_rule_MOVE_TO_START(struct filter_modify_ctx *ctx,
                                           msgpack_packer *packer,
                                           msgpack_object *map,
                                           struct modify_rule *rule)
{

    int match_keys =
        map_count_keys_matching_wildcard(map, rule->key, rule->key_len);

    if (match_keys == 0) {
        return FLB_FILTER_NOTOUCH;
    }
    else {
        msgpack_pack_map(packer, map->via.map.size);
        map_pack_each_fn(packer, map, rule,
                         kv_key_matches_wildcard_rule_key);
        map_pack_each_fn(packer, map, rule,
                         kv_key_does_not_match_wildcard_rule_key);
        return FLB_FILTER_MODIFIED;
    }
}

static inline int apply_modifying_rule(struct filter_modify_ctx *ctx,
                                       msgpack_packer *packer,
                                       msgpack_object *map,
                                       struct modify_rule *rule)
{
    switch (rule->ruletype) {
    case RENAME:
        return apply_rule_RENAME(ctx, packer, map, rule);
    case HARD_RENAME:
        return apply_rule_HARD_RENAME(ctx, packer, map, rule);
    case ADD:
        return apply_rule_ADD(ctx, packer, map, rule);
    case SET:
        return apply_rule_SET(ctx, packer, map, rule);
    case REMOVE:
        return apply_rule_REMOVE(packer, map, rule);
    case REMOVE_WILDCARD:
        return apply_rule_REMOVE_WILDCARD(packer, map, rule);
    case REMOVE_REGEX:
        return apply_rule_REMOVE_REGEX(packer, map, rule);
    case COPY:
        return apply_rule_COPY(ctx, packer, map, rule);
    case HARD_COPY:
        return apply_rule_HARD_COPY(ctx, packer, map, rule);
    case MOVE_TO_START:
        return apply_rule_MOVE_TO_START(ctx, packer, map, rule);
    case MOVE_TO_END:
        return apply_rule_MOVE_TO_END(ctx, packer, map, rule);
    default:
        flb_plg_warn(ctx->ins, "Unknown ruletype for rule with key %s, ignoring",
                     rule->key);
    }
    return FLB_FILTER_NOTOUCH;
}

static inline int apply_modifying_rules(msgpack_packer *packer,
                                        msgpack_object *root,
                                        struct filter_modify_ctx *ctx)
{
    msgpack_object ts = root->via.array.ptr[0];
    msgpack_object map = root->via.array.ptr[1];

    if (!evaluate_conditions(&map, ctx)) {
        flb_plg_debug(ctx->ins, "Conditions not met, not touching record");
        return 0;
    }

    bool has_modifications = false;

    int records_in = map.via.map.size;

    struct modify_rule *rule;

    msgpack_sbuffer sbuffer;
    msgpack_packer in_packer;
    msgpack_unpacker unpacker;
    msgpack_unpacked unpacked;

    int initial_buffer_size = 1024 * 8;
    int new_buffer_size = 0;

    struct mk_list *tmp;
    struct mk_list *head;

    msgpack_sbuffer_init(&sbuffer);
    msgpack_packer_init(&in_packer, &sbuffer, msgpack_sbuffer_write);
    msgpack_unpacked_init(&unpacked);
    if (!msgpack_unpacker_init(&unpacker, initial_buffer_size)) {
        flb_plg_error(ctx->ins, "Unable to allocate memory for unpacker, aborting");
        return -1;
    }

    mk_list_foreach_safe(head, tmp, &ctx->rules) {
        rule = mk_list_entry(head, struct modify_rule, _head);

        msgpack_sbuffer_clear(&sbuffer);

        if (apply_modifying_rule(ctx, &in_packer, &map, rule) !=
            FLB_FILTER_NOTOUCH) {

            has_modifications = true;
            new_buffer_size = sbuffer.size * 2;

            if (msgpack_unpacker_buffer_capacity(&unpacker) < new_buffer_size) {
                if (!msgpack_unpacker_reserve_buffer
                    (&unpacker, new_buffer_size)) {
                    flb_plg_error(ctx->ins, "Unable to re-allocate memory for "
                                  "unpacker, aborting");
                    return -1;
                }
            }

            memcpy(msgpack_unpacker_buffer(&unpacker), sbuffer.data,
                   sbuffer.size);
            msgpack_unpacker_buffer_consumed(&unpacker, sbuffer.size);

            msgpack_unpacker_next(&unpacker, &unpacked);

            if (unpacked.data.type == MSGPACK_OBJECT_MAP) {
                map = unpacked.data;
            }
            else {
                flb_plg_error(ctx->ins, "Expected MSGPACK_MAP, this is not a "
                              "valid return value, skipping");
            }
        }
    }

    if (has_modifications) {
        // * Record array init(2)
        msgpack_pack_array(packer, 2);

        // * * Record array item 1/2
        msgpack_pack_object(packer, ts);

        flb_plg_trace(ctx->ins, "Input map size %d elements, output map size "
                      "%d elements", records_in, map.via.map.size);

        // * * Record array item 2/2
        msgpack_pack_object(packer, map);
    }

    msgpack_unpacked_destroy(&unpacked);
    msgpack_unpacker_destroy(&unpacker);
    msgpack_sbuffer_destroy(&sbuffer);

    return has_modifications ? 1 : 0;

}

static int cb_modify_init(struct flb_filter_instance *f_ins,
                          struct flb_config *config, void *data)
{
    struct filter_modify_ctx *ctx;

    // Create context
    ctx = flb_malloc(sizeof(struct filter_modify_ctx));
    if (!ctx) {
        flb_errno();
        return -1;
    }
    mk_list_init(&ctx->conditions);
    mk_list_init(&ctx->rules);
    ctx->ins = f_ins;
    ctx->rules_cnt = 0;
    ctx->conditions_cnt = 0;

    if (setup(ctx, f_ins, config) < 0) {
        flb_free(ctx);
        return -1;
    }

    // Set context
    flb_filter_set_context(f_ins, ctx);
    return 0;
}

static int cb_modify_filter(const void *data, size_t bytes,
                            const char *tag, int tag_len,
                            void **out_buf, size_t * out_size,
                            struct flb_filter_instance *f_ins,
                            struct flb_input_instance *i_ins,
                            void *context, struct flb_config *config)
{
    msgpack_unpacked result;
    size_t off = 0;
    (void) f_ins;
    (void) i_ins;
    (void) config;

    struct filter_modify_ctx *ctx = context;

    int modifications = 0;
    int total_modifications = 0;

    msgpack_sbuffer buffer;
    msgpack_sbuffer_init(&buffer);

    msgpack_packer packer;
    msgpack_packer_init(&packer, &buffer, msgpack_sbuffer_write);

    // Records come in the format,
    //
    // [ TIMESTAMP, { K1:V1, K2:V2, ...} ],
    // [ TIMESTAMP, { K1:V1, K2:V2, ...} ]
    //
    // Example record,
    // [1123123, {"Mem.total"=>4050908, "Mem.used"=>476576, "Mem.free"=>3574332 } ]

    msgpack_unpacked_init(&result);
    while (msgpack_unpack_next(&result, data, bytes, &off) == MSGPACK_UNPACK_SUCCESS) {
        if (result.data.type == MSGPACK_OBJECT_ARRAY) {
            modifications =
                apply_modifying_rules(&packer, &result.data, ctx);

            if (modifications == 0) {
                // not matched, so copy original event.
                msgpack_pack_object(&packer, result.data);
            }
            total_modifications += modifications;
        }
        else {
            msgpack_pack_object(&packer, result.data);
        }
    }
    msgpack_unpacked_destroy(&result);

    if(total_modifications == 0) {
        msgpack_sbuffer_destroy(&buffer);
        return FLB_FILTER_NOTOUCH;
    }

    *out_buf = buffer.data;
    *out_size = buffer.size;

    return FLB_FILTER_MODIFIED;
}

static int cb_modify_exit(void *data, struct flb_config *config)
{
    struct filter_modify_ctx *ctx = data;

    teardown(ctx);
    flb_free(ctx);
    return 0;
}

static struct flb_config_map config_map[] = {
    {
     FLB_CONFIG_MAP_STR, "Set", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Add a key/value pair with key KEY and value VALUE. "
     "If KEY already exists, this field is overwritten."
    },
    {
     FLB_CONFIG_MAP_STR, "Add", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Add a key/value pair with key KEY and value VALUE if KEY does not exist"
    },
    {
     FLB_CONFIG_MAP_STR, "Remove", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Remove a key/value pair with key KEY if it exists"
    },
    {
     FLB_CONFIG_MAP_STR, "Remove_wildcard", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Remove all key/value pairs with key matching wildcard KEY"
    },
    {
     FLB_CONFIG_MAP_STR, "Remove_regex", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Remove all key/value pairs with key matching regexp KEY"
    },
    {
     FLB_CONFIG_MAP_STR, "Move_To_Start", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Move key/value pairs with keys matching KEY to the start of the message"
    },
    {
     FLB_CONFIG_MAP_STR, "Move_To_End", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Move key/value pairs with keys matching KEY to the end of the message"
    },
    {
     FLB_CONFIG_MAP_STR, "Rename", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Rename a key/value pair with key KEY to RENAMED_KEY "
     "if KEY exists AND RENAMED_KEY does not exist"
    },
    {
     FLB_CONFIG_MAP_STR, "Hard_Rename", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Rename a key/value pair with key KEY to RENAMED_KEY if KEY exists. "
     "If RENAMED_KEY already exists, this field is overwritten"
    },
    {
     FLB_CONFIG_MAP_STR, "Copy", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Copy a key/value pair with key KEY to COPIED_KEY "
     "if KEY exists AND COPIED_KEY does not exist"
    },
    {
     FLB_CONFIG_MAP_STR, "Hard_copy", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Copy a key/value pair with key KEY to COPIED_KEY if KEY exists. "
     "If COPIED_KEY already exists, this field is overwritten"
    },
    {
     FLB_CONFIG_MAP_STR, "Condition", NULL,
     FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
     "Set the condition to modify. Key_exists, Key_does_not_exist, A_key_matches, "
     "No_key_matches, Key_value_equals, Key_value_does_not_equal, Key_value_matches, "
     "Key_value_does_not_match, Matching_keys_have_matching_values "
     "and Matching_keys_do_not_have_matching_values are supported."
    },
    {0}
};

struct flb_filter_plugin filter_modify_plugin = {
    .name = "modify",
    .description = "modify records by applying rules",
    .cb_init = cb_modify_init,
    .cb_filter = cb_modify_filter,
    .cb_exit = cb_modify_exit,
    .config_map = config_map,
    .flags = 0
};

redpajama_set_name: RedPajamaGithub


text:
Category Archives: NJ State Library
>Middletown Library Trustees Expected To Approve $500K Fund Transfer Report
>Still catching up on recent goings on that I wasn't able to get to over the past two weeks is the latest news concerning the Middletown Library.
Back on June 2nd the Asbury Park Press ran a story about how at the next meeting of the Middletown Library's Board of Trustees meeting on June 15th (this upcoming Wednesday), the trustees are expected to vote on a report that details the transfer of nearly $500K in surplus and reserved funds to the Township before it is sent on to the NJ State Librarian.
If the state librarian approves of the report, which could take up to 45 days and is not a given, the surplus and reserves library funds can be transferred according to state law to the township in order for it to be used in offsetting the municipal budget.
As stated in previous posts, the report has been the responsibility of Library Director Susan O'Neal to put together. The report needed to be rather complex and meet very specific standards, it will include demographic projections, a three-year technology plan and a three-year strategic plan for approval.
After having read the APP article about the report, I got the feeling that certain members of the Township Committee, namely Middletown's appointed mayor, Tony Fiore, doesn't trust the library trustees to do what's expected of them based on the following excerpt:
"I don't anticipate any potential negative portrayals," said Fiore of the report. "I am confident they will do what is in their best interests and in that of the taxpayers of Middletown."
It almost seems as if Fiore expects Director O'Neal to somehow sabotage the report by adding something to it that would prevent the trustees to support it or the state librarian not to approve it, which would either delay the transfer of funds or kill the transfer all together.
I you ask me, I think Fiore is a little paranoid and has a bit of a Napoleon complex. Whether it is this issue or some other, he always has to inject subtle or obnoxious and veiled threats to make his points.
It's really arrogant and shows little class.
Filed under Asbury Park Press, Board of Trustees, Middletown Library, NJ State Library, State Librarian, surplus funds, Susan O'Neal, Tony Fiore
May 20, 2011 · 11:53 am
>The Middletown Library "Unfinished Business": The latest on the $500K transfer, the lot construction, the Lincroft Branch, and other issues.
>by guest blogger Linda Baum
Mike mentioned in a 5/17/11 post that a number of ongoing issues were slated to be discussed at this Wednesday's 5/18/11 meeting of the Middletown Library Board, which I attended.
One issue concerned the parking lot expansion project. As Mike said, the Board had been told by the town that T&M Engineering would be the engineer for this work. The Board was given no other option or opportunity to compare costs, but will be responsible for paying the bill for these services.
At Wednesday's meeting, the trustees voiced concern about the use of T&M, pointing out that the Board had not been satisfied with T&M's services on a prior project. They were told that T&M is the town's engineer for capital projects for 2011, so to the extent that the lot construction is designated as one of the town's capital projects this year, T&M will be the engineer. So says the town.
Maser Consulting had been hired by the Library to do initial design work for the lot prior to the town's taking of funds. That work is complete except for coordination with the engineer of choice.
It wasn't clear if a decision had been made about who would pay for the actual construction, the Town or the Library. While the lot expansion was "included" in the $500K transfer agreement between the Library and the Township, the question of who would pay was left unanswered. Committman Settembrino's comment at Wednesday's meeting that the library would be responsible for "soft costs" (such as the engineering costs) seemed to imply that the library would not be responsible for the "hard costs" for actual construction.
The Library Board is making no assumptions – they are more likely to be on the hook than not. In fact, they haven't decided to go ahead with any of the work. The Board feels they may not have sufficient funds.
There are still a number of steps and hurdles before the $500K transfer can be made. First, focus groups must be completed and a strategic plan finalized, and a package of materials including those pieces submitted to the State Librarian for approval. Committeman Settembrino said that Town personnel were under the impression that the package would be submitted to the state by the end of May, but Ms. O'Neal pointed out that the Board couldn't submit the package to the state until the Board passes a resolution that it has filled all the requirements, where 4 out of 5 pieces require the Board's approval. A decision was made to finalize review of the strategic plan at the Board's June 15th meeting, in line with Committeeman Settembrino's request that discussion take place before the Town's regular meeting on June 20th.
An important point is that there is no guarantee the State Library will give its approval. Ms. O'Neal commented that the State could take issue with the reserve figure in the Library's audit, where the reserve includes funds from municipal and other sources.
Some other topics discussed at the meeting:
The Lincroft branch is believed to have lead-based paint and asbestos in the walls given the age of the structure. The paint isn't peeling, and therefore poses no danger. A concern about the asbestos is that it may be in the walls of the front entryway, which has termite damage. So there are costs involved for the inspection and abatement plan in addition to the repair work. An architect will be presenting on this topic at the Board's June 15th meeting.
There was discussion about the need for either curbs or reflectors or boulders to prevent people from parking on the grass in certain sections of the library's lot. (I bet you didn't know that the fancy boulders in the lot aren't just there for looks. Nope, they're there to assist you in stopping.) The Board concluded that posts with reflectors would get the job done at a reasonable cost.
Kudos to Eagle Scout Andrew Bloy, who will be allowed to place a collection jar at the Library's front desk because he has demonstrated considerable community benefit. Allowing the collection effort represents an exception by the Board to Library policy. The Board was impressed with Mr. Bloy's request letter and community involvement. In fact, they mentioned that after Mr. Bloy learned that planting a medicinal herb garden at a local medical office would not earn him scouting credit, he did it anyway.
The Board discussed a software donation offer by a local company called Comprise Technologies. The software, offered free for six months, is designed to process payments made by credit card. The Board noted that credit cards are being used with increasing frequency for the payment of library fines. Comprise Technologies will be presenting at the Library Board meeting on July 20th. There are ongoing expenditures to be considered, including fees for the software and service, and costs for integration with other library systems. There was also discussion of implementing a charge for credit card payments, but the Board instead opted to request a donation when credit cards are used. The thinking is that folks probably wouldn't mind rounding up their payment to the next dollar, at least.
Filed under audit, Board of Trustees, budget surplus, Eagle Scout, Kevin Settembrino, Middletown Library, Middletown Township Committee, NJ State Library, Susan O'Neal, transfer of funds, unfinished business
>Many Questions Remain; Middletown's Library Surplus Issue Far From Settled And Could Be Derailed
>There was another Middletown Library Board meeting this past Wednesday night and if you weren't there to witness the goings on you missed a lot. Evidently many questions arose over the the time table for which the Township Committee expects to be paid the $500,000 that it practically extorted form the library in order to fill a budget gap in it's own 2011 budget, and what was required by the State Librarian before those dollars could be legally transferred.
If it weren't for the lone member of the public who attended this meeting( that's correct, no one else other that then Board members were in attendance), Linda Baum, no one would know that there is a problem brewing over these funds once again.
According to the NJ State Librarian, before surplus funds can be transferred from the Middletown Library to the Township Committee, a strategic plan must be prepared. The plan would need to include a number of focus group opinions, which would take time to complete. Only after this was all completed, could the plan to transfer funds from the library to the township be completed. Library Director Susan O'Neal estimated that it would take until August to complete.
Of course this did not sit very well with Township Commiteeman Kevin Settembrino, who was appointed to the Library Board by the mayor. Settembrino wanted the transfer of funds to take place with in four weeks so that the the Township's budget could be finalized.
Ms. Baum took minutes of the meeting for herself and passed them along to me to share:
The library mtg ran three hours. Got heated in parts. The number of people in the audience including me: One. Here are the main points:
There are certain requirements the library must meet before the state librarian will approve the giveback. Formation of a strategic plan is required, and focus groups are a required part. Ms. O'Neal estimated an August 2011 completion date for both. Mr. Settembrino didn't like that at all — he felt it would delay finalization of the town's budget. They discussed hiring a professional to conduct the groups at a cost of $3K max. A resolution to that effect was voted down 3-2. Some felt it could be done by library staff, while others felt staff lacked the time and that focus group participants would not be comfortable with library staff leading the groups. A few didn't want to spend money to give away money. Ms. Breen asked Kevin if the town would pay for it since they gain from it. He declined of course. Issues were cost, whether they could get community participation, and whether or not there was a need for new focus groups or if existing data could be used — a survey was done in 2004. Mr. Settembrino proposed using the 2004 survey results to produce the focus group report for inclusion in the new strategic plan. A resolution to do it internally was passed 3-2. Mr. Settembrino revisited the timeline and asked for completion in 4 weeks. Ms. O'Neal said the end of May would be more achievable. Mr. Milne questioned if, by doing the focus groups themselves and/or by utilizing data already in hand, the library would be at risk of not getting the approval from the state librarian. (Let's hope so.) They don't know how much leeway they have.
(I thought of a few good ideas to simplify and speed the process, but I realized whose side I was on and kept quiet.)
It got heated when Mr. Settembrino scoffed about library employees resistance to doing the extra work in light of their recent raises (you know, the one dollar per week). Wendy Latona let him have it. She brought up the $15,000 stipend.
The next issue was about the 2009 audit results. Discussion was specifically about around $88K in library money that was left on the table but not known about in February. Kevin asked if this would affect the decision on the giveback. The board felt the issue was handled and would not affect the giveback. Ms. O'Neal said she had not yet talked with Nick Trasente, and wanted to address 2009 as well as 2010 issues. I got a little confused here. I asked if the board's concern about the audit related to just the $88k issue. Yes, they said. I said that I had reviewed the corrective action plan and felt much was not addressed. I asked them to consider revisiting the giveback decision as new information comes to light.
Mr. Settembrino asked when the preliminary 2012 budget comes out. Ms. O'Neal said the draft budget (in the range of $3.5M) is done in October when the official rateables comes out. Settembrino pushed to get it earlier, saying the rateables is out now. Susan said she is required to use the official figure released in October. Kevin said he felt leaving the initial release till October didn't leave enough time to review or make changes as needed, or whatever. Ms. O'Neal replied, "Duly noted." I don't know if there was any offer to meet an earlier target. Ms. Breen complimented Susan on being a great director and told Kevin it seemed like he was scolding.
There were other topics discussed relating to library spending for travel and repairs. The Lincroft branch has termite damage in the entryway.
Coverage or lack thereof for underground storage tanks was touched upon. Property coverage for the library is included under the town's policy, which is an excess policy. Kevin will check into coverage.
There was a resolution to allot more money to the library's attorney, whose fees ran over due to the recent funding battle. It passed.
Minutes from the 2/16 and 3/16 mtgs were adopted. I have a printed copy of minutes from 2/16 – 19 pages. I didn't get a copy of the 3/16 minutes, but will ask Wendy for it.
Feel free to distribute.
I'll be posting more about this over the next couple of days.
Things here just don't seem right to me and if Settmebrino or the rest of those on the Township Committee wanted their money right away, then I think they should have done their homework properly to find out if there would be potential problems. But like so much that those that run Middletown do, this attempt to wrestle funds from the Library was done haphazardly and with authoritarian zeal without knowing the consequences of their actions.
Filed under Board of Trustees, Kevin Settembrino, Middletown Library, Middletown NJ, Middletown Township Committee, NJ State Library, reserved funds, State Librarian, surplus funds, Susan O'Neal
>Library Board Meeting Tonight; Update Issued For Library Supporters
>Middletown Library Director Susan O'Neal has posted the following update on the Middletown Township Library's website in advance of tonight's Library Board meeting, where it is presumed that an answer will be forthcoming on how much, if any, reserved library funds will be transfered to the Township to help offset the Topwnship's budget deficit:
The next meeting of the Library Board is Wednesday, March 16, at 7:00 p.m. This is, of course, a public meeting. The issues of the last two months, specifically the library making a contribution to the Township for the 2011 budget, and the terms of same, have been in negotiations since the last meeting. Last week, to our surprise, the Township Administrator and Attorney revealed to the press the amount of money they are asking for, $500,000. There are other terms which are still part of the negotiations. I can tell you that these are viewed as protections for the library from some of the threats that have been publically made. I cannot say, in truth, whether there is an agreement that will be struck by Wednesday night or not, but the Library is cautiously optimistic, and has given over much time and deliberation to the process.
If the Library transfers funds to the Township of Middletown, there are strict procedures stated in the law that must be followed, among these are the Library must prepare an Annual Report on the state of the library, it must submit a three year Technology Plan and a three year Strategic Plan. These last two plans are submitted to the NJ State Library for approval. Once these plans are approved, the Library can apply to the NJ State Library for the transfer to take place. The State Librarian has 45 days to approve or deny the transfer. These procedures were developed in tandem with the Department of Community Affairs, which oversees all municipal budgets in the State of New Jersey.
The intent of all this is to ensure that the library has sufficient funds remaining for current year operations and for the future plans it has adopted. In fact, an early version of the law was vetoed by Gov. Christie, because he saw that the safeguard provisions for the local libraries needed to be improved in the bills that were passed. If the Middletown Township Library Board of Trustees does decide to transfer monies to the Township, it is committed to following these procedures accurately and completely.
Once the terms have been negotiated and an agreement has been made, the Trustees desire is that a joint announcement of the terms will be made available to the public.
You are, of course, welcome to attend the upcoming Board Meeting when the agreement, if done, comes before the entire Board of Trustees for a vote.
Filed under 2011 budget, Board of Trustees, Gov. Chris Christie, Library Reserves, Middletown Library, Middletown Township Committee, NJ State Library, surplus funds, Susan O'Neal
>Library Director Issues Update On Library Reserves Issue
>Middletown Library Director Susan O'Neal, earlier today posted the following update on the issue of Library Reserve funds on the main page of the Middletown Township Library's website:
The Library "giveback" issue is now so full of rumors that it is difficult to know where to begin. One of the troubling issues is that some are casting the library as uncooperative. Not true.
So, I'll start with last year, when members of the Township Committee, Pam Brightbill and Sean Byrnes came to library board meetings and asked the Trustees to consider giving some of its reserves to the town. The Trustees listened, and made a quick response to sponsor one of the summer concerts of the Parks & Recreation Department. We followed up with a letter to the Mayor [dated June 10,2010] indicating the Board's willingness to provide some assistance, and asked four questions which were germane to the Board's deliberations. There was no response to the letter [which we will post on this website] These questions were not answered by August, when Mayor Scharfenberger attended the library board meeting, and he was asked again for a response. None followed, and the library pressed on in memos and finally, in November, a meeting was held with Library Trustees, Mr. Mercantante and Mr. Trascente. But questions of the Board were not completely answered. In fact, the inability of the library to get any reconciliation of the small budget surplus of 2008 and 2009 kept our 2010 budget in flux for the entire year. And, without the information it asked for, the Trustees could not make an informed decision about making a contribution to help the Township.
So now we get to late 2010, and the law on libraries returning some surpluses changes from libraries "may" return surpluses to "must" return surpluses that are not restricted for capital projects, or are from per capita state aid funds. Immediately, the request turned into a demand, and for much much more than the law would allow. By the library's calculations of the official "Proposed Transfer Form" of monies, the Middletown Library has $262,453 in funds which must be returned.
The Trustees of the Library are negotiating in good faith with the Township on this matter and will do what they are able to do legally.
Susan O'Neal, Director
p.s. By the way, the NJ State Library has informed us that ALL of the dozen or so libraries that have given back funds to their municipalities have followed the procedures outlined in the law. The MTPL will do the same.
Filed under budget deficit, Library Reserves, Middletown Library, Middletown Township Committee, NJ State Library, surplus funds, Susan O'Neal

redpajama_set_name: RedPajamaCommonCrawl


**Please Note: This form is meant for those requesting the Party Trailer. All Block Parties need to register with the Police Department communicating separately at blockparty@friscotexas.gov.
Submitting this form is not an approval for use of the trailer.
You will receive a confirmation email with further details if approved or denied.


"This is one of the grand aspects of your London."
We were sitting upon some barrels, not far within the St. Katherine's Dock Gates, on a sultry summer's day; watching the scene of extraordinary activity in the great entrepot before us. "There is no end to it! London Docks, St. Katherine's Docks, Commercial Docks on the other side, India Docks, Victorian Docks; black with coal, blue with indigo, brown with hides, white with flour; stained with purple wine-or brown with tobacco!"
(shadows in the throng), hungry-looking day-labourers landing the rich and sweet stores of the South or the breadstuffs of the generous West-all this makes a striking scene that holds fast the imagination of the observer, who has just skirted the dull outer wall of a great dock, faced by the low and shabby shops of poor Jack's arch enemies.
He who wants to study every form of ship, every kind of rigging, the thousand and one details of spars and ropes, the delightful play of light and colour which is a perpetual beauty about a clipper's deck; the sad human stories that crowd the emigrant vessel; the sailor of every clime and country; in short the immensity of commerce that counts warehouses by the mile and goods by the hundred thousand tons-can have no better field than these watery acres that give hospitable welcome to every flag. The light plays upon every known bunting. We thread our way round the busy basins, through bales and bundles and grass-bags, over skins and rags, and antlers, ores and dye-woods: now through pungent air, and now through a tallowy atmosphere-to the quay-and the great river where fleets are for ever moored. The four thousand feet of river frontage of the St. Katherine's Docks, only lead east, to where the London Docks take up the striking story of human skill and courage, centered from every navigable sea.
cool in their foundations between sixty and seventy thousand pipes of wine! This Tobacco Dock with the kiln in the corner, commonly known as the Queen's Tobacco Pipe (and wherein damaged and confiscated tobacco and other commodities are blown into thin air) and its dark avenues braided and curtained with webs fed by the exudations of many vintages-is, to the Temperance enthusiast a damned spot: and these alleys of hogsheads and pipes and ships whose comely sides they have filled, are only so many passages to the Valley of Death.
Dock House govern the employment of a capital amounting to about four millions sterling. They are the hosts of squadrons of the peaceful Marine that is overspreading the world with the blessings of civilisation. By us, where we sit watching sailors in the rigging, or slung by a ship's sides "peacocking" her bottom, looms the enormous figure-head of the Concordia, stretching out of the basin and overshadowing the quay. A noble representative vessel in the midst of this mast-forest, and by the banks of the busiest river in the world. This ship is of the fleet that shall prevail in the end, over the iron-clads and the floating rams. Its comely prow shall rise triumphant over many summer seas, when the Spitfires have been laid up, and put out of sight of a world at peace-save in such contests as those, the spoils of which lie along our leagues of quays, prone to the vigorous and courageous hand of the workman.
have studied on the Middlesex bank; only in Rotherhithe the seafaring element is intensified, and is upon everybody and everything. Every living creature slouches or shambles; the women are brawny of arm and of brazen countenance; the public-houses are driving a wonderful trade; and along all the line the money gained by night-watches in the northern seas, and over the crestless black billows of the Baltic, is being freely and badly spent.
Take Shadwell, Ratcliff Highway, Old Gravel Lane, and Rotherhithe, and you find few differences-save at points, in the intensity of the squalid recklessness. By day and by night it is the same interminable scene of heedless, shiftless money-squandering of Jack ashore, in the company of his sweethart.
The whole is a grand-picture-with a very dark background-such a back-ground as that which appeared to us one dark night, outside a public-house, by Dockhead.
constant jollity to the scene-and is the occasion of the interminable roystering apparent in the lines of low public-houses thronged with ragged, loud-voiced men and women. The pitched battle we witnessed outside a public-house at Dockhead one threatening night-is an incident that from time to time starts out of the level of the Ratcliff Highway,am's careless and vicious life of want and drink.


to forward a copy to them.
reports include the analyzed "best track" for each cyclone.
Storm Hali (March) were out-of-season storms.
author is not aware of the last year in which this occurred.
775 nm southwest of Johnston, it was only a minimal tropical storm.
summary covering the Northwest Pacific Basin.
began to move on a very gradual west-northwesterly course.
Paka was located 25 nm south of the eastern point of Rota.
amputated when a wind-blown car door slammed on her hand.
though, and perhaps remarkably, no lives were lost due to Typhoon Paka.
weakened due to restricted outflow and upper-level shear.
January since there was a chance the depression might re-intensify.
low-lying areas near the Gulf of Carpentaria.
with entrainment of drier air, caused Selwyn to begin to weaken.
over the next several days with convection occasionally flaring up.
the system was forecast to re-intensify, but this failed to happen.
dissipating system southwestward to near 20S, 86E by 1800 UTC on 3 Jan.
250 nm west of Manihiki Atoll in the northern Cooks with 30-kt winds.
Pam passed about 40 nm southwest of Rarotonga at 0600 UTC on 9 Dec.
30-kt winds at 1200 UTC on the 10th.
was some flooding of low-lying roads due to both heavy seas and rain.
been received by the author.


text:
Charles Coomer
charles.coomer@uky.edu
Charles Coomer CV_Feb_2018.pdf
@chadd92
Interests / Specialties:
Virus-Host Interaction
Bio / Education:
University of Oxford (2017-2021, anticipated)
University College London (2014-2015)
MSc Infection and Immunity
Western Kentucky University (2010-2014)
BA Biology; BA Chemistry
Mentor:
Alex Compton (NCI/NIH); Sergi Padilla-Parra (University of Oxford)
My dissertation project underscores the intersection between cell-intrinsic immunity, virus fusion and the biophysical properties which regulate this process using biochemical and quantitative microscopy approaches.
Grants:
National Institutes of Health Intramural AIDS Research Fellow, 2020-2021
Fellowship in Research Excellence Award, 2019-2020
NIH Oxford-Cambridge Scholars Program Microgrant, 2019
Selected Publications:
C. Coomer, K. Rahman, A. Compton (2020). The CD225 proteins: a family portrait of fusion regulators. Accepted to Trends in Genetics.
K. Rahman*, C. Coomer*, S. Majdoul, S. Ding, S. Lockett, S. Padilla-Parra, A. Compton (2020). A conserved motif functionally links the antiviral activity of IFITM3 with its oligomeric state in membranes. eLife. 9:e58537 DOI: 10.7554/eLife.58537
C. Coomer, I. Carlon-Andres, M. Iliopoulou, M. Dustin, E. Compeer, A. Compton, S. Padilla-Parra (2020). Single-cell glycolytic activity regulates membrane tension and HIV-1 fusion. PLoS Pathogens. https://doi.org/10.1371/journal.ppat.1008359
C. Coomer and S. Padilla-Parra (2020). Towards quantitative imaging of HIV-1 transmission in tissue. Submitted to Encyclopedia of Virology.
M. Iliopoulou, R. Nolan, L. Alvarez, Y. Watanabe, C. Coomer, et al (2018). A dynamic three step mechanism drives the HIV-1 prefusion reaction. Nature Structural and Molecular Biology. https://doi.org/10.1038/s41594-018-0113-x.
Kearney, M.F., Anderson, E.M., Coomer, C., Smith, L., Shao, W., Johnson, N., Kline, C., Spindler, J., Mellors, J.W., Coffin, J.M., and Ambrose, Z. (2015) Well-mixed plasma and tissue viral populations in RT-SHIV-infected macaques implies a lack of viral replication in the tissues during antiretroviral therapy. Retrovirology 12: 93.
Pope, W.H., et al (2015). Whole genome comparison of a large collection of mycobacteriophages reveals a continuum of phage genetic diversity. eLife; 4: e06416
M.F. Kearney; L. Smith; C. Coomer; G.J. Besson; J. Spindler; E.M. Anderson; W. Shao; T. Tanzosh; C. Rehm; J.W. Mellors; J.M. Coffin; F. Maldarelli. No Evidence for Evolution of Plasma HIV-1 RNA or PBMC HIV-1 DNA During Long-Term Suppressive Antiretroviral Therapy. In preparation for PLoS Pathogens.
Hatfull, G.F., et al (2012). Complete Genome Sequences of 138 Mycobacteriophages. Journal of Virology. 86: 2382-2384


text:
Starbucks Is Testing A Virtual Assistant That Takes Orders Via Voice And Text
We've got some good news, coffee lovers.
As of this summer, Starbucks will make it even easier to order and pay for your cup of joe. The chain is testing a virtual assistant feature within its popular iOS app that lets you skip baristas and place orders via voice or text.
Photo credit: www.cnet.com
The bot is called My Starbucks Barista and at this point, it will be available to about 1,000 customers all over the country. The highly-anticipated feature reportedly has the capacity to function as a voice-enabled assistant, while also maintaining the ability to customize your orders according to your personal preference.
Photo credit: www.chicagotribune.com
Gerri Martin-Flickinger – the company's CTO – said: "The Starbucks experience is built on the personal connection between our barista and customer, so everything we do in our digital ecosystem must reflect that sensibility. Our team is focused on making sure that voice ordering within our app is truly personal." The coffee maker is planning to continue rolling out the feature in phases during summer, and an Android version of My Starbucks Barista will be available later this year.
Photo credit: www.dfw.cbslocal.com
Moreover, Starbucks is launching a dedicated 'Reorder Skill' for Amazon's Alexa platform, which will make it easier for customers to get their usual food and beverage items. The only thing they need to do? Say: "Alexa, order my Starbucks."
ViralTide Copyright © 2020.


text:
Milton Ary Meier (São Paulo, ) é um médico brasileiro.

Foi eleito membro da Academia Nacional de Medicina em 2010, ocupando a Cadeira 39, da qual Augusto Paulino Soares de Souza é o patrono.

Membros da Academia Nacional de Medicina
Naturais da cidade de São Paulo

redpajama_set_name: RedPajamaWikipedia


This Swedish dishcloth will keep you wiping, cleaning, and scrubbing for months. These cloths lasts for about six months. They're reusable, washable, and biodegradable-and work better than their disposable counterpart, the paper towel. Care: The cloths can be cleaned in a few ways: place in top rack of the dishwasher, microwave for 2-3 minutes, sterilize in boiling water, or place in the washing machine and dryer. Note that the dryer may cause shrinkage. The cloths are also bleach safe.
Materials: 70% cellulose, 30% cotton.
Special weave absorbs 16 times its weight.
Eco-friendly alternative to paper towels and sponges.
100% biodegradable. Breaks down within 6 weeks in home compost, 16 weeks in a commercial landfill.
Lasts for at least 6 months with normal use.
Great for washing dishes, wiping counters, and even shining your mirrors.
Biodegradable paint lasts for the life of the cloth.
Does not leave behind streaks on glass.
Dimensions: 8 x 6.75 x 0.75 inch.


text:
Vigo-touting gang ripping off luxury four-wheelers headed to Punjab
Hilux, Fortuner, V8s targeted
SAMAA | Aamir Majeed - Posted: Nov 28, 2021 | Last Updated: 2 months ago
SAMAA | Aamir Majeed
Highway robbery, quite literally, has the police scrambling to ratchet up night patrols after four big hits in the last two months. Gangs are taking off with entire trailers loaded with luxury four-wheelers being transported through Sindh and Balochistan.
The trailers were hijacked on October 2 in Balochistan's Kalat, on October 21 in Mastung and then the gangs struck on November 20 in Sindh's Kandiaro and on November 24 in Hala.
The president of the All Pakistan Car Carrier Association, Imdad Naqvi, speculated that a single group is working the highway because each time the modus operandi was the same. They are targeting the Toyota Hilux Revos, Fortuners and Toyota Land Cruiser V8s whose starting prices are Rs7 million.
Naqvi said the gang used Vigos in all four snatchings. "The Vigo has a hooter or police lights on its roof like a police mobile to pose as law-enforcement," he said. "They signaled the driver to stop, and when he pulled over the trailer, ten to twelve armed men in plainclothes surrounded the long vehicle and took the staff hostage at gunpoint."
One man in the gang is an expert driving long vehicles like car carriers. The gang first offloads the driver and puts him in their Vigo so that their man can take control of the steering. "They took the long vehicles to a deserted place where they offloaded all the four-wheelers but they keep the driver and other staff hostage until the snatched four-wheelers reach their destination." This takes a few days.
The first suspects were dacoits who roam the highway, but the Sindh police have ruled them out. "Dacoits of the Pakka area instead of the Kutcha are behind these highway snatchings," said Anti-Vehicle Lifting Cell (AVLC) SSP Bashir Ahmed Brohi.
The Balochistan police arrested a few of the gang members and recovered some of the snatched vehicles. "The remaining members of this gang moved on to Sindh and regrouped with some locals," he added. The police recovered one of the snatched four-wheelers in Dadu.
A top Sindh police officer said he strongly suspected that insiders were involved. The officer, who wished not to be named, told Samaa Digital that he had reason to believe this because in the last three months the car carrier operators had abandoned precautionary measures they followed, which was highly suspicious.
"Earlier the keys of the [four-wheel] vehicles loaded on car carriers were dispatched to the owners by courier," he explained. "But now many operators are transporting the vehicles with the car key."
Also, previously the vehicle's battery was removed before the car was loaded onto the carrier, but some operators have started loading vehicles with the battery.
Another trick was to remove the ramp from the carriers before they departed, so if anyone wanted to even take the cars, they wouldn't be able to get them off.
In two of the cases, the police found that the keys and battery were on the vehicles being transported and the carriers had their ramps as well.
IGP Mushtaq Mehar directed SSPs for Hyderabad, Mirpurkhas, Shaheed Benazirabad, Sukkur and Larkana to step up night patrols on the National and Indus highways.
Follow SAMAA English on Facebook, Twitter, and Instagram.


text:
February 25, 2014 by pmikhail1
MARSians Are The Best
You might argue that the extent and severity of our winter is no longer funny. We are happy (not really) for all the skiers out there but each day are hopeful spring will, well…spring. While you are waiting, consider the following developments on MARS.
Gear Orders are available through the SportLab and can be seen at the BLING section of this website. The first order will be going in soon so don't delay. Samples for sizing are available at the SportLab.
Memberships for Muskoka Algonquin Runners for 2014 are available now. Download registration form at membership tab, complete and pay at the SportLab. Noncompetitive memberships are only $20, the best deal in town.
The MARS Roadtrip to the Keybank Vermont City Marathon departs May 22 and returns May 25. Ten MARSians are so far heading to Vermont. The Marathon Relay lottery (2-5 person teams) closes February 28. Click here for details.
The MEC 2014 Race Series has been announced. Race dates are April 5, May 10, June 28, September 13 and October 25. The race distances vary from 5K to 1/2 Marathon and the cost is a reasonable $15. Many of the races are in the Orillia area. Details here.
MARS Training Runs continue this week with long run 12 noon from Tim Horton's on Highway 60 on Thursday and Saturday workout at 6:30 am (see Calendar tab for location). All are welcome.
The next Run To The Pub will be Thursday March 27. Meet at River Mill Park at 4:30 pm to run and/or 5:30 pm inside the Pub. New members are welcome. With any luck it will be sunny and warm.
Craftsbury High School Cross Country Running Camp is June 29 – July 5, with departure June 28 and return late July 5. There are still spaces left at the camp and room in our travel vans but spots are filling fast. If you are thinking about attending now is the time to act. Last year we had to turn away two runners who expressed their interest too late after camp had filled. This is an opportunity of a lifetime. Click here for details and email Pierre Mikhail with any questions. See what past attendees have to say:
"It was such a pleasure to spend the week with people who have a passion for running and a healthy lifestyle. Every day was exciting and always challenging and very rewarding. The entire camp staff was friendly and helpful. I love Craftsbury!"
"Craftsbury has enriched my life, not just my running. I love it. What a special place!"
It's time to meet our next MARSian….. Troy Cox has been running since before he could walk. Troy is Vice President of Muskoka Algonquin Runners and also supports the club with a generous donation from Pharmasave. It has been said by many that Troy is "talented". While that may be true, what is truer is the fact that he is a dedicated runner, following the 10,000 hours principle (or perhaps 10,000 miles) in achieving excellence. He earns every ounce of speed he has. Troy helped coach our Huntsville Hoyas Cross Country Team this past fall. At one particularly difficult practice, some teenaged boys were in awe of the speed of one of their coaches who they could not keep up with. Two boys were overheard having the following conversation:
Boy 1: :"Who is that old guy? He's really fast"
Boy 2: "I think he used to be Semi-Pro"
Troy's running accomplishments are too many to mention in their entirety here. He holds the Masters Record for the Goodlife Toronto Half Marathon at 1:12:42 in 2009. In 2007 he came 27th at the Ottawa Marathon in a time of 2:36 and change. If you think he's slowing down, think again. In 2013 Troy placed 7th overall in the Goodlife Toronto Marathon and first in his age group. Troy anchored the MARS Men's 40-49 team that won the 2013 Ontario Masters XC Championships in November 2013.
MARS has compiled some running essentials about Troy from the runners who know him best (Troy declined being interviewed for this post, asking "What's MARS?"). We made stuff up:
Nickname: "Semi-Pro"
Weaknesses: Hotel Bookings
Favourite Races: "Whatever I run because I always win"
Distances Run: "None of your business"
Career PR: "Tricking Doug into running The Run For The Doug…and beating him"
Pre Race Rituals: "Telling My Club mates that it's ok not to be as fast as me unless it makes us lose"
Training Strategy/Motto/Motivation: "If I can put up with those idiots all week I can do my real long run on Sunday. Damn they are slow. I try to run up and down on the spot but I think they notice….."
Favourite Quote: "Who Are You?"
Describe MARS in one word: "What's MARS?"
See you on the roads!
This entry was posted in Club Details, Hoyas, Masters Running, Races, Running Story, Scheduled Runs. Bookmark the permalink.
← The Wait On MARS Is Over!
MARS March Madness →


When we think of Maspalomas holidays, we think of affordable luxury in one of Gran Canaria's most picturesque resorts - we think you'll agree, too. Situated on the island's sun-soaked south coast, where you'll find glamorous beaches, stunning scenery and plenty of places to relax and unwind.
Here at Holiday Gems, we have a fantastic selection of holidays and cheap holiday deals to Maspalomas, with all inclusive and self catering breaks available in some of the island's best apartments and hotels. Book your Maspalomas holiday for 2019/2020 today, you won't be disappointed.
Maspalomas is a superb choice for your Canaries holiday. There's so many great reasons to visit this superb part of the island. If you're looking for a relaxing break that's both peaceful and laid-back, Maspalomas could be for you.
Book your 2019/2020 holiday to this popular Canaries beauty spot today.
As for the weather, Gran Canaria enjoys a sub-tropical climate that brings with it pleasantly mild winters and long hot summers. At the height of summer, you can expect the temperature to break into the high 20s and even into the early 30s. We've penned a brief overview below.
In January and February, rain is more prevalent in Maspalomas although you can still expect sunshine on some days. The temperature around this time is on average 18°C, making the island pleasantly warm.
In March and April, the temperature in Maspalomas increases to around 20 degrees. Any previous rain begins to ease off, making Easter a great time to visit.
In May, Maspalomas begins to really warm up with summer well and truly here. The temperature increases to around 23 degrees and can hit 25 on some days.
June, July and August in Maspalomas are a sun-seeker's dream! The temperature around this time of year sits comfortably between the mid to high 20s. As the summer progresses, you may find some days breaking the 30 mark.
In September and October, Maspalomas enjoys much of the same hot weather with the temperature still comfortably around 25 degrees.
In November and December, Maspalomas begins to cool down ever so slightly. 20 and 18°C are now more common for this time of year.
Far from some of Gran Canaria's more action-packed resorts, life in Maspalomas is relaxed and easygoing. That being said, there's still a great deal of activities to keep you entertained during your stay. Read on to find out more.
Sunbathing is usually be top of every holidaymakers list. Maspalomas first-rate beach is the ideal place to top up your tan and relax.
You don't have to travel to Africa to see the desert. Gran Canaria boasts expansive desert plains, which can be explored on a 4x4 tour or camel ride.
If you're a keen golfer, you're in luck! Maspalomas boasts a fabulous 18 hole golf course with beautiful views of the surrounding region.
You'll find loads of great restaurants and bars around Maspalomas if you're looking for a night out. Alternatively, why not take a trip to the neighbouring resort of Playa del Ingles where you'll find a greater selection of nightclubs and bars.
Flights to Gran Canaria take approximately 4 hours and 40 minutes. You can pick up a flight from most major UK airports, including Bristol, Birmingham, Leeds Bradford, Doncaster Sheffield, Liverpool, Manchester, London airports, Newcastle, Belfast, Edinburgh, Glasgow and more.


You won't believe how easy life is in this delightful 1 bedroom, 2 bathroom villa. Open and airy with lots of storage space plus a separate 9 x 7 office, 2 walk in closets, easy care floors, step saving kitchen. The enclosed Florida Room leads you to an open patio overlooking a vast green area. Better yet, you'll be living in a friendly community with pool, club house and shuffle board only a short drive to the beach, shopping & freeways. Start enjoying life today.


John K. Park, M.D., M.Sc.
Dr. Bill Meyer is a physician with Carolina Conceptions. He is board certified in Obstetrics and Gynecology as well as eproductive Endocrinology and Infertility.
David K. Walmer, M.D., Ph.D.
Dr. Mark Fritz is board certified in both Obstetrics and Gynecology and in Reproductive Endocrinology and Infertility, and directs both the Assisted Reproductive Technologies program and fellowship training program at UNC.
Sameh Toma, M.D., F.A.C.O.G., is a fertility doctor at North Carolina Center for Reproductive Medicine, who specializes in Tubal Reversal Surgery and In Vitro Fertilization.
Dr. Hurd is board certified in obstetrics and gynecology with subspecialty certification in reproductive endocrinology and infertility. For almost two decades, he has been an active clinician and researcher focusing on reproductive endocrinology.