text:
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <alloca.h>

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>

#if HAVE_PWD_H
# include <pwd.h>
#endif

#include <unistd.h>

#if HAVE_DIRENT_H
# include <dirent.h>
#endif

#if HAVE_DIRENT_H
# define HAVE_DIR 1
#else
# define HAVE_DIR 0
#endif

#include "closeout.h"
#include "error.h"
#include "error-progname.h"
#include "progname.h"
#include "relocatable.h"
#include "basename.h"
#include "c-strstr.h"
#include "c-strcase.h"
#include "message.h"
#include "read-catalog.h"
#include "read-po.h"
#include "read-properties.h"
#include "read-stringtable.h"
#include "write-catalog.h"
#include "write-po.h"
#include "write-properties.h"
#include "write-stringtable.h"
#include "color.h"
#include "po-charset.h"
#include "localcharset.h"
#include "localename.h"
#include "po-time.h"
#include "plural-table.h"
#include "lang-table.h"
#include "xalloc.h"
#include "xmalloca.h"
#include "concat-filename.h"
#include "xerror.h"
#include "xvasprintf.h"
#include "msgl-english.h"
#include "plural-count.h"
#include "spawn-pipe.h"
#include "wait-process.h"
#include "xsetenv.h"
#include "str-list.h"
#include "propername.h"
#include "gettext.h"

#define _(str) gettext (str)
#define N_(str) (str)

/* Get F_OK.  It is lacking from <fcntl.h> on Woe32.  */
#ifndef F_OK
# define F_OK 0
#endif

#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))

extern const char * _nl_expand_alias (const char *name);

/* Locale name.  */
static const char *locale;

/* Language (ISO-639 code) and optional territory (ISO-3166 code).  */
static const char *catalogname;

/* Language (ISO-639 code).  */
static const char *language;

/* If true, the user is not considered to be the translator.  */
static bool no_translator;

/* Long options.  */
static const struct option long_options[] =
{
  { "color", optional_argument, NULL, CHAR_MAX + 5 },
  { "help", no_argument, NULL, 'h' },
  { "input", required_argument, NULL, 'i' },
  { "locale", required_argument, NULL, 'l' },
  { "no-translator", no_argument, NULL, CHAR_MAX + 1 },
  { "no-wrap", no_argument, NULL, CHAR_MAX + 2 },
  { "output-file", required_argument, NULL, 'o' },
  { "properties-input", no_argument, NULL, 'P' },
  { "properties-output", no_argument, NULL, 'p' },
  { "stringtable-input", no_argument, NULL, CHAR_MAX + 3 },
  { "stringtable-output", no_argument, NULL, CHAR_MAX + 4 },
  { "style", required_argument, NULL, CHAR_MAX + 6 },
  { "version", no_argument, NULL, 'V' },
  { "width", required_argument, NULL, 'w' },
  { NULL, 0, NULL, 0 }
};

/* Forward declaration of local functions.  */
static void usage (int status)
#if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ >= 5) || __GNUC__ > 2)
     __attribute__ ((noreturn))
#endif
;
static const char *find_pot (void);
static const char *catalogname_for_locale (const char *locale);
static const char *language_of_locale (const char *locale);
static char *get_field (const char *header, const char *field);
static msgdomain_list_ty *fill_header (msgdomain_list_ty *mdlp);
static msgdomain_list_ty *update_msgstr_plurals (msgdomain_list_ty *mdlp);

int
main (int argc, char **argv)
{
  int opt;
  bool do_help;
  bool do_version;
  char *output_file;
  const char *input_file;
  msgdomain_list_ty *result;
  catalog_input_format_ty input_syntax = &input_format_po;
  catalog_output_format_ty output_syntax = &output_format_po;

  /* Set program name for messages.  */
  set_program_name (argv[0]);
  error_print_progname = maybe_print_progname;

#ifdef HAVE_SETLOCALE
  /* Set locale via LC_ALL.  */
  setlocale (LC_ALL, "");
#endif

  /* Set the text message domain.  */
  bindtextdomain (PACKAGE, relocate (LOCALEDIR));
  bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
  textdomain (PACKAGE);

  /* Ensure that write errors on stdout are detected.  */
  atexit (close_stdout);

  /* Set default values for variables.  */
  do_help = false;
  do_version = false;
  output_file = NULL;
  input_file = NULL;
  locale = NULL;

  while ((opt = getopt_long (argc, argv, "hi:l:o:pPVw:", long_options, NULL))
         != EOF)
    switch (opt)
      {
      case '\0':                /* Long option.  */
        break;

      case 'h':
        do_help = true;
        break;

      case 'i':
        if (input_file != NULL)
          {
            error (EXIT_SUCCESS, 0, _("at most one input file allowed"));
            usage (EXIT_FAILURE);
          }
        input_file = optarg;
        break;

      case 'l':
        locale = optarg;
        break;

      case 'o':
        output_file = optarg;
        break;

      case 'p':
        output_syntax = &output_format_properties;
        break;

      case 'P':
        input_syntax = &input_format_properties;
        break;

      case 'V':
        do_version = true;
        break;

      case 'w':
        {
          int value;
          char *endp;
          value = strtol (optarg, &endp, 10);
          if (endp != optarg)
            message_page_width_set (value);
        }
        break;

      case CHAR_MAX + 1:
        no_translator = true;
        break;

      case CHAR_MAX + 2: /* --no-wrap */
        message_page_width_ignore ();
        break;

      case CHAR_MAX + 3: /* --stringtable-input */
        input_syntax = &input_format_stringtable;
        break;

      case CHAR_MAX + 4: /* --stringtable-output */
        output_syntax = &output_format_stringtable;
        break;

      case CHAR_MAX + 5: /* --color */
        if (handle_color_option (optarg) || color_test_mode)
          usage (EXIT_FAILURE);
        break;

      case CHAR_MAX + 6: /* --style */
        handle_style_option (optarg);
        break;

      default:
        usage (EXIT_FAILURE);
        break;
      }

  /* Version information is requested.  */
  if (do_version)
    {
      printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
      /* xgettext: no-wrap */
      printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
This is free software: you are free to change and redistribute it.\n\
There is NO WARRANTY, to the extent permitted by law.\n\
"),
              "2001-2010");
      printf (_("Written by %s.\n"), proper_name ("Bruno Haible"));
      exit (EXIT_SUCCESS);
    }

  /* Help is requested.  */
  if (do_help)
    usage (EXIT_SUCCESS);

  /* Test for extraneous arguments.  */
  if (optind != argc)
    error (EXIT_FAILURE, 0, _("too many arguments"));

  /* Search for the input file.  */
  if (input_file == NULL)
    input_file = find_pot ();

  /* Determine target locale.  */
  if (locale == NULL)
    {
      locale = gl_locale_name (LC_MESSAGES, "LC_MESSAGES");
      if (strcmp (locale, "C") == 0)
        {
          multiline_error (xstrdup (""),
                           xstrdup (_("\
You are in a language indifferent environment.  Please set\n\
your LANG environment variable, as described in the ABOUT-NLS\n\
file.  This is necessary so you can test your translations.\n")));
          exit (EXIT_FAILURE);
        }
    }
  {
    const char *alias = _nl_expand_alias (locale);
    if (alias != NULL)
      locale = alias;
  }
  catalogname = catalogname_for_locale (locale);
  language = language_of_locale (locale);

  /* Default output file name is CATALOGNAME.po.  */
  if (output_file == NULL)
    {
      output_file = xasprintf ("%s.po", catalogname);

      /* But don't overwrite existing PO files.  */
      if (access (output_file, F_OK) == 0)
        {
          multiline_error (xstrdup (""),
                           xasprintf (_("\
Output file %s already exists.\n\
Please specify the locale through the --locale option or\n\
the output .po file through the --output-file option.\n"),
                                      output_file));
          exit (EXIT_FAILURE);
        }
    }

  /* Read input file.  */
  result = read_catalog_file (input_file, input_syntax);

  /* Fill the header entry.  */
  result = fill_header (result);

  /* Initialize translations.  */
  if (strcmp (language, "en") == 0)
    result = msgdomain_list_english (result);
  else
    result = update_msgstr_plurals (result);

  /* Write the modified message list out.  */
  msgdomain_list_print (result, output_file, output_syntax, true, false);

  if (!no_translator)
    fprintf (stderr, "\n");
  fprintf (stderr, _("Created %s.\n"), output_file);

  exit (EXIT_SUCCESS);
}

/* Display usage information and exit.  */
static void
usage (int status)
{
  if (status != EXIT_SUCCESS)
    fprintf (stderr, _("Try '%s --help' for more information.\n"),
             program_name);
  else
    {
      printf (_("\
Usage: %s [OPTION]\n\
"), program_name);
      printf ("\n");
      /* xgettext: no-wrap */
      printf (_("\
Creates a new PO file, initializing the meta information with values from the\n\
user's environment.\n\
"));
      printf ("\n");
      printf (_("\
Mandatory arguments to long options are mandatory for short options too.\n"));
      printf ("\n");
      printf (_("\
Input file location:\n"));
      printf (_("\
  -i, --input=INPUTFILE       input POT file\n"));
      printf (_("\
If no input file is given, the current directory is searched for the POT file.\n\
If it is -, standard input is read.\n"));
      printf ("\n");
      printf (_("\
Output file location:\n"));
      printf (_("\
  -o, --output-file=FILE      write output to specified PO file\n"));
      printf (_("\
If no output file is given, it depends on the --locale option or the user's\n\
locale setting.  If it is -, the results are written to standard output.\n"));
      printf ("\n");
      printf (_("\
Input file syntax:\n"));
      printf (_("\
  -P, --properties-input      input file is in Java .properties syntax\n"));
      printf (_("\
      --stringtable-input     input file is in NeXTstep/GNUstep .strings syntax\n"));
      printf ("\n");
      printf (_("\
Output details:\n"));
      printf (_("\
  -l, --locale=LL_CC          set target locale\n"));
      printf (_("\
      --no-translator         assume the PO file is automatically generated\n"));
      printf (_("\
      --color                 use colors and other text attributes always\n\
      --color=WHEN            use colors and other text attributes if WHEN.\n\
                              WHEN may be 'always', 'never', 'auto', or 'html'.\n"));
      printf (_("\
      --style=STYLEFILE       specify CSS style rule file for --color\n"));
      printf (_("\
  -p, --properties-output     write out a Java .properties file\n"));
      printf (_("\
      --stringtable-output    write out a NeXTstep/GNUstep .strings file\n"));
      printf (_("\
  -w, --width=NUMBER          set output page width\n"));
      printf (_("\
      --no-wrap               do not break long message lines, longer than\n\
                              the output page width, into several lines\n"));
      printf ("\n");
      printf (_("\
Informative output:\n"));
      printf (_("\
  -h, --help                  display this help and exit\n"));
      printf (_("\
  -V, --version               output version information and exit\n"));
      printf ("\n");
      /* TRANSLATORS: The placeholder indicates the bug-reporting address
         for this package.  Please add _another line_ saying
         "Report translation bugs to <...>\n" with the address for translation
         bugs (typically your translation team's web or email address).  */
      fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
             stdout);
    }

  exit (status);
}

/* Search for the POT file and return its name.  */
static const char *
find_pot ()
{
#if HAVE_DIR
  DIR *dirp;
  char *found = NULL;

  dirp = opendir (".");
  if (dirp != NULL)
    {
      for (;;)
        {
          struct dirent *dp;

          errno = 0;
          dp = readdir (dirp);
          if (dp != NULL)
            {
              const char *name = dp->d_name;
              size_t namlen = strlen (name);

              if (namlen > 4 && memcmp (name + namlen - 4, ".pot", 4) == 0)
                {
                  if (found == NULL)
                    found = xstrdup (name);
                  else
                    {
                      multiline_error (xstrdup (""),
                                       xstrdup (_("\
Found more than one .pot file.\n\
Please specify the input .pot file through the --input option.\n")));
                      usage (EXIT_FAILURE);
                    }
                }
            }
          else if (errno != 0)
            error (EXIT_FAILURE, errno, _("error reading current directory"));
          else
            break;
        }
      if (closedir (dirp))
        error (EXIT_FAILURE, errno, _("error reading current directory"));

      if (found != NULL)
        return found;
    }
#endif

  multiline_error (xstrdup (""),
                   xstrdup (_("\
Found no .pot file in the current directory.\n\
Please specify the input .pot file through the --input option.\n")));
  usage (EXIT_FAILURE);
  /* NOTREACHED */
  return NULL;
}

/* Return the gettext catalog name corresponding to a locale.  If the locale
   consists of a language and a territory, and the language is mainly spoken
   in that territory, the territory is removed from the locale name.
   For example, "de_DE" or "de_DE.ISO-8859-1" are simplified to "de",
   because the resulting catalog can be used as a default for all "de_XX",
   such as "de_AT".  */
static const char *
catalogname_for_locale (const char *locale)
{
  static const char *locales_with_principal_territory[] = {
                /* Language     Main territory */
    "ace_ID",   /* Achinese     Indonesia */
    "af_ZA",    /* Afrikaans    South Africa */
    "ak_GH",    /* Akan         Ghana */
    "am_ET",    /* Amharic      Ethiopia */
    "an_ES",    /* Aragonese    Spain */
    "ang_GB",   /* Old English  Britain */
    "arn_CL",   /* Mapudungun   Chile */
    "as_IN",    /* Assamese     India */
    "ast_ES",   /* Asturian     Spain */
    "av_RU",    /* Avaric       Russia */
    "awa_IN",   /* Awadhi       India */
    "az_AZ",    /* Azerbaijani  Azerbaijan */
    "ban_ID",   /* Balinese     Indonesia */
    "be_BY",    /* Belarusian   Belarus */
    "bej_SD",   /* Beja         Sudan */
    "bem_ZM",   /* Bemba        Zambia */
    "bg_BG",    /* Bulgarian    Bulgaria */
    "bho_IN",   /* Bhojpuri     India */
    "bik_PH",   /* Bikol        Philippines */
    "bin_NG",   /* Bini         Nigeria */
    "bm_ML",    /* Bambara      Mali */
    "bn_IN",    /* Bengali      India */
    "bo_CN",    /* Tibetan      China */
    "br_FR",    /* Breton       France */
    "bs_BA",    /* Bosnian      Bosnia */
    "bug_ID",   /* Buginese     Indonesia */
    "ca_ES",    /* Catalan      Spain */
    "ce_RU",    /* Chechen      Russia */
    "ceb_PH",   /* Cebuano      Philippines */
    "co_FR",    /* Corsican     France */
    "cr_CA",    /* Cree         Canada */
    /* Don't put "crh_UZ" or "crh_UA" here.  That would be asking for fruitless
       political discussion.  */
    "cs_CZ",    /* Czech        Czech Republic */
    "csb_PL",   /* Kashubian    Poland */
    "cy_GB",    /* Welsh        Britain */
    "da_DK",    /* Danish       Denmark */
    "de_DE",    /* German       Germany */
    "din_SD",   /* Dinka        Sudan */
    "doi_IN",   /* Dogri        India */
    "dsb_DE",   /* Lower Sorbian        Germany */
    "dv_MV",    /* Divehi       Maldives */
    "dz_BT",    /* Dzongkha     Bhutan */
    "ee_GH",    /* Éwé          Ghana */
    "el_GR",    /* Greek        Greece */
    /* Don't put "en_GB" or "en_US" here.  That would be asking for fruitless
       political discussion.  */
    "es_ES",    /* Spanish      Spain */
    "et_EE",    /* Estonian     Estonia */
    "fa_IR",    /* Persian      Iran */
    "fi_FI",    /* Finnish      Finland */
    "fil_PH",   /* Filipino     Philippines */
    "fj_FJ",    /* Fijian       Fiji */
    "fo_FO",    /* Faroese      Faeroe Islands */
    "fon_BJ",   /* Fon          Benin */
    "fr_FR",    /* French       France */
    "fur_IT",   /* Friulian     Italy */
    "fy_NL",    /* Western Frisian      Netherlands */
    "ga_IE",    /* Irish        Ireland */
    "gd_GB",    /* Scottish Gaelic      Britain */
    "gon_IN",   /* Gondi        India */
    "gsw_CH",   /* Swiss German Switzerland */
    "gu_IN",    /* Gujarati     India */
    "he_IL",    /* Hebrew       Israel */
    "hi_IN",    /* Hindi        India */
    "hil_PH",   /* Hiligaynon   Philippines */
    "hr_HR",    /* Croatian     Croatia */
    "hsb_DE",   /* Upper Sorbian        Germany */
    "ht_HT",    /* Haitian      Haiti */
    "hu_HU",    /* Hungarian    Hungary */
    "hy_AM",    /* Armenian     Armenia */
    "id_ID",    /* Indonesian   Indonesia */
    "ig_NG",    /* Igbo         Nigeria */
    "ii_CN",    /* Sichuan Yi   China */
    "ilo_PH",   /* Iloko        Philippines */
    "is_IS",    /* Icelandic    Iceland */
    "it_IT",    /* Italian      Italy */
    "ja_JP",    /* Japanese     Japan */
    "jab_NG",   /* Hyam         Nigeria */
    "jv_ID",    /* Javanese     Indonesia */
    "ka_GE",    /* Georgian     Georgia */
    "kab_DZ",   /* Kabyle       Algeria */
    "kaj_NG",   /* Jju          Nigeria */
    "kam_KE",   /* Kamba        Kenya */
    "kmb_AO",   /* Kimbundu     Angola */
    "kcg_NG",   /* Tyap         Nigeria */
    "kdm_NG",   /* Kagoma       Nigeria */
    "kg_CD",    /* Kongo        Democratic Republic of Congo */
    "kk_KZ",    /* Kazakh       Kazakhstan */
    "kl_GL",    /* Kalaallisut  Greenland */
    "km_KH",    /* Central Khmer        Cambodia */
    "kn_IN",    /* Kannada      India */
    "ko_KR",    /* Korean       Korea (South) */
    "kok_IN",   /* Konkani      India */
    "kr_NG",    /* Kanuri       Nigeria */
    "kru_IN",   /* Kurukh       India */
    "lg_UG",    /* Ganda        Uganda */
    "li_BE",    /* Limburgish   Belgium */
    "lo_LA",    /* Laotian      Laos */
    "lt_LT",    /* Lithuanian   Lithuania */
    "lu_CD",    /* Luba-Katanga Democratic Republic of Congo */
    "lua_CD",   /* Luba-Lulua   Democratic Republic of Congo */
    "luo_KE",   /* Luo          Kenya */
    "lv_LV",    /* Latvian      Latvia */
    "mad_ID",   /* Madurese     Indonesia */
    "mag_IN",   /* Magahi       India */
    "mai_IN",   /* Maithili     India */
    "mak_ID",   /* Makasar      Indonesia */
    "man_ML",   /* Mandingo     Mali */
    "men_SL",   /* Mende        Sierra Leone */
    "mg_MG",    /* Malagasy     Madagascar */
    "mi_NZ",    /* Maori        New Zealand */
    "min_ID",   /* Minangkabau  Indonesia */
    "mk_MK",    /* Macedonian   Macedonia */
    "ml_IN",    /* Malayalam    India */
    "mn_MN",    /* Mongolian    Mongolia */
    "mni_IN",   /* Manipuri     India */
    "mos_BF",   /* Mossi        Burkina Faso */
    "mr_IN",    /* Marathi      India */
    "ms_MY",    /* Malay        Malaysia */
    "mt_MT",    /* Maltese      Malta */
    "mwr_IN",   /* Marwari      India */
    "my_MM",    /* Burmese      Myanmar */
    "na_NR",    /* Nauru        Nauru */
    "nah_MX",   /* Nahuatl      Mexico */
    "nap_IT",   /* Neapolitan   Italy */
    "nb_NO",    /* Norwegian Bokmål    Norway */
    "nds_DE",   /* Low Saxon    Germany */
    "ne_NP",    /* Nepali       Nepal */
    "nl_NL",    /* Dutch        Netherlands */
    "nn_NO",    /* Norwegian Nynorsk    Norway */
    "no_NO",    /* Norwegian    Norway */
    "nr_ZA",    /* South Ndebele        South Africa */
    "nso_ZA",   /* Northern Sotho       South Africa */
    "nym_TZ",   /* Nyamwezi     Tanzania */
    "nyn_UG",   /* Nyankole     Uganda */
    "oc_FR",    /* Occitan      France */
    "oj_CA",    /* Ojibwa       Canada */
    "or_IN",    /* Oriya        India */
    "pa_IN",    /* Punjabi      India */
    "pag_PH",   /* Pangasinan   Philippines */
    "pam_PH",   /* Pampanga     Philippines */
    "pap_AN",   /* Papiamento   Netherlands Antilles */
    "pbb_CO",   /* Páez                Colombia */
    "pl_PL",    /* Polish       Poland */
    "ps_AF",    /* Pashto       Afghanistan */
    "pt_PT",    /* Portuguese   Portugal */
    "raj_IN",   /* Rajasthani   India */
    "rm_CH",    /* Romansh      Switzerland */
    "rn_BI",    /* Kirundi      Burundi */
    "ro_RO",    /* Romanian     Romania */
    "ru_RU",    /* Russian      Russia */
    "sa_IN",    /* Sanskrit     India */
    "sah_RU",   /* Yakut        Russia */
    "sas_ID",   /* Sasak        Indonesia */
    "sat_IN",   /* Santali      India */
    "sc_IT",    /* Sardinian    Italy */
    "scn_IT",   /* Sicilian     Italy */
    "sg_CF",    /* Sango        Central African Republic */
    "shn_MM",   /* Shan         Myanmar */
    "si_LK",    /* Sinhala      Sri Lanka */
    "sid_ET",   /* Sidamo       Ethiopia */
    "sk_SK",    /* Slovak       Slovakia */
    "sl_SI",    /* Slovenian    Slovenia */
    "smn_FI",   /* Inari Sami   Finland */
    "sms_FI",   /* Skolt Sami   Finland */
    "so_SO",    /* Somali       Somalia */
    "sq_AL",    /* Albanian     Albania */
    "sr_RS",    /* Serbian      Serbia */
    "sr_YU",    /* Serbian      Yugoslavia - this line can be removed in 2010 */
    "srr_SN",   /* Serer        Senegal */
    "suk_TZ",   /* Sukuma       Tanzania */
    "sus_GN",   /* Susu         Guinea */
    "sv_SE",    /* Swedish      Sweden */
    "te_IN",    /* Telugu       India */
    "tem_SL",   /* Timne        Sierra Leone */
    "tet_ID",   /* Tetum        Indonesia */
    "tg_TJ",    /* Tajik        Tajikistan */
    "th_TH",    /* Thai         Thailand */
    "tiv_NG",   /* Tiv          Nigeria */
    "tk_TM",    /* Turkmen      Turkmenistan */
    "tl_PH",    /* Tagalog      Philippines */
    "to_TO",    /* Tonga        Tonga */
    "tr_TR",    /* Turkish      Turkey */
    "tum_MW",   /* Tumbuka      Malawi */
    "ug_CN",    /* Uighur       China */
    "uk_UA",    /* Ukrainian    Ukraine */
    "umb_AO",   /* Umbundu      Angola */
    "ur_PK",    /* Urdu         Pakistan */
    "uz_UZ",    /* Uzbek        Uzbekistan */
    "ve_ZA",    /* Venda        South Africa */
    "vi_VN",    /* Vietnamese   Vietnam */
    "wa_BE",    /* Walloon      Belgium */
    "wal_ET",   /* Walamo       Ethiopia */
    "war_PH",   /* Waray        Philippines */
    "wen_DE",   /* Sorbian      Germany */
    "yao_MW",   /* Yao          Malawi */
    "zap_MX"    /* Zapotec      Mexico */
  };
  const char *dot;
  size_t i;

  /* Remove the ".codeset" part from the locale.  */
  dot = strchr (locale, '.');
  if (dot != NULL)
    {
      const char *codeset_end;
      char *shorter_locale;

      codeset_end = strpbrk (dot + 1, "_@");
      if (codeset_end == NULL)
        codeset_end = dot + strlen (dot);

      shorter_locale = XNMALLOC (strlen (locale), char);
      memcpy (shorter_locale, locale, dot - locale);
      strcpy (shorter_locale + (dot - locale), codeset_end);
      locale = shorter_locale;
    }

  /* If the territory is the language's principal territory, drop it.  */
  for (i = 0; i < SIZEOF (locales_with_principal_territory); i++)
    if (strcmp (locale, locales_with_principal_territory[i]) == 0)
      {
        const char *language_end;
        size_t len;
        char *shorter_locale;

        language_end = strchr (locale, '_');
        if (language_end == NULL)
          abort ();

        len = language_end - locale;
        shorter_locale = XNMALLOC (len + 1, char);
        memcpy (shorter_locale, locale, len);
        shorter_locale[len] = '\0';
        locale = shorter_locale;
        break;
      }

  return locale;
}

/* Return the language of a locale.  */
static const char *
language_of_locale (const char *locale)
{
  const char *language_end;

  language_end = strpbrk (locale, "_.@");
  if (language_end != NULL)
    {
      size_t len;
      char *result;

      len = language_end - locale;
      result = XNMALLOC (len + 1, char);
      memcpy (result, locale, len);
      result[len] = '\0';

      return result;
    }
  else
    return locale;
}

/* Return the most likely desired charset for the PO file, as a portable
   charset name.  */
static const char *
canonical_locale_charset ()
{
  const char *tmp;
  char *old_LC_ALL;
  const char *charset;

  /* Save LC_ALL environment variable.  */

  tmp = getenv ("LC_ALL");
  old_LC_ALL = (tmp != NULL ? xstrdup (tmp) : NULL);

  xsetenv ("LC_ALL", locale, 1);

#ifdef HAVE_SETLOCALE
  if (setlocale (LC_ALL, "") == NULL)
    /* Nonexistent locale.  Use anything.  */
    charset = "";
  else
#endif
    /* Get the locale's charset.  */
    charset = locale_charset ();

  /* Restore LC_ALL environment variable.  */

  if (old_LC_ALL != NULL)
    xsetenv ("LC_ALL", old_LC_ALL, 1), free (old_LC_ALL);
  else
    unsetenv ("LC_ALL");

#ifdef HAVE_SETLOCALE
  setlocale (LC_ALL, "");
#endif

  /* Canonicalize it.  */
  charset = po_charset_canonicalize (charset);
  if (charset == NULL)
    charset = po_charset_ascii;

  return charset;
}

/* Return the English name of the language.  */
static const char *
englishname_of_language ()
{
  size_t i;

  for (i = 0; i < language_table_size; i++)
    if (strcmp (language_table[i].code, language) == 0)
      return language_table[i].english;

  return xasprintf ("Language %s", language);
}

/* Construct the value for the PACKAGE name.  */
static const char *
project_id (const char *header)
{
  const char *old_field;
  const char *gettextlibdir;
  char *prog;
  char *argv[3];
  pid_t child;
  int fd[1];
  FILE *fp;
  char *line;
  size_t linesize;
  size_t linelen;
  int exitstatus;

  /* Return the first part of the Project-Id-Version field if present, assuming
     it was already filled in by xgettext.  */
  old_field = get_field (header, "Project-Id-Version");
  if (old_field != NULL && strcmp (old_field, "PACKAGE VERSION") != 0)
    {
      /* Remove the last word from old_field.  */
      const char *last_space;

      last_space = strrchr (old_field, ' ');
      if (last_space != NULL)
        {
          while (last_space > old_field && last_space[-1] == ' ')
            last_space--;
          if (last_space > old_field)
            {
              size_t package_len = last_space - old_field;
              char *package = XNMALLOC (package_len + 1, char);
              memcpy (package, old_field, package_len);
              package[package_len] = '\0';

              return package;
            }
        }
      /* It contains no version, just a package name.  */
      return old_field;
    }

  gettextlibdir = getenv ("GETTEXTLIBDIR");
  if (gettextlibdir == NULL || gettextlibdir[0] == '\0')
    gettextlibdir = relocate (LIBDIR "/gettext");

  prog = xconcatenated_filename (gettextlibdir, "project-id", NULL);

  /* Call the project-id shell script.  */
  argv[0] = "/bin/sh";
  argv[1] = prog;
  argv[2] = NULL;
  child = create_pipe_in (prog, "/bin/sh", argv, DEV_NULL, false, true, false,
                          fd);
  if (child == -1)
    goto failed;

  /* Retrieve its result.  */
  fp = fdopen (fd[0], "r");
  if (fp == NULL)
    {
      error (0, errno, _("fdopen() failed"));
      goto failed;
    }

  line = NULL; linesize = 0;
  linelen = getline (&line, &linesize, fp);
  if (linelen == (size_t)(-1))
    {
      error (0, 0, _("%s subprocess I/O error"), prog);
      fclose (fp);
      goto failed;
    }
  if (linelen > 0 && line[linelen - 1] == '\n')
    line[linelen - 1] = '\0';

  fclose (fp);

  /* Remove zombie process from process list, and retrieve exit status.  */
  exitstatus = wait_subprocess (child, prog, false, false, true, false, NULL);
  if (exitstatus != 0)
    {
      error (0, 0, _("%s subprocess failed with exit code %d"),
             prog, exitstatus);
      goto failed;
    }

  return line;

failed:
  return "PACKAGE";
}

/* Construct the value for the Project-Id-Version field.  */
static const char *
project_id_version (const char *header)
{
  const char *old_field;
  const char *gettextlibdir;
  char *prog;
  char *argv[4];
  pid_t child;
  int fd[1];
  FILE *fp;
  char *line;
  size_t linesize;
  size_t linelen;
  int exitstatus;

  /* Return the old value if present, assuming it was already filled in by
     xgettext.  */
  old_field = get_field (header, "Project-Id-Version");
  if (old_field != NULL && strcmp (old_field, "PACKAGE VERSION") != 0)
    return old_field;

  gettextlibdir = getenv ("GETTEXTLIBDIR");
  if (gettextlibdir == NULL || gettextlibdir[0] == '\0')
    gettextlibdir = relocate (LIBDIR "/gettext");

  prog = xconcatenated_filename (gettextlibdir, "project-id", NULL);

  /* Call the project-id shell script.  */
  argv[0] = "/bin/sh";
  argv[1] = prog;
  argv[2] = "yes";
  argv[3] = NULL;
  child = create_pipe_in (prog, "/bin/sh", argv, DEV_NULL, false, true, false,
                          fd);
  if (child == -1)
    goto failed;

  /* Retrieve its result.  */
  fp = fdopen (fd[0], "r");
  if (fp == NULL)
    {
      error (0, errno, _("fdopen() failed"));
      goto failed;
    }

  line = NULL; linesize = 0;
  linelen = getline (&line, &linesize, fp);
  if (linelen == (size_t)(-1))
    {
      error (0, 0, _("%s subprocess I/O error"), prog);
      fclose (fp);
      goto failed;
    }
  if (linelen > 0 && line[linelen - 1] == '\n')
    line[linelen - 1] = '\0';

  fclose (fp);

  /* Remove zombie process from process list, and retrieve exit status.  */
  exitstatus = wait_subprocess (child, prog, false, false, true, false, NULL);
  if (exitstatus != 0)
    {
      error (0, 0, _("%s subprocess failed with exit code %d"),
             prog, exitstatus);
      goto failed;
    }

  return line;

failed:
  return "PACKAGE VERSION";
}

/* Construct the value for the PO-Revision-Date field.  */
static const char *
po_revision_date (const char *header)
{
  if (no_translator)
    /* Because the PO file is automatically generated, we use the
       POT-Creation-Date, not the current time.  */
    return get_field (header, "POT-Creation-Date");
  else
    {
      /* Assume the translator will modify the PO file now.  */
      time_t now;

      time (&now);
      return po_strftime (&now);
    }
}

/* Returns the struct passwd entry for the current user.  */
static struct passwd *
get_user_pwd ()
{
#if HAVE_PWD_H  /* Only Unix, not native Woe32.  */
  const char *username;
  struct passwd *userpasswd;

  /* 1. attempt: getpwnam(getenv("USER"))  */
  username = getenv ("USER");
  if (username != NULL)
    {
      errno = 0;
      userpasswd = getpwnam (username);
      if (userpasswd != NULL)
        return userpasswd;
      if (errno != 0)
        error (EXIT_FAILURE, errno, "getpwnam(\"%s\")", username);
    }

  /* 2. attempt: getpwnam(getlogin())  */
  username = getlogin ();
  if (username != NULL)
    {
      errno = 0;
      userpasswd = getpwnam (username);
      if (userpasswd != NULL)
        return userpasswd;
      if (errno != 0)
        error (EXIT_FAILURE, errno, "getpwnam(\"%s\")", username);
    }

  /* 3. attempt: getpwuid(getuid())  */
  errno = 0;
  userpasswd = getpwuid (getuid ());
  if (userpasswd != NULL)
    return userpasswd;
  if (errno != 0)
    error (EXIT_FAILURE, errno, "getpwuid(\"%d\")", getuid ());
#endif

  return NULL;
}

/* Return the user's full name.  */
static const char *
get_user_fullname ()
{
  struct passwd *pwd;

  pwd = get_user_pwd ();
#if HAVE_PWD_H
  if (pwd != NULL)
    {
      const char *fullname;
      const char *fullname_end;
      char *result;

      /* Return the pw_gecos field, up to the first comma (if any).  */
      fullname = pwd->pw_gecos;
      fullname_end = strchr (fullname, ',');
      if (fullname_end == NULL)
        fullname_end = fullname + strlen (fullname);

      result = XNMALLOC (fullname_end - fullname + 1, char);
      memcpy (result, fullname, fullname_end - fullname);
      result[fullname_end - fullname] = '\0';

      return result;
    }
#endif

  return NULL;
}

/* Return the user's email address.  */
static const char *
get_user_email ()
{
  const char *prog = relocate (LIBDIR "/gettext/user-email");
  char *argv[4];
  pid_t child;
  int fd[1];
  FILE *fp;
  char *line;
  size_t linesize;
  size_t linelen;
  int exitstatus;

  /* Ask the user for his email address.  */
  argv[0] = "/bin/sh";
  argv[1] = (char *) prog;
  argv[2] = (char *) _("\
The new message catalog should contain your email address, so that users can\n\
give you feedback about the translations, and so that maintainers can contact\n\
you in case of unexpected technical problems.\n");
  argv[3] = NULL;
  child = create_pipe_in (prog, "/bin/sh", argv, DEV_NULL, false, true, false,
                          fd);
  if (child == -1)
    goto failed;

  /* Retrieve his answer.  */
  fp = fdopen (fd[0], "r");
  if (fp == NULL)
    {
      error (0, errno, _("fdopen() failed"));
      goto failed;
    }

  line = NULL; linesize = 0;
  linelen = getline (&line, &linesize, fp);
  if (linelen == (size_t)(-1))
    {
      error (0, 0, _("%s subprocess I/O error"), prog);
      fclose (fp);
      goto failed;
    }
  if (linelen > 0 && line[linelen - 1] == '\n')
    line[linelen - 1] = '\0';

  fclose (fp);

  /* Remove zombie process from process list, and retrieve exit status.  */
  exitstatus = wait_subprocess (child, prog, false, false, true, false, NULL);
  if (exitstatus != 0)
    {
      error (0, 0, _("%s subprocess failed with exit code %d"),
             prog, exitstatus);
      goto failed;
    }

  return line;

failed:
  return "EMAIL@ADDRESS";
}

/* Construct the value for the Last-Translator field.  */
static const char *
last_translator ()
{
  if (no_translator)
    return "Automatically generated";
  else
    {
      const char *fullname = get_user_fullname ();
      const char *email = get_user_email ();

      if (fullname != NULL)
        return xasprintf ("%s <%s>", fullname, email);
      else
        return xasprintf ("<%s>", email);
    }
}

/* Return the name of the language used by the language team, in English.  */
static const char *
language_team_englishname ()
{
  size_t i;

  /* Search for a name depending on the catalogname.  */
  for (i = 0; i < language_variant_table_size; i++)
    if (strcmp (language_variant_table[i].code, catalogname) == 0)
      return language_variant_table[i].english;

  /* Search for a name depending on the language only.  */
  return englishname_of_language ();
}

/* Return the language team's mailing list address or homepage URL.  */
static const char *
language_team_address ()
{
  const char *prog = relocate (PROJECTSDIR "/team-address");
  char *argv[7];
  pid_t child;
  int fd[1];
  FILE *fp;
  char *line;
  size_t linesize;
  size_t linelen;
  int exitstatus;

  /* Call the team-address shell script.  */
  argv[0] = "/bin/sh";
  argv[1] = (char *) prog;
  argv[2] = (char *) relocate (PROJECTSDIR);
  argv[3] = (char *) relocate (LIBDIR "/gettext");
  argv[4] = (char *) catalogname;
  argv[5] = (char *) language;
  argv[6] = NULL;
  child = create_pipe_in (prog, "/bin/sh", argv, DEV_NULL, false, true, false,
                          fd);
  if (child == -1)
    goto failed;

  /* Retrieve its result.  */
  fp = fdopen (fd[0], "r");
  if (fp == NULL)
    {
      error (0, errno, _("fdopen() failed"));
      goto failed;
    }

  line = NULL; linesize = 0;
  linelen = getline (&line, &linesize, fp);
  if (linelen == (size_t)(-1))
    line = "";
  else if (linelen > 0 && line[linelen - 1] == '\n')
    line[linelen - 1] = '\0';

  fclose (fp);

  /* Remove zombie process from process list, and retrieve exit status.  */
  exitstatus = wait_subprocess (child, prog, false, false, true, false, NULL);
  if (exitstatus != 0)
    {
      error (0, 0, _("%s subprocess failed with exit code %d"),
             prog, exitstatus);
      goto failed;
    }

  return line;

failed:
  return "";
}

/* Construct the value for the Language-Team field.  */
static const char *
language_team ()
{
  if (no_translator)
    return "none";
  else
    {
      const char *englishname = language_team_englishname ();
      const char *address = language_team_address ();

      if (address != NULL && address[0] != '\0')
        return xasprintf ("%s %s", englishname, address);
      else
        return englishname;
    }
}

/* Construct the value for the Language field.  */
static const char *
language_value ()
{
  return catalogname;
}

/* Construct the value for the MIME-Version field.  */
static const char *
mime_version ()
{
  return "1.0";
}

/* Construct the value for the Content-Type field.  */
static const char *
content_type (const char *header)
{
  bool was_utf8;
  const char *old_field;

  /* If the POT file contains charset=UTF-8, it means that the POT file
     contains non-ASCII characters, and we keep the UTF-8 encoding.
     Otherwise, when the POT file is plain ASCII, we use the locale's
     encoding.  */
  was_utf8 = false;
  old_field = get_field (header, "Content-Type");
  if (old_field != NULL)
    {
      const char *charsetstr = c_strstr (old_field, "charset=");

      if (charsetstr != NULL)
        {
          charsetstr += strlen ("charset=");
          was_utf8 = (c_strcasecmp (charsetstr, "UTF-8") == 0);
        }
    }
  return xasprintf ("text/plain; charset=%s",
                    was_utf8 ? "UTF-8" : canonical_locale_charset ());
}

/* Construct the value for the Content-Transfer-Encoding field.  */
static const char *
content_transfer_encoding ()
{
  return "8bit";
}

/* Construct the value for the Plural-Forms field.  */
static const char *
plural_forms ()
{
  size_t i;

  /* Search for a formula depending on the catalogname.  */
  for (i = 0; i < plural_table_size; i++)
    if (strcmp (plural_table[i].lang, catalogname) == 0)
      return plural_table[i].value;

  /* Search for a formula depending on the language only.  */
  for (i = 0; i < plural_table_size; i++)
    if (strcmp (plural_table[i].lang, language) == 0)
      return plural_table[i].value;

  return NULL;
}

static struct
{
  const char *name;
  const char * (*getter0) (void);
  const char * (*getter1) (const char *header);
}
fields[] =
  {
    { "Project-Id-Version", NULL, project_id_version },
    { "PO-Revision-Date", NULL, po_revision_date },
    { "Last-Translator", last_translator, NULL },
    { "Language-Team", language_team, NULL },
    { "Language", language_value, NULL },
    { "MIME-Version", mime_version, NULL },
    { "Content-Type", NULL, content_type },
    { "Content-Transfer-Encoding", content_transfer_encoding, NULL },
    { "Plural-Forms", plural_forms, NULL }
  };

#define NFIELDS SIZEOF (fields)
#define FIELD_LAST_TRANSLATOR 2

/* Retrieve a freshly allocated copy of a field's value.  */
static char *
get_field (const char *header, const char *field)
{
  size_t len = strlen (field);
  const char *line;

  for (line = header;;)
    {
      if (strncmp (line, field, len) == 0 && line[len] == ':')
        {
          const char *value_start;
          const char *value_end;
          char *value;

          value_start = line + len + 1;
          if (*value_start == ' ')
            value_start++;
          value_end = strchr (value_start, '\n');
          if (value_end == NULL)
            value_end = value_start + strlen (value_start);

          value = XNMALLOC (value_end - value_start + 1, char);
          memcpy (value, value_start, value_end - value_start);
          value[value_end - value_start] = '\0';

          return value;
        }

      line = strchr (line, '\n');
      if (line != NULL)
        line++;
      else
        break;
    }

  return NULL;
}

/* Add a field with value to a header, and return the new header.  */
static char *
put_field (const char *old_header, const char *field, const char *value)
{
  size_t len = strlen (field);
  const char *line;
  char *new_header;
  char *p;

  for (line = old_header;;)
    {
      if (strncmp (line, field, len) == 0 && line[len] == ':')
        {
          const char *value_start;
          const char *value_end;

          value_start = line + len + 1;
          if (*value_start == ' ')
            value_start++;
          value_end = strchr (value_start, '\n');
          if (value_end == NULL)
            value_end = value_start + strlen (value_start);

          new_header = XNMALLOC (strlen (old_header)
                                 - (value_end - value_start)
                                 + strlen (value)
                                 + (*value_end != '\n' ? 1 : 0)
                                 + 1,
                                 char);
          p = new_header;
          memcpy (p, old_header, value_start - old_header);
          p += value_start - old_header;
          memcpy (p, value, strlen (value));
          p += strlen (value);
          if (*value_end != '\n')
            *p++ = '\n';
          strcpy (p, value_end);

          return new_header;
        }

      line = strchr (line, '\n');
      if (line != NULL)
        line++;
      else
        break;
    }

  new_header = XNMALLOC (strlen (old_header) + 1
                         + len + 2 + strlen (value) + 1
                         + 1,
                         char);
  p = new_header;
  memcpy (p, old_header, strlen (old_header));
  p += strlen (old_header);
  if (p > new_header && p[-1] != '\n')
    *p++ = '\n';
  memcpy (p, field, len);
  p += len;
  *p++ = ':';
  *p++ = ' ';
  memcpy (p, value, strlen (value));
  p += strlen (value);
  *p++ = '\n';
  *p = '\0';

  return new_header;
}

/* Return the title format string.  */
static const char *
get_title ()
{
  /* This is tricky.  We want the translation in the given locale specified by
     the command line, not the current locale.  But we want it in the encoding
     that we put into the header entry, not the encoding of that locale.
     We could avoid the use of OUTPUT_CHARSET by using a separate message
     catalog and bind_textdomain_codeset(), but that doesn't seem worth the
     trouble for one single message.  */
  const char *encoding;
  const char *tmp;
  char *old_LC_ALL;
  char *old_LANGUAGE;
  char *old_OUTPUT_CHARSET;
  const char *msgid;
  const char *english;
  const char *result;

  encoding = canonical_locale_charset ();

  /* First, the English title.  */
  english = xasprintf ("%s translations for %%s package",
                       englishname_of_language ());

  /* Save LC_ALL, LANGUAGE, OUTPUT_CHARSET environment variables.  */

  tmp = getenv ("LC_ALL");
  old_LC_ALL = (tmp != NULL ? xstrdup (tmp) : NULL);

  tmp = getenv ("LANGUAGE");
  old_LANGUAGE = (tmp != NULL ? xstrdup (tmp) : NULL);

  tmp = getenv ("OUTPUT_CHARSET");
  old_OUTPUT_CHARSET = (tmp != NULL ? xstrdup (tmp) : NULL);

  xsetenv ("LC_ALL", locale, 1);
  unsetenv ("LANGUAGE");
  xsetenv ("OUTPUT_CHARSET", encoding, 1);

#ifdef HAVE_SETLOCALE
  if (setlocale (LC_ALL, "") == NULL)
    /* Nonexistent locale.  Use the English title.  */
    result = english;
  else
#endif
    {
      /* Fetch the translation.  */
      /* TRANSLATORS: "English" needs to be replaced by your language.
         For example in it.po write "Traduzioni italiani ...",
         *not* "Traduzioni inglesi ...".  */
      msgid = N_("English translations for %s package");
      result = gettext (msgid);
      if (result != msgid && strcmp (result, msgid) != 0)
        /* Use the English and the foreign title.  */
        result = xasprintf ("%s\n%s", english, result);
      else
        /* No translation found.  Use the English title.  */
        result = english;
    }

  /* Restore LC_ALL, LANGUAGE, OUTPUT_CHARSET environment variables.  */

  if (old_LC_ALL != NULL)
    xsetenv ("LC_ALL", old_LC_ALL, 1), free (old_LC_ALL);
  else
    unsetenv ("LC_ALL");

  if (old_LANGUAGE != NULL)
    xsetenv ("LANGUAGE", old_LANGUAGE, 1), free (old_LANGUAGE);
  else
    unsetenv ("LANGUAGE");

  if (old_OUTPUT_CHARSET != NULL)
    xsetenv ("OUTPUT_CHARSET", old_OUTPUT_CHARSET, 1), free (old_OUTPUT_CHARSET);
  else
    unsetenv ("OUTPUT_CHARSET");

#ifdef HAVE_SETLOCALE
  setlocale (LC_ALL, "");
#endif

  return result;
}

/* Perform a set of substitutions in a string and return the resulting
   string.  When subst[j][0] found, it is replaced with subst[j][1].
   subst[j][0] must not be the empty string.  */
static const char *
subst_string (const char *str,
              unsigned int nsubst, const char *(*subst)[2])
{
  if (nsubst > 0)
    {
      char *malloced = NULL;
      size_t *substlen;
      size_t i;
      unsigned int j;

      substlen = (size_t *) xmalloca (nsubst * sizeof (size_t));
      for (j = 0; j < nsubst; j++)
        {
          substlen[j] = strlen (subst[j][0]);
          if (substlen[j] == 0)
            abort ();
        }

      for (i = 0;;)
        {
          if (str[i] == '\0')
            break;
          for (j = 0; j < nsubst; j++)
            if (*(str + i) == *subst[j][0]
                && strncmp (str + i, subst[j][0], substlen[j]) == 0)
              {
                size_t replacement_len = strlen (subst[j][1]);
                size_t new_len = strlen (str) - substlen[j] + replacement_len;
                char *new_str = XNMALLOC (new_len + 1, char);
                memcpy (new_str, str, i);
                memcpy (new_str + i, subst[j][1], replacement_len);
                strcpy (new_str + i + replacement_len, str + i + substlen[j]);
                if (malloced != NULL)
                  free (malloced);
                str = new_str;
                malloced = new_str;
                i += replacement_len;
                break;
              }
          if (j == nsubst)
            i++;
        }

      freea (substlen);
    }

  return str;
}

/* Perform a set of substitutions on each string of a string list.
   When subst[j][0] found, it is replaced with subst[j][1].  subst[j][0]
   must not be the empty string.  */
static void
subst_string_list (string_list_ty *slp,
                   unsigned int nsubst, const char *(*subst)[2])
{
  size_t j;

  for (j = 0; j < slp->nitems; j++)
    slp->item[j] = subst_string (slp->item[j], nsubst, subst);
}

/* Fill the templates in all fields of the header entry.  */
static msgdomain_list_ty *
fill_header (msgdomain_list_ty *mdlp)
{
  /* Cache the strings filled in, for use when there are multiple domains
     and a header entry for each domain.  */
  const char *field_value[NFIELDS];
  size_t k, j, i;

  for (i = 0; i < NFIELDS; i++)
    field_value[i] = NULL;

  for (k = 0; k < mdlp->nitems; k++)
    {
      message_list_ty *mlp = mdlp->item[k]->messages;

      if (mlp->nitems > 0)
        {
          message_ty *header_mp = NULL;
          char *header;

          /* Search the header entry.  */
          for (j = 0; j < mlp->nitems; j++)
            if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete)
              {
                header_mp = mlp->item[j];
                break;
              }

          /* If it wasn't found, provide one.  */
          if (header_mp == NULL)
            {
              static lex_pos_ty pos = { __FILE__, __LINE__ };

              header_mp = message_alloc (NULL, "", NULL, "", 1, &pos);
              message_list_prepend (mlp, header_mp);
            }

          header = xstrdup (header_mp->msgstr);

          /* Fill in the fields.  */
          for (i = 0; i < NFIELDS; i++)
            {
              if (field_value[i] == NULL)
                field_value[i] =
                  (fields[i].getter1 != NULL
                   ? fields[i].getter1 (header)
                   : fields[i].getter0 ());

              if (field_value[i] != NULL)
                {
                  char *old_header = header;
                  header = put_field (header, fields[i].name, field_value[i]);
                  free (old_header);
                }
            }

          /* Replace the old translation in the header entry.  */
          header_mp->msgstr = header;
          header_mp->msgstr_len = strlen (header) + 1;

          /* Update the comments in the header entry.  */
          if (header_mp->comment != NULL)
            {
              const char *subst[4][2];
              const char *id;
              time_t now;

              id = project_id (header);
              subst[0][0] = "SOME DESCRIPTIVE TITLE";
              subst[0][1] = xasprintf (get_title (), id, id);
              subst[1][0] = "PACKAGE";
              subst[1][1] = id;
              subst[2][0] = "FIRST AUTHOR <EMAIL@ADDRESS>";
              subst[2][1] = field_value[FIELD_LAST_TRANSLATOR];
              subst[3][0] = "YEAR";
              subst[3][1] =
                xasprintf ("%d",
                           (time (&now), (localtime (&now))->tm_year + 1900));
              subst_string_list (header_mp->comment, SIZEOF (subst), subst);
            }

          /* Finally remove the fuzzy attribute.  */
          header_mp->is_fuzzy = false;
        }
    }

  return mdlp;
}

/* Update the msgstr plural entries according to the nplurals count.  */
static msgdomain_list_ty *
update_msgstr_plurals (msgdomain_list_ty *mdlp)
{
  size_t k;

  for (k = 0; k < mdlp->nitems; k++)
    {
      message_list_ty *mlp = mdlp->item[k]->messages;
      message_ty *header_entry;
      unsigned long int nplurals;
      char *untranslated_plural_msgstr;
      size_t j;

      header_entry = message_list_search (mlp, NULL, "");
      nplurals = get_plural_count (header_entry ? header_entry->msgstr : NULL);
      untranslated_plural_msgstr = XNMALLOC (nplurals, char);
      memset (untranslated_plural_msgstr, '\0', nplurals);

      for (j = 0; j < mlp->nitems; j++)
        {
          message_ty *mp = mlp->item[j];
          bool is_untranslated;
          const char *p;
          const char *pend;

          if (mp->msgid_plural != NULL)
            {
              /* Test if mp is untranslated.  (It most likely is.)  */
              is_untranslated = true;
              for (p = mp->msgstr, pend = p + mp->msgstr_len; p < pend; p++)
                if (*p != '\0')
                  {
                    is_untranslated = false;
                    break;
                  }
              if (is_untranslated)
                {
                  /* Change mp->msgstr_len consecutive empty strings into
                     nplurals consecutive empty strings.  */
                  if (nplurals > mp->msgstr_len)
                    mp->msgstr = untranslated_plural_msgstr;
                  mp->msgstr_len = nplurals;
                }
            }
        }
    }
  return mdlp;
}

redpajama_set_name: RedPajamaGithub


text:
In-Stream Video Ad CTR Far Higher Than Banners, Rich Media in H1
Analytics, Automated & MarTech | Data-driven | Digital
In-stream video ads garnered significantly higher click-through-rates (CTRs) than banners and rich media in H1, details a [download page] September 2012 report from MediaMind. In-stream video ad serving template (VAST) impressions saw an average CTR of 2.84%, while the average CTR for player-ad interface definition (VPAID) impressions was 1.63%. By comparison, the standard banner rate stood at 0.1%, and rich media's at 0.22%. An August 2012 MediaMind study found the same 0.1% CTR for standard banner ads in the US, but, a much higher 0.87% for mobile banners.
Meanwhile, according to the latest report, rich media with video (0.26%) performed better than rich media without video (0.21%).
In examining the CTR differences between VAST and VPAID, the report concludes that VAST ads more actively call for click-throughs and interactions. VPAID is less focused on direct response, and also enables and captures in-stream interactions, not necessarily requiring a click-through. Viewers may also be dissuaded from interrupting their video experience by clicking on such an ad during long-form content and being taken to a separate page or site.
Worldwide, as the September 2012 report details, the VAST CTR has climbed significantly over the past 5 quarters, from 0.77% in Q1 2011 to 3.05% in Q2 2012, with a peak of 3.09% in Q1 2012.
In-Stream VPAID Interaction Rate Higher Than CTR
Data from "Video Is Everywhere: Because It's What Consumers Want" indicates that the overall interaction rate for VPAID (defined as the number of interactions divided by the number of impressions) was 9.57%, versus its 1.63% CTR. MediaMind observes that interaction rates peaked at more than 500% (5 interactions per ad per campaign) for some of the top-performing campaigns, although the company excluded campaigns with interaction rates higher than 30% so as to normalize the aggregate data.
The lower CTR as compared to interaction rate make sense, given the factors described in the VPAID and VAST comparison.
Completion Rates Highest For In-Stream VPAID
Moving to an analysis of completion rates, the study finds that in-stream VPAID ads registered the highest rate, of 68.14%, followed by in-stream VAST (66.21%) and rich media (57.87%). (All of the ads analyzed were between 10 and 30 seconds in length.)
An April 2012 report from Vindico suggests that ad completion rate is a better success metric than CTR. Based on an analysis of 30 billion video ad impressions from 2011, the company found that of viewers who had navigated past brands' landing pages, 96% had previously completed the brands' video ads without clicking, compared to just 4% who had clicked on the ads. And of those navigating to a checkout page, 98% had completed the brands' video ads without clicking. That despite the proportion of viewers who arrived at the landing page being relatively evenly split between both groups.
About The Data: MediaMind's analysis is based on approximately 4200 video campaigns with nearly 3 billion impressions worldwide across the MediaMind video ad network from January-June 2012.

redpajama_set_name: RedPajamaCommonCrawl


text:
Luiz and Gabriel or Mari and Holding? Arteta's Arsenal centre-back dilemma
Mikel Arteta has four in-form centre-backs to choose from this season, so who should start together at the back for the Gunners?
When Mikel Arteta started his first full season in charge of Arsenal, he knew he had some big decisions to make regarding the heart of his defence.
With eight centre-backs on the books, the Spaniard's squad was massively unbalanced and he could see the issues that was going to throw up, so the priority during the summer was reducing the numbers.
Shkodran Mustafi and Sokratis were both told they could leave, but buyers couldn't be found, while attempts to send William Saliba out on loan also ended in failure – with a deadline-day return to Saint Etienne failing to get over the line.
Konstantinos Mavropanos did at least get a move, with the 23-year-old agreeing to spend the campaign with Stuttgart in the Bundesliga, but Arteta was nonetheless left in a difficult situation.
He knew, given the amount of players he had at his disposal, that certain players were going to find themselves playing very little football – which is far from ideal when it comes to maintaining harmony behind the scenes.
"When you have the squad we have, it's impossible to have 31 happy players in the camp," the Gunners boss said. "I don't know any [other] club who has that."
Arteta chose to leave Sokrtais out of his squad altogether, with the Greece international not even registered for the Premier League, and Saliba had to make do with a handful of appearances for the Under-23s.
Mustafi, meanwhile, made just three substitute appearances in the Premier League before the turn of the year, although he was at least a regular in the Europa League group stages and also featured in the League Cup defeat by Manchester City.
Still, it was clear that the general situation could not continue, with Arsenal eventually deciding to take the drastic action of cancelling the contracts of both Sokratis and Mustafi in January and sending Saliba out on loan to Nice.
Those moves in the transfer market have left Arteta with a far more manageable defensive department to pick from and, for the first time since he arrived, the Gunners boss finally has a group of centre-backs that has a balanced feel to it.
Gabriel Magalhaes has been excellent since his move in the summer and has been showing signs of getting back to his very best after a difficult couple of months which saw him pick up an injury and catch coronavirus.
David Luiz is arguably in his best run of form for Arsenal, while Pablo Mari and Rob Holding have been excellent at times this season, especially in the few games they have been paired together.
The quartet's impressive displays have left Arteta with a very different sort of dilemma to the one he faced at the start of the season. It's now a case of who starts, and when?
In recent weeks, Gabriel and David Luiz have been Arteta's preferred duo, despite both being more comfortable as the left sided centre-back when deployed in a pair.
It's Luiz who has moved over the right, with the former Chelsea star producing some excellent performances alongside his compatriot.
The Brazilians have started each of Arsenal's last three games and were exceptional in the first leg against Olympiacos - and the north London derby victory against Spurs at the weekend.
Gabriel was also Arsenal's outstanding player in the 1-0 defeat by Olympiacos on Thursday night in north London and is back to the sort of form he showed at the start of the season, when he was named Arsenal's player of the month in September, October and November.
Luiz, meanwhile, is delivering consistently on the field again but also continues to be a major presence behind the scenes, especially with the younger players in the squad.
"It's credit to him because he trains really hard," Arteta said when asked about Luiz's purple patch.
"This season was really tough for him in the beginning because he'd been through some injuries but he's kept at it, he understood his role, he knows his role in the team, he's one of our leaders and he's so willing to keep improving.
"He knows the things that he's really good at and the things where there is still room for improvement. He's a really honest man with himself. He's won everything and it's a joy to work with him.
"He's a great example for [the youngsters]. He's got a good mixture with them between some banter and then some stick. They all listen to him because of who he is and what he's done in the game.
"But also because of how he behaves every day, how professional he is and how he goes about the job. He is one of the key role models that we have in our team."
However, while Luiz and Gabriel have now started together in six of Arsenal's last nine games in all competitions, it would be no surprise to see Mari and Holding come in for Sunday's Premier League clash at West Ham.
The pair have only started four games together this season, but in those games they have shown a fine understanding, helping Arsenal to two clean sheets and three wins.
Arteta's side have conceded just twice in the games when Mari and Holding have started in the centre of defence, with the only defeat coming when they were beaten 1-0 by champions-elect Manchester City.
Arteta's side have won 75 per cent of the games they've started together, compared to 54.5% when it's Gabriel and Luiz. They also only concede 0.5 goals per game, far less than the 1.3 goals per game when it's the two Brazilians.
"He's a leader, someone that trains really hard," Arteta said of Mari, who joined Arsenal on a permanent basis from Flamengo last summer. "He's a professional, a great communicator on the pitch and he gives you some security and stability."
But of all Arsenal's centre-backs this season, it's perhaps Holding who has enjoyed the most consistent campaign so far.
The 25-year-old was close to joining Newcastle last year before Arteta blocked the move and he repaid his manager's faith by returning the sort of form he was showing before he suffered his cruciate knee injury in 2018 .
Holding has made 27 appearances in all competitions. Of his fellow centre-backs, only Luiz (28) has started more matches – although it's Holding who tops the charts in terms of minutes played (2,243).
He also averages 0.8 goals conceded per game, which is better than Luiz (1.0) and Gabriel (1.3), and the same as Mari.
The Englishman wins more aerials (2.6) than Luiz and Mari, though, makes more tackles (1.6), clearances (4.3) and also concedes fewer fouls (0.7).
"When you compare how he has evolved in a year's time, it is incredible," Arteta said when discussing Holding's improvement this season.
"It is down to him, how professional he is, how much he wants to learn, how much he puts into every training session and then his character and his personality. He is growing in every aspect. I am really happy with him."
The form of his centre-backs, and the way they play together, leaves Arteta with a welcome selection headache.
Arsenal's manager doesn't have to worry about how many central defenders he has in his squad anymore, but he has to work out who to pair together on a game-by-game basis.
It's Gabriel and Luiz who appear to be top of the pecking order for now, but the stats show that Mari and Holding have every right to feel like they should be getting a bit more game time.
For Arteta at least, it's a nice problem to have.
Copyright © 2023 Goal (United Kingdom) All rights reserved. The information contained in Goal (United Kingdom) may not be published, broadcast, rewritten, or redistributed without the prior written authority of Goal (United Kingdom)


Show Your Team Spirit with Fenton USA Jewelry!
Show your "fan spirit" with handcrafted art glass jewelry in your favorite team's colors! Choose from a large selection of made in the USA beads featuring officially licensed artwork for more than 45 colleges and universities. Fenton USA Jewelry's Collegiate Collection includes high quality art glass beads (two regular size and a larger Cornerstone bead), a bead on a coordinating school color leather cord bracelet, and a few earring and other jewelry styles. To view the complete Collegiate Jewelry collection, click here.
Mix and match with coordinating color beads from Fenton's regular jewelry line to make your Team Spirit fashion statement! You can create a variety of eye-catching looks with our handcrafted sterling silver jewelry accessories. Choose from bracelets and bangles to necklaces and pendants! Click here to view the complete line of jewelry accessories. Fenton USA Jewelry is also available through our network of authorized Fenton dealers. Click here to locate a Fenton dealer near you or click on each image to order from the Fenton Art Glass web site!
Miami (of Ohio) University Jewelry: Cornerstone Bead, Leather Cord Bracelet and regular size beads in Milk Glass and Red glass. Each image shows the front and back views. Click on each image to order.
Shown at left: University of Miami Leather Cord Bracelet and The Ohio State University Cornerstone Bead. Click on each image to order or check with your local Fenton dealer.
Fenton Gift Shop is pleased to offer new Limited Edition pieces, designed by our award-winning Fenton Art Glass designers. Each piece will be handpainted, signed and dated. Shown above are an Alley Cat and a Chessie Box, handcrafted, using a Fenton mould, as exclusives for the Fenton Gift Shop by our friends at Mosser Glass. Fenton Gift Shop is also pleased to introduce Crown Tuscan as a new pink color, a softer hue that works well with these wonderful handpainted designs.
Robin Spindler created the lovely design on this 11" tall Crown Tuscan Alley Cat that reminds one of the Victorian era. Note the handpainted rosebuds and lace details, as well as the two pearlized gem accents and gold ribbon accent on one of the cat's ears. As always, you'll instantly fall in love with the impish grin on the Alley Cat's face! This "Purr-T in Pink" Alley Cat figurine by Robin Spindler is $250.00.
Kim Barley's "Summertime Snuggle Cat" design is perfect for this Crown Tuscan 8" tall Chessie Box! A soft floral blanket surround the sleepy "Chessie Cat" and Kim added touches of blue airbrushing, lush green trees and vibrant flowers (on the back) to complete the look on this Chessie Box. This "Summertime Snuggle Cat" Chessie Box by Kim Barley is $220.
Pre-orders for the Alley Cat figurine and Chessie Box will be accepted until midnight (ET) on Monday, August 10, 2015.
The 9" tall "Butterflies and Daisies" Vase was handcrafted in Opal Satin, using a Fenton mould, as a Fenton Gift Shop exclusive by Davis-Lynch Glass Company. The Opal Satin 3.75" tall "Pumpkin Cat" Cat figurine was handcrafted by Mosser Glass.
Pre-orders for the "Butterflies and Daisies" Vase and the "Pumpkin Cat" Figurine will be accepted until midnight (ET) on Wednesday, August 12, 2015.
You'll love the delicate, handpainted design of a trio of butterflies hovering amongst bright pink daisies on this 9" Vase, designed by Frances Burton. Her design encircles the vase, and no matter how you display it, you'll have a beautiful view of a butterfly and daisies. This "Butterflies and Daisies" Vase is $220.00.
You'll be ready for Halloween decorating with this wonderful handpainted "Pumpkin Cat" figurine designed by Kim Barley. Kim's whimsical design encircles this figurine with a moon and stars, pumpkins with wonderful details (see the candle inside one of the pumpkins?) and those large expressive eyes! This "Pumpkin Cat" Figurine is $85.00.
To pre-order, please contact the Fenton Gift Shop: 1-800-319-7793, ext. 342 or via email: purchasing@fentongiftshop.com. You may also request to have your email added to a mailing list in order to receive future notifications of limited editions as they become available. Fenton Gift Shop's regular hours are Wednesday, Thursday, Friday, and Saturday from 10 a.m.-3 p.m. ET. and closed Sunday, Monday and Tuesday.
Here's your opportunity to own a unique, rare, one-of-a-kind creation, through our weekly eBay Auctions! Items featured this week. . .
Shown here are our latest offerings from award-wining Fenton designers: A one-of-a-kind elegant Amphora Vase with stand featuring a lovely handpainted "Single Dahlia" design by Frances Burton, which encircles the vase.
This one-of-a-kind Elephant Treasure Box has been airbrushed to a more natural gray color by Kim Barley. She's added details of colorful "parade" attire to complete this piece. Perfect place to store your "treasures" or a wonderful addition to any Fenton figurine collection.
Last, but not least is a black and white photo, made from an old negative, showing Fenton glassworkers gathered at their campsite (located on a nearby riverbank). The original photo was taken circa 1910, during the annual "Summer Stop" when the factory would shut down for repairs. You'll love looking at the period style clothing ... You'll also notice that most of the men hold a "refreshing drink"! Fenton's factory manager Jacob Rosenthal can be seen in the back row. This Fenton eBay auction ends at noon (ET) on Wednesday, August 12th.


text:
package com.androidmapsextensions;

import com.google.android.gms.maps.model.Cap;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.PatternItem;

import java.util.List;

public class PolylineOptions {

    public final com.google.android.gms.maps.model.PolylineOptions real = new com.google.android.gms.maps.model.PolylineOptions();
    private Object data;

    public PolylineOptions add(LatLng point) {
        real.add(point);
        return this;
    }

    public PolylineOptions add(LatLng... points) {
        real.add(points);
        return this;
    }

    public PolylineOptions addAll(Iterable<LatLng> points) {
        real.addAll(points);
        return this;
    }

    public PolylineOptions clickable(boolean clickable) {
        real.clickable(clickable);
        return this;
    }

    public PolylineOptions color(int color) {
        real.color(color);
        return this;
    }

    public PolylineOptions data(Object data) {
        this.data = data;
        return this;
    }

    public PolylineOptions endCap(Cap cap) {
        real.endCap(cap);
        return this;
    }

    public PolylineOptions geodesic(boolean geodesic) {
        real.geodesic(geodesic);
        return this;
    }

    public int getColor() {
        return real.getColor();
    }

    public Object getData() {
        return data;
    }

    public Cap getEndCap() {
        return real.getEndCap();
    }

    public int getJointType() {
        return real.getJointType();
    }

    public List<PatternItem> getPattern() {
        return real.getPattern();
    }

    public List<LatLng> getPoints() {
        return real.getPoints();
    }

    public Cap getStartCap() {
        return real.getStartCap();
    }

    public float getWidth() {
        return real.getWidth();
    }

    public float getZIndex() {
        return real.getZIndex();
    }

    public boolean isClickable() {
        return real.isClickable();
    }

    public boolean isGeodesic() {
        return real.isGeodesic();
    }

    public boolean isVisible() {
        return real.isVisible();
    }

    public PolylineOptions jointType(int type) {
        real.jointType(type);
        return this;
    }

    public PolylineOptions pattern(List<PatternItem> pattern) {
        real.pattern(pattern);
        return this;
    }

    public PolylineOptions startCap(Cap cap) {
        real.startCap(cap);
        return this;
    }

    public PolylineOptions visible(boolean visible) {
        real.visible(visible);
        return this;
    }

    public PolylineOptions width(float width) {
        real.width(width);
        return this;
    }

    public PolylineOptions zIndex(float zIndex) {
        real.zIndex(zIndex);
        return this;
    }
}


text:
Stanisław Rafajłowicz (lit. Stanislovas Svetkus Rapolionis, łac. Stanislaus Rapagel(l)anus, Stanislaus Lituanus; ur. około 1485 lub 1500 w Hornostaiszkach koło Ejszyszek, zm. 13 maja 1545 w Królewcu) – luteranin i reformator protestancki z Wielkiego Księstwa Litewskiego.

Pod patronatem księcia pruskiego Albrechta Hohenzollerna uzyskał licencjat a następnie doktorat z teologii na protestanckim Uniwersytecie w Wittenberdze, gdzie studiował pod kierunkiem Marcina Lutra i Filipa Melanchtona. Po ukończeniu studiów został pierwszym profesorem teologii na nowo utworzonym Uniwersytecie Albrechta w Królewcu, znanym również jako Albertyna. Jako profesor rozpoczął pracę nad kilkoma publikacjami i tłumaczeniami, między innymi tłumaczeniem Biblii na język polski. Uważa się, że rozpoczął także pierwsze tłumaczenie Biblii na język litewski. Wraz z Abrahamem Kulwieciem Rafajłowicz był jednym z pierwszych autorów piszących w języku litewskim. Mimo że Rafajłowicz i Kulwieć zmarli dość wcześnie pozostawiając po sobie niedokończone prace, położyli oni podwaliny pod rozwój przyszłej literatury litewskiej.

Początki i studia w Krakowie
Niewiele wiadomo o życiu Rafajłowicza przed rozpoczęciem przez niego studiów na Uniwersytecie Marcina Lutra w Halle i Wittenberdze w 1542 roku. Wynika to z faktu że większość jego wczesnych biografii jest jedynie przypuszczeniem. Był potomkiem litewskiej rodziny szlacheckiej zamieszkującej wieś Hornostaiszki w okolicach Ejszyszek, która prawdopodobnie używała herbu Działosza (zdjęcie podobnego herbu zostało dodane obok jego nazwiska w rejestrze na Uniwersytecie w Królewcu). Jego data urodzenia jest nieznana. W 1726 r. Michael Lilienthal napisał, że Rafajłowicz zmarł w wieku 60 lat, co oznaczałoby iż urodził się około 1485 roku. Jednak nowsze publikacje zwykle podają rok 1500 jako faktyczną datę narodzin.

Wszyscy ówcześni biografowie którzy podjęli się napisania życiorysu Rafajłowicza stwierdzili, że przed jego nawróceniem na luteranizm (prawdopodobnie około 1525 roku) należał on do Zakonu Franciszkanów w Wilnie. Był wykształconym człowiekiem i zarabiał na życie jako prywatny nauczyciel miejscowej szlachty. Uważa się, że Rafajłowcz uzyskał wsparcie od Jonasa Stanislovasa Bilevičiusa, żmudzkiego szlachcica i przygotował grupę studentów na studia na Uniwersytecie Jagiellońskim (ówcześnie pod nazwą Akademia Krakowska), jedynej istniejącej wówczas uczelni wyższej w regionie. On i jego pięciu studentów zapisali się na uniwersytet 3 sierpnia 1528 roku. Jest prawdopodobne, że Abraham Kulwieć również należał do tej grupy. Rafajłowicz przedstawiał się jako Stanislovas, syn Jurgisa z Rosieni w diecezji żmudzkiej (Stanislaus Georgy de Rozeny dioecesis Smodiensis) być może dlatego, aby ukryć swoją prawdziwą tożsamość gdyż on jako były mnich chciał dostać się do katolickiego uniwersytetu. Studia ukończył w 1532 lub 1533 roku, zostając bakałarzem.

Do dzisiaj nie zachowały się żadne źródła potwierdzające informacje o działalności Rafajłowicza w okresie  od 1532 do 1542 roku. Prawdopodobnie był wychowawcą szlachty lub uczył w szkole wyższej założonej przez Abrahama Kulwiecia w Wilnie. Król polski i wielki książę litewski Zygmunt I Stary nie popierał reformacji, a w maju 1542 r. wydał edykt o herezji skierowany przeciwko Kulwieciowi i innym protestantom, którzy mogli być teraz sądzeni przez biskupa. Wielu działaczy protestanckich opuściło zatem Wielkie Księstwo Litewskie i osiedliło się w luterańskich Prusach Książęcych.

Studia w Wittenberdze
Rafajłowicz otrzymał wsparcie finansowe od księcia Albrechta i zapisał się na Uniwersytet w Wittenberdze 22 marca 1542 roku. Zachowane ogłoszenie z tamtych czasów sugeruje, że Rafajłowicz oferował prywatne lekcje języka hebrajskiego. Doktorat z teologii uzyskał po publicznej obronie swoich 28 tez w dniu 23 maja 1544 roku. Obronie tej przewodniczył Marcin Luter (w ostatniej dekadzie życia przewodniczył on 13 obronom), prawdopodobnie Filip Melanchton był jego promotorem. Teza Rafajłowicza Die poenitentia (O skrusze, dobrych uczynkach i ich wpływie na wyrok) została zainspirowana wykładem religijnym wygłoszonym w 1541 na konferencji w Ratyzbonie. Protokół obrony, rozpowszechniany później w licznych ośrodkach luterańskich napisał Johann Stoltz (jego kopię zachowała Biblioteka Akademicka Uniwersytetu Łotewskiego). 29 maja Rafajłowicz otrzymał insygnia doktora teologii (czapkę, pierścień i Biblię) a Kaspar Cruciger Starszy wygłosił przemówienie De dono interpretis in ecclesia, które podkreślało znaczenie prawidłowego wyjaśnienia słowa Bożego świeckim ludziom. Ceremonia zakończyła się uroczystą publiczną procesją przez miasto i wielką ucztą.

Pobyt w Królewcu
Niedługo później Rafajłowicz wyjechał do Królewca gdzie brał udział w tworzeniu Collegium Albertinum, późniejszego Uniwersytetu w Królewcu. Został pierwszym kierownikiem Wydziału Teologicznego tej uczelni. Jego roczna pensja wynosiła 200 guldenów, co było najwyższą wówczas oferowaną pensją i odzwierciedlało wagę jego pozycji. Uczył teologii, języka hebrajskiego, był również psalmistą. Rafajłowicz, choć niski i ze skrzywieniem kręgosłupa, stał się znany ze swoich zdolności retorycznych, a jego wykłady stały się popularne, brali w nich udział wybitni członkowie pruskiego establishmentu, w tym książę Albrecht.

Rafajłowicz był aktywny zawodowo krócej niż rok. Napisał i opublikował 42 tezę łacińską De ecclesia et eius notis na temat niektórych podstawowych cech luteranizmu. Korzystając z argumentów biblijnych wyjaśnił, dlaczego kościół reformatów był przeciwny kultowi świętych, celibatowi kapłanów, radom ewangelicznym, Sakramentowi Pokuty, rozgrzeszaniu z grzechów śmiertelnych i innym kwestiom. Oryginalne wydanie, opublikowane przez Jana Weinreicha, nie zachowało się, ale tekst został ponownie opublikowany przez Hieronymusa Mencla w 1558 i 1562.

Rafajłowcz był również aktywny w tłumaczeniach. Ocenił katechizm przetłumaczony przez Jana Seklucjana na język polski i zatwierdził go do użycia w diecezji pomezańskiej pomimo pewnej krytyki i oporu ze strony duchowieństwa. Pracował nad tłumaczeniem Biblii na język polski. Z zachowanych do dziś listów wynika, że Rafajłowicz korespondował z Bernardem Wojewódką, drukarzem z Krakowa, o założeniu sklepu w Królewcu w celu drukowania polskiej Biblii. Rafajłowicz przetłumaczył co najmniej jeden hymn na litewski. Wszystko wskazuje na to, że była to pieśń Patris sapientia, veritas divina, która ma dziesięć zwrotek. Hymn został opublikowany jako Giesme ape kenteghima Jhesaus Christaus amszinoija Diewa sunaus w 1570 roku w kancjonale Martynasa Mažvydasa. Jest to jedyny zachowany tekst Rafajłowicza w języku litewskim.  Naukowcy uważają, że Rafajłowicz zaczął tłumaczyć również Biblię na język litewski chociaż nie ma na to bezpośrednich dowodów.

W listopadzie 1544 Rafajłowicz ożenił się z Catherine, córką Basiliusa Axta, osobistego lekarza księcia Prus. Koszty związane ze ślubem pokrył sam książę. W maju 1545 Rafajłowicz nagle doznał udaru mózgu i paraliżu. Zmarł kilka dni później, 13 maja. Książę Albrecht winą za przedwczesną śmierć Rafajłowicza obarczył liczne nieporozumienia i intrygi na uniwersytecie. Osobiście uczestniczył później w dużej ceremonii pogrzebowej i rozkazał pochować go w Katedrze Matki Bożej i św. Wojciecha w Królewcu. Mowę pogrzebową wygłosił Johann Briesmann. Utwór pochwalny na jego cześć został napisany przez Bernardusa Holtorpiusa. Napis na nagrobku Rafajłowicza głosił: "Tu leży wielki człowiek, duma narodu litewskiego". Jego grób nie zachował się.

Przypisy

Bibliografia

Wykładowcy Uniwersytetu Albrechta w Królewcu
Absolwenci i studenci Uniwersytetu w Wittenberdze
Absolwenci Uniwersytetu Jagiellońskiego
Ludzie związani z Wilnem
Litewscy pisarze
Litewscy pisarze polskojęzyczni
Luteranizm na Litwie
Polska szlachta
Reformatorzy protestanccy
Zmarli w 1545

redpajama_set_name: RedPajamaWikipedia