public function execute()
 {
     $output = $this->getOption('output', 'default');
     // Select an output engine
     switch ($output) {
         case 'wiki':
             $out = new WikiStatsOutput();
             break;
         case 'text':
             $out = new TextStatsOutput();
             break;
         case 'csv':
             $out = new CsvStatsOutput();
             break;
         default:
             $out = new TranslateStatsOutput();
     }
     $skipLanguages = array();
     if ($this->hasOption('skiplanguages')) {
         $skipLanguages = array_map('trim', explode(',', $this->getOption('skiplanguages')));
     }
     $reportScore = false;
     // Check if score should be reported and prepare weights
     $most = $this->getOption('most');
     $weights = array();
     if ($most && isset($this->localisedWeights[$most])) {
         $reportScore = true;
         foreach ($this->localisedWeights[$most] as $weight) {
             $weights[] = $weight;
         }
     }
     // check if l10n should be done
     $l10n = false;
     if (($output === 'wiki' || $output === 'default') && !$this->hasOption('nol10n')) {
         $l10n = true;
     }
     $wmfscore = $this->hasOption('wmfscore');
     // Get groups from input
     $groups = array();
     if ($reportScore) {
         $reqGroups = array_keys($this->localisedWeights[$most]);
     } elseif ($wmfscore) {
         $reqGroups = array_keys($this->localisedWeights['wikimedia']);
     } else {
         $reqGroups = array_map('trim', explode(',', $this->getOption('groups')));
     }
     // List of all groups
     $allGroups = MessageGroups::singleton()->getGroups();
     // Get list of valid groups
     foreach ($reqGroups as $id) {
         // Page translation group ids use spaces which are not nice on command line
         $id = str_replace('_', ' ', $id);
         if (isset($allGroups[$id])) {
             $groups[$id] = $allGroups[$id];
         } else {
             $this->output("Unknown group: {$id}");
         }
     }
     if ($wmfscore) {
         // Override/set parameters
         $out = new CsvStatsOutput();
         $reportScore = true;
         $weights = array();
         foreach ($this->localisedWeights['wikimedia'] as $weight) {
             $weights[] = $weight;
         }
         $wmfscores = array();
     }
     if (!count($groups)) {
         $this->error('No groups given', true);
     }
     // List of all languages.
     $languages = Language::fetchLanguageNames(false);
     // Default sorting order by language code, users can sort wiki output.
     ksort($languages);
     if ($this->hasOption('legenddetail')) {
         $out->addFreeText("{{" . $this->getOption('legenddetail') . "}}\n");
     }
     $totalWeight = 0;
     if ($reportScore) {
         if ($wmfscore) {
             foreach ($this->localisedWeights['wikimedia'] as $weight) {
                 $totalWeight += $weight;
             }
         } else {
             foreach ($this->localisedWeights[$most] as $weight) {
                 $totalWeight += $weight;
             }
         }
     }
     $showContinent = $this->getOption('continent');
     if (!$wmfscore) {
         // Output headers
         $out->heading();
         $out->blockstart();
         if ($most) {
             $out->element($l10n ? "{{int:translate-gs-pos}}" : 'Pos.', true);
         }
         $out->element($l10n ? "{{int:translate-gs-code}}" : 'Code', true);
         $out->element($l10n ? "{{int:translate-page-language}}" : 'Language', true);
         if ($showContinent) {
             $out->element($l10n ? "{{int:translate-gs-continent}}" : 'Continent', true);
         }
         if ($most && $this->hasOption('speakers')) {
             $out->element($l10n ? "{{int:translate-gs-speakers}}" : 'Speakers', true);
         }
         if ($reportScore) {
             $out->element(($l10n ? "{{int:translate-gs-score}}" : 'Score') . ' (' . $totalWeight . ')', true);
         }
         /**
          * @var $g MessageGroup
          */
         foreach ($groups as $g) {
             // Add unprocessed description of group as heading
             if ($reportScore) {
                 $gid = $g->getId();
                 $heading = $g->getLabel() . " (" . $this->localisedWeights[$most][$gid] . ")";
             } else {
                 $heading = $g->getLabel();
             }
             $out->element($heading, true);
             if (!$reportScore && $this->hasOption('fuzzy')) {
                 $out->element($l10n ? "{{int:translate-percentage-fuzzy}}" : 'Fuzzy', true);
             }
         }
         $out->blockend();
     }
     $rows = array();
     foreach ($languages as $code => $name) {
         // Skip list
         if (in_array($code, $skipLanguages)) {
             continue;
         }
         $rows[$code] = array();
     }
     foreach ($groups as $groupName => $g) {
         $stats = MessageGroupStats::forGroup($groupName);
         // Perform the statistic calculations on every language
         foreach ($languages as $code => $name) {
             // Skip list
             if (!$most && in_array($code, $skipLanguages)) {
                 continue;
             }
             // Do not calculate if we do not need it for anything.
             if ($wmfscore && isset($this->wikimediaCodeMap[$code]) && $this->wikimediaCodeMap[$code] == '') {
                 continue;
             }
             // If --most is set, skip all other
             if ($most && !isset($this->mostSpokenLanguages[$code])) {
                 continue;
             }
             $total = $stats[$code][MessageGroupStats::TOTAL];
             $translated = $stats[$code][MessageGroupStats::TRANSLATED];
             $fuzzy = $stats[$code][MessageGroupStats::FUZZY];
             $rows[$code][] = array(false, $translated, $total);
             if ($this->hasOption('fuzzy')) {
                 $rows[$code][] = array(true, $fuzzy, $total);
             }
         }
         unset($collection);
     }
     // init summary array
     $summarise = false;
     if ($this->hasOption('summary')) {
         $summarise = true;
         $summary = array();
     }
     foreach ($languages as $code => $name) {
         // Skip list
         if (!$most && in_array($code, $skipLanguages)) {
             continue;
         }
         // Skip unneeded
         if ($wmfscore && isset($this->wikimediaCodeMap[$code]) && $this->wikimediaCodeMap[$code] == '') {
             continue;
         }
         // If --most is set, skip all other
         if ($most && !isset($this->mostSpokenLanguages[$code])) {
             continue;
         }
         $columns = $rows[$code];
         $allZero = true;
         foreach ($columns as $fields) {
             if (intval($fields[1]) !== 0) {
                 $allZero = false;
             }
         }
         // Skip dummy languages if requested
         if ($allZero && $this->hasOption('skipzero')) {
             continue;
         }
         // Output the the row
         if (!$wmfscore) {
             $out->blockstart();
         }
         // Fill language position field
         if ($most) {
             $out->element($this->mostSpokenLanguages[$code][0]);
         }
         // Fill language name field
         if (!$wmfscore) {
             // Fill language code field
             $out->element($code);
             if ($l10n && function_exists('efI18nTagsInit')) {
                 $out->element("{{#languagename:" . $code . "}}");
             } else {
                 $out->element($name);
             }
         }
         // Fill continent field
         if ($showContinent) {
             if ($this->mostSpokenLanguages[$code][2] == 'multiple') {
                 $continent = $l10n ? "{{int:translate-gs-multiple}}" : 'Multiple';
             } else {
                 $continent = $l10n ? "{{int:timezoneregion-" . $this->mostSpokenLanguages[$code][2] . "}}" : ucfirst($this->mostSpokenLanguages[$code][2]);
             }
             $out->element($continent);
         }
         // Fill speakers field
         if ($most && $this->hasOption('speakers')) {
             $out->element(number_format($this->mostSpokenLanguages[$code][1]));
         }
         // Fill the score field
         if ($reportScore) {
             // Keep count
             $i = 0;
             // Start with 0 points
             $score = 0;
             foreach ($columns as $fields) {
                 list(, $upper, $total) = $fields;
                 // Weigh the score and add it to the current score
                 $score += $weights[$i] * $upper / $total;
                 $i++;
             }
             // Report a round numbers
             $score = number_format($score, 0);
             if ($summarise) {
                 $continent = $this->mostSpokenLanguages[$code][2];
                 if (isset($summary[$continent])) {
                     $newcount = $summary[$continent][0] + 1;
                     $newscore = $summary[$continent][1] + (int) $score;
                 } else {
                     $newcount = 1;
                     $newscore = $score;
                 }
                 $summary[$continent] = array($newcount, $newscore);
             }
             if ($wmfscore) {
                 // Multiple variants can be used for the same wiki.
                 // Store the scores in an array and output them later
                 // when they can be averaged.
                 if (isset($this->wikimediaCodeMap[$code])) {
                     $wmfcode = $this->wikimediaCodeMap[$code];
                 } else {
                     $codeparts = explode('-', $code);
                     $wmfcode = $codeparts[0];
                 }
                 if (isset($wmfscores[$wmfcode])) {
                     $count = $wmfscores[$wmfcode]['count'] + 1;
                     $tmpWmfScore = (int) $wmfscores[$wmfcode]['score'];
                     $tmpWmfCount = (int) $wmfscores[$wmfcode]['count'];
                     $score = ($tmpWmfCount * $tmpWmfScore + (int) $score) / $count;
                     $wmfscores[$wmfcode] = array('score' => $score, 'count' => $count);
                 } else {
                     $wmfscores[$wmfcode] = array('score' => $score, 'count' => 1);
                 }
             } else {
                 $out->element($score);
             }
         }
         // Fill fields for groups
         if (!$wmfscore) {
             foreach ($columns as $fields) {
                 list($invert, $upper, $total) = $fields;
                 $c = $out->formatPercent($upper, $total, $invert);
                 $out->element($c);
             }
             $out->blockend();
         }
     }
     $out->footer();
     if ($reportScore && $this->hasOption('summary')) {
         if ($reportScore && $this->hasOption('legendsummary')) {
             $out->addFreeText("{{" . $this->getOption('legendsummary') . "}}\n");
         }
         $out->summaryheading();
         $out->blockstart();
         $out->element($l10n ? "{{int:translate-gs-continent}}" : 'Continent', true);
         $out->element($l10n ? "{{int:translate-gs-count}}" : 'Count', true);
         $out->element($l10n ? "{{int:translate-gs-avgscore}}" : 'Avg. score', true);
         $out->blockend();
         ksort($summary);
         $totals = array(0, 0);
         foreach ($summary as $key => $values) {
             $out->blockstart();
             if ($key == 'multiple') {
                 $out->element($l10n ? "{{int:translate-gs-multiple}}" : 'Multiple');
             } else {
                 $out->element($l10n ? "{{int:timezoneregion-" . $key . "}}" : ucfirst($key));
             }
             $out->element($values[0]);
             $out->element(number_format($values[1] / $values[0]));
             $out->blockend();
             $totals[0] += $values[0];
             $totals[1] += $values[1];
         }
         $out->blockstart();
         $out->element($l10n ? "{{int:translate-gs-total}}" : 'Total');
         $out->element($totals[0]);
         $out->element(number_format($totals[1] / $totals[0]));
         $out->blockend();
         $out->footer();
     }
     // Custom output
     if ($wmfscore) {
         ksort($wmfscores);
         foreach ($wmfscores as $code => $stats) {
             echo $code . ';' . number_format($stats['score']) . ";\n";
         }
     }
 }
\t\t* 'text'     : Text with tabs.
Example: php maintenance/transstat.php --output=text

TEXT;
    exit(1);
}
# Select an output engine
switch ($options['output']) {
    case 'wiki':
        $output = new WikiStatsOutput();
        break;
    case 'text':
        $output = new TextStatsOutput();
        break;
    case 'csv':
        $output = new CsvStatsOutput();
        break;
    default:
        showUsage();
}
# Languages
$wgLanguages = new Languages();
# Header
$output->heading();
$output->blockstart();
$output->element('Language', true);
$output->element('Code', true);
$output->element('Fallback', true);
$output->element('Translated', true);
$output->element('%', true);
$output->element('Obsolete', true);