def test_at_line_surface_no_status() -> None: at_line = SurfaceAtLine(SurfaceLabel([], atf.Surface.SURFACE, "Stone wig")) assert at_line.lemmatization == (LemmatizationToken("surface Stone wig"), ) assert at_line.surface_label == SurfaceLabel([], atf.Surface.SURFACE, "Stone wig") assert at_line.display_value == "surface Stone wig"
def test_at_line_surface() -> None: at_line = SurfaceAtLine( SurfaceLabel((atf.Status.CORRECTION, ), atf.Surface.SURFACE, "Stone wig")) assert at_line.lemmatization == ( LemmatizationToken("surface Stone wig!"), ) assert at_line.surface_label == SurfaceLabel( (atf.Status.CORRECTION, ), atf.Surface.SURFACE, "Stone wig") assert at_line.display_value == "surface Stone wig!"
def test_at_line_surface_instantiate_text_with_wrong_surface() -> None: with pytest.raises(ValueError): at_line = SurfaceAtLine( SurfaceLabel((atf.Status.CORRECTION, ), atf.Surface.OBVERSE, "Stone wig")) assert at_line.lemmatization == ( LemmatizationToken("obverse Stone wig!"), ) assert at_line.surface_label == SurfaceLabel( (atf.Status.CORRECTION, ), atf.Surface.OBVERSE, "Stone wig") assert at_line.display_value == "obverse Stone wig!"
class ManuscriptLineFactory(factory.Factory): class Meta: model = ManuscriptLine manuscript_id = factory.Sequence(lambda n: n) labels = ( SurfaceLabel.from_label(Surface.OBVERSE), ColumnLabel.from_label("iii", [Status.COLLATION, Status.CORRECTION]), ) line = factory.Sequence( lambda n: TextLine.of_iterable( LineNumber(n), ( Word.of( [ Reading.of_name("ku"), Joiner.hyphen(), BrokenAway.open(), Reading.of_name("nu"), Joiner.hyphen(), Reading.of_name("ši"), BrokenAway.close(), ] ), ), ) ) paratext = (NoteLine((StringPart("note"),)), RulingDollarLine(Ruling.SINGLE)) omitted_words = (1,)
class LabelsFactory(factory.Factory): class Meta: model = Labels object = None surface = factory.fuzzy.FuzzyChoice( [None, SurfaceLabel.from_label(Surface.OBVERSE)] ) column = None
def test_labels(text_with_labels) -> None: assert text_with_labels.labels == [ LineLabel(None, None, None, LineNumber(1)), LineLabel( ColumnLabel.from_int(1), SurfaceLabel([], atf.Surface.SURFACE, "Stone wig"), ObjectLabel([], atf.Object.OBJECT, "Stone wig"), LineNumber(2), ), ]
def text_with_labels(): return Text.of_iterable([ TextLine.of_iterable(LineNumber(1), [Word.of([Reading.of_name("bu")])]), ColumnAtLine(ColumnLabel.from_int(1)), SurfaceAtLine(SurfaceLabel([], atf.Surface.SURFACE, "Stone wig")), ObjectAtLine(ObjectLabel([], atf.Object.OBJECT, "Stone wig")), TextLine.of_iterable(LineNumber(2), [Word.of([Reading.of_name("bu")])]), ])
def test_load_and_dump_surface_label_schema(): surface_label = SurfaceLabel([atf.Status.CORRECTION], atf.Surface.SURFACE, "stone wig") dump = SurfaceLabelSchema().dump(surface_label) assert dump == { "status": ["CORRECTION"], "surface": "SURFACE", "text": "stone wig", "abbreviation": "stone wig", } assert SurfaceLabelSchema().load(dump) == surface_label
import pytest from ebl.transliteration.domain.atf import Status, Surface, Object from ebl.transliteration.domain.labels import ( parse_labels, ColumnLabel, Label, LabelVisitor, SurfaceLabel, ObjectLabel, ) from ebl.transliteration.domain.lark_parser import PARSE_ERRORS LABELS: List[Tuple[str, str, str, Label]] = [ ("o", "", "@obverse", SurfaceLabel(tuple(), Surface.OBVERSE)), ("r", "", "@reverse", SurfaceLabel(tuple(), Surface.REVERSE)), ("b.e.", "", "@bottom", SurfaceLabel(tuple(), Surface.BOTTOM)), ("e.", "", "@edge", SurfaceLabel(tuple(), Surface.EDGE)), ("l.e.", "", "@left", SurfaceLabel(tuple(), Surface.LEFT)), ("r.e.", "", "@right", SurfaceLabel(tuple(), Surface.RIGHT)), ("t.e.", "", "@top", SurfaceLabel(tuple(), Surface.TOP)), ("o", "'", "@obverse", SurfaceLabel((Status.PRIME, ), Surface.OBVERSE)), ("r", "?", "@reverse", SurfaceLabel((Status.UNCERTAIN, ), Surface.REVERSE)), ("b.e.", "!", "@bottom", SurfaceLabel((Status.CORRECTION, ), Surface.BOTTOM)), ("e.", "*", "@edge", SurfaceLabel((Status.COLLATION, ), Surface.EDGE)), ( "l.e.", "*!",
def test_parse_labels_multiple() -> None: labels = (SurfaceLabel.from_label(Surface.OBVERSE), ColumnLabel.from_int(3)) assert parse_labels(" ".join(label.to_value() for label in labels)) == labels
"#tr.en: translation", TranslationLine((StringPart("translation"),), "en", None), ), ( "#tr.ar.(2): translation", TranslationLine( (StringPart("translation"),), "ar", Extent(LineNumber(2), tuple()) ), ), ( "#tr.(2): translation", TranslationLine( (StringPart("translation"),), "en", Extent(LineNumber(2), tuple()) ), ), ( "#tr.de.(o iii 1): translation", TranslationLine( (StringPart("translation"),), "de", Extent( LineNumber(1), (SurfaceLabel(tuple(), Surface.OBVERSE), ColumnLabel(tuple(), 3)), ), ), ), ], ) def test_parse_translation_line(atf, expected_line) -> None: assert parse_translation_line(atf) == expected_line
MANUSCRIPT_ID = 1 LABELS = (ColumnLabel.from_int(1), ) TEXT_LINE = TextLine( LineNumber(1), ( Word.of([Reading.of_name("kur")], unique_lemma=(WordId("word1"), ), alignment=0), Word.of([Reading.of_name("ra")], unique_lemma=(WordId("word2"), ), alignment=None), ), ) NEW_MANUSCRIPT_ID = 2 NEW_LABELS = (SurfaceLabel.from_label(Surface.REVERSE), ) NEW_TEXT_LINE = TextLine( LineNumber(1), (Word.of([Reading.of_name("kur")]), Word.of([Reading.of_name("pa")]))) MANUSCRIPT_LINE = ManuscriptLine(MANUSCRIPT_ID, LABELS, TEXT_LINE) @pytest.mark.parametrize( "old,new,expected", [ (MANUSCRIPT_LINE, MANUSCRIPT_LINE, MANUSCRIPT_LINE), ( MANUSCRIPT_LINE, ManuscriptLine(NEW_MANUSCRIPT_ID, NEW_LABELS, NEW_TEXT_LINE), ManuscriptLine(NEW_MANUSCRIPT_ID, NEW_LABELS, TEXT_LINE.merge(NEW_TEXT_LINE)),
def make_label(self, data, **kwargs) -> SurfaceLabel: return SurfaceLabel(data["status"], data["surface"], data["text"])
AnnotationDataFactory, ) from ebl.tests.factories.fragment import TransliteratedFragmentFactory from ebl.transliteration.domain import atf from ebl.transliteration.domain.labels import ColumnLabel, SurfaceLabel, ObjectLabel from ebl.transliteration.domain.line_label import LineLabel from ebl.transliteration.domain.line_number import LineNumber, LineNumberRange @pytest.mark.parametrize( "line_label, expected", [ ( LineLabel( ColumnLabel.from_int(1), SurfaceLabel([], atf.Surface.SURFACE, "Stone wig"), ObjectLabel([], atf.Object.OBJECT, "Stone wig"), LineNumber(2), ), "i Stone wig Stone wig 2", ), ( LineLabel(None, None, None, LineNumberRange(LineNumber(1, True), LineNumber(3))), "1'-3", ), ], ) def test_format_line_label(line_label, expected, annotations_repository, photo_repository, fragment_repository): image_extractor = AnnotationImageExtractor(fragment_repository,
[ ControlLine("#", "first"), EmptyLine(), ControlLine("#", "second") ], ), ( "#first\n \n#second", [ ControlLine("#", "first"), EmptyLine(), ControlLine("#", "second") ], ), ("&K11111", [ControlLine("&", "K11111")]), ("@reverse", [SurfaceAtLine(SurfaceLabel([], atf.Surface.REVERSE))]), ( "$ (end of side)", [ StateDollarLine( None, atf.Extent.END_OF, ScopeContainer(atf.Scope.SIDE, ""), None, None, ) ], ), ("#some notes", [ControlLine("#", "some notes")]), ("=: continuation", [ControlLine("=:", " continuation")]), ],
ChapterName, Labels, ParallelComposition, ParallelFragment, ParallelText, ) @pytest.mark.parametrize( "cf,duplicates,labels,display_value", [ ( True, True, Labels( surface=SurfaceLabel((Status.CORRECTION, ), Surface.OBVERSE)), "cf. F K.1 &d o! 1", ), (False, False, Labels(), "F K.1 1"), ], ) def test_parallel_fragment(cf, duplicates, labels, display_value) -> None: museum_number = MuseumNumber.of("K.1") line_number = LineNumber(1) line = ParallelFragment(cf, museum_number, duplicates, labels, line_number) assert line.has_cf is cf assert line.museum_number == museum_number assert line.has_duplicates is duplicates assert line.labels == labels assert line.line_number == line_number
def ebl_atf_text_line__edge(self, text: str = ""): return SurfaceLabel.from_label(atf.Surface.EDGE, text=text)
def ebl_atf_text_line__generic_surface(self, text: str): return SurfaceLabel.from_label(atf.Surface.SURFACE, text=text)
"line,expected_tokens", [ ("@composite", [CompositeAtLine(atf.Composite.COMPOSITE, "")]), ("@m=locator o 1", [CompositeAtLine(atf.Composite.MILESTONE, "o", 1)]), ("@m=locator o", [CompositeAtLine(atf.Composite.MILESTONE, "o")]), ("@div part 1", [CompositeAtLine(atf.Composite.DIV, "part", 1)]), ("@end part", [CompositeAtLine(atf.Composite.END, "part")]), ("@m=division paragraph ", [DivisionAtLine("paragraph")]), ("@m=division paragraph 1", [DivisionAtLine("paragraph", 1)]), ("@date", [DiscourseAtLine(atf.Discourse.DATE)]), ( "@reverse!*", [ SurfaceAtLine( SurfaceLabel( [atf.Status.CORRECTION, atf.Status.COLLATION], atf.Surface.REVERSE, )) ], ), ( "@reverse!", [ SurfaceAtLine( SurfaceLabel([atf.Status.CORRECTION], atf.Surface.REVERSE)) ], ), ("@reverse", [SurfaceAtLine(SurfaceLabel([], atf.Surface.REVERSE))]), ("@edge", [SurfaceAtLine(SurfaceLabel([], atf.Surface.EDGE, ""))]), ("@edge a", [SurfaceAtLine(SurfaceLabel([], atf.Surface.EDGE, "a"))]), ( "@surface stone",
) @pytest.mark.parametrize( "line,expected_line", [ ( "// cf. F K.1 &d tablet* o! iii? 1", ParallelFragment( True, MuseumNumber.of("K.1"), True, Labels( ObjectLabel.from_object(atf.Object.TABLET, [atf.Status.COLLATION]), SurfaceLabel.from_label(atf.Surface.OBVERSE, [atf.Status.CORRECTION]), ColumnLabel.from_int(3, [atf.Status.UNCERTAIN]), ), LineNumber(1), ), ), ( "// F K.1 1", ParallelFragment(False, MuseumNumber.of("K.1"), False, Labels(), LineNumber(1)), ), ( '// cf. L I.1 OB "my name" 1', ParallelText( True, TextId(Genre.LITERATURE, 1, 1),
"content": [OneOfTokenSchema().dump(ValueToken.of("object stone wig!*"))], "type": "ObjectAtLine", "label": { "status": ["CORRECTION", "COLLATION"], "object": "OBJECT", "text": "stone wig", "abbreviation": "stone wig", }, "displayValue": "object stone wig!*", }, ), ( SurfaceAtLine( SurfaceLabel( [atf.Status.CORRECTION, atf.Status.COLLATION], atf.Surface.SURFACE, "stone wig", ) ), { "prefix": "@", "content": [OneOfTokenSchema().dump(ValueToken.of("surface stone wig!*"))], "type": "SurfaceAtLine", "surface_label": { "status": ["CORRECTION", "COLLATION"], "surface": "SURFACE", "text": "stone wig", "abbreviation": "stone wig", }, "displayValue": "surface stone wig!*", },
def ebl_atf_text_line__SURFACE(self, surface: Token): return SurfaceLabel.from_label( atf.Surface.from_atf(surface)) # pyre-ignore[6]
from ebl.corpus.domain.chapter import Chapter from ebl.corpus.domain.line import Line, LineVariant, ManuscriptLine from ebl.corpus.domain.manuscript import Manuscript from ebl.transliteration.domain.text_id import TextId from ebl.transliteration.domain.line_number import LineNumber from ebl.transliteration.domain.sign_tokens import Reading from ebl.transliteration.domain.text_line import TextLine from ebl.transliteration.domain.tokens import ValueToken from ebl.transliteration.domain.word_tokens import Word from ebl.transliteration.domain.genre import Genre from ebl.transliteration.domain.labels import SurfaceLabel from ebl.transliteration.domain.atf import Surface from ebl.corpus.web.extant_lines import ExtantLinesSchema from ebl.transliteration.application.line_number_schemas import OneOfLineNumberSchema LABELS = (SurfaceLabel.from_label(Surface.OBVERSE), ) MANUSCRIPT_TEXT_1 = TextLine(LineNumber(2), (Word.of([Reading.of([ValueToken.of("ku")])]), )) def test_extant_lines_schema() -> None: manuscript = Manuscript(1) manuscript_line = ManuscriptLine(1, LABELS, MANUSCRIPT_TEXT_1) variant = LineVariant(tuple(), manuscripts=(manuscript_line, )) text_line = Line(LineNumber(1), (variant, )) chapter = Chapter(TextId(Genre.LITERATURE, 0, 0), manuscripts=(manuscript, ), lines=(text_line, )) assert ExtantLinesSchema().dump(chapter) == { "extantLines": { str(manuscript.siglum): {
def ebl_atf_text_line__face(self, text: Token): return SurfaceLabel.from_label(atf.Surface.FACE, text=str(text))
class TransliteratedFragmentFactory(FragmentFactory): text = Text(( TextLine.of_iterable( LineNumber(1, True), ( Word.of([UnidentifiedSign.of()]), Word.of([ Logogram.of_name( "BA", surrogate=[ Reading.of_name("ku"), Joiner.hyphen(), Reading.of_name("u", 4), ], ) ]), Column.of(), Tabulation.of(), Word.of([ BrokenAway.open(), UnknownNumberOfSigns.of(), Joiner.hyphen(), Reading.of_name("ku"), BrokenAway.close(), Joiner.hyphen(), Reading.of_name("nu"), Joiner.hyphen(), Reading.of_name("ši"), ]), Variant.of(Divider.of(":"), Reading.of_name("ku")), Word.of([ BrokenAway.open(), UnknownNumberOfSigns.of(), BrokenAway.close(), ]), Column.of(2), Divider.of(":", ("@v", ), (Flag.DAMAGE, )), CommentaryProtocol.of("!qt"), Word.of([Number.of_name("10", flags=[Flag.DAMAGE])]), ), ), TextLine.of_iterable( LineNumber(2, True), ( Word.of([ BrokenAway.open(), UnknownNumberOfSigns.of(), BrokenAway.close(), ]), Word.of([Logogram.of_name("GI", 6)]), Word.of([Reading.of_name("ana")]), Word.of([ Reading.of_name("u", 4), Joiner.hyphen(), Reading.of(( ValueToken.of("š"), BrokenAway.open(), ValueToken.of("u"), )), ]), Word.of([UnknownNumberOfSigns.of(), BrokenAway.close()]), ), ), TextLine.of_iterable( LineNumber(3, True), ( Word.of([BrokenAway.open(), UnknownNumberOfSigns.of()]), Word.of([ Reading.of(( ValueToken.of("k"), BrokenAway.close(), ValueToken.of("i"), )), Joiner.hyphen(), Reading.of_name("du"), ]), Word.of([Reading.of_name("u")]), Word.of([ Reading.of_name("ba"), Joiner.hyphen(), Reading.of_name("ma"), Joiner.hyphen(), Reading.of(( ValueToken.of("t"), BrokenAway.open(), ValueToken.of("i"), )), ]), Word.of([UnknownNumberOfSigns.of(), BrokenAway.close()]), ), ), TextLine.of_iterable( LineNumber(6, True), ( Word.of([ BrokenAway.open(), UnknownNumberOfSigns.of(), BrokenAway.close(), ]), Word.of([UnclearSign.of([Flag.DAMAGE])]), Word.of([Reading.of_name("mu")]), Word.of([ Reading.of_name("ta"), Joiner.hyphen(), Reading.of_name("ma"), InWordNewline.of(), Joiner.hyphen(), Reading.of_name("tu", 2), ]), ), ), TextLine.of_iterable( LineNumber(7, True), ( Word.of([ Variant.of(Reading.of_name("šu"), CompoundGrapheme.of(["BI×IS"])) ]), LanguageShift.normalized_akkadian(), AkkadianWord.of([ValueToken.of("kur")]), ), ), StateDollarLine( atf.Qualification.AT_LEAST, 1, ScopeContainer(atf.Surface.OBVERSE, ""), atf.State.MISSING, None, ), ImageDollarLine("1", None, "numbered diagram of triangle"), RulingDollarLine(atf.Ruling.SINGLE), LooseDollarLine("this is a loose line"), SealDollarLine(1), SealAtLine(1), HeadingAtLine(1), ColumnAtLine(ColumnLabel([atf.Status.COLLATION], 1)), SurfaceAtLine( SurfaceLabel([atf.Status.COLLATION], atf.Surface.SURFACE, "stone wig")), ObjectAtLine( ObjectLabel([atf.Status.COLLATION], atf.Object.OBJECT, "stone wig")), DiscourseAtLine(atf.Discourse.DATE), DivisionAtLine("paragraph", 5), CompositeAtLine(atf.Composite.DIV, "part", 1), NoteLine(( StringPart("a note "), EmphasisPart("italic"), LanguagePart.of_transliteration( Language.AKKADIAN, (Word.of([Reading.of_name("bu")]), )), )), ParallelComposition(False, "my name", LineNumber(1)), ParallelText( True, TextId(CorpusGenre.LITERATURE, 1, 1), ChapterName(Stage.OLD_BABYLONIAN, "", "my name"), LineNumber(1), False, ), ParallelFragment(False, MuseumNumber.of("K.1"), True, Labels(), LineNumber(1), False), )) signs = ( "X BA KU ABZ075 ABZ207a\\u002F207b\\u0020X ABZ377n1/KU ABZ377n1 ABZ411\n" "MI DIŠ UD ŠU\n" "KI DU ABZ411 BA MA TI\n" "X MU TA MA UD\n" "ŠU/|BI×IS|") folios = Folios((Folio("WGL", "3"), Folio("XXX", "3"))) record = Record((RecordEntry("test", RecordType.TRANSLITERATION), )) line_to_vec = (( LineToVecEncoding.TEXT_LINE, LineToVecEncoding.TEXT_LINE, LineToVecEncoding.TEXT_LINE, LineToVecEncoding.TEXT_LINE, LineToVecEncoding.TEXT_LINE, LineToVecEncoding.SINGLE_RULING, ), )
def ebl_atf_text_line__surface_with_status(self, surface: SurfaceLabel, statuses): return SurfaceAtLine( SurfaceLabel(statuses, surface.surface, surface.text))
class LemmatizedFragmentFactory(TransliteratedFragmentFactory): text = Text(( TextLine.of_iterable( LineNumber(1, True), ( Word.of([UnidentifiedSign.of()]), Word.of([ Logogram.of_name( "BA", surrogate=[ Reading.of_name("ku"), Joiner.hyphen(), Reading.of_name("u", 4), ], ) ]), Column.of(), Tabulation.of(), Word.of([ BrokenAway.open(), UnknownNumberOfSigns.of(), Joiner.hyphen(), Reading.of_name("ku"), BrokenAway.close(), Joiner.hyphen(), Reading.of_name("nu"), Joiner.hyphen(), Reading.of_name("ši"), ]), Variant.of(Divider.of(":"), Reading.of_name("ku")), Word.of([ BrokenAway.open(), UnknownNumberOfSigns.of(), BrokenAway.close(), ]), Column.of(2), Divider.of(":", ("@v", ), (Flag.DAMAGE, )), CommentaryProtocol.of("!qt"), Word.of([Number.of_name("10", flags=[Flag.DAMAGE])]), ), ), TextLine.of_iterable( LineNumber(2, True), ( Word.of([BrokenAway.open(), UnknownNumberOfSigns.of()]), Word.of([Logogram.of_name("GI", 6)], unique_lemma=(WordId("ginâ I"), )), Word.of([Reading.of_name("ana")], unique_lemma=(WordId("ana I"), )), Word.of( [ Reading.of_name("u₄"), Joiner.hyphen(), Reading.of_name("š[u"), ], unique_lemma=(WordId("ūsu I"), ), ), Word.of([UnknownNumberOfSigns.of(), BrokenAway.close()]), ), ), TextLine.of_iterable( LineNumber(3, True), ( Word.of([BrokenAway.open(), UnknownNumberOfSigns.of()]), Word.of( unique_lemma=(WordId("kīdu I"), ), parts=[ Reading.of(( ValueToken.of("k"), BrokenAway.close(), ValueToken.of("i"), )), Joiner.hyphen(), Reading.of_name("du"), ], ), Word.of(unique_lemma=(WordId("u I"), ), parts=[Reading.of_name("u")]), Word.of( unique_lemma=(WordId("bamātu I"), ), parts=[ Reading.of_name("ba"), Joiner.hyphen(), Reading.of_name("ma"), Joiner.hyphen(), Reading.of(( ValueToken.of("t"), BrokenAway.open(), ValueToken.of("i"), )), ], ), Word.of([UnknownNumberOfSigns.of(), BrokenAway.close()]), ), ), TextLine.of_iterable( LineNumber(6, True), ( Word.of([ BrokenAway.open(), UnknownNumberOfSigns.of(), BrokenAway.close(), ]), Word.of([UnclearSign.of([Flag.DAMAGE])]), Word.of(unique_lemma=(WordId("mu I"), ), parts=[Reading.of_name("mu")]), Word.of( unique_lemma=(WordId("tamalāku I"), ), parts=[ Reading.of_name("ta"), Joiner.hyphen(), Reading.of_name("ma"), InWordNewline.of(), Joiner.hyphen(), Reading.of_name("tu", 2), ], ), ), ), TextLine.of_iterable( LineNumber(7, True), ( Word.of([ Variant.of(Reading.of_name("šu"), CompoundGrapheme.of(["BI×IS"])) ]), LanguageShift.normalized_akkadian(), AkkadianWord.of([ValueToken.of("kur")], unique_lemma=(WordId("normalized I"), )), ), ), StateDollarLine( atf.Qualification.AT_LEAST, 1, ScopeContainer(atf.Surface.OBVERSE, ""), atf.State.MISSING, None, ), ImageDollarLine("1", None, "numbered diagram of triangle"), RulingDollarLine(atf.Ruling.SINGLE), LooseDollarLine("this is a loose line"), SealDollarLine(1), SealAtLine(1), HeadingAtLine(1), ColumnAtLine(ColumnLabel([atf.Status.COLLATION], 1)), SurfaceAtLine( SurfaceLabel([atf.Status.COLLATION], atf.Surface.SURFACE, "stone wig")), ObjectAtLine( ObjectLabel([atf.Status.COLLATION], atf.Object.OBJECT, "stone wig")), DiscourseAtLine(atf.Discourse.DATE), DivisionAtLine("paragraph", 5), CompositeAtLine(atf.Composite.DIV, "part", 1), NoteLine(( StringPart("a note "), EmphasisPart("italic"), LanguagePart.of_transliteration( Language.AKKADIAN, (Word.of([Reading.of_name("bu")]), )), )), ParallelComposition(False, "my name", LineNumber(1)), ParallelText( True, TextId(CorpusGenre.LITERATURE, 1, 1), ChapterName(Stage.OLD_BABYLONIAN, "", "my name"), LineNumber(1), False, ), ParallelFragment(False, MuseumNumber.of("K.1"), True, Labels(), LineNumber(1), False), ))