Why Did We Store Two-Dimensional Vectors for Vector Search?
Introduction
Previously, we looked at how to perform natural language search on case law data using vector embeddings. Generally, vector embedding models have limitations on the length of input data. These limitations lead to the problem of not being able to process long sentences, and a commonly used method to overcome this is to split sentences into appropriate lengths. However, splitting sentences into appropriate lengths creates another problem from the perspective of storing data. Here, we explain what problems occur and what features we added to Aeca to improve upon them.
Vector Embeddings
Vector embeddings typically involve inputting pairs of text (sentences, paragraphs, etc.)—Sentence A
and Sentence B
in the figure below. As shown in the figure, a pair of embedding vectors u
and v
are output, and the model is trained so that if the two inputs are similar, their similarity (cosine-sim(u, v)
) is high, and if they are not similar, it is low.
Context Length and Training Data
Like all model training, the training data has a significant impact on the model's performance. The data used for pre-training and the data used to fine-tune embedding performance affect the search quality when used in vector search. Typically, the length of tokens used for embedding is about 512, which corresponds roughly to a paragraph. Inputs exceeding this length are discarded. Furthermore, even if the maximum token length is 512, if the training data mostly consists of data smaller than 512 tokens, we can expect that the model will not produce good results for long inputs.
These limitations apply directly to vector search as well. If you convert a long case law text into a single embedding vector without special processing, significant information loss occurs.
Handling Vector Data
For the reasons above, for vector search, we need to embed text in appropriately sized paragraphs and organize related data according to the split structure.
The following is an example of case law data. A document consists of the case name (name
), court name (court_type
), judgment summary (judgment_summary
), holding statement (holding_statement
), main text (content
), etc. Here, the holding statement seems to slightly exceed the aforementioned 512 tokens, and it's difficult to represent the judgment summary and main text as a single vector.
[ { "content": "【원고, 상고인 겸 피상고인】 주식회사 한올테크놀로지 (소송대리인 법무법인(유한) 율촌 담당변호사 김능환 외 3인)\n【피고, 피상고인 겸 상고인】 다쏘시스템코리아 주식회사 외 1인 (소송대리인 변호사 손지열 외 3인)\n【원심판결】 서울고법 2016. 4. 7. 선고 2014나27205 판결\n【주 문】\n 원고의 피고 다쏘시스템코리아 주식회사에 대한 상고를 각하한다. 원고의 피고 다쏘 시스템 에스에이에 대한 상고와 피고들의 상고를 모두 기각한다. 상고비용은 각자 부담한다. \n\n【이 유】 1. 원고의 상고이유(상고이유서 제출기간이 지난 후에 제출된 상고이유보충서들의 기재는 상고이유를 보충하는 범위 내에서)에 대한 판단\n 가. 피고 다쏘시스템코리아 주식회사(이하 ‘피고 다쏘시스템코리아’라고 한다)에 대한 상고이유에 관하여\n 기록에 의하면, 원고는 피고 다쏘시스템코리아와 체결한 이 사건 계약을 위반하지 않았다고 주장하였는데, 제1심은 원고의 위 주장을 배척하면서도 피고 다쏘시스템코리아에게 손해가 발생하였다고 단정하기 어렵다며 결국 원고의 위 피고에 대한 손해배상채무 부존재확인청구를 받아들였고, 위 피고가 이에 불복하여 항소하였으나 원심은 위 피고의 항소를 기각하였음을 알 수 있다.\n 그렇다면 원고의 위 피고에 대한 상고는 자신이 승소한 부분에 관한 것으로서 상고의 이익이 없어 부적법하다.\n 나. 피고 다쏘 시스템 에스에이에 대한 상고이유에 관하여 \n (1) 사용자가 컴퓨터 하드디스크 드라이브(HDD) 등의 보조기억장치에 설치된 컴퓨터프로그램을 실행하거나 인터넷으로 디지털화된 저작물을 검색, 열람 및 전송하는 등의 과정에서 컴퓨터 중앙처리장치(CPU)는 실행된 컴퓨터프로그램의 처리속도 향상 등을 위하여 컴퓨터프로그램을 주기억장치인 램(RAM)에 적재하여 이용하게 되는데, 이러한 과정에서 일어나는 컴퓨터프로그램의 복제는 전원이 꺼지면 복제된 컴퓨터프로그램의 내용이 모두 지워진다는 점에서 일시적 복제라고 할 수 있다.\n저작권법은 제2조 제22호에서 복제의 개념에 ‘일시적으로 유형물에 고정하거나 다시 제작하는 것’을 포함시키면서도, 제35조의2에서 \"컴퓨터에서 저작물을 이용하는 경우에는 원활하고 효율적인 정보처리를 위하여 필요하다고 인정되는 범위 안에서 그 저작물을 그 컴퓨터에 일시적으로 복제할 수 있다. 다만 그 저작물의 이용이 저작권을 침해하는 경우에는 그러하지 아니하다.\"라고 규정하여 일시적 복제에 관한 면책규정을 두고 있다. 그 취지는 새로운 저작물 이용환경에 맞추어 저작권자의 권리보호를 충실하게 만드는 한편 이로 인하여 컴퓨터에서의 저작물 이용과 유통이 과도하게 제한되는 것을 방지함으로써 저작권의 보호와 저작물의 원활한 이용의 적절한 균형을 도모하는 데 있다. 이와 같은 입법 취지 등에 비추어 볼 때 여기에서 말하는 ‘원활하고 효율적인 정보처리를 위하여 필요하다고 인정되는 범위’에는 일시적 복제가 저작물의 이용 등에 불가피하게 수반되는 경우는 물론 안정성이나 효율성을 높이기 위해 이루어지는 경우도 포함된다고 볼 것이지만, 일시적 복제 자체가 독립한 경제적 가치를 가지는 경우는 제외되어야 할 것이다(대법원 2017. 11. 23. 선고 2015다1017, 1024, 1031, 1048 판결 참조)\n (2) 원심판결의 이유 및 원심이 적법하게 채택하여 조사한 증거 등에 의하면 다음과 같은 사실을 알 수 있다.\n (가) 원고는 피고 다쏘 시스템 에스에이의 자회사인 피고 다쏘시스템코리아와 피고 다쏘 시스템 에스에이가 저작권을 가지고 있는 카티아(CATIA) 소프트웨어(이하 ‘피고 소프트웨어’라 한다)에 관하여 일반 브이에이알(VAR, Value-Added Reseller) 계약이라는 명칭의 판매대리점 계약을 체결하였다.\n (나) 피고 다쏘 시스템 에스에이는 피고 소프트웨어에 대한 이용허락계약(이하 ‘이 사건 라이선스 계약’이라 한다)을 통하여 라이선스받은 최대 동시사용자 수보다 많은 사용자가 피고 소프트웨어를 동시에 사용할 수 없도록 하는 동시사용 방식의 라이선스를 부여하였다. 이는 피고 소프트웨어가 설치되어 있는 사용자 컴퓨터로부터 라이선스 부여 요구를 받은 서버가 선착순으로 라이선스를 할당하고 보유한 라이선스를 모두 소진하면 이미 할당받은 사용자가 라이선스를 반납할 때까지 기다렸다가 이를 회수하여 다시 라이선스를 요구하는 다른 사용자에게 재할당을 하는 방식이다. \n 사용자 컴퓨터는 최초에 서버와 약속한 대로 일정 시간마다 라이선스의 유효성을 확인하는 메시지(heartbeat)를 보내 서버로부터 라이선스의 유효성을 확인받고, 서버는 정해진 시간 내에 사용자 컴퓨터로부터 신호를 받지 못할 경우 해당 사용자 컴퓨터로부터 라이선스를 회수한 후 다른 사용자 컴퓨터가 사용할 수 있는 상태로 전환하게 된다.\n (다) 원고는 피고 소프트웨어의 최종사용자가 라이선스를 추가로 확보할 수 있는 기능을 가진 소프트웨어(이하 ‘원고 소프트웨어’라 한다)를 개발하여 피고 소프트웨어의 최종사용자들에게 판매하였다. 라이선스의 개수와 동일한 수의 피고 소프트웨어가 실행되던 중 피고 소프트웨어의 다른 사용자들이 원고 소프트웨어를 사용하게 되면, 원고 소프트웨어는 사용자 컴퓨터에 실행되어 있으나 실제로 사용되지는 않고 있는 피고 소프트웨어를 비활성화시킴으로써 피고 소프트웨어를 종료시키지 않은 상태로 라이선스를 반환하도록 하고, 이와 같이 반환된 라이선스는 다른 사용자 컴퓨터에서 새롭게 실행된 피고 소프트웨어가 할당받아 사용할 수 있게 된다. 원고 소프트웨어가 위와 같이 피고 소프트웨어를 비활성화시키더라도 종료되지 않은 피고 소프트웨어는 그대로 램(RAM)에 일시적으로 복제된 상태로 남게 된다. 만일 피고 소프트웨어의 사용자들이 모든 라이선스를 실행하고 있던 중 원고 소프트웨어를 사용하여 비활성화시킨 일부 라이선스를 새로운 사용자에게 할당하여 피고 소프트웨어를 실행한 사용자에게 제공하게 되면, 이용허락된 최대 동시사용자 수를 초과하는 피고 소프트웨어가 램(RAM)에 일시적으로 복제되게 된다. \n (3) 위 사실관계를 앞에서 본 법리에 따라 살펴본다.\n (가) 이 사건 라이선스 계약은 이용허락 범위에 프로그램의 ‘사용’뿐만 아니라 ‘액세스’도 포함시키고 있는데, 위 ‘액세스’는 피고 소프트웨어를 실행시킬 때 발생하는 것으로, 그 과정에서 피고 소프트웨어가 램(RAM)에 일시적으로 복제되게 된다. 이 사건 라이선스 계약은 라이선스 계약에 명시된 경우를 제외하고 명시적이거나 묵시적인 어떠한 권리나 라이선스가 최종사용자에게 허용되지 않는다는 내용을 포함하고 있는데, 이용허락 당시 약정한 최대 수를 초과하는 일시적 복제를 허락한다는 취지의 내용은 포함하고 있지 않다. 따라서 이 사건 라이선스 계약을 체결할 당시 저작권자인 피고 다쏘 시스템 에스에이가 약정한 최대 라이선스 수를 넘는 일시적 복제까지 허락하였다고 볼 수 없다.\n (나) 원고 소프트웨어는 위와 같은 피고 소프트웨어의 기본적인 관리 및 작동방식을 바탕으로 하여 라이선스를 할당받은 사용자 중 실제로 피고 소프트웨어를 사용하고 있지 않은 사용자를 가려내어 그 사용자가 실행 중인 피고 소프트웨어를 비활성화시킴으로써 피고 소프트웨어가 사용가능한 라이선스를 추가적으로 확보하는 작업을 하는 것이지, 피고 소프트웨어의 작동과정에서 원활하고 효율적인 정보처리를 위한 작업을 하는 것으로만 볼 수 없다. 또한 원고 소프트웨어로 인해 실행 중이기는 하나 실제로 사용되고 있지는 않은 피고 소프트웨어가 비활성화되는 과정에서 피고 소프트웨어가 종료되지 않은 채 사용자 컴퓨터의 램(RAM)에 복제된 상태로 남아 있게 되는데, 이는 원고 소프트웨어에 의해 추가적으로 발생한 것이지 피고 소프트웨어를 이용하는 과정 중에 불가피하게 수반되는 결과물이라고 볼 수도 없다.\n 이 사건 라이선스 계약과 같은 동시사용 방식에서 유상 거래의 핵심이 되는 것은 ‘최대 라이선스의 수’라고 볼 수 있는데, 원고 소프트웨어로 인해 ‘최대 라이선스의 수’가 증가되는 효과가 발생하게 된다. 원고의 홍보자료에도 원고 소프트웨어를 사용하게 되면 실제 구매한 라이선스 수보다 약 20%의 라이선스를 더 구매한 것과 같은 효과를 가지게 된다고 밝히고 있다. 동시사용 라이선스 계약은 다수의 사용자를 전제로 하는데, 실행 중이지만 실제로 사용되지 않은 소프트웨어로 인해 최대 라이선스의 수만큼 실행되지 않는 경우가 종종 발생한다. 동시사용 방식 라이선스 계약에서 ‘최대 라이선스 수’를 결정할 때에는 이러한 사정을 고려할 수밖에 없는데, 원고 소프트웨어를 사용하면 구매할 라이선스 수를 줄일 수 있으므로, 피고 소프트웨어의 라이선스 판매량이 감소하는 경제적 효과가 발생하게 된다.\n (다) 이러한 사정 등을 종합하면, 원고 소프트웨어에 의해 발생하는 일시적 복제는 피고 소프트웨어의 이용과정에서 불가피하게 수반되거나 안정성이나 효율성을 높이는 것으로만 보기 어렵고, 독립한 경제적 가치를 가지는 것으로 볼 수 있다. \n (4) 따라서 원고 소프트웨어가 피고 다쏘 시스템 에스에이의 일시적 복제권을 침해하였다는 취지로 판단한 원심의 결론은 정당하다. 거기에 일시적 복제권 및 저작권법 제35조의2의 규정에 관한 법리를 오해하거나 논리와 경험의 법칙을 위반하여 자유심증주의의 한계를 벗어나는 등의 사유로 판결에 영향을 미친 잘못이 없다. \n 2. 피고들의 상고이유에 대한 판단\n 가. 피고 다쏘시스템코리아의 상고이유에 관하여\n 원심은 그 판시와 같은 이유로 원고의 채무불이행으로 인해 손해가 발생하였다는 피고 다쏘시스템코리아의 주장을 배척하였다. \n 피고 다쏘시스템코리아의 상고이유 주장은 손해의 발생 여부에 관한 증거의 취사선택 및 사실인정을 다투는 취지로 적법한 상고이유가 되지 못한다. 기록을 살펴보아도 원심판결에 논리와 경험의 법칙을 위반하여 자유심증주의의 한계를 벗어난 잘못이 없다.\n 나. 피고 다쏘 시스템 에스에이의 상고이유에 관하여\n 관련 법리와 기록에 따라 살펴보면, 원심이 그 판시와 같은 이유로 원고 소프트웨어로 인해 피고 소프트웨어에 대한 기술적 보호조치가 무력화되었다고 볼 수 없다고 판단한 것은 정당하다. 거기에 논리와 경험의 법칙을 위반하여 자유심증주의의 한계를 벗어난 잘못이 없다. \n 3. 결론\n 그러므로 원고의 피고 다쏘시스템코리아에 대한 상고를 각하하고, 원고의 피고 다쏘 시스템 에스에이에 대한 상고와 피고들의 상고를 모두 기각하며, 상고비용은 각자 부담하도록 하여, 관여 대법관의 일치된 의견으로 주문과 같이 판결한다.\n\n대법관 민유숙(재판장) 조희대(주심) 김재형 이동원", "court_name": "대법원", "court_type_code": "400201", "doc_id": 204295, "holding_statement": "[1] 사용자가 컴퓨터 하드디스크 드라이브(HDD) 등의 보조기억장치에 설치된 컴퓨터프로그램을 실행하는 등의 과정에서 프로그램을 주기억장치인 램(RAM)에 적재하여 이용하는 것이 저작권법 제2조 제22호에서 말하는 ‘일시적 복제’에 해당하는지 여부(적극) / 저작권법 제2조 제22호에서 복제의 개념에 일시적 복제를 포함시키면서도 같은 법 제35조의2에서 일시적 복제에 관한 면책규정을 둔 취지 및 위 규정에 의하여 면책이 인정되는 일시적 복제의 범위\n[2] 甲 주식회사가 乙 외국회사가 저작권을 가지고 있는 소프트웨어에 관하여 판매대리점 계약을 체결하였고, 乙 회사는 위 소프트웨어에 대한 이용허락계약(라이선스 계약)을 통하여 라이선스받은 최대 동시사용자 수보다 많은 사용자가 소프트웨어를 동시에 사용할 수 없도록 하는 동시사용 방식의 라이선스를 부여하고 있었는데, 甲 회사가 위 소프트웨어의 최종사용자가 라이선스를 추가로 확보할 수 있는 기능을 가진 소프트웨어를 개발하여 乙 회사의 소프트웨어의 최종사용자들에게 판매하였고, 이를 사용하면 최대 동시사용자 수를 초과하는 乙 회사의 소프트웨어가 사용자 컴퓨터의 램(RAM)에 일시적으로 복제된 상태로 남게 되는 사안에서, 甲 회사의 소프트웨어에 의해 발생하는 일시적 복제는 乙 회사의 소프트웨어의 이용과정에서 불가피하게 수반되거나 안정성이나 효율성을 높이는 것으로만 보기 어렵고, 독립한 경제적 가치를 가지는 것으로 볼 수 있으므로, 甲 회사의 소프트웨어는 乙 회사의 일시적 복제권을 침해하였다고 한 사례\n", "judgment": "선고", "judgment_date": "20181115", "judgment_summary": "[1] 사용자가 컴퓨터 하드디스크 드라이브(HDD) 등의 보조기억장치에 설치된 컴퓨터프로그램을 실행하거나 인터넷으로 디지털화된 저작물을 검색, 열람 및 전송하는 등의 과정에서 컴퓨터 중앙처리장치(CPU)는 실행된 컴퓨터프로그램의 처리속도 향상 등을 위하여 컴퓨터프로그램을 주기억장치인 램(RAM)에 적재하여 이용하게 되는데, 이러한 과정에서 일어나는 컴퓨터프로그램의 복제는 전원이 꺼지면 복제된 컴퓨터프로그램의 내용이 모두 지워진다는 점에서 일시적 복제라고 할 수 있다. \n저작권법은 제2조 제22호에서 복제의 개념에 ‘일시적으로 유형물에 고정하거나 다시 제작하는 것’을 포함시키면서도, 제35조의2에서 \"컴퓨터에서 저작물을 이용하는 경우에는 원활하고 효율적인 정보처리를 위하여 필요하다고 인정되는 범위 안에서 그 저작물을 그 컴퓨터에 일시적으로 복제할 수 있다. 다만 그 저작물의 이용이 저작권을 침해하는 경우에는 그러하지 아니하다.\"라고 규정하여 일시적 복제에 관한 면책규정을 두고 있다. 그 취지는 새로운 저작물 이용환경에 맞추어 저작권자의 권리보호를 충실하게 만드는 한편 이로 인하여 컴퓨터에서의 저작물 이용과 유통이 과도하게 제한되는 것을 방지함으로써 저작권의 보호와 저작물의 원활한 이용의 적절한 균형을 도모하는 데 있다. 이와 같은 입법 취지 등에 비추어 볼 때 여기에서 말하는 ‘원활하고 효율적인 정보처리를 위하여 필요하다고 인정되는 범위’에는 일시적 복제가 저작물의 이용 등에 불가피하게 수반되는 경우는 물론 안정성이나 효율성을 높이기 위해 이루어지는 경우도 포함된다고 볼 것이지만, 일시적 복제 자체가 독립한 경제적 가치를 가지는 경우는 제외되어야 한다.\n[2] 甲 주식회사가 乙 외국회사가 저작권을 가지고 있는 소프트웨어에 관하여 판매대리점 계약을 체결하였고, 乙 회사는 위 소프트웨어에 대한 이용허락계약(라이선스 계약)을 통하여 라이선스받은 최대 동시사용자 수보다 많은 사용자가 소프트웨어를 동시에 사용할 수 없도록 하는 동시사용 방식의 라이선스를 부여하고 있었는데, 甲 회사가 위 소프트웨어의 최종사용자가 라이선스를 추가로 확보할 수 있는 기능을 가진 소프트웨어를 개발하여 乙 회사의 소프트웨어의 최종사용자들에게 판매하였고, 이를 사용하면 최대 동시사용자 수를 초과하는 乙 회사의 소프트웨어가 사용자 컴퓨터의 램(RAM)에 일시적으로 복제된 상태로 남게 되는 사안에서, 라이선스 계약을 체결할 당시 저작권자인 乙 회사가 약정한 최대 라이선스 수를 넘는 일시적 복제까지 허락하였다고 볼 수 없는 점, 甲 회사의 소프트웨어는 乙 회사의 소프트웨어의 작동과정에서 원활하고 효율적인 정보처리를 위한 작업을 하는 것으로만 볼 수 없고, 乙 회사의 소프트웨어가 사용자 컴퓨터의 램(RAM)에 복제된 상태로 남게 되는 것은 甲 회사의 소프트웨어에 의해 추가적으로 발생한 것이지 乙 회사의 소프트웨어를 이용하는 과정 중에 불가피하게 수반되는 결과물이라고 볼 수도 없는 점, 라이선스 계약과 같은 동시사용 방식에서 유상 거래의 핵심이 되는 것은 ‘최대 라이선스의 수’라고 볼 수 있는데, 甲 회사의 소프트웨어로 인해 ‘최대 라이선스의 수’가 증가되는 효과가 발생하게 되고 甲 회사의 소프트웨어를 사용하면 구매할 라이선스 수를 줄일 수 있으므로 乙 회사의 소프트웨어의 라이선스 판매량이 감소하는 경제적 효과가 발생하게 되는 점 등을 종합하면, 甲 회사의 소프트웨어에 의해 발생하는 일시적 복제는 乙 회사의 소프트웨어의 이용과정에서 불가피하게 수반되거나 안정성이나 효율성을 높이는 것으로만 보기 어렵고, 독립한 경제적 가치를 가지는 것으로 볼 수 있으므로, 甲 회사의 소프트웨어는 乙 회사의 일시적 복제권을 침해하였다고 한 사례.\n", "judgment_type": "판결", "name": "손해배상등[일시적 복제에 의한 복제권 침해가 쟁점이 된 사건(동시접속 라이선스 사건)]", "number": "2016다20916", "reference_cases": "[1] 대법원 2017. 11. 23. 선고 2015다1017, 1024, 1031, 1048 판결(공2018상, 4)\n", "reference_provisions": "[1] 저작권법 제2조 제22호, 제16조, 제35조의2, 제46조 제2항 / [2] 저작권법 제2조 제22호, 제16조, 제35조의2, 제46조 제2항\n", "total_hits": 364, "type_code": "400101", "type_name": "민사" } ]
To address this, we split long sentences. In the previous work, we split only the main text into paragraphs for convenience. To store such split data, we have two choices. One is to redundantly store the case name, court name, judgment summary, main text, etc., as many times as the number of split paragraphs, or to separate them into two collections. If we choose to store redundantly, the main text will be stored redundantly as many times as the number of split paragraphs, making the size of the collection inefficiently large. Therefore, in the previous work, we separated the collections.
When collections are separated, it looks like the following. One collection (demo.law
) stores the main text and other supplementary information.
And another collection (demo.law.content
) stores the split paragraphs of the main text.
However, although this method is more efficient than redundant storage, it increases complexity because we have to manage separate storage and join two collections during queries. Also, there are more considerations, such as whether to prioritize the score of the retrieved paragraph or other fields, whether to merge the scores of both, and where to set the criterion for the number of documents.
Unfortunately, this method is common when using storage that supports vector search. This problem arises because the storage that indexes/searches cannot fully keep up with the limitations and characteristics of the embedding models.
Here, we think about ways to store vector data in a structured manner, like the nested fields supported by Aeca.
Supporting Two-Dimensional Vectors
To address this, we modified the code that stores, indexes, and searches vector data so that a field in a document can store one or more vector data, that is, store two-dimensional vectors.
We will explain the detailed implementation in the next article.
Now, we no longer need to separate two or more collections to consider the limitations of embedding models. We store a single collection and store the embedding data of the split paragraphs (passage_embed
) as a two-dimensional array.
As a result, the commands to merge the two collections are also removed, and the query has become simpler.
Execution Time and Data Size
Tests were conducted on a MacBook Pro M3 Max with 36GB of RAM, and the execution times are as follows. The execution time was not significantly different from storing in separate collections.
- Data Insertion: 14m 24.3s
- Indexing: 33m 44s
Data storage slightly reduced the size of the Full-Text Search index as the text data of the split paragraphs was excluded.
Existing | Two-Dimensional Vector | |
Original Data | 3.2 GiB (965.2 MiB, Paragraphs: 2.3 GiB) | 3 GiB |
Index | 11.7 GiB (3.7 GiB, Paragraphs: 8 GiB) | 9.8 GiB |
Conclusion
We looked into what constraints vector embedding models have and what problems can occur in the storage and indexing process when splitting and storing long documents considering these constraints. This is something that can be easily encountered in the field, and we can reduce complexity through Aeca.
References
Getting to Know Aeca
If you'd like to explore Aeca further, you can easily install it with Docker and start using it right away. For more detailed explanations about adopting Aeca or to request a product brochure, please contact us via Customer Support.
Read more
Searching Case Law Data with Natural Language
Explains how to build a natural language search service by applying vector search to a case law search demo using FTS.
By Aeca Team|2024-07-04
Making Case Law Data Quickly Searchable
Explains the process of downloading case law data and building a case law search service in just one day using Aeca.
By Aeca Team|2024-06-21