#!/usr/bin/env python
 
import copy
import os
import tempfile
from unittest import TestCase, main
 
from cogent.parse.binary_sff import (
    seek_pad, parse_common_header, parse_read_header, parse_read_data,
    validate_common_header, parse_read, parse_binary_sff, UnsupportedSffError,
    write_pad, write_common_header, write_read_header, write_read_data,
    write_read, write_binary_sff, format_common_header, format_read_header,
    format_read_data, format_binary_sff, base36_encode, base36_decode,
    decode_location, decode_timestamp, decode_accession, decode_sff_filename,
    )
 
__author__ = "Kyle Bittinger"
__copyright__ = "Copyright 2007-2012, The Cogent Project"
__credits__ = ["Kyle Bittinger"]
__license__ = "GPL"
__version__ = "1.5.3-dev"
__maintainer__ = "Kyle Bittinger"
__email__ = "kylebittinger@gmail.com"
__status__ = "Production"
 
 
TEST_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
SFF_FP = os.path.join(TEST_DIR, 'data', 'F6AVWTA01.sff')
 
 
class WritingFunctionTests(TestCase):
    def setUp(self):
        self.output_file = tempfile.TemporaryFile()
 
    def test_write_pad(self):
        self.output_file.write('\x01\x02\x03\x04')
        write_pad(self.output_file)
        self.output_file.seek(0)
        buff = self.output_file.read()
        self.assertEqual(buff, '\x01\x02\x03\x04\x00\x00\x00\x00')
 
    def test_write_common_header(self):
        write_common_header(self.output_file, COMMON_HEADER)
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
        self.output_file.seek(0)
        observed = parse_common_header(self.output_file)
        self.assertEqual(observed, COMMON_HEADER)
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
    def test_write_read_header(self):
        write_read_header(self.output_file, READ_HEADER)
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
        self.output_file.seek(0)
        observed = parse_read_header(self.output_file)
        self.assertEqual(observed, READ_HEADER)
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
    def test_write_read_data(self):
        write_read_data(self.output_file, READ_DATA)
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
        self.output_file.seek(0)
        num_flows = len(READ_DATA['flowgram_values'])
        num_bases = len(READ_DATA['Bases'])
        observed = parse_read_data(self.output_file, num_bases, num_flows)
        self.assertEqual(observed, READ_DATA)
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
    def test_write_read(self):
        read = READ_HEADER.copy()
        read.update(READ_DATA)
        write_read(self.output_file, read)
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
        self.output_file.seek(0)
        num_flows = len(read['flowgram_values'])
        observed = parse_read(self.output_file)
        self.assertEqual(observed, read)
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
    def test_write_binary_sff(self):
        read = READ_HEADER.copy()
        read.update(READ_DATA)
 
        header = COMMON_HEADER.copy()
        header['number_of_reads'] = 1
 
        write_binary_sff(self.output_file, header, [read])
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
        self.output_file.seek(0)
        observed_header, observed_reads = parse_binary_sff(
            self.output_file, native_flowgram_values=True)
        observed_reads = list(observed_reads)
        self.assertEqual(observed_header, header)
        self.assertEqual(observed_reads[0], read)
        self.assertEqual(len(observed_reads), 1)
 
        file_pos = self.output_file.tell()
        self.assertTrue(file_pos % 8 == 0)
 
 
class ParsingFunctionTests(TestCase):
    def setUp(self):
        self.sff_file = open(SFF_FP)
 
    def test_seek_pad(self):
        f = self.sff_file
        f.seek(8)
        seek_pad(f)
        self.assertEqual(f.tell(), 8)
        f.seek(9)
        seek_pad(f)
        self.assertEqual(f.tell(), 16)
        f.seek(10)
        seek_pad(f)
        self.assertEqual(f.tell(), 16)
        f.seek(15)
        seek_pad(f)
        self.assertEqual(f.tell(), 16)
        f.seek(16)
        seek_pad(f)
        self.assertEqual(f.tell(), 16)
        f.seek(17)
        seek_pad(f)
        self.assertEqual(f.tell(), 24)
 
    def test_parse_common_header(self):
        observed = parse_common_header(self.sff_file)
        self.assertEqual(observed, COMMON_HEADER)
 
    def test_validate_common_header(self):
        header = {
            'magic_number': 779314790,
            'version': 1,
            'flowgram_format_code': 1,
            'index_offset': 0,
            'index_length': 0,
            'number_of_reads': 0,
            'header_length': 0,
            'key_length': 0,
            'number_of_flows_per_read': 0,
            'flow_chars': 'A',
            'key_sequence': 'A',
            }
        self.assertEqual(validate_common_header(header), None)
        header['version'] = 2
        self.assertRaises(UnsupportedSffError, validate_common_header, header)
 
    def test_parse_read_header(self):
        self.sff_file.seek(440)
        observed = parse_read_header(self.sff_file)
        self.assertEqual(observed, READ_HEADER)
 
    def test_parse_read_data(self):
        self.sff_file.seek(440 + 32)
        observed = parse_read_data(self.sff_file, 271, 400)
        self.assertEqual(observed, READ_DATA)
 
    def test_parse_read(self):
        self.sff_file.seek(440)
        observed = parse_read(self.sff_file, 400)
        expected = dict(READ_HEADER.items() + READ_DATA.items())
        self.assertEqual(observed, expected)
 
    def test_parse_sff(self):
        header, reads = parse_binary_sff(self.sff_file)
        self.assertEqual(header, COMMON_HEADER)
        counter = 0
        for read in reads:
            self.assertEqual(
                len(read['flowgram_values']), header['number_of_flows_per_read'])
            counter += 1
        self.assertEqual(counter, 20)
 
 
class FormattingFunctionTests(TestCase):
    def setUp(self):
        self.output_file = tempfile.TemporaryFile()
 
    def test_format_common_header(self):
        self.assertEqual(
            format_common_header(COMMON_HEADER), COMMON_HEADER_TXT)
 
    def test_format_read_header(self):
        self.assertEqual(
            format_read_header(READ_HEADER), READ_HEADER_TXT)
 
    def test_format_read_header(self):
        self.assertEqual(
            format_read_data(READ_DATA, READ_HEADER), READ_DATA_TXT)
 
    def test_format_binary_sff(self):
        output_buffer = format_binary_sff(open(SFF_FP))
        output_buffer.seek(0)
        expected = COMMON_HEADER_TXT + READ_HEADER_TXT + READ_DATA_TXT
        observed = output_buffer.read(len(expected))
        self.assertEqual(observed, expected)
 
 
class Base36Tests(TestCase):
    def test_base36_encode(self):
        self.assertEqual(base36_encode(2), 'C')
        self.assertEqual(base36_encode(37), 'BB')
 
    def test_base36_decode(self):
        self.assertEqual(base36_decode('C'), 2)
        self.assertEqual(base36_decode('BB'), 37)
 
    def test_decode_location(self):
        self.assertEqual(decode_location('C'), (0, 2))
 
    def test_decode_timestamp(self):
        self.assertEqual(decode_timestamp('C3U5GW'), (2004, 9, 22, 16, 59, 10))
        self.assertEqual(decode_timestamp('GA202I'), (2010, 1, 22, 13, 28, 56))
 
    def test_decode_accession(self):
        self.assertEqual(
            decode_accession('GA202I001ER3QL'),
            ((2010, 1, 22, 13, 28, 56), '0', 1, (1843, 859)))
 
    def test_decode_sff_filename(self):
        self.assertEqual(
            decode_sff_filename('F6AVWTA01.sff'),
            ((2009, 11, 25, 14, 30, 19), 'A', 1))
 
 
COMMON_HEADER = {
    'header_length': 440,
    'flowgram_format_code': 1,
    'index_length': 900,
    'magic_number': 779314790,
    'number_of_flows_per_read': 400,
    'version': 1,
    'flow_chars': 100 * 'TACG',
    'key_length': 4,
    'key_sequence': 'TCAG',
    'number_of_reads': 20,
    'index_offset': 33464,
    }
 
COMMON_HEADER_TXT = """\
Common Header:
  Magic Number:  0x2E736666
  Version:       0001
  Index Offset:  33464
  Index Length:  900
  # of Reads:    20
  Header Length: 440
  Key Length:    4
  # of Flows:    400
  Flowgram Code: 1
  Flow Chars:    TACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACG
  Key Sequence:  TCAG
"""
 
READ_HEADER = {
    'name_length': 14,
    'Name': 'GA202I001ER3QL',
    'clip_adapter_left': 0,
    'read_header_length': 32,
    'clip_adapter_right': 0,
    'number_of_bases': 271,
    'clip_qual_left': 5,
    'clip_qual_right': 271,
    }
 
READ_HEADER_TXT = """
>GA202I001ER3QL
  Run Prefix:   R_2010_01_22_13_28_56_
  Region #:     1
  XY Location:  1843_0859
 
  Read Header Len:  32
  Name Length:      14
  # of Bases:       271
  Clip Qual Left:   5
  Clip Qual Right:  271
  Clip Adap Left:   0
  Clip Adap Right:  0
"""
 
READ_DATA = {
    'flow_index_per_base': (
        1, 2, 3, 2, 3, 3, 2, 1, 1, 2, 1, 2, 0, 2, 3, 3, 2, 3, 3, 0, 2, 0, 2, 0,
        1, 1, 1, 2, 0, 2, 2, 1, 0, 0, 3, 0, 2, 1, 0, 1, 1, 3, 1, 2, 2, 2, 3, 2,
        1, 0, 2, 0, 3, 0, 3, 3, 1, 3, 0, 0, 0, 0, 2, 1, 0, 2, 0, 2, 0, 2, 2, 2,
        2, 3, 2, 2, 0, 1, 0, 0, 0, 2, 1, 3, 2, 0, 3, 3, 2, 1, 2, 0, 2, 2, 1, 2,
        1, 2, 0, 1, 3, 0, 0, 3, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 3, 0, 2, 1, 1, 2,
        1, 3, 2, 2, 1, 0, 3, 3, 0, 2, 0, 1, 1, 3, 3, 3, 2, 0, 0, 0, 3, 3, 2, 1,
        1, 2, 2, 1, 1, 0, 1, 0, 2, 0, 3, 1, 1, 0, 2, 0, 0, 1, 0, 3, 2, 3, 3, 3,
        1, 3, 2, 0, 1, 3, 3, 3, 1, 3, 2, 0, 1, 2, 2, 3, 3, 3, 2, 3, 3, 3, 0, 3,
        3, 2, 2, 0, 3, 1, 1, 3, 0, 1, 0, 3, 2, 2, 0, 2, 0, 2, 0, 0, 2, 3, 2, 2,
        0, 2, 0, 3, 2, 3, 1, 2, 0, 3, 0, 2, 2, 2, 1, 1, 2, 2, 1, 1, 0, 3, 3, 2,
        0, 1, 0, 3, 0, 2, 3, 1, 1, 1, 1, 3, 1, 0, 1, 1, 2, 2, 3, 1, 0, 0, 1, 1,
        3, 3, 1, 3, 0, 1, 0),
    'flowgram_values': (
        101, 0, 98, 3, 0, 104, 2, 95, 1, 0, 97, 3, 0, 110, 2, 102, 102, 110, 2,
        99, 101, 0, 195, 5, 102, 0, 5, 96, 7, 0, 95, 7, 101, 0, 8, 98, 9, 0,
        190, 9, 201, 0, 194, 101, 107, 104, 12, 198, 13, 104, 2, 105, 295, 7,
        4, 197, 10, 101, 195, 98, 101, 3, 10, 100, 102, 0, 100, 7, 101, 0, 96,
        8, 11, 102, 12, 102, 203, 9, 196, 8, 13, 206, 13, 6, 103, 10, 4, 103,
        102, 3, 7, 479, 9, 102, 202, 10, 198, 6, 195, 9, 102, 0, 100, 5, 100,
        2, 103, 8, 8, 100, 6, 102, 7, 200, 388, 10, 97, 100, 8, 5, 100, 12, 197,
        7, 13, 103, 8, 7, 104, 10, 101, 104, 12, 201, 12, 99, 8, 99, 106, 13,
        103, 102, 8, 202, 108, 9, 13, 293, 7, 4, 203, 103, 202, 107, 376, 103,
        8, 11, 188, 8, 99, 101, 104, 8, 92, 101, 12, 4, 92, 11, 101, 7, 96, 202,
        8, 12, 93, 11, 11, 202, 7, 195, 101, 102, 6, 0, 101, 7, 7, 106, 2, 6,
        107, 4, 404, 12, 6, 104, 8, 10, 98, 2, 105, 110, 100, 8, 95, 3, 105,
        102, 208, 201, 13, 195, 14, 0, 99, 86, 202, 9, 301, 206, 8, 8, 85, 6,
        101, 6, 9, 103, 8, 9, 96, 4, 7, 102, 111, 0, 8, 93, 7, 194, 111, 5, 10,
        95, 5, 10, 104, 2, 6, 98, 103, 0, 11, 99, 15, 192, 110, 5, 98, 8, 91, 8,
        10, 92, 5, 10, 102, 8, 7, 105, 15, 102, 7, 9, 100, 2, 3, 102, 6, 9, 203,
        6, 14, 107, 12, 8, 107, 1, 103, 13, 202, 2, 6, 108, 103, 99, 11, 2, 201,
        207, 14, 8, 94, 4, 95, 9, 195, 13, 193, 9, 306, 13, 100, 11, 6, 75, 13,
        91, 12, 205, 7, 203, 10, 3, 107, 17, 111, 12, 4, 105, 106, 7, 208, 5, 9,
        202, 8, 108, 6, 84, 16, 103, 108, 92, 16, 93, 8, 95, 94, 207, 17, 10,
        103, 3, 0, 104, 0, 202, 217, 16, 12, 197, 4, 90, 15, 17, 108, 98, 125,
        104, 88, 14, 15, 99, 187, 106, 109, 12, 100, 11, 81, 8, 11, 92, 304,
        112, 107, 2, 11, 94, 7, 6, 86, 97, 19, 3, 225, 206),
    'Bases': (
        'TCAGCAGTAGTCCTGCTGCCTTCCGTAGGAGTTTGGACCGTGTCTCAGTTCCAATGTGGGGGACCTTCCT'
        'CTCAGAACCCCTATCCATCGAAGACTAGGTGGGCCGTTACCCCGCCTACTATCTAATGGAACGCATCCCC'
        'ATCGTCTACCGGAATACCTTTAATCATGTGAACATGTGAACTCATGATGCCATCTTGTATTAATCTTCCT'
        'TTCAGAAGGCTGTCCAAGAGTAGACGGCAGGTTGGATACGTGTTACTCACCCGTGCGCCGG'),
    'quality_scores': (
        37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        37, 37, 37, 37, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
        40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 37, 37, 37, 37, 37,
        37, 37, 37, 34, 34, 34, 34, 34, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        38, 32, 32, 32, 32, 38, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
        37, 37, 37, 37, 38, 38, 38, 38, 40, 40, 40, 38, 38, 38, 38, 38, 38, 38,
        40, 38, 38, 38, 38, 38, 38, 37, 38, 38, 36, 37, 37, 36, 33, 28, 28, 31,
        31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 31, 30, 30, 25, 25, 25,
        25),
    }
 
READ_DATA_TXT = """
Flowgram:	1.01	0.00	0.98	0.03	0.00	1.04	0.02	0.95	0.01	0.00	0.97	0.03	0.00	1.10	0.02	1.02	1.02	1.10	0.02	0.99	1.01	0.00	1.95	0.05	1.02	0.00	0.05	0.96	0.07	0.00	0.95	0.07	1.01	0.00	0.08	0.98	0.09	0.00	1.90	0.09	2.01	0.00	1.94	1.01	1.07	1.04	0.12	1.98	0.13	1.04	0.02	1.05	2.95	0.07	0.04	1.97	0.10	1.01	1.95	0.98	1.01	0.03	0.10	1.00	1.02	0.00	1.00	0.07	1.01	0.00	0.96	0.08	0.11	1.02	0.12	1.02	2.03	0.09	1.96	0.08	0.13	2.06	0.13	0.06	1.03	0.10	0.04	1.03	1.02	0.03	0.07	4.79	0.09	1.02	2.02	0.10	1.98	0.06	1.95	0.09	1.02	0.00	1.00	0.05	1.00	0.02	1.03	0.08	0.08	1.00	0.06	1.02	0.07	2.00	3.88	0.10	0.97	1.00	0.08	0.05	1.00	0.12	1.97	0.07	0.13	1.03	0.08	0.07	1.04	0.10	1.01	1.04	0.12	2.01	0.12	0.99	0.08	0.99	1.06	0.13	1.03	1.02	0.08	2.02	1.08	0.09	0.13	2.93	0.07	0.04	2.03	1.03	2.02	1.07	3.76	1.03	0.08	0.11	1.88	0.08	0.99	1.01	1.04	0.08	0.92	1.01	0.12	0.04	0.92	0.11	1.01	0.07	0.96	2.02	0.08	0.12	0.93	0.11	0.11	2.02	0.07	1.95	1.01	1.02	0.06	0.00	1.01	0.07	0.07	1.06	0.02	0.06	1.07	0.04	4.04	0.12	0.06	1.04	0.08	0.10	0.98	0.02	1.05	1.10	1.00	0.08	0.95	0.03	1.05	1.02	2.08	2.01	0.13	1.95	0.14	0.00	0.99	0.86	2.02	0.09	3.01	2.06	0.08	0.08	0.85	0.06	1.01	0.06	0.09	1.03	0.08	0.09	0.96	0.04	0.07	1.02	1.11	0.00	0.08	0.93	0.07	1.94	1.11	0.05	0.10	0.95	0.05	0.10	1.04	0.02	0.06	0.98	1.03	0.00	0.11	0.99	0.15	1.92	1.10	0.05	0.98	0.08	0.91	0.08	0.10	0.92	0.05	0.10	1.02	0.08	0.07	1.05	0.15	1.02	0.07	0.09	1.00	0.02	0.03	1.02	0.06	0.09	2.03	0.06	0.14	1.07	0.12	0.08	1.07	0.01	1.03	0.13	2.02	0.02	0.06	1.08	1.03	0.99	0.11	0.02	2.01	2.07	0.14	0.08	0.94	0.04	0.95	0.09	1.95	0.13	1.93	0.09	3.06	0.13	1.00	0.11	0.06	0.75	0.13	0.91	0.12	2.05	0.07	2.03	0.10	0.03	1.07	0.17	1.11	0.12	0.04	1.05	1.06	0.07	2.08	0.05	0.09	2.02	0.08	1.08	0.06	0.84	0.16	1.03	1.08	0.92	0.16	0.93	0.08	0.95	0.94	2.07	0.17	0.10	1.03	0.03	0.00	1.04	0.00	2.02	2.17	0.16	0.12	1.97	0.04	0.90	0.15	0.17	1.08	0.98	1.25	1.04	0.88	0.14	0.15	0.99	1.87	1.06	1.09	0.12	1.00	0.11	0.81	0.08	0.11	0.92	3.04	1.12	1.07	0.02	0.11	0.94	0.07	0.06	0.86	0.97	0.19	0.03	2.25	2.06
Flow Indexes:	1	3	6	8	11	14	16	17	18	20	21	23	23	25	28	31	33	36	39	39	41	41	43	43	44	45	46	48	48	50	52	53	53	53	56	56	58	59	59	60	61	64	65	67	69	71	74	76	77	77	79	79	82	82	85	88	89	92	92	92	92	92	94	95	95	97	97	99	99	101	103	105	107	110	112	114	114	115	115	115	115	117	118	121	123	123	126	129	131	132	134	134	136	138	139	141	142	144	144	145	148	148	148	151	151	152	153	153	154	155	155	155	155	156	159	159	161	162	163	165	166	169	171	173	174	174	177	180	180	182	182	183	184	187	190	193	195	195	195	195	198	201	203	204	205	207	209	210	211	211	212	212	214	214	217	218	219	219	221	221	221	222	222	225	227	230	233	236	237	240	242	242	243	246	249	252	253	256	258	258	259	261	263	266	269	272	274	277	280	283	283	286	289	291	293	293	296	297	298	301	301	302	302	305	307	309	309	311	311	313	313	313	315	318	320	322	322	324	324	327	329	332	333	335	335	338	338	340	342	344	345	346	348	350	351	352	352	355	358	360	360	361	361	364	364	366	369	370	371	372	373	376	377	377	378	379	381	383	386	387	387	387	388	389	392	395	396	399	399	400	400
Bases:	tcagCAGTAGTCCTGCTGCCTTCCGTAGGAGTTTGGACCGTGTCTCAGTTCCAATGTGGGGGACCTTCCTCTCAGAACCCCTATCCATCGAAGACTAGGTGGGCCGTTACCCCGCCTACTATCTAATGGAACGCATCCCCATCGTCTACCGGAATACCTTTAATCATGTGAACATGTGAACTCATGATGCCATCTTGTATTAATCTTCCTTTCAGAAGGCTGTCCAAGAGTAGACGGCAGGTTGGATACGTGTTACTCACCCGTGCGCCGG
Quality Scores:	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	40	37	37	37	37	37	37	37	37	34	34	34	34	34	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	38	32	32	32	32	38	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	37	38	38	38	38	40	40	40	38	38	38	38	38	38	38	40	38	38	38	38	38	38	37	38	38	36	37	37	36	33	28	28	31	31	31	31	31	31	31	31	31	31	31	32	32	31	30	30	25	25	25	25
"""
 
if __name__ == '__main__':
    main()