{
    "add": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    res = 0\n    for v in args:\n        v = float(v if v and v != 'None' else 0)\n        res += v\n    return str(res)\n",
    "and": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    i = 0\n    while i < len(args):\n        if not args[i]:\n            return ''\n        i += 1\n    return '1'\n",
    "approximate_formats": "def evaluate(self, formatter, kwargs, mi, locals):\n    if hasattr(mi, '_proxy_metadata'):\n        fmt_data = mi._proxy_metadata.db_approx_formats\n        if not fmt_data:\n            return ''\n        data = sorted(fmt_data)\n        return ','.join(v.upper() for v in data)\n    self.only_in_gui_error()\n",
    "arguments": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    # The arguments function is implemented in-line in the formatter\n    raise NotImplementedError()\n",
    "assign": "def evaluate(self, formatter, kwargs, mi, locals, target, value):\n    locals[target] = value\n    return value\n",
    "author_links": "def evaluate(self, formatter, kwargs, mi, locals, val_sep, pair_sep):\n    if hasattr(mi, '_proxy_metadata'):\n        link_data = mi._proxy_metadata.link_maps\n        if not link_data:\n            return ''\n        link_data = link_data.get('authors')\n        if not link_data:\n            return ''\n        names = sorted(link_data.keys(), key=sort_key)\n        return pair_sep.join(n + val_sep + link_data[n] for n in names)\n    self.only_in_gui_error()\n",
    "author_sorts": "def evaluate(self, formatter, kwargs, mi, locals, val_sep):\n    sort_data = mi.author_sort_map\n    if not sort_data:\n        return ''\n    names = [sort_data.get(n) for n in mi.authors if n.strip()]\n    return val_sep.join(n for n in names)\n",
    "book_count": "def evaluate(self, formatter, kwargs, mi, locals, query, use_vl):\n    from calibre.db.fields import rendering_composite_name\n    if (not tweaks.get('allow_template_database_functions_in_composites', False) and\n            formatter.global_vars.get(rendering_composite_name, None)):\n        raise ValueError(_('The book_count() function cannot be used in a composite column'))\n    db = self.get_database(mi)\n    try:\n        ids = db.search_getting_ids(query, None, use_virtual_library=use_vl != '0')\n        return len(ids)\n    except Exception:\n        traceback.print_exc()\n",
    "book_values": "def evaluate(self, formatter, kwargs, mi, locals, column, query, sep, use_vl):\n    from calibre.db.fields import rendering_composite_name\n    if (not tweaks.get('allow_template_database_functions_in_composites', False) and\n            formatter.global_vars.get(rendering_composite_name, None)):\n        raise ValueError(_('The book_values() function cannot be used in a composite column'))\n    db = self.get_database(mi)\n    if column not in db.field_metadata:\n        raise ValueError(_(\"The column {} doesn't exist\").format(column))\n    try:\n        ids = db.search_getting_ids(query, None, use_virtual_library=use_vl != '0')\n        s = set()\n        for id_ in ids:\n            f = db.new_api.get_proxy_metadata(id_).get(column, None)\n            if isinstance(f, (tuple, list)):\n                s.update(f)\n            elif f:\n                s.add(str(f))\n        return sep.join(s)\n    except Exception as e:\n        raise ValueError(e)\n",
    "booksize": "def evaluate(self, formatter, kwargs, mi, locals):\n    if hasattr(mi, '_proxy_metadata'):\n        try:\n            v = mi._proxy_metadata.book_size\n            if v is not None:\n                return str(mi._proxy_metadata.book_size)\n            return ''\n        except:\n            pass\n        return ''\n    self.only_in_gui_error()\n",
    "capitalize": "def evaluate(self, formatter, kwargs, mi, locals, val):\n    return capitalize(val)\n",
    "character": "def evaluate(self, formatter, kwargs, mi, locals, character_name):\n    # The globals function is implemented in-line in the formatter\n    raise NotImplementedError()\n",
    "check_yes_no": "def evaluate(self, formatter, kwargs, mi, locals, field, is_undefined, is_false, is_true):\n    # 'field' is a lookup name, not a value\n    if field not in self.get_database(mi).field_metadata:\n        raise ValueError(_(\"The column {} doesn't exist\").format(field))\n    res = getattr(mi, field, None)\n    if res is None:\n        if is_undefined == '1':\n            return 'yes'\n        return \"\"\n    if not isinstance(res, bool):\n        raise ValueError(_('check_yes_no requires the field be a Yes/No custom column'))\n    if is_false == '1' and not res:\n        return 'yes'\n    if is_true == '1' and res:\n        return 'yes'\n    return \"\"\n",
    "ceiling": "def evaluate(self, formatter, kwargs, mi, locals, x):\n    x = float(x if x and x != 'None' else 0)\n    return str(int(ceil(x)))\n",
    "cmp": "def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):\n    x = float(x if x and x != 'None' else 0)\n    y = float(y if y and y != 'None' else 0)\n    if x < y:\n        return lt\n    if x == y:\n        return eq\n    return gt\n",
    "connected_device_name": "def evaluate(self, formatter, kwargs, mi, locals, storage_location):\n    # We can't use get_database() here because we need the device manager.\n    # In other words, the function really does need the GUI\n    with suppress(Exception):\n        # Do the import here so that we don't entangle the GUI when using\n        # command line functions\n        from calibre.gui2.ui import get_gui\n        info = get_gui().device_manager.get_current_device_information()\n        if info is None:\n            return ''\n        try:\n            if storage_location not in {'main', 'carda', 'cardb'}:\n                raise ValueError(\n                     _('connected_device_name: invalid storage location \"{}\"'\n                                .format(storage_location)))\n            info = info['info'][4]\n            if storage_location not in info:\n                return ''\n            return info[storage_location]['device_name']\n        except Exception:\n            traceback.print_exc()\n            raise\n    self.only_in_gui_error()\n",
    "connected_device_uuid": "def evaluate(self, formatter, kwargs, mi, locals, storage_location):\n    # We can't use get_database() here because we need the device manager.\n    # In other words, the function really does need the GUI\n    with suppress(Exception):\n        # Do the import here so that we don't entangle the GUI when using\n        # command line functions\n        from calibre.gui2.ui import get_gui\n        info = get_gui().device_manager.get_current_device_information()\n        if info is None:\n            return ''\n        try:\n            if storage_location not in {'main', 'carda', 'cardb'}:\n                raise ValueError(\n                     _('connected_device_name: invalid storage location \"{}\"'\n                                .format(storage_location)))\n            info = info['info'][4]\n            if storage_location not in info:\n                return ''\n            return info[storage_location]['device_store_uuid']\n        except Exception:\n            traceback.print_exc()\n            raise\n    self.only_in_gui_error()\n",
    "contains": "def evaluate(self, formatter, kwargs, mi, locals,\n             val, test, value_if_present, value_if_not):\n    if re.search(test, val, flags=re.I):\n        return value_if_present\n    else:\n        return value_if_not\n",
    "count": "def evaluate(self, formatter, kwargs, mi, locals, val, sep):\n    return str(len([v for v in val.split(sep) if v]))\n",
    "current_library_name": "def evaluate(self, formatter, kwargs, mi, locals):\n    from calibre.library import current_library_name\n    return current_library_name()\n",
    "current_library_path": "def evaluate(self, formatter, kwargs, mi, locals):\n    from calibre.library import current_library_path\n    return current_library_path()\n",
    "current_virtual_library_name": "def evaluate(self, formatter, kwargs, mi, locals):\n    return self.get_database(mi).data.get_base_restriction_name()\n",
    "date_arithmetic": "def evaluate(self, formatter, kwargs, mi, locals, date, calc_spec, fmt=None):\n    try:\n        d = parse_date(date)\n        if d == UNDEFINED_DATE:\n            return ''\n        while calc_spec:\n            mo = re.match(r'([-+\\d]+)([smhdwy])', calc_spec)\n            if mo is None:\n                raise ValueError(\n                    _(\"{0}: invalid calculation specifier '{1}'\").format(\n                        'date_arithmetic', calc_spec))\n            d += self.calc_ops[mo[2]](int(mo[1]))\n            calc_spec = calc_spec[len(mo[0]):]\n        return format_date(d, fmt if fmt else 'iso')\n    except ValueError as e:\n        raise e\n    except Exception as e:\n        traceback.print_exc()\n        raise ValueError(_(\"{0}: error: {1}\").format('date_arithmetic', str(e)))\n",
    "days_between": "def evaluate(self, formatter, kwargs, mi, locals, date1, date2):\n    try:\n        d1 = parse_date(date1)\n        if d1 == UNDEFINED_DATE:\n            return ''\n        d2 = parse_date(date2)\n        if d2 == UNDEFINED_DATE:\n            return ''\n    except:\n        return ''\n    i = d1 - d2\n    return '%.1f'%(i.days + (i.seconds/(24.0*60.0*60.0)))\n",
    "divide": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n    x = float(x if x and x != 'None' else 0)\n    y = float(y if y and y != 'None' else 0)\n    return str(x / y)\n",
    "eval": "def evaluate(self, formatter, kwargs, mi, locals, template):\n    from calibre.utils.formatter import EvalFormatter\n    template = template.replace('[[', '{').replace(']]', '}')\n    return EvalFormatter().safe_format(template, locals, 'EVAL', None)\n",
    "first_non_empty": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    i = 0\n    while i < len(args):\n        if args[i]:\n            return args[i]\n        i += 1\n    return ''\n",
    "field": "def evaluate(self, formatter, kwargs, mi, locals, name):\n    return formatter.get_value(name, [], kwargs)\n",
    "field_exists": "def evaluate(self, formatter, kwargs, mi, locals, field_name):\n    if field_name.lower() in mi.all_field_keys():\n        return '1'\n    return ''\n",
    "finish_formatting": "def evaluate(self, formatter, kwargs, mi, locals_, val, fmt, prefix, suffix):\n    if not val:\n        return val\n    return prefix + formatter._do_format(val, fmt) + suffix\n",
    "first_matching_cmp": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    if (len(args) % 2) != 0:\n        raise ValueError(_('first_matching_cmp requires an even number of arguments'))\n    val = float(args[0] if args[0] and args[0] != 'None' else 0)\n    for i in range(1, len(args) - 1, 2):\n        c = float(args[i] if args[i] and args[i] != 'None' else 0)\n        if val < c:\n            return args[i+1]\n    return args[len(args)-1]\n",
    "floor": "def evaluate(self, formatter, kwargs, mi, locals, x):\n    x = float(x if x and x != 'None' else 0)\n    return str(int(floor(x)))\n",
    "format_date": "def evaluate(self, formatter, kwargs, mi, locals, val, format_string):\n    if not val or val == 'None':\n        return ''\n    try:\n        if format_string == 'to_number':\n            s = parse_date(val).timestamp()\n        elif format_string.startswith('from_number'):\n            val = datetime.fromtimestamp(float(val))\n            f = format_string[12:]\n            s = format_date(val, f if f else 'iso')\n        else:\n            s = format_date(parse_date(val), format_string)\n        return s\n    except:\n        s = 'BAD DATE'\n    return s\n",
    "format_number": "def evaluate(self, formatter, kwargs, mi, locals, val, template):\n    if val == '' or val == 'None':\n        return ''\n    if '{' not in template:\n        template = '{0:' + template + '}'\n    try:\n        v1 = float(val)\n    except:\n        return ''\n    try:  # Try formatting the value as a float\n        return template.format(v1)\n    except:\n        pass\n    try:  # Try formatting the value as an int\n        v2 = trunc(v1)\n        if v2 == v1:\n            return template.format(v2)\n    except:\n        pass\n    return ''\n",
    "formats_modtimes": "def evaluate(self, formatter, kwargs, mi, locals, fmt):\n    fmt_data = mi.get('format_metadata', {})\n    try:\n        data = sorted(fmt_data.items(), key=lambda x:x[1]['mtime'], reverse=True)\n        return ','.join(k.upper()+':'+format_date(v['mtime'], fmt)\n                    for k,v in data)\n    except:\n        return ''\n",
    "formats_paths": "def evaluate(self, formatter, kwargs, mi, locals):\n    fmt_data = mi.get('format_metadata', {})\n    try:\n        return ','.join(k.upper()+':'+str(v['path']) for k,v in iteritems(fmt_data))\n    except:\n        return ''\n",
    "formats_sizes": "def evaluate(self, formatter, kwargs, mi, locals):\n    fmt_data = mi.get('format_metadata', {})\n    try:\n        return ','.join(k.upper()+':'+str(v['size']) for k,v in iteritems(fmt_data))\n    except:\n        return ''\n",
    "fractional_part": "def evaluate(self, formatter, kwargs, mi, locals, x):\n    x = float(x if x and x != 'None' else 0)\n    return str(modf(x)[0])\n",
    "globals": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    # The globals function is implemented in-line in the formatter\n    raise NotImplementedError()\n",
    "has_cover": "def evaluate(self, formatter, kwargs, mi, locals):\n    if mi.has_cover:\n        return _('Yes')\n    return ''\n",
    "human_readable": "def evaluate(self, formatter, kwargs, mi, locals, val):\n    try:\n        return human_readable(round(float(val)))\n    except:\n        return ''\n",
    "identifier_in_list": "def evaluate(self, formatter, kwargs, mi, locals, val, ident, fv, nfv):\n    l = [v.strip() for v in val.split(',') if v.strip()]\n    (id, _, regexp) = ident.partition(':')\n    if not id:\n        return nfv\n    id += ':'\n    if l:\n        for v in l:\n            if v.startswith(id):\n                if not regexp or re.search(regexp, v[len(id):], flags=re.I):\n                    return fv\n    return nfv\n",
    "ifempty": "def evaluate(self, formatter, kwargs, mi, locals, val, value_if_empty):\n    if val:\n        return val\n    else:\n        return value_if_empty\n",
    "language_codes": "def evaluate(self, formatter, kwargs, mi, locals, lang_strings):\n    retval = []\n    for c in [c.strip() for c in lang_strings.split(',') if c.strip()]:\n        try:\n            cv = canonicalize_lang(c)\n            if cv:\n                retval.append(canonicalize_lang(cv))\n        except:\n            pass\n    return ', '.join(retval)\n",
    "language_strings": "def evaluate(self, formatter, kwargs, mi, locals, lang_codes, localize):\n    retval = []\n    for c in [c.strip() for c in lang_codes.split(',') if c.strip()]:\n        try:\n            n = calibre_langcode_to_name(c, localize != '0')\n            if n:\n                retval.append(n)\n        except:\n            pass\n    return ', '.join(retval)\n",
    "in_list": "def evaluate(self, formatter, kwargs, mi, locals, val, sep, *args):\n    if (len(args) % 2) != 1:\n        raise ValueError(_('in_list requires an odd number of arguments'))\n    l = [v.strip() for v in val.split(sep) if v.strip()]\n    i = 0\n    while i < len(args):\n        if i + 1 >= len(args):\n            return args[i]\n        sf = args[i]\n        fv = args[i+1]\n        if l:\n            for v in l:\n                if re.search(sf, v, flags=re.I):\n                    return fv\n        i += 2\n",
    "is_marked": "def evaluate(self, formatter, kwargs, mi, locals):\n    c = self.get_database(mi).data.get_marked(mi.id)\n    return c if c else ''\n",
    "list_count_matching": "def evaluate(self, formatter, kwargs, mi, locals, list_, pattern, sep):\n    res = 0\n    for v in [x.strip() for x in list_.split(sep) if x.strip()]:\n        if re.search(pattern, v, flags=re.I):\n            res += 1\n    return str(res)\n",
    "list_difference": "def evaluate(self, formatter, kwargs, mi, locals, list1, list2, separator):\n    l1 = [l.strip() for l in list1.split(separator) if l.strip()]\n    l2 = {icu_lower(l.strip()) for l in list2.split(separator) if l.strip()}\n    res = []\n    for i in l1:\n        if icu_lower(i) not in l2 and i not in res:\n            res.append(i)\n    if separator == ',':\n        return ', '.join(res)\n    return separator.join(res)\n",
    "list_equals": "def evaluate(self, formatter, kwargs, mi, locals, list1, sep1, list2, sep2, yes_val, no_val):\n    s1 = {icu_lower(l.strip()) for l in list1.split(sep1) if l.strip()}\n    s2 = {icu_lower(l.strip()) for l in list2.split(sep2) if l.strip()}\n    if s1 == s2:\n        return yes_val\n    return no_val\n",
    "list_intersection": "def evaluate(self, formatter, kwargs, mi, locals, list1, list2, separator):\n    l1 = [l.strip() for l in list1.split(separator) if l.strip()]\n    l2 = {icu_lower(l.strip()) for l in list2.split(separator) if l.strip()}\n    res = []\n    for i in l1:\n        if icu_lower(i) in l2 and i not in res:\n            res.append(i)\n    if separator == ',':\n        return ', '.join(res)\n    return separator.join(res)\n",
    "list_item": "def evaluate(self, formatter, kwargs, mi, locals, val, index, sep):\n    if not val:\n        return ''\n    index = int(index)\n    val = val.split(sep)\n    try:\n        return val[index].strip()\n    except:\n        return ''\n",
    "list_join": "def evaluate(self, formatter, kwargs, mi, locals, with_separator, *args):\n    if len(args) % 2 != 0:\n        raise ValueError(\n            _(\"Invalid 'List, separator' pairs. Every list must have one \"\n              \"associated separator\"))\n    # Starting in python 3.7 dicts preserve order so we don't need OrderedDict\n    result = dict()\n    i = 0\n    while i < len(args):\n        lst = [v.strip() for v in args[i].split(args[i+1]) if v.strip()]\n        result.update({item.lower():item for item in lst})\n        i += 2\n    return with_separator.join(result.values())\n",
    "list_re": "def evaluate(self, formatter, kwargs, mi, locals, src_list, separator, include_re, opt_replace):\n    l = [l.strip() for l in src_list.split(separator) if l.strip()]\n    res = []\n    for item in l:\n        if re.search(include_re, item, flags=re.I) is not None:\n            if opt_replace:\n                item = re.sub(include_re, opt_replace, item)\n            for i in [t.strip() for t in item.split(separator) if t.strip()]:\n                if i not in res:\n                    res.append(i)\n    if separator == ',':\n        return ', '.join(res)\n    return separator.join(res)\n",
    "list_re_group": "def evaluate(self, formatter, kwargs, mi, locals, src_list, separator, include_re,\n             search_re, *args):\n    from calibre.utils.formatter import EvalFormatter\n    l = [l.strip() for l in src_list.split(separator) if l.strip()]\n    res = []\n    for item in l:\n        def repl(mo):\n            newval = ''\n            if mo and mo.lastindex:\n                for dex in range(0, mo.lastindex):\n                    gv = mo.group(dex+1)\n                    if gv is None:\n                        continue\n                    if len(args) > dex:\n                        template = args[dex].replace('[[', '{').replace(']]', '}')\n                        newval += EvalFormatter().safe_format(template, {'$': gv},\n                                          'EVAL', None, strip_results=False)\n                    else:\n                        newval += gv\n            return newval\n        if re.search(include_re, item, flags=re.I) is not None:\n            item = re.sub(search_re, repl, item, flags=re.I)\n            for i in [t.strip() for t in item.split(separator) if t.strip()]:\n                if i not in res:\n                    res.append(i)\n    if separator == ',':\n        return ', '.join(res)\n    return separator.join(res)\n",
    "list_remove_duplicates": "def evaluate(self, formatter, kwargs, mi, locals, list_, separator):\n    res = {icu_lower(l.strip()): l.strip() for l in list_.split(separator) if l.strip()}\n    if separator == ',':\n        separator = ', '\n    return separator.join(res.values())\n",
    "list_sort": "def evaluate(self, formatter, kwargs, mi, locals, list1, direction, separator):\n    res = [l.strip() for l in list1.split(separator) if l.strip()]\n    if separator == ',':\n        return ', '.join(sorted(res, key=sort_key, reverse=direction != \"0\"))\n    return separator.join(sorted(res, key=sort_key, reverse=direction != \"0\"))\n",
    "list_split": "def evaluate(self, formatter, kwargs, mi, locals, list_val, sep, id_prefix):\n    l = [v.strip() for v in list_val.split(sep)]\n    res = ''\n    for i,v in enumerate(l):\n        res = locals[id_prefix+'_'+str(i)] = v\n    return res\n",
    "list_union": "def evaluate(self, formatter, kwargs, mi, locals, list1, list2, separator):\n    res = {icu_lower(l.strip()): l.strip() for l in list2.split(separator) if l.strip()}\n    res.update({icu_lower(l.strip()): l.strip() for l in list1.split(separator) if l.strip()})\n    if separator == ',':\n        separator = ', '\n    return separator.join(res.values())\n",
    "lookup": "def evaluate(self, formatter, kwargs, mi, locals, val, *args):\n    if len(args) == 2:  # here for backwards compatibility\n        if val:\n            return formatter.vformat('{'+args[0].strip()+'}', [], kwargs)\n        else:\n            return formatter.vformat('{'+args[1].strip()+'}', [], kwargs)\n    if (len(args) % 2) != 1:\n        raise ValueError(_('lookup requires either 2 or an odd number of arguments'))\n    i = 0\n    while i < len(args):\n        if i + 1 >= len(args):\n            return formatter.vformat('{' + args[i].strip() + '}', [], kwargs)\n        if re.search(args[i], val, flags=re.I):\n            return formatter.vformat('{'+args[i+1].strip() + '}', [], kwargs)\n        i += 2\n",
    "lowercase": "def evaluate(self, formatter, kwargs, mi, locals, val):\n    return val.lower()\n",
    "mod": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n    x = float(x if x and x != 'None' else 0)\n    y = float(y if y and y != 'None' else 0)\n    return str(int(x % y))\n",
    "multiply": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    res = 1\n    for v in args:\n        v = float(v if v and v != 'None' else 0)\n        res *= v\n    return str(res)\n",
    "not": "def evaluate(self, formatter, kwargs, mi, locals, val):\n    return '' if val else '1'\n",
    "ondevice": "def evaluate(self, formatter, kwargs, mi, locals):\n    if hasattr(mi, '_proxy_metadata'):\n        if mi._proxy_metadata.ondevice_col:\n            return _('Yes')\n        return ''\n    self.only_in_gui_error()\n",
    "or": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    i = 0\n    while i < len(args):\n        if args[i]:\n            return '1'\n        i += 1\n    return ''\n",
    "print": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    print(args)\n    return ''\n",
    "rating_to_stars": "def evaluate(self, formatter, kwargs, mi, locals, value, use_half_stars):\n    if not value:\n        return ''\n    err_msg = _('The rating must be a number between 0 and 5')\n    try:\n        v = float(value) * 2\n    except:\n        raise ValueError(err_msg)\n    if v < 0 or v > 10:\n        raise ValueError(err_msg)\n    from calibre.ebooks.metadata import rating_to_stars\n    return rating_to_stars(v, use_half_stars == '1')\n",
    "range": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    limit_val = 1000\n    start_val = 0\n    step_val = 1\n    if len(args) == 1:\n        stop_val = int(args[0] if args[0] and args[0] != 'None' else 0)\n    elif len(args) == 2:\n        start_val = int(args[0] if args[0] and args[0] != 'None' else 0)\n        stop_val = int(args[1] if args[1] and args[1] != 'None' else 0)\n    elif len(args) >= 3:\n        start_val = int(args[0] if args[0] and args[0] != 'None' else 0)\n        stop_val = int(args[1] if args[1] and args[1] != 'None' else 0)\n        step_val = int(args[2] if args[2] and args[2] != 'None' else 0)\n        if len(args) > 3:\n            limit_val = int(args[3] if args[3] and args[3] != 'None' else 0)\n    r = range(start_val, stop_val, step_val)\n    if len(r) > limit_val:\n        raise ValueError(\n            _(\"{0}: length ({1}) longer than limit ({2})\").format(\n                        'range', len(r), str(limit_val)))\n    return ', '.join([str(v) for v in r])\n",
    "raw_field": "def evaluate(self, formatter, kwargs, mi, locals, name, default=None):\n    res = getattr(mi, name, None)\n    if res is None and default is not None:\n        return default\n    if isinstance(res, list):\n        fm = mi.metadata_for_field(name)\n        if fm is None:\n            return ', '.join(res)\n        return fm['is_multiple']['list_to_ui'].join(res)\n    return str(res)\n",
    "raw_list": "def evaluate(self, formatter, kwargs, mi, locals, name, separator):\n    res = getattr(mi, name, None)\n    if not isinstance(res, list):\n        return \"%s is not a list\" % name\n    return separator.join(res)\n",
    "re": "def evaluate(self, formatter, kwargs, mi, locals, val, pattern, replacement):\n    return re.sub(pattern, replacement, val, flags=re.I)\n",
    "re_group": "def evaluate(self, formatter, kwargs, mi, locals, val, pattern, *args):\n    from calibre.utils.formatter import EvalFormatter\n    def repl(mo):\n        res = ''\n        if mo and mo.lastindex:\n            for dex in range(0, mo.lastindex):\n                gv = mo.group(dex+1)\n                if gv is None:\n                    continue\n                if len(args) > dex:\n                    template = args[dex].replace('[[', '{').replace(']]', '}')\n                    res += EvalFormatter().safe_format(template, {'$': gv},\n                                       'EVAL', None, strip_results=False)\n                else:\n                    res += gv\n        return res\n    return re.sub(pattern, repl, val, flags=re.I)\n",
    "round": "def evaluate(self, formatter, kwargs, mi, locals, x):\n    x = float(x if x and x != 'None' else 0)\n    return str(int(round(x)))\n",
    "select": "def evaluate(self, formatter, kwargs, mi, locals, val, key):\n    if not val:\n        return ''\n    vals = [v.strip() for v in val.split(',')]\n    tkey = key+':'\n    for v in vals:\n        if v.startswith(tkey):\n            return v[len(tkey):]\n    return ''\n",
    "series_sort": "def evaluate(self, formatter, kwargs, mi, locals):\n    if mi.series:\n        langs = mi.languages\n        lang = langs[0] if langs else None\n        return title_sort(mi.series, lang=lang)\n    return ''\n",
    "set_globals": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    # The globals function is implemented in-line in the formatter\n    raise NotImplementedError()\n",
    "shorten": "def evaluate(self, formatter, kwargs, mi, locals,\n             val, leading, center_string, trailing):\n    l = max(0, int(leading))\n    t = max(0, int(trailing))\n    if len(val) > l + len(center_string) + t:\n        return val[0:l] + center_string + ('' if t == 0 else val[-t:])\n    else:\n        return val\n",
    "strcat": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    i = 0\n    res = ''\n    for i in range(0, len(args)):\n        res += args[i]\n    return res\n",
    "strcat_max": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    if len(args) < 2:\n        raise ValueError(_('strcat_max requires 2 or more arguments'))\n    if (len(args) % 2) != 0:\n        raise ValueError(_('strcat_max requires an even number of arguments'))\n    try:\n        max = int(args[0])\n    except:\n        raise ValueError(_('first argument to strcat_max must be an integer'))\n    i = 2\n    result = args[1]\n    try:\n        while i < len(args):\n            if (len(result) + len(args[i]) + len(args[i+1])) > max:\n                break\n            result = result + args[i] + args[i+1]\n            i += 2\n    except:\n        pass\n    return result.strip()\n",
    "strcmp": "def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):\n    v = strcmp(x, y)\n    if v < 0:\n        return lt\n    if v == 0:\n        return eq\n    return gt\n",
    "strcmpcase": "def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):\n    from calibre.utils.icu import case_sensitive_strcmp as case_strcmp\n    v = case_strcmp(x, y)\n    if v < 0:\n        return lt\n    if v == 0:\n        return eq\n    return gt\n",
    "str_in_list": "def evaluate(self, formatter, kwargs, mi, locals, val, sep, *args):\n    if (len(args) % 2) != 1:\n        raise ValueError(_('str_in_list requires an odd number of arguments'))\n    l = [v.strip() for v in val.split(sep) if v.strip()]\n    i = 0\n    while i < len(args):\n        if i + 1 >= len(args):\n            return args[i]\n        sf = args[i]\n        fv = args[i+1]\n        c = [v.strip() for v in sf.split(sep) if v.strip()]\n        if l:\n            for v in l:\n                for t in c:\n                    if strcmp(t, v) == 0:\n                        return fv\n        i += 2\n",
    "strlen": "def evaluate(self, formatter, kwargs, mi, locals, a):\n    try:\n        return len(a)\n    except:\n        return -1\n",
    "subitems": "def evaluate(self, formatter, kwargs, mi, locals, val, start_index, end_index):\n    if not val:\n        return ''\n    si = int(start_index)\n    ei = int(end_index)\n    has_periods = '.' in val\n    items = [v.strip() for v in val.split(',') if v.strip()]\n    rv = set()\n    for item in items:\n        if has_periods and '.' in item:\n            components = self.period_pattern.split(item)\n        else:\n            components = [item]\n        try:\n            if ei == 0:\n                t = '.'.join(components[si:]).strip()\n            else:\n                t = '.'.join(components[si:ei]).strip()\n            if t:\n                rv.add(t)\n        except:\n            pass\n    return ', '.join(sorted(rv, key=sort_key))\n",
    "sublist": "def evaluate(self, formatter, kwargs, mi, locals, val, start_index, end_index, sep):\n    if not val:\n        return ''\n    si = int(start_index)\n    ei = int(end_index)\n    # allow empty list items so counts are what the user expects\n    val = [v.strip() for v in val.split(sep)]\n    if sep == ',':\n        sep = ', '\n    try:\n        if ei == 0:\n            return sep.join(val[si:])\n        else:\n            return sep.join(val[si:ei])\n    except:\n        return ''\n",
    "substr": "def evaluate(self, formatter, kwargs, mi, locals, str_, start_, end_):\n    return str_[int(start_): len(str_) if int(end_) == 0 else int(end_)]\n",
    "subtract": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n    x = float(x if x and x != 'None' else 0)\n    y = float(y if y and y != 'None' else 0)\n    return str(x - y)\n",
    "swap_around_articles": "def evaluate(self, formatter, kwargs, mi, locals, val, separator):\n    if not val:\n        return ''\n    if not separator:\n        return title_sort(val).replace(',', ';')\n    result = []\n    try:\n        for v in [x.strip() for x in val.split(separator)]:\n            result.append(title_sort(v).replace(',', ';'))\n    except:\n        traceback.print_exc()\n    return separator.join(sorted(result, key=sort_key))\n",
    "swap_around_comma": "def evaluate(self, formatter, kwargs, mi, locals, val):\n    return re.sub(r'^(.*?),\\s*(.*$)', r'\\2 \\1', val, flags=re.I).strip()\n",
    "switch": "def evaluate(self, formatter, kwargs, mi, locals, val, *args):\n    if (len(args) % 2) != 1:\n        raise ValueError(_('switch requires an even number of arguments'))\n    i = 0\n    while i < len(args):\n        if i + 1 >= len(args):\n            return args[i]\n        if re.search(args[i], val, flags=re.I):\n            return args[i+1]\n        i += 2\n",
    "switch_if": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n    if (len(args) % 2) != 1:\n        raise ValueError(_('switch_if requires an odd number of arguments'))\n    # We shouldn't get here because the function is inlined. However, someone\n    # might call it directly.\n    i = 0\n    while i < len(args):\n        if i + 1 >= len(args):\n            return args[i]\n        if args[i]:\n            return args[i+1]\n        i += 2\n",
    "template": "def evaluate(self, formatter, kwargs, mi, locals, template):\n    template = template.replace('[[', '{').replace(']]', '}')\n    return formatter.__class__().safe_format(template, kwargs, 'TEMPLATE', mi)\n",
    "test": "def evaluate(self, formatter, kwargs, mi, locals, val, value_if_set, value_not_set):\n    if val:\n        return value_if_set\n    else:\n        return value_not_set\n",
    "titlecase": "def evaluate(self, formatter, kwargs, mi, locals, val):\n    return titlecase(val)\n",
    "today": "def evaluate(self, formatter, kwargs, mi, locals):\n    return format_date(now(), 'iso')\n",
    "to_hex": "def evaluate(self, formatter, kwargs, mi, locals, val):\n    return val.encode().hex()\n",
    "transliterate": "def evaluate(self, formatter, kwargs, mi, locals, source):\n    from calibre.utils.filenames import ascii_text\n    return ascii_text(source)\n",
    "uppercase": "def evaluate(self, formatter, kwargs, mi, locals, val):\n    return val.upper()\n",
    "urls_from_identifiers": "def evaluate(self, formatter, kwargs, mi, locals, identifiers, sort_results):\n    from calibre.ebooks.metadata.sources.identify import urls_from_identifiers\n    try:\n        v = {}\n        for id_ in identifiers.split(','):\n            if id_:\n                pair = id_.split(':', maxsplit=1)\n                if len(pair) == 2:\n                    l = pair[0].strip()\n                    r = pair[1].strip()\n                    if l and r:\n                        v[l] = r\n        urls = urls_from_identifiers(v, sort_results=str(sort_results) != '0')\n        p = prepare_string_for_xml\n        a = partial(prepare_string_for_xml, attribute=True)\n        links = [f'<a href=\"{a(url)}\" title=\"{a(id_typ)}:{a(id_val)}\">{p(name)}</a>'\n            for name, id_typ, id_val, url in urls]\n        return ', '.join(links)\n    except Exception as e:\n        return str(e)\n",
    "user_categories": "def evaluate(self, formatter, kwargs, mi, locals_):\n    if hasattr(mi, '_proxy_metadata'):\n        cats = {k for k, v in iteritems(mi._proxy_metadata.user_categories) if v}\n        cats = sorted(cats, key=sort_key)\n        return ', '.join(cats)\n    self.only_in_gui_error()\n",
    "virtual_libraries": "def evaluate(self, formatter, kwargs, mi, locals_):\n    db = self.get_database(mi)\n    try:\n        a = db.data.get_virtual_libraries_for_books((mi.id,))\n        return ', '.join(a[mi.id])\n    except ValueError as v:\n        return str(v)\n",
    "annotation_count": "def evaluate(self, formatter, kwargs, mi, locals):\n    c = self.get_database(mi).new_api.annotation_count_for_book(mi.id)\n    return '' if c == 0 else str(c)\n"
}