Make WordPress Core


Ignore:
Timestamp:
10/10/2021 01:15:16 AM (3 years ago)
Author:
SergeyBiryukov
Message:

External Libraries: Revert [51900] for now to investigate test failures.

See #54162.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/ID3/module.audio-video.quicktime.php

    r51900 r51901  
    2525{
    2626
    27     /** audio-video.quicktime
    28      * return all parsed data from all atoms if true, otherwise just returned parsed metadata
    29      *
    30      * @var bool
    31      */
    32     public $ReturnAtomData        = false;
    33 
    34     /** audio-video.quicktime
    35      * return all parsed data from all atoms if true, otherwise just returned parsed metadata
    36      *
    37      * @var bool
    38      */
     27    public $ReturnAtomData        = true;
    3928    public $ParseAllPossibleAtoms = false;
    4029
     
    182171        }
    183172
    184         if (!isset($info['bitrate']) && !empty($info['playtime_seconds'])) {
     173        if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
    185174            $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
    186175        }
     
    572561                                                $atom_structure['data'] = substr($boxdata, 8);
    573562                                                if ($atomname == 'covr') {
    574                                                     if (!empty($atom_structure['data'])) {
    575                                                         $atom_structure['image_mime'] = 'image/unknown'; // provide default MIME type to ensure array keys exist
    576                                                         if (function_exists('getimagesizefromstring') && ($getimagesize = getimagesizefromstring($atom_structure['data'])) && !empty($getimagesize['mime'])) {
    577                                                             $atom_structure['image_mime'] = $getimagesize['mime'];
    578                                                         } else {
    579                                                             // if getimagesizefromstring is not available, or fails for some reason, fall back to simple detection of common image formats
    580                                                             $ImageFormatSignatures = array(
    581                                                                 'image/jpeg' => "\xFF\xD8\xFF",
    582                                                                 'image/png'  => "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A",
    583                                                                 'image/gif'  => 'GIF',
    584                                                             );
    585                                                             foreach ($ImageFormatSignatures as $mime => $image_format_signature) {
    586                                                                 if (substr($atom_structure['data'], 0, strlen($image_format_signature)) == $image_format_signature) {
    587                                                                     $atom_structure['image_mime'] = $mime;
    588                                                                     break;
    589                                                                 }
    590                                                             }
    591                                                         }
    592                                                         $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
    593                                                     } else {
    594                                                         $this->warning('Unknown empty "covr" image at offset '.$baseoffset);
     563                                                    // not a foolproof check, but better than nothing
     564                                                    if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {
     565                                                        $atom_structure['image_mime'] = 'image/jpeg';
     566                                                    } elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {
     567                                                        $atom_structure['image_mime'] = 'image/png';
     568                                                    } elseif (preg_match('#^GIF#', $atom_structure['data'])) {
     569                                                        $atom_structure['image_mime'] = 'image/gif';
    595570                                                    }
     571                                                    $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
    596572                                                }
    597573                                                break;
     
    753729                    $atom_structure['flags']['slide_show']   = (bool) $atom_structure['slide_show_flag'];
    754730
    755                     $ptv_lookup = array(
    756                         0 => 'normal',
    757                         1 => 'double',
    758                         2 => 'half',
    759                         3 => 'full',
    760                         4 => 'current'
    761                     );
     731                    $ptv_lookup[0] = 'normal';
     732                    $ptv_lookup[1] = 'double';
     733                    $ptv_lookup[2] = 'half';
     734                    $ptv_lookup[3] = 'full';
     735                    $ptv_lookup[4] = 'current';
    762736                    if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
    763737                        $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
     
    935909                                        $atom_structure['sample_description_table'][$i]['video_color_table_id']    =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68,  2));
    936910
    937                                         $atom_structure['sample_description_table'][$i]['video_pixel_color_type']  = (((int) $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
     911                                        $atom_structure['sample_description_table'][$i]['video_pixel_color_type']  = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
    938912                                        $atom_structure['sample_description_table'][$i]['video_pixel_color_name']  = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
    939913
     
    941915                                            $info['quicktime']['video']['codec_fourcc']        = $atom_structure['sample_description_table'][$i]['data_format'];
    942916                                            $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
    943                                             $info['quicktime']['video']['codec']               = (((int) $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
     917                                            $info['quicktime']['video']['codec']               = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
    944918                                            $info['quicktime']['video']['color_depth']         = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
    945919                                            $info['quicktime']['video']['color_depth_name']    = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
     
    16251599
    16261600                case 'NCDT':
    1627                     // https://exiftool.org/TagNames/Nikon.html
     1601                    // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
    16281602                    // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
    16291603                    $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
     
    16311605                case 'NCTH': // Nikon Camera THumbnail image
    16321606                case 'NCVW': // Nikon Camera preVieW image
    1633                 case 'NCM1': // Nikon Camera preview iMage 1
    1634                 case 'NCM2': // Nikon Camera preview iMage 2
    1635                     // https://exiftool.org/TagNames/Nikon.html
     1607                    // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
    16361608                    if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
    1637                         $descriptions = array(
    1638                             'NCTH' => 'Nikon Camera Thumbnail Image',
    1639                             'NCVW' => 'Nikon Camera Preview Image',
    1640                             'NCM1' => 'Nikon Camera Preview Image 1',
    1641                             'NCM2' => 'Nikon Camera Preview Image 2',
    1642                         );
    16431609                        $atom_structure['data'] = $atom_data;
    16441610                        $atom_structure['image_mime'] = 'image/jpeg';
    1645                         $atom_structure['description'] = isset($descriptions[$atomname]) ? $descriptions[$atomname] : 'Nikon preview image';
    1646                         $info['quicktime']['comments']['picture'][] = array(
    1647                             'image_mime' => $atom_structure['image_mime'],
    1648                             'data' => $atom_data,
    1649                             'description' => $atom_structure['description']
    1650                         );
    1651                     }
    1652                     break;
    1653                 case 'NCTG': // Nikon - https://exiftool.org/TagNames/Nikon.html#NCTG
    1654                     getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.nikon-nctg.php', __FILE__, true);
    1655                     $nikonNCTG = new getid3_tag_nikon_nctg($this->getid3);
    1656 
    1657                     $atom_structure['data'] = $nikonNCTG->parse($atom_data);
    1658                     break;
    1659                 case 'NCHD': // Nikon:MakerNoteVersion  - https://exiftool.org/TagNames/Nikon.html
    1660                     $makerNoteVersion = '';
    1661                     for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) {
    1662                         if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) {
    1663                             $makerNoteVersion .= ' '.ord($atom_data[$i]);
    1664                         } else {
    1665                             $makerNoteVersion .= $atom_data[$i];
    1666                         }
    1667                     }
    1668                     $makerNoteVersion = rtrim($makerNoteVersion, "\x00");
    1669                     $atom_structure['data'] = array(
    1670                         'MakerNoteVersion' => $makerNoteVersion
    1671                     );
    1672                     break;
    1673                 case 'NCDB': // Nikon                   - https://exiftool.org/TagNames/Nikon.html
    1674                 case 'CNCV': // Canon:CompressorVersion - https://exiftool.org/TagNames/Canon.html
     1611                        $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
     1612                        $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
     1613                    }
     1614                    break;
     1615                case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
     1616                    $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
     1617                    break;
     1618                case 'NCHD': // Nikon:MakerNoteVersion  - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
     1619                case 'NCDB': // Nikon                   - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
     1620                case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
    16751621                    $atom_structure['data'] = $atom_data;
    16761622                    break;
     
    16791625                    // some kind of metacontainer, may contain a big data dump such as:
    16801626                    // mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
    1681                     // https://xhelmboyx.tripod.com/formats/qti-layout.txt
     1627                    // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
    16821628
    16831629                    $atom_structure['version']   =          getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
     
    17761722                                    'debug_list'     => '',      // Used to debug variables stored as comma delimited strings
    17771723                            );
    1778                             $debug_structure = array();
    17791724                            $debug_structure['debug_items'] = array();
    17801725                            // Can start loop here to decode all sensor data in 32 Byte chunks:
     
    20952040     */
    20962041    public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
    2097         $atom_structure = array();
     2042        $atom_structure  = false;
    20982043        $subatomoffset  = 0;
    20992044        $subatomcounter = 0;
     
    21132058                    continue;
    21142059                }
    2115                 break;
     2060                return $atom_structure;
    21162061            }
    21172062            if (strlen($subatomdata) < ($subatomsize - 8)) {
     
    21192064                // this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large
    21202065                // so we passed in the start of a following atom incorrectly?
    2121                 break;
     2066                return $atom_structure;
    21222067            }
    21232068            $atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
    21242069            $subatomoffset += $subatomsize;
    21252070        }
    2126 
    2127         if (empty($atom_structure)) {
    2128             return false;
    2129         }
    2130 
    21312071        return $atom_structure;
    21322072    }
     
    26132553        if (empty($QuicktimeContentRatingLookup)) {
    26142554            $QuicktimeContentRatingLookup[0]  = 'None';
    2615             $QuicktimeContentRatingLookup[1]  = 'Explicit';
    26162555            $QuicktimeContentRatingLookup[2]  = 'Clean';
    2617             $QuicktimeContentRatingLookup[4]  = 'Explicit (old)';
     2556            $QuicktimeContentRatingLookup[4]  = 'Explicit';
    26182557        }
    26192558        return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
     
    26662605        }
    26672606        return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
     2607    }
     2608
     2609    /**
     2610     * @param string $atom_data
     2611     *
     2612     * @return array
     2613     */
     2614    public function QuicktimeParseNikonNCTG($atom_data) {
     2615        // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
     2616        // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
     2617        // Data is stored as records of:
     2618        // * 4 bytes record type
     2619        // * 2 bytes size of data field type:
     2620        //     0x0001 = flag   (size field *= 1-byte)
     2621        //     0x0002 = char   (size field *= 1-byte)
     2622        //     0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
     2623        //     0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
     2624        //     0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
     2625        //     0x0007 = bytes  (size field *= 1-byte), values are stored as ??????
     2626        //     0x0008 = ?????  (size field *= 2-byte), values are stored as ??????
     2627        // * 2 bytes data size field
     2628        // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
     2629        // all integers are stored BigEndian
     2630
     2631        $NCTGtagName = array(
     2632            0x00000001 => 'Make',
     2633            0x00000002 => 'Model',
     2634            0x00000003 => 'Software',
     2635            0x00000011 => 'CreateDate',
     2636            0x00000012 => 'DateTimeOriginal',
     2637            0x00000013 => 'FrameCount',
     2638            0x00000016 => 'FrameRate',
     2639            0x00000022 => 'FrameWidth',
     2640            0x00000023 => 'FrameHeight',
     2641            0x00000032 => 'AudioChannels',
     2642            0x00000033 => 'AudioBitsPerSample',
     2643            0x00000034 => 'AudioSampleRate',
     2644            0x02000001 => 'MakerNoteVersion',
     2645            0x02000005 => 'WhiteBalance',
     2646            0x0200000b => 'WhiteBalanceFineTune',
     2647            0x0200001e => 'ColorSpace',
     2648            0x02000023 => 'PictureControlData',
     2649            0x02000024 => 'WorldTime',
     2650            0x02000032 => 'UnknownInfo',
     2651            0x02000083 => 'LensType',
     2652            0x02000084 => 'Lens',
     2653        );
     2654
     2655        $offset = 0;
     2656        $data = null;
     2657        $datalength = strlen($atom_data);
     2658        $parsed = array();
     2659        while ($offset < $datalength) {
     2660            $record_type       = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));  $offset += 4;
     2661            $data_size_type    = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
     2662            $data_size         = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
     2663            switch ($data_size_type) {
     2664                case 0x0001: // 0x0001 = flag   (size field *= 1-byte)
     2665                    $data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));
     2666                    $offset += ($data_size * 1);
     2667                    break;
     2668                case 0x0002: // 0x0002 = char   (size field *= 1-byte)
     2669                    $data = substr($atom_data, $offset, $data_size * 1);
     2670                    $offset += ($data_size * 1);
     2671                    $data = rtrim($data, "\x00");
     2672                    break;
     2673                case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
     2674                    $data = '';
     2675                    for ($i = $data_size - 1; $i >= 0; $i--) {
     2676                        $data .= substr($atom_data, $offset + ($i * 2), 2);
     2677                    }
     2678                    $data = getid3_lib::BigEndian2Int($data);
     2679                    $offset += ($data_size * 2);
     2680                    break;
     2681                case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
     2682                    $data = '';
     2683                    for ($i = $data_size - 1; $i >= 0; $i--) {
     2684                        $data .= substr($atom_data, $offset + ($i * 4), 4);
     2685                    }
     2686                    $data = getid3_lib::BigEndian2Int($data);
     2687                    $offset += ($data_size * 4);
     2688                    break;
     2689                case 0x0005: // 0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
     2690                    $data = array();
     2691                    for ($i = 0; $i < $data_size; $i++) {
     2692                        $numerator    = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));
     2693                        $denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));
     2694                        if ($denomninator == 0) {
     2695                            $data[$i] = false;
     2696                        } else {
     2697                            $data[$i] = (double) $numerator / $denomninator;
     2698                        }
     2699                    }
     2700                    $offset += (8 * $data_size);
     2701                    if (count($data) == 1) {
     2702                        $data = $data[0];
     2703                    }
     2704                    break;
     2705                case 0x0007: // 0x0007 = bytes  (size field *= 1-byte), values are stored as ??????
     2706                    $data = substr($atom_data, $offset, $data_size * 1);
     2707                    $offset += ($data_size * 1);
     2708                    break;
     2709                case 0x0008: // 0x0008 = ?????  (size field *= 2-byte), values are stored as ??????
     2710                    $data = substr($atom_data, $offset, $data_size * 2);
     2711                    $offset += ($data_size * 2);
     2712                    break;
     2713                default:
     2714                    echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
     2715                    break 2;
     2716            }
     2717
     2718            switch ($record_type) {
     2719                case 0x00000011: // CreateDate
     2720                case 0x00000012: // DateTimeOriginal
     2721                    $data = strtotime($data);
     2722                    break;
     2723                case 0x0200001e: // ColorSpace
     2724                    switch ($data) {
     2725                        case 1:
     2726                            $data = 'sRGB';
     2727                            break;
     2728                        case 2:
     2729                            $data = 'Adobe RGB';
     2730                            break;
     2731                    }
     2732                    break;
     2733                case 0x02000023: // PictureControlData
     2734                    $PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');
     2735                    $FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange',    0x83=>'red', 0x84=>'green',  0xff=>'n/a');
     2736                    $ToningEffect = array(0x80=>'b&w', 0x81=>'sepia',  0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');
     2737                    $data = array(
     2738                        'PictureControlVersion'     =>                           substr($data,  0,  4),
     2739                        'PictureControlName'        =>                     rtrim(substr($data,  4, 20), "\x00"),
     2740                        'PictureControlBase'        =>                     rtrim(substr($data, 24, 20), "\x00"),
     2741                        //'?'                       =>                           substr($data, 44,  4),
     2742                        'PictureControlAdjust'      => $PictureControlAdjust[ord(substr($data, 48,  1))],
     2743                        'PictureControlQuickAdjust' =>                       ord(substr($data, 49,  1)),
     2744                        'Sharpness'                 =>                       ord(substr($data, 50,  1)),
     2745                        'Contrast'                  =>                       ord(substr($data, 51,  1)),
     2746                        'Brightness'                =>                       ord(substr($data, 52,  1)),
     2747                        'Saturation'                =>                       ord(substr($data, 53,  1)),
     2748                        'HueAdjustment'             =>                       ord(substr($data, 54,  1)),
     2749                        'FilterEffect'              =>         $FilterEffect[ord(substr($data, 55,  1))],
     2750                        'ToningEffect'              =>         $ToningEffect[ord(substr($data, 56,  1))],
     2751                        'ToningSaturation'          =>                       ord(substr($data, 57,  1)),
     2752                    );
     2753                    break;
     2754                case 0x02000024: // WorldTime
     2755                    // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
     2756                    // timezone is stored as offset from GMT in minutes
     2757                    $timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));
     2758                    if ($timezone & 0x8000) {
     2759                        $timezone = 0 - (0x10000 - $timezone);
     2760                    }
     2761                    $timezone /= 60;
     2762
     2763                    $dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));
     2764                    switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {
     2765                        case 2:
     2766                            $datedisplayformat = 'D/M/Y'; break;
     2767                        case 1:
     2768                            $datedisplayformat = 'M/D/Y'; break;
     2769                        case 0:
     2770                        default:
     2771                            $datedisplayformat = 'Y/M/D'; break;
     2772                    }
     2773
     2774                    $data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);
     2775                    break;
     2776                case 0x02000083: // LensType
     2777                    $data = array(
     2778                        //'_'  => $data,
     2779                        'mf' => (bool) ($data & 0x01),
     2780                        'd'  => (bool) ($data & 0x02),
     2781                        'g'  => (bool) ($data & 0x04),
     2782                        'vr' => (bool) ($data & 0x08),
     2783                    );
     2784                    break;
     2785            }
     2786            $tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));
     2787            $parsed[$tag_name] = $data;
     2788        }
     2789        return $parsed;
    26682790    }
    26692791
Note: See TracChangeset for help on using the changeset viewer.