{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":121150,"databundleVersionId":15061024,"sourceType":"competition"}],"dockerImageVersionId":31234,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Import libaries to be uses tensorflow, keras, numpy and polars ","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers,mixed_precision\nimport numpy as np \nimport polars as pl ","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:58:40.678182Z","iopub.execute_input":"2025-12-23T18:58:40.678372Z","iopub.status.idle":"2025-12-23T18:58:55.744557Z","shell.execute_reply.started":"2025-12-23T18:58:40.678330Z","shell.execute_reply":"2025-12-23T18:58:55.743863Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"policy = mixed_precision.Policy('mixed_float16')\nmixed_precision.set_global_policy(policy)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:05.109407Z","iopub.execute_input":"2025-12-23T18:59:05.109993Z","iopub.status.idle":"2025-12-23T18:59:05.113444Z","shell.execute_reply.started":"2025-12-23T18:59:05.109961Z","shell.execute_reply":"2025-12-23T18:59:05.112620Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## fix any encoding issue","metadata":{}},{"cell_type":"code","source":"\ndef fix_encoding(text):\n    if text is None: return \"\"\n    try:\n        return text.encode('latin-1').decode('utf-8')\n    except:\n        return text","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:07.163529Z","iopub.execute_input":"2025-12-23T18:59:07.164241Z","iopub.status.idle":"2025-12-23T18:59:07.168293Z","shell.execute_reply.started":"2025-12-23T18:59:07.164211Z","shell.execute_reply":"2025-12-23T18:59:07.167516Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Load trainig Data set ","metadata":{}},{"cell_type":"code","source":"\ndf = pl.read_csv('/kaggle/input/deep-past-initiative-machine-translation/train.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:09.177760Z","iopub.execute_input":"2025-12-23T18:59:09.178105Z","iopub.status.idle":"2025-12-23T18:59:09.364577Z","shell.execute_reply.started":"2025-12-23T18:59:09.178075Z","shell.execute_reply":"2025-12-23T18:59:09.364045Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## apply the fix_error encoding function to the data Training data set ","metadata":{"execution":{"iopub.status.busy":"2025-12-22T21:09:32.992030Z","iopub.execute_input":"2025-12-22T21:09:32.992369Z","iopub.status.idle":"2025-12-22T21:09:32.998570Z","shell.execute_reply.started":"2025-12-22T21:09:32.992340Z","shell.execute_reply":"2025-12-22T21:09:32.997111Z"}}},{"cell_type":"code","source":"df_clean  = df.with_columns([\n    pl.col(\"transliteration\").map_elements(fix_encoding,return_dtype=pl.String),\n    pl.col(\"translation\").map_elements(fix_encoding,return_dtype=pl.String)\n]).with_columns([(pl.lit(\"starttoken\") + pl.col(\"translation\") + pl.lit(\"endtoken\")).alias(\"translation_target\")])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:10.999132Z","iopub.execute_input":"2025-12-23T18:59:10.999470Z","iopub.status.idle":"2025-12-23T18:59:11.128362Z","shell.execute_reply.started":"2025-12-23T18:59:10.999441Z","shell.execute_reply":"2025-12-23T18:59:11.127506Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"source_len = 350 \ntarget_len = 450\nmax_vocab_target = 12000\nmax_vocab_source = 2000\nembed_dim = 256\nnum_heads = 8 \nff_dim = 512","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:13.103315Z","iopub.execute_input":"2025-12-23T18:59:13.104022Z","iopub.status.idle":"2025-12-23T18:59:13.107298Z","shell.execute_reply.started":"2025-12-23T18:59:13.103997Z","shell.execute_reply":"2025-12-23T18:59:13.106689Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Create the Tokenization ","metadata":{}},{"cell_type":"code","source":"source_vec = layers.TextVectorization(\n    max_tokens = max_vocab_source,\n    output_mode = \"int\",\n    output_sequence_length = source_len\n)\n\ntarget_vec = layers.TextVectorization(\n    max_tokens = max_vocab_target,\n    output_mode = \"int\",\n    output_sequence_length= target_len + 1\n    \n)\n\nsource_vec.adapt(df_clean[\"transliteration\"].to_list())\ntarget_vec.adapt(df_clean[\"translation_target\"].to_list())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:15.050212Z","iopub.execute_input":"2025-12-23T18:59:15.050941Z","iopub.status.idle":"2025-12-23T18:59:15.996666Z","shell.execute_reply.started":"2025-12-23T18:59:15.050909Z","shell.execute_reply":"2025-12-23T18:59:15.996073Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Print(view the tokenization list ","metadata":{}},{"cell_type":"code","source":"vocab = source_vec.get_vocabulary()\n\nfor i, word in enumerate(vocab[:5]):\n        print(f\"ID {i}:{word}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:17.559587Z","iopub.execute_input":"2025-12-23T18:59:17.560083Z","iopub.status.idle":"2025-12-23T18:59:17.570106Z","shell.execute_reply.started":"2025-12-23T18:59:17.560057Z","shell.execute_reply":"2025-12-23T18:59:17.569386Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## building the Transformer Architexture","metadata":{}},{"cell_type":"code","source":"class PositionalEmbedding(layers.Layer):\n    def __init__ (self,sequence_length, vocab_size, embed_dim ,**kwargs):\n        super().__init__(**kwargs)\n        self.sequence_length = sequence_length\n        self.vocab_size = vocab_size\n        self.embed_dim = embed_dim\n        self.token_embeddings = layers.Embedding(vocab_size,embed_dim)\n        self.position_embeddings = layers.Embedding(sequence_length,embed_dim)\n\n    def build(self, input_shape):\n        \"\"\"Build the layer - ensures all sublayers are built\"\"\"\n        self.token_embeddings.build(input_shape)\n        self.position_embeddings.build((input_shape[0], self.sequence_length))\n        super().build(input_shape)\n\n\n    def call(self,inputs):\n        length = tf.shape(inputs)[-1]\n        positions = tf.range(start = 0, limit = length,delta = 1)\n        embedded_tokens = self.token_embeddings(inputs)\n        embedded_positions = self.position_embeddings(positions)\n        return embedded_tokens + embedded_positions\n        \n    def get_config(self):\n        config = super().get_config()\n        config.update({\n            'sequence_length': self.sequence_length,\n            'vocab_size': self.vocab_size,\n            'embed_dim': self.embed_dim,\n        })\n        return config","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:20.306945Z","iopub.execute_input":"2025-12-23T18:59:20.307670Z","iopub.status.idle":"2025-12-23T18:59:20.315211Z","shell.execute_reply.started":"2025-12-23T18:59:20.307641Z","shell.execute_reply":"2025-12-23T18:59:20.314557Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# transformer encoder \n\ndef transformer_encoder(inputs, embed_dim , num_heads , ff_dim):\n    x = layers.MultiHeadAttention(num_heads = num_heads, key_dim = embed_dim)(inputs,inputs,use_causal_mask = True)\n    x = layers.LayerNormalization()(inputs + layers.Dropout(0.1)(x))\n    f = layers.Dense(ff_dim, activation = \"relu\")(x)\n    f = layers.Dense(embed_dim)(f)\n    return layers.LayerNormalization()(x + f)\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:23.687141Z","iopub.execute_input":"2025-12-23T18:59:23.687527Z","iopub.status.idle":"2025-12-23T18:59:23.692236Z","shell.execute_reply.started":"2025-12-23T18:59:23.687501Z","shell.execute_reply":"2025-12-23T18:59:23.691441Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#transformer decoder \n\ndef transformer_decoder (inputs, enc_out, embed_dim, num_heads, ff_dim):\n    x = layers.MultiHeadAttention(num_heads = num_heads, key_dim = embed_dim)(inputs,inputs, use_causal_mask = True)\n    x = layers.LayerNormalization()(inputs + x )\n    x2 = layers.MultiHeadAttention(num_heads = num_heads, key_dim = embed_dim)(x,enc_out)\n    x = layers.LayerNormalization()( x + x2)\n    f = layers.Dense(ff_dim, activation = \"relu\")(x)\n    f = layers.Dense(embed_dim)(f)\n    return layers.LayerNormalization()(x + f)\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:25.327072Z","iopub.execute_input":"2025-12-23T18:59:25.327652Z","iopub.status.idle":"2025-12-23T18:59:25.332539Z","shell.execute_reply.started":"2025-12-23T18:59:25.327621Z","shell.execute_reply":"2025-12-23T18:59:25.331619Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## Asembling the model \n\nenc_inputs = layers.Input(shape = (None,), dtype = \"int64\", name = \"assyrian\")\ndec_inputs = layers.Input(shape = (None,), dtype = \"int64\", name = \"english\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:27.174494Z","iopub.execute_input":"2025-12-23T18:59:27.174784Z","iopub.status.idle":"2025-12-23T18:59:27.180128Z","shell.execute_reply.started":"2025-12-23T18:59:27.174757Z","shell.execute_reply":"2025-12-23T18:59:27.179283Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x = PositionalEmbedding(source_len + 1, max_vocab_source,embed_dim)(enc_inputs)\nenc_out = transformer_encoder(x, embed_dim, num_heads, ff_dim)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:32.638599Z","iopub.execute_input":"2025-12-23T18:59:32.639311Z","iopub.status.idle":"2025-12-23T18:59:32.712697Z","shell.execute_reply.started":"2025-12-23T18:59:32.639263Z","shell.execute_reply":"2025-12-23T18:59:32.711938Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x = PositionalEmbedding (target_len + 1, max_vocab_target, embed_dim)(dec_inputs)\ndec_out = transformer_decoder(x, enc_out,embed_dim, num_heads, ff_dim)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:34.383661Z","iopub.execute_input":"2025-12-23T18:59:34.383967Z","iopub.status.idle":"2025-12-23T18:59:34.483246Z","shell.execute_reply.started":"2025-12-23T18:59:34.383940Z","shell.execute_reply":"2025-12-23T18:59:34.482516Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"outputs = layers.Dense(max_vocab_target, activation = \"softmax\", dtype='float32')(dec_out)\nmodel = tf.keras.Model([enc_inputs,dec_inputs],outputs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:36.463160Z","iopub.execute_input":"2025-12-23T18:59:36.463530Z","iopub.status.idle":"2025-12-23T18:59:36.479669Z","shell.execute_reply.started":"2025-12-23T18:59:36.463502Z","shell.execute_reply":"2025-12-23T18:59:36.479007Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(optimizer = \"adam\" , loss = \"sparse_categorical_crossentropy\", metrics = [\"accuracy\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:38.111693Z","iopub.execute_input":"2025-12-23T18:59:38.111981Z","iopub.status.idle":"2025-12-23T18:59:38.128318Z","shell.execute_reply.started":"2025-12-23T18:59:38.111959Z","shell.execute_reply":"2025-12-23T18:59:38.127794Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"source_data = source_vec(df_clean[\"transliteration\"].to_list())\ntarget_data = target_vec(df_clean[\"translation_target\"].to_list())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:39.767226Z","iopub.execute_input":"2025-12-23T18:59:39.767822Z","iopub.status.idle":"2025-12-23T18:59:40.618988Z","shell.execute_reply.started":"2025-12-23T18:59:39.767789Z","shell.execute_reply":"2025-12-23T18:59:40.618206Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dec_in = target_data[:,:-1]\ndec_out_labels= target_data[:,1:]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:43.846781Z","iopub.execute_input":"2025-12-23T18:59:43.847485Z","iopub.status.idle":"2025-12-23T18:59:43.861788Z","shell.execute_reply.started":"2025-12-23T18:59:43.847456Z","shell.execute_reply":"2025-12-23T18:59:43.861115Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print( \"training model \")\n\nhistory = model.fit(\n    [source_data, dec_in ],\n    dec_out_labels,\n    batch_size = 8,\n    epochs = 30,\n    shuffle = True\n    \n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T18:59:47.623113Z","iopub.execute_input":"2025-12-23T18:59:47.623517Z","iopub.status.idle":"2025-12-23T19:05:51.676264Z","shell.execute_reply.started":"2025-12-23T18:59:47.623491Z","shell.execute_reply":"2025-12-23T19:05:51.675504Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:05:58.268173Z","iopub.execute_input":"2025-12-23T19:05:58.268896Z","iopub.status.idle":"2025-12-23T19:05:58.302723Z","shell.execute_reply.started":"2025-12-23T19:05:58.268868Z","shell.execute_reply":"2025-12-23T19:05:58.302182Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save(\"assyrian_to_english_v1.keras\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:06:06.402561Z","iopub.execute_input":"2025-12-23T19:06:06.403118Z","iopub.status.idle":"2025-12-23T19:06:07.438137Z","shell.execute_reply.started":"2025-12-23T19:06:06.403091Z","shell.execute_reply":"2025-12-23T19:06:07.437307Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## kaggle Submition v1 ","metadata":{}},{"cell_type":"code","source":"## load the test dataset\n\ndf_test = pl.read_csv('/kaggle/input/deep-past-initiative-machine-translation/test.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:06:29.066730Z","iopub.execute_input":"2025-12-23T19:06:29.067035Z","iopub.status.idle":"2025-12-23T19:06:29.078957Z","shell.execute_reply.started":"2025-12-23T19:06:29.067009Z","shell.execute_reply":"2025-12-23T19:06:29.078208Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#load the train model created preiously \nmodel = tf.keras.models.load_model(\"/kaggle/working/assyrian_to_english_v1.keras\",custom_objects={'PositionalEmbedding': PositionalEmbedding})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:08:44.481559Z","iopub.execute_input":"2025-12-23T19:08:44.482139Z","iopub.status.idle":"2025-12-23T19:08:45.566659Z","shell.execute_reply.started":"2025-12-23T19:08:44.482111Z","shell.execute_reply":"2025-12-23T19:08:45.565866Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## REBUILD THE DICTIONARY \ndf_train = pl.read_csv('/kaggle/input/deep-past-initiative-machine-translation/train.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:08:51.898742Z","iopub.execute_input":"2025-12-23T19:08:51.899089Z","iopub.status.idle":"2025-12-23T19:08:51.905999Z","shell.execute_reply.started":"2025-12-23T19:08:51.899059Z","shell.execute_reply":"2025-12-23T19:08:51.905464Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#clean text list \n\ndef clean_text(text):\n    if not isinstance(text, str): return \"\"\n    text = text.replace(\"-\",\" \").replace(\".\", \" \").lower()\n    return text ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:08:55.191143Z","iopub.execute_input":"2025-12-23T19:08:55.191471Z","iopub.status.idle":"2025-12-23T19:08:55.195401Z","shell.execute_reply.started":"2025-12-23T19:08:55.191445Z","shell.execute_reply":"2025-12-23T19:08:55.194639Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"source_vec = tf.keras.layers.TextVectorization(\n    max_tokens = 4000,\n    output_mode = \"int\",\n    output_sequence_length = 350\n)\ntarget_vec = tf.keras.layers.TextVectorization(\n    max_tokens = 12000,\n    output_mode = \"int\",\n    output_sequence_length = 451\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:09:57.257879Z","iopub.execute_input":"2025-12-23T19:09:57.258523Z","iopub.status.idle":"2025-12-23T19:09:57.270834Z","shell.execute_reply.started":"2025-12-23T19:09:57.258493Z","shell.execute_reply":"2025-12-23T19:09:57.270270Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"source_texts = df_train[\"transliteration\"].map_elements(clean_text, return_dtype=str).to_list()\ntarget_texts = (\n    (\"starttoken\" + df_train[\"translation\"] + \"endtoken\")\n    .map_elements(clean_text, return_dtype=str)\n    .to_list()\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:12:58.106557Z","iopub.execute_input":"2025-12-23T19:12:58.106868Z","iopub.status.idle":"2025-12-23T19:12:58.145080Z","shell.execute_reply.started":"2025-12-23T19:12:58.106842Z","shell.execute_reply":"2025-12-23T19:12:58.144304Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"source_vec.adapt(source_texts)\ntarget_vec.adapt(target_texts)\n\n# Get vocabulary\nvocab = target_vec.get_vocabulary()\nprint(f\"Source vocabulary size: {len(source_vec.get_vocabulary())}\")\nprint(f\"Target vocabulary size: {len(vocab)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:13:00.816912Z","iopub.execute_input":"2025-12-23T19:13:00.817214Z","iopub.status.idle":"2025-12-23T19:13:00.920304Z","shell.execute_reply.started":"2025-12-23T19:13:00.817188Z","shell.execute_reply":"2025-12-23T19:13:00.919565Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# inference function \ndef translation_predict(assyrian_text):\n    assyrian_text = clean_text(assyrian_text)\n    source = source_vec([assyrian_text])\n\n    decode_words = \"starttoken\"\n\n    for i in range(450):\n        tokenized_target = target_vec([decode_words])[:,:-1]\n        prediction = model.predict([source,tokenized_target],verbose = 0 )\n\n        sample_token_index = np.argmax(prediction[0, i, :])\n        sample_word = vocab[sample_token_index]\n\n        if sample_word == \"endtoken\":\n            break\n        decode_words += \" \" + sample_word\n\n    final_translation = decode_words.replace(\"starttoken\", \"\").strip()\n    return final_translation\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:17:04.362272Z","iopub.execute_input":"2025-12-23T19:17:04.362884Z","iopub.status.idle":"2025-12-23T19:17:04.367904Z","shell.execute_reply.started":"2025-12-23T19:17:04.362855Z","shell.execute_reply":"2025-12-23T19:17:04.367098Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## generation prediction \npredictions = []\nfor index, row in enumerate(df_test.iter_rows(named=True)):\n    result =  translation_predict(row['transliteration'])\n    predictions.append(result)\n    if index % 10 == 0:\n        print(f\"Processed {index} rows.....\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:17:08.867675Z","iopub.execute_input":"2025-12-23T19:17:08.868402Z","iopub.status.idle":"2025-12-23T19:19:05.644381Z","shell.execute_reply.started":"2025-12-23T19:17:08.868361Z","shell.execute_reply":"2025-12-23T19:19:05.643735Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## submition files \n\nsubmission = pl.DataFrame({ \"id\": df_test[\"id\"],\n                          \"translation\": predictions}\n                         )\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:23:20.376849Z","iopub.execute_input":"2025-12-23T19:23:20.377580Z","iopub.status.idle":"2025-12-23T19:23:20.381432Z","shell.execute_reply.started":"2025-12-23T19:23:20.377551Z","shell.execute_reply":"2025-12-23T19:23:20.380822Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission.write_csv(\"submission.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-23T19:23:36.218021Z","iopub.execute_input":"2025-12-23T19:23:36.218635Z","iopub.status.idle":"2025-12-23T19:23:36.222302Z","shell.execute_reply.started":"2025-12-23T19:23:36.218608Z","shell.execute_reply":"2025-12-23T19:23:36.221661Z"}},"outputs":[],"execution_count":null}]}