diff --git a/bombsquad_server b/bombsquad_server index 91d2901..1f72e7f 100644 --- a/bombsquad_server +++ b/bombsquad_server @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.9 +#!/usr/bin/env -S python3.10 -O # Released under the MIT License. See LICENSE for details. # diff --git a/dist/ba_data/data/langdata.json b/dist/ba_data/data/langdata.json index 119e80a..bf5e68c 100644 --- a/dist/ba_data/data/langdata.json +++ b/dist/ba_data/data/langdata.json @@ -9,6 +9,7 @@ "Danish": "Dansk", "Dutch": "Nederlands", "Esperanto": "Esperanto", + "Filipino": "Tagalog ", "French": "Français", "German": "Deutsch", "Gibberish": "Gibberish", @@ -19,7 +20,7 @@ "Italian": "Italiano", "Japanese": "日本語", "Korean": "한국어", - "Persian": " فارسی", + "Persian": "فارسی‎", "Polish": "Polski", "Portuguese": "Português", "Romanian": "Română", @@ -28,6 +29,7 @@ "Slovak": "Slovenčina ", "Spanish": "Español", "Swedish": "Svenska", + "Tamil": "தமிழ்", "Thai": "ภาษาไทย", "Turkish": "Türkçe", "Ukrainian": "Українська", @@ -60,6 +62,7 @@ "Abdul", "Abdulloh", "Abe", + "Ahmed abed", "abhi", "AbhinaY", "Gifasa abidjahsi", @@ -100,9 +103,10 @@ "Abdullah Akkan", "Berk Akkaya", "AKYG", - "Mohammed al-abri", + "mohammed al-abri", "Ali Al-Gattan", "alaa", + "Ahmad Alahmad", "Anna Alanis", "Manuel Alanis", "alanjijuoo7fudu@gmail.com", @@ -138,16 +142,19 @@ "Amar", "alfredo jasper a ambel", "Amedeo", + "ameen", "Kidane Amen-Allah", "amin.ir", "Amir", "amir22games", "amir234", + "amir80sas", "AmirMahdi.D :P", "Amirul", "Ange Kevin Amlaman", "amr", "Anandchaursiya", + "Anas", "AnatoliyanChubukov", "AnatoliyanChybycov", "Bryan Enrique Perez de Anda", @@ -184,11 +191,14 @@ "Hellmann Arias", "Muhammad Arief", "Arin", + "Arroz", "ARSHAD", "Artem", "Valentino Artizzu", + "Arxyma", "Ashik", "Ashish", + "AskarBink", "Asraf", "Asshold", "Eliane Santos de assis", @@ -198,7 +208,9 @@ "Audacious7214", "Aufaghifari", "Ausiàs", + "autismo", "Autoskip", + "Ryan Auxil", "Avamander", "awase2020@gmail.com", "sev alaslam Awd", @@ -211,9 +223,11 @@ "Burak Karadeniz (Myth B)", "Myth B.", "B4likeBefore", + "Praveen Babu", "Balage8", "BalaguerM", "Peter Balind", + "Levalia Ball", "Balqis", "Balraj", "Smutny Bambol", @@ -237,6 +251,7 @@ "David BAUMANN", "bayanus", "Wojtek Bałut", + "Hi bbbbbbbbb", "Eduardo Beascochea", "Eduan Bekker", "бравлер Андрей Belarus", @@ -250,7 +265,9 @@ "Benjamín", "benjapol", "Ori bennov", + "BenVectorgames", "benybrot96", + "berkay", "Bernardiny", "Anton Bang Berner", "Felix Bernhard", @@ -261,6 +278,7 @@ "BlackShadowQ", "Daniel Block", "BlueBlur", + "bob bobber", "The Bomboler 💣", "bombsquad", "Bomby", @@ -280,6 +298,7 @@ "Bořivoj", "Paul braga", "Sammy Braun", + "Brayk", "Brendan", "Federico Brigante", "Anderson Brito", @@ -297,7 +316,10 @@ "ByAdrianYT", "Mohamad Hossein BZ", "Christoffer Bünner", + "mvp aka cactus", + "mvp aka legend (aka cactus) 🌵", "Cadødø", + "Chris Laurence Cagoco", "Calet", "Kenneth Callaghan", "Federico Campagnolo", @@ -333,6 +355,7 @@ "Nick Clime", "Jerome Collet", "probably my. com", + "Comrade", "Stefano Corona", "Corrolot", "Francisco Law Cortez", @@ -362,6 +385,7 @@ "Dani", "Daniel", "Daniel3505", + "DaniesAlex007", "Dančo", "Iman Darius", "DarkAnarcy", @@ -369,12 +393,15 @@ "DarshaN", "Shibin das", "Dasto", + "David", "Davide", + "DavidPlayzloll", "DaymanLP", "Ddávid", "Die or Dead", "Привет от детей DeadLine", "deepjith", + "deliciouspudding43", "delshe", "Denis", "Dennis", @@ -399,6 +426,7 @@ "Dmirus", "Count Su Doku", "DominikSikora!", + "Kai Dominique", "Gerardo Doro", "DottorMorte", "Dragomir", @@ -422,11 +450,14 @@ "EKFH", "avatar por reina del carnaval en la que te lo mando el", "Rezk ElAdawy", + "ElCatCaesar", "ElderLink", + "Elian", "Elsans320_YT", "Elskoser", "ElVolKo", "Ramy Emad", + "Emil", "Kürti Emil", "Muhammed emir", "EmirSametEr", @@ -443,6 +474,8 @@ "Esmael", "Jose espinoza", "ethanmigueltrinidad", + "ExaYT", + "Exelendary", "Abdullatif Badinjki ExPeRt 1420", "ExplosiveDinosaurs.com", "EXTENDOO", @@ -457,7 +490,9 @@ "FanDolz.", "Faqih", "Muhammad Faqih ''None''", + "Syed Irfan Farhan", "Luiz Henrique Faria", + "Syed Fahrin Farihin", "FaultyAdventure", "Putra Riski Fauzi", "fauziozan.23@gmail.com", @@ -474,16 +509,20 @@ "FightBiscuit", "filip", "Filip117", + "Fillowskyy", "Firdaus", "Daffa Firdaus", "Aldereus Fire", "Robert Fischer", "Kai Fleischmann", "Iancu Florin", + "FluffyPal", "FLᎧRᏋᏁTIᏁᎧ", "Angelo Fontana", "FortKing", + "Freaku", "Golden Freddy", + "FREÂK", "Andrey Fridholm", "FriskTheHuman303", "Froshlee14", @@ -492,6 +531,7 @@ "Gustavo FunnyGuard28", "Erick G", "Roberto G", + "George G.", "Fabian G.L.", "G192", "MZ G4MES", @@ -530,6 +570,7 @@ "Jhon Zion N. delos reyes gmail", "God丶烛龙", "박준서(PJS GoodNews)", + "gowthamvelkarthik.k", "Nicola Grassi", "Gerrit Grobler", "Oliver Grosskloss", @@ -541,6 +582,7 @@ "Gurad", "Max Guskov", "Rachmat Gusti", + "Aditya Gwala", "Tódor Gábor", "Tymoteusz Górski", "Thomas Günther", @@ -563,12 +605,14 @@ "Abdi Haryadi", "Hasan", "Mohammad hasan", + "Hisham bin Hashim", "Emil Hauge", "Arian Haxhijaj", "Ergin Haxhijaj", "Florian Haxhijaj", "Hayate", "Hayate16", + "hehhwushh", "Lukas Heim", "Hugues Heitz", "HellisWrath", @@ -617,6 +661,7 @@ "!YamGila (Syed Ilham)", "Iliya_bomB", "illonis", + "Syed Ilham Ilman", "Ily77788", "Ilya", "IlyxaGold", @@ -700,6 +745,7 @@ "kalpesh", "Kalyan", "Kamal", + "Aiman Aryan Kamarajan", "Kamil (Limak09)", "Kaneki", "Smurfit Kappa", @@ -738,6 +784,7 @@ "Philipp Koch", "Kolmat", "komasio", + "komasio71", "KomodoRec", "Niko Koren", "Nikolay Korolyov", @@ -766,6 +813,7 @@ "John Patrick Lachica", "laikrai", "m a lakum", + "Dmitry Lamperujev", "K. Larsen", "Nicklas Larsen", "Shin Lasung", @@ -784,11 +832,13 @@ "Shuaibing Li", "Tred Li", "Juan Liao", + "LickyBeeYT", "Nicola Ligas", "Limak09", "lin", "Dustin Lin", "Kyle Lin", + "Linus", "Linux44313", "LiteBalt", "LittleNyanCat", @@ -815,9 +865,11 @@ "luispro25", "Luka", "Luke", + "Luke994", "Lukman", "Hermanni Luosujärvi", "Lurã", + "Luthy", "Geogre Lyu", "M.R.T", "Mac 143338", @@ -832,6 +884,7 @@ "Mahmoud", "maicol", "Majestozão", + "Makar", "Maks1212", "Malaysian", "EMILIO MALQUIN", @@ -859,6 +912,7 @@ "Martín", "Taobao Mascot", "Masood", + "MasterRyan", "Mathias", "matias", "matj1", @@ -876,6 +930,7 @@ "Kevin Mejía", "MereCrack", "Mert", + "Meryu07", "Meysam", "MGH", "Mick", @@ -903,9 +958,12 @@ "Mohamed", "Mohammad", "Mohammad11dembele", + "MOHAMMADERFAN", "Mohammadhosain", "Mohammed", + "MOHAMMEDTALAL1ST", "1n Mohhaamad", + "Moin", "MONIRIE", "Carlos Montalvo", "Ederson Moraes", @@ -963,7 +1021,9 @@ "Nico-iVekko", "Nicola", "Nicolas", + "Niels", "Frederik Nielsen", + "Nifujini", "Nikali2007", "Nima", "XU NING", @@ -975,6 +1035,7 @@ "Noam", "Simone Nobili", "NofaseCZ", + "Max Noisa", "Noisb", "Noobslaya101", "noorjandle1", @@ -1001,8 +1062,10 @@ "Abhinay Pandey", "PangpondTH", "PantheRoP", + "ParadoxPlayz", "Gavin Park", "Parkurist", + "Pascal17", "Pastis69", "Sagar patil", "pato", @@ -1010,6 +1073,7 @@ "paulo", "Dominik Pavešić", "BARLAS PAVLOS-IASON", + "Payu", "PC189085", "PC192082", "pc192089", @@ -1048,21 +1112,27 @@ "Jaideep Kumar PM", "podolianyn", "poggersCat", + "Pong", "Pooya", "pouriya", "Pranav", "Luca Preibsch", + "Prem", "Fabian Prinz", "Private0201", "Priyanshu", + "Brayk pro 2.0", + "Sus propios", "psychatrickivi12", "pszlklismo", "Pulidomedia.com", "haris purnama", "GABRIEL PUTRICK", "Gangler Quentin", + "Qwsa", "QŴE", "Anbarasan R", + "efvdtrrgvvfygttty5 5 r", "Felo Raafat", "Tim Rabatr", "RadicalGamer", @@ -1158,7 +1228,10 @@ "M. Rizki Agus Salim", "Salted", "Salvo04", + "San", + "SaNt0RiNiKits577YT", "Guilherme Santana", + "Santiago", "Ivan Santos :)", "Diamond Sanwich", "SAO_OMH", @@ -1175,6 +1248,7 @@ "Mihai Serbanica", "Daniel Balam Cabrera Serrano", "Yefta Aditya Setiawan", + "Sg", "sgx", "Black Shadow", "ShadowQ", @@ -1184,6 +1258,7 @@ "Nalam Shashwath", "Haige Shi", "ShockedGaming", + "Shogun", "Shayan Shokry", "Dominik Sikora", "Leonardo Henrique da Silva", @@ -1212,6 +1287,7 @@ "Spielfream", "Spy", "sss", + "ST", "Danny Stalman", "stampycat", "Bartosz Staniszewski", @@ -1222,12 +1298,16 @@ "stelios", "Stephanie", "stephen", + "Aleksa Stevčić", "Janis Stolzenwald", "Storm", + "STPayoube", + "Stratex", "SYED EPIC STUDIOS", "sun.4810", "Samet Sunal", "sundar", + "Indo sus", "Sven", "Shannon Sy", "syaifudib", @@ -1237,12 +1317,14 @@ "Daniel Sýkora", "Arung Taftazani", "taha", + "Rasim Eren TAHMAZ", "Juancho Talarga", "Emre Talha(Alienus)", "talopl123", "Talrev134", "Kaustubh Tando", "Kaustubh Tandon", + "Tania", "Dmytro Tarasenko", "Tarma", "tarun", @@ -1271,6 +1353,7 @@ "TheMikirog", "Theo", "Thiago_TRZ", + "ThisIsBad", "Trevon Thrasher", "Tiberiu", "Cristian Ticu", @@ -1325,6 +1408,7 @@ "Robin Vinith", "vinoth", "Vishal", + "Voxel", "VTOR", "Fernando Véliz", "Vít", @@ -1355,6 +1439,7 @@ "WonkaWoe", "Moury ji world", "wsltshh", + "Wurstkatze", "WurstSaft", "Xavier", "Francisco Xavier", @@ -1383,6 +1468,7 @@ "yullian", "NEEROOA Muhammad Yusuf", "Yuuki", + "Yy", "yyr_rs", "z", "Sam Z", @@ -1424,6 +1510,7 @@ "опять Вильян", "Тот самый Вильян", "Влад", + "Даниил", "данил", "дибисяра", "Евгений(Eugene)", @@ -1455,6 +1542,7 @@ "Ярослав \"Noiseaholic\"", "қуатжан", "اا", + "احمدرضا", "احمد اسامه", "احمد سني اسماعيل", "الأول", @@ -1471,6 +1559,7 @@ "حسين حساني", "جود حيدر", "محمد خالد", + "امیرحسین دهقان", "امید رضازاده", "محمد وائل سلطان", "ص", @@ -1493,6 +1582,7 @@ "نریمان", "عادل نوروزی", "ه۶۹", + "حسین وفایی‌فرد", "انا يا عمر انا بران يا عمر انا بران يا عمر انا بران يا عمر انا بران يا عمر انا بران يا عمر انا بران يا عمر انا بران يا عمر انا بران يا عمر انا بران يا عمر انا بران يا عمر انا بران يا", "١٢٣٤٥", "علیرضا پودینه", @@ -1500,6 +1590,7 @@ "അർഷഖ് ഹസ്സൻ", "วีรภัทร", "แมวผงาด(JuniorMeowMeow)", + "๖̶ζ͜͡zephyro", "✰ℭØØҜĬ£$✰", "JPnatu なつ", "クリーバー", @@ -1512,6 +1603,7 @@ "别闹我有药/Medic", "别闹我有药Medic", "南宫銷子()", + "哔哩哔哩@Medic药", "夏神(后期汉化修正)", "小黑猫", "张帅", @@ -1524,6 +1616,7 @@ "熊老三", "盐焗汽水er", "神仙", + "药药Medic", "蔚蓝枫叶", "鲲鹏元帅", "꧁ℤephyro꧂", @@ -1531,8 +1624,10 @@ "권찬근", "김원재", "넌", + "먹꾸리", "박건희", "김대중 부관참시", + "붐추", "사람사는 세상", "신라성", "이지민", diff --git a/dist/ba_data/data/languages/arabic.json b/dist/ba_data/data/languages/arabic.json index db5e42d..c3455df 100644 --- a/dist/ba_data/data/languages/arabic.json +++ b/dist/ba_data/data/languages/arabic.json @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "Google Play سجل دخولك عبر", "signInWithTestAccountInfoText": "(حساب موجود على هاتفك; استخدم حساب الهاتف للمتابعة)", "signInWithTestAccountText": "تسجيل الدخول بحساب تجريبي", + "signInWithV2InfoText": "حساب يعمل على جميع المنصات", + "signInWithV2Text": "قم بتسجيل الدخول باستخدام حساب BombSquad", "signOutText": "تسجيل الخروج", "signingInText": "...جارٍ تسجيل دخولك", "signingOutText": "...جارٍ تسجيل خروجك", @@ -37,6 +39,7 @@ "titleText": "الحساب", "unlinkAccountsInstructionsText": "حدد حسابا لإلغاء ربطه", "unlinkAccountsText": "إلغاء ربط الحسابات", + "v2LinkInstructionsText": "استخدم هذا الارتباط لإنشاء حساب أو تسجيل الدخول.", "viaAccount": "(${NAME} عبر الحساب)", "youAreSignedInAsText": ": قمت بتسجيل الدخول كـ" }, @@ -496,6 +499,7 @@ "yourPowerRankingText": "تصنيف الطاقة:" }, "copyOfText": "${NAME} نسخ", + "copyText": "ينسخ", "createEditPlayerText": "<اصنع او عدل حساب>", "createText": "اصنع", "creditsWindow": { @@ -1496,6 +1500,7 @@ "Dutch": "هولندي", "English": "الإنجليزية", "Esperanto": "الاسبرانتو", + "Filipino": "الفلبينية", "Finnish": "اللغة الفنلندية", "French": "الفرنسية", "German": "الألمانية", @@ -1516,6 +1521,7 @@ "Slovak": "السلوفاكية", "Spanish": "الإسبانية", "Swedish": "اللغة السويدية", + "Tamil": "اللغةالتاميلية", "Thai": "تايلاندي", "Turkish": "اللغة التركية", "Ukrainian": "الأوكراني", diff --git a/dist/ba_data/data/languages/belarussian.json b/dist/ba_data/data/languages/belarussian.json index 36846ba..ce89a78 100644 --- a/dist/ba_data/data/languages/belarussian.json +++ b/dist/ba_data/data/languages/belarussian.json @@ -28,6 +28,8 @@ "signInWithGooglePlayText": "Увайсці з дапамогаю Google Play", "signInWithTestAccountInfoText": "(акаўнт, які ўжо існуе; спачатку увайдзіце з прылады)", "signInWithTestAccountText": "Увайсці з тэст-акаўнта", + "signInWithV2InfoText": "(уліковы запіс, які працуе на ўсіх платформах)", + "signInWithV2Text": "Увайдзіце з уліковым запісам BombSquad", "signOutText": "Выйсці", "signingInText": "Уваход...", "signingOutText": "Выхад...", @@ -38,6 +40,7 @@ "titleText": "Акаўнт", "unlinkAccountsInstructionsText": "Выберыце ўліковы запіс, каб спыніць сувязь", "unlinkAccountsText": "Адлучэнне акаунтау", + "v2LinkInstructionsText": "Выкарыстоўвайце гэтую спасылку, каб стварыць уліковы запіс або ўвайсці.", "viaAccount": "(праз акаунт ${NAME})", "youAreSignedInAsText": "Вы ўвайшлі як:" }, @@ -496,6 +499,7 @@ "yourPowerRankingText": "Ваш Узровень:" }, "copyOfText": "Копія ${NAME}", + "copyText": "Копія", "createEditPlayerText": "<Стварыць/Змяніць Гульца>", "createText": "Стварыць", "creditsWindow": { @@ -1511,6 +1515,7 @@ "Dutch": "Нямецкая", "English": "Англійская", "Esperanto": "Эсперанта", + "Filipino": "філіпінскі", "Finnish": "Фінская", "French": "Французская", "German": "Нямецкая", @@ -1531,6 +1536,7 @@ "Slovak": "Славацкая", "Spanish": "Гішпанская", "Swedish": "Шведская", + "Tamil": "тамільская", "Thai": "Тайская мова", "Turkish": "Турэцкі", "Ukrainian": "Украінскі", diff --git a/dist/ba_data/data/languages/chinese.json b/dist/ba_data/data/languages/chinese.json index 965cc2b..7c092d6 100644 --- a/dist/ba_data/data/languages/chinese.json +++ b/dist/ba_data/data/languages/chinese.json @@ -30,6 +30,8 @@ "signInWithGooglePlayText": "用 Google Play 来登陆", "signInWithTestAccountInfoText": "使用设备上的其他网络帐号登录;不建议选择该项", "signInWithTestAccountText": "用测试账户来登陆", + "signInWithV2InfoText": "(账户在所有平台都通用)", + "signInWithV2Text": "使用炸弹小分队账号登录", "signOutText": "登出", "signingInText": "登录中...", "signingOutText": "登出中...", @@ -39,6 +41,7 @@ "titleText": "账号", "unlinkAccountsInstructionsText": "选择要取消关联的帐户", "unlinkAccountsText": "取消连结帐户", + "v2LinkInstructionsText": "扫码或使用链接来登录或注册新账户", "viaAccount": "(不可用名称 ${NAME})", "youAreLoggedInAsText": "您已登录为", "youAreSignedInAsText": "你已登录为:" @@ -498,6 +501,7 @@ "yourPowerRankingText": "你的能力排位:" }, "copyOfText": "${NAME} 复制", + "copyText": "copy", "createEditPlayerText": "<创建/编辑玩家>", "createText": "创建", "creditsWindow": { @@ -1151,7 +1155,7 @@ "purchasingText": "正在购买…", "quitGameText": "退出${APP_NAME}?", "quittingIn5SecondsText": "在5秒后退出...", - "randomPlayerNamesText": "Deva最萌,企鹅王,企鹅骑士团成员,王♂の传人,挨揍使我快乐,ChineseBomber,一拳超人,二营长の意大利炮,野渡无人舟自横,马克斯,雪糕,炸鸡翅,手柄玩家18子,寻找宝藏的海盗,炸弹投手,炸弹不是糖果,我是对面的,Xxx_至高无上之炸弹王_xxX,万有引力,鸟语花香,狗年大吉,小狗狗,大狗子,二狗子,三狗子,四狗子,五狗子,高质量人类,吴签,菜虚困,劈我瓜是吧,是我dio哒,亚达哟", + "randomPlayerNamesText": "企鹅王,企鹅骑士团成员,王♂の传人,挨揍使我快乐,ChineseBomber,一拳超人,二营长の意大利炮,野渡无人舟自横,马克斯,雪糕,炸鸡翅,手柄玩家18子,寻找宝藏的海盗,炸弹投手,炸弹不是糖果,我是对面的,万有引力,鸟语花香,狗年大吉,小狗狗,大狗子,二狗子,三狗子,四狗子,五狗子,高质量人类,吴签,菜虚困,劈我瓜是吧,是我dio哒,亚达哟,王雷卖鱼,蕉♂个朋友,小猪配齐,摇摆羊,可莉,胡桃,钟离,七七,刻晴,甘雨,巴巴托斯,温迪,旅行者,绿坝娘,哔哩哔哩,别闹我有药", "randomText": "随机", "rankText": "排行", "ratingText": "排名", @@ -1514,6 +1518,7 @@ "Dutch": "荷兰语", "English": "英语", "Esperanto": "世界语", + "Filipino": "菲律宾语", "Finnish": "芬兰语", "French": "法语", "German": "德语", @@ -1534,6 +1539,7 @@ "Slovak": "斯洛伐克语", "Spanish": "西班牙语", "Swedish": "瑞典语", + "Tamil": "泰米尔语", "Thai": "泰语", "Turkish": "土耳其语", "Ukrainian": "乌克兰语", diff --git a/dist/ba_data/data/languages/chinesetraditional.json b/dist/ba_data/data/languages/chinesetraditional.json index b2a7a87..b060b86 100644 --- a/dist/ba_data/data/languages/chinesetraditional.json +++ b/dist/ba_data/data/languages/chinesetraditional.json @@ -27,6 +27,8 @@ "signInWithGooglePlayText": "用play商店登入", "signInWithTestAccountInfoText": "(舊有的帳號登入方式;使用後來的創設的帳號)", "signInWithTestAccountText": "用測試帳號登入", + "signInWithV2InfoText": "(可用於所有平臺的賬戶)", + "signInWithV2Text": "使用Bombsquad賬戶登入", "signOutText": "登出", "signingInText": "登入中…", "signingOutText": "登出中…", @@ -34,6 +36,7 @@ "titleText": "帳號", "unlinkAccountsInstructionsText": "選擇一個要解除連結的帳號", "unlinkAccountsText": "解除連結帳號", + "v2LinkInstructionsText": "使用此鏈接新建或登錄賬戶", "viaAccount": "(透過帳號 ${NAME})", "youAreSignedInAsText": "您以這帳號登入:" }, @@ -492,6 +495,7 @@ "yourPowerRankingText": "你的能力排名:" }, "copyOfText": "${NAME} 拷貝", + "copyText": "複製", "createEditPlayerText": "<創建/編輯玩家>", "createText": "創建", "creditsWindow": { @@ -1492,6 +1496,7 @@ "Dutch": "荷蘭語", "English": "英語", "Esperanto": "世界語", + "Filipino": "菲律賓語", "Finnish": "芬蘭語", "French": "法語", "German": "德語", @@ -1512,6 +1517,7 @@ "Slovak": "斯洛伐克語", "Spanish": "西班牙語", "Swedish": "瑞典語", + "Tamil": "泰米爾語", "Thai": "泰語", "Turkish": "土耳其語", "Ukrainian": "烏克蘭語", diff --git a/dist/ba_data/data/languages/croatian.json b/dist/ba_data/data/languages/croatian.json index 53efc5f..4f5fbbf 100644 --- a/dist/ba_data/data/languages/croatian.json +++ b/dist/ba_data/data/languages/croatian.json @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "Prijavi sa sa Google Play", "signInWithTestAccountInfoText": "(stari tip profila; ubuduće koristi profile uređaja)", "signInWithTestAccountText": "Prijavi se s testnim profilom", + "signInWithV2InfoText": "(račun koji radi na svim platformama)", + "signInWithV2Text": "Prijavite se s BombSquad računom", "signOutText": "Odjavi se", "signingInText": "Prijava...", "signingOutText": "Odjava...", @@ -39,6 +41,7 @@ "titleText": "Račun", "unlinkAccountsInstructionsText": "Odaberi račun za prekid veze.", "unlinkAccountsText": "Prekini vezu računa", + "v2LinkInstructionsText": "Koristite ovu vezu za kreiranje računa ili prijavu.", "viaAccount": "(Preko ${NAME} računa)", "youAreSignedInAsText": "Prijavljeni ste kao:" }, @@ -498,6 +501,7 @@ "yourPowerRankingText": "Tvoja pozicija" }, "copyOfText": "Kopija ${NAME}", + "copyText": "Kopirati", "createEditPlayerText": "", "createText": "Stvori", "creditsWindow": { @@ -684,11 +688,18 @@ "bluetoothJoinText": "Uključi se preko Bluetooth-a", "bluetoothText": "Bluetooth", "checkingText": "provjeravam...", + "copyCodeConfirmText": "Kôd je kopiran u međuspremnik.", + "copyCodeText": "Kopiraj kod", "dedicatedServerInfoText": "Za najbolje rezultate, postavi posvećen server. Vidi bombsquadgame.com/server da saznas kako.", "disconnectClientsText": "Ovo će isključiti ${COUNT} igrača\niz partije. Jesi li siguran?", "earnTicketsForRecommendingAmountText": "Prijatelji će dobiti ${COUNT} ulaznica ako probaju igru\n(ti ćeš dobiti ${YOU_COUNT} ulaznica za svakog koji proba)", "earnTicketsForRecommendingText": "Podeli igri za besplatne karte\n...", "emailItText": "Emajlaj", + "favoritesSaveText": "Spremi kao favorit", + "favoritesText": "Omiljeni", + "freeCloudServerAvailableMinutesText": "Sljedeći besplatni poslužitelj u oblaku dostupan za ${MINUTES} minuta.", + "freeCloudServerAvailableNowText": "Besplatno dostupan poslužitelj u oblaku!", + "freeCloudServerNotAvailableText": "Nema dostupnih besplatnih poslužitelja u oblaku.", "friendHasSentPromoCodeText": "${COUNT} ${APP_NAME} ulaznica od ${NAME}", "friendPromoCodeAwardText": "Primit ćeš ${COUNT} ulaznica svaki put kada je kod iskorišten.", "friendPromoCodeExpireText": "Ovaj kod će isteći za ${EXPIRE_HOURS} sati i radi samo za nove igrače.", @@ -703,7 +714,8 @@ "googlePlaySeeInvitesText": "Pogledaj pozive", "googlePlayText": "Google Play", "googlePlayVersionOnlyText": "(Android / Google Play verzija)", - "hostPublicPartyDescriptionText": "Izradi javnu partiju:", + "hostPublicPartyDescriptionText": "Izradi javnu partiju", + "hostingUnavailableText": "Hosting nedostupan", "inDevelopmentWarningText": "Pažnja: \n\nMrežna igra je nova značajka koja je još u razvoju. \nZasad, preporučuje se da su svi\nigrači spojeni na istu Wi-Fi mrežu.", "internetText": "Internet", "inviteAFriendText": "Prijatelji nemaju igru? Pozovi ih da je\nprobaju i oni će dobiti ${COUNT} besplatnih ulaznica.", diff --git a/dist/ba_data/data/languages/czech.json b/dist/ba_data/data/languages/czech.json index 39214ce..630b1b6 100644 --- a/dist/ba_data/data/languages/czech.json +++ b/dist/ba_data/data/languages/czech.json @@ -30,6 +30,8 @@ "signInWithGooglePlayText": "Přihlásit se přes Google Play", "signInWithTestAccountInfoText": "(zastaralý typ účtu; použije raději účet zařízení)", "signInWithTestAccountText": "Přihlásit se s testovacím účtem", + "signInWithV2InfoText": "(účet který funguje na všech platformách)", + "signInWithV2Text": "Přihlášení s BombSquad účtem", "signOutText": "Odhlásit se", "signingInText": "Přihlašuji se...", "signingOutText": "Odhlašuji se...", @@ -40,6 +42,7 @@ "titleText": "Profil", "unlinkAccountsInstructionsText": "Zvolte účet k odpojení", "unlinkAccountsText": "Odpojit účty", + "v2LinkInstructionsText": "Použijte tento odkaz pro vytvoření účtu nebo přihlášení.", "viaAccount": "(přes účet ${NAME})", "youAreLoggedInAsText": "Jste přihlášen jako:", "youAreSignedInAsText": "Jste přihlášen jako:" @@ -502,6 +505,7 @@ "yourPowerRankingText": "Vaše pozice:" }, "copyOfText": "${NAME} Kopie", + "copyText": "Kopírovat", "createEditPlayerText": "", "createText": "Vytvořit", "creditsWindow": { @@ -1381,7 +1385,7 @@ "Agent Johnson": "Agent Johnson", "B-9000": "B-9000", "Bernard": "Bernard", - "Bones": "Kosťa", + "Bones": "Kosťík", "Butch": "Butch", "Easter Bunny": "Velikonoční králíček", "Flopsy": "Flopsy", @@ -1515,6 +1519,7 @@ "Dutch": "Holandština", "English": "Angličtina", "Esperanto": "Esperanto", + "Filipino": "Filipínština", "Finnish": "Finština", "French": "Francouzština", "German": "Němčina", @@ -1535,6 +1540,7 @@ "Slovak": "Slovenština", "Spanish": "Španělština", "Swedish": "Švédština", + "Tamil": "Tamiština", "Thai": "Thaiština", "Turkish": "Turečtina", "Ukrainian": "Ukrajinština", diff --git a/dist/ba_data/data/languages/dutch.json b/dist/ba_data/data/languages/dutch.json index 02ba231..a706cfc 100644 --- a/dist/ba_data/data/languages/dutch.json +++ b/dist/ba_data/data/languages/dutch.json @@ -31,6 +31,8 @@ "signInWithGooglePlayText": "Log in met Google Play", "signInWithTestAccountInfoText": "(oudere account type; gebruik device account gaat door)", "signInWithTestAccountText": "Log in met test account", + "signInWithV2InfoText": "(een account dat op alle platforms werkt)", + "signInWithV2Text": "Inloggen met een BombSquad rekening", "signOutText": "Log Uit", "signingInText": "Inloggen...", "signingOutText": "Uitloggen...", @@ -41,6 +43,7 @@ "titleText": "Profiel", "unlinkAccountsInstructionsText": "Selecteer een account om los te koppelen.", "unlinkAccountsText": "Koppel accounts los.", + "v2LinkInstructionsText": "Gebruik deze link om een ​​account aan te maken of in te loggen.", "viaAccount": "(via account ${NAME})", "youAreLoggedInAsText": "Je bent ingelogd als:", "youAreSignedInAsText": "U bent ingelogd als:" @@ -660,6 +663,7 @@ "titleFolderText": "Selecteer een Map", "useThisFolderButtonText": "Gebruik Deze Map" }, + "filterText": "Filteren", "finalScoreText": "Uiteindelijke Score", "finalScoresText": "Uiteindelijke Scores", "finalTimeText": "Uiteindelijke Tijd", @@ -710,11 +714,18 @@ "bluetoothJoinText": "Neem deel via Bluetooth", "bluetoothText": "Bluetooth", "checkingText": "controleren...", + "copyCodeConfirmText": "Code gekopieerd naar klembord", + "copyCodeText": "Kopieer Code", "dedicatedServerInfoText": "Voor het beste resultaat, zet dan een dedicated server op. Zie bombsquadgame.com/server om te leren hoe.", "disconnectClientsText": "Hierdoor verbreekt de verbinding met ${COUNT} spelers(s)\nvan uw partij. Weet u het zeker?", "earnTicketsForRecommendingAmountText": "Vrienden ontvangen ${COUNT} tickets als ze het spel proberen\n(en jij ontvangt ${YOU_COUNT} voor elke vriend die dit doet)", "earnTicketsForRecommendingText": "Deel de game \nVoor gratis tickets...", "emailItText": "Mail het", + "favoritesSaveText": "Opslaan Als Favoriet", + "favoritesText": "Favorieten", + "freeCloudServerAvailableMinutesText": "Volgende gratis cloud server beschikbaar in ${MINUTES} minuten.", + "freeCloudServerAvailableNowText": "Volgende gratis cloud server beschikbaar!", + "freeCloudServerNotAvailableText": "Geen gratis cloud server beschikbaar.", "friendHasSentPromoCodeText": "${COUNT} ${APP_NAME} tickets van ${NAME}", "friendPromoCodeAwardText": "Je krijgt ${COUNT} tickets elke keer het is gebruikt.", "friendPromoCodeExpireText": "Deze code zal vervallen in ${EXPIRE_HOURS} uren en werkt alleen met nieuwe spelers.", @@ -729,19 +740,21 @@ "googlePlaySeeInvitesText": "Zie Uitnodigingen", "googlePlayText": "Google Play", "googlePlayVersionOnlyText": "(Android / Google Play versie)", - "hostPublicPartyDescriptionText": "Accommodeer een Publieke Partij:", + "hostPublicPartyDescriptionText": "Accommodeer een Publieke Partij", + "hostingUnavailableText": "Gastheer Niet beschikbaar", "inDevelopmentWarningText": "Let op:\n\nNetwerk spel is een nieuwe functie in ontwikkeling.\nVoor nu wordt het streng aangeraden dat alle\nspelers op het zelfde Wi-Fi netwerk zijn.", "internetText": "Internet", "inviteAFriendText": "Hebben je vrienden dit spel niet?\nNodig ze uit om het uit te proberen en ze krijgen ${COUNT} gratis tickets.", "inviteFriendsText": "Nodig vrienden uit", - "joinPublicPartyDescriptionText": "Meedoen aan een Publieke Partij.", - "localNetworkDescriptionText": "Neem deel aan een partij in uw netwerk:", + "joinPublicPartyDescriptionText": "Meedoen aan een Publieke Partij", + "localNetworkDescriptionText": "Word lid van een feest in de buurt (LAN, Bluetooth, meer)", "localNetworkText": "Lokaal Netwerk", "makePartyPrivateText": "Maak mijn Partij Privé", "makePartyPublicText": "Maak Mijn Partij Publiek", "manualAddressText": "Adres", "manualConnectText": "Verbind", "manualDescriptionText": "Neem deel aan een partij via adres", + "manualJoinSectionText": "Deelnemen op adres", "manualJoinableFromInternetText": "Kunnen mensen deelnemen via het internet?:", "manualJoinableNoWithAsteriskText": "NEE*", "manualJoinableYesText": "JA", @@ -749,14 +762,17 @@ "manualText": "Handmatig", "manualYourAddressFromInternetText": "Uw adres via het internet:", "manualYourLocalAddressText": "Uw lokale adres:", + "nearbyText": "Dichtbij", "noConnectionText": "", "otherVersionsText": "(andere versies)", + "partyCodeText": "Partijcode", "partyInviteAcceptText": "Accepteren", "partyInviteDeclineText": "Weigeren", "partyInviteGooglePlayExtraText": "(bekijk het 'Google Play' tabblad in het 'Verzamel' venster)", "partyInviteIgnoreText": "Negeren", "partyInviteText": "${NAME} heeft je uitgenodigd\nom bij zijn partij te voegen!", "partyNameText": "Partij Naam", + "partyServerRunningText": "Uw partyserver is actief.", "partySizeText": "partij grootte", "partyStatusCheckingText": "status controleren...", "partyStatusJoinableText": "uw partij is nu toegankelijk via het internet", @@ -765,12 +781,22 @@ "partyStatusNotPublicText": "uw partij is niet publiek", "pingText": "ping", "portText": "Port", + "privatePartyCloudDescriptionText": "Privaat partijen draaien op toegewijd cloud servers; geen routerconfiguratie vereist.", + "privatePartyHostText": "Organiseer een Privefeestje", + "privatePartyJoinText": "Lid worden Privefeestje", + "privateText": "Privaat", + "publicHostRouterConfigText": "Hiervoor moet mogelijk port-forwarding op uw router worden geconfigureerd. Voor een gemakkelijkere optie, organiseer een privéfeest.", + "publicText": "Openbaar", "requestingAPromoCodeText": "Code aanvragen...", "sendDirectInvitesText": "Verzend directe uitnodigingen", "shareThisCodeWithFriendsText": "Deel deze code met vrienden:", "showMyAddressText": "Toon Mijn Adres", "startAdvertisingText": "Begin Adverteren", + "startHostingPaidText": "Host nu voor ${COST}", + "startHostingText": "Gastheer", + "startStopHostingMinutesText": "Je kunt de komende ${MINUTES} minuten gratis starten en stoppen met hosten.", "stopAdvertisingText": "Stop Adverteren", + "stopHostingText": "Stoppen Gastheer Partij", "titleText": "Verzamel", "wifiDirectDescriptionBottomText": "Als alle apparaten een 'Wi-Fi Direct' paneel hebben, dan zou het mogelijk moeten zijn\nom ze te vinden en verbinden met elkaar. Als alle apparaten verbonden zijn, kan u hier\npartijen vormen via het 'Lokaal Netwerk' tab, net als bij een normaal Wi-Fi netwerk.\n\nVoor het beste resultaat zou de Wi-Fi Direct host ook de host moeten zijn van de ${APP_NAME} partij.", "wifiDirectDescriptionTopText": "Wi-Fi Direct kan gebruikt worden om directe verbinding te maken tussen Android apparaten zonder\ngebruik te maken van een Wi-Fi netwerk. Dit werkt het best bij Android 4.2 of nieuwer.\n\nOm het te gebruiken, open de Wi-Fi instellingen en zoek voor 'Wi-Fi Direct' in het menu.", @@ -838,6 +864,7 @@ "controllersInfoTextFantasia": "Een speler kan de afstandbediening gebruiken als controller,\nmaar gamepads zijn sterk aanbevolen. Je kunt ook mobiele-apparaten\ngebruiken als controllers via de gratis 'Bombsquad Remote' app.\nZie 'Controllers' onder 'Instellingen' voor meer info.", "controllersInfoTextMac": "Een of twee spelers kunnen gebruik maken van het toetsenbord, maar Bombsquad is het beste met gamepads.\nBombsquad kan gebruik maken van USB gamepads, PS3 controllers, Xbox 360 controllers, gebruik\nWiimotes en iOS / Android-apparaten om de karakters te besturen. Hopelijk heb je\neen aantal van deze bij de hand. Zie 'Controllers' onder 'Instellingen' voor meer info.", "controllersInfoTextOuya": "U kunt OUYA controllers, PS3 controllers, Xbox 360 controllers, \nen tal van andere USB-en Bluetooth-gamepads gebruiken met Bombsquad.\nU kunt ook iOS-en Android-apparaten gebruiken als controllers via de gratis\n'Bombsquad Remote' app. Zie 'Controllers' onder 'Instellingen' voor meer info.", + "controllersInfoTextRemoteOnly": "Je kunt ${APP_NAME} spelen met vrienden via een netwerk, of jij\nkunnen allemaal op hetzelfde apparaat spelen door telefoons te gebruiken als\ncontrollers via de gratis app '${REMOTE_APP_NAME}'.", "controllersText": "Controllers", "controlsSubtitleText": "Uw vriendelijke ${APP_NAME} personage heeft een aantal basis acties:", "controlsText": "Besturing", @@ -949,6 +976,9 @@ "jumpText": "Spring", "keepText": "houd", "keepTheseSettingsText": "Deze instellingen behouden?", + "keyboardChangeInstructionsText": "Dubbelklik op de spatiebalk om van toetsenbord te wisselen.", + "keyboardNoOthersAvailableText": "Geen andere toetsenborden beschikbaar.", + "keyboardSwitchText": "Toetsenbord overschakelen naar '${NAME}'.", "kickOccurredText": "${NAME} is eruit geschopt.", "kickQuestionText": "${NAME} er uit schoppen?", "kickText": "Er uit schoppen", @@ -1031,6 +1061,9 @@ "maxConnectionsText": "Max Connecties", "maxPartySizeText": "Max Partij Grootte", "maxPlayersText": "Max Spelers", + "modeArcadeText": "Speelhal Modus", + "modeClassicText": "Klassieke Modus", + "modeDemoText": "Demo Modus", "mostValuablePlayerText": "Meest Waardevolle Speler", "mostViolatedPlayerText": "Meest Geschonden Speler", "mostViolentPlayerText": "Meest Gewelddadige Speler", @@ -1074,6 +1107,7 @@ "offText": "Uit", "okText": "Ok", "onText": "Aan", + "oneMomentText": "Een Moment..", "onslaughtRespawnText": "${PLAYER} zal respawnen in golf ${WAVE}", "orText": "${A} of ${B}", "otherText": "Andere ...", @@ -1125,6 +1159,7 @@ "playerText": "Speler", "playlistNoValidGamesErrorText": "Deze speellijst bevat geen geldige vrijgespeelde spellen.", "playlistNotFoundText": "speellijst niet gevonden", + "playlistText": "Afspeellijst", "playlistsText": "Speellijsten", "pleaseRateText": "Als u geniet van ${APP_NAME}, zou u dan een moment willen\nnemen om een waardering te geven of recensie te schrijven.\nDit geeft ons nuttige feedback voor toekomstige ontwikkelingen.\n\nBedankt!\n-eric", "pleaseWaitText": "Even geduld...", @@ -1551,6 +1586,7 @@ "Dutch": "Nederlands", "English": "Engels", "Esperanto": "Esperanto", + "Filipino": "Filipijns", "Finnish": "Fins", "French": "Frans", "German": "Duits", @@ -1571,8 +1607,11 @@ "Slovak": "Sloveens", "Spanish": "Spaans", "Swedish": "Zweeds", + "Tamil": "Tamil", + "Thai": "Thais", "Turkish": "Turks", "Ukrainian": "Oekraïens", + "Venetian": "Venetiaanse", "Vietnamese": "Vietnamees" }, "leagueNames": { @@ -1621,6 +1660,7 @@ "Account linking successful!": "Account succesvol gelinkt!", "Account unlinking successful!": "Account verbinding succesvol verbroken!", "Accounts are already linked.": "Accounts zijn al gelinkt.", + "Ad view could not be verified.\nPlease be sure you are running an official and up-to-date version of the game.": "Advertentieweergave kan niet worden geverifieerd.\nZorg ervoor dat je een officiële en up-to-date versie van het spel gebruikt.", "An error has occurred; (${ERROR})": "er is een fout opgetreden; (${ERROR})", "An error has occurred; please contact support. (${ERROR})": "er is een fout opgetreden, neem contact op met de ondersteuning. (${ERROR})", "An error has occurred; please contact support@froemling.net.": "Er is een fout opgetreden; neem alstublieft contact op met support@froemling.net.", @@ -1646,6 +1686,7 @@ "Max number of profiles reached.": "Maximaal aantal profielen bereikt.", "Maximum friend code rewards reached.": "Maximum vriend code beloning behaald", "Message is too long.": "Bericht is te lang.", + "No servers are available. Please try again soon.": "Er zijn geen servers beschikbaar. Probeer het binnenkort opnieuw.", "Profile \"${NAME}\" upgraded successfully.": "Profiel \"${NAME}\" is succesvol opgewaardeerd.", "Profile could not be upgraded.": "Profiel kon niet worden opgewaardeerd.", "Purchase successful!": "Aankoop succesvol!", @@ -1655,10 +1696,12 @@ "Sorry, this code has already been used.": "Sorry, deze code is al gebruikt.", "Sorry, this code has expired.": "Sorry, deze code is verlopen.", "Sorry, this code only works for new accounts.": "Sorry, deze code werkt alleen op nieuwe accounts.", + "Still searching for nearby servers; please try again soon.": "Nog steeds op zoek naar servers in de buurt; probeer het snel opnieuw.", "Temporarily unavailable; please try again later.": "Tijdelijk niet beschikbaar; probeer het later opnieuw.", "The tournament ended before you finished.": "Het toernooi eindigde voordat u klaar was.", "This account cannot be unlinked for ${NUM} days.": "Dit account kan gedurende ${NUM} dagen niet worden ontkoppeld.", "This code cannot be used on the account that created it.": "Deze code kan niet gebruikt worden op het account die het gemaakt heeft.", + "This is currently unavailable; please try again later.": "Dit is momenteel niet beschikbaar; probeer het later opnieuw.", "This requires version ${VERSION} or newer.": "Dit vereist versie ${VERSION} of nieuwer.", "Tournaments disabled due to rooted device.": "Toernooien uitgeschakeld vanwege geworteld apparaat", "Tournaments require ${VERSION} or newer": "toernooi vereist ${VERSION} of nieuwer", diff --git a/dist/ba_data/data/languages/english.json b/dist/ba_data/data/languages/english.json index 71fdd00..12f6f79 100644 --- a/dist/ba_data/data/languages/english.json +++ b/dist/ba_data/data/languages/english.json @@ -27,6 +27,8 @@ "signInWithGooglePlayText": "Sign in with Google Play", "signInWithTestAccountInfoText": "(legacy account type; use device accounts going forward)", "signInWithTestAccountText": "Sign in with test account", + "signInWithV2InfoText": "(an account that works on all platforms)", + "signInWithV2Text": "Sign in with a BombSquad account", "signOutText": "Sign Out", "signingInText": "Signing in...", "signingOutText": "Signing out...", @@ -34,6 +36,7 @@ "titleText": "Account", "unlinkAccountsInstructionsText": "Select an account to unlink", "unlinkAccountsText": "Unlink Accounts", + "v2LinkInstructionsText": "Use this link to create an account or sign in.", "viaAccount": "(via account ${NAME})", "youAreSignedInAsText": "You are signed in as:" }, @@ -494,6 +497,7 @@ "yourPowerRankingText": "Your Power Ranking:" }, "copyOfText": "${NAME} Copy", + "copyText": "Copy", "createEditPlayerText": "", "createText": "Create", "creditsWindow": { @@ -1504,6 +1508,7 @@ "Dutch": null, "English": null, "Esperanto": null, + "Filipino": null, "Finnish": null, "French": null, "German": null, diff --git a/dist/ba_data/data/languages/esperanto.json b/dist/ba_data/data/languages/esperanto.json index d7abb9d..c47137d 100644 --- a/dist/ba_data/data/languages/esperanto.json +++ b/dist/ba_data/data/languages/esperanto.json @@ -1,14 +1,23 @@ { "accountSettingsWindow": { "accountProfileText": "(konta profilo)", + "accountsText": "Kontoj", "achievementProgressText": "Atingoj: ${COUNT} el ${TOTAL}", - "campaignProgressText": "Kampanja progreso: ${PROGRESS}", + "campaignProgressText": "Kampanja progreso [malfacila]: ${PROGRESS}", + "customName": "Adaptita nomo", + "linkAccountsEnterCodeText": "Enigi kodon", + "linkAccountsText": "Ligi kontojn", + "linkedAccountsText": "Ligitaj kontoj:", + "nameChangeConfirm": "Ĉu redakti vian kontan nomon al ${NAME}?", "notLoggedInText": "", "resetProgressConfirmNoAchievementsText": "Ĉi tio reigos vian kunlaboran progreson\nkaj lokajn plej altajn poentojn (sed ne\nviajn biletojn). Ne eblas malfari.\nĈu vi certas?", "resetProgressConfirmText": "Ĉi tio reigos vian kunlaboran\nprogreson, atingojn kaj lokajn\nplej altajn poentojn (sed ne\nviajn biletojn). Ne eblas malfari.\nĈu vi certas?", "resetProgressText": "Reigi progreson", "signInInfoText": "Ensalutu por konservi vian progreson\nen la nubon, gajni biletojn kaj\npartopreni en turniroj.", "signInText": "Ensaluti", + "signInWithDeviceText": "Ensaluti per aparatkonto", + "signInWithGameCircleText": "Ensaluti per Game Circle", + "signInWithGooglePlayText": "Ensaluti per Google Play", "signOutText": "Elsaluti", "signingInText": "Ensalutas...", "signingOutText": "Elsalutas...", @@ -17,6 +26,8 @@ "testAccountWarningText": "Atentu: vi estas ensalutita per test-konto.\nĈi tiu konto estas specifa por ĉi tiu aparato kaj\npovas esti fojfoje reigata. (do ne dum multa tempo\nkolektu kaj malŝlosu aferojn per ĝi)\n\nUzu vendo-version de la ludo por uzi \"veran\" konton\n(Game-Center, Google Plus ktp). Tio ankaŭ permesas\nal vi konservi progreson en la nubon kaj kunhavigi\ntion inter diversaj aparatoj.", "ticketsText": "Biletoj: ${COUNT}", "titleText": "Konto", + "unlinkAccountsText": "Malligi kontojn", + "viaAccount": "(per konto ${NAME})", "youAreLoggedInAsText": "Vi ensalutis kiel:", "youAreSignedInAsText": "Vi ensalutiĝis kiel:" }, @@ -305,7 +316,7 @@ "betaValidatedText": "Beta validiĝis; Ĝuu!", "bombBoldText": "BOMBO", "bombText": "Bombo", - "bsRemoteConfigureInAppText": "BombSquad teleregilo estas konfigurita en la aplikaĵo mem.", + "bsRemoteConfigureInAppText": "${REMOTE_APP_NAME} estas konfigurita en la aplikaĵo mem.", "buttonText": "butono", "canWeDebugText": "Ĉu vi ŝatus ke BombSquad aŭtomate raportu cimojn,\nkraŝojn kaj bazajn uzadajn informojn al la programisto?\n\nĈi tiuj datumoj ne enhavas personajn informojn kaj helpas\npor manteni la ludon flua kaj sencima.", "cancelText": "Nuligi", @@ -397,7 +408,7 @@ "explanationText": "Por uzi poŝtelefonon aŭ tabletkomputilon kiel sendratan\nregilon, instalu la aplikaĵon \"BombSquad Remote\" en ĝi.\nKiom ajn da aparatoj povas konektiĝi sendratrete, kaj senpage!", "forAndroidText": "por Android:", "forIOSText": "por iOS:", - "getItForText": "Akiru BombSquad Remote por iOS en la aplikaĵvendejo de \nApple aŭ por Android en la aplikaĵvendejo de Google aŭ Amazon", + "getItForText": "Akiru ${REMOTE_APP_NAME} por iOS ĉe la Apple App Store\naŭ por Android ĉe la Google Play Store aŭ Amazon Appstore", "googlePlayText": "Google Play", "titleText": "Uzi poŝaparatojn kiel regilojn:" }, @@ -415,6 +426,7 @@ "entryFeeText": "Enirpago", "multipliersText": "Multobligiloj", "ofTotalTimeText": "el ${TOTAL}", + "playNowText": "Ludi nun", "pointsText": "Poentoj", "powerRankingNotInTopText": "(ne en la supraj ${NUMBER})", "powerRankingPointsEqualsText": "= ${NUMBER} poentoj", @@ -435,6 +447,7 @@ }, "copyOfText": "Kopio de ${NAME}", "createAPlayerProfileText": "Ĉu krei ludantprofilon?", + "createEditPlayerText": "", "createText": "Krei", "creditsWindow": { "additionalAudioArtIdeasText": "Aldonaj aŭdaĵoj, unuaj artaĵoj kaj ideoj fare de ${NAME}", @@ -450,7 +463,7 @@ "soundsText": "Sonoj (${SOURCE}):", "specialThanksText": "Speciale dankon:", "thanksEspeciallyToText": "Specife dankon al ${NAME}", - "titleText": "Dankdiroj de BombSquad", + "titleText": "Dankdiroj de ${APP_NAME}", "whoeverInventedCoffeeText": "Kiu ajn inventis kafon" }, "currentStandingText": "Via nuna pozicio estas #${RANK}", @@ -480,6 +493,7 @@ "defaultNewGameListNameText": "Mia ludlisto de ${PLAYMODE}", "defaultNewTeamGameListNameText": "Miaj teamludoj", "defaultTeamGameListNameText": "Normala teamludaro", + "deleteText": "Forigi", "denyText": "Rifuzi", "desktopResText": "Distingivo", "difficultyEasyText": "Facile", @@ -489,6 +503,7 @@ "directBrowserToURLText": "Bonvolu viziti en retumilo la jenan ligilon:", "doneText": "Farite", "drawText": "Egalludo", + "duplicateText": "Duobligi", "editGameListWindow": { "addGameText": "Aldoni\nludon", "cantOverwriteDefaultText": "Ne eblas transskribi la implicitan ludliston!", @@ -544,6 +559,7 @@ "useMusicFileText": "Muzikdosiero (mp3, k.s.)", "useMusicFolderText": "Dosierujo da muzikdosieroj" }, + "editText": "Redakti", "endText": "Fini", "epicDescriptionFilterText": "${DESCRIPTION} en brila malrapideco", "epicNameFilterText": "Brila ${NAME}", @@ -551,10 +567,10 @@ "errorOutOfDiskSpaceText": "elĉerpiĝis diskspaco", "errorText": "Eraro", "errorUnknownText": "nekonata eraro", - "exitGameText": "Ĉu eliri el BombSquad?", + "exitGameText": "Ĉu eliri el ${APP_NAME}?", "externalStorageText": "Ekstera konservujo", "failText": "Fiasko", - "fatalErrorText": "Ho ve; io mankas aŭ rompiĝis.\nBonvolu provi reinstali BombSquad aŭ\nkontaktu ${EMAIL} por helpo.", + "fatalErrorText": "Ho ve; io mankas aŭ rompiĝis.\nBonvolu provi reinstali la apon aŭ\nkontaktu ${EMAIL} por helpo.", "fileSelectorWindow": { "titleFileFolderText": "Elektu dosieron aŭ dosierujon", "titleFileText": "Elektu dosieron", @@ -565,7 +581,7 @@ "finalScoresText": "Finaj poentoj", "finalTimeText": "Fina tempo", "finishingInstallText": "Finante instaliĝon, bonvolu atendi...", - "fireTVRemoteWarningText": "* Por pli bona sperto, uzu\nludregilojn aŭ instalu la\n'BombSquad Remote'-aplikaĵon\nen viaj telefonoj kaj tabuletoj.", + "fireTVRemoteWarningText": "* Por pli bona sperto, uzu\nludregilojn aŭ instalu la\n'${REMOTE_APP_NAME}'-aplikaĵon\nen viaj telefonoj kaj tabuletoj.", "firstToFinalText": "Unua-ĝis-${COUNT} finalo", "firstToSeriesText": "Unua-ĝis-${COUNT} serio", "fiveKillText": "KVINMORTIGO!!!", @@ -607,17 +623,25 @@ "bluetoothText": "Bluetooth", "checkingText": "kontrolante...", "disconnectClientsText": "Tio malkonektos la ${COUNT} ludanto(j)n\nen via ludantaro. Ĉu vi certas?", + "friendPromoCodeWhereToEnterText": "(en \"Agordoj->Por spertuloj->Enigu kodon\")", "googlePlayDescriptionText": "Inviti ludantojn al la ludantaro per Google Play:", "googlePlayInviteText": "Inviti", "googlePlayReInviteText": "Estas ${COUNT} ludanto(j) de Google Play en via ludantaro\nkiuj malkonektiĝos se vi komencos novan inviton.\nEnmetu ilin en la nova invito por rehavi ilin.", "googlePlaySeeInvitesText": "Vidi invitojn", "googlePlayText": "Google Play", + "googlePlayVersionOnlyText": "(versio de Android / Google Play)", "inDevelopmentWarningText": "Notu:\n\nReta ludado estas nova kaj ankoraŭ disvolvata.\nPor nun, estas rekomendate ke ĉiuj ludantoj\nestu en la sama sendrata reto.", + "internetText": "Interreto", + "inviteFriendsText": "Inviti amikojn", + "joinPublicPartyDescriptionText": "Aliĝi al publika ludantaro", "localNetworkDescriptionText": "Aliĝi al ludantaro en via reto:", "localNetworkText": "Loka reto", + "makePartyPrivateText": "Privatigi mian ludantaron", + "makePartyPublicText": "Publikigi mian ludantaron", "manualAddressText": "Adreso", "manualConnectText": "Konekti", "manualDescriptionText": "Aliĝi al ludantaro per adreso:", + "manualJoinSectionText": "Aliĝi per adreso", "manualJoinableFromInternetText": "Ĉu eblas aliĝi al vi de la interreto?:", "manualJoinableNoWithAsteriskText": "NE*", "manualJoinableYesText": "JES", @@ -625,12 +649,19 @@ "manualText": "Mane", "manualYourAddressFromInternetText": "Via adreso de la interreto:", "manualYourLocalAddressText": "Via loka adreso:", + "nearbyText": "Proksime", "noConnectionText": "", + "otherVersionsText": "(aliaj versioj)", "partyInviteAcceptText": "Akcepti", "partyInviteDeclineText": "Malakcepti", "partyInviteGooglePlayExtraText": "(vidu la paĝon 'Google Play' en la fenestro 'Kolektiĝi')", "partyInviteIgnoreText": "Ignori", "partyInviteText": "${NAME} invitis vin\npor aliĝi al la ludantaro!", + "partySizeText": "ludantaro grandeco", + "portText": "Pordo", + "privateText": "Privataj", + "publicText": "Publikaj", + "showMyAddressText": "Montri mian adreson", "titleText": "Kolektiĝi", "wifiDirectDescriptionBottomText": "Se ĉiuj aparatoj havas panelon 'Wi-Fi Direct', ili devus povi uzi tion por trovi\nkaj konektiĝi unu al la alia. Kiam ĉiuj aparatoj estas konektitaj, vi povas formi\nludantarojn ĉi tie per la paĝo 'Loka reto', same kiel kun normala Vifi-reto.\n\nPrefere la gastiganto 'Wi-Fi Direct' ankaŭ estu la ludantargastiganto de BombSquad.", "wifiDirectDescriptionTopText": "Wi-Fi Direct povas esti uzata por konekti Android-aparatojn rekte sen\nbezoni Vifi-reton. Tio plej bone funkcias per Android 4.2 aŭ pli nova.\n\nPor uzi ĝin, malfermu la Vifiajn agordojn kaj serĉu 'Wi-Fi Direct' en la menuo.", @@ -690,17 +721,17 @@ }, "helpWindow": { "bombInfoText": "- Bombo -\nPli forta ol batoj, sed povas\nefektivigi gravan sindifekton.\nPor plej bonaj rezultoj, ĵetu al\nmalamiko antaŭ ol la drato finiĝas.", - "canHelpText": "BombSquad povas helpi.", - "controllersInfoText": "Vi povas ludi BombSquad kun amikoj en reto, aŭ vi povas ĉiuj ludi\nen la sama aparato se vi havas sufiĉe da regiloj. BombSquad subtenas\nmultajn regilojn; vi eĉ povas uzi vian poŝtelefonon kiel regilon\nper la senpaga aplikaĵo 'BombSquad Remote'.\nVidu Agordoj->Regiloj por pliaj informoj.", + "canHelpText": "${APP_NAME} povas helpi.", + "controllersInfoText": "Vi povas ludi ${APP_NAME} kun amikoj en reto, aŭ vi povas\nĉiuj ludi en la sama aparato se vi havas sufiĉe da regiloj.\n${APP_NAME} subtenas multajn regilojn; vi eĉ povas uzi vian\npoŝtelefonon kiel regilon per la senpaga aplikaĵo '${REMOTE_APP_NAME}'.\nVidu Agordoj->Regiloj por pliaj informoj.", "controllersInfoTextFantasia": "Unu persono povas uzi la teleregilon kiel regilo, sed mi forte\nrekomendus uzi ludregtabulojn. Vi ankaŭ povas uzi viajn poŝ-\naparatojn per la senpaga aplikaĵo 'BombSquad Remote'.\nVidu 'Regiloj' sub 'Agordoj' por pliaj informoj.", "controllersInfoTextMac": "Unu aŭ du ludantoj povas uzi la klavaron, sed BombSquad plej bonas kun\nludregtabuloj. BombSquad povas uzi USB-ludregtabulojn, PS3-regilojn, regilojn\nde XBox 360, Wii-regilojn kaj iOS/Android-aparatojn por regi rolulojn. Espereble\nvi havas kelkajn tiajn disponeblaj. Vidu 'Regiloj' sub 'Agordoj' por pliaj informoj.", "controllersInfoTextOuya": "Vi povas uzi OUYA-regilon, PS3-regilojn, regilojn de XBox 360 kaj multajn\naliajn ludregtabulojn Bludentajn kaj USBajn ene de BombSquad.\nVi ankaŭ povas uzi iOS-aparatojn kaj Android por regi la ludon per la\nsenpaga aplikaĵo 'BombSquad Remote'. Vidu 'Regiloj' sub 'Agordoj' por\npliaj informoj.", "controllersText": "Regiloj", - "controlsSubtitleText": "Via amikema BombSquad-rolulo havas kelkajn bazajn agojn:", + "controlsSubtitleText": "Via amikema ${APP_NAME}-rolulo havas kelkajn bazajn agojn:", "controlsText": "Regumoj", - "devicesInfoText": "La VR-versio de BombSquad povas esti ludata en la reto kun la\nnormala versio, do ektrovu viajn aldonajn telefonojn, tabuletojn\nkaj komputilojn, kaj ekludu. Eĉ povas esti utile konekti normalan\nversion de la ludo al la VR-versio por permesi al homoj ekster vi\nkunvidi la agadon.", + "devicesInfoText": "La VR-versio de ${APP_NAME} povas esti ludata en la reto kun la\nnormala versio, do ektrovu viajn aldonajn telefonojn, tabuletojn\nkaj komputilojn, kaj ekludu. Eĉ povas esti utile konekti normalan\nversion de la ludo al la VR-versio por permesi al homoj ekster vi\nkunvidi la agadon.", "devicesText": "Aparatoj", - "friendsGoodText": "Bonas havi ilin. BombSquad plej amuzas kun pluraj ludantoj kaj\npovas subteni ĝis 8 samtempe, kio kondukas nin al:", + "friendsGoodText": "Bonas havi ilin. ${APP_NAME} plej amuzas kun pluraj ludantoj kaj\npovas subteni ĝis 8 samtempe, kio kondukas nin al:", "friendsText": "Amikoj", "jumpInfoText": "- Salti -\nSaltu por transiri truetojn,\npor ĵeti pli alten, kaj por\nesprimi ĝojsentojn.", "orPunchingSomethingText": "Aŭ bati ion, ĵeti ion de deklivo, kaj eksplodigi ĝin survoje malsupren per gluanta bombo.", @@ -728,9 +759,9 @@ "punchInfoText": "- Bato -\nBatoj pli damaĝas ju pli viaj\npugnoj moviĝas, do kuru kaj\nrotaciu kiel frenezulo.", "runInfoText": "- Kuri -\nPremadu AJNAN butonon por kuri. Flankbutonoj kaj pafkliko taŭgas se vi havas ilin.\nKurado helpas vin iri ien pli rapide, sed malpli facilas turni, do atentu deklivojn.", "someDaysText": "Fojfoje vi simple sentas emon bati ion. Aŭ eksplodigi ion.", - "titleText": "Helpo de BombSquad", + "titleText": "Helpo de ${APP_NAME}", "toGetTheMostText": "Por profiti plej de ĉi tiu ludo, necesos:", - "welcomeText": "Bonvenon al BombSquad!" + "welcomeText": "Bonvenon al ${APP_NAME}!" }, "holdAnyButtonText": "", "holdAnyKeyText": "", @@ -756,17 +787,20 @@ "corruptFileText": "Detektiĝis koruptaj dosieroj. Bonvolu provi reinstali, aŭ retpoŝtu ${EMAIL}", "errorPlayingMusicText": "Eraro ludante muzikon: ${MUSIC}", "errorResettingAchievementsText": "Ne eblas reigi enretajn atingojn; provu denove pli malfrue.", - "hasMenuControlText": "${NAME} nun regas la menuon.", + "hasMenuControlText": "${NAME} regas la menuon.", "incompatibleVersionHostText": "Gastiganto uzas alian version de la ludo.\nCertigu vin ke vi ambaŭ estu ĝisdataj kaj provu denove.", "incompatibleVersionPlayerText": "${NAME} uzas alian version de la ludo.\nCertigu vin ke vi ambaŭ estu ĝisdataj kaj provu denove.", "invalidAddressErrorText": "Eraro: nevalida adreso.", + "invalidNameErrorText": "Eraro: nevalida nomo.", + "invalidPortErrorText": "Eraro: nevalida pordo.", "invitationSentText": "Invito sendiĝis.", "invitationsSentText": "${COUNT} invitoj sendiĝis.", - "joinedPartyInstructionsText": "Amiko aliĝis al via ludantaro.\nIru al 'Ekludi' por komenci ludon.", + "joinedPartyInstructionsText": "Iu aliĝis al via ludantaro.\nIru al 'Ekludi' por komenci ludon.", "keyboardText": "Klavaro", "kickIdlePlayersKickedText": "${NAME} forpuŝiĝas pro neaktiveco.", "kickIdlePlayersWarning1Text": "${NAME} forpuŝiĝos post ${COUNT} sekundoj se ankoraŭ neaktiva.", "kickIdlePlayersWarning2Text": "(eblas malŝalti tion en Agordoj -> Por spertuloj)", + "leftGameText": "Forlasis '${NAME}'.", "leftPartyText": "Eliris el ludantaro de ${NAME}.", "noMusicFilesInFolderText": "Dosierujo ne enhavas muzikdosierojn.", "playerJoinedPartyText": "${NAME} aliĝis al la ludantaro!", @@ -822,9 +856,11 @@ "levelHighestScoresText": "Plej altaj poentoj en ${LEVEL}", "levelIsLockedText": "${LEVEL} estas ŝlosita.", "levelMustBeCompletedFirstText": "Unue necesas kompletigi ${LEVEL}.", + "levelText": "Nivelo ${NUMBER}", "levelUnlockedText": "Nivelo malŝlosita!", "livesBonusText": "Vivopremio", "loadingText": "ŝargas", + "macControllerSubsystemBothText": "Ambaŭ (ne rekomendita)", "mainMenu": { "creditsText": "Dankdiroj", "demoMenuText": "Montromenuo", @@ -846,6 +882,8 @@ "mapSelectText": "Elektu...", "mapSelectTitleText": "Mapoj de ${GAME}", "mapText": "Mapo", + "maxPartySizeText": "Maksimuma grandeco de ludantaro", + "maxPlayersText": "Maksimumaj ludantoj", "mostValuablePlayerText": "Plej valora ludanto", "mostViolatedPlayerText": "Plej perfortita ludanto", "mostViolentPlayerText": "Plej perforta ludanto", @@ -860,10 +898,12 @@ "nameScoresText": "${NAME} poentas!", "nameSuicideKidFriendlyText": "${NAME} ging per ongeluk dood", "nameSuicideText": "${NAME} mortigis sin.", + "nameText": "Nomo", "nativeText": "Propra", "newPersonalBestText": "Nova persona plejbono!", "newTestBuildAvailableText": "Nova testkonstruo haveblas! (${VERSION} konstruo ${BUILD}).\nEkhavu ĝin ĉe ${ADDRESS}", - "newVersionAvailableText": "Nova versio de BombSquad estas havebla! (${VERSION})", + "newText": "Nova", + "newVersionAvailableText": "Nova versio de ${APP_NAME} estas havebla! (${VERSION})", "nextLevelText": "Sekva nivelo", "noAchievementsRemainingText": "- neniom", "noContinuesText": "(sen pluiroj)", @@ -877,15 +917,18 @@ "notEnoughPlayersRemainingText": "Ne sufiĉe da ludantoj restas; eliri kaj komenci novan ludon.", "notEnoughPlayersText": "Vi bezonas almenaŭ ${COUNT} ludantojn por komenci ĉi tiun ludon!", "notNowText": "Ne nun", - "notSignedInErrorText": "Vi devas esti ensalutita en via konto por fari tion.", - "notSignedInText": "(ne ensalutita)", + "notSignedInErrorText": "Vi devas ensaluti por fari tion.", + "notSignedInGooglePlayErrorText": "Vi devas ensaluti per Google Play por fari tion.", + "notSignedInText": "ne ensalutita", "nothingIsSelectedErrorText": "Nenio elektiĝis!", "numberText": "#${NUMBER}", "offText": "Malŝaltite", "okText": "Bone", "onText": "Ŝaltite", + "oneMomentText": "Unu momenton...", "onslaughtRespawnText": "${PLAYER} reviviĝos en ondo ${WAVE}", "orText": "${A} aŭ ${B}", + "otherText": "Aliaj...", "outOfText": "(#${RANK} el ${ALL})", "ownFlagAtYourBaseWarning": "Via propra flago estu\nje via bazo por poenti!", "packageModsEnabledErrorText": "Reta ludado ne estas permesata dum lokaj pakaĵaj modifikaĵoj estas aktivaj (vidu Agordoj->Por spertuloj)", @@ -917,6 +960,7 @@ }, "playerCountAbbreviatedText": "${COUNT}lud", "playerDelayedJoinText": "${PLAYER} eniros komence de la sekva ludo.", + "playerInfoText": "Informoj pri ludanto", "playerLeftText": "${PLAYER} foriris de la ludo.", "playerLimitReachedText": "Ludanto-limo de ${COUNT} atingita; neniu plu aliĝu.", "playerLimitReachedUnlockProText": "Ĝisdatigu al \"${PRO}\" en la vendejo por ludi kun pli ol ${COUNT} ludantoj.", @@ -925,15 +969,18 @@ "deleteButtonText": "Forviŝi\nprofilon", "deleteConfirmText": "Ĉu forviŝi '${PROFILE}'?", "editButtonText": "Redakti\nprofilon", - "explanationText": "(krei adaptitajn nomojn k aperojn por ludantoj en ĉi tiu aparato)", + "explanationText": "(adaptitaj ludantnomoj kaj aperojn por ĉi tiu konto)", "newButtonText": "Nova\nprofilo", "titleText": "Ludanto-profiloj" }, "playerText": "Ludanto", "playlistNoValidGamesErrorText": "Ĉi tiu ludlisto ne enhavas validajn malŝlositajn ludojn.", "playlistNotFoundText": "ludlisto ne troviĝis", + "playlistText": "Ludlisto", "playlistsText": "Ludlistoj", - "pleaseRateText": "Se vi ŝatas BombSquad, bonvolu konsideri momenton\npor rankumi ĝin aŭ verki prijuĝon. Tio donos utilan\nretrokuplon kaj helpos subteni pluan disvolviĝon.\n\ndankon!\n-eric", + "pleaseRateText": "Se vi ŝatas ${APP_NAME}, bonvolu konsideri momenton\npor rankumi ĝin aŭ verki prijuĝon. Tio donos utilan\nretrokuplon kaj helpos subteni pluan disvolviĝon.\n\nDankon!\n- Eriko", + "pleaseWaitText": "Bonvolu atendi...", + "pluginsText": "Kromaĵoj", "pressAnyButtonPlayAgainText": "Premu ajnan butonon por reekludi...", "pressAnyButtonText": "Premu ajnan butonon por pluiri...", "pressAnyButtonToJoinText": "premu ajnan butonon por aliĝi...", @@ -951,12 +998,12 @@ "codeTextDescription": "Promocia kodo", "enterText": "Enigi" }, - "promoSubmitErrorText": "Eraro aplikante vian promocian kodon; kontrolu vian retkonekton", + "promoSubmitErrorText": "Eraro aplikante vian kodon; kontrolu vian retkonekton", "ps3ControllersWindow": { "macInstructionsText": "Malŝaltu la energion malantaŭe de via PS3, certigu ke Bludento\nestu aktiva en via Makintoŝo, tiam konektu vian regilon al via\nMakintoŝo per USB-kablo por parigi ilin. De tiam, vi povas uzi la\nhejmbutonon de la regilo por konekti ĝin kun via Makintoŝo ĉu\ndrate (USB) ĉu sendrate (Bludento).\n\nEn kelkaj Makintoŝo la sistemo povas peti vin enigi paskodon por\nparigi. Se tio okazas, jen la sekva klarigo aŭ guglu por helpo.\n\n\n\n\nPS3-regiloj konektitaj sendrate aperu en la aparatlisto en Sistem-\npreferoj->Bludento. Povas esti necese forigi ilin de tiu listo por\nuzi ilin denove kun via PS3.\n\nAnkaŭ certiĝu diskonekti ilin de Bludento kiam ne en uzo, alikaze\nmalŝparante la bateriojn.\n\nBludento povu trakti ĝis 7 konektitajn aparatojn, sed via sperto\npovus esti alia.", "ouyaInstructionsText": "Por uzi PS3-regilon kun via OUYA, simple konektu ĝin per USB-kablo unufoje\npor parigi ĝin. Farante tion viaj aliaj regiloj povas malŝaltiĝi, do tiam restartu\nvian OUYA kaj malligu la USB-kablon.\n\nDe tiam sufiĉu uzi la regilan hejmbutonon por konekti ĝin sendrate. Post kiam\nvi ludis, premu la HEJM-butonon dum 10 sekundoj por malŝalti la regilon; alie\nĝi povas resti ŝaltita, tiel malŝparante bateriojn.", "pairingTutorialText": "klariga video por parigi", - "titleText": "Uzi PS3-regilojn kun BombSquad:" + "titleText": "Uzi PS3-regilojn kun ${APP_NAME}:" }, "publicBetaText": "PUBLIKA BETA", "punchBoldText": "BATO", @@ -964,7 +1011,7 @@ "purchaseForText": "Aĉetu por ${PRICE}", "purchaseGameText": "Aĉeti ludon", "purchasingText": "Aĉetiĝas...", - "quitGameText": "Ĉu fermi BombSquad?", + "quitGameText": "Ĉu fermi ${APP_NAME}?", "quittingIn5SecondsText": "Fermos en 5 sekundoj...", "randomText": "Hazarde", "rankText": "Ranko", @@ -973,6 +1020,9 @@ "readyText": "preta", "recentText": "Lastatempaj", "remainingInTrialText": "restas en elprovo", + "remote_app": { + "start": "Komenci" + }, "removeInGameAdsText": "Malŝlosu \"${PRO}\" en la vendejo por forigi enludajn reklamojn.", "renameText": "Renomi", "replayEndText": "Fini remontron", @@ -1018,9 +1068,9 @@ "benchmarksText": "Kompartestoj kaj streĉtestoj", "enablePackageModsDescriptionText": "(ebligas aldonajn modifikajn kapablojn sed malebligas retludadon)", "enablePackageModsText": "Ebligi lokajn pakaĵajn modifikaĵojn", - "enterPromoCodeText": "Enigu promocian kodon", + "enterPromoCodeText": "Enigu kodon", "forTestingText": "Notu: ĉi tiuj valoroj estas nur por testado kaj perdiĝos je fermiĝo de la aplikaĵo.", - "helpTranslateText": "La neanglaj tradukoj de BombSquad nur eblas pro la komunumo.\nSe vi volas kontribui aŭ korekti tradukon, sekvu la suban\nligilon. Jam antaŭe dankon!", + "helpTranslateText": "La neanglaj tradukoj de ${APP_NAME} nur eblas pro\nla komunumo. Se vi volas kontribui aŭ korekti tradukon,\nsekvu la suban ligilon. Jam antaŭe dankon!", "kickIdlePlayersText": "Forpuŝi neaktivajn ludantojn", "kidFriendlyModeText": "Infanamika modo (malpli da perforto ktp)", "languageText": "Lingvo", @@ -1031,13 +1081,15 @@ "showPlayerNamesText": "Montri ludantonomojn", "showUserModsText": "Montri modifikaĵujon", "titleText": "Por spertuloj", - "translationEditorButtonText": "BombSquad traduko-redaktilo", + "translationEditorButtonText": "${APP_NAME} traduko-redaktilo", "translationFetchErrorText": "tradukstato ne haveblas", "translationFetchingStatusText": "kontrolante staton de traduko...", "translationNoUpdateNeededText": "la nuna lingvo estas ĝisdata, hura!", "translationUpdateNeededText": "** la nuna lingvo bezonas ĝisdatigojn!! **", "vrTestingText": "Testo de VR" }, + "shareText": "Kunhavigi", + "showText": "Montri", "signInWithGameCenterText": "Uzu la Ludcentran aplikaĵon por ensaluti.", "singleGamePlaylistNameText": "Nur ${GAME}", "singlePlayerCountText": "1 ludanto", @@ -1065,16 +1117,17 @@ "Victory": "Finpoenta ekrano" }, "spaceKeyText": "spaco", + "statsText": "Statistiko", "store": { "alreadyOwnText": "Vi jam posedas ${NAME}!", "bombSquadProDescriptionText": "Duobligos biletojn gajnitajn enlude\n\nForigos enludan reklamon\n\nInkluzivas ${COUNT} aldonajn biletojn\n\n+${PERCENT}% aldone en ligaj poentoj\n\nMalŝlosos nivelojn '${INF_ONSLAUGHT}'\n kaj '${INF_RUNAROUND}' (kunlaborajn)", "bombSquadProFeaturesText": "Avantaĝoj:", - "bombSquadProNameText": "BombSquad Pro", + "bombSquadProNameText": "${APP_NAME} Pro", "buyText": "Aĉeti", "charactersText": "Roluloj", "comingSoonText": "Baldaŭ...", "extrasText": "Aldonaĵoj", - "freeBombSquadProText": "BombSquad nun estas senpaga, sed ĉar vi origine aĉetis ĝin vi ricevas\nla ĝisdatigon BombSquad Pro kaj ${COUNT} biletojn kiel dankomontro.\nĜuu la novajn funkciojn, kaj dankon pro via subteno!\n-Eric", + "freeBombSquadProText": "BombSquad nun estas senpaga, sed ĉar vi origine aĉetis ĝin vi ricevas\nla ĝisdatigon BombSquad Pro kaj ${COUNT} biletojn kiel dankomontro.\nĜuu la novajn funkciojn, kaj dankon pro via subteno!\n- Eriko", "gameUpgradesText": "Ludaj ĝisdatigoj", "getCoinsText": "Ekhavi monerojn", "holidaySpecialText": "Feria specialaĵo", @@ -1094,6 +1147,7 @@ "saleText": "RABATE", "searchText": "Serĉi", "teamsFreeForAllGamesText": "Ludoj teamaj / Ĉiuj kune", + "upgradeQuestionText": "Ĉu ĝisdatigi?", "winterSpecialText": "Vintra specialaĵo", "youOwnThisText": "- jam havas tion -" }, @@ -1133,6 +1187,7 @@ "tournamentsText": "Turniroj", "translations": { "characterNames": { + "B-9000": "B-9000", "Bernard": "Bernardo", "Bones": "Ĝisostulo", "Santa Claus": "Sankta Nikolao" @@ -1234,7 +1289,10 @@ "Keyboard P2": "Klavaro Lud2" }, "languages": { - "Chinese": "Ĉina", + "Arabic": "Araba", + "Belarussian": "Belorusa", + "Chinese": "Ĉina simpligita", + "ChineseTraditional": "Ĉina tradicia", "Croatian": "Kroata", "Czech": "Ĉeĥa", "Danish": "Dana", @@ -1245,15 +1303,28 @@ "French": "Franca", "German": "Germana", "Gibberish": "Sensenca", + "Greek": "Greka", + "Hindi": "Hindia", "Hungarian": "Hungara", + "Indonesian": "Indonezia", "Italian": "Itala", "Japanese": "Japana", "Korean": "Korea", + "Persian": "Persa", "Polish": "Pola", "Portuguese": "Portugala", + "Romanian": "Rumana", "Russian": "Rusa", + "Serbian": "Serba", + "Slovak": "Slovaka", "Spanish": "Hispana", - "Swedish": "Sveda" + "Swedish": "Sveda", + "Tamil": "Tamila", + "Thai": "Tajlanda", + "Turkish": "Turka", + "Ukrainian": "Ukraina", + "Venetian": "Venecia", + "Vietnamese": "Vjetnama" }, "leagueNames": { "Bronze": "Bronza", @@ -1298,6 +1369,7 @@ "serverResponses": { "BombSquad Pro unlocked!": "BombSquad Pro malŝlosiĝis!", "Entering tournament...": "Enirante turniron...", + "Invalid code.": "Nevalida kodo.", "Invalid promo code.": "Nevalida promocia kodo.", "Invalid purchase.": "Nevalida aĉeto.", "Max number of playlists reached.": "Atingiĝis maksimumo da ludlistoj.", @@ -1308,6 +1380,7 @@ "This requires version ${VERSION} or newer.": "Ĉi tio petas version ${VERSION} aŭ pli nova.", "You already own this!": "Vi jam posedas ĉi tion!", "You don't have enough tickets for this!": "Vi ne havas sufiĉe da biletoj por ĉi tio!", + "You don't own that.": "Vi ne posedas tion.", "You got ${COUNT} tickets!": "Vi havas ${COUNT} biletojn!", "You got a ${ITEM}!": "Vi havas ${ITEM}!", "You have been promoted to a new league; congratulations!": "Vi promoviĝis al nova ligo; gratulojn!", @@ -1415,9 +1488,9 @@ "tutorial": { "cpuBenchmarkText": "Rapidege irante tra la klarigo (precipe por testi la rapidecon de CPU)", "phrase01Text": "Saluton!", - "phrase02Text": "Bonvenon al BombSquad!", + "phrase02Text": "Bonvenon al ${APP_NAME}!", "phrase03Text": "Jen kelkaj konsiloj por regi vian rolulon:", - "phrase04Text": "Multaj aferoj en BombSquad estas bazitaj je FIZIKO.", + "phrase04Text": "Multaj aferoj en ${APP_NAME} estas bazitaj je FIZIKO.", "phrase05Text": "Ekzemple, se vi batas,...", "phrase06Text": "...damaĝo estas bazita je la rapideco de viaj pugnoj.", "phrase07Text": "Ĉu vi vidis? Ni ne movis, do tio apenaŭ damaĝis al ${NAME}", @@ -1461,6 +1534,7 @@ "upFirstText": "Venos unue:", "upNextText": "Venos poste en ludo ${COUNT}:", "updatingAccountText": "Ĝisdatigante vian konton...", + "upgradeText": "Ĝisdatigi", "upgradeToPlayText": "Malŝlosu \"${PRO}\" en la enluda vendejo por ludi ĉi tion.", "useDefaultText": "Uzi ekvaloron", "usesExternalControllerText": "Ĉi tiu ludo uzas eksteran regilon por enigo.", @@ -1519,7 +1593,7 @@ "macInstructions2Text": "Por uzi regilojn sendrate, vi ankaŭ bezonos la ricevilon kiu\nvenas kun 'Xbox 360 Wireless Controller for Windows'.\nUnu ricevilo permesas konekti ĝis 4 regilojn.\n\nGrave: riceviloj de ekstera deveno ne funkcios kun ĉi tiu pelilo;\ncertigu vin ke la ricevilo diras 'Microsoft' kaj ne 'XBOX 360'.\nMicrosoft ne plu vendas ĉi tiujn dise, do vi bezonos ekhavi tiun\nkiu venas kune kun la regilo aŭ serĉi per vendaj retejoj kiel eBay.\n\nSe vi trovas ĉi tion utila, bonvolu konsideri mondonon al la pelila\nprogramisto per lia retejo.", "macInstructionsText": "Por uzi la regilojn Xbox 360, vi devas instali la pelilon\npor Makintoŝo havebla je la malsupra ligilo.\nĜi funkcias kaj por drataj kaj sendrataj regiloj.", "ouyaInstructionsText": "Por uzi dratajn regilojn de Xbox 360 kun BombSquad, simple\nkonektu ilin al la USB-eniro de via aparato. Vi povas uzi USB-nabon\npor konekti al pluraj regiloj.\n\nPor uzi sendratajn regilojn, ‎vi bezonas sendratan ricevilon,\nhaveblan kiel parto de la pakaĵo \"Xbox 360 wireless Controller\nfor Windows\" aŭ vendite dise. Ĉiu ricevilo eniras USB-pordon kaj\npermesas al vi konekti ĝis 4 sendratajn regilojn.", - "titleText": "Uzi regilojn de Xbox 360 kun BombSquad:" + "titleText": "Uzi regilojn de Xbox 360 kun ${APP_NAME}:" }, "yesAllowText": "Jes, permesu!", "yourBestScoresText": "Viaj plej bonaj poentoj", diff --git a/dist/ba_data/data/languages/filipino.json b/dist/ba_data/data/languages/filipino.json new file mode 100644 index 0000000..e85c851 --- /dev/null +++ b/dist/ba_data/data/languages/filipino.json @@ -0,0 +1,1860 @@ +{ + "accountSettingsWindow": { + "accountNameRules": "Marapat na ang pangalan ng account na iyon ay walang mga special characters o mga emoji", + "accountsText": "Mga account", + "achievementProgressText": "Mga Nakamtan: ${COUNT} sa ${TOTAL}", + "campaignProgressText": "Ang Progreso sa Laro [Mahirap]: ${PROGRESS}", + "changeOncePerSeason": "Mapapalit mo lang ito isa-isa kada season", + "changeOncePerSeasonError": "Kailangan mo muna maghintay ng susunod na season para mapalitan ito. (${NUM} araw)", + "customName": "Custom na Pangalan", + "linkAccountsEnterCodeText": "Ilagay ang Code", + "linkAccountsGenerateCodeText": "Gumawa ng Code", + "linkAccountsInfoText": "(ibahagi ang pag-usad sa iba't ibang platform)", + "linkAccountsInstructionsNewText": "Para maiugnay ang dalawang accounts, gumawa ka ng code sa una at ilagay \nyung code sa pangalawa. Data na galing sa pangalawang account ay \nmaibabahagi sa dalawa.\n(Data na nasa unang account ay mawawala)\n\nMaari kang magugnay ng hangang ${COUNT} accounts.\n\nIMPORTANTE: Iugnay lamang ang iyong mga accounts, \ndahil kapag iuugnay mo sa kaibigan mo ang iyong \naccount,hindi kayo makakapaglaro ng sabay.", + "linkAccountsInstructionsText": "Para mag-ugnay ng dalawang account, gumawa ng code\nsa isa at ilagay ang code na iyon sa kabila.\nAng iyong pag-usad at imbentaryo ay pagsasamahin.\nMaaari mong i-ugnay hanggang sa ${COUNT} accounts.\n\nBabala lang; hindi na ito maibabalik!", + "linkAccountsText": "Iugnay ang mga Account", + "linkedAccountsText": "Naka-ugnay na mga Account", + "nameChangeConfirm": "Baguhin ang pangalan ng iyong account sa ${NAME}?", + "resetProgressConfirmNoAchievementsText": "Ibabalik nito sa dati ang iyong pag-usad,\nat lokal na mga high-score (pwera sa ticket).\nHindi na ito maibabalik pa. Ipagpatuloy pa rin?", + "resetProgressConfirmText": "Ibabalik nito sa dati ang iyong pag-usad,\nmga nakamtan, at lokal na mga high-score\n(pwera sa ticket). Hindi na ito maibabalik\npa. Ipagpatuloy pa rin?", + "resetProgressText": "I-reset ang Progreso", + "setAccountName": "I-set ang Account name", + "setAccountNameDesc": "Piliin ang pangalan na ipapakita para sa iyong account.\nMaaari mong gamitin ang pangalan mula sa isa sa iyong mga naka-link \nna account o lumikha ng isang natatanging pasadyang pangalan.", + "signInInfoText": "Magsign-in para kumolekta ng mga ticket, makipagkompetensya online,\nat makabahagi ng pag-usad sa iba't ibang mga device.", + "signInText": "Mag-sign in", + "signInWithDeviceInfoText": "(isang automatic account na magagamit lamang sa device na ito)", + "signInWithDeviceText": "Mag-sign in gamit ang device", + "signInWithGameCircleText": "Magsign-in gamit ang Game Circle", + "signInWithGooglePlayText": "Magsign-in gamit ang Google Play", + "signInWithTestAccountInfoText": "(uri ng legacy account; gamitin ang mga account ng device na pasulong)", + "signInWithTestAccountText": "Magsign in gamit ang test account", + "signInWithV2InfoText": "(ang account na gumagana sa lahat na platforms)", + "signInWithV2Text": "Mag sign in gamit ang BombSquad account", + "signOutText": "Mag-sign out", + "signingInText": "Nagsasign-in...", + "signingOutText": "Nagsasign-out...", + "ticketsText": "Mga ticket: ${COUNT}", + "titleText": "Account", + "unlinkAccountsInstructionsText": "Pumili ng account na i-uunlink", + "unlinkAccountsText": "I-unlink ang mga accounts", + "v2LinkInstructionsText": "Gamitin ang link na ito para gumawa ng account o mag sign in.", + "viaAccount": "(sa pamamagitan ng account ${NAME})", + "youAreSignedInAsText": "Nakasign-in ka bilang:" + }, + "achievementChallengesText": "Mga nakamit", + "achievementText": "Mga Nakamtan", + "achievements": { + "Boom Goes the Dynamite": { + "description": "Mapasabog ang 3 kalaban gamit ang TNT", + "descriptionComplete": "Napasabog ang 3 kalaban gamit ang TNT", + "descriptionFull": "Mapasabog ang 3 kalaban gamit ang TNT sa ${LEVEL}", + "descriptionFullComplete": "Napasabog ang 3 kalabangamit ang TNT sa ${LEVEL}", + "name": "Sabog ang Sabi ng Dinamita" + }, + "Boxer": { + "description": "Manalo sa laro ng hindi gumagamit ng bomba", + "descriptionComplete": "Nanalo sa laro ng hindi gumagamit ng bomba", + "descriptionFull": "Tapusin ang ${LEVEL} na walang gamit na bomba", + "descriptionFullComplete": "Natapos ang ${LEVEL} na himdi gumagamit ng bomba", + "name": "Boksingero" + }, + "Dual Wielding": { + "descriptionFull": "Ikonekta ang 2 controllers (hardware o app)", + "descriptionFullComplete": "Konektado ang 2 controllers (hardware o app)", + "name": "Dalawang Nangalaro" + }, + "Flawless Victory": { + "description": "Manalo nang hindi natatamaan", + "descriptionComplete": "Nanalo nang hindi natamaan", + "descriptionFull": "Manalo sa ${LEVEL} nang hindi makakakuha ng hit", + "descriptionFullComplete": "Nanalo sa ${LEVEL} nang hindi nakakakuha ng hit", + "name": "‘Di Mintis Na Pagtagumpay" + }, + "Free Loader": { + "descriptionFull": "Magsimula ng isang Awayang Rambulan na may 2+ manlalaro", + "descriptionFullComplete": "Nagsimula ang isang Free-For-All na may 2+ manlalaro", + "name": "Manggagamit" + }, + "Gold Miner": { + "description": "Pumatay Ng 6 na kalaban gamit ang mga land-mine", + "descriptionComplete": "Pumatay ng 6 na kalaban gamit ang mga land-mine", + "descriptionFull": "Pumatay ng 6 na kalaban gamit ang mga land -mine sa ${LEVEL}", + "descriptionFullComplete": "Nakapatay ng 6 na kalaban gamit ang mga land-mine sa ${LEVEL}", + "name": "Minahang Lagayan" + }, + "Got the Moves": { + "description": "Manalo ng ‘di sumusuntok o gumagamit ng mga bomba", + "descriptionComplete": "Nanalo ng ‘di sumusuntok o gumagamit ng bomba", + "descriptionFull": "Manalo sa ${LEVEL} ng ‘di sumusuntok o gumagamit ng bomba", + "descriptionFullComplete": "Nanalo sa ${LEVEL} ng ‘di sumusuntok o gumagamit ng bomba", + "name": "May Galaw" + }, + "In Control": { + "descriptionFull": "Magconnect ng controller (hardware o app)", + "descriptionFullComplete": "Nagconnect ng controller (hardware o app)", + "name": "Kumokontrol" + }, + "Last Stand God": { + "description": "Maka-iskor ng 1000 na puntos", + "descriptionComplete": "Naka-iskor ng 1000 na puntos", + "descriptionFull": "Naka-iskor ng 1000 na puntos sa ${LEVEL}", + "descriptionFullComplete": "Naka-iskor ng 1000 na puntos sa ${LEVEL}", + "name": "Bathala ng ${LEVEL}" + }, + "Last Stand Master": { + "description": "Naka-iskor ng 250 na puntos", + "descriptionComplete": "Naka-iskor ng 250 na puntos", + "descriptionFull": "Maka-iskor ng 250 na puntos sa ${LEVEL}", + "descriptionFullComplete": "Naka-iskor ng 250 na puntos sa ${LEVEL}", + "name": "Pinuno ng ${LEVEL}" + }, + "Last Stand Wizard": { + "description": "Maka-iskor ng 500 na puntos", + "descriptionComplete": "Naka-iskor ng 500 na puntos", + "descriptionFull": "Maka-iskor ng 500 na puntos sa ${LEVEL}", + "descriptionFullComplete": "Naka-iskor ng 500 na puntos sa ${LEVEL}", + "name": "Salamangkero ng ${LEVEL}" + }, + "Mine Games": { + "description": "Pumatay ng 3 kalaban gamit ang land-mine", + "descriptionComplete": "Nakatay ng 3 kalaban gamit ang land-mine", + "descriptionFull": "Pumatay ng 3 kalaban gamit ang land-mine sa ${LEVEL}", + "descriptionFullComplete": "Nakapatay ng 3 kalaban gamit ang land-mine sa ${LEVEL}", + "name": "Laro ng mga mina" + }, + "Off You Go Then": { + "description": "Maghagis ng 3 kalaban palabas sa mapa", + "descriptionComplete": "Nakapaghagis ng 3 kalaban palabas ng mapa", + "descriptionFull": "Maghagis ng 3 kalaban palabas ng mapa sa ${LEVEL}", + "descriptionFullComplete": "Nakapaghagis ng 3 kalaban palabas ng mapa sa ${LEVEL}", + "name": "Lumayas Ka Dito" + }, + "Onslaught God": { + "description": "Maka-iskor ng 5000 na puntos", + "descriptionComplete": "Naka-iskor ng 5000 na puntos", + "descriptionFull": "Maka-iskor ng 5000 na puntos sa ${LEVEL}", + "descriptionFullComplete": "Naka-iskor ng 5000 na puntos sa ${LEVEL}", + "name": "Bathala ng ${LEVEL}" + }, + "Onslaught Master": { + "description": "Maka-iskor ng 500 na puntos", + "descriptionComplete": "Naka-iskor ng 500 na puntos", + "descriptionFull": "Maka-iskor ng 500 na puntos sa ${LEVEL}", + "descriptionFullComplete": "Naka-iskor ng 500 na puntos sa ${LEVEL}", + "name": "Pinuno ng ${LEVEL}" + }, + "Onslaught Training Victory": { + "description": "Talunin lahat ng kalaban", + "descriptionComplete": "Natalo lahat ng kalaban", + "descriptionFull": "Talunin lahat ng kalaban sa ${LEVEL}", + "descriptionFullComplete": "Natalo lahat ng kalaban sa ${LEVEL}", + "name": "Kampeon ng ${LEVEL}" + }, + "Onslaught Wizard": { + "description": "Maka-iskor ng 1000 na puntos", + "descriptionComplete": "Naka-iskor ng 1000 na puntos", + "descriptionFull": "Maka-iskor ng 1000 na puntos sa ${LEVEL}", + "descriptionFullComplete": "Naka-iskor ng 1000 na puntos sa ${LEVEL}", + "name": "Salamangkero ng ${LEVEL}" + }, + "Precision Bombing": { + "description": "Manalo ng walang kahit anong pampalakas", + "descriptionComplete": "Nanalo ng walang kahit anong powerups", + "descriptionFull": "Manalo sa ${LEVEL} ng walang kahit anong pampalakas", + "descriptionFullComplete": "Manalo sa ${LEVEL} ng walang kahit anong pampalakas", + "name": "Talas sa Pagpapasabog" + }, + "Pro Boxer": { + "description": "Manalo ng di gumagamit ng Bomba", + "descriptionComplete": "Nanalo ng di gumagamit ng bomba", + "descriptionFull": "Manalo sa ${LEVEL} ng di gumagamit ng bomba", + "descriptionFullComplete": "Nanalo sa ${LEVEL} ng gumagamit ng bomba", + "name": "Bihasang Boksingero" + }, + "Pro Football Shutout": { + "description": "Manalo ng walang puntos ang kalaban", + "descriptionComplete": "Nanalo ng walang puntos ang kalaban", + "descriptionFull": "Manalo sa ${LEVEL} ng walang puntos ang kalaban", + "descriptionFullComplete": "Nanalo sa ${LEVEL} ng walang puntos ang kalaban", + "name": "Buwaya sa ${LEVEL}" + }, + "Pro Football Victory": { + "description": "Panalunin ang laro", + "descriptionComplete": "Manalo sa laro", + "descriptionFull": "Manalo sa laro sa ${LEVEL}", + "descriptionFullComplete": "Nanalo sa laro sa ${LEVEL}", + "name": "Kampeon ng ${LEVEL}" + }, + "Pro Onslaught Victory": { + "description": "Matalo lahat ng mga kaway", + "descriptionComplete": "Natalo lahat ng mga kaway", + "descriptionFull": "Matalo lahat ng mga kaway sa ${LEVEL}", + "descriptionFullComplete": "Natalo lahat ng mga kaway sa ${LEVEL}", + "name": "Kampeon ng ${LEVEL}" + }, + "Pro Runaround Victory": { + "description": "Tapusin lahat ng mga kaway", + "descriptionComplete": "Natapos lahat ng mga kaway", + "descriptionFull": "Tapusin ang lahat ng mg kaway sa ${LEVEL}", + "descriptionFullComplete": "Tinapos lahat ng mga kaway sa ${LEVEL}", + "name": "Kampeon ng ${LEVEL}" + }, + "Rookie Football Shutout": { + "description": "Manalo nang hindi hinahayaang makapuntos ang kalaban", + "descriptionComplete": "Nanalo nang hindi hinahayaang makapuntos ang kalaban", + "descriptionFull": "Manalo sa ${LEVEL} nang hindi hinahayaang makapuntos ang kalaban", + "descriptionFullComplete": "Nanalo sa ${LEVEL} nang hindi hinahayaang makapuntos ang kalaban", + "name": "${LEVEL} Shutout" + }, + "Rookie Football Victory": { + "description": "Ipanalo ang laro", + "descriptionComplete": "Naipanalo ang laro", + "descriptionFull": "Panalunin ang laro sa ${LEVEL}", + "descriptionFullComplete": "Pinanalo ang laro sa ${LEVEL}", + "name": "${LEVEL} Panalo" + }, + "Rookie Onslaught Victory": { + "description": "Italo lahat ang mga kaway", + "descriptionComplete": "Natalo lahat ang mga kaway", + "descriptionFull": "Italo lahat ang mga kaway sa ${LEVEL}", + "descriptionFullComplete": "Natalo lahat ng mga kaway sa ${LEVEL}", + "name": "${LEVEL} Panalo" + }, + "Runaround God": { + "description": "Maka-iskor ng 2000 na Puntos", + "descriptionComplete": "Naka-iskor ng 2000 na puntos", + "descriptionFull": "Maka-iskor ng 2000 na puntos sa ${LEVEL}", + "descriptionFullComplete": "Naka-iskorng 2000 na puntos sa ${LEVEL}", + "name": "${LEVEL} Panginoon" + }, + "Runaround Master": { + "description": "Pumuntos ng 500", + "descriptionComplete": "Nakapuntos ng 500", + "descriptionFull": "Pumuntos ng 500 sa ${LEVEL}", + "descriptionFullComplete": "Nakakuha ng 500 puntos sa ${LEVEL}", + "name": "${LEVEL} Master" + }, + "Runaround Wizard": { + "description": "Pumuntos ng 1000", + "descriptionComplete": "Naka score ng 1000 points", + "descriptionFull": "Mag score ng 1000 points sa ${LEVEL}", + "descriptionFullComplete": "Naka score ng 1000 points sa ${LEVEL}", + "name": "${LEVEL} Wizard" + }, + "Sharing is Caring": { + "descriptionFull": "I-share ang game sa iyong kaibigan", + "descriptionFullComplete": "Natapos na ang pag share sa game sa iyong kaibigan", + "name": "Ang pagbigay ay pag-alaga" + }, + "Stayin' Alive": { + "description": "Manalo nang hindi namamatay", + "descriptionComplete": "Nanalo nang hindi namatay", + "descriptionFull": "Nanalo ${LEVEL} nang hindi namatay", + "descriptionFullComplete": "Nanalo ${LEVEL} nang hindi namatay", + "name": "Manatiling Buhay" + }, + "Super Mega Punch": { + "description": "Magdulot ng 100% damage sa isang suntok", + "descriptionComplete": "Nagdulot ng 100% damage sa isang suntok", + "descriptionFull": "Magdulot ng 100% damage ng isang suntok sa ${LEVEL}", + "descriptionFullComplete": "Nagdulot ng 100% damage sa isang suntok sa ${LEVEL}", + "name": "Sobrang Mega Na Suntok" + }, + "Super Punch": { + "description": "Magdulot ng 50% damage sa isang suntok", + "descriptionComplete": "Nagdulot ng 50% damage sa isang suntok", + "descriptionFull": "Magdulot ng 50% damage sa isang suntok sa ${LEVEL}", + "descriptionFullComplete": "Nagdulot ng 50% damage sa isang suntok sa ${LEVEL}", + "name": "Sobrang Suntok" + }, + "TNT Terror": { + "description": "Pumatay ng 6 na kalaban gamit ang TNT", + "descriptionComplete": "Pinatay ng 6 na kalaban gamit ang TNT", + "descriptionFull": "Pumatay ng 6 na kalaban gamit ang TNT sa ${LEVEL}", + "descriptionFullComplete": "Pinatay ng 6 na kalaban gamit ang TNT sa ${LEVEL}", + "name": "Takutan ng TNT" + }, + "Team Player": { + "descriptionFull": "Magsimula ng laro na mayroong 4+ na manlalaro", + "descriptionFullComplete": "Nagsimula ng laro na mayroong 4+ na manlalaro", + "name": "Manlalaro Ng Koponan" + }, + "The Great Wall": { + "description": "Itigil ang bawat kalaban", + "descriptionComplete": "Pinigilan ang bawat kalaban", + "descriptionFull": "Itigil ang bawat kalaban sa ${LEVEL}", + "descriptionFullComplete": "Pinigilan ang bawat kalaban sa ${LEVEL}", + "name": "Ang Malaking Pader" + }, + "The Wall": { + "description": "Itigil ang bawat kalaban", + "descriptionComplete": "Pinigilan ang bawat kalaban", + "descriptionFull": "Itigil ang bawat kalaban sa ${LEVEL}", + "descriptionFullComplete": "Pinigilan ang bawat kalaban sa ${LEVEL}", + "name": "Ang Pader" + }, + "Uber Football Shutout": { + "description": "Manalo nang hindi maka puntos ang mga kalaban", + "descriptionComplete": "Manalo nang hindi maka puntos ang mga kalaban", + "descriptionFull": "Manalo sa ${LEVEL} na hindi maka puntos ang mga kalaban", + "descriptionFullComplete": "Manalo sa ${LEVEL} na hindi maka puntos ang mga kalaban", + "name": "${LEVEL} Pagsarhan" + }, + "Uber Football Victory": { + "description": "Ipanalo ang laro", + "descriptionComplete": "Nanalo ang laro", + "descriptionFull": "I-panalo ang laro sa ${LEVEL}", + "descriptionFullComplete": "Manalo ang laro sa ${LEVEL}", + "name": "${LEVEL} Natagumpay" + }, + "Uber Onslaught Victory": { + "description": "Talunin ang lahat na mga kaway", + "descriptionComplete": "Natalo ang lahat na mga kaway", + "descriptionFull": "Talunin ang lahat na mga kaway sa ${LEVEL}", + "descriptionFullComplete": "Natalo ang lahat na mga kaway sa ${LEVEL}", + "name": "${LEVEL} Panalo" + }, + "Uber Runaround Victory": { + "description": "Tapusin ang lahat na kaway", + "descriptionComplete": "Natapos ang lahat na mga kaway", + "descriptionFull": "Tapusin ang lahat na mga kaway sa ${LEVEL}", + "descriptionFullComplete": "Natapos ang lahat na mga kaway sa ${LEVEL}", + "name": "${LEVEL} Natagumpay" + } + }, + "achievementsRemainingText": "Ang Mga Natitirang Nakamtan:", + "achievementsText": "Achievements", + "achievementsUnavailableForOldSeasonsText": "Pasensya na, hindi available ang mga detalye ng achievements para sa mga lumang seasons.", + "addGameWindow": { + "getMoreGamesText": "Kukuha ng higit pang mga laro…", + "titleText": "Magdagdag Ng Laro" + }, + "allowText": "Payagan", + "alreadySignedInText": "Ang iyong account ay naka-sign in mula sa isa pang device;\nMangyaring lumipat ng mga accounts o isara ang laro sa iyong\niba pang mga device at subukan muli.", + "apiVersionErrorText": "Hindi ma-load ang module ${NAME}; naka-target ang api-version ${VERSION_USED}; kailangan namin ${VERSION_REQUIRED}", + "audioSettingsWindow": { + "headRelativeVRAudioInfoText": "(Lalabas ang “Auto” ng ito kapag nakasaksak ang headphones)", + "headRelativeVRAudioText": "Head-Relative VR Audio", + "musicVolumeText": "Volume ng Musika", + "soundVolumeText": "Lakas ng Tunog", + "soundtrackButtonText": "Mga Soundtrack", + "soundtrackDescriptionText": "(I-assign ang iyong sariling musika para magtugtug kapag naglalaro)", + "titleText": "Audio" + }, + "autoText": "Auto", + "backText": "Bumalik", + "banThisPlayerText": "I-ban ang Manlalarong Ito", + "bestOfFinalText": "Pinakamahusay-sa-${COUNT} Final", + "bestOfSeriesText": "Pinakamahusay sa ${COUNT} series:", + "bestOfUseFirstToInstead": 0, + "bestRankText": "Ang iyong pinakamahusay ay #${RANK}", + "bestRatingText": "Ang iyong pinakamahusay na rating ay ${RATING}", + "bombBoldText": "BOMBA", + "bombText": "Bomba", + "boostText": "Palakasin", + "bsRemoteConfigureInAppText": "${REMOTE_APP_NAME} naka-configure ito sa mismong app.", + "buttonText": "pindutan", + "canWeDebugText": "Gusto mo ba na ang BombSquad ay automatic na mag report ng\nbugs, crashes, at mga basic usage na info na i-sent sa developer?\n\nHindi ito naglalaman ng mga personal information at makatulong ito\npara ang laro ay gumagana at bug-free.", + "cancelText": "Kanselahin", + "cantConfigureDeviceText": "Pasensya na, ang ${DEVICE} ay hindi ma-configure.", + "challengeEndedText": "Natapos na ang challenge na ito.", + "chatMuteText": "I-mute ang Chat", + "chatMutedText": "Chat Muted", + "chatUnMuteText": "I-unmute ang Chat", + "choosingPlayerText": "", + "completeThisLevelToProceedText": "I complete mo muna\nang level na ito bago ka mag-proceed!", + "completionBonusText": "Bonus sa Pagkumpleto nito:", + "configControllersWindow": { + "configureControllersText": "I-configure ang mga Controller", + "configureKeyboard2Text": "I-configure ang Keyboard sa P2", + "configureKeyboardText": "I-configure ang Keyboard", + "configureMobileText": "Mobile Devices bilang Controllers", + "configureTouchText": "I-configure ang Touchscreen", + "ps3Text": "PS3 Controllers", + "titleText": "Mga Controller", + "wiimotesText": "Wiimotes", + "xbox360Text": "Xbox 360 Controllers" + }, + "configGamepadSelectWindow": { + "androidNoteText": "Tandaan: nag-iiba-iba ang suporta sa controller sa mga devices at bersyon ng Andriod.", + "pressAnyButtonText": "Pindutin ang anumang button sa controller\nna gusto mong i-configure…", + "titleText": "I-configure ang mga Controller" + }, + "configGamepadWindow": { + "advancedText": "Advanced", + "advancedTitleText": "Advanced na Setup ng Controller", + "analogStickDeadZoneDescriptionText": "(itaas ito kapag ang iyong karakter ay nag ‘d-drift’ kapag binitawan mo ang stick)", + "analogStickDeadZoneText": "Analog Stick Dead Zone", + "appliesToAllText": "(nalalapat sa lahat ng controller ng ganitong uri)", + "autoRecalibrateDescriptionText": "(paganahin ito kung ang iyong karakter ay hindi gumagalaw ng buong bilis)", + "autoRecalibrateText": "Auto-Recalibrate Analog Stick", + "axisText": "aksis", + "clearText": "alisin", + "dpadText": "dpad", + "extraStartButtonText": "Extra na Start Button", + "ifNothingHappensTryAnalogText": "Kapag walang gumagana, i-try na i-assign sa analog stick.", + "ifNothingHappensTryDpadText": "Kapag hindi gumana, i-try na i-assign sa d-pad.", + "ignoreCompletelyDescriptionText": "(pigilan ang controller na ito na maapektuhan ang alinman sa laro o mga menu)", + "ignoreCompletelyText": "Huwag Pansinin", + "ignoredButton1Text": "Pindutan Na ‘Di Pansinin 1", + "ignoredButton2Text": "Pindutan Na ‘Di Pansinin 2", + "ignoredButton3Text": "Pindutan Na ‘Di Pansinin 3", + "ignoredButton4Text": "Pindutan Na ‘Di Pansinin 4", + "ignoredButtonDescriptionText": "(gamitin ito para ma-prevent ang ‘home’ o ‘sync’ buttons na nakakaapekto sa UI)", + "pressAnyAnalogTriggerText": "Pindutin ang anumang analog trigger…", + "pressAnyButtonOrDpadText": "Pindutin ang anumang pindutan o dpad…", + "pressAnyButtonText": "Pindutin ang anumang pindutan…", + "pressLeftRightText": "Pindutin ang left o right…", + "pressUpDownText": "Pindutin ang up o down…", + "runButton1Text": "Run Button 1", + "runButton2Text": "Run Button 2", + "runTrigger1Text": "Run Trigger 1", + "runTrigger2Text": "Run Trigger 2", + "runTriggerDescriptionText": "(ang analog triggers ay pwede ka makatakbo sa mabilisang speeds)", + "secondHalfText": "Gamitin ito para i-configure ang pangalawang kalahati \nng 2-controllers-sa-1 device na \nnagpapakita ng iisang controller.", + "secondaryEnableText": "Paganahin", + "secondaryText": "Pangalawang Controller", + "startButtonActivatesDefaultDescriptionText": "(i-off ito kung ang iyong start button ay higit pa sa isang ‘menu’ button)", + "startButtonActivatesDefaultText": "Start Button Activates Defualt Widget", + "titleText": "Setup ng Controller", + "twoInOneSetupText": "2-in-1 na Setup ng Controller", + "uiOnlyDescriptionText": "(pigilan ang controller na ito mula sa aktwal na pagsali sa isang laro)", + "uiOnlyText": "I-limit ito para lang sa Menu Use", + "unassignedButtonsRunText": "Tumatakbo ang Lahat ng Hindi Nakatalagang Pindutan", + "unsetText": "", + "vrReorientButtonText": "VR Reorient Button" + }, + "configKeyboardWindow": { + "configuringText": "Nag-configure ${DEVICE}", + "keyboard2NoteText": "Tandaan: karamihan sa mga keyboard ay maaari lamang magrehistro ng ilang mga keypress sa\nminsan, kaya ang pagkakaroon ng pangalawang keyboard player ay maaaring gumana nang mas mahusay\nkung may nakadikit na hiwalay na keyboard para magamit nila.\nTandaan na kakailanganin mo pa ring magtalaga ng mga natatanging key sa\ndalawang manlalaro kahit na sa kasong iyon." + }, + "configTouchscreenWindow": { + "actionControlScaleText": "Aksyon Control Scale", + "actionsText": "Mga aksyon", + "buttonsText": "buttons", + "dragControlsText": "< i-drag ang mga kontrol upang muling iposisyon ang mga ito >", + "joystickText": "joystick", + "movementControlScaleText": "Sukat ng Kontrol ng Paggalaw", + "movementText": "Paggalaw", + "resetText": "I-reset", + "swipeControlsHiddenText": "Itago ang mga Swipe Icon", + "swipeInfoText": "Ang mga kontrol sa pag-swipe ay medyo nasanay ngunit\ngawing mas madali ang paglalaro nang hindi tumitingin sa mga kontrol.", + "swipeText": "mag-swipe", + "titleText": "I-configure ang Touchscreen" + }, + "configureItNowText": "I-configure ngayon?", + "configureText": "Configure", + "connectMobileDevicesWindow": { + "amazonText": "Amazon Appstore", + "appStoreText": "App Store", + "bestResultsText": "Para sa pinakamahusay na mga resulta, kakailanganin mo ng isang lag-free na wifi network. Kaya mo\nbawasan ang wifi lag sa pamamagitan ng pag-off ng iba pang mga wireless na device, sa pamamagitan ng\nnaglalaro malapit sa iyong wifi router, at sa pamamagitan ng pagkonekta sa\ndirektang host ng laro sa network sa pamamagitan ng ethernet.", + "explanationText": "Para gumamit ng smart-phone o tablet bilang wireless controller,\ni-install ang \"${REMOTE_APP_NAME}\" na app dito. Anumang bilang ng mga device\nmaaaring kumonekta sa isang larong ${APP_NAME} sa Wi-Fi, at libre ito!", + "forAndroidText": "para sa Andriod:", + "forIOSText": "para sa iOS:", + "getItForText": "Kumuha ng ${REMOTE_APP_NAME} para sa iOS sa Apple App Store\no para sa Android sa Google Play Store o Amazon Appstore", + "googlePlayText": "Google Play", + "titleText": "Paggamit ng Mga Mobile Device bilang Mga Controller:" + }, + "continuePurchaseText": "Magpatuloy sa halagang ${PRICE}?", + "continueText": "Magpatuloy", + "controlsText": "Mga Kontrol", + "coopSelectWindow": { + "activenessAllTimeInfoText": "Hindi ito nag a-apply sa all-time rankings.", + "activenessInfoText": "Ang multiplier na ito ay tumataas sa mga araw kung kailan ka\nmaglaro at bumaba sa mga araw na hindi mo ginagawa.", + "activityText": "Aktibidad", + "campaignText": "Kampanya", + "challengesInfoText": "Makakuha ng mga premyo para sa pagkumpleto ng mga mini-game.\n\nAng mga premyo at antas ng kahirapan ay tumataas\nsa bawat oras na ang isang hamon ay nakumpleto at\nbumaba kapag ang isa ay nag-expire o na-forfeit.", + "challengesText": "Mga Challenges", + "currentBestText": "Kasalukuyang Pinakamahusay", + "customText": "Kustom", + "entryFeeText": "Pasok", + "forfeitConfirmText": "Isuko ang hamon na ito?", + "forfeitNotAllowedYetText": "Ang hamon na ito ay hindi pa maaaring mawala.", + "forfeitText": "Forfeit", + "multipliersText": "Mga multiplier", + "nextChallengeText": "Susunod na Challenge", + "nextPlayText": "Susunod na Play", + "ofTotalTimeText": "ng ${TOTAL}", + "playNowText": "Maglaro Ngayon", + "pointsText": "Puntos", + "powerRankingFinishedSeasonUnrankedText": "(tapos na season walang ranggo", + "powerRankingNotInTopText": "(hindi sa taas ${NUMBER})", + "powerRankingPointsEqualsText": "= ${NUMBER} pts", + "powerRankingPointsMultText": "(x ${NUMBER} pts)", + "powerRankingPointsText": "${NUMBER} pts", + "powerRankingPointsToRankedText": "(${CURRENT} sa ${REMAINING} pts)", + "powerRankingText": "Kakayahang Ranggo", + "prizesText": "Premyo", + "proMultInfoText": "Ang manlalaro na may ${PRO} pagtaas\nay tumanggap na ${PERCENT}% dagdag puntos dito.", + "seeMoreText": "Tingnan pa...", + "skipWaitText": "Lagktawang Paghintay", + "timeRemainingText": "Natitirang Oras", + "toRankedText": "Sagad Sa Ranggo", + "totalText": "kabuuan", + "tournamentInfoText": "Makipagkumpitensya para sa matataas na marka sa\nibang mga manlalaro sa iyong liga.\n\nAng mga premyo ay iginagawad sa pinakamataas na iskor\nmga manlalaro kapag nag-expire ang oras ng tournament.", + "welcome1Text": "Maligayang pagdating sa ${LEAGUE}. Maaari mong pagbutihin ang iyong\nranggo ng liga sa pamamagitan ng pagkamit ng mga star rating, pagkumpleto\nmga tagumpay, at panalong tropeo sa mga paligsahan.", + "welcome2Text": "Maaari ka ring makakuha ng mga tiket mula sa marami sa parehong mga aktibidad.\nMaaaring gamitin ang mga tiket para i-unlock ang mga bagong character, mapa, at\nmini-games, para makapasok sa mga tournament, at higit pa.", + "yourPowerRankingText": "Iyong Power Ranking:" + }, + "copyOfText": "Kopya ng ${NAME}", + "copyText": "I-kopya", + "createEditPlayerText": "", + "createText": "Gumawa", + "creditsWindow": { + "additionalAudioArtIdeasText": "Adisyonal Audio, Agang Artwork, Ideya ni ${NAME}", + "additionalMusicFromText": "Adisyonal musika galing kay ${NAME}", + "allMyFamilyText": "Lahat sa aking kaibigan at pamilya ko na tumulong sa play test", + "codingGraphicsAudioText": "Coding, Graphics, at Audio ni ${NAME}", + "languageTranslationsText": "Pagsasalin Ng Wika:", + "legalText": "Ligal:", + "publicDomainMusicViaText": "Public-domain music mula sa ${NAME}", + "softwareBasedOnText": "Ang software na ito ay batay sa bahagi ng gawain ng ${NAME}", + "songCreditText": "${TITLE} Ginawa ni ${PERFORMER}\nBinubuo ni ${COMPOSER}, Inayos ni ${ARRANGER}, Na-publish ni ${PUBLISHER},\nSa kagandahang-loob ng ${SOURCE}", + "soundAndMusicText": "Tunog at Musika", + "soundsText": "Mga Tunog (${SOURCE}):", + "specialThanksText": "Espesyal Na Pasasalamat:", + "thanksEspeciallyToText": "Salamat, lalo na kay ${NAME}", + "titleText": "${APP_NAME} Mga Kredito", + "whoeverInventedCoffeeText": "Kung sino man nag-imbento ng kape" + }, + "currentStandingText": "Ang kasalukuyang tayo mo ay #${RANK}", + "customizeText": "I-customize...", + "deathsTallyText": "${COUNT} pagkamatay", + "deathsText": "Pagkamatay", + "debugText": "debug", + "debugWindow": { + "reloadBenchmarkBestResultsText": "Pakiusap: pwedeng inirerekomenda na itakda mo ang Settings->Graphics->Texture sa 'Mataas' habang isinusuri nito", + "runCPUBenchmarkText": "I-takbo ang CPU Benchmark", + "runGPUBenchmarkText": "I-takbo ang GPU Benchmark", + "runMediaReloadBenchmarkText": "I-takbo ang Media-Reload Benchmark", + "runStressTestText": "I-takbo ang stress test", + "stressTestPlayerCountText": "Bilang Ng Manlalaro", + "stressTestPlaylistDescriptionText": "Stress Test Playlist", + "stressTestPlaylistNameText": "Pangalan Ng Playlist", + "stressTestPlaylistTypeText": "Playlist Type", + "stressTestRoundDurationText": "Pagtagal Ng Round", + "stressTestTitleText": "Stress Test", + "titleText": "Benchmarks at Stress Test", + "totalReloadTimeText": "Kabuuang reload time: ${TIME} (tingnan Ang log para sa mga detalye)" + }, + "defaultGameListNameText": "Default ${PLAYMODE} Playlist", + "defaultNewGameListNameText": "Ang aking ${PLAYMODE} Playlist", + "deleteText": "Tanggalin", + "demoText": "Demo", + "denyText": "Tanggihan", + "desktopResText": "Desktop Res", + "difficultyEasyText": "Madali", + "difficultyHardOnlyText": "Mahirap Na Mode Lang", + "difficultyHardText": "Mahirap", + "difficultyHardUnlockOnlyText": "Itong level na ito ay naka-unlock sa Mahirap na mode lang.\nSa tingin mo ba mayroong ano ang kinakailangan!?!?!", + "directBrowserToURLText": "Mangyaring idirekta Ang isang web-browser sa sumusunod na URL:", + "disableRemoteAppConnectionsText": "I-disable Ang Mga Remote-App Na Konekyson", + "disableXInputDescriptionText": "Pumayag ng higit sa 4 na controllers ngunit maaaring hindi mabuti ang kalagay", + "disableXInputText": "Disable XInput", + "doneText": "Tapos", + "drawText": "Patas", + "duplicateText": "I-duplicate", + "editGameListWindow": { + "addGameText": "Idagdag na\nLaro", + "cantOverwriteDefaultText": "Hindi ma-overwrite ang default playlist!", + "cantSaveAlreadyExistsText": "Isang playlist na may ganyang pangalan na!", + "cantSaveEmptyListText": "Hindi ma-save ang walang laman na playlist!", + "editGameText": "I-Edit ang\nLaro", + "listNameText": "Pangalan Ng Playlist", + "nameText": "Pangalan", + "removeGameText": "Tanggalin ang\nLaro", + "saveText": "I-save Ang Listahan", + "titleText": "Editor Ng Playlist" + }, + "editProfileWindow": { + "accountProfileInfoText": "Itong espesyal na profile ay may\npangalan at icon batay sa iyong account.\n\n${ICONS}\n\nGumawa ng custom na profile para gamitin ng \nmagkaibang pangalan o custom icons.", + "accountProfileText": "(account profile)", + "availableText": "Ang pangalang \"${NAME}” na ito ay maari mong gamitin pang-icon", + "characterText": "karakter", + "checkingAvailabilityText": "Titignan ko kung maaari mo gamitin ang \"${NAME}\"...", + "colorText": "kulay", + "getMoreCharactersText": "Kumuha Ka Pang Mga Karakter...", + "getMoreIconsText": "Kumuha Ka Pang Mga Icons...", + "globalProfileInfoText": "Golbal player profiles ay garantisadong magkaroon ng unique na pangalan worldwide.\nNa-include nila rin ang custom icons.", + "globalProfileText": "(global na profile)", + "highlightText": "highlight", + "iconText": "Mga icon", + "localProfileInfoText": "Ang mga profile Ng lokal na manlalaro ay walang mga icon at ang kanilang mga \npangalan ay hindi garantisadong unique. I-upgrade para maging isang global \nprofile at ma-reserve ng isang unique na pangalan at ma-add ng custom icon.", + "localProfileText": "(lokal na profile)", + "nameDescriptionText": "Pangalan Ng Manlalaro", + "nameText": "Pangalan", + "randomText": "random", + "titleEditText": "I-Edit Ang Profile", + "titleNewText": "Bagong Profile", + "unavailableText": "hindi available ang \"${NAME}\"; sumubok ng ibang pangalan", + "upgradeProfileInfoText": "Irereserba nito ang pangalan ng iyong manlalaro sa buong mundo\nat nagbibigay-daan sa iyong magtalaga ng custom na icon dito.", + "upgradeToGlobalProfileText": "Upgrade sa Global na Profile" + }, + "editSoundtrackWindow": { + "cantDeleteDefaultText": "Hindi mo maitanggal Ang default soundtrack", + "cantEditDefaultText": "Hindi ma-edit ang default soundtrack. I-duplicate mo o gumawa Ng bago", + "cantOverwriteDefaultText": "Hindi ma-overwrite ang default soundtrack", + "cantSaveAlreadyExistsText": "Isang soundtrack na may ganyang pangalan na!", + "defaultGameMusicText": "", + "defaultSoundtrackNameText": "Default na Soundtrack", + "deleteConfirmText": "Itanggal Ang Soundtrack:\n\n'${NAME}'?", + "deleteText": "I-delete Ang\nSoundtrack", + "duplicateText": "I-duplicate Ang\nSoundtrack", + "editSoundtrackText": "Editor Ng Soundtrack", + "editText": "I-edit Ang\nSoundtrack", + "fetchingITunesText": "kumuha ng Music App playlists...", + "musicVolumeZeroWarning": "Paunawa: Ang volume ng musika ay nakatakda sa 0", + "nameText": "Pangalan", + "newSoundtrackNameText": "Ang Aking Soundtrack ${COUNT}", + "newSoundtrackText": "Bagong Soundtrack:", + "newText": "Bagong \nSoundtrack", + "selectAPlaylistText": "Pumili Ng Playlist", + "selectASourceText": "Music Source", + "testText": "test", + "titleText": "Soundtracks", + "useDefaultGameMusicText": "Default na Laro ng Musika", + "useITunesPlaylistText": "Music App Playlist", + "useMusicFileText": "File Ng Musika (mp3, etc)", + "useMusicFolderText": "Folder Ng Mga File Ng Musika" + }, + "editText": "I-edit", + "endText": "Itigil", + "enjoyText": "Ikasiya!", + "epicDescriptionFilterText": "${DESCRIPTION} sa isang epic na slow motion.", + "epicNameFilterText": "Epikong ${NAME}", + "errorAccessDeniedText": "walang pahintulot", + "errorOutOfDiskSpaceText": "Wala sa puwang ng disk", + "errorText": "Error", + "errorUnknownText": "hindi batid na error", + "exitGameText": "Exit mula sa ${APP_NAME}?", + "exportSuccessText": "Na-export ang '${NAME}'.", + "externalStorageText": "External na Storage", + "failText": "Bigo", + "fatalErrorText": "Uh oh; may kulang o sira.\nPakisubukang muling i-install ang app o\nmakipag-ugnayan kay ${EMAIL} para sa tulong.", + "fileSelectorWindow": { + "titleFileFolderText": "Pumili ng File o Folder", + "titleFileText": "Pumili ng File", + "titleFolderText": "Pumili ng Folder", + "useThisFolderButtonText": "Gamitin Ang Folder Na Ito" + }, + "filterText": "Salain", + "finalScoreText": "Huling Marka", + "finalScoresText": "Huling Mga Marka", + "finalTimeText": "Huling Oras", + "finishingInstallText": "Pagtatapos ng pag-install; sandali lang...", + "fireTVRemoteWarningText": "* Para sa isang mas mahusay na karanasan, gamitin\nGame Controllers o i-install ang\n'${REMOTE_APP_NAME}' app sa iyong\nmga telepono at tablet.", + "firstToFinalText": "Una-sa-${COUNT} Wakas", + "firstToSeriesText": "Una-sa-${COUNT} Panunuran", + "fiveKillText": "LIMANG PAGPATAY!!!", + "flawlessWaveText": "Walang Kapintasan na Kaway!", + "fourKillText": "APAT NA PAGPATAY!!!", + "friendScoresUnavailableText": "Hindi available ang marka ng kaibigan", + "gameCenterText": "GameCenter", + "gameCircleText": "GameCircle", + "gameLeadersText": "Mga Pinuno Ng Pang-${COUNT} na Laro", + "gameListWindow": { + "cantDeleteDefaultText": "Hindi pwedeng itanggal ang default na playlist.", + "cantEditDefaultText": "Hindi ma-edit ang default playlist! I-duplicate mo o gumawa ng bago.", + "cantShareDefaultText": "Hindi pwede ma-share ang default na playlist.", + "deleteConfirmText": "Tanggalin ang \"${LIST}\"?", + "deleteText": "Tanggalin ang\nPlaylist", + "duplicateText": "I-duplicate ang\nPlaylist", + "editText": "I-edit ang\nPlaylist", + "newText": "Gumawa ng\nPlaylist", + "showTutorialText": "Ipakita Ang Tutorial", + "shuffleGameOrderText": "I-shuffle Ang Kaayusan Ng Laro", + "titleText": "I-customize Ang ${TYPE} Playlists" + }, + "gameSettingsWindow": { + "addGameText": "Maglagay ng Laro" + }, + "gamesToText": "${WINCOUNT} na laro sa ${LOSECOUNT}", + "gatherWindow": { + "aboutDescriptionLocalMultiplayerExtraText": "Tandaan: anumang device sa isang party ay maaaring magkaroon ng higit pa\nkaysa sa isang manlalaro kung mayroon kang sapat na mga controller.", + "aboutDescriptionText": "Gamitin ang mga tab na ito para mag-assemble ng party.\n\nHinahayaan ka ng mga party na maglaro at mga paligsahan\nkasama ang iyong mga kaibigan sa iba't ibang device.\n\nGamitin ang ${PARTY} na button sa kanang tuktok upang\nmakipag-chat at makipag-ugnayan sa iyong partido.\n(sa isang controller, pindutin ang ${BUTTON} habang nasa isang menu)", + "aboutText": "About", + "addressFetchErrorText": "", + "appInviteMessageText": "Pinadalhan ka ni ${NAME} ng ${COUNT} ticket sa ${APP_NAME}", + "appInviteSendACodeText": "Mag-send ka sa Kanila ng Code", + "appInviteTitleText": "${APP_NAME} App Invite", + "bluetoothAndroidSupportText": "(gumagana sa anumang Android device na mayroong Bluetooth)", + "bluetoothDescriptionText": "Mag-host/sumali sa isang party sa pamamagitan ng Bluetooth:", + "bluetoothHostText": "Mag-host gamit ang Bluetooth", + "bluetoothJoinText": "Sumali gamit ang Bluetooth", + "bluetoothText": "Bluetooth", + "checkingText": "nag-checking…", + "copyCodeConfirmText": "Nakopya ang code sa clipboard.", + "copyCodeText": "I-kopya ang Code", + "dedicatedServerInfoText": "Para sa pinakamahusay na mga resulta, mag-set up ng nakalaang server. Tingnan ang bombsquadgame.com/server para malaman kung paano.", + "disconnectClientsText": "Ididiskonekta nito ang ${COUNT} (mga) manlalaro\nsa iyong party. Sigurado ka ba?", + "earnTicketsForRecommendingAmountText": "Makakatanggap ang mga kaibigan ng ${COUNT} na tiket kung susubukan nila ang laro\n(at makakatanggap ka ng ${YOU_COUNT} para sa bawat gagawa)", + "earnTicketsForRecommendingText": "I-share ang laro\npara makatanggap ng libreng tickets…", + "emailItText": "I-email", + "favoritesSaveText": "I-save bilang paborito", + "favoritesText": "Mga Paborito", + "freeCloudServerAvailableMinutesText": "Available ang susunod na libreng cloud server sa loob ng ${MINUTES} (na) minuto.", + "freeCloudServerAvailableNowText": "Mayroong libreng cloud server!", + "freeCloudServerNotAvailableText": "Walang available na libreng cloud server.", + "friendHasSentPromoCodeText": "${COUNT} ${APP_NAME} na mga tiket mula sa ${NAME}", + "friendPromoCodeAwardText": "Makakatanggap ka ng ${COUNT} na tiket sa tuwing ito ay gagamitin.", + "friendPromoCodeExpireText": "Mag-e-expire ang code sa loob ng ${EXPIRE_HOURS} na oras at gagana lang para sa mga bagong manlalaro.", + "friendPromoCodeInstructionsText": "Upang gamitin ito, buksan ang ${APP_NAME} at pumunta sa \"Mga Setting->Advanced->Ilagay ang Code\".\nTingnan ang bombsquadgame.com para sa mga link sa pag-download para sa lahat ng sinusuportahang platform.", + "friendPromoCodeRedeemLongText": "Maaari itong ma-redem ng ${COUNT} na libreng tiket ng hanggang ${MAX_USES} na tao.", + "friendPromoCodeRedeemShortText": "Maaari itong ma-redem ng ${COUNT} na tiket sa larong ito.", + "friendPromoCodeWhereToEnterText": "(sa \"Settings->Advanced->Ilagay Ang Code\")", + "getFriendInviteCodeText": "Kumuha ng imbitasyon ng code ng kaibigan", + "googlePlayDescriptionText": "Mag-imbita ng mga manlalaro ng Google Play sa iyong party:", + "googlePlayInviteText": "Mag-imbita", + "googlePlayReInviteText": "Mayroong ${COUNT} (mga) Google Play na manlalaro sa iyong party \nna madidiskonekta kung magsisimula ka ng bagong imbitasyon.\nIsama sila sa bagong imbitasyon para maibalik mo sila.", + "googlePlaySeeInvitesText": "Ipakita Ang Mga Imbitasyon", + "googlePlayText": "Google Play", + "googlePlayVersionOnlyText": "(Bersyon ng Android / Google Play)", + "hostPublicPartyDescriptionText": "Mag-host ng Pampublikong Party", + "hostingUnavailableText": "Hindi Available Ang Pagho-host", + "inDevelopmentWarningText": "Note:\n\nAng Network Play ay bago at patuloy na umuunlad na feature.\nSa ngayon, Ito'y lubos na inirerekomenda na ang lahat ng \nmga manlalaro ay nasa parehong Wi-Fi network.", + "internetText": "Internet", + "inviteAFriendText": "Walang laro ang mga kaibigan mo nito? Mag-imbita mo sila \npara sila'y subukan maglaro ito at makakatanggap sila ng ${COUNT} libreng tiket.", + "inviteFriendsText": "Mag-imbita ng mga kaibigan", + "joinPublicPartyDescriptionText": "Sumali sa isang Pampublikong Party", + "localNetworkDescriptionText": "Sumali sa malapit na party (LAN, Bluetooth, etc.)", + "localNetworkText": "Lokal na Network", + "makePartyPrivateText": "Gawing Pribado Ang Party Ko", + "makePartyPublicText": "Gawing Publiko Ang Party Ko", + "manualAddressText": "Address", + "manualConnectText": "I-connect", + "manualDescriptionText": "Sumali sa isang party sa pamamagitan ng address:", + "manualJoinSectionText": "Sumali Sa Pamamagitan Ng Address", + "manualJoinableFromInternetText": "Pwede ka bang sumali sa internet?:", + "manualJoinableNoWithAsteriskText": "HINDI*", + "manualJoinableYesText": "OO*", + "manualRouterForwardingText": "*upang ayusin ito, subukang i-configure ang iyong router para ipasa ang UDP port ${PORT} sa iyong lokal na address", + "manualText": "Manwal", + "manualYourAddressFromInternetText": "Ang iyong address mula sa internet:", + "manualYourLocalAddressText": "Iyong lokal na address:", + "nearbyText": "Malapit", + "noConnectionText": "", + "otherVersionsText": "", + "partyCodeText": "Code ng Partido", + "partyInviteAcceptText": "Tanggapin", + "partyInviteDeclineText": "Tanggihan", + "partyInviteGooglePlayExtraText": "(tingnan ang 'Google Play' tab sa 'Sumama' window)", + "partyInviteIgnoreText": "Ignorahin", + "partyInviteText": "Inimbitahan ka ni ${NAME} \nna sumali sa kanilang party", + "partyNameText": "Pangalan Ng Partido", + "partyServerRunningText": "Tumatakbo ang iyong party server.", + "partySizeText": "Dami Ng Partido", + "partyStatusCheckingText": "sinusuri ang katayuan...", + "partyStatusJoinableText": "ang iyong party ay maaari na ngayong sumali mula sa internet", + "partyStatusNoConnectionText": "hindi makakonekta sa server", + "partyStatusNotJoinableText": "ang iyong party ay hindi maaaring sumali mula sa internet", + "partyStatusNotPublicText": "hindi publiko Ang iyong partido", + "pingText": "ping", + "portText": "Port", + "privatePartyCloudDescriptionText": "Ang mga pribadong partido ay tumatakbo sa mga nakalaang cloud server; Hindi kailangan ng router configuration", + "privatePartyHostText": "Mag-host ng Pribadong Party", + "privatePartyJoinText": "Sumali sa Pribadong Party", + "privateText": "Pribado", + "publicHostRouterConfigText": "Maaaring mangailangan nito ng pag-configure ng port-forwarding sa iyong router. Para sa mas madaling opsyon, mag-host ng pribadong party.", + "publicText": "Publiko", + "requestingAPromoCodeText": "Humihiling ng code...", + "sendDirectInvitesText": "I-send ng direktang imbitasyon", + "shareThisCodeWithFriendsText": "Ibahagi ang code na ito sa iyong mga kaibigan:", + "showMyAddressText": "Ipakita Ang Address Ko", + "startHostingPaidText": "Mag-host ngayon ng ${COST}", + "startHostingText": "Host", + "startStopHostingMinutesText": "Maaari kang magsimula at huminto sa pa nang libre sa susunod na ${MINUTES} minuto.", + "stopHostingText": "Itigil Ang Pagho-host", + "titleText": "Sumama", + "wifiDirectDescriptionBottomText": "Kung ang lahat ng device ay may panel na 'Wi-Fi Direct', dapat ay magagamit nila ito upang maghanap\nat kumonekta sa isa't isa. Kapag nakakonekta na ang lahat ng device, maaari kang bumuo ng mga party\ndito gamit ang tab na 'Local Network', katulad lang ng sa isang regular na Wi-Fi network.\n\nPara sa pinakamahusay na mga resulta, ang Wi-Fi Direct host ay dapat ding ang ${APP_NAME} party host", + "wifiDirectDescriptionTopText": "Maaaring gamitin ang Wi-Fi Direct upang direktang ikonekta ang mga Android device nang wala\nnangangailangan ng Wi-Fi network. Ito ay pinakamahusay na gumagana sa Android 4.2 o mas mataas.\n\nUpang magamit nito, buksan ang mga settings ng iyong Wi-Fi at hanapin ang 'Wi-Fi Direct' sa menu.", + "wifiDirectOpenWiFiSettingsText": "Buksan Ang Mga Settings ng Wi-Fi", + "wifiDirectText": "Wi-Fi Direct", + "worksBetweenAllPlatformsText": "(ito’y gumagana sa pagitan ng lahat ng mga platform)", + "worksWithGooglePlayDevicesText": "(ito’y gumagana sa mga devices na tumatakbo ang bersyon ng Google Play (android) ng larong ito)", + "youHaveBeenSentAPromoCodeText": "Pinadalhan ka ng promo code na ${APP_NAME}:" + }, + "getTicketsWindow": { + "freeText": "LIBRE!", + "freeTicketsText": "Libreng Tiket", + "inProgressText": "Ang isang transaksyon ay isinasagawa; mangyaring subukan muli ng saglit.", + "purchasesRestoredText": "Naibalik na ang mga nabili.", + "receivedTicketsText": "Nakatanggap ka ng ${COUNT} tiket!", + "restorePurchasesText": "Ibalik Ang Mga Nabili", + "ticketPack1Text": "Kaunting Pakete Ng Tiket", + "ticketPack2Text": "Katamtamang Pakete Ng Tiket", + "ticketPack3Text": "Maraming Pakete Ng Tiket", + "ticketPack4Text": "Malaking Pakete Ng Tiket", + "ticketPack5Text": "Mas Malaking Pakete Ng Tiket", + "ticketPack6Text": "Pinakamalaking Pakete Ng Tiket", + "ticketsFromASponsorText": "Kumuha ng ${COUNT} na tiket\nmula sa isang sponsor", + "ticketsText": "${COUNT} Tiket", + "titleText": "Kumuha Ng Tiket", + "unavailableLinkAccountText": "Pasensya na, hindi available ang pagbili sa platform na ito.\nBilang isang solusyon, maaari mong i-link ang account na ito sa isang account na nasa\nisa pang platform at bumili doon.", + "unavailableTemporarilyText": "Hindi available ito. Subukang muli mamaya.", + "unavailableText": "Pasensya na, hindi ito available.", + "versionTooOldText": "Pasensya na, ang bersyon ng laro na ito ay masyadong luma; mangyaring mag-update sa isang mas bagong bersyon.", + "youHaveShortText": "mayroon kang ${COUNT}", + "youHaveText": "mayroon kang ${COUNT} na tiket" + }, + "googleMultiplayerDiscontinuedText": "Pasensya na, hindi na available ang multiplayer na serbisyo ng Google.\nGumagawa ako ng kapalit sa lalong madaling panahon.\nHanggang doon, mangyaring sumubok ng ibang paraan ng koneksyon.\n-Eric", + "googlePlayText": "Google Play", + "graphicsSettingsWindow": { + "alwaysText": "Palagi", + "fullScreenCmdText": "Fullscreen (Cmd-F)", + "fullScreenCtrlText": "Fullscreen (Ctrl-F)", + "gammaText": "Gama", + "highText": "Mataas", + "higherText": "Napakataas", + "lowText": "Mababa", + "mediumText": "Katamtaman", + "neverText": "Wala", + "resolutionText": "Resolusyon", + "showFPSText": "Ipakita ang FPS", + "texturesText": "Mga Texture", + "titleText": "Grapika", + "tvBorderText": "TV Na Border", + "verticalSyncText": "Patagong Pag-sync", + "visualsText": "Biswal" + }, + "helpWindow": { + "bombInfoText": "- Bomba -\nMas malakas pa sa suntok, pero\nmaaaring magresulta sa matinding pananakit sa sarili.\nPara sa pinakamahusay na mga resulta, itapon patungo\nkalaban bago maubos ang fuse.", + "bombInfoTextScale": 0.5, + "canHelpText": "Makakatulong ang ${APP_NAME}.", + "controllersInfoText": "Maaari mong laruin ang ${APP_NAME} kasama ng mga kaibigan sa isang network, o ikaw\nlahat ay maaaring maglaro sa parehong device kung mayroon kang sapat na mga controller.\nSinusuportahan ng ${APP_NAME} ang iba't ibang mga ito; maaari ka ring gumamit ng mga telepono\nbilang mga controller sa pamamagitan ng libreng '${REMOTE_APP_NAME}' app.\nTingnan ang Mga Setting->Controller para sa higit pang impormasyon.", + "controllersInfoTextRemoteOnly": "Maaari mong laruin ang ${APP_NAME} kasama ng mga kaibigan sa isang network, o ikaw\nlahat ay maaaring maglaro sa parehong device sa pamamagitan ng paggamit ng mga phones bilang\nmga controller sa pamamagitan ng libreng '${REMOTE_APP_NAME}' app.", + "controllersText": "Mga Controllers", + "controlsSubtitleText": "Ang iyong magiliw na ${APP_NAME} ay may ilang mga pangunahing aksyon", + "controlsText": "Mga Kontrol", + "devicesInfoText": "Maaaring laruin ang VR na bersyon ng ${APP_NAME} sa network\nang regular na bersyon, kaya tanggalin ang iyong mga karagdagang telepono, tablet,\nat mga computer at simulan ang iyong laro. Maaari itong maging kapaki-pakinabang sa\nikonekta ang isang regular na bersyon ng laro sa bersyon ng VR para lang\npayagan ang mga tao sa labas na manood ng aksyon.", + "devicesText": "Mga Device", + "friendsGoodText": "Ang mga ito ay magandang pagkakaroon. Ang ${APP_NAME} ay pinakanakakatuwa sa ilan\nmga manlalaro at maaaring sumuporta ng hanggang 8 sa isang pagkakataon, na humahantong sa:", + "friendsText": "Mga Kaibigan", + "jumpInfoText": "-Tumalon-\nTumalon upang tumawid sa maliliit na puwang,\nupang ihagis ang mga bagay na mas mataas, at\nupang ipahayag ang damdamin ng kagalakan.", + "jumpInfoTextScale": 0.5, + "orPunchingSomethingText": "O sumuntok ng isang bagay, itinapon ito sa isang bangin, at pinasabog ito habang pababa gamit ang isang malagkit na bomba.", + "pickUpInfoText": "- Pulutin -\nKunin ang mga flag, mga kaaway, o anumang bagay\nkung hindi ay hindi naka-bold sa lupa.\nPindutin muli upang ihagis.", + "pickUpInfoTextScale": 0.5, + "powerupBombDescriptionText": "Payagan kang maglabas ng tatlong bomba\nsa isang hilera sa halip na isa lamang.", + "powerupBombNameText": "Tatlong-Bomba", + "powerupCurseDescriptionText": "Malamang na gusto mong iwasan ang mga ito.\n ...o ikaw?", + "powerupCurseNameText": "Sumpa", + "powerupHealthDescriptionText": "Ibangon ka sa buong kalusugan.\nHindi mo naisip nito.", + "powerupHealthNameText": "Medikal-Pakete", + "powerupIceBombsDescriptionText": "Mas mahina kaysa sa mga normal na bomba\nngunit nagyelo ang iyong mga kalaban\nat partikular na malutong.", + "powerupIceBombsNameText": "Bombang-Yelo", + "powerupImpactBombsDescriptionText": "Medyo mahina kaysa sa regular\nbomba, ngunit sumasabog ito kapag nabagsak.", + "powerupImpactBombsNameText": "Gatilyong-Bomba", + "powerupLandMinesDescriptionText": "Ang mga ito ay dumating sa mga pakete ng 3;\nKapaki-pakinabang para sa base defense o\npaghinto ng mabilis na mga kalaban.", + "powerupLandMinesNameText": "Mina", + "powerupPunchDescriptionText": "Ang iyong mga suntok ay mas mahirap,\nmas mabilis, mas mahusay, at mas malakas.", + "powerupPunchNameText": "Boxing-Gloves", + "powerupShieldDescriptionText": "Pumigil na pagsakit\nkaya hindi mo kailangan.", + "powerupShieldNameText": "Enrhiyang-Kalasag", + "powerupStickyBombsDescriptionText": "Dumikit sa anumang matamaan nila.\nIto’y naging pagtawanan.", + "powerupStickyBombsNameText": "Malagkit-Bomba", + "powerupsSubtitleText": "Siyempre, walang larong kumpleto pag walang powerups:", + "powerupsText": "Powerups", + "punchInfoText": "- Suntok -\nAng mga suntok ay mas nakakasakit\nmas mabilis ang paggalaw ng iyong mga kamay, kaya\ntumakbo at umiikot na parang baliw.", + "runInfoText": "- Takbo -\nPindutin ang ANY button para tumakbo. Ang mga trigger o mga button sa balikat ay gumagana nang maayos kung mayroon ka ng mga ito.\nAng pagtakbo ay nagpapabilis sa iyo ng mga lugar ngunit nahihirapan kang lumiko, kaya mag-ingat sa mga bangin.", + "someDaysText": "May mga araw na parang gusto mong sumuntok ng kung ano. O nagpapasabog ng isang bagay.", + "titleText": "Tulong ng ${APP_NAME}", + "toGetTheMostText": "Upang masulit ang larong ito, kakailanganin mo:", + "welcomeText": "Maligayang Pagdating sa ${APP_NAME}" + }, + "holdAnyButtonText": "", + "holdAnyKeyText": "", + "hostIsNavigatingMenusText": "- Ang ${HOST} ay nagna-navigate sa mga menu tulad ng isang boss -", + "importPlaylistCodeInstructionsText": "Gamitin ang sumusunod na code upang i-import ang playlist na ito sa ibang lugar:", + "importPlaylistSuccessText": "Na-import na ${TYPE} na playlist '${NAME}'", + "importText": "Iangkat", + "importingText": "Pag-Import…", + "inGameClippedNameText": "in-game ay naging\n\"${NAME}\"", + "installDiskSpaceErrorText": "ERROR: Hindi makumpleto ang pag-install.\nMaaaring wala ka nang espasyo sa iyong device.\nMag-clear ng ilang espasyo at subukang muli.", + "internal": { + "arrowsToExitListText": "pindutin ang ${LEFT} o ${RIGHT} upang lumabas sa listahan", + "buttonText": "pindutan", + "cantKickHostError": "Hindi mo maaaring I-kick ang host.", + "chatBlockedText": "Na-block si ${NAME} sa loob ng ${TIME} segundo.", + "connectedToGameText": "Sumali sa '${NAME}'", + "connectedToPartyText": "Sumali sa party ni ${NAME}!", + "connectingToPartyText": "Nagdudugtong….", + "connectionFailedHostAlreadyInPartyText": "Nabigo ang koneksyon; nasa ibang party ang host.", + "connectionFailedPartyFullText": "Nabigo ang koneksyon; puno na ang party.", + "connectionFailedText": "Nabigo ang koneksyon.", + "connectionFailedVersionMismatchText": "Nabigo ang koneksyon; nagpapatakbo ang host ng ibang bersyon ng laro.\nTiyaking pareho kayong napapanahon at subukang muli sumali.", + "connectionRejectedText": "Tinanggihan ang koneksyon.", + "controllerConnectedText": "Nakakonekta si ${CONTROLLER}.", + "controllerDetectedText": "1 controller ang natuklasan.", + "controllerDisconnectedText": "Nadiskonekta si ${CONTROLLER}.", + "controllerDisconnectedTryAgainText": "Nadiskonekta si ${CONTROLLER}. Pakisubukang kumonekta muli.", + "controllerForMenusOnlyText": "Ang controller na ito ay hindi maaaring gamitin sa paglalaro; para lamang mag-navigate sa mga menu.", + "controllerReconnectedText": "Muling kumonekta si ${CONTROLLER}.", + "controllersConnectedText": "Nakakonekta ang ${COUNT} controllers.", + "controllersDetectedText": "${COUNT} controller ang natukalsan.", + "controllersDisconnectedText": "${COUNT} controller ang nadiskonekta.", + "corruptFileText": "Natukoy ang (mga) corrupted na file. Pakisubukang muling i-install, o mag-email sa ${EMAIL}", + "errorPlayingMusicText": "Error sa paglalaro ng musika: ${MUSIC}", + "errorResettingAchievementsText": "Hindi ma-reset ang mga online na achievements; Subukang muli mamaya.", + "hasMenuControlText": "Si ${NAME} lang ay may kontrol sa menu.", + "incompatibleNewerVersionHostText": "Ang host ay nagpapatakbo ng mas bagong bersyon ng laro.\nMag-update sa pinakabagong bersyon at subukang muli.", + "incompatibleVersionHostText": "Ang host ay nagpapatakbo ng ibang bersyon ng laro.\nTiyaking pareho kayong napapanahong bersyon at subukang muli.", + "incompatibleVersionPlayerText": "Ang ${NAME} ay nagpapatakbo ng ibang bersyon ng laro.\nTiyaking pareho kayong napapanahong bersyon at subukang muli.", + "invalidAddressErrorText": "Error: di-wastong address.", + "invalidNameErrorText": "Errol: di-wastong pangalan.", + "invalidPortErrorText": "Error: di-wastong port.", + "invitationSentText": "Napadala na ang imbitasyon.", + "invitationsSentText": "${COUNT} (na) imbitasyon ang napadala.", + "joinedPartyInstructionsText": "May sumali sa iyong partido.\nPumunta sa 'Maglaro' para magsimula ng laro.", + "keyboardText": "Keyboard", + "kickIdlePlayersKickedText": "na-kicked si ${NAME} dahil sa pagiging idle.", + "kickIdlePlayersWarning1Text": "I-kikick si ${NAME} sa loob ng ${COUNT} (na) segundo kung idle pa rin.", + "kickIdlePlayersWarning2Text": "(maaari mong i-off ito sa Mga Setting -> Advanced)", + "leftGameText": "Umalis sa '${NAME}'.", + "leftPartyText": "Umalis sa party ni ${NAME}.", + "noMusicFilesInFolderText": "Walang mga file ng musika ang folder.", + "playerJoinedPartyText": "Sumali si ${NAME} sa party mo!", + "playerLeftPartyText": "Umalis si ${NAME} sa party mo.", + "rejectingInviteAlreadyInPartyText": "Pagtanggi sa imbitasyon (nasa isang party na).", + "serverRestartingText": "Nagre-restart ang server. Mangyaring sumali muli sa isang saglit…", + "serverShuttingDownText": "Nagsasara ang server...", + "signInErrorText": "Error sa pag-sign in.", + "signInNoConnectionText": "Hindi makapag-sign in. (walang koneksyon sa internet?)", + "telnetAccessDeniedText": "ERROR: ang user ay hindi nagbigay ng access sa telnet.", + "timeOutText": "(time out sa ${TIME} segundo)", + "touchScreenJoinWarningText": "Sumali ka gamit ang touchscreen.\nKung ito ay isang pagkakamali, i-tap ang 'Menu->Umalis sa Laro' kasama nito.", + "touchScreenText": "TouchScreen", + "unableToResolveHostText": "Error: hindi malutas ang host.", + "unavailableNoConnectionText": "Ito’y kasalukuyang hindi magagamit (walang koneksyon sa internet?)", + "vrOrientationResetCardboardText": "Gamitin ito upang i-reset ang oryentasyon ng VR.\nUpang maglaro ng laro kakailanganin mo ng isang panlabas na controller.", + "vrOrientationResetText": "Pag-reset ng oryentasyon ng VR.", + "willTimeOutText": "(magta-time out kung idle)" + }, + "jumpBoldText": "TALON", + "jumpText": "Talon", + "keepText": "Panatilihin", + "keepTheseSettingsText": "Panatilihin ang mga setting na ito?", + "keyboardChangeInstructionsText": "I-double press space para mapalitan ang mga keyboard.", + "keyboardNoOthersAvailableText": "Walang ibang mga keyboard na magagamit.", + "keyboardSwitchText": "Nagpapalit ng keyboard sa \"${NAME}\".", + "kickOccurredText": "kicked na si ${NAME}", + "kickQuestionText": "I-Kick si ${NAME}?", + "kickText": "", + "kickVoteCantKickAdminsText": "Hindi ma-kick ang mga admin.", + "kickVoteCantKickSelfText": "Hindi mo ma-kick ng sarili mo.", + "kickVoteFailedNotEnoughVotersText": "Hindi marami ang mga manlalaro para sa isang boto.", + "kickVoteFailedText": "Nabigo ang kick-vote.", + "kickVoteStartedText": "Sinimulan na ang isang kick vote para kay ${NAME}.", + "kickVoteText": "Bumoto sa Kick", + "kickVotingDisabledText": "Naka-disable ang kick voting.", + "kickWithChatText": "I-type ang ${YES} sa chat para sa oo at ${NO} para sa hindi.", + "killsTallyText": "${COUNT} na ang pumapatay", + "killsText": "Pumapatay", + "kioskWindow": { + "easyText": "Madali", + "epicModeText": "Mode na Epic", + "fullMenuText": "Buong Menu", + "hardText": "Mahirap", + "mediumText": "Katamtaman", + "singlePlayerExamplesText": "Mga Halimbawa ng Single Player / Co-op", + "versusExamplesText": "Halimbawa ng mga Versus" + }, + "languageSetText": "Ang wika ay \"${LANGUAGE}\" na ngayon.", + "lapNumberText": "Ikot ${CURRENT}/${TOTAL}", + "lastGamesText": "(huling ${COUNT} na laro)", + "leaderboardsText": "Mga Leaderboard", + "league": { + "allTimeText": "Lahat Ng Oras", + "currentSeasonText": "Kasalukuyang Season (${NUMBER})", + "leagueFullText": "Liga ng ${NAME}.", + "leagueRankText": "Ranggo ng Liga", + "leagueText": "Liga", + "rankInLeagueText": "#${RANK}, ${NAME} ${SUFFIX} na Liga", + "seasonEndedDaysAgoText": "Natapos ang season ${NUMBER} araw ang nakalipas.", + "seasonEndsDaysText": "Matatapos ang season sa ${NUMBER} (na) araw.", + "seasonEndsHoursText": "Matatapos ang season sa ${NUMBER} (na) oras.", + "seasonEndsMinutesText": "Matatapos ang season sa ${NUMBER} (na) minuto.", + "seasonText": "Season ${NUMBER}", + "tournamentLeagueText": "Dapat mong maabot ang liga ng ${NAME} upang makapasok sa paligsahan na ito.", + "trophyCountsResetText": "Ire-reset ang mga bilang ng tropeo sa susunod na season." + }, + "levelBestScoresText": "Pinakamahusay na mga iskor sa ${LEVEL}", + "levelBestTimesText": "Pinakamahusay na lahat sa ${LEVEL}", + "levelIsLockedText": "Naka-lock ang ${LEVEL}.", + "levelMustBeCompletedFirstText": "Dapat makumpleto muna ang ${LEVEL}.", + "levelText": "Antas ${NUMBER}", + "levelUnlockedText": "Unlocked ang Level na Ito!", + "livesBonusText": "Bonus ng Buhay", + "loadingText": "Saglit lang...", + "loadingTryAgainText": "Naglo-load; subukan muli sa isang saglit…", + "macControllerSubsystemBothText": "Pareho (hindi inirerekomenda)", + "macControllerSubsystemClassicText": "Klasiko", + "macControllerSubsystemDescriptionText": "(subukang baguhin ito kung ang iyong mga controllers ay hindi gumagana)", + "macControllerSubsystemMFiNoteText": "Natukoy ang Made-for-iOS/Mac controller;\nMaaaring gusto mong paganahin ang mga ito sa Mga Setting -> Mga Controller", + "macControllerSubsystemMFiText": "Made-for-iOS/Mac", + "macControllerSubsystemTitleText": "Suporta sa Controller", + "mainMenu": { + "creditsText": "Mga Kredito", + "demoMenuText": "Demo na Menu", + "endGameText": "Itigil ang Laro", + "exitGameText": "Umalis sa Laro", + "exitToMenuText": "Balik sa menu?", + "howToPlayText": "Paano maglaro", + "justPlayerText": "(Si ${NAME} lang)", + "leaveGameText": "Ialis sa Laro", + "leavePartyConfirmText": "Talagang aalis sa party na ito?", + "leavePartyText": "Umalis sa Party", + "quitText": "Umalis", + "resumeText": "Ipatuloy", + "settingsText": "Mga Setting" + }, + "makeItSoText": "Gawin itong Kaya", + "mapSelectGetMoreMapsText": "Kumuha ng Higit pang Mapa...", + "mapSelectText": "Pumili…", + "mapSelectTitleText": "Mapa ng ${GAME}", + "mapText": "Mapa", + "maxConnectionsText": "Max na Koneksyon", + "maxPartySizeText": "Max ng Pagdami ng Party", + "maxPlayersText": "Pagdami ng Mga Manlalaro", + "modeArcadeText": "Arcade na Mode", + "modeClassicText": "Klasikong Mode", + "modeDemoText": "Mode na Demo", + "mostValuablePlayerText": "Pinakamalupit sa lahat", + "mostViolatedPlayerText": "Pinakanakawawa sa lahat", + "mostViolentPlayerText": "Pinakamadugo sa lahat", + "moveText": "Galaw", + "multiKillText": "${COUNT}-PAGPATAY!!!", + "multiPlayerCountText": "${COUNT} na manlalaro", + "mustInviteFriendsText": "Tandaan: dapat kang mag-imbita ng mga kaibigan\nang panel na \"${GATHER}\" o i-attach\nmga controller para maglaro ng multiplayer.", + "nameBetrayedText": "${VICTIM} ay pinagtaksilan ni ${NAME}.", + "nameDiedText": "${NAME} ay namatay.", + "nameKilledText": "${VICTIM} ay pinatay ni ${NAME}.", + "nameNotEmptyText": "Hindi pwede ang walang pangalan!", + "nameScoresText": "${NAME} Naka-score!", + "nameSuicideKidFriendlyText": "Hindi sinasadyang namatay si ${NAME}.", + "nameSuicideText": "Nagpakamatay si ${NAME}.", + "nameText": "Pangalan", + "nativeText": "Natural", + "newPersonalBestText": "Bagong personal na pinakamahusay!", + "newTestBuildAvailableText": "Available ang isang mas bagong pagsubok na build! (${VERSION} build ${BUILD}).\nKunin ito sa ${ADDRESS}", + "newText": "Bago", + "newVersionAvailableText": "Available ang isang mas bagong bersyon ng ${APP_NAME}! (${VERSION})", + "nextAchievementsText": "Mga Susunod na Nakamit:", + "nextLevelText": "Mga Susunod na Level", + "noAchievementsRemainingText": "- wala", + "noContinuesText": "(hindi i-continue)", + "noExternalStorageErrorText": "Walang nakitang external na storage sa device na ito", + "noGameCircleText": "Error: hindi naka-log in sa GameCircle", + "noScoresYetText": "Wala pang score.", + "noThanksText": "Salamat Nalang", + "noTournamentsInTestBuildText": "BABALA: Babalewalain ang mga score sa tournament mula sa test build na ito.", + "noValidMapsErrorText": "Walang nakitang valid na mapa para sa ganitong uri ng laro.", + "notEnoughPlayersRemainingText": "Hindi marami na manlalaro ang natitira; umalis at magsimula ng bagong laro.", + "notEnoughPlayersText": "Kailangan mo ng atleast ${COUNT} na manlalaro upang simulan ang larong ito!", + "notNowText": "Hindi muna ngayon", + "notSignedInErrorText": "Dapat kang mag-sign in para magawa ito.", + "notSignedInGooglePlayErrorText": "Dapat kang mag-sign in gamit ang Google Play para magawa ito.", + "notSignedInText": "hindi naka-sign in", + "nothingIsSelectedErrorText": "Walang napili!", + "numberText": "#${NUMBER}", + "offText": "Naka-Off", + "okText": "Ok lang", + "onText": "Naka-On", + "oneMomentText": "Saglit lang…", + "onslaughtRespawnText": "Ang ${PLAYER} ay respawn sa wave na ${WAVE}", + "orText": "${A} o ${B}", + "otherText": "Iba Pa…", + "outOfText": "(#${RANK} sa ${ALL})", + "ownFlagAtYourBaseWarning": "Ang iyong sariling watawat ay dapat na\nsa iyong base upang makapuntos!", + "packageModsEnabledErrorText": "Ang network-play ay hindi pinapayagan habang ang local-package-mods ay pinagana (tingnan ang Mga Setting->Advanced)", + "partyWindow": { + "chatMessageText": "Mensahe", + "emptyText": "Walang tao ang iyong party", + "hostText": "(ang host)", + "sendText": "I-send", + "titleText": "Iyong Party" + }, + "pausedByHostText": "(naka-pause ng host)", + "perfectWaveText": "Perpekto na Kaway!", + "pickUpText": "Pulutin", + "playModes": { + "coopText": "Kooperatiba", + "freeForAllText": "Awayang Rambulan", + "multiTeamText": "Maraming Team", + "singlePlayerCoopText": "Nag-iisa / Kooperatiba", + "teamsText": "Mga Teams" + }, + "playText": "Maglaro", + "playWindow": { + "oneToFourPlayersText": "1-4 na manlalaro", + "titleText": "Maglaro", + "twoToEightPlayersText": "2-8 na manlalaro" + }, + "playerCountAbbreviatedText": "${COUNT}n.m", + "playerDelayedJoinText": "Papasok si ${PLAYER} sa simula ng susunod na round.", + "playerInfoText": "Impormasyon ng Manlalaro", + "playerLeftText": "Umalis si ${PLAYER} sa laro.", + "playerLimitReachedText": "Naabot na ang limitasyon ng manlalaro na ${COUNT}; hindi pinapayagan ang mga ibang sumali.", + "playerProfilesWindow": { + "cantDeleteAccountProfileText": "Hindi mo matatanggal ang profile ng iyong account.", + "deleteButtonText": "Itangal ang\nProfile", + "deleteConfirmText": "Itangal si ‘${PROFILE}’?", + "editButtonText": "I-edit ang\nProfile", + "explanationText": "(mga pangalan at hitsura ng custom na manlalaro para sa account na ito)", + "newButtonText": "Gumawa ng\nProfile", + "titleText": "Profile ng Manlalaro" + }, + "playerText": "Manlalaro", + "playlistNoValidGamesErrorText": "Ang playlist na ito ay hindi naglalaman ng mga wastong naka-unlock na laro.", + "playlistNotFoundText": "hindi nahanap ang playlist", + "playlistText": "Playlist", + "playlistsText": "Mga Playlist", + "pleaseRateText": "Kung nae-enjoy mo ang ${APP_NAME}, mangyaring isaalang-alang ang \npagkuha na sandali lang at i-rate ito o pagsulat ng isang pagsusuri. Nagbibigay ito ngkapaki-pakinabang na feedback at \ntumutulong sa pagsuporta sa pag-unlad sa hinaharap.\n\nsalamat!\n-eric", + "pleaseWaitText": "Hintay lang…", + "pluginsDetectedText": "May nakitang bagong (mga) plugin. Paganahin/i-configure ang mga ito sa mga setting.", + "pluginsText": "Mga Plugin", + "practiceText": "Pagsasagawa", + "pressAnyButtonPlayAgainText": "Pindutin ang anumang button para maglaro muli...", + "pressAnyButtonText": "Pindutin ang anumang button para magpatuloy...", + "pressAnyButtonToJoinText": "pindutin ang anumang button para sumali...", + "pressAnyKeyButtonPlayAgainText": "Pindutin ang anumang key/button para maglaro muli...", + "pressAnyKeyButtonText": "Pindutin ang anumang key/button para magpatuloy...", + "pressAnyKeyText": "Pindutin ang anumang key…", + "pressJumpToFlyText": "** Pindutin ang tumalon nang paulit-ulit upang lumipad **", + "pressPunchToJoinText": "Pindutin ang SUNTOK para sumali...", + "pressToOverrideCharacterText": "pindutin ang ${BUTTONS} upang i-override ang iyong karakter", + "pressToSelectProfileText": "pindutin ang ${BUTTONS} upang pumili ng manlalaro", + "pressToSelectTeamText": "pindutin ang ${BUTTONS} para pumili ng team", + "promoCodeWindow": { + "codeText": "Code", + "enterText": "I-enter" + }, + "promoSubmitErrorText": "Error sa pagsusumite ng code; suriin ang iyong koneksyon ng internet", + "ps3ControllersWindow": { + "macInstructionsText": "I-off ang power sa likod ng iyong PS3, siguraduhin\nNaka-enable ang Bluetooth sa iyong Mac, pagkatapos ay ikonekta ang iyong controller\nsa iyong Mac sa pamamagitan ng USB cable upang ipares ang dalawa. Mula noon, ikaw\nmaaaring gamitin ang home button ng controller para ikonekta ito sa iyong Mac\nsa alinman sa wired (USB) o wireless (Bluetooth) mode.\n\nSa ilang mga Mac maaari kang ma-prompt para sa isang passcode kapag nagpapares.\nKung mangyari ito, tingnan ang sumusunod na tutorial o google para sa tulong.\n\n\n\n\nDapat lumabas sa device ang mga PS3 controller na nakakonekta nang wireless\nlistahan sa System Preferences->Bluetooth. Maaaring kailanganin mong alisin ang mga ito\nmula sa listahang iyon kapag gusto mong gamitin muli ang mga ito sa iyong PS3.\n\nTiyakin din na idiskonekta ang mga ito sa Bluetooth kapag hindi naka-in\ngamitin o ang kanilang mga baterya ay patuloy na mauubos.\n\nDapat hawakan ng Bluetooth ang hanggang 7 konektadong device,\nkahit na ang iyong mileage ay maaaring mag-iba.", + "ouyaInstructionsText": "Para gumamit ng PS3 controller sa iyong OUYA, ikonekta lang ito gamit ang USB cable\nisang beses upang ipares ito. Ang paggawa nito ay maaaring madiskonekta ang iyong iba pang mga controller, kaya\ndapat mong i-restart ang iyong OUYA at i-unplug ang USB cable.\n\nMula noon, magagamit mo na ang HOME button ng controller para\nikonekta ito nang wireless. Kapag tapos ka nang maglaro, pindutin nang matagal ang HOME button\npara sa 10 segundo upang i-off ang controller; kung hindi, maaari itong manatili sa\nat mga basurang baterya.", + "pairingTutorialText": "pagpapares ng tutorial na video", + "titleText": "Paggamit ng mga PS3 Controller sa ${APP_NAME}:" + }, + "punchBoldText": "SUNTOK", + "punchText": "Suntok", + "purchaseForText": "Ibili para sa ${PRICE}", + "purchaseGameText": "Ibili ang laro", + "purchasingText": "Nagbabayad...", + "quitGameText": "Ihinto ang ${APP_NAME}?", + "quittingIn5SecondsText": "Humihinto sa loob ng 5 segundo...", + "randomPlayerNamesText": "DEFAULT_NAMES", + "randomText": "Random", + "rankText": "Ranggo", + "ratingText": "Marka", + "reachWave2Text": "Abutin ang kaway 2 para ma-ranggo.", + "readyText": "nakahanda", + "recentText": "Makabago", + "remoteAppInfoShortText": "Ang ${APP_NAME} ay pinakanakakatuwa kapag nilalaro kasama ng pamilya at mga kaibigan.\nIkonekta ang isa o higit pang mga controller ng hardware o i-install ang\n${REMOTE_APP_NAME} app sa mga phone o tablet upang magamit ang mga ito\nbilang mga controllers.", + "remote_app": { + "app_name": "BombSquad Remote", + "app_name_short": "BSRemote", + "button_position": "Posisyon ng Pindutan", + "button_size": "Laki ng Pindutan", + "cant_resolve_host": "Hindi malutas ang host.", + "capturing": "Kumukuha…", + "connected": "Konektdo.", + "description": "Gamitin ang iyong mga phone o tablet bilang controller sa BombSquad.\nHanggang 8 device ang maaaring kumonekta nang sabay-sabay para sa epic na lokal na multiplayer na kabaliwan sa isang TV o tablet", + "disconnected": "Nadiskonekta ng server.", + "dpad_fixed": "nakapirmi", + "dpad_floating": "lumulutang", + "dpad_position": "Posisyon ng D-Pad", + "dpad_size": "Laki ng D-Pad", + "dpad_type": "Uri ng D-Pad", + "enter_an_address": "Maglagay ng Address", + "game_full": "Ang laro ay puno na o hindi tumatanggap ng mga koneksyon.", + "game_shut_down": "Nagsara ang laro.", + "hardware_buttons": "Mga Pindutan ng Hardware", + "join_by_address": "Sumali sa pamamagitan ng Address...", + "lag": "Lag: ${SECONDS} na segundo", + "reset": "I-reset sa default", + "run1": "Takbo 1", + "run2": "Takbo 2", + "searching": "Naghahanap ng mga laro sa BombSquad...", + "searching_caption": "I-tap ang pangalan ng laro para sumali dito.\nTiyaking nasa parehong kang wifi network sa laro.", + "start": "Simulan", + "version_mismatch": "Hindi tugma ang bersyon.\nTiyaking BombSquad at BombSquad Remote\nay ang mga pinakabagong bersyon at subukang muli." + }, + "removeInGameAdsText": "I-unlock ang \"${PRO}\" sa tindahan upang alisin ang mga in-game na ad.", + "renameText": "I-palitan", + "replayEndText": "Itigil Ang Replay", + "replayNameDefaultText": "Replay ng Huling Laro", + "replayReadErrorText": "Error sa pagbabasa ng replay file.", + "replayRenameWarningText": "Palitan ang pangalan ng \"${REPLAY}\" pagkatapos ng isang laro kung gusto mong panatilihin ito; kung hindi, ito ay mapapatungan.", + "replayVersionErrorText": "Pasensya na, ginawa ang replay na ito sa ibang paraang\nbersyon ng laro at hindi magagamit.", + "replayWatchText": "Panoorin ang replay", + "replayWriteErrorText": "Error sa pagsulat ng replay file.", + "replaysText": "Mga Replay", + "reportPlayerExplanationText": "Gamitin ang email na ito upang mag-ulat ng pagdaya, hindi naaangkop na pananalita, o iba pang masamang gawin.\nPakilarawan sa ibaba:", + "reportThisPlayerCheatingText": "Pagdaya", + "reportThisPlayerLanguageText": "Hindi Angkop na Salita", + "reportThisPlayerReasonText": "Ano ang gusto mong iulat?", + "reportThisPlayerText": "Iulat ang Manlalaro na Ito", + "requestingText": "Humihiling", + "restartText": "I-restart", + "retryText": "I-retry", + "revertText": "Ibalik", + "runText": "Takbo", + "saveText": "I-save", + "scanScriptsErrorText": "(Mga) error sa pag-scan ng mga script; tingnan ang log para sa mga detalye.", + "scoreChallengesText": "Mga Hamon sa Iskor", + "scoreListUnavailableText": "Hindi available ang listahan ng iskor", + "scoreText": "Iskor", + "scoreUnits": { + "millisecondsText": "Milisegundo", + "pointsText": "Puntos", + "secondsText": "Segundo" + }, + "scoreWasText": "(ay nasa ${COUNT})", + "selectText": "Piliin", + "seriesWinLine1PlayerText": "ANG NANALO SA", + "seriesWinLine1TeamText": "ANG NANALO SA", + "seriesWinLine1Text": "ANG NANALO SA", + "seriesWinLine2Text": "SERYE!", + "settingsWindow": { + "accountText": "Account", + "advancedText": "Advanced", + "audioText": "Audio", + "controllersText": "Mga Controller", + "graphicsText": "Grapika", + "playerProfilesMovedText": "Tandaan: Ang mga Profile ng Manlalaro ay inilipat sa Account window sa pangunahing menu.", + "titleText": "Mga Setting" + }, + "settingsWindowAdvanced": { + "alwaysUseInternalKeyboardDescriptionText": "(isang simpleng, controller-friendly na on-screen na keyboard para sa pag-edit ng teksto)", + "alwaysUseInternalKeyboardText": "Laging Gumamit ng Panloob na Keyboard", + "benchmarksText": "Mga Benchmark at Stress-Test", + "disableCameraGyroscopeMotionText": "I-disable ang Camera Gyroscope Motion", + "disableCameraShakeText": "Huwag paganahin ang Camera Shake", + "disableThisNotice": "(maaari mong i-disable ang notice na ito sa mga advanced na setting)", + "enablePackageModsDescriptionText": "(nagpapagana ng mga karagdagang kakayahan sa pag-modding ngunit hindi pinapagana ang net-play)", + "enablePackageModsText": "Paganahin ang Lokal na Package Mods", + "enterPromoCodeText": "Ilagay ang Code", + "forTestingText": "Tandaan: ang mga value na ito ay para lamang sa pagsubok at mawawala kapag lumabas ang app.", + "helpTranslateText": "Ang mga pagsasalin na hindi Ingles ng ${APP_NAME} ay isang komunidad\nsuportadong pagsisikap. Kung gusto mong mag-ambag o magtama\nisang pagsasalin, sundan ang link sa ibaba. Salamat!", + "kickIdlePlayersText": "I-kick Ang Mga Idle na Manlalaro", + "kidFriendlyModeText": "Kid-Friendly Mode (binawasan ang karahasan, atbp)", + "languageText": "Wika", + "moddingGuideText": "Gabay sa Modding", + "mustRestartText": "Dapat mong i-restart ang laro para magka-epekto ito.", + "netTestingText": "Pagsusuri ng Network", + "resetText": "I-reset", + "showBombTrajectoriesText": "Ipakita ang Mga Trajectory ng Bomba", + "showPlayerNamesText": "Ipakita ang Mga Pangalan ng Manlalaro", + "showUserModsText": "Ipakita ang Mods Folder", + "titleText": "Advanced", + "translationEditorButtonText": "Editor ng Wika ng ${APP_NAME}.", + "translationFetchErrorText": "hindi available ang katayuan ng wika", + "translationFetchingStatusText": "sinusuri ang status ng lengguwahe…", + "translationInformMe": "Ipaalam sa akin kapag ang aking wika ay nangangailangan ng mga update", + "translationNoUpdateNeededText": "ang kasalukuyang wika ay makabago; woohoo!", + "translationUpdateNeededText": "** ang kasalukuyang wika ay nangangailangan ng mga update!! **", + "vrTestingText": "Testing ng VR" + }, + "shareText": "I-share", + "sharingText": "Nagbabahagi….", + "showText": "Ipakita", + "signInForPromoCodeText": "Dapat kang mag-sign in sa isang account para magkabisa ang mga code.", + "signInWithGameCenterText": "Para gumamit ng Game Center account,\nmag-sign in gamit ang Game Center app.", + "singleGamePlaylistNameText": "${GAME} lang", + "singlePlayerCountText": "1 manlalaro", + "soloNameFilterText": "Solo na ${NAME}", + "soundtrackTypeNames": { + "CharSelect": "Pagpili ng Karakter", + "Chosen One": "Napili ng Isa", + "Epic": "Larong Epic na Mode", + "Epic Race": "Epic na Takbuan", + "FlagCatcher": "Kunin ang Bandila", + "Flying": "Masayang Isip", + "Football": "Rugbi", + "ForwardMarch": "Pag-atake", + "GrandRomp": "Pagsakop", + "Hockey": "Hockey", + "Keep Away": "Layuan Mo", + "Marching": "Bantayan", + "Menu": "Pangunahing Menu", + "Onslaught": "Pagsalakay", + "Race": "Takbuan", + "Scary": "Hari Ng Burol", + "Scores": "Screen Ng Iskor", + "Survival": "Kaligtasan", + "ToTheDeath": "Laban Ng Kamatayan", + "Victory": "Final Na Screen Ng Iskor" + }, + "spaceKeyText": "space", + "statsText": "Katayuan", + "storagePermissionAccessText": "Nangangailangan ito ng access sa storage", + "store": { + "alreadyOwnText": "Nabili mo na ang ${NAME}!", + "bombSquadProNameText": "${APP_NAME} Pro", + "bombSquadProNewDescriptionText": "• Nag-aalis ng mga in-game na ad at nag-screen\n• Nagbubukas ng higit pang mga setting ng laro\n• Kasama rin ang:", + "buyText": "Ibili", + "charactersText": "Mga Karakter", + "comingSoonText": "Abangan...", + "extrasText": "Padagdag", + "freeBombSquadProText": "Ang BombSquad ay libre na ngayon, ngunit dahil ikaw ang orihinal na bumili nito, ikaw na\npagtanggap ng BombSquad Pro upgrade at ${COUNT} na mga tiket bilang pasasalamat.\nTangkilikin ang mga bagong feature, at salamat sa iyong suporta!\n-Eric", + "holidaySpecialText": "Espesyal Na Holiday", + "howToSwitchCharactersText": "(pumunta sa \"${SETTINGS} -> ${PLAYER_PROFILES}\" para magtalaga at mag-customize ng mga character)", + "howToUseIconsText": "(gumawa ng mga global profile ng manlalaro (sa window ng account) para magamit ang mga ito)", + "howToUseMapsText": "(gamitin ang mga mapa na ito sa sarili mong Mga Team/Rambulan na mga playlist)", + "iconsText": "Mga Icon", + "loadErrorText": "Hindi ma-load ang page.\nSuriin ang iyong koneksyon sa internet.", + "loadingText": "Saglit lang…", + "mapsText": "Mga Mapa", + "miniGamesText": "Mga MiniGames", + "oneTimeOnlyText": "(isang beses lamang)", + "purchaseAlreadyInProgressText": "Ang isang nabilhin ng item na ito ay isinasagawa na.", + "purchaseConfirmText": "Ibili ang ${ITEM}?", + "purchaseNotValidError": "Hindi wasto ang nabilhin.\nMakipag-ugnayan kay ${EMAIL} kung ito ay isang error.", + "purchaseText": "Bilhin", + "saleBundleText": "Diskwento ng Bundle!", + "saleExclaimText": "Diskwento!", + "salePercentText": "(${PERCENT}% diskwento)", + "saleText": "BAWAS", + "searchText": "Hanapin", + "teamsFreeForAllGamesText": "Mga Team / Rambulan Na Mga Laro", + "totalWorthText": "*** ${TOTAL_WORTH} na halaga! ***", + "upgradeQuestionText": "I-upgrade?", + "winterSpecialText": "Espesyal na Taglamig", + "youOwnThisText": "- nabilhin mo na ito -" + }, + "storeDescriptionText": "8 Player Party Game Kabaliwan!\n\nIsabugin ang iyong mga kaibigan (o ang computer) sa isang tournament ng mga putok na mini-game gaya ng Kunin-Ang-Bandila, Bombang-Hockey, at Epic-Na-Bagalan-Ng-Laban-Ng-Kamatayan!\n\nPinapadali ng mga simpleng kontrol at malawak na suporta sa controller para sa hanggang 8 tao na makilahok sa aksyon; maaari mo ring gamitin ang iyong mga mobile device bilang mga controller sa pamamagitan ng libreng 'BombSquad Remote' app!\n\nIhagis Ang Mga Bomba!\n\nTingnan ang www.froemling.net/bombsquad para sa karagdagang impormasyon.", + "storeDescriptions": { + "blowUpYourFriendsText": "Isabog ang iyong mga kaibigan", + "competeInMiniGamesText": "Makipagkumpitensya sa mga mini-game mula sa takbuan hanggang sa paglipad.", + "customize2Text": "I-customize ang mga character, mini-game, at maging ang mga soundtrack.", + "customizeText": "I-customize ang mga character at gumawa ng sarili mong mga mini-game playlist.", + "sportsMoreFunText": "Mas masaya ang sports na may pampasabog.", + "teamUpAgainstComputerText": "Makipagtulungan laban sa computer." + }, + "storeText": "Tindahan", + "submitText": "Ipasa", + "submittingPromoCodeText": "Nagsusumite ng Code...", + "teamNamesColorText": "Mga Pangalan/Kulay ng Team…", + "telnetAccessGrantedText": "Pinagana ang pag-access sa Telnet..", + "telnetAccessText": "Natuklasan ang pag-access sa Telnet; payagan?", + "testBuildErrorText": "Ang test build na ito ay hindi na aktibo; mangyaring suriin para sa isang bagong bersyon.", + "testBuildText": "Test Build", + "testBuildValidateErrorText": "Hindi ma-validate ang test build. (walang koneksyon sa internet?)", + "testBuildValidatedText": "Na-validate ang Test Build; Tamasahin!", + "thankYouText": "Salamat sa iyong suporta! Tangkilikin ang laro!!", + "threeKillText": "TRIPLENG PAGPATAY!!", + "timeBonusText": "Bonus Ng Oras", + "timeElapsedText": "Oras Na Lumipas", + "timeExpiredText": "Nag-expire Na Ang Oras!", + "timeSuffixDaysText": "${COUNT}d", + "timeSuffixHoursText": "${COUNT}h", + "timeSuffixMinutesText": "${COUNT}m", + "timeSuffixSecondsText": "${COUNT}s", + "tipText": "Tip", + "titleText": "BombSquad", + "titleVRText": "BombSquad VR", + "topFriendsText": "Pangunahing Kaibigan", + "tournamentCheckingStateText": "Sinusuri ang estado ng paligsahan; pakihintay...", + "tournamentEndedText": "Natapos na ang paligsahan na ito. Magsisimula ng bago mamaya.", + "tournamentEntryText": "Pagpasok sa Paligsahan", + "tournamentResultsRecentText": "Mga Resulta ng Kamakailang Paligsahan", + "tournamentStandingsText": "Mga Paninindigan sa Paligsahan", + "tournamentText": "Paligsahan", + "tournamentTimeExpiredText": "Na-expire Na Ang Oras Ng Paligsahan", + "tournamentsText": "Mga Paligsahan", + "translations": { + "characterNames": { + "Agent Johnson": "Ahente Johnson", + "B-9000": "B-9000", + "Bernard": "Oso", + "Bones": "Buto", + "Butch": "Bakero", + "Easter Bunny": "Kuneho", + "Flopsy": "Malambot", + "Frosty": "Taong Niyebe", + "Gretel": "Mag-aawit Na Manananggal", + "Grumbledorf": "Manggagaway", + "Jack Morgan": "Pirata", + "Kronk": "Salbahe", + "Lee": "Lee", + "Lucky": "Swerte", + "Mel": "Malagkitang Pagluto", + "Middle-Man": "Astig Na Lalaki", + "Minimus": "Minimus", + "Pascal": "Ibong Lamig", + "Pixel": "Diwata", + "Sammy Slam": "Mambubuno", + "Santa Claus": "Santa Klaus", + "Snake Shadow": "Aninong Balatkayo", + "Spaz": "Kawal", + "Taobao Mascot": "Taobao Maskot", + "Todd McBurton": "Todd McBurton", + "Zoe": "Dalagang Bombero", + "Zola": "Gererong Babae" + }, + "coopLevelNames": { + "${GAME} Training": "Pagsasanay Sa ${GAME}", + "Infinite ${GAME}": "Walang Katapusang ${GAME}", + "Infinite Onslaught": "Walang Katapusang Pagsalakay", + "Infinite Runaround": "Walang Katapusang Bantayan", + "Onslaught Training": "Pagsasanay Sa Pagsalakay", + "Pro ${GAME}": "Batidong ${GAME}", + "Pro Football": "Batidong Rugbi", + "Pro Onslaught": "Batidong Pagsalakay", + "Pro Runaround": "Batidong Bantayan", + "Rookie ${GAME}": "Bagitong ${GAME}", + "Rookie Football": "Bagitong Rugbi", + "Rookie Onslaught": "Bagitog Pagsalakay", + "The Last Stand": "Ang Huling Labanan", + "Uber ${GAME}": "Kasukdulang ${GAME}", + "Uber Football": "Kasukdulang Rugbi", + "Uber Onslaught": "Kasukdulang Pagsalakay", + "Uber Runaround": "Kasukdulang Bantayan" + }, + "gameDescriptions": { + "Be the chosen one for a length of time to win.\nKill the chosen one to become it.": "Maging ang napili ng tiyak na oras para manalo.\nPatayin ang napili para maging isa nito.", + "Bomb as many targets as you can.": "Bomba ng maraming target hangga't maaari mo.", + "Carry the flag for ${ARG1} seconds.": "Hawakan ang bandila sa loob ng ${ARG1} segundo.", + "Carry the flag for a set length of time.": "Hawakan ang bandila para sa isang nakatakdang haba ng oras.", + "Crush ${ARG1} of your enemies.": "Patayin ang ${ARG1} ng iyong mga kalaban", + "Defeat all enemies.": "Talunin ang lahat ng iyong mga kalaban", + "Dodge the falling bombs.": "Umiwas sa mga bumabagsak na bomba.", + "Final glorious epic slow motion battle to the death.": "Huling maluwalhating epic slow motion na labanan hanggang kamatayan.", + "Gather eggs!": "Ipunin ng mga itlog!", + "Get the flag to the enemy end zone.": "Kunin ang bandila sa end zone ng kalaban.", + "How fast can you defeat the ninjas?": "Gaano kabilis mo matatalo ang mga ninja?", + "Kill a set number of enemies to win.": "Pumatay ng isang set na bilang ng mga kalaban upang manalo.", + "Last one standing wins.": "Kung sino ang huling nakatayo ang siyang mananalo.", + "Last remaining alive wins.": "Kung sino ang huling natitirang buhay ang siyang mananalo.", + "Last team standing wins.": "Kung sino ang huling katayuan ng koponan ang siyang mananalo", + "Prevent enemies from reaching the exit.": "Pigilan ang mga kalaban na makarating at makalabas sa labasan.", + "Reach the enemy flag to score.": "Abutin ang bandila ng kalaban upang maka-iskor.", + "Return the enemy flag to score.": "Ibalik ang watawat ng kalaban upang maka-iskor.", + "Run ${ARG1} laps.": "Tumakbo ng ${ARG1} ikot", + "Run ${ARG1} laps. Your entire team has to finish.": "Tumakbo ng {ARG1} ikot. Kailangang matapos ang iyong buong team na ito.", + "Run 1 lap.": "Tumakbo ng 1 ikot.", + "Run 1 lap. Your entire team has to finish.": "Tumakbo ng 1 ikot. Kailangang matapos ang iyong buong team na ito.", + "Run real fast!": "Tumakbo ng mabilis!", + "Score ${ARG1} goals.": "Makaiskor ng ${ARG1} gol.", + "Score ${ARG1} touchdowns.": "Makaiskor ng ${ARG1} touchdowns.", + "Score a goal.": "Makaiskor ng isang gol.", + "Score a touchdown.": "Makaiskor ng isang touchdown.", + "Score some goals.": "Makaiskor ng ilang gol.", + "Secure all ${ARG1} flags.": "Bantayinang lahat ng ${ARG1} na bandila.", + "Secure all flags on the map to win.": "Bantayin ang lahat ng mga bandila sa mapa na ito upang manalo.", + "Secure the flag for ${ARG1} seconds.": "Bantayin ang bandila ng ${ARG1} segundo", + "Secure the flag for a set length of time.": "Bantayin ang banila sa isang nakatakdang haba ng oras.", + "Steal the enemy flag ${ARG1} times.": "Nakawin ang watawat ng kalaban ng ${ARG1} beses.", + "Steal the enemy flag.": "Nakawin ang watawat ng kalaban.", + "There can be only one.": "Maaaring isa lamang dito.", + "Touch the enemy flag ${ARG1} times.": "Humawak sa bandera ng iyong kalaban ng ${ARG1} beses.", + "Touch the enemy flag.": "Humawak sa bandera ng iyong kalaban.", + "carry the flag for ${ARG1} seconds": "Hawakan ang bandila ng ${ARG1} segundo", + "kill ${ARG1} enemies": "patayin ang ${ARG1} na mga kalaban.", + "last one standing wins": "kung sino ang huling nakatayo ang siyang mananalo", + "last team standing wins": "kung sino ang huling katayuan ng team ang siyang mananalo", + "return ${ARG1} flags": "ibalik ang ${ARG1} na mga bandera", + "return 1 flag": "ibalik ang 1 bandila", + "run ${ARG1} laps": "Tumakbo ng ${ARG1} ikot", + "run 1 lap": "tumakbo ng 1 ikot", + "score ${ARG1} goals": "makaiskor ng ${ARG1} gol", + "score ${ARG1} touchdowns": "makaiskor ng ${ARG1} touchdowns", + "score a goal": "makaiskor ng isang gol.", + "score a touchdown": "makaiskor ng isang touchdown.", + "secure all ${ARG1} flags": "bantayin ang lahat ng ${ARG1} na bandila", + "secure the flag for ${ARG1} seconds": "bantayin ang bandila ng ${ARG1} segundo", + "touch ${ARG1} flags": "humawak ng ${ARG1} na mga bandila", + "touch 1 flag": "humawak ng 1 bandila" + }, + "gameNames": { + "Assault": "Pag-atake", + "Capture the Flag": "Kunin ang Bandila", + "Chosen One": "Napili ang Isa", + "Conquest": "Pagsakop", + "Death Match": "Laban ng Kamatayan", + "Easter Egg Hunt": "Paghahanap ng mga Easter Egg", + "Elimination": "Kaligtasan", + "Football": "Rugbi", + "Hockey": "Hockey", + "Keep Away": "Layuan Mo", + "King of the Hill": "Hari ng Burol", + "Meteor Shower": "Ulan ng mga Bulalakaw", + "Ninja Fight": "Labanan ng mga Ninja", + "Onslaught": "Pagsalakay", + "Race": "Takbuan", + "Runaround": "Bantayan", + "Target Practice": "Pagsasanay ng Patamaan", + "The Last Stand": "Ang Huling Labanan" + }, + "inputDeviceNames": { + "Keyboard": "Keyboard", + "Keyboard P2": "Keyboard F2" + }, + "languages": { + "Arabic": "Arabe", + "Belarussian": "Belaruso", + "Chinese": "Tsino Na Pinasimple", + "ChineseTraditional": "Intsik", + "Croatian": "Kroatyano", + "Czech": "Tsek", + "Danish": "Makadenmark", + "Dutch": "Olandes", + "English": "Ingles", + "Esperanto": "Esperanto", + "Filipino": "Tagalog", + "Finnish": "Finnish", + "French": "Pranses", + "German": "Aleman", + "Gibberish": "Pagyayapyap", + "Greek": "Griyego", + "Hindi": "Indiyano", + "Hungarian": "Hanggaryan", + "Indonesian": "Indonesiyo", + "Italian": "Italiyano", + "Japanese": "Nippongo", + "Korean": "Koreano", + "Persian": "Persyano", + "Polish": "Polish", + "Portuguese": "Portuges", + "Romanian": "Rumano", + "Russian": "Ruso", + "Serbian": "Serbyan", + "Slovak": "Eslobako", + "Spanish": "Espanyol", + "Swedish": "Suweko", + "Tamil": "Tamil", + "Thai": "Siyam", + "Turkish": "Turko", + "Ukrainian": "Ukranyo", + "Venetian": "Benesiya", + "Vietnamese": "Byetnam" + }, + "leagueNames": { + "Bronze": "Tanso", + "Diamond": "Diyamante", + "Gold": "Ginto", + "Silver": "Pilak" + }, + "mapsNames": { + "Big G": "Malaking G", + "Bridgit": "Tawiring Tulay", + "Courtyard": "Looban Patyo", + "Crag Castle": "Kastilyong Bangin", + "Doom Shroom": "Itim na Kabute", + "Football Stadium": "Istadyum", + "Happy Thoughts": "Masayang Isip", + "Hockey Stadium": "Istadyum ng Hockey", + "Lake Frigid": "Yelong Lawa", + "Monkey Face": "Mukha ng Unggoy", + "Rampage": "Mandaluhong", + "Roundabout": "Paliguy-ligoy", + "Step Right Up": "Hakbang Pataas", + "The Pad": "Ang Pad", + "Tip Top": "Tulis na Mataas", + "Tower D": "Taasang D", + "Zigzag": "Sigsag" + }, + "playlistNames": { + "Just Epic": "Epic Lang", + "Just Sports": "Shorts Lang" + }, + "scoreNames": { + "Flags": "Watawat", + "Goals": "Layunin", + "Score": "Iskor", + "Survived": "Nakaligtas", + "Time": "Oras", + "Time Held": "Oras na Gaganapin" + }, + "serverResponses": { + "A code has already been used on this account.": "Nagamit na ang isang code sa account na ito.", + "A reward has already been given for that address.": "Naibigay na ang reward para sa address na iyon.", + "Account linking successful!": "Matagumpay ang pag-link ng account!", + "Account unlinking successful!": "Matagumpay ang pag-unlink ng account!", + "Accounts are already linked.": "Naka-link na ang mga account.", + "Ad view could not be verified.\nPlease be sure you are running an official and up-to-date version of the game.": "Hindi ma-verify ang ad view.\nMangyaring siguraduhin na ikaw ay nagpapatakbo ng isang opisyal at bago na bersyon ng laro.", + "An error has occurred; (${ERROR})": "May nangyaring pagakamali; (${ERROR})", + "An error has occurred; please contact support. (${ERROR})": "May nangyaring pagakamali; mangyaring makipag-ugnayan sa contact support. (${ERROR})", + "An error has occurred; please contact support@froemling.net.": "May nangyaring pagakamali; mangyaring makipag-ugnayan sa support@froemling.net.", + "An error has occurred; please try again later.": "May nangyaring pagakamali; Subukang muli mamaya.", + "Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "Sigurado ka bang gusto mong i-link ang mga account na ito?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nHindi na ito maaaring bawiin!", + "BombSquad Pro unlocked!": "Na-unlock ang BombSquad Pro!", + "Can't link 2 accounts of this type.": "Hindi ma-link ang 2 account na may ganitong uri.", + "Can't link 2 diamond league accounts.": "Hindi ma-link ang 2 dyamante na ligang account.", + "Can't link; would surpass maximum of ${COUNT} linked accounts.": "Hindi ma-link; ito ay lalampas sa maximum na ${COUNT} na naka-link na account.", + "Cheating detected; scores and prizes suspended for ${COUNT} days.": "Natukoy ang pagdadaya; nasuspinde ang mga iskor at premyo sa loob ng ${COUNT} (na) araw.", + "Could not establish a secure connection.": "Hindi makapagtatag ng secure na koneksyon.", + "Daily maximum reached.": "Naabot na ang pang-araw-araw ng request.", + "Entering tournament...": "Papasok sa paligsahan…", + "Invalid code.": "Di-wastong code.", + "Invalid payment; purchase canceled.": "Di-wastong pagbabayad; kinansela ang pagbili.", + "Invalid promo code.": "Di-wastong promo code.", + "Invalid purchase.": "Di-wastong bilihin", + "Invalid tournament entry; score will be ignored.": "Di-wastong entry sa paligsahan; hindi papansinin ang mga iskor.", + "Item unlocked!": "Na-unlock ang aytem!", + "LINKING DENIED. ${ACCOUNT} contains\nsignificant data that would ALL BE LOST.\nYou can link in the opposite order if you'd like\n(and lose THIS account's data instead)": "TINANGGI ANG PAG-LINK. Naglalaman ang ${ACCOUNT}.\nmakabuluhang data na MAWAWALA LAHAT.\nMaaari kang mag-link sa kabaligtaran na pagkakasunud-sunod kung gusto mo\n(at sa halip ay mawala ang data ng account na ITO)", + "Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "I-link ang account na ${ACCOUNT} sa account na ito?\nMawawala ang lahat ng umiiral na data sa ${ACCOUNT}.\nHindi na ito maaaring bawiin. Sigurado ka ba?", + "Max number of playlists reached.": "Naabot na ang maximum na bilang ng mga playlist.", + "Max number of profiles reached.": "Naabot na ang maximum na bilang ng mga profile.", + "Maximum friend code rewards reached.": "Naabot ang maximum na mga reward sa code ng kaibigan.", + "Message is too long.": "Ang mensahe ay napakataas.", + "No servers are available. Please try again soon.": "Walang makakuha na mga server. Pakisubukang muli sa lalong madaling oras.", + "Profile \"${NAME}\" upgraded successfully.": "Matagumpay na na-upgrade ang profile na \"${NAME}\".", + "Profile could not be upgraded.": "Hindi ma-upgrade ang profile.", + "Purchase successful!": "Matagumpay ang pagbili!", + "Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "Nakatanggap ng ${COUNT} na tiket para sa pag-sign in.\nBumalik bukas para makatanggap ng ${TOMORROW_COUNT}.", + "Server functionality is no longer supported in this version of the game;\nPlease update to a newer version.": "Hindi na sinusuportahan ang functionality ng server sa bersyong ito ng laro;\nMangyaring mag-update sa isang mas bagong bersyon.", + "Sorry, there are no uses remaining on this code.": "Pasensya na, wala nang natitirang gamit sa code na ito.", + "Sorry, this code has already been used.": "Pasensya na, nagamit na ang code na ito.", + "Sorry, this code has expired.": "Pasensya na, nag-expire na ang code na ito.", + "Sorry, this code only works for new accounts.": "Pasensya na, gumagana lang ang code na ito para sa mga bagong account.", + "Still searching for nearby servers; please try again soon.": "Naghahanap pa rin ng mga kalapit na server; mangyaring subukan muli sa lalong madaling oras.", + "Temporarily unavailable; please try again later.": "Pansamantalang hindi magagamit; Subukang muli mamaya.", + "The tournament ended before you finished.": "Natapos ang tournament bago ka natapos.", + "This account cannot be unlinked for ${NUM} days.": "Ang account na ito ay hindi maaaring i-unlink sa loob ng ${NUM} (na) araw.", + "This code cannot be used on the account that created it.": "Hindi magagamit ang code na ito sa account na lumikha nito.", + "This is currently unavailable; please try again later.": "Ito ay kasalukuyang hindi magagamit; Subukang muli mamaya.", + "This requires version ${VERSION} or newer.": "Nangangailangan ito ng bersyon na ${VERSION} o mas bago.", + "Tournaments disabled due to rooted device.": "Na-disable ang mga tournament dahil sa na-root na device.", + "Tournaments require ${VERSION} or newer": "Ang mga paligsahan ay nangangailangan ng ${VERSION} o mas bago", + "Unlink ${ACCOUNT} from this account?\nAll data on ${ACCOUNT} will be reset.\n(except for achievements in some cases)": "I-unlink ang ${ACCOUNT} mula sa account na ito?\nIre-reset ang lahat ng data sa ${ACCOUNT}.\n(maliban sa mga nakamit sa ilang pagkakataon)", + "WARNING: complaints of hacking have been issued against your account.\nAccounts found to be hacking will be banned. Please play fair.": "BABALA: ang mga reklamo ng pag-hack ay inilabas laban sa iyong account.\nIpagbabawal ang mga account na makikitang nagha-hack. Mangyaring maglaro ng patas.", + "Would you like to link your device account to this one?\n\nYour device account is ${ACCOUNT1}\nThis account is ${ACCOUNT2}\n\nThis will allow you to keep your existing progress.\nWarning: this cannot be undone!\n": "Gusto mo bang i-link ang iyong device account sa isang ito?\n\nAng iyong device account ay ${ACCOUNT1}\nAng account na ito ay ${ACCOUNT2}\n\nPapayagan ka nitong panatilihin ang iyong progress.\nBabala: hindi na ito maaaring bawiin!", + "You already own this!": "Nabili mo na ito!", + "You can join in ${COUNT} seconds.": "Makakasali ka sa loob ng ${COUNT} segundo.", + "You don't have enough tickets for this!": "Hindi sapat ang tickets mo para dito!", + "You don't own that.": "Hindi sayo iyan.", + "You got ${COUNT} tickets!": "Nakakuha ka ng ${COUNT} tickets!", + "You got a ${ITEM}!": "Nakakuha ka ng ${ITEM}!", + "You have been promoted to a new league; congratulations!": "Na-promote ka sa isang bagong liga; congrats!", + "You must update to a newer version of the app to do this.": "Dapat kang mag-update sa mas bagong bersyon ng app para magawa ito.", + "You must update to the newest version of the game to do this.": "Dapat kang mag-update sa pinakabagong bersyon ng laro upang magawa ito.", + "You must wait a few seconds before entering a new code.": "Dapat kang maghintay ng ilang segundo bago maglagay ng bagong code.", + "You ranked #${RANK} in the last tournament. Thanks for playing!": "Ikaw ay niraranggo ng #${RANK} sa huling paligsahan. Salamat sa paglalaro!", + "Your account was rejected. Are you signed in?": "Tinanggihan ang iyong account. Naka-sign in ka ba?", + "Your copy of the game has been modified.\nPlease revert any changes and try again.": "Ang iyong kopya ng laro ay na-modified.\nMangyaring ibalik ang anumang mga pagbabago at subukang muli.", + "Your friend code was used by ${ACCOUNT}": "Ang code ng iyong kaibigan ay ginamit ng ${ACCOUNT}" + }, + "settingNames": { + "1 Minute": "1 Minuto", + "1 Second": "1 Segundo", + "10 Minutes": "10 Minuto", + "2 Minutes": "2 minuto", + "2 Seconds": "2 segundo", + "20 Minutes": "20 minuto", + "4 Seconds": "4 segundo", + "5 Minutes": "5 minuto", + "8 Seconds": "8 segundo", + "Allow Negative Scores": "Payagan ang Mga Negatibong Iskor", + "Balance Total Lives": "Balansehin ang Kabuuang Buhay", + "Bomb Spawning": "Paglitaw ng Bomba", + "Chosen One Gets Gloves": "Ang Isa Sa Napili Ay Makukuha Ng Gloves", + "Chosen One Gets Shield": "Ang Isa Sa Napili Ay Makukuha Ng Kalasag", + "Chosen One Time": "Oras Ng Isa Sa Napili", + "Enable Impact Bombs": "I-enable Ang Mga Gatilyong Bomba", + "Enable Triple Bombs": "I-enable Ang Mga Tatlong Bomba", + "Entire Team Must Finish": "Dapat Tapusin ng Buong Team.", + "Epic Mode": "Epic na Mode", + "Flag Idle Return Time": "Oras Ang Hindi Paggalaw Ng Watawat", + "Flag Touch Return Time": "Oras Sa Pag-balik Na Paghawak Ng Watawat", + "Hold Time": "Oras Ng Paghahawak", + "Kills to Win Per Player": "Pumapatay sa Pagpanalo Bawat Manlalaro", + "Laps": "Mga Lap", + "Lives Per Player": "Mga Buhay Bawat Manlalaro", + "Long": "Matagal", + "Longer": "Mas Matagal", + "Mine Spawning": "Lumilitaw Ng Mina", + "No Mines": "Bawal Ang Mina", + "None": "Wala", + "Normal": "Normal", + "Pro Mode": "Pangmagalingan Mode", + "Respawn Times": "Oras Sa Pag-respawn", + "Score to Win": "Iskor Para Manalo", + "Short": "Maikli", + "Shorter": "Mas Maikli", + "Solo Mode": "Mapagisa Mode", + "Target Count": "Bilang ng target", + "Time Limit": "Limitadong oras" + }, + "statements": { + "${TEAM} is disqualified because ${PLAYER} left": "Na-disqualify ang ${TEAM} dahil umalis si ${PLAYER}.", + "Killing ${NAME} for skipping part of the track!": "Pinapatayin si ${NAME} dahil sa paglaktaw sa bahagi ng track!", + "Warning to ${NAME}: turbo / button-spamming knocks you out.": "Babala kay ${NAME}: turbo / button-spamming ang pagpapatayin sayo." + }, + "teamNames": { + "Bad Guys": "Mga masasama", + "Blue": "Asul", + "Good Guys": "Mga mabubuti", + "Red": "Pula" + }, + "tips": { + "A perfectly timed running-jumping-spin-punch can kill in a single hit\nand earn you lifelong respect from your friends.": "Ang isang perpektong naka-time na takbo-talon-ikot-suntok ay maaaring makapatay sa isang hit\nat magkaroon ka ng panghabambuhay na paggalang mula sa iyong mga kaibigan.", + "Always remember to floss.": "Laging tandaan na mag-floss.", + "Create player profiles for yourself and your friends with\nyour preferred names and appearances instead of using random ones.": "Gumawa ng mga profile ng player para sa iyong sarili at sa iyong mga kaibigan\nang iyong mga gustong pangalan at hitsura sa halip na gumamit ng mga random.", + "Curse boxes turn you into a ticking time bomb.\nThe only cure is to quickly grab a health-pack.": "Ginagawa ka ng sumpa sa isang ticking time na bomba.\nAng tanging lunas ay ang mabilisang kumuha ng health-pack.", + "Despite their looks, all characters' abilities are identical,\nso just pick whichever one you most closely resemble.": "Sa kabila ng kanilang hitsura, lahat ng kakayahan ng mga karakter ay magkapareho,\nkaya pumili lang kung alin ang pinakahawig mo.", + "Don't get too cocky with that energy shield; you can still get yourself thrown off a cliff.": "Huwag masyadong maangas sa enerhiya na kalasag na iyon; ihahagis ka nila sa isang platform", + "Don't run all the time. Really. You will fall off cliffs.": "Huwag tumakbo sa lahat ng oras. Talaga. Mahuhulog ka sa platform", + "Don't spin for too long; you'll become dizzy and fall.": "Huwag paikutin nang masyadong mahaba; mahihilo ka at mahulog.", + "Hold any button to run. (Trigger buttons work well if you have them)": "Pindutin ang anumang pindutan upang tumakbo. (Mahusay na gumagana ang mga pindutan ng pag-trigger kung mayroon ka nito)", + "Hold down any button to run. You'll get places faster\nbut won't turn very well, so watch out for cliffs.": "Pindutin nang matagal ang anumang button para tumakbo. Mas mabilis kang makakakuha ng mga lugar\nngunit hindi lumiko nang mahusay, kaya mag-ingat sa matalim na mga gilid", + "Ice bombs are not very powerful, but they freeze\nwhoever they hit, leaving them vulnerable to shattering.": "Ang mga bomba ng yelo ay hindi masyadong malakas, ngunit nagyeyelo\nkung sino man ang kanilang natamaan, na nag-yelo sa kanila na madaling masira.", + "If someone picks you up, punch them and they'll let go.\nThis works in real life too.": "Kung may napulot sa iyo, suntukin mo siya at bibitaw siya.\nGumagana rin ito sa totoong buhay.", + "If you are short on controllers, install the '${REMOTE_APP_NAME}' app\non your mobile devices to use them as controllers.": "Kung kulang ka sa mga controller, i-install ang '${REMOTE_APP_NAME}' app\nsa iyong mga mobile device upang gamitin ang mga ito bilang mga controller.", + "If you get a sticky-bomb stuck to you, jump around and spin in circles. You might\nshake the bomb off, or if nothing else your last moments will be entertaining.": "Kung nakadikit sa iyo ang isang malagkit na bomba, tumalon at paikutin. Baka \ni-alis mo ang bomba, o kung wala na ang iyong mga huling sandali ay nakakaaliw.", + "If you kill an enemy in one hit you get double points for it.": "Kung pumatay ka ng isang kalaban sa isang hit makakakuha ka ng dobleng puntos para dito.", + "If you pick up a curse, your only hope for survival is to\nfind a health powerup in the next few seconds.": "Kung nakatanggap ka ng sumpa, ang tanging pag-asa mo para mabuhay ay\nmaghanap ng health powerup sa susunod na ilang segundo.", + "If you stay in one place, you're toast. Run and dodge to survive..": "Kung manatili ka sa isang lugar, toasted ka. Tumakbo at umigtad para mabuhay..", + "If you've got lots of players coming and going, turn on 'auto-kick-idle-players'\nunder settings in case anyone forgets to leave the game.": "Kung marami kang manlalaro na dumarating at pupunta, i-on ang 'auto-kick-ng-idle-na-manlalaro’\nsa ilalim ng mga setting kung sakaling may makakalimutang umalis sa laro.", + "If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "Kung masyadong mainit ang iyong device o gusto mong makatipid ng baterya,\ni-down ang \"Biswal” o \"Resolusyon\" sa Mga Setting->Grapika", + "If your framerate is choppy, try turning down resolution\nor visuals in the game's graphics settings.": "Kung hindi mabuti ang iyong framerate, subukang ibaba ang resolusyon\no mga biswal sa mga setting ng grapika ng laro.", + "In Capture-the-Flag, your own flag must be at your base to score, If the other\nteam is about to score, stealing their flag can be a good way to stop them.": "Sa Kunin-ang-Bandila, ang iyong sariling bandila ay dapat nasa iyong base para makaiskor, Kung ang isa\nang team ay malapit nang makapuntos, ang pagnanakaw ng kanilang bandila ay maaaring maging isang magandang paraan upang pigilan sila.", + "In hockey, you'll maintain more speed if you turn gradually.": "Sa hockey, mapapanatili mo ang higit na bilis kung unti-unti kang lumiko.", + "It's easier to win with a friend or two helping.": "mas madaling manalo sa tulong ng isa o dalawang kaibigan.", + "Jump just as you're throwing to get bombs up to the highest levels.": "Tumalon habang humagis upang makakuha ng mga bomba hanggang sa pinakamataas na antas.", + "Land-mines are a good way to stop speedy enemies.": "Ang mga mina ay isang mahusay na paraan upang pigilan ang mabilis na mga kalaban.", + "Many things can be picked up and thrown, including other players. Tossing\nyour enemies off cliffs can be an effective and emotionally fulfilling strategy.": "Maraming bagay ang maaaring kunin at ihagis, kabilang ang iba pang mga manlalaro. Paghahagis\nang iyong mga kalaban mula sa mga gilid ay maaaring maging isang epektibo at emosyonal na diskarte.", + "No, you can't get up on the ledge. You have to throw bombs.": "Hindi, hindi ka makakabangon sa pag-ungos. Kailangan mong maghagis ng bomba.", + "Players can join and leave in the middle of most games,\nand you can also plug and unplug controllers on the fly.": "Maaaring sumali at umalis ang mga manlalaro sa gitna ng karamihan ng mga laro,\nat maaari mo ring isaksak at i-unplug ang mga controller nang mabilis.", + "Practice using your momentum to throw bombs more accurately.": "Magsanay gamit ang iyong momentum para maghagis ng mga bomba nang mas tumpak.", + "Punches do more damage the faster your fists are moving,\nso try running, jumping, and spinning like crazy.": "Ang mga suntok ay mas nagdudulot ng saktan sa mas mabilis na paggalaw ng iyong mga kamay,\nkaya subukang tumakbo, tumalon, at umiikot na parang baliw.", + "Run back and forth before throwing a bomb\nto 'whiplash' it and throw it farther.": "Patakbong pabalik-balik bago maghagis ng bomba\nupang ‘ma-ikot’ ito at ihagis ito nang mas malayo.", + "Take out a group of enemies by\nsetting off a bomb near a TNT box.": "Ilabas ang isang grupo ng mga kalaban sa pamamagitan ng\nnaglalagay ng bomba malapit sa isang TNT box.", + "The head is the most vulnerable area, so a sticky-bomb\nto the noggin usually means game-over.": "Ang ulo ay ang pinaka-mahina na lugar, kaya isang malagkit-bomba \nna lumapag sa ulo mo ay game-over na.", + "This level never ends, but a high score here\nwill earn you eternal respect throughout the world.": "Ang level na ito ay hindi kailanman nagtatapos, ngunit isang mataas na iskor dito\nbibigyan ka ng walang hanggang paggalang sa buong mundo.", + "Throw strength is based on the direction you are holding.\nTo toss something gently in front of you, don't hold any direction.": "Ang lakas ng paghagis ay batay sa direksyon na iyong hinahawakan.\nUpang ihagis ang isang bagay nang malumanay sa harap mo, huwag humawak sa anumang direksyon.", + "Tired of the soundtrack? Replace it with your own!\nSee Settings->Audio->Soundtrack": "Pagod na sa mga soundtrack? Palitan nito ng iyong sarili!\nTingnan ang Mga Setting->Audio->Soundtrack", + "Try 'Cooking off' bombs for a second or two before throwing them.": "Try mo ‘I-timing” ang mga bomba sa isang segundo o dalawa bag mo ihagis.", + "Try tricking enemies into killing eachother or running off cliffs.": "Subukang linlangin ang mga kalaban sa pagpatay sa isa't isa o pahulog sa mga gilid.", + "Use the pick-up button to grab the flag < ${PICKUP} >": "Gamitin ang pick-up button para kunin ang bandera < ${PICKUP} >", + "Whip back and forth to get more distance on your throws..": "Paikut-ikot upang makakuha ng higit na distansya sa iyong mga paghagis..", + "You can 'aim' your punches by spinning left or right.\nThis is useful for knocking bad guys off edges or scoring in hockey.": "Maaari mong 'itutok' ang iyong mga suntok sa pamamagitan ng pag-ikot pakaliwa o pakanan.\nIto ay kapaki-pakinabang para sa pagtanggal ng mga kalaban sa mga gilid o pag-iskor sa hockey.", + "You can judge when a bomb is going to explode based on the\ncolor of sparks from its fuse: yellow..orange..red..BOOM.": "Maaari mong hatulan kung kailan sasabog ang isang bomba batay sa\nkulay ng sparks mula sa fuse nito: Dilaw..Kahel..Pula..SABOG.", + "You can throw bombs higher if you jump just before throwing.": "Maaari kang maghagis ng mga bomba nang mas mataas kung tumalon ka bago ihagis.", + "You take damage when you whack your head on things,\nso try to not whack your head on things.": "Pwede kang masaktan kapag natamaan mo ang iyong ulo sa mga bagay,\nkaya't subukang huwag ipilit ang iyong ulo sa iyan.", + "Your punches do much more damage if you are running or spinning.": "Ang iyong mga suntok ay nagdudulot ng higit na damage kung ikaw ay tumatakbo o umiikot." + } + }, + "trophiesRequiredText": "Nangangailangan ito ng ${NUMBER} na trophies.", + "trophiesText": "Mga Tropeo", + "trophiesThisSeasonText": "Mga Tropeo Ngayong Season", + "tutorial": { + "cpuBenchmarkText": "Pagpapatakbo ng tutorial sa nakakatawang bilis (pangunahing test sa bilis ng CPU)", + "phrase01Text": "Kamusta!", + "phrase02Text": "Maligayang pagdating sa ${APP_NAME}!", + "phrase03Text": "Narito ang ilang mga tip para sa pagkontrol ng iyong karakter:", + "phrase04Text": "Maraming bagay sa ${APP_NAME} ang nakabatay sa PISIKA", + "phrase05Text": "Halimbawa, kapag sumuntok ka,..", + "phrase06Text": "..binase ang damage sa bilis ng mga kamay mo.", + "phrase07Text": "Kita mo? Hindi kami gumagalaw, kaya halos hindi nasaktan si ${NAME}", + "phrase08Text": "Ngayon, tumalon at umikot tayo upang makakuha ng higit na bilis.", + "phrase09Text": "Ayan, mas maganda", + "phrase10Text": "Ang pagtakbo ay nakakatulong din.", + "phrase11Text": "Pindutin nang matagal ang KAHIT ANONG pindutan para tumakbo.", + "phrase12Text": "Para sa sobrang kahanga-hangang mga suntok, subukang tumakbo AT umikot.", + "phrase13Text": "Oops; pasensya na ${NAME}.", + "phrase14Text": "Maaari mong kunin at ihagis ang mga bagay tulad ng mga bandera.. o si ${NAME}.", + "phrase15Text": "Sa huli, meron pampasabog", + "phrase16Text": "Ang paghagis ng bomba ay kailangan may practice", + "phrase17Text": "Aray! Hindi napakahusay na hagis.", + "phrase18Text": "Ang paggalaw ay nakakatulong sa iyo na ihagis ng mas malayo.", + "phrase19Text": "Ang pagtalon tumutulong para matapon mo na masmataas", + "phrase20Text": "Ikot at ihagis ang iyong mga bomba para sa mas mahabang paghagis.", + "phrase21Text": "Ang pagtiming sa bomba ay pwedeng tricky", + "phrase22Text": "Aba.", + "phrase23Text": "Subukang “i-timing” fuse para sa isang segundo o dalawa.", + "phrase24Text": "Yay! Magaling na gawa.", + "phrase25Text": "Well, hanggang doon lang.", + "phrase26Text": "Ngayon kunin mo sila, tigre!", + "phrase27Text": "Alalahanin ang iyong pagsasanay, at babalik KANG buhay!", + "phrase28Text": "...siguro...", + "phrase29Text": "Paalam!", + "randomName1Text": "Fernandez", + "randomName2Text": "Angelo", + "randomName3Text": "Stephen", + "randomName4Text": "Joshua", + "randomName5Text": "Villar", + "skipConfirmText": "Sure ka na i-skip ang tutorial? Tap o pindutin para ma i-confirm.", + "skipVoteCountText": "${COUNT}/${TOTAL} boto na gustong laktawan", + "skippingText": "Nilalaktawan ang tutorial", + "toSkipPressAnythingText": "(i-tap o pindutin ang anuman para laktawan ang tutorial)" + }, + "twoKillText": "DOBLENG PAGPATAY!!", + "unavailableText": "hindi available", + "unconfiguredControllerDetectedText": "Naktuklas ang hindi naka-configure na controller:", + "unlockThisInTheStoreText": "Ito ay dapat na naka-unlock sa tindahan.", + "unlockThisProfilesText": "Upang lumikha ng higit sa ${NUM} na mga profile, kailangan mo:", + "unlockThisText": "Upang i-unlock ito, kailangan mo ng:", + "unsupportedHardwareText": "Pasensya na, ang hardware na ito ay hindi suportado ng build na ito ng laro.", + "upFirstText": "Bumangon muna:", + "upNextText": "Susunod sa larong ${COUNT}:", + "updatingAccountText": "Ina-update ang iyong account...", + "upgradeText": "I-upgrade", + "upgradeToPlayText": "I-unlock ang \"${PRO}\" sa in-game store upang i-play ito.", + "useDefaultText": "Gamitin ang default", + "usesExternalControllerText": "Gumagamit ang larong ito ng external na controller para sa input.", + "usingItunesText": "Paggamit ng Music App para sa soundtrack...", + "validatingTestBuildText": "Pinapatunayan ang Test Build...", + "victoryText": "Panalo!", + "voteDelayText": "Hindi ka makapagsimula ng bagong botohan sa ${NUMBER} segundo", + "voteInProgressText": "Ang pagboboto ay isinasagawa na.", + "votedAlreadyText": "Nakaboto ka na", + "votesNeededText": "Kailangan ng ${NUMBER} (na) boto", + "vsText": "vs.", + "waitingForHostText": "(naghihintay para sa ${HOST} na magpatuloy)", + "waitingForPlayersText": "naghihintay ng mga manlalaro na sumali...", + "waitingInLineText": "Naghihintay sa pila (puno ang party)...", + "watchAVideoText": "Manood ng Isang video", + "watchAnAdText": "Manood ng Ad", + "watchWindow": { + "deleteConfirmText": "Tangalin \"${REPLAY}\"?", + "deleteReplayButtonText": "Itanggal ang \nReplay", + "myReplaysText": "Ang Mga Replay Ko", + "noReplaySelectedErrorText": "Walang Napiling Replay", + "playbackSpeedText": "Bilis ng Pag-playback: ${SPEED}", + "renameReplayButtonText": "I-palitan ang\nReplay", + "renameReplayText": "Palitan ang pangalan ng \"${REPLAY}\" sa:", + "renameText": "I-palitan", + "replayDeleteErrorText": "Error sa pagtanggal ng replay", + "replayNameText": "Pangalan ng Replay", + "replayRenameErrorAlreadyExistsText": "Mayroon nang replay na may ganoong pangalan.", + "replayRenameErrorInvalidName": "Hindi mapalitan ang pangalan ng replay; hindi wastong pangalan.", + "replayRenameErrorText": "Error sa pagpapalit ng pangalan ng replay.", + "sharedReplaysText": "Ang mga binigay na replays", + "titleText": "Manood", + "watchReplayButtonText": "Ipanood ang\nReplay" + }, + "waveText": "Kaway", + "wellSureText": "Oo syempre", + "wiimoteLicenseWindow": { + "titleText": "Copyright ni DarwiinRemote" + }, + "wiimoteListenWindow": { + "listeningText": "Nakikinig sa Wiimote...", + "pressText": "Pindutin ang mga pindutan ng Wiimote 1 at 2 nang sabay-sabay.", + "pressText2": "Sa mas bagong Wiimotes na may built in na Motion Plus, pindutin na lang ang pulang 'sync' na button sa likod." + }, + "wiimoteSetupWindow": { + "copyrightText": "Copyright ni DarwinRemote", + "listenText": "Makinig", + "macInstructionsText": "Tiyaking naka-off ang iyong Wii at naka-enable ang Bluetooth\nsa iyong Mac, pagkatapos ay pindutin ang 'Makinig'. Maaari ang suporta ng Wiimote\nmaging medyo patumpik-tumpik, kaya maaaring kailanganin mong subukan ng ilang beses\nbago ka magkaroon ng koneksyon.\n\nDapat hawakan ng Bluetooth ang hanggang 7 konektadong device,\nkahit na ang iyong mileage ay maaaring mag-iba.\n\nSinusuportahan ng BombSquad ang orihinal na Wiimotes, Nunchuks,\nat ang Klasikong Controller.\nGumagana na rin ang mas bagong Wii Remote Plus\nngunit hindi sa mga kalakip.", + "thanksText": "Salamat sa DarwiinRemote team\nPara maging posible ito.", + "titleText": "Wiimote Setup" + }, + "winsPlayerText": "${NAME} Nanalo!", + "winsTeamText": "${NAME} Nanalo!", + "winsText": "${NAME} Nanalo!", + "worldScoresUnavailableText": "Ang scores sa buong mundo ay hindi pa handa", + "worldsBestScoresText": "Pinakamahusay na Iskor ng Mundo", + "worldsBestTimesText": "Pinakamahusay na Oras sa Mundo", + "xbox360ControllersWindow": { + "getDriverText": "Kunin ang Driver", + "macInstructions2Text": "Upang gumamit ng mga controller nang wireless, kakailanganin mo rin ang receiver na iyon\nay kasama ang 'Xbox 360 Wireless Controller para sa Windows'.\nPinapayagan ka ng isang receiver na kumonekta hanggang sa 4 na controllers.\n\nMahalaga: Ang mga 3rd-party na receiver ay hindi gagana sa driver na ito;\ntiyaking 'Microsoft' ang nakasulat dito sa iyong receiver, hindi 'XBOX 360'.\nHindi na ibinebenta ng Microsoft ang mga ito nang hiwalay, kaya kakailanganin mong makuha\nyung naka-bundle sa controller or else search ebay.\n\nKung sa tingin mo ay kapaki-pakinabang ito, mangyaring isaalang-alang ang isang donasyon sa\ndeveloper ng driver sa kanilang site.", + "macInstructionsText": "Upang magamit ang mga controller ng Xbox 360, kakailanganin mong mag-install\nang Mac driver na available sa link sa ibaba.\nGumagana ito sa parehong wired at wireless controllers.", + "ouyaInstructionsText": "Para gumamit ng mga wired na Xbox 360 controllers sa BombSquad, simple lang\nisaksak ang mga ito sa USB port ng iyong device. Maaari kang gumamit ng USB hub\nupang ikonekta ang maramihang mga controller.\n\nPara gumamit ng mga wireless na controller, kakailanganin mo ng wireless na receiver,\nmagagamit bilang bahagi ng \"Xbox 360 wireless Controller para sa Windows\"\npakete o ibinebenta nang hiwalay. Ang bawat receiver ay nakasaksak sa isang USB port at\nnagbibigay-daan sa iyong kumonekta ng hanggang 4 na wireless controllers.", + "titleText": "Ginagamit ang Xbox 360 Controllers sa ${APP_NAME}:" + }, + "yesAllowText": "Sige!", + "yourBestScoresText": "Pinakamataas Mong Iskor", + "yourBestTimesText": "Pinakamabilis Mong Oras" +} \ No newline at end of file diff --git a/dist/ba_data/data/languages/french.json b/dist/ba_data/data/languages/french.json index 711e687..bbf0f95 100644 --- a/dist/ba_data/data/languages/french.json +++ b/dist/ba_data/data/languages/french.json @@ -30,6 +30,8 @@ "signInWithGooglePlayText": "Connectez-vous avec Google Play", "signInWithTestAccountInfoText": "(ancien compte; utilisez les comptes de cet appareil pour les prochaines fois)", "signInWithTestAccountText": "Connectez-vous avec un compte test", + "signInWithV2InfoText": "(un compte qui fonctionne sur toutes les plateformes)", + "signInWithV2Text": "Connectez-vous avec un compte Bombsquad", "signOutText": "Se déconnecter", "signingInText": "Connexion...", "signingOutText": "Déconnexion...", @@ -40,6 +42,7 @@ "titleText": "Compte", "unlinkAccountsInstructionsText": "Sélectionnez un compte à délier", "unlinkAccountsText": "Délier des comptes", + "v2LinkInstructionsText": "Utiliser ce lien pour créer un compte ou se connecter.", "viaAccount": "(via le compte ${NAME})", "youAreLoggedInAsText": "Vous êtes connecté en temps que :", "youAreSignedInAsText": "Vous êtes connecté(e) en tant que:" @@ -1592,6 +1595,7 @@ "Dutch": "Néerlandais", "English": "Anglais", "Esperanto": "Espéranto", + "Filipino": "Philippin", "Finnish": "Finnois", "French": "Français", "German": "Allemand", @@ -1612,6 +1616,7 @@ "Slovak": "Slovaque", "Spanish": "Espagnol", "Swedish": "Suédois", + "Tamil": "Tamil", "Thai": "Thaïlandais", "Turkish": "Turc", "Ukrainian": "Ukrainien", @@ -1951,6 +1956,7 @@ "getDriverText": "Obtenez les pilotes", "macInstructions2Text": "Pour utiliser les contrôleurs sans-fils, vous avez besoin du récepteur \nqui vient avec le 'Contrôleur Xbox 360 Sans-Fils pour Windows'.\nUn seul récepteur est suffisante pour jusqu'à 4 contrôleurs.\n\nImportant: les recepteurs 3e-Party ne fonctionneront pas avec\nce pilote; soyez sûr que votre récepteur a 'Microsoft' écrit,\npas 'Xbox 360'. Microsoft ne vend plus séparément, alors vous \ndevez acheter avec le ontrôleur ou cherchez sur eBay.\n\nSi vous avez trouvé ceci utile, considerez à contribuer au développeur\ndu pilote sur son site-web.", "macInstructionsText": "Pour utiliser les contrôleurs Xbox 360, vous devez installer \nle pilote pour Mac qui est disponible au lien en-dessous. \nIl fonctionne avec les contrôleurs sans-fils et filaires.", + "macInstructionsTextScale": 0.8, "ouyaInstructionsText": "Pour utiliser les contrôleurs filaires Xbox 360 avec BombSquad,\nbranchez simplement dans le port USB. Vous pouvez utiliser\nun hub USB pour connecter plusieurs contrôleurs.\n\nPour utilisez les contrôleurs sans-fils, vous devez avoir un récepteur, \ndisponible avec le \"Contrôleur Xbox 360 sans-fils pour Windows\"\npaquet ou vendre individuellement. Chaque récepteur se branche dans un port\nUSB et vous permet à connecter 4 contrôleurs sans-fils", "titleText": "Utiliser les Contrôleurs Xbox 360 avec ${APP_NAME}:" }, diff --git a/dist/ba_data/data/languages/german.json b/dist/ba_data/data/languages/german.json index a80cb66..c036ff9 100644 --- a/dist/ba_data/data/languages/german.json +++ b/dist/ba_data/data/languages/german.json @@ -1,6 +1,6 @@ { "accountSettingsWindow": { - "accountNameRules": "Der Account Name darf kein Emoji oder andere spezielle Buchstaben enthalten.", + "accountNameRules": "Der Konto Name darf kein Emoji oder andere spezielle Buchstaben enthalten.", "accountProfileText": "Benutzerprofil", "accountsText": "Konten", "achievementProgressText": "Erfolge: ${COUNT} von ${TOTAL}", @@ -11,25 +11,27 @@ "linkAccountsEnterCodeText": "Code eingeben", "linkAccountsGenerateCodeText": "Code generieren", "linkAccountsInfoText": "(Teile deine Erfolge über verschiedene Platformen)", - "linkAccountsInstructionsNewText": "Um zwei Accounts zu verknüpfen muss ein Code auf dem ersten Gerät generiert werden und\ndieser Code auf dem zweiten Gerät eingegeben werden.\nDaten von dem zweiten Account werden dann zwischen beiden Geräten geteilt.\n(Daten vom ersten Account gehen verloren!)\n\nDu kannst bis zu ${COUNT} Accounts verknüpfen.\n\nWICHTIG: Verknüpfe nur Accounts die dir gehören;\nWenn du deine Accounts mit denen deiner Freunden\nverknüpft kannst du nicht mit deinen Freunden gleichzeitig online spielen.", + "linkAccountsInstructionsNewText": "Um zwei Konten zu verknüpfen muss ein Code auf dem ersten Gerät generiert\nund auf dem zweiten Gerät eingegeben werden.\nDaten von dem zweiten Konto werden dann zwischen beiden Geräten geteilt.\n(Daten vom ersten Konto gehen verloren!)\n\nDu kannst bis zu ${COUNT} Kontos verknüpfen.\n\nWICHTIG: Verknüpfe nur Kontos die dir gehören;\nWenn du deine Kontos mit denen deiner Freunde\nverknüpfst, kannst du nicht mit deinen Freunden gleichzeitig Online spielen.", "linkAccountsInstructionsText": "Um zwei Accounts miteinander zu verknüpfen,generiere einen \nCode auf einem der Geräte und trage ihn auf dem anderen ein.\nFortschritt und Inventar werden kombiniert.\nDu kannst bis zu ${COUNT} Accounts miteinander verknüpfen.\n\nSei vorsichtig; das kann nicht rückgängig gemacht werden!", - "linkAccountsText": "Accounts verknüpfen", - "linkedAccountsText": "Verknüpfte Accounts:", - "nameChangeConfirm": "Möchtest du deinen Account Namen in ${NAME} ändern?", + "linkAccountsText": "Konten verknüpfen", + "linkedAccountsText": "Verknüpfte Konten:", + "nameChangeConfirm": "Möchtest du deinen Konto Namen in ${NAME} ändern?", "notLoggedInText": "", "resetProgressConfirmNoAchievementsText": "Das wird deinen Koop-Fortschritt und deine\nHigh-Scores zurücksetzen (aber nicht deine Tickets).\nDies kann nicht rückgängig gemacht werden. Bist du sicher?", "resetProgressConfirmText": "Das wird deinen Koop-Fortschritt, deine\nErfolge und deine lokalen High-Scores\nzurücksetzen (aber nicht deine Tickets). Dies kann\nnicht rückgängig gemacht werden. Bist du sicher?", "resetProgressText": "Fortschritt zurücksetzen", - "setAccountName": "Account Name festlegen", + "setAccountName": "Konto Namen festlegen", "setAccountNameDesc": "Wählen Sie den Namen aus, der für Ihr Konto angezeigt werden soll.\nSie können den Namen von einem Ihrer verlinkten\nKonten benutzen oder erstellen Sie einen einzigartigen benutzerdefinierten Name.", "signInInfoText": "Melde dich an, um deinen Fortschritt in der Cloud zu speichern,\nTickets zu verdienen und an Turnieren teilzunehmen.", "signInText": "Anmelden", - "signInWithDeviceInfoText": "(ein automatischer Account, den du nur von diesem Gerät benutzen kannst)", - "signInWithDeviceText": "Mit Gerät-Account einloggen", + "signInWithDeviceInfoText": "(ein automatisches Konto, das du nur auf diesem Gerät benutzen kannst)", + "signInWithDeviceText": "Mit Gerät-Konto einloggen", "signInWithGameCircleText": "Mit Game Circle einloggen", "signInWithGooglePlayText": "Mit Google Play anmelden", - "signInWithTestAccountInfoText": "(veraltete Accountart, benutze Gerät-Accounts)", - "signInWithTestAccountText": "Mit Testaccount einloggen", + "signInWithTestAccountInfoText": "(veraltete Kontoart, benutze Geräte-Kontos)", + "signInWithTestAccountText": "Mit Testkonto einloggen", + "signInWithV2InfoText": "(Ein Account der auf allen Plattformen funktioniert)", + "signInWithV2Text": "Einloggen mit einem BombSquad Account", "signOutText": "Abmelden", "signingInText": "Anmelden...", "signingOutText": "Abmelden...", @@ -37,10 +39,11 @@ "testAccountWarningOculusText": "Achtung: Du bist mit einen \"Testaccount\" angemeldet.\nDieser wird im Laufe diesen Jahres mit einem Oculus Account ersetzt. \nDadurch kann man Tickets kaufen und vieles mehr.\n\nFürs erste wirst du alle Tickets im Spiel verdienen müssen.\n(Du bekommst aber dafür das BombSquad Pro Upgrade umsonst)", "testAccountWarningText": "Achtung: Du meldest dich mit einem \"Testaccount\" an.\nDieser Account ist an dieses Gerät gebunden und wird\nregelmäßig zurückgesetzt. (Also bitte gib dir nicht \nzuviel Mühe um etwas zu sammeln/freizuschalten)\n\nVerwende eine offizielle Version des Spiels, um einen \"echten\" \nAccount zu benutzen (Game-Center, Google Plus, etc.) \nDas erlaubt es dir auch, deinen Spielstand in der Cloud zu \nspeichern und auf einem anderen Gerät weiterzuspielen.", "ticketsText": "Tickets: ${COUNT}", - "titleText": "Account", - "unlinkAccountsInstructionsText": "Wähle ein Account aus um die Verknüpfung zu trennen", - "unlinkAccountsText": "Accounts entknüpfen", - "viaAccount": "(über dem Account ${NAME})", + "titleText": "Konto", + "unlinkAccountsInstructionsText": "Wähle ein Konto aus um die Verknüpfung zu trennen", + "unlinkAccountsText": "Kontos entknüpfen", + "v2LinkInstructionsText": "Benutze diesen Link um einen Account zu erstellen oder dich einzuloggen.", + "viaAccount": "(über das Konto ${NAME})", "youAreLoggedInAsText": "Du bist eingeloggt als:", "youAreSignedInAsText": "Du bist angemeldet als:" }, @@ -1615,6 +1618,7 @@ "Dutch": "Holländisch", "English": "Englisch", "Esperanto": "Esperanto", + "Filipino": "Philippinisch", "Finnish": "Finnisch", "French": "Französisch", "German": "Deutsch", @@ -1635,7 +1639,8 @@ "Slovak": "Slovakisch", "Spanish": "Spanisch", "Swedish": "Schwedisch", - "Thai": "thailändisch", + "Tamil": "Tamil", + "Thai": "Thailändisch", "Turkish": "Türkisch", "Ukrainian": "Ukrainisch", "Venetian": "Venezianisch", diff --git a/dist/ba_data/data/languages/gibberish.json b/dist/ba_data/data/languages/gibberish.json index 853492d..af5d8f0 100644 --- a/dist/ba_data/data/languages/gibberish.json +++ b/dist/ba_data/data/languages/gibberish.json @@ -32,6 +32,8 @@ "signInWithGooglePlayText": "Snf ocj weo fGOofl Plfl", "signInWithTestAccountInfoText": "(lgjo cac cojef ot; oeco doic w eofjw oero )", "signInWithTestAccountText": "Sjc weo fwtjwoefj cowefwf", + "signInWithV2InfoText": "(an zofj c woof woke wo Eire wf ofjjowg)", + "signInWithV2Text": "Sngo cow erwoj CBombSOudds acorjds.", "signOutText": "Sgngz Ozt", "signingInText": "Sgngngn infz..", "signingOutText": "Sngning ozt..", @@ -42,6 +44,7 @@ "titleText": "Acnfnnz", "unlinkAccountsInstructionsText": "Slj cwefjwe f owcjwoeijowief", "unlinkAccountsText": "Uldfj owjowerjsr", + "v2LinkInstructionsText": "Usdl ow cweoroe arc o woij erode cowefoweirjewr sers.", "viaAccount": "(fc cowefjwef ${NAME})", "youAreLoggedInAsText": "Yzrl arz lgzffd iz az:", "youAreSignedInAsText": "Yz arz sngnfd inz arz:" @@ -1624,6 +1627,7 @@ "Dutch": "Dtchjdflz", "English": "Englfjlzjsh", "Esperanto": "Esprorjjzlz", + "Filipino": "Fefjwoeifj", "Finnish": "Fnnizhsh", "French": "Frnzhfhn", "German": "Grmmzndn", diff --git a/dist/ba_data/data/languages/greek.json b/dist/ba_data/data/languages/greek.json index 5e53f1d..e71cb08 100644 --- a/dist/ba_data/data/languages/greek.json +++ b/dist/ba_data/data/languages/greek.json @@ -28,6 +28,8 @@ "signInWithGooglePlayText": "Σύνδεση με Google Play", "signInWithTestAccountInfoText": "(προσωρινός λογαριασμός. Δημιουργήστε λογαριασμό συσκευής για συνέχιση προόδου)", "signInWithTestAccountText": "Σύνδεση με δοκιμαστικό λογαριασμό", + "signInWithV2InfoText": "ένας λογαριασμός που λειτουργεί σε όλες τις πλατφορμες", + "signInWithV2Text": "Συνδεθείτε με ένα λογαριασμό BombSquad", "signOutText": "Αποσύνδεση", "signingInText": "Σύνδεση...", "signingOutText": "Αποσύνδεση...", @@ -35,6 +37,7 @@ "titleText": "Λογαριασμός", "unlinkAccountsInstructionsText": "Επιλέξτε έναν λογαριασμό για αποδέσμευση", "unlinkAccountsText": "Αποδέσμευση Λογαριασμών", + "v2LinkInstructionsText": "Χρησημοποιήστε αυτόν τον σύνδεσμο για να δημιουργήσετε έναν λογαριασμό ή για να συνδεθείτε.", "viaAccount": "(μέσω λογαριασμού ${NAME})", "youAreSignedInAsText": "Είστε συνδεδεμένοι ως:" }, @@ -494,6 +497,7 @@ "yourPowerRankingText": "Η Κατάταξη Δύναμής Σας:" }, "copyOfText": "${NAME} Αντίγραφο", + "copyText": "αντίγραφο", "createEditPlayerText": "<Δημιουργία/Επεξεργασία Παίκτη>", "createText": "Δημιουργία", "creditsWindow": { @@ -1500,6 +1504,7 @@ "Dutch": "Ολλανδικά", "English": "Αγγλικά", "Esperanto": "Εσπαράντο", + "Filipino": "Φιλιπινέζικα", "Finnish": "Φινλανδικά", "French": "Γαλλικά", "German": "Γερμανικά", @@ -1520,6 +1525,7 @@ "Slovak": "Σλοβακικά", "Spanish": "Ισπανικά", "Swedish": "Σουηδικά", + "Tamil": "Ταμίλ", "Thai": "ταϊλανδέζικο", "Turkish": "Τούρκικα", "Ukrainian": "Ουκρανικά", diff --git a/dist/ba_data/data/languages/hindi.json b/dist/ba_data/data/languages/hindi.json index 807d3a8..e6dd376 100644 --- a/dist/ba_data/data/languages/hindi.json +++ b/dist/ba_data/data/languages/hindi.json @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "गूगल प्ले से साईन ईन करे", "signInWithTestAccountInfoText": "(पुराना खाते का प्ररूप; आगे के लिए यंत्र खाते का प्रयोग करें)", "signInWithTestAccountText": "परीक्षण के खाते से साइन इन करें", + "signInWithV2InfoText": "(एक खाता जो सभी प्लेटफार्मों पर काम करता है)", + "signInWithV2Text": "BombSquad खाते से साइन इन करें", "signOutText": "साइन आउट", "signingInText": "साइन इन हो रहा है...", "signingOutText": "साइन आउट हो रहा है...", @@ -39,6 +41,7 @@ "titleText": "खाता", "unlinkAccountsInstructionsText": "अनलिंक करने के लिए एक खाता चुनें", "unlinkAccountsText": "खाते अनलिंक करें", + "v2LinkInstructionsText": "खाता बनाने या साइन इन करने के लिए इस लिंक का उपयोग करें।", "viaAccount": "(खाता ${NAME} के माध्यम से)", "youAreSignedInAsText": "आप इस खाते से साइनड इन हो: " }, @@ -497,6 +500,7 @@ "yourPowerRankingText": "आपका सत्ता पद :" }, "copyOfText": "${NAME} दूसरा", + "copyText": "नकल किजिए", "createEditPlayerText": "<प्लेयर बनाएँ / संपादित करें>", "createText": "बनायें", "creditsWindow": { @@ -1504,6 +1508,7 @@ "Dutch": "डच", "English": "अंग्रेजी", "Esperanto": "एस्पेरांतो", + "Filipino": "फिलिनो", "Finnish": "फिनिश", "French": "फ्रेंच", "German": "जर्मन", @@ -1524,6 +1529,7 @@ "Slovak": "स्लोवाक", "Spanish": "स्पेनिश", "Swedish": "स्वीडिश", + "Tamil": "तामिल", "Thai": "थाई", "Turkish": "तुर्की", "Ukrainian": "यूक्रेनी", diff --git a/dist/ba_data/data/languages/hungarian.json b/dist/ba_data/data/languages/hungarian.json index 039cc57..cf12f2e 100644 --- a/dist/ba_data/data/languages/hungarian.json +++ b/dist/ba_data/data/languages/hungarian.json @@ -30,6 +30,8 @@ "signInWithGooglePlayText": "Belépés Google fiókkal", "signInWithTestAccountInfoText": "(Egy régi típusú felhasználó; Mostantól a készülék felhasználóját használd.)", "signInWithTestAccountText": "Bejelentkezés teszt felhasználóval", + "signInWithV2InfoText": "(egy fiók, amely minden platformon működik)", + "signInWithV2Text": "Jelentkezzen be BombSquad fiókkal", "signOutText": "Kijelentkezés", "signingInText": "Bejelentkezés...", "signingOutText": "Kijelentkezés...", @@ -40,6 +42,7 @@ "titleText": "Felhasználó", "unlinkAccountsInstructionsText": "Válassz ki egy fiókot a leválasztáshoz", "unlinkAccountsText": "Fiókok leválasztása", + "v2LinkInstructionsText": "Használja ezt a linket fiók létrehozásához vagy bejelentkezéshez.", "viaAccount": "(számlán keresztül ${NAME})", "youAreSignedInAsText": "Be vagy jelentkezve, mint:" }, @@ -498,6 +501,7 @@ "yourPowerRankingText": "Helyezésed:" }, "copyOfText": "${NAME} másolata", + "copyText": "Másolat", "createEditPlayerText": "", "createText": "Készíts", "creditsWindow": { @@ -1513,6 +1517,7 @@ "Dutch": "Holland", "English": "Angol", "Esperanto": "Eszperanto", + "Filipino": "Filippínó", "Finnish": "Finn", "French": "Francia", "German": "Német", @@ -1533,6 +1538,7 @@ "Slovak": "Szlovák", "Spanish": "Spanyol", "Swedish": "Svéd", + "Tamil": "Tamil", "Thai": "Thai, Thai ember", "Turkish": "Török", "Ukrainian": "Ukrán", diff --git a/dist/ba_data/data/languages/indonesian.json b/dist/ba_data/data/languages/indonesian.json index 5198c1c..dd784e5 100644 --- a/dist/ba_data/data/languages/indonesian.json +++ b/dist/ba_data/data/languages/indonesian.json @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "Masuk menggunakan Google Play", "signInWithTestAccountInfoText": "(akun tipe lama; gunakan akun device untuk kedepannya)", "signInWithTestAccountText": "Masuk menggunakan akun percobaan", + "signInWithV2InfoText": "(Akun yang berfungsi di semua akun)", + "signInWithV2Text": "Daftar dengan akun bombsquad", "signOutText": "Keluar", "signingInText": "Sedang masuk...", "signingOutText": "Sedang keluar...", @@ -36,6 +38,7 @@ "titleText": "Akun", "unlinkAccountsInstructionsText": "Pilih akun yang akan diputuskan.", "unlinkAccountsText": "Memutus Akun.", + "v2LinkInstructionsText": "Gunakan tautan ini untuk membuat akun atau masuk.", "viaAccount": "(melalui akun ${NAME})", "youAreSignedInAsText": "Kamu terdaftar sebagai:" }, @@ -494,6 +497,7 @@ "yourPowerRankingText": "Peringkat Kekuatan Kamu:" }, "copyOfText": "Salinan ${NAME}", + "copyText": "Salin", "createEditPlayerText": "", "createText": "Buat", "creditsWindow": { @@ -1500,6 +1504,7 @@ "Dutch": "Belanda", "English": "Inggris", "Esperanto": "Esperanto", + "Filipino": "Filipina", "Finnish": "Finlandia", "French": "Prancis", "German": "Jerman", @@ -1520,6 +1525,7 @@ "Slovak": "Slovakia", "Spanish": "Spanyol", "Swedish": "Swedia", + "Tamil": "Tamil", "Thai": "Thai", "Turkish": "Turki", "Ukrainian": "Ukraina", diff --git a/dist/ba_data/data/languages/italian.json b/dist/ba_data/data/languages/italian.json index 5247edb..e9f6d87 100644 --- a/dist/ba_data/data/languages/italian.json +++ b/dist/ba_data/data/languages/italian.json @@ -15,11 +15,11 @@ "linkAccountsInstructionsNewText": "Per collegare due account, genera un codice nel primo dispositivo\ned inserisci il codice nel secondo. I dati del secondo account\nverranno condivisi in entrambi gli account.\n(I dati del primo account andranno persi)\n\nPuoi collegare fino a ${COUNT} account.\n\nIMPORTANTE: collega solo account che ti appartengono;\nSe colleghi account di amici non sarete in grado di\ngiocare online allo stesso momento.", "linkAccountsInstructionsText": "Per collegare due account, crea un codice su uno\ndei dispositivi e inserisci quel codice negli altri. \nProgressi e inventario verranno combinati.\nPuoi collegare fino a ${COUNT} account.\n\nIMPORTANTE: Collega solo account che possiedi!\nSe colleghi un account con un tuo amico non potrete\ngiocare allo stesso momento!\n \nInoltre: questa operazione non può essere annullata, quindi stai attento!", "linkAccountsText": "Collega account", - "linkedAccountsText": "Account Connessi:", + "linkedAccountsText": "Account Collegati:", "nameChangeConfirm": "Confermi di voler modificare il tuo nome in ${NAME}?", "notLoggedInText": "", - "resetProgressConfirmNoAchievementsText": "Stai per cancellare i tuoi progressi in\nmodalità cooperativa e i tuoi punteggi\nlocali (ma non i tuoi ticket). L'opera-\nzione è irreversibile: continuare?", - "resetProgressConfirmText": "Stai per cancellare i tuoi progressi in\nmodalità cooperativa, i tuoi punteggi\nlocali e i trofei (ma non i tuoi ticket).\nL'operazione è irreversibile: continuare?", + "resetProgressConfirmNoAchievementsText": "Stai per cancellare i tuoi progressi in\nmodalità cooperativa, i tuoi obbiettivi, i tuoi punteggi\nlocali (ma non i tuoi biglietti). \n\nL'operazione è irreversibile: continuare?", + "resetProgressConfirmText": "Stai per cancellare i tuoi progressi in\nmodalità cooperativa, i tuoi punteggi\nlocali e i tuoi obiettivi (ma non i tuoi biglietti).\nL'operazione è irreversibile: continuare?", "resetProgressText": "Cancella Progressi", "setAccountName": "Inserisci un nome utente", "setAccountNameDesc": "Seleziona quale nome visualizzare per il tuo account.\nPuoi usare quel nome per uno dei tuoi account collegati,\noppure creare un unico nome personalizzato.", @@ -31,6 +31,8 @@ "signInWithGooglePlayText": "Accedi con Google Play", "signInWithTestAccountInfoText": "(tipo di account obsoleto; usa gli account dispositivo d'ora in poi)", "signInWithTestAccountText": "Accedi con un account di prova", + "signInWithV2InfoText": "(un account che funziona su tutte le piattaforme)", + "signInWithV2Text": "Effettua l'accesso con un account di BombSquad", "signOutText": "Esci", "signingInText": "Accesso in corso...", "signingOutText": "Uscita in corso...", @@ -41,18 +43,19 @@ "titleText": "Account", "unlinkAccountsInstructionsText": "Seleziona un account da scollegare", "unlinkAccountsText": "Scollega Account", + "v2LinkInstructionsText": "Usa questo link per creare un account o accedere.", "viaAccount": "(tramite ${NAME})", "youAreLoggedInAsText": "Accesso effettuato come:", - "youAreSignedInAsText": "Hai effettuato l'accesso come:" + "youAreSignedInAsText": "Hai effettuato l'accesso con:" }, "achievementChallengesText": "Sfide trofeo", - "achievementText": "Trofeo", + "achievementText": "Obiettivo", "achievements": { "Boom Goes the Dynamite": { "description": "Uccidi 3 cattivoni con la TNT", - "descriptionComplete": "Uccisi 3 cattivoni con la TNT", + "descriptionComplete": "Hai Ucciso 3 cattivoni con la TNT", "descriptionFull": "Uccidi 3 cattivoni con la TNT in ${LEVEL}", - "descriptionFullComplete": "Uccisi 3 cattivoni con la TNT in ${LEVEL}", + "descriptionFullComplete": "Hai Ucciso 3 cattivoni con la TNT in ${LEVEL}", "name": "E la dinamite fa Boom!" }, "Boxer": { @@ -72,7 +75,7 @@ "descriptionComplete": "Hai vinto senza essere colpito", "descriptionFull": "Vinci ${LEVEL} senza essere colpito", "descriptionFullComplete": "Hai vinto ${LEVEL} senza essere colpito", - "name": "Vittoria schiacciante" + "name": "Vittoria Impeccabile" }, "Free Loader": { "descriptionFull": "Avvia una partita Tutti Contro Tutti con 2 o più giocatori", @@ -84,7 +87,7 @@ "descriptionComplete": "Hai ucciso 6 cattivoni con le mine antiuomo", "descriptionFull": "Uccidi 6 cattivoni con le mine in ${LEVEL}", "descriptionFullComplete": "Hai ucciso 6 cattivoni con le mine antiuomo in ${LEVEL}", - "name": "Minatore" + "name": "Minatore D'Oro" }, "Got the Moves": { "description": "Vinci senza tirare pugni né bombe", @@ -114,7 +117,7 @@ }, "Last Stand Wizard": { "description": "Fai 500 punti", - "descriptionComplete": "Hai fatto 500 punti", + "descriptionComplete": "Hai totalizzato 500 punti", "descriptionFull": "Totalizza 500 punti in ${LEVEL}", "descriptionFullComplete": "Hai totalizzato 500 punti in ${LEVEL}", "name": "Mago di ${LEVEL}" @@ -248,7 +251,7 @@ "Sharing is Caring": { "descriptionFull": "Condividi con successo il gioco con un amico", "descriptionFullComplete": "Gioco condiviso con successo con un amico", - "name": "Condividere significa tenerci" + "name": "La Condivisione E' La Cura" }, "Stayin' Alive": { "description": "Vinci senza morire", @@ -276,7 +279,7 @@ "descriptionComplete": "Hai ucciso 6 cattivoni con la TNT", "descriptionFull": "Uccidi 6 cattivoni con la TNT su ${LEVEL}", "descriptionFullComplete": "Hai ucciso 6 cattivoni con la TNT su ${LEVEL}", - "name": "Il dinamitardo" + "name": "Terrore Del Tritolo" }, "Team Player": { "descriptionFull": "Avvia una partita Squadre con 4+ giocatori", @@ -319,7 +322,7 @@ "name": "Vittoria in ${LEVEL}" }, "Uber Runaround Victory": { - "description": "Comleta tutte le ondate", + "description": "Completa tutte le ondate", "descriptionComplete": "Hai completato tutte le ondate", "descriptionFull": "Completa tutte le ondate in ${LEVEL}", "descriptionFullComplete": "Completa tutte le ondate in ${LEVEL}", @@ -331,7 +334,7 @@ "achievementsUnavailableForOldSeasonsText": "Mi dispiace, ma gli obbiettivi non sono disponibili per le stagioni vecchie.", "addGameWindow": { "getMoreGamesText": "Ottieni Giochi...", - "titleText": "Aggiunga Partita" + "titleText": "Aggiungi Partita" }, "allowText": "Consenti", "alreadySignedInText": "Il tuo account è collegato da un altro dispositivo;\ncambia account o chiudi il gioco nel tuo altro\ndispositivo e riprova.", @@ -351,7 +354,7 @@ "bestOfFinalText": "Finale Al-meglio-di-${COUNT}", "bestOfSeriesText": "Serie al meglio di ${COUNT}:", "bestRankText": "Il tuo miglior piazzamento: N.${RANK}", - "bestRatingText": "La tua valutazione massima è ${RATING}", + "bestRatingText": "La tua valutazione migliore è ${RATING}", "betaErrorText": "Questa versione non è più attiva; per favore, cercane una più recente.", "betaValidateErrorText": "Impossibile convalidare la beta. (nessuna connessione internet?)", "betaValidatedText": "Versione beta convalidata; Divertiti!", @@ -445,9 +448,9 @@ "movementControlScaleText": "Dimensione controlli movimento", "movementText": "Movimento", "resetText": "Reset", - "swipeControlsHiddenText": "Nascondi icone scivolati", - "swipeInfoText": "Ci vuole un po' per abituarsi ai comandi in stile 'Attacco',\nma rendono più facile giocare senza guardare i comandi.", - "swipeText": "Attacco", + "swipeControlsHiddenText": "Nascondi icone a scivolo", + "swipeInfoText": "Ci vuole un po' per abituarsi ai comandi a scivolo,\nma rendono più facile giocare senza guardare i tasti o lo stick.", + "swipeText": "Scivolo", "titleText": "Configura il Touchscreen", "touchControlsScaleText": "Scala dei Comandi Touch" }, @@ -501,7 +504,7 @@ "titleText": "Cooperativi", "toRankedText": "Al prossimo livello", "totalText": "Totale", - "tournamentInfoText": "Competi per punteggi alti con\naltri giocatori della tua lega.\n\nI premi sono dati ai giocatori con\ni punteggi più alti quando il tempo del torneo scade.", + "tournamentInfoText": "Competi per punteggi alti con\naltri giocatori della tua lega.\n\nI premi sono assegnati ai giocatori con\ni punteggi più alti quando il tempo del torneo scade.", "welcome1Text": "Benvenuto in ${LEAGUE}. Puoi migliorare il tuo\n livello lega guadagnando stelle, completando\n obbiettivi, e vincendo i trofei.", "welcome2Text": "Puoi anche guadagnare biglietti con molte attività simili.\nI biglietti possono essere usato per sbloccare nuovi capitoli, mappe e\nmini-giochi, per entrare nei tornei ed altro.", "yourPowerRankingText": "La tua posizione assoluta" @@ -598,7 +601,7 @@ "globalProfileText": "(profilo globale)", "highlightText": "colore principale", "iconText": "icona", - "localProfileInfoText": "I profili giocatori locali non hanno icone e i loro nomi\nnon sono garantiti che siano unici. Aggiorna a un profilo\nglobale per riservare un nome unico e per aggiungere un'icona personalizzata", + "localProfileInfoText": "I profili giocatori locali non hanno icone e non è\n garantito che siano unici. Aggiorna a un profilo\nglobale per riservare un nome unico e per aggiungere un'icona personalizzata", "localProfileText": "(profilo locale)", "nameDescriptionText": "Nome del giocatore", "nameText": "Nome", @@ -669,7 +672,7 @@ "firstToFinalText": "Finale First-to-${COUNT}", "firstToSeriesText": "Serie First-to-${COUNT}", "fiveKillText": "CINQUE UCCISIONI!!!", - "flawlessWaveText": "Ondata schiacciante", + "flawlessWaveText": "Ondata Impeccabile!", "fourKillText": "QUATTRO UCCISIONI!!!", "freeForAllText": "Tutti Contro Tutti", "friendScoresUnavailableText": "Punteggi degli amici non disponibili.", @@ -698,7 +701,7 @@ "gamesToText": "${WINCOUNT} - ${LOSECOUNT}", "gatherWindow": { "aboutDescriptionLocalMultiplayerExtraText": "Ricorda: qualunque dispositivo in un gruppo può ospitare \npiù di un giocatore se si hanno abbastanza controller.", - "aboutDescriptionText": "Usa queste schede per creare un gruppo-\n\nI gruppi ti permettono di partecipare a giochi e\ntornei con i tuoi amici usando diversi dispositivi.\n\nUsa il tasto ${PARTY} in alto a destra per chattare\ne interagire con il tuo gruppo.\n(su un controller, premi ${BUTTON} in un menu)", + "aboutDescriptionText": "Usa queste schede per assemblare un party.\n\nI party ti permettono di partecipare a giochi e\ntornei con i tuoi amici usando diversi dispositivi.\n\nUsa il tasto ${PARTY} in alto a destra per chattare\ne interagire con il tuo gruppo.\n(su un controller, premi ${BUTTON} in un menu)", "aboutText": "Informazioni", "addressFetchErrorText": "", "appInviteInfoText": "Invita i tuoi amici a provare BonvSquad e loro \nriceveranno ${COUNT} biglietti gratis. Tu guadagnerai\n${YOU_COUNT} per ogni amico che lo farà.", @@ -706,7 +709,7 @@ "appInviteSendACodeText": "Inviagli un codice", "appInviteTitleText": "Invito per l'app di ${APP_NAME}", "bluetoothAndroidSupportText": "(funziona su dispositivi Android dotati di Bluetooth)", - "bluetoothDescriptionText": "Ospita/unisciti a un gruppo via Bluetooth:", + "bluetoothDescriptionText": "Ospita/unisciti a un party via Bluetooth:", "bluetoothHostText": "Ospita via Bluetooth", "bluetoothJoinText": "Unisciti via Bluetooth", "bluetoothText": "Bluetooth", @@ -718,8 +721,8 @@ "earnTicketsForRecommendingAmountText": "I tuoi amici riceveranno ${COUNT} biglietti se proveranno il gioco\n(anche tu riceverai ${YOU_COUNT} biglietti per ogni amico che lo farà)", "earnTicketsForRecommendingText": "Condividi il gioco\nper biglietti gratis...", "emailItText": "Manda Email", - "favoritesSaveText": "enregistrer comme favori", - "favoritesText": "Favoris", + "favoritesSaveText": "Salva nei preferiti", + "favoritesText": "Preferiti", "freeCloudServerAvailableMinutesText": "Il prossimo server gratuito sarà disponibile tra ${MINUTES} minuti!", "freeCloudServerAvailableNowText": "Server gratuito disponibile!", "freeCloudServerNotAvailableText": "Nessun server gratuito disponibile", @@ -746,12 +749,12 @@ "joinPublicPartyDescriptionText": "Unisciti a un party pubblico", "localNetworkDescriptionText": "Unisciti ad un Party vicino (LAN, Bluetooth, etc.)", "localNetworkText": "Rete locale", - "makePartyPrivateText": "Rendi privato il mio gruppo", - "makePartyPublicText": "Rendi pubblico il mio gruppo", + "makePartyPrivateText": "Rendi privato il mio party", + "makePartyPublicText": "Rendi pubblico il mio party", "manualAddressText": "Indirizzi", "manualConnectText": "Connettiti", "manualDescriptionText": "Unisciti a un gruppo all'indirizzo:", - "manualJoinSectionText": "se joindre à la direction", + "manualJoinSectionText": "Unisciti con l'indirizzo", "manualJoinableFromInternetText": "Sei raggiungibile da internet?", "manualJoinableNoWithAsteriskText": "NO*", "manualJoinableYesText": "SÌ", @@ -762,26 +765,26 @@ "nearbyText": "Locale", "noConnectionText": "", "otherVersionsText": "(altre versioni)", - "partyCodeText": "Code du parti", + "partyCodeText": "Codice del Party", "partyInviteAcceptText": "Accetta", "partyInviteDeclineText": "Rifiuta", "partyInviteGooglePlayExtraText": "(vedi la scheda 'Google Play' nella finestra 'Raduna')", "partyInviteIgnoreText": "Ignora", - "partyInviteText": "${NAME} ti ha invitato\nad unirsi al suo gruppo!", - "partyNameText": "Nome gruppo", - "partyServerRunningText": "votre serveur de groupe est en cours d'exécution", - "partySizeText": "dimensione gruppo", + "partyInviteText": "${NAME} ti ha invitato\nad unirsi al suo party!", + "partyNameText": "Nome Party", + "partyServerRunningText": "Il tuo party è in esecuzione.", + "partySizeText": "dimensione party", "partyStatusCheckingText": "controllo status in corso...", - "partyStatusJoinableText": "il tuo gruppo è ora raggiungibile da internet", + "partyStatusJoinableText": "il tuo party è ora raggiungibile da internet", "partyStatusNoConnectionText": "impossibile connettersi al server", - "partyStatusNotJoinableText": "il tuo gruppo non è raggiungibile da internet", - "partyStatusNotPublicText": "il tuo gruppo non è pubblico", + "partyStatusNotJoinableText": "il tuo party non è raggiungibile da internet", + "partyStatusNotPublicText": "il tuo party non è pubblico", "pingText": "ping", "portText": "Porta", - "privatePartyCloudDescriptionText": "les parties privées s'exécutent sur des serveurs cloud dédiés; aucune configuration de routeur requise", + "privatePartyCloudDescriptionText": "I party privati prendono posto su dei cloud server fatti apposta; non c'è bisogno di una configurazione del router.", "privatePartyHostText": "Ospita un Party privato", "privatePartyJoinText": "Entra in un Party privato", - "privateText": "Privé", + "privateText": "Privato", "publicHostRouterConfigText": "Questa opzione richiede la configurazione di port-forwarding sul tuo router. Per comodità, utilizza la funzionalità di hosting su server", "publicText": "Pubblico", "requestingAPromoCodeText": "Richiesta codice in corso...", @@ -1579,6 +1582,7 @@ "Dutch": "Olandese", "English": "Inglese", "Esperanto": "Esperanto", + "Filipino": "Filippino", "Finnish": "Finlandese", "French": "Francese", "German": "Tedesco", @@ -1599,6 +1603,7 @@ "Slovak": "Slovacco", "Spanish": "Spagnolo", "Swedish": "Svedese", + "Tamil": "Tamil", "Thai": "Tailandese", "Turkish": "Turco", "Ukrainian": "Ucraino", @@ -1814,7 +1819,7 @@ "You can judge when a bomb is going to explode based on the\ncolor of sparks from its fuse: yellow..orange..red..BOOM.": "Puoi capire quando una bomba sta per esplodere basandoti\nsul colore della miccia: giallo... arancione... rosso... BOOOM.", "You can throw bombs higher if you jump just before throwing.": "Se salti appena prima di lanciarle, le bombe arrivano più in alto.", "You don't need to edit your profile to change characters; Just press the top\nbutton (pick-up) when joining a game to override your default.": "Non c'è bisogno di creare un profilo per cambiare personaggio; basta premere \nil pulsante superiore (afferra) quando prendi parte ad un gioco.", - "You take damage when you whack your head on things,\nso try to not whack your head on things.": "Vieni danneggiato quando sbatti la testa contro le cose.\nQuini? Quindi cerca di non sbattere la testa contro le cose.", + "You take damage when you whack your head on things,\nso try to not whack your head on things.": "Subisci danno quando sbatti la testa contro le cose,\nquindi cerca di non farlo.", "Your punches do much more damage if you are running or spinning.": "I pugni fanno molti più danni se stai correndo o roteando." } }, @@ -1845,7 +1850,7 @@ "phrase19Text": "Saltare aiuta a lanciare più in alto.", "phrase20Text": "Fai girare la tua bomba per lanci ancora più lunghi.", "phrase21Text": "Capire quando lanciare può essere difficile.", - "phrase22Text": "Uff...", + "phrase22Text": "Accipicchia.", "phrase23Text": "Prova a far consumare la miccia per un secondo o due.", "phrase24Text": "Così si fa! Cotto a puntino.", "phrase25Text": "Be', questo è tutto.", diff --git a/dist/ba_data/data/languages/korean.json b/dist/ba_data/data/languages/korean.json index b441e10..feb7172 100644 --- a/dist/ba_data/data/languages/korean.json +++ b/dist/ba_data/data/languages/korean.json @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "Google Play로 로그인", "signInWithTestAccountInfoText": "(이전 계정 유형, 앞의 기기 계정을 이용하세요)", "signInWithTestAccountText": "테스트 계정으로 로그인", + "signInWithV2InfoText": "(모든 플랫폼에서 작동하는 계정입니다)", + "signInWithV2Text": "BombSquad 계정으로 로그인", "signOutText": "로그아웃", "signingInText": "로그인 중...", "signingOutText": "로그아웃 중...", @@ -37,6 +39,7 @@ "titleText": "계정", "unlinkAccountsInstructionsText": "계정 연동을 해제할 계정을 선택하세요", "unlinkAccountsText": "계정 연동해제", + "v2LinkInstructionsText": "니 링크를 사용해서 계정을 만들거나, 로그인을 하세요.", "viaAccount": "(계정 종류 ${NAME})", "youAreSignedInAsText": "현재 로그인된 사용자 이름:" }, @@ -495,6 +498,7 @@ "yourPowerRankingText": "내 파워 랭킹:" }, "copyOfText": "${NAME} 사본", + "copyText": "복사", "createEditPlayerText": "<플레이어 생성/편집>", "createText": "생성", "creditsWindow": { @@ -1496,6 +1500,7 @@ "Dutch": "네덜란드어", "English": "영어", "Esperanto": "에스페란토", + "Filipino": "필리핀어", "Finnish": "핀란드어", "French": "프랑스어", "German": "독일어", @@ -1516,6 +1521,7 @@ "Slovak": "슬로바키아어", "Spanish": "스페인어", "Swedish": "스웨덴어", + "Tamil": "타밀어", "Thai": "태국어", "Turkish": "터키어", "Ukrainian": "우크라이나어", diff --git a/dist/ba_data/data/languages/persian.json b/dist/ba_data/data/languages/persian.json index f647a8e..5beae4d 100644 --- a/dist/ba_data/data/languages/persian.json +++ b/dist/ba_data/data/languages/persian.json @@ -1,9 +1,9 @@ { "accountSettingsWindow": { - "accountNameRules": "نام می‌تواند اموجی (شکلک) یا نویسه‌های ویژه داشته باشد", + "accountNameRules": "نام نمی‌تواند اموجی (شکلک) یا نویسه‌ های ویژه داشته باشد", "accountProfileText": "(مشخصات حساب)", "accountsText": "پروفایل ها", - "achievementProgressText": "${TOTAL} از‎ ${COUNT} :دستاوردها", + "achievementProgressText": "${TOTAL}/${COUNT} :دستاوردها", "campaignProgressText": "${PROGRESS} :[سخت]‎ پیشروی در بازی اصلی", "changeOncePerSeason": ".فقط یک‌بار در هر فصل می‌توانید این مورد را تغییر دهید", "changeOncePerSeasonError": "(روز تا فصل بعد‎ ${NUM}) برای تغییر این گزینه باید تا فصل بعد صبر کنید", @@ -13,8 +13,8 @@ "linkAccountsInfoText": "(به اشتراک گذاری پیشروی بین دستگاه‌های مختلف)", "linkAccountsInstructionsNewText": "برای اتصال دو پروفایل، ابتدا یک کد در پروفایل اول بسازید\nسپس آن را در پروفایل دوم وارد کنید. پس از این کار \n.اطلاعات پروفایل دوم بین دو پروفایل به اشتراک گذاشته می‌شود\n(اطلاعات پروفایل اول از بین خواهد رفت)\n\n.پروفایل را به هم متصل کنید‎ ${COUNT} شما می‌توانید تا\nتوجه: تنها پروفایل‌هایی که مال خودتان است را\nبه هم متصل کنید! اگر به پروفایل دوستانتان وصل\n.شوید، نمی‌توانید همزمان آنلاین بازی کنید", "linkAccountsInstructionsText": "برای اتصال دو حساب، در یکی از\nآن ها کدی ایجاد کرده \nو آن را در دیگری وارد کنید.\nپیشرفت ها و موجودی ترکیب خواهد شد.\nحساب را وصل کنید ${COUNT} شما می توانید.\n!توجه : فقط حساب هایی را وصل کنید که برای\n شماست\nاگر شما حساب دیگری را وصل کنید، شما توانایی این را ندارید که در یک زمان بازی کنید!\nاین عمل برگشت پذیر نیست، پس \nدقت کنید!", - "linkAccountsText": "متصل کردن پروفایل‌ها", - "linkedAccountsText": "پروفایل‌های متصل‌شده:‎", + "linkAccountsText": "متصل کردن حساب ها", + "linkedAccountsText": ":حساب های متصل شده", "nameChangeConfirm": "تغییر کند؟‎ ${NAME} آیا نام شما به", "resetProgressConfirmNoAchievementsText": "همهٔ پیشروی‌های شما در بخش همکاری و بالاترین امتیازات\nشما پاک خواهد شد. (به استثنای بلیت‌های شما)\nاین کار برگشت‌پذیر نیست. آیا مطمئنید؟", "resetProgressConfirmText": "همهٔ پیشروی‌ها در بخش همکاری، دستاوردها\n.و امتیازات بالای شما پاک خواهد شد\n(به استثنای بلیت‌های شما)\nاین کار برگشت‌پذیر نیست. آیا مطمئنید؟", @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "ورود با حساب بازی‌های گوگل", "signInWithTestAccountInfoText": "(حساب میراثی؛ از حساب‌های دستگاه برای پیشروی استفاده می‌کند)", "signInWithTestAccountText": "ورود با حساب آزمایشی", + "signInWithV2InfoText": "یک حساب کاربری که بر روی تمام سیستم عامل ها کار می کند", + "signInWithV2Text": "ورود به سیستم با حساب بمب اسکواد", "signOutText": "خروج از حساب", "signingInText": "در حال اتصال…", "signingOutText": "در حال خروج…", @@ -36,6 +38,7 @@ "titleText": "حساب", "unlinkAccountsInstructionsText": "یک حساب را برای جداسازی انتخاب کنید", "unlinkAccountsText": "جداسازی حساب‌ها", + "v2LinkInstructionsText": "استفاده از این لینک برای ایجاد یک حساب کاربری و یا ورود به سیستم.", "viaAccount": "(${NAME} از طریق حساب)", "youAreSignedInAsText": ":با این حساب وصل شده‌اید" }, @@ -496,6 +499,7 @@ "yourPowerRankingText": "رتبه‌بندی قدرت شما:" }, "copyOfText": "${NAME} کپی", + "copyText": "کپی کردن", "createEditPlayerText": "<ایجاد/ویرایش بازیکن>", "createText": "ساختن", "creditsWindow": { @@ -550,7 +554,7 @@ "disableXInputDescriptionText": "اجازه می‌دهد به بیش از 4 کنترل کننده اما ممکن است کار نکند.", "disableXInputText": "غیرفعال کردن ورودی ایکس", "doneText": "انجام شد", - "drawText": "مساوی", + "drawText": "برابر", "duplicateText": "تکراری", "editGameListWindow": { "addGameText": "افزودن\nبازی", @@ -953,7 +957,7 @@ "singlePlayerExamplesText": "Single Player / Co-op Examples", "versusExamplesText": "Versus Examples" }, - "languageSetText": ".است «${LANGUAGE}» زبان هم‌اکنون", + "languageSetText": "زبان فعلی: ${LANGUAGE}", "lapNumberText": "${TOTAL}/${CURRENT} دور", "lastGamesText": "(بازی آخر ${COUNT})", "leaderboardsText": "مدیران", @@ -1179,7 +1183,7 @@ "replayEndText": "پایان بازپخش", "replayNameDefaultText": "بازپخش بازی اخیر", "replayReadErrorText": "خطا در خواندن فایل بازپخش", - "replayRenameWarningText": "پس از بازی اگر شما خواستید نگه داشته شود,درغیر اینصورت بازنویسی خواهد شد\"${REPLAY}\"تغییر نام", + "replayRenameWarningText": "عبارت «${REPLAY}» را تغییر دهید، اگر می‌خواهید بعد از یک بازی آن را از دست ندهید. در غیر این صورت بازنویسی می‌شود.", "replayVersionErrorText": "با عرض پوزش این بازبخش در ورژن مختلفیاز بازی ایجاد شده\n است و نمیتوان مورد استفاده قرار گیرد", "replayWatchText": "دیدن بازبخش بازی", "replayWriteErrorText": "خطا در نوشتن فایل بازپخش.", @@ -1230,7 +1234,7 @@ "enablePackageModsText": "فعالسازی پکیج مد محلی", "enterPromoCodeText": "وارد کردن کد", "forTestingText": "توجه: این تغیرات برای آزمایش کردن هستند و هنگام خروج به حال اول باز میگردند", - "helpTranslateText": "${APP_NAME}'s non-English translations are a community\nsupported effort. If you'd like to contribute or correct\na translation, follow the link below. Thanks in advance!", + "helpTranslateText": "ترجمه‌های غیرانگلیسی ${APP_NAME} تلاشی است که\nتوسط انجمن پشتیبانی می‌شود. اگر مایل به کمک یا تصحیح\nترجمه هستید، پیوند زیر را دنبال کنید. پیشاپیش متشکرم!", "kickIdlePlayersText": "بیرون انداختن بازیکنان غیرفعال", "kidFriendlyModeText": "حالت دوستانه برای کودکان. خشونت کم", "languageText": "زبان", @@ -1347,7 +1351,7 @@ "timeSuffixMinutesText": "دقیقه ${COUNT}", "timeSuffixSecondsText": "ثانیه ${COUNT}", "tipText": "نکته", - "titleText": "BombSquad", + "titleText": "بمب‌اسکواد", "titleVRText": "BombSquad VR", "topFriendsText": "بالاترین امتیاز دوستان", "tournamentCheckingStateText": "چک کردن وضعیت مسابقات؛ لطفا صبر کنید", @@ -1445,7 +1449,7 @@ "Steal the enemy flag ${ARG1} times.": "بار ${ARG1} ربودن پرچم حریف", "Steal the enemy flag.": "ربودن پرچم حریف", "There can be only one.": "صاحب پرچم فقط میتونه یه نفر باشه", - "Touch the enemy flag ${ARG1} times.": "بار ${ARG1}لمس پرچم دشمن", + "Touch the enemy flag ${ARG1} times.": "${ARG1} بار لمس پرچم دشمن", "Touch the enemy flag.": "لمس پرچم دشمن", "carry the flag for ${ARG1} seconds": "ثانیه${ARG1}حمل و نگهداری پرچم برای", "kill ${ARG1} enemies": "حریف ${ARG1} ازبین بردن", @@ -1470,7 +1474,7 @@ "Chosen One": "فرد منتخب", "Conquest": "قدرت نمایی", "Death Match": "نبرد مرگبار", - "Easter Egg Hunt": "Easterگرفتن تخم مرغ های جشن", + "Easter Egg Hunt": "شکار تخم‌مرغ عید پاک", "Elimination": "استقامت", "Football": "فوتبال آمریکایی", "Hockey": "هاکی", @@ -1479,9 +1483,9 @@ "Meteor Shower": "بمباران", "Ninja Fight": "نبرد با نینجاها", "Onslaught": "مبارزه", - "Race": "مسابقه ی دو", + "Race": "مسابقهٔ دو", "Runaround": "مانع", - "Target Practice": "تمرین بمب اندازی", + "Target Practice": "تمرین بمب‌اندازی", "The Last Stand": "دفاع آخر" }, "inputDeviceNames": { @@ -1490,7 +1494,7 @@ }, "languages": { "Arabic": "عربی", - "Belarussian": "بلاروس", + "Belarussian": "بلاروسی", "Chinese": "چینی ساده شده", "ChineseTraditional": "چینی سنتی", "Croatian": "کرواتی", @@ -1499,10 +1503,11 @@ "Dutch": "هلندی", "English": "انگلیسی", "Esperanto": "اسپرانتو", + "Filipino": "فلیپینی", "Finnish": "فنلاندی", "French": "فرانسوی", "German": "آلمانی", - "Gibberish": "قبريش", + "Gibberish": "قبرسی", "Greek": "یونانی", "Hindi": "هندی", "Hungarian": "مجارستانی", @@ -1510,15 +1515,16 @@ "Italian": "ایتالیایی", "Japanese": "ژاپنی", "Korean": "کره‌ای", - "Persian": "فارسی", + "Persian": "فارسی‎", "Polish": "لهستانی", "Portuguese": "پرتغالی", "Romanian": "رومانیایی", "Russian": "روسی", "Serbian": "صربستانی", - "Slovak": "اسلوواکی", + "Slovak": "اسلواک", "Spanish": "اسپانیایی", "Swedish": "سوئدی", + "Tamil": "تامیلی", "Thai": "تایلندی", "Turkish": "ترکی", "Ukrainian": "اوکراینی", @@ -1806,7 +1812,7 @@ "watchWindow": { "deleteConfirmText": "حذف شود؟\"${REPLAY}\"", "deleteReplayButtonText": "حذف\nبازبخش", - "myReplaysText": "بازیهای ضبط شده‌ی من", + "myReplaysText": "بازی‌های ضبط‌شدهٔ من", "noReplaySelectedErrorText": "بازپخشی انتخاب نشده", "playbackSpeedText": "سرعت باز پخش:${SPEED}", "renameReplayButtonText": "تغییرنام\nبازبخش", @@ -1818,8 +1824,8 @@ "replayRenameErrorInvalidName": "نمی‌توان نام بازبخش را تغیر داد: نام نامعتبر است", "replayRenameErrorText": "خطا در تغییر نام بازپخش.", "sharedReplaysText": "اشتراک گزاری بازی ها", - "titleText": "بازی های ضبط شده", - "watchReplayButtonText": "تماشای بازی\nضبط شده" + "titleText": "بازی‌های ضبط‌شده", + "watchReplayButtonText": "تماشای بازی\nضبط‌شده" }, "waveText": "دست", "wellSureText": "! حتما", diff --git a/dist/ba_data/data/languages/polish.json b/dist/ba_data/data/languages/polish.json index f3ecd95..feb123e 100644 --- a/dist/ba_data/data/languages/polish.json +++ b/dist/ba_data/data/languages/polish.json @@ -30,6 +30,8 @@ "signInWithGooglePlayText": "Zapisz się kontem Google Play", "signInWithTestAccountInfoText": "Konto.", "signInWithTestAccountText": "Zapisz się testowym kontem.", + "signInWithV2InfoText": "(konto działa na wszystkich platformach)", + "signInWithV2Text": "Zaloguj się używając konta BombSquad", "signOutText": "Wypisz się", "signingInText": "Zapisywanie się...", "signingOutText": "Wypisywanie...", @@ -40,6 +42,7 @@ "titleText": "Konto", "unlinkAccountsInstructionsText": "Wybierz konto do rozłączenia", "unlinkAccountsText": "Rozłącz konta", + "v2LinkInstructionsText": "Użyj tego linku aby stworzyć konto lub zaloguj się.", "viaAccount": "(przez konto ${NAME})", "youAreLoggedInAsText": "Jesteś zalogowany jako:", "youAreSignedInAsText": "Jesteś zapisany jako:" @@ -507,6 +510,7 @@ "yourPowerRankingText": "Twoje miejsce:" }, "copyOfText": "${NAME} - kopia", + "copyText": "Kopiuj", "createAPlayerProfileText": "Utworzyć profil gracza?", "createEditPlayerText": "", "createText": "Utwórz", @@ -1579,6 +1583,7 @@ "Dutch": "Holenderski", "English": "Angielski", "Esperanto": "Esperanto", + "Filipino": "Filipiński", "Finnish": "Fiński", "French": "Francuski", "German": "Niemiecki", @@ -1599,6 +1604,7 @@ "Slovak": "słowacki", "Spanish": "Hiszpański", "Swedish": "Szwedzki", + "Tamil": "Tamil", "Thai": "Tajski", "Turkish": "Turecki", "Ukrainian": "Ukraiński", diff --git a/dist/ba_data/data/languages/portuguese.json b/dist/ba_data/data/languages/portuguese.json index 59bb5b9..97ec479 100644 --- a/dist/ba_data/data/languages/portuguese.json +++ b/dist/ba_data/data/languages/portuguese.json @@ -11,18 +11,18 @@ "linkAccountsEnterCodeText": "Inserir código", "linkAccountsGenerateCodeText": "Gerar código", "linkAccountsInfoText": "(compartilhar progresso entre várias plataformas)", - "linkAccountsInstructionsNewText": "Para vincular duas contas, gere um código na primeira\ne insira o código na segunda. O progresso da\nsegunda conta será sincronizado com ambas.\n(Progresso da primeira conta será perdido)\n\nVocê pode vincular ${COUNT} contas.\n\nIMPORTANTE: apenas vincule contas que você tem acesso; \nSe você vincular a conta de um amigo vocês não\nserão capazes de jogar online ao mesmo tempo.", + "linkAccountsInstructionsNewText": "Para vincular duas contas, gere um código na primeira\ne insira o código na segunda. O progresso da\nsegunda conta será sincronizado com ambas.\n(O progresso da primeira conta será perdido)\n\nVocê pode vincular até ${COUNT} contas.\n\nIMPORTANTE: vincule apenas contas que tem acesso; \nSe você vincular a conta de um amigo, vocês não\nirão conseguir jogar online ao mesmo tempo.", "linkAccountsInstructionsText": "Para vincular duas contas, gere um código\nem uma delas e o insira na outra.\nProgresso e inventário serão combinados.\nVocê pode vincular até ${COUNT} contas.\n\nIMPORTANTE: Vincule apenas as contas que você possui!\nSe você vincular contas a seus amigos, você\nnão será capaz de jogar ao mesmo tempo!\n\nAlém disso: isso não pode ser desfeito atualmente, então tenha cuidado!", "linkAccountsText": "Vincular contas", "linkedAccountsText": "Contas vinculadas:", "nameChangeConfirm": "Mudar o nome da sua conta para ${NAME}?", "notLoggedInText": "", - "resetProgressConfirmNoAchievementsText": "Isso reiniciará o seu progresso no cooperativo e\nsuas pontuações (mas não os seus bilhetes).\nIsso não pode ser desfeito. Tem certeza?", - "resetProgressConfirmText": "Isso reiniciará o seu progresso no cooperativo,\nsuas conquistas e suas pontuações\n(mas não os seus bilhetes). Isso não pode\nser desfeito. Tem certeza?", + "resetProgressConfirmNoAchievementsText": "Isto reiniciará o seu progresso no cooperativo e\nas suas pontuações (mas não os seus bilhetes).\nIsto não pode ser desfeito. Tem certeza?", + "resetProgressConfirmText": "Isto reiniciará o seu progresso no cooperativo,\nas suas conquistas e as suas pontuações\n(mas não os seus bilhetes). Isto não pode\nser desfeito. Tem certeza?", "resetProgressText": "Reiniciar progresso", "setAccountName": "Escolha o nome da conta", "setAccountNameDesc": "Escolha o nome que será exibido na sua conta.\nVocê pode usar o nome de uma de suas contas\nou criar um nome personalizado exclusivo.", - "signInInfoText": "Inicie a sessão para ganhar bilhetes, compita online e compartilhe\nseu progresso entre vários dispositivos.", + "signInInfoText": "Inicie sessão para ganhar bilhetes, compita online e compartilhe\no seu progresso entre vários dispositivos.", "signInText": "Iniciar sessão", "signInWithDeviceInfoText": "(uma conta automática disponível apenas neste aparelho)", "signInWithDeviceText": "Iniciar sessão com conta do dispositivo", @@ -30,6 +30,8 @@ "signInWithGooglePlayText": "Iniciar sessão com Google Play", "signInWithTestAccountInfoText": "(tipo de conta legado; use as contas do dispositivo daqui em diante)", "signInWithTestAccountText": "Iniciar sessão com conta teste", + "signInWithV2InfoText": "(uma conta que funciona em todas as plataformas)", + "signInWithV2Text": "Iniciar sessão com conta do BombSquad", "signOutText": "Finalizar sessão", "signingInText": "Iniciando sessão...", "signingOutText": "Finalizando sessão...", @@ -40,6 +42,7 @@ "titleText": "Conta", "unlinkAccountsInstructionsText": "Selecione uma conta para desvincular", "unlinkAccountsText": "Desvincular contas", + "v2LinkInstructionsText": "Utilize o link para criar uma conta ou entrar nela.", "viaAccount": "(via ${NAME})", "youAreLoggedInAsText": "Você está logado como:", "youAreSignedInAsText": "Iniciou sessão como:" @@ -52,7 +55,7 @@ "descriptionComplete": "Matou 3 inimigos com TNT", "descriptionFull": "Mate 3 inimigos com TNT no ${LEVEL}", "descriptionFullComplete": "Matou 3 inimigos com TNT no ${LEVEL}", - "name": "Quem Brinca com Fogo Sai Queimado" + "name": "Quem brinca com fogo, sai queimado" }, "Boxer": { "description": "Ganhe sem usar bombas", @@ -207,7 +210,7 @@ "descriptionComplete": "Ganhou sem deixar os inimigos marcarem", "descriptionFull": "Ganhe no ${LEVEL} sem deixar os inimigos marcarem", "descriptionFullComplete": "Ganhou no ${LEVEL} sem deixar os inimigos marcarem", - "name": "${LEVEL} De Levada" + "name": "${LEVEL} de levada" }, "Rookie Football Victory": { "description": "Ganhe a partida", @@ -245,8 +248,8 @@ "name": "Mago do ${LEVEL}" }, "Sharing is Caring": { - "descriptionFull": "Compartilhe o jogo com um amigo com êxito", - "descriptionFullComplete": "Jogo compartilhado com um amigo com êxito", + "descriptionFull": "Compartilhe o jogo com um amigo", + "descriptionFullComplete": "Jogo compartilhado com um amigo", "name": "Compartilhar é amar" }, "Stayin' Alive": { @@ -261,14 +264,14 @@ "descriptionComplete": "Causou 100% de dano com um soco", "descriptionFull": "Cause 100% de dano com um soco no ${LEVEL}", "descriptionFullComplete": "Causou 100% de dano com um soco no ${LEVEL}", - "name": "Super Mega Soco" + "name": "Super mega soco" }, "Super Punch": { "description": "Cause 50% de dano com um soco", "descriptionComplete": "Causou 50% de dano com um soco", "descriptionFull": "Cause 50% de dano com um soco no ${LEVEL}", "descriptionFullComplete": "Causou 50% de dano com um soco no ${LEVEL}", - "name": "Super Soco" + "name": "Supersoco" }, "TNT Terror": { "description": "Mate 6 inimigos com TNT", @@ -333,15 +336,15 @@ "titleText": "Adicionar jogo" }, "allowText": "Permitir", - "alreadySignedInText": "Sua conta está logada em outro dispositivo;\nMude de conta ou feche o jogo no seu\noutro dispositivo e tente novamente.", - "apiVersionErrorText": "Não pôde carregar o módulo ${NAME}; ele é destinado à versão ${VERSION_USED}; exigimos a ${VERSION_REQUIRED}.", + "alreadySignedInText": "A conta tem sessão iniciada em outro dispositivo;\nMude de conta ou feche o jogo no seu\noutro dispositivo e tente novamente.", + "apiVersionErrorText": "Não é possível carregar o módulo ${NAME}; ele é destinado à versão ${VERSION_USED}; exigimos a ${VERSION_REQUIRED}.", "audioSettingsWindow": { "headRelativeVRAudioInfoText": "(\"Auto\" ativado apenas quando os fones estão conectados)", "headRelativeVRAudioText": "Áudio para fones de RV", "musicVolumeText": "Volume da música", "soundVolumeText": "Volume do som", - "soundtrackButtonText": "Trilha Sonora", - "soundtrackDescriptionText": "(tocar sua própria música durante o jogo)", + "soundtrackButtonText": "Trilha sonora", + "soundtrackDescriptionText": "(tocar a sua própria música durante o jogo)", "titleText": "Áudio" }, "autoText": "Auto", @@ -359,13 +362,13 @@ "boostText": "Impulso", "bsRemoteConfigureInAppText": "${REMOTE_APP_NAME} é configurado no próprio aplicativo.", "buttonText": "botão", - "canWeDebugText": "Gostaria que BombSquad reportasse erros, falhas e \ninformações básicas de uso para o desenvolvedor?\n\nEstes dados não contêm informações pessoais e ajudam\na manter o jogo funcionando sem erros e livre de problemas.", + "canWeDebugText": "Deseja que o BombSquad comunique os erros, falhas e \ninformações básicas de uso para o desenvolvedor?\n\nEstes dados não contêm informações pessoais e ajudam\na manter o jogo funcionando corretamente.", "cancelText": "Cancelar", "cantConfigureDeviceText": "Desculpe, ${DEVICE} não é configurável.", "challengeEndedText": "Este desafio acabou.", - "chatMuteText": "Silenciar bate-papo", - "chatMutedText": "Bate-papo silenciado", - "chatUnMuteText": "Reativar som do bate-papo", + "chatMuteText": "Silenciar chat", + "chatMutedText": "Chat silenciado", + "chatUnMuteText": "Reativar som do chat", "choosingPlayerText": "", "completeThisLevelToProceedText": "Você deve completar \neste nível para continuar!", "completionBonusText": "Bônus de conclusão", @@ -389,10 +392,10 @@ "configGamepadWindow": { "advancedText": "Avançado", "advancedTitleText": "Configuração avançada dos controles", - "analogStickDeadZoneDescriptionText": "(ative isto se seu personagem 'escorrega' quando você solta o direcional)", + "analogStickDeadZoneDescriptionText": "(ative isto se o personagem 'escorrega' quando você solta o direcional)", "analogStickDeadZoneText": "Área morta do analógico", "appliesToAllText": "(serve para todos os controles deste tipo)", - "autoRecalibrateDescriptionText": "(ative isto se o seu personagem não se move na velocidade máxima)", + "autoRecalibrateDescriptionText": "(ative isto se o personagem não se move na velocidade máxima)", "autoRecalibrateDescriptionTextScale": 0.4, "autoRecalibrateText": "Calibrar automaticamente o analógico", "autoRecalibrateTextScale": 0.65, @@ -431,7 +434,7 @@ "twoInOneSetupText": "Configuração do Controle 2-em-1", "uiOnlyDescriptionText": "(impede que este controle entre em um jogo)", "uiOnlyText": "Limitar o Uso ao Menu", - "unassignedButtonsRunText": "Todo Botão Não Definido Executa", + "unassignedButtonsRunText": "Todo o botão não definido executa", "unassignedButtonsRunTextScale": 0.8, "unsetText": "", "vrReorientButtonText": "Botão Reorientar VR" @@ -499,7 +502,7 @@ "powerRankingPointsMultText": "(x ${NUMBER} pts)", "powerRankingPointsText": "${NUMBER} pts", "powerRankingPointsToRankedText": "(${CURRENT} de ${REMAINING} pts)", - "powerRankingText": "Classificação Geral", + "powerRankingText": "Classificação geral", "prizesText": "Prêmios", "proMultInfoText": "Jogadores com a versão ${PRO}\nrecebem um aumento de ${PERCENT}% nos pontos.", "seeMoreText": "Mais...", @@ -520,10 +523,10 @@ "createEditPlayerText": "", "createText": "Criar", "creditsWindow": { - "additionalAudioArtIdeasText": "Áudio adicional, Arte inicial e Ideias por ${NAME}", + "additionalAudioArtIdeasText": "Áudio adicional, Arte inicial e ideias por ${NAME}", "additionalMusicFromText": "Música adicional de ${NAME}", "allMyFamilyText": "Toda a família e amigos que ajudaram nos testes", - "codingGraphicsAudioText": "Programação, Gráficos e Áudio por ${NAME}", + "codingGraphicsAudioText": "Programação, gráficos e áudio por ${NAME}", "creditsText": " Codificação, Gráficos, e Áudio por Eric Froemling\n \n Áudio Adicional, Trabalho de Arte Inicial, e Ideias por Raphael Suter\n \n Som & Música:\n\n${SOUND_AND_MUSIC}\n\n Música de Domínio Público via Musopen.com (um ótimo site para música clássica)\n Agradecimentos especialmente para o Exército dos EUA, Marinha e Bandas da Marinha.\n\n Um grande obrigado aos seguintes colaboradores do freesound.org para o uso de seus sons:\n${FREESOUND_NAMES}\n\n Agradecimentos Especiais:\n\n Todd, Laura, e Robert Froemling\n Todos os meus amigos e familiares que ajudaram a testar o jogo\n Quem quer que inventou o café\n\n Legal:\n\n${LEGAL_STUFF}\n\n www.froemling.net\n", "languageTranslationsText": "Traduções:", "legalText": "Legal:", @@ -932,7 +935,7 @@ "arrowsToExitListText": "aperte ${LEFT} ou ${RIGHT} para sair da lista", "buttonText": "botão", "cantKickHostError": "Você não pode expulsar o anfitrião.", - "chatBlockedText": "O bate-papo de ${NAME} está bloqueado por ${TIME} segundo(s).", + "chatBlockedText": "O chat de ${NAME} está bloqueado por ${TIME} segundo(s).", "connectedToGameText": "Conectou-se a '${NAME}'", "connectedToPartyText": "Entrou na sala de ${NAME}!", "connectingToPartyText": "Conectando...", @@ -1006,7 +1009,7 @@ "kickVoteStartedText": "Uma votação para expulsar ${NAME} foi iniciada.", "kickVoteText": "Votação para expulsar", "kickVotingDisabledText": "A votação para expulsar está desativado.", - "kickWithChatText": "Digite ${YES} no bate-papo para sim e ${NO} para não.", + "kickWithChatText": "Escreva ${YES} no chat para sim e ${NO} para não.", "killsTallyText": "${COUNT} abates", "killsText": "Abates", "kioskWindow": { @@ -1132,7 +1135,7 @@ "ownFlagAtYourBaseWarning": "Sua própria bandeira deve estar\nem sua base para fazer um ponto!", "packageModsEnabledErrorText": "Não pode jogar em rede enquanto local-package-mods estiverem ativados (veja Configurações > Avançado)", "partyWindow": { - "chatMessageText": "Mensagem do bate-papo", + "chatMessageText": "Mensagem do chat", "emptyText": "Sua sala está vazia", "hostText": "(anfitrião)", "sendText": "Enviar", @@ -1217,7 +1220,7 @@ "purchasingText": "Comprando...", "quitGameText": "Sair do ${APP_NAME}?", "quittingIn5SecondsText": "Saindo em 5 segundos...", - "randomPlayerNamesText": "João,Maria,Anderson,Lucas,Roberto,César,Felipe,Pedro,Zézinho,Jaílson,Hélvio,Plínio,Clara,Lorena,Beatriz,Wandernilson,Marcos,Michele,Taís,Florentina,Tadeu,Teodoro,Gabriel,Joelma,Chimbinha,Lula,Dilma,Leonardo,Irene,Samanta,Gioconda,Guilhermina,Guilherme,Frederico,Bartolomeu,Dionísio,Diógenes,Haroldo,Ronaldinho,Ricardo,Selma,Bruna,Vanderlei,Danilo,Celso,Vitória,Denise,Samuel,Daniel,Gigi,Manuel,Wiz,Gretchen,Creusa,Chico,Leôncio,Leônidas,Washington,Cleusa,José,Joane,Severino,Casé,Carlos,Davi,Bianca,Clautila,Dafne,Jorge,Sandra,Armando,Basílio,Rochele,Camila,Débora,Rafael,Jonatan,Clodomiro,Clodovil,Vera,Simão,Raíssa,Toni,Tânia,Regina,Bela,Max,Maximiliano,Claudinei,Cláudio,Luciana,Anália,Aparecida,Marcelo,Flávio,Emílio,Tiago,Hebe,Ana,Beth,Gugu,Vítor,Nílton,Maurício,Marciano,Belquior,Clemente,Rosa,Rose,Rosemar,Gabriela,Sérgio,Antônio,Ben,Ivan,jamim,Abreu,Luís,Elton,Fabiana,Waldir,Wilson,Tainá,Tainara,Xuxa,Sacha,Teotônio,Téo,Valdirene,Laurindo,Priscila,Joaquim,Estevão,Gilmar,Erick,Gilson,Romário,Dunga,Ludmila,Luciano,Gilvan,Tamara,Carla,Zezé,Fernando,Fernanda,Adegesto,Acheropita,Anatalino,Lino,Araci,Marluci,Eusébio,Darcília,Dignatario,Ernesto,Cássio,Conrado,Fábio,Heitor,Ivan,Murilo,Andressa,Mateus,Otávio,Helena,atuamãe,Laís,Lavínia,Leila,Letícia,Nair,Henrique,Lara,Diogo,Diego,Geniclécio,Serafim,Lisa,Inri,Eusébio,Gerônimo,Bernardo,Bernadete,Henriete,Eliete,Fudêncio,Peruíbe,Tomás,Tomashedisso,Giovana,Prieto,Gabriely,Suélen,Jamily,Jamil,Geraldo,Nazareth,Forníco,Ícaro,Breno,Bruno,Cilmara,Nilza,Caio,Borges,Cleimara,Janeclécio,Iram,Tico,Teco,Genilson,Marlos,William,Nando,Nanda,Isabel,Jamal,Elias,Félix,Caroline,Carolina,Vilma,Rafaely,Tonho,Túnica,Miguel,Cona,Jones,Juan,Anastácio", + "randomPlayerNamesText": "João,Maria,Anderson,Lucas,Roberto,César,Felipe,Pedro,Zézinho,Jaílson,Hélvio,Plínio,Clara,Lorena,Beatriz,Wandernilson,Marcos,Michele,Taís,Florentina,Tadeu,Teodoro,Gabriel,Joelma,Chimbinha,Lula,Dilma,Leonardo,Irene,Samanta,Gioconda,Guilhermina,Guilherme,Frederico,Bartolomeu,Dionísio,Diógenes,Haroldo,Ronaldinho,Ricardo,Selma,Bruna,Vanderlei,Danilo,Celso,Vitória,Denise,Samuel,Daniel,Gigi,Manuel,Wiz,Gretchen,Creusa,Chico,Leôncio,Leônidas,Washington,Cleusa,José,Joane,Severino,Casé,Carlos,Davi,Bianca,Clautila,Dafne,Jorge,Sandra,Armando,Basílio,Rochele,Camila,Débora,Rafael,Jonatan,Clodomiro,Clodovil,Vera,Simão,Raíssa,Toni,Tânia,Regina,Bela,Max,Maximiliano,Claudinei,Cláudio,Luciana,Anália,Aparecida,Marcelo,Flávio,Emílio,Tiago,Hebe,Ana,Beth,Gugu,Vítor,Nílton,Maurício,Marciano,Belquior,Clemente,Rosa,Rose,Rosemar,Gabriela,Sérgio,Antônio,Ben,Ivan,jamim,Abreu,Luís,Elton,Fabiana,Waldir,Wilson,Tainá,Tainara,Xuxa,Sacha,Teotônio,Téo,Valdirene,Laurindo,Priscila,Joaquim,Estevão,Gilmar,Erick,Gilson,Romário,Dunga,Ludmila,Luciano,Gilvan,Tamara,Carla,Zezé,Fernando,Fernanda,Adegesto,Acheropita,Anatalino,Lino,Araci,Marluci,Eusébio,Darcília,Dignatario,Ernesto,Cássio,Conrado,Fábio,Heitor,Ivan,Murilo,Andressa,Mateus,Otávio,Helena,Laís,Lavínia,Leila,Letícia,Nair,Henrique,Lara,Diogo,Diego,Geniclécio,Serafim,Lisa,Inri,Eusébio,Gerônimo,Bernardo,Bernadete,Henriete,Eliete,Fudêncio,Peruíbe,Tomás,Tomashedisso,Giovana,Prieto,Gabriely,Suélen,Jamily,Jamil,Geraldo,Nazareth,Forníco,Ícaro,Breno,Bruno,Cilmara,Nilza,Caio,Borges,Cleimara,Janeclécio,Iram,Tico,Teco,Genilson,Marlos,William,Nando,Nanda,Isabel,Jamal,Elias,Félix,Caroline,Carolina,Vilma,Rafaely,Tonho,Túnica,Miguel,Jones,Juan,Anastácio,Francisco,Xavier", "randomText": "Aleatório", "rankText": "Classificação", "ratingText": "Avaliação", @@ -1607,6 +1610,7 @@ "Dutch": "Holandês", "English": "Inglês", "Esperanto": "Esperanto", + "Filipino": "Filipino", "Finnish": "Finlandês", "French": "Francês", "German": "Alemão", @@ -1627,6 +1631,7 @@ "Slovak": "Eslovaco", "Spanish": "Espanhol", "Swedish": "Sueco", + "Tamil": "tâmil", "Thai": "Tailandês", "Turkish": "Turco", "Ukrainian": "Ucraniano", diff --git a/dist/ba_data/data/languages/romanian.json b/dist/ba_data/data/languages/romanian.json index f5baddd..c3bf193 100644 --- a/dist/ba_data/data/languages/romanian.json +++ b/dist/ba_data/data/languages/romanian.json @@ -1,35 +1,37 @@ { "accountSettingsWindow": { - "accountNameRules": "Numele Contului nu poate conține emoji sau alte semne speciale", + "accountNameRules": "Numele Contulurilor nu pot conține emoji-uri sau alte semne speciale", "accountProfileText": "(profil de cont)", "accountsText": "Conturi", "achievementProgressText": "Realizări: ${COUNT} din ${TOTAL}", "campaignProgressText": "Progres campanie [Greu]: ${PROGRESS}", - "changeOncePerSeason": "Acesta poate fi schimbat o singura data pe sezon", - "changeOncePerSeasonError": "Trebuie sa astepti pana urmatorul sezon ca sa schimbi asta din nou (${NUM} zile)", + "changeOncePerSeason": "Acesta poate fi schimbat o singură dată pe sezon", + "changeOncePerSeasonError": "Trebuie să aștepți până la următorul sezon dacă vrei să schimbi asta din nou timp de (${NUM} zile)", "customName": "Nume personalizat", "deviceSpecificAccountText": "Foloseşti un cont specific dispozitivului: ${NAME}", "linkAccountsEnterCodeText": "Introdu Codul", "linkAccountsGenerateCodeText": "Generează Codul", - "linkAccountsInfoText": "(împărtăşeşte progresul între diferite platforme)", - "linkAccountsInstructionsNewText": "Pentru a conecta două conturi, generați un cod pe primul\nși introduceți acel cod pe al doilea. Date din\nal doilea cont va fi apoi partajat între amândoi.\n(Datele din primul cont se vor pierde)\n\nPuteți conecta până la ${COUNT} conturi.\n\nIMPORTANT: conectați numai conturile pe care le dețineți;\nDacă vă conectați la conturile prietenilor, nu veți face acest lucru\nsă poți juca online în același timp.", + "linkAccountsInfoText": "(împărtăşeşte progresul între platforme diferite)", + "linkAccountsInstructionsNewText": "Pentru a conecta două conturi, generați un cod pe primul\nși introduceți acel cod pe al doilea. Date din\nal doilea cont va fi apoi partajat între amândouă.\n(Datele din primul cont se vor pierde)\n\nPuteți conecta până la ${COUNT} conturi.\n\nIMPORTANT: conectați numai conturile pe care le dețineți;\nDacă vă conectați la conturile prietenilor, nu veți putea\nsă jucați online în același timp.", "linkAccountsInstructionsText": "Pentru a conecta 2 conturi, generează un cod pe\nunul din ele şi introdu acelmcod pe celălalt.\nProgresul şi inventarul tău vor fi combinate.\nPoți conecta până la ${COUNT} conturi.\n\nAi grijă; acest lucru nu poate fi şters!", "linkAccountsText": "Conectează Conturi", "linkedAccountsText": "Conturi conectate:", - "nameChangeConfirm": "Schimbăti numele contului in ${NAME}?", - "resetProgressConfirmNoAchievementsText": "Această acțiune va reseta progresul co-op\nși high-score-urile (nu și biletele) și nu\npoate fi anulată. Ești sigur(ă)?", - "resetProgressConfirmText": "Această acțiune va reseta progresul\nco-op, realizările și high-scoreurile\n(nu și biletele) și nu poate fi\nanulată. Ești sigur?", - "resetProgressText": "Resetează progres", - "setAccountName": "Seteazaă numele contului", - "setAccountNameDesc": "Selectati numele pentru a afisa pentru contul tau.Tu poti folosi numele de la unul dintre conturile tale legate sau sa creezi un nume unic si personalizat", + "nameChangeConfirm": "Vrei să-ți schimbi numele contului in ${NAME}?", + "resetProgressConfirmNoAchievementsText": "Această acțiune va reseta progresul co-op\nși high-score-urile (dar nu și biletele) și nu\npoate fi anulată. Ești sigur(ă)?", + "resetProgressConfirmText": "Această acțiune va reseta progresul\nco-op, realizările și high-scoreurile\n(dar nu și biletele) și nu poate fi\nanulată. Ești sigur(ă)?", + "resetProgressText": "Resetează progresul", + "setAccountName": "Setează-ți numele contului", + "setAccountNameDesc": "Selectează-ți numele dorit pentru contul tău.\nPoți folosi și numele unui cont de-al tău\nsau să creezi un joc unic personalizat.", "signInInfoText": "Conectează-te pentru a colecta bilete, a juca online,\nşi a juca cu acelaşi cont pe dispozitive diferite.", "signInText": "Conectează-te", "signInWithDeviceInfoText": "(un cont automat care este disponibil doar pe acest dispozitiv)", - "signInWithDeviceText": "Conectează-te cu un cont de dispozitiv", - "signInWithGameCircleText": "Conectrază-te cu Game Circle", + "signInWithDeviceText": "Conectează-te cu un cont de tip dispozitiv", + "signInWithGameCircleText": "Conectează-te cu Game Circle", "signInWithGooglePlayText": "Conectează-te cu Google Play", - "signInWithTestAccountInfoText": "(tip de cont normal; foloseşte conturi de dispozitiv şi cele noi)", + "signInWithTestAccountInfoText": "(tip de cont normal; foloseşte conturile de tip dispozitiv şi cele noi)", "signInWithTestAccountText": "Conectează-te cu un cont de test.", + "signInWithV2InfoText": "(un cont care funcționează pe toate platformele)", + "signInWithV2Text": "Conectează-te cu un cont Bombsquad", "signOutText": "Decoectează-te", "signingInText": "Se conecteză...", "signingOutText": "Se deconectează...", @@ -38,8 +40,9 @@ "testAccountWarningText": "Atenție: te conectezi cu un cont \"de test\". Acest cont\nva fi legat numai de acest dispozitiv și va fi resetat\nperiodic. (deci nu pierde prea mult timp colectând/\ndeblocând lucruri pe el)\n\nFolosește o versiune retail a jocului pentru a folosi\ncontul \"real\" (Game-Center, Google+ etc.). Aceasta te\nlasă să iți și salvezi progresul pe cloud și să îl\nîmparți pe mai multe dispozitive.", "ticketsText": "Bilete: ${COUNT}", "titleText": "Cont", - "unlinkAccountsInstructionsText": "Selecteaza un cont pentru a te deconecta", - "unlinkAccountsText": "Conturi deconectate", + "unlinkAccountsInstructionsText": "Selectează un cont pentru a-l deconecta", + "unlinkAccountsText": "Deconectează Conturi", + "v2LinkInstructionsText": "Folosește acest link pentru a creea un cont sau a te înregistra.", "viaAccount": "(prin contul ${NAME})", "youAreSignedInAsText": "Ești conectat ca și:" }, @@ -49,15 +52,15 @@ "Boom Goes the Dynamite": { "description": "Omoară 3 inamici folosind TNT", "descriptionComplete": "Ai omorât 3 inamici folosind TNT", - "descriptionFull": "Omoară 3 inamici folosind TNT la ${LEVEL}", - "descriptionFullComplete": "Ai omorât 3 inamici folosind TNT la ${LEVEL}", + "descriptionFull": "Omoară 3 inamici folosind TNT în ${LEVEL}", + "descriptionFullComplete": "Ai omorât 3 inamici folosind TNT în ${LEVEL}", "name": "Bum Face Dinamita" }, "Boxer": { - "description": "Câștigă fără a folosi bombe", - "descriptionComplete": "Ai câștigat fără sa folosești bombe", - "descriptionFull": "Completează ${LEVEL} fără sa folosești bombe", - "descriptionFullComplete": "Ai completat ${LEVEL} fără sa folosești bombe", + "description": "Câștigă fără să folosești vreo bombă", + "descriptionComplete": "Ai câștigat fără să folosești vreo bombă", + "descriptionFull": "Completează ${LEVEL} fără să folosești vreo bombă", + "descriptionFullComplete": "Ai completat ${LEVEL} fără sa folosești vreo bombă", "name": "Boxer" }, "Dual Wielding": { @@ -73,22 +76,22 @@ "name": "Victorie perfectă" }, "Free Loader": { - "descriptionFull": "Porneşte un joc Fiecare-pentru-el cu 2+ jucători", - "descriptionFullComplete": "Ai pornit un joc Fiecare-pentru-el cu 2+ jucători", + "descriptionFull": "Porneşte un joc Fiecare-Pentru-El cu 2+ jucători", + "descriptionFullComplete": "Ai pornit un joc Fiecare-Pentru-El cu 2+ jucători", "name": "Încărcător Liber" }, "Gold Miner": { "description": "Omoară 6 inamici folosind mine", "descriptionComplete": "Ai omorât 6 inamici folosind mine", - "descriptionFull": "Omoară 6 inamici folosind mine la ${LEVEL}", - "descriptionFullComplete": "Ai omorât 6 inamici folosind mine la ${LEVEL}", + "descriptionFull": "Omoară 6 inamici folosind mine în ${LEVEL}", + "descriptionFullComplete": "Ai omorât 6 inamici folosind mine în ${LEVEL}", "name": "Miner de aur" }, "Got the Moves": { - "description": "Câștigă fără a folosi pumnii sau bombe", + "description": "Câștigă fără să folosești pumni sau bombe", "descriptionComplete": "Ai câștigat fără să folosești pumnii sau bombele", "descriptionFull": "Câștigă ${LEVEL} fără să folosești pumni sau bombe", - "descriptionFullComplete": "Ai câștigat ${LEVEL} fără sa folosești pumni sau bombe", + "descriptionFullComplete": "Ai câștigat ${LEVEL} fără să folosești pumni sau bombe", "name": "Știi mișcările" }, "In Control": { @@ -97,95 +100,95 @@ "name": "În control" }, "Last Stand God": { - "description": "Marchează 1000 puncte", - "descriptionComplete": "A marcat 1000 de puncte", - "descriptionFull": "Înscrie 1000 de punctele la ${LEVEL}", - "descriptionFullComplete": "Ai înscris 1000 puncte la ${LEVEL}", - "name": "Zeu ${LEVEL}" + "description": "Marchează 1000 de puncte", + "descriptionComplete": "Ai marcat 1000 de puncte", + "descriptionFull": "Înscrie 1000 de punctele în ${LEVEL}", + "descriptionFullComplete": "Ai înscris 1000 de puncte în ${LEVEL}", + "name": "Zeu la ${LEVEL}" }, "Last Stand Master": { - "description": "Înscrie 250 puncte", - "descriptionComplete": "Ai înscris 250 puncte", - "descriptionFull": "Înscrie 250 puncte la ${LEVEL}", - "descriptionFullComplete": "Ai înscris 250 puncte la ${LEVEL}", + "description": "Înscrie 250 de puncte", + "descriptionComplete": "Ai înscris 250 de puncte", + "descriptionFull": "Înscrie 250 puncte în ${LEVEL}", + "descriptionFullComplete": "Ai înscris 250 puncte în ${LEVEL}", "name": "Maestru ${LEVEL}" }, "Last Stand Wizard": { "description": "Înscrie 500 de puncte", - "descriptionComplete": "Ai înscris 500 puncte", - "descriptionFull": "Înscrie 500 puncte la ${LEVEL}", - "descriptionFullComplete": "Ai înscris 500 punce la ${LEVEL}", + "descriptionComplete": "Ai înscris 500 de puncte", + "descriptionFull": "Înscrie 500 de puncte în ${LEVEL}", + "descriptionFullComplete": "Ai înscris 500 de puncte în ${LEVEL}", "name": "Vrăjitor ${LEVEL}" }, "Mine Games": { - "description": "Omoară 3 inamici cu mine", - "descriptionComplete": "Omoară 3 inamici folosind mine", - "descriptionFull": "Omoară 3 inamici folosind mine la ${LEVEL}", - "descriptionFullComplete": "Ai omorât 3 inamici folosind mine la ${LEVEL}", + "description": "Omoară 3 inamici folosind mine", + "descriptionComplete": "Ai omorât 3 inamici folosind mine", + "descriptionFull": "Omoară 3 inamici folosind mine în ${LEVEL}", + "descriptionFullComplete": "Ai omorât 3 inamici folosind mine în ${LEVEL}", "name": "Jocurile minelor" }, "Off You Go Then": { - "description": "Aruncă 3 inamici peste hartă", - "descriptionComplete": "Ai aruncat 3 inamici peste hartă", - "descriptionFull": "Aruncă 3 inamici peste hartă la ${LEVEL}", - "descriptionFullComplete": "Ai aruncat 3 inamici peste hartă la ${LEVEL}", + "description": "Aruncă 3 inamici de pe hartă", + "descriptionComplete": "Ai aruncat 3 inamici de pe hartă", + "descriptionFull": "Aruncă 3 inamici de pe hartă în ${LEVEL}", + "descriptionFullComplete": "Ai aruncat 3 inamici de pe hartă în ${LEVEL}", "name": "Jos cu tine" }, "Onslaught God": { - "description": "Înscrie 5000 puncte", - "descriptionComplete": "Ai înscris 5000 puncte", - "descriptionFull": "Înscrie 5000 puncte la ${LEVEL}", - "descriptionFullComplete": "Ai înscris 5000 puncte la ${LEVEL}", - "name": "Zeu ${LEVEL}" + "description": "Înscrie 5000 de puncte", + "descriptionComplete": "Ai înscris 5000 de puncte", + "descriptionFull": "Înscrie 5000 de puncte în ${LEVEL}", + "descriptionFullComplete": "Ai înscris 5000 de puncte în ${LEVEL}", + "name": "Zeu la ${LEVEL}" }, "Onslaught Master": { - "description": "Înscrie 500 puncte", - "descriptionComplete": "Ai înscris 500 puncte", - "descriptionFull": "Înscrie 500 puncte la ${LEVEL}", - "descriptionFullComplete": "Ai înscris 500 puncte ${LEVEL}", - "name": "Maestru ${LEVEL}" + "description": "Înscrie 500 de puncte", + "descriptionComplete": "Ai înscris 500 de puncte", + "descriptionFull": "Înscrie 500 de puncte în ${LEVEL}", + "descriptionFullComplete": "Ai înscris 500 de puncte ${LEVEL}", + "name": "Maestru la ${LEVEL}" }, "Onslaught Training Victory": { "description": "Înfrânge toate valurile", "descriptionComplete": "Ai înfrânt toate valurile", - "descriptionFull": "Înfrânge toate valurile la ${LEVEL}", - "descriptionFullComplete": "Ai înfrânt toate valurile la ${LEVEL}", + "descriptionFull": "Înfrânge toate valurile în ${LEVEL}", + "descriptionFullComplete": "Ai înfrânt toate valurile în ${LEVEL}", "name": "Victorie ${LEVEL}" }, "Onslaught Wizard": { - "description": "Inscrie 1000 de puncte", - "descriptionComplete": "Ai insris 100 de puncte", - "descriptionFull": "Inscrie 1000 de puncte in ${LEVEL}", - "descriptionFullComplete": "Ai insris 1000 de puncte in ${LEVEL}", - "name": "Vrajitor ${LEVEL}" + "description": "Înscrie 1000 de puncte", + "descriptionComplete": "Ai înscris 1000 de puncte", + "descriptionFull": "Înscrie 1000 de puncte în ${LEVEL}", + "descriptionFullComplete": "Ai înscris 1000 de puncte în ${LEVEL}", + "name": "Vrăjitor ${LEVEL}" }, "Precision Bombing": { "description": "Câștigă fără să folosești powerup-uri", "descriptionComplete": "Ai câștigat fără să folosești powerup-uri", "descriptionFull": "Câștigă ${LEVEL} fără să folosești powerup-uri", - "descriptionFullComplete": "Ai câștigat ${LEVEL}. fără să folosești powerup-uri", + "descriptionFullComplete": "Ai câștigat ${LEVEL} fără să folosești powerup-uri", "name": "Bombardament de precizie" }, "Pro Boxer": { - "description": "Castiga fara sa folosesti vreo bomba", - "descriptionComplete": "Ai castigat fara sa folosesti vreo bomba", - "descriptionFull": "Completeaza ${LEVEL} fara sa folosesti vreo bomba", - "descriptionFullComplete": "Ai completat ${LEVEL} fara sa folosesti vreo bomba", - "name": "Boxeor profesionist" + "description": "Câștigă fără să folosești vreo bombă", + "descriptionComplete": "Ai câștigat fără să folosești vreo bombă", + "descriptionFull": "Completează ${LEVEL} fără să folosești vreo bombă", + "descriptionFullComplete": "Ai completat ${LEVEL} fără să folosești vreo bombă", + "name": "Boxeor Profesionist" }, "Pro Football Shutout": { - "description": "Castiga fara sa ii lasi pe inamici sa inscrie", - "descriptionComplete": "Ai castigat fară sa îi laşi le inamici sa inscrie", - "descriptionFull": "Castiga ${LEVEL} fara sa ii lasi pe inamici sa inscrie", - "descriptionFullComplete": "Ai câștigat ${LEVEL} fără să lași pe inamici să înscrie", - "name": "Shutout ${LEVEL}" + "description": "Câștigă fără să-i lași pe inamici să înscrie", + "descriptionComplete": "Ai câștigat fără să-i lași pe inamici să înscrie", + "descriptionFull": "Câștigă ${LEVEL} fără să-i lași pe inamici să înscrie", + "descriptionFullComplete": "Ai câștigat ${LEVEL} fără să-i lași pe inamici să înscrie", + "name": "Shut-out ${LEVEL}" }, "Pro Football Victory": { "description": "Câștigă jocul", "descriptionComplete": "Ai câștigat jocul", "descriptionFull": "Câștigă jocul din ${LEVEL}", "descriptionFullComplete": "Ai câștigat jocul din ${LEVEL}", - "name": "Victorie ${LEVEL}" + "name": "Victorie în ${LEVEL}" }, "Pro Onslaught Victory": { "description": "Înfrânge toate valurile", @@ -197,51 +200,51 @@ "Pro Runaround Victory": { "description": "Completează toate valurile", "descriptionComplete": "Ai completat toate valurile", - "descriptionFull": "Completează toate valurile la ${LEVEL}", - "descriptionFullComplete": "Ai completat toate valurile la ${LEVEL}", + "descriptionFull": "Completează toate valurile din ${LEVEL}", + "descriptionFullComplete": "Ai completat toate valurile din ${LEVEL}", "name": "Victorie ${LEVEL}" }, "Rookie Football Shutout": { - "description": "Câștigă fără să înscrie tipii răi", - "descriptionComplete": "Ai câștigat fără să înscrie tipii răi", - "descriptionFull": "Câștigă ${LEVEL} fără să înscrie tipii răi", - "descriptionFullComplete": "Ai câștigat ${LEVEL} fără să înscrie tipii răi", - "name": "Shutout ${LEVEL}" + "description": "Câștigă fără să-i lași pe tipii răi să înscrie", + "descriptionComplete": "Ai câștigat fără să-i lași pe tipii răi să înscrie", + "descriptionFull": "Câștigă ${LEVEL} fără să-i lași pe tipii răi să înscrie", + "descriptionFullComplete": "Ai câștigat ${LEVEL} fără să-i lași pe tipii răi să înscrie", + "name": "Shut-out ${LEVEL}" }, "Rookie Football Victory": { "description": "Câștigă jocul", "descriptionComplete": "Ai câștigat jocul", - "descriptionFull": "Câștigă jocul la ${LEVEL}", - "descriptionFullComplete": "Ai câștigat jocul la ${LEVEL}", + "descriptionFull": "Câștigă jocul din ${LEVEL}", + "descriptionFullComplete": "Ai câștigat jocul din ${LEVEL}", "name": "Victorie ${LEVEL}" }, "Rookie Onslaught Victory": { - "description": "Învinge toate trupele", - "descriptionComplete": "Învinge toate trupele", - "descriptionFull": "Învinge toate trupele în ${LEVEL}", - "descriptionFullComplete": "Învinge toate trupele în ${LEVEL}", - "name": "${LEVEL} Victorie" + "description": "Înfrânge toate valurile", + "descriptionComplete": "Ai înfrânt toate valurile", + "descriptionFull": "Înfrânge toate valurile din ${LEVEL}", + "descriptionFullComplete": "Ai înfrânt toate valurile din ${LEVEL}", + "name": "Victorie în ${LEVEL}" }, "Runaround God": { - "description": "Strânge 2000 de puncte", - "descriptionComplete": "Strânge 2000 de puncte", - "descriptionFull": "Strânge 2000 de puncte în ${LEVEL}", - "descriptionFullComplete": "Strânge 2000 de puncte în ${LEVEL}", - "name": "${LEVEL} Zeu" + "description": "Înscrie 2000 de puncte", + "descriptionComplete": "Ai înscris 2000 de puncte", + "descriptionFull": "Înscrie 2000 de puncte în ${LEVEL}", + "descriptionFullComplete": "Ai înscris 2000 de puncte în ${LEVEL}", + "name": "Zeu la ${LEVEL}" }, "Runaround Master": { - "description": "Strânge 500 de puncte", - "descriptionComplete": "Ai strâns 500 de puncte", - "descriptionFull": "Strânge 500 de puncte în ${LEVEL}", - "descriptionFullComplete": "Ai strâns 500 de puncte în ${LEVEL}", + "description": "Înscrie 500 de puncte", + "descriptionComplete": "Ai înscris 500 de puncte", + "descriptionFull": "Înscrie 500 de puncte în ${LEVEL}", + "descriptionFullComplete": "Ai înscris 500 de puncte în ${LEVEL}", "name": "Maestru la ${LEVEL}" }, "Runaround Wizard": { - "description": "Strânge 1000 de puncte", + "description": "Înscrie 1000 de puncte", "descriptionComplete": "Ai strâns 1000 de puncte", - "descriptionFull": "Strânge 1000 de puncte pe ${LEVEL}", - "descriptionFullComplete": "Ai strâns 1000 de puncte pe ${LEVEL}", - "name": "Vrăjitor la ${LEVEL}" + "descriptionFull": "Înscrie 1000 de puncte în ${LEVEL}", + "descriptionFullComplete": "Ai înscris 1000 de puncte în ${LEVEL}", + "name": "Vrăjitorul din ${LEVEL}" }, "Sharing is Caring": { "descriptionFull": "Împărtăşeşte jocul cu un prieten", @@ -249,79 +252,79 @@ "name": "E bine să împarți" }, "Stayin' Alive": { - "description": "Câştigă fără a muri", - "descriptionComplete": "Ai câştigat fără a muri", - "descriptionFull": "Câştigă pe ${LEVEL} fără a muri", - "descriptionFullComplete": "Ai câştigat pe ${LEVEL} fără a muri", - "name": "Rămănând in viață" + "description": "Câştigă fără să mori", + "descriptionComplete": "Ai câştigat fără să mori", + "descriptionFull": "Câştigă ${LEVEL} fără să mori", + "descriptionFullComplete": "Ai câştigat ${LEVEL} fără să mori", + "name": "Rămănând în viață" }, "Super Mega Punch": { - "description": "Cauzează un damage de 100% cu o lovitură", - "descriptionComplete": "Ai cauzat un damage de 100% cu o lovitură", - "descriptionFull": "Cauzează un damage de 100% cu o lovitură în ${LEVEL}", - "descriptionFullComplete": "Ai cauzat un damage de 100% cu o lovitură în ${LEVEL}", - "name": "Lovitură super mega" + "description": "Cauzează o daună de 100% cu o singură lovitură", + "descriptionComplete": "Ai cauzat o daună de 100% cu o singură lovitură", + "descriptionFull": "Cauzează o daună de 100% cu o singură lovitură în ${LEVEL}", + "descriptionFullComplete": "Ai cauzat o daună de 100% cu o singură lovitură în ${LEVEL}", + "name": "Super Mega Lovitură" }, "Super Punch": { - "description": "Cauzează un damage de 50% cu o lovitură", - "descriptionComplete": "Ai cauzat un damage de 50% cu o lovitură", - "descriptionFull": "Cauzează un damage de 50% cu o lovitură în ${LEVEL}", - "descriptionFullComplete": "Ai cauzat un damage de 50% cu o lovitură în ${LEVEL}", + "description": "Cauzează o daună de 50% cu o singură lovitură", + "descriptionComplete": "Ai cauzat o daună de 50% cu o singură lovitură", + "descriptionFull": "Cauzează o daună de 50% cu o singură lovitură în ${LEVEL}", + "descriptionFullComplete": "Ai cauzat o daună de 50% cu o singură lovitură în ${LEVEL}", "name": "Super Pumn" }, "TNT Terror": { - "description": "Omoară 6 tipi răi cu TNT", - "descriptionComplete": "Ai omorât 6 tipi răi cu TNT", - "descriptionFull": "Omoară 6 tipi răi cu TNT la ${LEVEL}", - "descriptionFullComplete": "Ai omorât 6 tipi răi cu TNT la ${LEVEL}", - "name": "Teroarea TNT" + "description": "Omoară 6 inamici folosind TNT", + "descriptionComplete": "Ai omorât 6 inamici folosind TNT", + "descriptionFull": "Omoară 6 inamici folosind TNT în ${LEVEL}", + "descriptionFullComplete": "Ai omorât 6 inamici folosind TNT în ${LEVEL}", + "name": "Teroarea cu TNT" }, "Team Player": { "descriptionFull": "Porneşte un joc pe Echipe cu 4+ jucători", "descriptionFullComplete": "Ai pornit un joc pe Echipe cu 4+ jucători", - "name": "Jucător in Echipă" + "name": "Jucător în Echipă" }, "The Great Wall": { "description": "Opreşte fiecare tip rău", "descriptionComplete": "Ai oprit fiecare tip rău", - "descriptionFull": "Opreşte fiecare tip rău în ${LEVEL}", - "descriptionFullComplete": "Ai oprit fiecare tip rău în ${LEVEL}", - "name": "Marele zid" + "descriptionFull": "Opreşte fiecare tip rău din ${LEVEL}", + "descriptionFullComplete": "Ai oprit fiecare tip rău din ${LEVEL}", + "name": "Marele Zid" }, "The Wall": { "description": "Oprește fiecare tip rău", "descriptionComplete": "Ai oprit fiecare tip rău", - "descriptionFull": "Oprește fiecare tip rău la ${LEVEL}", - "descriptionFullComplete": "Ai oprit fiecare tip rău la ${LEVEL}", + "descriptionFull": "Oprește fiecare tip rău din ${LEVEL}", + "descriptionFullComplete": "Ai oprit fiecare tip rău din ${LEVEL}", "name": "Zidul" }, "Uber Football Shutout": { - "description": "Câștigă fără să lași pe inamici să înscrie", - "descriptionComplete": "Ai câștigat fără să lași pe inamici să înscrie", - "descriptionFull": "Câștigă ${LEVEL} fără să lași pe inamici să înscrie", - "descriptionFullComplete": "Ai câștigat ${LEVEL} fără să lași pe inamici să înscrie", - "name": "Shutout ${LEVEL}" + "description": "Câștigă fără să-i lași pe inamici să înscrie", + "descriptionComplete": "Ai câștigat fără să-i lași pe inamici să înscrie", + "descriptionFull": "Câștigă ${LEVEL} fără să-i lași pe inamici să înscrie", + "descriptionFullComplete": "Ai câștigat ${LEVEL} fără să-i lași pe inamici să înscrie", + "name": "Shut-out ${LEVEL}" }, "Uber Football Victory": { "description": "Câștigă jocul", "descriptionComplete": "Ai câștigat jocul", - "descriptionFull": "Câștigă jocul la ${LEVEL}", - "descriptionFullComplete": "Ai câștigat jocul la ${LEVEL}", - "name": "Victorie ${LEVEL}" + "descriptionFull": "Câștigă jocul din ${LEVEL}", + "descriptionFullComplete": "Ai câștigat jocul din ${LEVEL}", + "name": "Victorie în ${LEVEL}" }, "Uber Onslaught Victory": { "description": "Înfrânge toate valurile", "descriptionComplete": "Ai înfrânt toate valurile", - "descriptionFull": "Înfrânge toate valurile la ${LEVEL}", - "descriptionFullComplete": "Ai înfrânt toate valurile la ${LEVEL}", - "name": "Victorie ${LEVEL}" + "descriptionFull": "Înfrânge toate valurile din ${LEVEL}", + "descriptionFullComplete": "Ai înfrânt toate valurile din ${LEVEL}", + "name": "Victorie în ${LEVEL}" }, "Uber Runaround Victory": { "description": "Completează toate valurile", "descriptionComplete": "Ai completat toate valurile", - "descriptionFull": "Completează toate valurile la ${LEVEL}", - "descriptionFullComplete": "Ai terminat toate valurile de la ${LEVEL}", - "name": "Victorie ${LEVEL}" + "descriptionFull": "Completează toate valurile din ${LEVEL}", + "descriptionFullComplete": "Ai terminat toate valurile din ${LEVEL}", + "name": "Victorie în ${LEVEL}" } }, "achievementsRemainingText": "Realizări rămase:", @@ -329,216 +332,217 @@ "achievementsUnavailableForOldSeasonsText": "Scuze, dar detaliile realizărilor din sezoanele trecute sunt indisponibile.", "addGameWindow": { "getMoreGamesText": "Ia mai multe jocuri...", - "titleText": "Adaugă joc" + "titleText": "Adaugă un joc" }, "allowText": "Permite", - "alreadySignedInText": "Contul dvs. este conectat de pe un alt dispozitiv;\nvă rugăm să schimbați conturile sau să închideți jocul pe\nalte dispozitive și încercați din nou.", - "apiVersionErrorText": "Nu se poate deschide moduluL ${NAME}; acela accesează versiunea api ${VERSION_USED}, pe când e nevoie de ${VERSION_REQUIRED}.", + "alreadySignedInText": "Contul tău este deja conectat de pe un alt dispozitiv;\nte rog să schimbi conturile sau să închizi jocul de pe\nalte dispozitive și să încerci din nou.", + "apiVersionErrorText": "Nu se poate deschide moduluL ${NAME}; acela accesează versiunea api ${VERSION_USED}, pe când versiunea ${VERSION_REQUIRED} este nevoită.", "audioSettingsWindow": { "headRelativeVRAudioInfoText": "(\"Auto\" activează asta doar când căștile sunt conectate)", "headRelativeVRAudioText": "Audio VR relativ capului", - "musicVolumeText": "Volum muzică", - "soundVolumeText": "Volum sunete", + "musicVolumeText": "Volumul Muzicii", + "soundVolumeText": "Volumul Sunetelor", "soundtrackButtonText": "Coloană sonoră", - "soundtrackDescriptionText": "(setează ce muzică sa cânte în timpul jocului)", + "soundtrackDescriptionText": "(selectează muzica care vrei să cânte în timpul jocului)", "titleText": "Audio" }, "autoText": "Automat", "backText": "Înapoi", - "banThisPlayerText": "Interzice acest jucator", - "bestOfFinalText": "Finală cel-mai-bun-din-${COUNT}", - "bestOfSeriesText": "Serii cel mai bun din ${COUNT}:", - "bestRankText": "Cea mai bună poziție a ta: #${RANK}", - "bestRatingText": "Cel mai bun rating al tău e ${RATING}", + "banThisPlayerText": "Interzice Accesul Acestui Jucător", + "bestOfFinalText": "Finala cel-mai-bun-din-${COUNT}", + "bestOfSeriesText": "Seriile cel mai bun din ${COUNT}:", + "bestRankText": "Cea mai bună poziție a ta este: #${RANK}", + "bestRatingText": "Cel mai bun rating al tău este ${RATING}", "bombBoldText": "BOMBĂ", "bombText": "Bombă", - "boostText": "Viteza", - "bsRemoteConfigureInAppText": "${REMOTE_APP_NAME} se configureaza în însăși aplicatia", + "boostText": "Crește-ți", + "bsRemoteConfigureInAppText": "${REMOTE_APP_NAME} este configurat în aplicație", "buttonText": "buton", - "canWeDebugText": "Ai dori ca BombSquad să trimită automat bug-uri,\ncrash-uri și informații de bază programatorului?\n\nAceste informații nu conțin date personale și doar\najută la îmbunătățirea jocului.", + "canWeDebugText": "Ai vrea ca BombSquad să trimită automat bug-uri,\ncrash-uri și informații de bază programatorului jocului?\n\nAceste informații nu conțin date personale ci doar\najută la îmbunătățirea jocului.", "cancelText": "Anulează", - "cantConfigureDeviceText": "Scuze, dar ${DEVICE} nu e configurabil.", + "cantConfigureDeviceText": "Scuze, dar ${DEVICE} nu este configurabil.", "challengeEndedText": "Acest concurs s-a terminat.", "chatMuteText": "Dezactiveaza chat-ul", - "chatMutedText": "Chat dezactivat", - "chatUnMuteText": "Activeaza chat-ul", - "choosingPlayerText": "", + "chatMutedText": "Chat Dezactivat", + "chatUnMuteText": "Reactiveaza chat-ul", + "choosingPlayerText": "", "completeThisLevelToProceedText": "Trebuie să completezi\nacest nivel pentru a continua!", "completionBonusText": "Bonus de completare", "configControllersWindow": { "configureControllersText": "Configurează controllere", - "configureKeyboard2Text": "Configurează tastatură P2", - "configureKeyboardText": "Configurează tastatură", + "configureKeyboard2Text": "Configurează tastatura pentru P2", + "configureKeyboardText": "Configurează tastatura", "configureMobileText": "Dispozitive mobile ca și controllere", - "configureTouchText": "Configurează touchscreen", - "ps3Text": "Controllere PS3", + "configureTouchText": "Configurează Touchscreen", + "ps3Text": "Controllere de PS3", "titleText": "Controllere", - "wiimotesText": "Wiimotes", - "xbox360Text": "Controllere X-Box 360" + "wiimotesText": "Controllere pentru Wii", + "xbox360Text": "Controllere de X-Box 360" }, "configGamepadSelectWindow": { - "androidNoteText": "Notă: suportul controllerului poate varia de la versiunea android și de la dispozitiv.", - "pressAnyButtonText": "Apasă ce buton de pe controller\nVrei să configurezi...", + "androidNoteText": "Notă: suportul pentru controllere poate varia de la versiunea android și de la dispozitiv.", + "pressAnyButtonText": "Apasă pe orice buton de pe controllerul\npe care ai vrea să-l configurezi...", "titleText": "Configurează controllere" }, "configGamepadWindow": { "advancedText": "Avansat", "advancedTitleText": "Setări controller avansate", - "analogStickDeadZoneDescriptionText": "(Ridică valoarea acestuia dacă iți \"alunecă\" omulețul când dai drumul la 'stick)", - "analogStickDeadZoneText": "Dead-zone 'stick analog", - "appliesToAllText": "(se aplică la toate controllerele de acest tip)", - "autoRecalibrateDescriptionText": "(activează asta dacă omulețul nu se mișcă la viteza maximă)", - "autoRecalibrateText": "Recalibrare automată 'stick analog", + "analogStickDeadZoneDescriptionText": "(Ridică valoarea acestuia dacă iți \"alunecă\" caracterul când dai drumul la \"stick\")", + "analogStickDeadZoneText": "Zona-Moartă a Stick-ului Analog", + "appliesToAllText": "(se aplică la toate controllerele de acest fel)", + "autoRecalibrateDescriptionText": "(activează asta dacă caracterul tău nu se mișcă la viteza maximă)", + "autoRecalibrateText": "Recalibrare Automată a Stick-ului Analog", "axisText": "axă", "clearText": "șterge", "dpadText": "D-pad", - "extraStartButtonText": "Buton start secundar", - "ifNothingHappensTryAnalogText": "Dacă nu se întâmplă nimic, încearcă să folosești 'stick-ul analog.", - "ifNothingHappensTryDpadText": "Dacă nimic nu se întâmplă, încearcă d-pad-ul.", - "ignoreCompletelyDescriptionText": "(fă ca acest controller sa nu afecteze jocul sau meniul)", - "ignoreCompletelyText": "Ignorare completa", - "ignoredButton1Text": "Buton ignorat 1", - "ignoredButton2Text": "Buton ignorat 2", - "ignoredButton3Text": "Buton ignorat 3", - "ignoredButton4Text": "Butonul 4 Ignorat", - "ignoredButtonDescriptionText": "(folosește asta pentru butoane ca 'home' sau 'sync' pentru a fi ignorate de joc)", + "extraStartButtonText": "Buton Start Secundar", + "ifNothingHappensTryAnalogText": "Dacă nu se întâmplă nimic, încearcă să folosești stick-ul analog.", + "ifNothingHappensTryDpadText": "Dacă nu se întâmplă nimic, încearcă D-pad-ul.", + "ignoreCompletelyDescriptionText": "(fă în așa fel încât acest controller sa nu afecteze jocul sau meniul)", + "ignoreCompletelyText": "Ignoră-l Complet", + "ignoredButton1Text": "Buton Ignorat 1", + "ignoredButton2Text": "Buton Ignorat 2", + "ignoredButton3Text": "Buton Ignorat 3", + "ignoredButton4Text": "Buton Ignorat 4", + "ignoredButtonDescriptionText": "(folosește asta pentru ca butoanele 'home' sau 'sync' să fie ignorate în timpul jocului)", "pressAnyAnalogTriggerText": "Apasă orice trigger analog...", - "pressAnyButtonOrDpadText": "Apasă orice buton sau dpad-ul...", + "pressAnyButtonOrDpadText": "Apasă orice buton sau D-Pad-ul", "pressAnyButtonText": "Apasă orice buton...", - "pressLeftRightText": "Apasă stânga/dreapta...", - "pressUpDownText": "Apasă sus/jos...", - "runButton1Text": "Buton fugă 1", - "runButton2Text": "Buton fugă 2", - "runTrigger1Text": "Trigger fugă 1", - "runTrigger2Text": "Trigger fugă 2", + "pressLeftRightText": "Apasă stânga sau dreapta...", + "pressUpDownText": "Apasă sus sau jos...", + "runButton1Text": "Buton de Fugă 1", + "runButton2Text": "Buton de Fugă 2", + "runTrigger1Text": "Trigger de Fugă 1", + "runTrigger2Text": "Trigger de Fugă 2", "runTriggerDescriptionText": "(trigger-urile analogice te lasă să alergi la viteze diferite)", - "secondHalfText": "Foloseşte această opțiune pentru a configura\na doua parte dintr-un 2-controllere-în-1 controller\ncare se arată ca unul singur.", + "secondHalfText": "Foloseşte această opțiune pentru a configura\na doua parte dintr-un dispozitiv 2-controllere-în-1 \ncare defapt se arată ca unul singur.", "secondaryEnableText": "Permite", - "secondaryText": "Controller secundar", + "secondaryText": "Controller Secundar", "startButtonActivatesDefaultDescriptionText": "(opreşte această funcție dacă butonul tău de start este un buton de 'meniu')", - "startButtonActivatesDefaultText": "Butonul Start activează Widget-ul Implicit", - "titleText": "Setup pentru controller", - "twoInOneSetupText": "Setup pentru un controller 2-în-1", - "uiOnlyDescriptionText": "(blochează acest controller pentru a nu putea intra in joc)", - "uiOnlyText": "Limiteaza la controluri", - "unassignedButtonsRunText": "Toate butoanele neatrebuite rulează", + "startButtonActivatesDefaultText": "Butonul de Start Activează Widget-ul Implicit", + "titleText": "Setup Pentru Controller", + "twoInOneSetupText": "Setup Pentru Un Controller 2-în-1", + "uiOnlyDescriptionText": "(nu-i permite acestui controller să intre în joc)", + "uiOnlyText": "Limitează la Folosirea Meniului", + "unassignedButtonsRunText": "Toate Butoanele Neatribuite Rulează", "unsetText": "<șterge>", - "vrReorientButtonText": "Buton de reorientare VR" + "vrReorientButtonText": "Buton de Reorientare VR" }, "configKeyboardWindow": { - "configuringText": "Se configurează ${DEVICE}", - "keyboard2NoteText": "Notă: multe tastaturi pot inregistra doar câteva apăsări\nodată, deci avănd o a doua tastatură ar merge mai bine\ndacă este un al doilea jucător.\nNotează că va trebui să editezi controlurile la amândoi\njucători, chiar şi în cazul de mai sus." + "configuringText": "${DEVICE} se configurează", + "keyboard2NoteText": "Notă: multe tastaturi pot inregistra doar câteva apăsări\nde-odată, deci avănd altă tastatură ar merge mai bine\ndacă există un al doilea jucător.\nȚine minte că va trebui să aplici controale diferite celor doi jucători,\nchiar şi în cazul de mai sus." }, "configTouchscreenWindow": { - "actionControlScaleText": "Dimensiune controluri acțiuni", + "actionControlScaleText": "Dimensiune Controluri Acțiuni", "actionsText": "Acțiuni", "buttonsText": "butoane", - "dragControlsText": "< trage de controluri pentru a le poziționa >", + "dragControlsText": "< trage de controluri pentru a le repoziționa >", "joystickText": "joystick", - "movementControlScaleText": "Dimensiune control mișcare", + "movementControlScaleText": "Dimensiune Control Mișcare", "movementText": "Mișcare", "resetText": "Resetare", - "swipeControlsHiddenText": "Ascunde iconițele swipe", - "swipeInfoText": "Modul \"swipe\" are nevoie de puțin antrenament, dar e mai\nușor să joci fără să te uiți la controluri.", + "swipeControlsHiddenText": "Ascunde Iconițele De Glisare", + "swipeInfoText": "Durează ceva timp până te înveți cu controalele de tip 'Glisare'\ndar o să-ți fie mult mai ușor să te joci fără să te uiți la controale.", "swipeText": "glisare", - "titleText": "Configurează touchscreen" + "titleText": "Configurează Touchscreen-ul" }, - "configureItNowText": "Configurează acum?", + "configureItNowText": "Vrei să îl configurezi acum?", "configureText": "Configurează", "connectMobileDevicesWindow": { - "amazonText": "Amazon appstore", - "appStoreText": "App store", - "bestResultsText": "Pentru cele mai bune rezultate vei avea nevoie de o rețea Wi-Fi \nfără lag. Poți să reduci lag-ul prin oprirea Wi-Fi-ului altor telefoane,\nprin jucarea lângă router, şi prin conectarea \"jocului-mamă\" direct la rețea\nprin Ethernet.", - "explanationText": "Pentru a folosi un telefon inteligent sau o tabletă drept controller, instalează\naplicația \"${REMOTE_APP_NAME}\" pe el. Orice număr de dispozitive se pot conecta la\nun joc ${APP_NAME} peste Wi-Fi, şi este gratis!", + "amazonText": "Amazon Appstore", + "appStoreText": "App Store", + "bestResultsText": "Pentru cele mai bune rezultate vei avea nevoie de o rețea Wi-Fi \nfără lag. Poți să reduci lag-ul prin oprirea Wi-Fi-ului de pe alte telefoane,\nprin jucarea lângă router, sau prin conectarea \"jocului-mamă\" direct la rețea\nprin Ethernet.", + "explanationText": "Pentru a folosi un telefon sau o tabletă drept controller, instalează\naplicația \"${REMOTE_APP_NAME}\" pe acestea. Orice dispozitiv se poate conecta la\nun joc ${APP_NAME} prin Wi-Fi, şi este gratis!", "forAndroidText": "pentru Android:", "forIOSText": "Pentru iOS:", - "getItForText": "Ia-ți ${REMOTE_APP_NAME} pentru iOS din Apple App Store\nsau pentru Android din Google Play sau Amazon Appstore", + "getItForText": "Ia-ți aplicația ${REMOTE_APP_NAME} pentru iOS din Apple App Store,\npentru Android din Google Play Store sau de pe Amazon Appstore", "googlePlayText": "Google Play", - "titleText": "Pentru a folosi dispozitive mobile ca și controllere:" + "titleText": "Folosirea Dispozitivelor Mobile drept Controllere:" }, - "continuePurchaseText": "Continuă pentru ${PRICE}?", - "continueText": "Continuă", - "controlsText": "Controluri", + "continuePurchaseText": "Continui pentru ${PRICE}?", + "continueText": "Continui", + "controlsText": "Controale", "coopSelectWindow": { - "activenessAllTimeInfoText": "Acesta nu se aplică clasamentelor din totdeauna", - "activenessInfoText": "Acest multiplicator crește în zilele în\ncare joci și scade în cele in care nu", + "activenessAllTimeInfoText": "Acesta nu se aplică clasamentelor din totdeauna.", + "activenessInfoText": "Acest multiplicator crește în zilele în\ncare joci și scade în cele in care nu joci.", "activityText": "Activitate", "campaignText": "Campanie", "challengesInfoText": "Primeşte premii pentru completarea minijocurilor.\n\nPremiile şi dificultatea nivelelor cresc\nde fiecare dată când un Challenge este făcut\nşi scade când unul expiră sau este abandonat.", "challengesText": "Provocări", - "currentBestText": "Best-ul curent", - "customText": "Particularizat", - "entryFeeText": "Intrare", + "currentBestText": "Cel mai bun de până acum", + "customText": "Particularizare", + "entryFeeText": "Intrarea", "forfeitConfirmText": "Abandonezi acest challenge?", - "forfeitNotAllowedYetText": "Acest concurs nu poate fi abandonat acum.", - "forfeitText": "Abandonare", - "multipliersText": "Amplificatori", - "nextChallengeText": "Următorul Challenge", - "nextPlayText": "Următorul joc", + "forfeitNotAllowedYetText": "Acest concurs nu poate fi abandonat chiar acum.", + "forfeitText": "Abandonează", + "multipliersText": "Multiplicatori", + "nextChallengeText": "Challenge-ul Următor", + "nextPlayText": "Jocul Următor", "ofTotalTimeText": "din ${TOTAL}", - "playNowText": "Joacă acum", + "playNowText": "Joacă Acum", "pointsText": "Puncte", "powerRankingFinishedSeasonUnrankedText": "(ai terminat sezonul fără rank)", "powerRankingNotInTopText": "(nu eşti în top ${NUMBER})", - "powerRankingPointsEqualsText": "= ${NUMBER} puncte", + "powerRankingPointsEqualsText": "= ${NUMBER} (de) puncte", "powerRankingPointsMultText": "(x ${NUMBER} puncte)", "powerRankingPointsText": "${NUMBER} puncte", "powerRankingPointsToRankedText": "(${CURRENT} din ${REMAINING} puncte)", - "powerRankingText": "Rank de putere", + "powerRankingText": "Rank-ul Tău de Putere", "prizesText": "Premii", - "proMultInfoText": "Jucătorii cu upgradeul ${PRO} \nprimesc un bonus de ${PERCENT}% la puncte aici.", - "seeMoreText": "Mai mult...", - "skipWaitText": "Treci peste aşteptare", + "proMultInfoText": "Jucătorii cu upgrade-ul ${PRO} \nprimesc aici un bonus de ${PERCENT}% la puncte.", + "seeMoreText": "Mai multe...", + "skipWaitText": "Treci fără să mai aștepți", "timeRemainingText": "Timp Rămas", - "toRankedText": "Către rank", + "toRankedText": "Către Rank", "totalText": "total", - "tournamentInfoText": "Întrecete pentru scoruri mari\ncu alți jucători din liga ta.\n\nPremiile sunt dăruite jucătorilor cu\nscoruri in top când expiră concursul.", - "welcome1Text": "Bine ai venit la ${LEAGUE}. Poți să-ți măreşti\nrankul prin completarea medaliilor, câştigând trofee\nin concursuri şi prin rankul de 3 stele la jocuri.", - "welcome2Text": "Mai poți primii bilete şi prin alte activități de acelaşi fel.\nBiletele se pot folosi pentru a debloca charactere, hărți, şi\nmini-jocuri, intra in concursurii, şi altele.", - "yourPowerRankingText": "Rankul tău de putere:" + "tournamentInfoText": "Întrece-te pentru scoruri mari\ncu alți jucători din liga ta.\n\nPremiile sunt dăruite jucătorilor cu\nscoruri din top când expiră concursul.", + "welcome1Text": "Bine ai venit în ${LEAGUE}. Poți să-ți măreşti\nrankul prin adunarea medaliilor, câştigarea trofeelor\nîn concursuri şi prin rankul de 3 stele în jocuri.", + "welcome2Text": "Mai poți primi bilete şi prin alte activități de acelaşi fel.\nBiletele se pot folosi pentru a debloca charactere, hărți,\nmini-jocuri, pentru a intra în concursurii, şi multe altele.", + "yourPowerRankingText": "Rankul tău de Putere:" }, - "copyOfText": "Copie de ${NAME}", + "copyOfText": "Copie ${NAME}", + "copyText": "Copiază", "createEditPlayerText": "", - "createText": "Crează", + "createText": "Creează", "creditsWindow": { - "additionalAudioArtIdeasText": "Sunet adițional, Artă, și Idei de ${NAME}", - "additionalMusicFromText": "Muzică adițională de ${NAME}", - "allMyFamilyText": "Toți prietenii și familia care m-au ajutat să testez", + "additionalAudioArtIdeasText": "Sunet Adițional, Artă, și Idei de ${NAME}", + "additionalMusicFromText": "Muzică Adițională de ${NAME}", + "allMyFamilyText": "Toți prietenii și familia care m-au ajutat să testez jocul", "codingGraphicsAudioText": "Cod, Grafice, şi Audio de ${NAME}", "languageTranslationsText": "Traduceri:", "legalText": "Legal:", - "publicDomainMusicViaText": "Public-Muzica din domeniulc ${NAME}", - "softwareBasedOnText": "Acest software este bazat in partea de lucru al lui ${NAME}", + "publicDomainMusicViaText": "Muzica din domeniul Public ${NAME}", + "softwareBasedOnText": "Acest software este bazat în partea de lucru al lui ${NAME}", "songCreditText": "${TITLE} Performat de ${PERFORMER}\nCompus de ${COMPOSER}, Aranjat de ${ARRANGER}, Publicat de ${PUBLISHER},\ncurtoazie din ${SOURCE}", "soundAndMusicText": "Sunete & Muzică:", "soundsText": "Sunete (${SOURCE}):", "specialThanksText": "Mulțumiri speciale:", "thanksEspeciallyToText": "Mulțumiri deosebite: ${NAME}", "titleText": "Credite ${APP_NAME}", - "whoeverInventedCoffeeText": "Cine a inventat cafeaua" + "whoeverInventedCoffeeText": "Celui care a inventat cafeaua" }, "currentStandingText": "Rangul tău este #${RANK}", "customizeText": "Particularizează...", "deathsTallyText": "${COUNT} vieți pierdute", "deathsText": "Vieți pierdute", - "debugText": "Eliminare bugguri", + "debugText": "Eliminare de buguri", "debugWindow": { - "reloadBenchmarkBestResultsText": "Notă: Este recomandat ca tu să setezi Setări->Grafici->Texturi la 'Mare' când testezi.", + "reloadBenchmarkBestResultsText": "Notă: Este recomandat ca tu să te duci la Setări->Grafici->Texturi și să le dai pe 'Înalte' când testezi asta.", "runCPUBenchmarkText": "Rulează test CPU", "runGPUBenchmarkText": "Rulează test GPU", - "runMediaReloadBenchmarkText": "Pornește Media-Reîncarcă Contualizator", - "runStressTestText": "Pornește Test-Stres", - "stressTestPlayerCountText": "Numărătoare Playeri", - "stressTestPlaylistDescriptionText": "Lista de Redări pentru Testele de Stres", - "stressTestPlaylistNameText": "Numele listei de redare", - "stressTestPlaylistTypeText": "Tipul Listei de Redare", + "runMediaReloadBenchmarkText": "Pornește test de Încărcare Media", + "runStressTestText": "Pornește testul de stres", + "stressTestPlayerCountText": "Număr de Jucători", + "stressTestPlaylistDescriptionText": "Lista de Jocuri pentru Testele de Stres", + "stressTestPlaylistNameText": "Numele listei de jocuri", + "stressTestPlaylistTypeText": "Tipul Listei de Jocuri", "stressTestRoundDurationText": "Durata rundei", "stressTestTitleText": "Test de Stres", - "titleText": "Teste Stres şi repere", - "totalReloadTimeText": "Timp total de reîncărcare: ${TIME} (vezi logul pentru detalii)" + "titleText": "Teste de Stres şi repere", + "totalReloadTimeText": "Timp total de reîncărcare: ${TIME} (vezi jurnalul de activități pentru detalii)" }, - "defaultGameListNameText": "Lista de redare ${PLAYMODE} normală", - "defaultNewGameListNameText": "${PLAYMODE} Lista mea de redare.", + "defaultGameListNameText": "Lista de jocuri de ${PLAYMODE} normală", + "defaultNewGameListNameText": "Lista mea de jocuri de ${PLAYMODE}", "deleteText": "Șterge", "demoText": "Demo", "denyText": "Refuză", @@ -546,50 +550,50 @@ "difficultyEasyText": "Ușor", "difficultyHardOnlyText": "Numai pe \"Greu\"", "difficultyHardText": "Greu", - "difficultyHardUnlockOnlyText": "Acest nivel poate fi deblocat doar pe \"Greu\".\nCrezi că poți s-o faci?!?!", - "directBrowserToURLText": "Direcționează un browser web la următorul URL:", - "disableRemoteAppConnectionsText": "Dezactivați conexiunile la distanță", - "disableXInputDescriptionText": "Permite mai mult de 4 controlere dar nu va merge asa de bine", - "disableXInputText": "Dezactivați XInput", + "difficultyHardUnlockOnlyText": "Acest nivel poate fi deblocat numai pe \"Greu\".\nCrezi că poți s-o faci!?!?!", + "directBrowserToURLText": "Te rog să direcționezi un browser web la următorul URL:", + "disableRemoteAppConnectionsText": "Dezactivează conexiunile de pe Remote-App", + "disableXInputDescriptionText": "Permite mai mult de 4 controlere dar nu va merge chiar așa de bine.", + "disableXInputText": "Dezactivează XInput", "doneText": "Gata", - "drawText": "Egalitate", - "duplicateText": "Multiplica", + "drawText": "Remiză", + "duplicateText": "Multiplică", "editGameListWindow": { "addGameText": "Adaugă\nun joc", - "cantOverwriteDefaultText": "Nu poți î locuii lista de redare normală!", - "cantSaveAlreadyExistsText": "Un playlist cu acelaşi nume deja există!", - "cantSaveEmptyListText": "Nu se poate salva un playlist gol!", - "editGameText": "Editează\nUn joc", - "listNameText": "Numele playlistului", + "cantOverwriteDefaultText": "Nu poți înlocui lista de jocuri normală!", + "cantSaveAlreadyExistsText": "O listă de jocuri cu acelaşi nume deja există!", + "cantSaveEmptyListText": "Nu poți salva o listă goală!", + "editGameText": "Editează\nJocul", + "listNameText": "Numele Listei", "nameText": "Nume", - "removeGameText": "Şterge\nun joc", + "removeGameText": "Şterge\nJocul", "saveText": "Salvează Lista", - "titleText": "Editor Lista de redare." + "titleText": "Editor de Liste de Jocuri." }, "editProfileWindow": { - "accountProfileInfoText": "Acest profil special are nume\nşi imagice bazată pe contul tău.\n\n${ICONS}\n\nCreează profiluri personalizate\npentru a folosi nume sau diferite imagini.", - "accountProfileText": "(profil cont)", - "availableText": "Numele \"${NAME}\" este disponibil.", + "accountProfileInfoText": "Acest profil special are nume\nşi o imagine bazată pe contul tău.\n\n${ICONS}\n\nCreează profile personalizate\npentru a folosi nume sau iconițe personalizate.", + "accountProfileText": "(profil al contului)", + "availableText": "Numele \"${NAME}\" este utilizabil.", "changesNotAffectText": "Notă: schimbările nu vor afecta caracterele care sunt deja în joc", "characterText": "caracter", - "checkingAvailabilityText": "Se verifică disponibilitatea pentru \"${NAME}\". . .", + "checkingAvailabilityText": "Se verifică dacă numele \"${NAME}\" este disponibil...", "colorText": "culoare", - "getMoreCharactersText": "Ia mai multe...", - "getMoreIconsText": "Adună mai multe imagini...", - "globalProfileInfoText": "Profilurile globale de playeri sunt garantate \nsa aibă nume si imagini unice.", + "getMoreCharactersText": "Ia mai multe Caractere...", + "getMoreIconsText": "Ia mai multe iconițe...", + "globalProfileInfoText": "Profilurile globale ale jucătorilor sunt garantate \nsa aibă nume și iconițe unice.", "globalProfileText": "(profil global)", - "highlightText": "accente", - "iconText": "imagine", - "localProfileInfoText": "Profilurile locale nu au imagini şi numele lor nu sunt \ngarantate să fie speciale. Upgradează-ți profilul\npentru a rezerva un nume special şi să adaugi o imagine.", + "highlightText": "accent", + "iconText": "iconiță", + "localProfileInfoText": "Profilurile locale nu au iconițe şi numele lor nu sunt \ngarantate să fie speciale. Upgradează-ți profilul\npentru a rezerva un nume special şi să adaugi o iconiță.", "localProfileText": "(profil local)", - "nameDescriptionText": "Nume jucător", + "nameDescriptionText": "Numele Jucătorului", "nameText": "Nume", - "randomText": "aleator", - "titleEditText": "Editează profil", + "randomText": "auto-generat", + "titleEditText": "Editează profilul", "titleNewText": "Profil nou", - "unavailableText": "\"${NAME}\" nu este disponibil; încearcă alt nume.", - "upgradeProfileInfoText": "Acest lucru vă va rezerva numele jucătorului\nşi vă va lăsa sa introduceți o imagine pentru el.", - "upgradeToGlobalProfileText": "Upgradează la Profil Global" + "unavailableText": "Numele \"${NAME}\" nu este disponibil; încearcă alt nume.", + "upgradeProfileInfoText": "Acest lucru îți va rezerva numele de jucător\nşi te va lăsa să introduci o iconiță pentru acesta.", + "upgradeToGlobalProfileText": "Îmbunătățește-l la un Profil Global" }, "editSoundtrackWindow": { "cantDeleteDefaultText": "Nu poți şterge soundtrackul normal.", @@ -597,49 +601,49 @@ "cantOverwriteDefaultText": "Nu poți înlocui soundtrackul normal", "cantSaveAlreadyExistsText": "Un soundtrack cu acelaşi nume deja există!", "defaultGameMusicText": "", - "defaultSoundtrackNameText": "Soundtrack Normal", - "deleteConfirmText": "Ştergi Soundtrackul:\n\n'${NAME}'?", - "deleteText": "Şterge\nSoundtrack", - "duplicateText": "Duplică\nSoundtrack", + "defaultSoundtrackNameText": "Soundtrack-ul Normal", + "deleteConfirmText": "Ştergi Soundtrack-ul:\n\n'${NAME}'?", + "deleteText": "Şterge\nSoundtrack-ul", + "duplicateText": "Duplică\nSoundtrack-ul", "editSoundtrackText": "Editor de Soundtrack", - "editText": "Editează\nSoundtrack", - "fetchingITunesText": "preluarea listelor de redare a aplicațiilor muzicale ...", - "musicVolumeZeroWarning": "Atenție: volumul muzicii este setat pe 0", + "editText": "Editează\nSoundtrack-ul", + "fetchingITunesText": "se preiau listele de redare din Aplicațiile Muzicale...", + "musicVolumeZeroWarning": "Atenție: volumul muzicii este setat la 0", "nameText": "Nume", - "newSoundtrackNameText": "Soundtrackul Meu ${COUNT}", + "newSoundtrackNameText": "Soundtrack-ul Meu ${COUNT}", "newSoundtrackText": "Soundtrack Nou:", "newText": "Soundtrack\nNou", "selectAPlaylistText": "Selectează o Listă de Redare", "selectASourceText": "Sursa Muzicii", - "testText": "test", + "testText": "testează", "titleText": "Soundtrack-uri", - "useDefaultGameMusicText": "Muzică Normală de Joc", - "useITunesPlaylistText": "Lista de redare a aplicației muzicale", - "useMusicFileText": "Fişier de Muzica (mp3, etc)", - "useMusicFolderText": "Folder pentru Fişierele de Muzică" + "useDefaultGameMusicText": "Muzica Normală din Joc", + "useITunesPlaylistText": "Lista de Redare a Aplicației Muzicale", + "useMusicFileText": "Fişier de Muzică (mp3, etc)", + "useMusicFolderText": "Dosar cu Fişiere de Muzică" }, - "editText": "Editeaza", - "endText": "Sfârșit", - "enjoyText": "Bucurați-vă!", + "editText": "Editează", + "endText": "Sfârșește", + "enjoyText": "Bucură-te!", "epicDescriptionFilterText": "${DESCRIPTION} În slow motion epic.", "epicNameFilterText": "${NAME} Epic", "errorAccessDeniedText": "acces respins", - "errorOutOfDiskSpaceText": "rămas fără memorie", + "errorOutOfDiskSpaceText": "ai rămas fără memorie", "errorText": "Eroare", "errorUnknownText": "eroare necunoscută", - "exitGameText": "Închizi ${APP_NAME}?", - "exportSuccessText": "'${NAME}' exportat", - "externalStorageText": "Depozit External", - "failText": "Eșuare", - "fatalErrorText": "Oh nu; ceva lipseşte sau este stricat.\nTe rog încearcă să reinstalezi aplicația sau\ncontactează ${EMAIL} pentru ajutor.", + "exitGameText": "Ieși din ${APP_NAME}?", + "exportSuccessText": "'${NAME}' exportat cu succes.", + "externalStorageText": "Memorie Externă", + "failText": "Eșec", + "fatalErrorText": "Oh nu; ceva lipseşte sau este stricat.\nTe rog încearcă să reinstalezi aplicația sau\ncontactează E-Mail-ul ${EMAIL} pentru ajutor.", "fileSelectorWindow": { - "titleFileFolderText": "Selectează un fișier sau un folder", + "titleFileFolderText": "Selectează un Fișier sau un Dosar", "titleFileText": "Selectează un fișier", - "titleFolderText": "Selectează un folder", - "useThisFolderButtonText": "Folosește acest folder" + "titleFolderText": "Selectează un Dosar", + "useThisFolderButtonText": "Folosește Acest Dosar" }, "filterText": "Filtru", - "finalScoreText": "Scor final", + "finalScoreText": "Scor Final", "finalScoresText": "Scoruri Finale", "finalTimeText": "Timp Final", "finishingInstallText": "Se termină de instalat; un moment...", @@ -647,407 +651,442 @@ "firstToFinalText": "Finala Primul-la-${COUNT}", "firstToSeriesText": "Seriile Primul-la-${COUNT}", "fiveKillText": "Penta-omor!!!", - "flawlessWaveText": "Val perfect!", + "flawlessWaveText": "Val Perfect!", "fourKillText": "Cvadr-omor!!!", "friendScoresUnavailableText": "Scorurile prietenilor nu sunt disponibile.", "gameCenterText": "GameCenter", "gameCircleText": "GameCircle", "gameLeadersText": "Liderii Jocului ${COUNT}", "gameListWindow": { - "cantDeleteDefaultText": "Nu poți şterge lista de redare normală.", - "cantEditDefaultText": "Nu poți edita lista de redare normală! Duplic-o sau creează una nouă.", - "cantShareDefaultText": "Nu poti trimite playlistul default", + "cantDeleteDefaultText": "Nu poți şterge lista de jocuri normală.", + "cantEditDefaultText": "Nu poți edita lista de jocuri normală! Duplic-o sau creează una nouă.", + "cantShareDefaultText": "Nu poti trimite mai departe playlist-ul normal", "deleteConfirmText": "Ştergi \"${LIST}\"?", - "deleteText": "Şterge\nlistă de redare", - "duplicateText": "Duplică\nO Listă de redare", - "editText": "Editează\no listă de redare", - "newText": "Listă de redare\nNouă", + "deleteText": "Şterge\nLista de Jocuri", + "duplicateText": "Duplică\nLista de Jocuri", + "editText": "Editează\nLista de Jocuri", + "newText": "Listă de Jocuri\nNouă", "showTutorialText": "Arată Tutorialul", - "shuffleGameOrderText": "Hărți la nimereală", - "titleText": "Particularizează Listele de Redare de ${TYPE}" + "shuffleGameOrderText": "Hărți Aleatorii", + "titleText": "Particularizează Listele de Jocuri de tip ${TYPE}" }, "gameSettingsWindow": { - "addGameText": "Adaugă joc" + "addGameText": "Adaugă un Joc" }, "gamesToText": "${WINCOUNT} jocuri la ${LOSECOUNT}", "gatherWindow": { - "aboutDescriptionLocalMultiplayerExtraText": "Ține minte: orice dispozitiv din grup poate avea\nmai mult de un jucător dacă sunt destule controllere.", - "aboutDescriptionText": "Folosește aceste tab-uri pentru a asambla un grup.\n\nGrupurile te lasă să joci jocuri și turnee împreună\ncu prietenii tăi, folosind mai multe dispozitive.\n\nFolosește butonul ${PARTY} din dreapta-sus pentru a\nvorbi și interacționa cu grupul.\n(dacă folosești un controller, folosește ${BUTTON} cât timp ești într-un meniu)", + "aboutDescriptionLocalMultiplayerExtraText": "Ține minte: orice dispozitiv dintr-o petrecere poate avea\nmai mult de un jucător dacă sunt destule controllere.", + "aboutDescriptionText": "Folosește aceste file pentru a asambla o petrecere.\n\nPetrecerile te lasă să joci jocuri și turnee împreună\ncu prietenii tăi, folosind mai multe dispozitive.\n\nFolosește butonul ${PARTY} din dreapta-sus pentru a\nvorbi și interacționa cu grupul.\n(dacă folosești un controller, folosește ${BUTTON} cât timp ești într-un meniu)", "aboutText": "Despre", - "addressFetchErrorText": "", + "addressFetchErrorText": "", "appInviteInfoText": "Invită-ți prietenii să încerce BombSquad și\nvor primii ${COUNT} bilete gratis. Tu vei primi\n${YOU_COUNT} pentru fiecare care o face.", "appInviteMessageText": "${NAME} ți-a trimis ${COUNT} de bilete în ${APP_NAME}", - "appInviteSendACodeText": "Trimite-i un cod", - "appInviteTitleText": "Invitație pentru ${APP_NAME}", - "bluetoothAndroidSupportText": "(funcționează cu orice dispozitiv android care suportă bluetooth)", - "bluetoothDescriptionText": "Ține/intră într-un joc folosind bluetooth:", - "bluetoothHostText": "Ține un joc bluetooth", - "bluetoothJoinText": "Intră într-un joc bluetooth", + "appInviteSendACodeText": "Trimite-i Un Cod", + "appInviteTitleText": "Invitație Pentru A Încerca ${APP_NAME}", + "bluetoothAndroidSupportText": "(funcționează cu orice dispozitiv Android care suportă Bluetooth)", + "bluetoothDescriptionText": "Ține un joc/intră într-un joc folosind Bluetooth:", + "bluetoothHostText": "Ține un joc pe Bluetooth", + "bluetoothJoinText": "Intră într-un joc de pe Bluetooth", "bluetoothText": "Bluetooth", "checkingText": "se verifică...", "copyCodeConfirmText": "Codul a fost copiat în clipboard.", - "copyCodeText": "Copiați codul", - "dedicatedServerInfoText": "Pentru cele mai bune rezultate, configurați un server dedicat. Consultați bombsquadgame.com/server pentru a afla cum.", + "copyCodeText": "Copiază Codul", + "dedicatedServerInfoText": "Pentru cele mai bune rezultate, configurează un server dedicat. Consultă bombsquadgame.com/server pentru a afla cum.", "disconnectClientsText": "Aceasta va deconecta ${COUNT} jucător(i) din\ngrupul tău curent. Ești sigur?", - "earnTicketsForRecommendingAmountText": "Prietenii vor primii ${COUNT} tichete daca vor incerca jocul \n(iar tu vei primii ${YOU_COUNT} pentru fiecare care incearca)", + "earnTicketsForRecommendingAmountText": "Prietenii tăi vor primii ${COUNT} de bilete dacă vor încerca jocul \n(iar tu vei primi ${YOU_COUNT} pentru fiecare care încearcă)", "earnTicketsForRecommendingText": "Împărtăşeşte jocul\npentru bilete gratuite...", "emailItText": "Dă-l prin Email", - "favoritesSaveText": "Salvați ca favorit", + "favoritesSaveText": "Salvează ca favorit", "favoritesText": "Favorite", - "freeCloudServerAvailableMinutesText": "Următorul server cloud gratuit disponibil în ${MINUTES} minute.", + "freeCloudServerAvailableMinutesText": "Următorul server cloud gratuit va fi disponibil în ${MINUTES} minute.", "freeCloudServerAvailableNowText": "Server cloud gratuit disponibil!", "freeCloudServerNotAvailableText": "Nu sunt disponibile servere cloud gratuite.", - "friendHasSentPromoCodeText": "${COUNT} Bilete ${APP_NAME} de la ${NAME}", + "friendHasSentPromoCodeText": "${COUNT} Bilete pe ${APP_NAME} de la ${NAME}", "friendPromoCodeAwardText": "Vei primi ${COUNT} de bilete de fiecare dată când este folosit.", - "friendPromoCodeExpireText": "Codul v-a expira în ${EXPIRE_HOURS} ore şi merge doar pentru jucătorii noi.", - "friendPromoCodeInstructionsText": "Pentru a-l utiliza, deschideți ${APP_NAME} și accesați „Setări-> Avansat-> Introduceți codul”.\nConsultați bombsquadgame.com pentru linkuri de descărcare pentru toate platformele acceptate.", - "friendPromoCodeRedeemLongText": "Poate fi înscris pentru ${COUNT} de bilete gratuite de către un maxim de ${MAX_USES} de persoane.", - "friendPromoCodeRedeemShortText": "Poate fi înscris pentru ${COUNT} de bilete în joc.", - "friendPromoCodeWhereToEnterText": "(în „Setări-> Avansat-> Introduceți codul”)", - "getFriendInviteCodeText": "Cere un cod de invitare pentru prieteni", - "googlePlayDescriptionText": "Invită jucători Google Play în grupul tău:", + "friendPromoCodeExpireText": "Codul va expira în ${EXPIRE_HOURS} de ore şi merge doar pentru jucătorii noi.", + "friendPromoCodeInstructionsText": "Pentru a-l utiliza, deschide ${APP_NAME} și accesează „Setări-> Avansat-> Introdu codul”.\nConsultă bombsquadgame.com pentru linkuri de descărcare pentru toate platformele acceptate.", + "friendPromoCodeRedeemLongText": "Poate fi introdus pentru ${COUNT} de bilete gratuite de către un maxim de ${MAX_USES} de persoane.", + "friendPromoCodeRedeemShortText": "Poate fi introdus în joc pentru ${COUNT} de bilete.", + "friendPromoCodeWhereToEnterText": "(în „Setări-> Avansat-> Introdu codul”)", + "getFriendInviteCodeText": "Cere un Cod de Invitare Pentru Prieteni", + "googlePlayDescriptionText": "Invită jucători Google Play la petrecerea ta:", "googlePlayInviteText": "Invită", - "googlePlayReInviteText": "Sunt ${COUNT} jucători Google Play în grupul tău care vor\nfi deconectați dacă faci o altă invitație. Include-i și\npe ei în noua invitație pentru a-i avea înapoi în grup.", - "googlePlaySeeInvitesText": "Vezi invitații", + "googlePlayReInviteText": "Sunt ${COUNT} jucători Google Play în grupul tău care vor\nfi deconectați dacă faci o altă invitație. Include-i și\npe ei în noua invitație pentru a-i avea înapoi la petrecere.", + "googlePlaySeeInvitesText": "Vezi Invitații", "googlePlayText": "Google Play", - "googlePlayVersionOnlyText": "(Numai pentru versiunea Android/Google Play)", - "hostPublicPartyDescriptionText": "Găzduiește o petrecere publică", - "hostingUnavailableText": "Gazduirea nu este disponibilă", - "inDevelopmentWarningText": "Notă:\n\nJocul peste rețea este încă o opțiune în dezvoltare.\nDeocamdată se recomandă ca toți jucătorii să fie pe\naceiași rețea Wi-Fi.", + "googlePlayVersionOnlyText": "(Numai pentru versiunea Android / Google Play)", + "hostPublicPartyDescriptionText": "Creează Un Joc Public", + "hostingUnavailableText": "Creeare Indisponibilă", + "inDevelopmentWarningText": "Notă:\n\nJocul peste rețea este încă o opțiune în dezvoltare.\nDeocamdată se recomandă ca toți jucătorii să fie pe\naceeași rețea Wi-Fi.", "internetText": "Internet", - "inviteAFriendText": "Prietenii nu au jocul? Invită-i să-l\nîncerce şi vor primii ${COUNT} de bilete gratis.", - "inviteFriendsText": "Invită Prieteni", - "joinPublicPartyDescriptionText": "Alăturați-vă unui partid public", - "localNetworkDescriptionText": "Alăturați-vă unei petreceri din apropiere (LAN, Bluetooth etc.)", - "localNetworkText": "Rețea locală", - "makePartyPrivateText": "Faceți petrecerea mea privată", - "makePartyPublicText": "Faceți Partidul Meu Public", - "manualAddressText": "Adresă", - "manualConnectText": "Conectare", - "manualDescriptionText": "Intră într-un grup la adresa:", - "manualJoinSectionText": "Alăturați-vă după adresă", - "manualJoinableFromInternetText": "Se poate conecta la tine de pe internet?:", + "inviteAFriendText": "Prietenii tăi nu au jocul? Invită-i să-l\nîncerce şi vor primii ${COUNT} de bilete gratis.", + "inviteFriendsText": "Invită-ți Prietenii", + "joinPublicPartyDescriptionText": "Alăturați-vă unui joc public", + "localNetworkDescriptionText": "Alătură-te unui joc din apropiere (LAN, Bluetooth etc.)", + "localNetworkText": "Rețea Locală", + "makePartyPrivateText": "Fă-mi Jocul Privat", + "makePartyPublicText": "Fă-mi Jocul Public", + "manualAddressText": "Adresa", + "manualConnectText": "Conectează-te", + "manualDescriptionText": "Intră într-un joc cu adresa:", + "manualJoinSectionText": "Alătură-te cu Ajutorul Adresei", + "manualJoinableFromInternetText": "Se pot conecta alții de pe internet la jocul tău?:", "manualJoinableNoWithAsteriskText": "NU*", "manualJoinableYesText": "DA", - "manualRouterForwardingText": "*pentru a repara asta, configurează router-ul tău să dea forward la portul UDP ${PORT} către adresa ta locală", + "manualRouterForwardingText": "*pentru a repara asta, configurează-ți router-ul ca acesta să dea forward la portul UDP ${PORT} către adresa ta locală", "manualText": "Manual", "manualYourAddressFromInternetText": "Adresa ta de pe internet:", "manualYourLocalAddressText": "Adresa ta locală:", "nearbyText": "Din apropiere", "noConnectionText": "", "otherVersionsText": "(alte versiuni)", - "partyCodeText": "Codul partidului", + "partyCodeText": "Codul Jocului", "partyInviteAcceptText": "Acceptă", "partyInviteDeclineText": "Refuză", "partyInviteGooglePlayExtraText": "(vezi tab-ul 'Google Play' din fereastra 'Adunare')", "partyInviteIgnoreText": "Ignoră", "partyInviteText": "${NAME} te-a invitat\nsă intri în grupul lui/ei!", - "partyNameText": "Numele grupului", - "partyServerRunningText": "Serverul de partid se execută.", - "partySizeText": "Mărimea petrecerii", - "partyStatusCheckingText": "verificarea stării ...", - "partyStatusJoinableText": "petrecerea ta este acum accesibilă de pe internet", + "partyNameText": "Numele Server-ului", + "partyServerRunningText": "Server-ul tău de joc este activ.", + "partySizeText": "nr. de locuri", + "partyStatusCheckingText": "Se verifică starea...", + "partyStatusJoinableText": "Server-ul tău este acum accesibil de pe internet", "partyStatusNoConnectionText": "nu se poate conecta la server", - "partyStatusNotJoinableText": "petrecerea dvs. nu poate fi alăturată de pe internet", - "partyStatusNotPublicText": "petrecerea ta nu este publică", - "pingText": "latenta", + "partyStatusNotJoinableText": "nimeni de pe internet nu poate intra pe server-ul tău", + "partyStatusNotPublicText": "server-ul tău nu este public", + "pingText": "latența", "portText": "Port", - "privatePartyCloudDescriptionText": "Petreceri private rulează pe servere cloud dedicate; nu este necesară configurarea routerului.", - "privatePartyHostText": "Găzduiește o petrecere privată", - "privatePartyJoinText": "Alăturați-vă unei petreceri private", + "privatePartyCloudDescriptionText": "Jocurile private rulează pe servere cloud dedicate; nu este necesară configurarea router-ului.", + "privatePartyHostText": "Creează un Server Privat", + "privatePartyJoinText": "Alătură-te unui Server Privat", "privateText": "Privat", - "publicHostRouterConfigText": "Acest lucru poate necesita configurarea redirecționării porturilor pe router. Pentru o opțiune mai ușoară, găzduiește o petrecere privată.", + "publicHostRouterConfigText": "Acest lucru poate necesita configurarea redirecționării portului de pe router. Ca alternativă, creează un server privat.", "publicText": "Public", - "requestingAPromoCodeText": "Se cere codul...", - "sendDirectInvitesText": "Trimite Invitați Direct", + "requestingAPromoCodeText": "Se obține codul...", + "sendDirectInvitesText": "Trimite Invitații Directe", "shareThisCodeWithFriendsText": "Împărtăşeşte codul ăsta cu prietenii:", - "showMyAddressText": "Afișează adresa mea", - "startHostingPaidText": "Găzduiește acum pentru ${COST}", - "startHostingText": "Gazdă", - "startStopHostingMinutesText": "Puteți începe și opri găzduirea gratuit pentru următoarele ${MINUTES} minute.", - "stopHostingText": "Opriți găzduirea", + "showMyAddressText": "Afișează Adresa Mea", + "startHostingPaidText": "Creează Acum Pentru ${COST}", + "startHostingText": "Creează", + "startStopHostingMinutesText": "Poți creea și opri servere gratis pentru următoarele ${MINUTES} minute.", + "stopHostingText": "Oprește Server-ul", "titleText": "Adunare", - "wifiDirectDescriptionBottomText": "Dacă toate dispozitivele au un panou 'Wi-Fi Direct', ar trebui să poată să îl folosească să\nse găsească și să se conecteze unii la alții. Când toate dispozitivele sunt conectate se pot\nforma grupuri, aici, folosind tab-ul 'Rețea locală', ca și când ați fi pe aceiași rețea Wi-Fi.\n\nPentru cele mai bune rezultate, host-ul Wi-Fi Direct ar trebui să fie și host-ul grupului ${APP_NAME}.", - "wifiDirectDescriptionTopText": "Wi-Fi direct se poate folosi pentru conectarea dispozitivelor Android fără\na folosi o rețea Wi-Fi. Aceasta funcționează (bine) pe Android 4.2 sau mai nou.\n\nPentru a folosi Wi-Fi direct, deschide setările Wi-Fi și caută 'Wi-Fi Direct' în meniu.", - "wifiDirectOpenWiFiSettingsText": "Deschide setări Wi-Fi", - "wifiDirectText": "Wi-fi direct", - "worksBetweenAllPlatformsText": "(funcționează între toate platformele)", - "worksWithGooglePlayDevicesText": "(funcționează pe orice dispozitiv care are versiunea Google Play(android) a jocului)", + "wifiDirectDescriptionBottomText": "Dacă toate dispozitivele au un panou 'Wi-Fi Direct', ar trebui să poată să îl folosească să\nse găsească și să se conecteze unii la alții. Când toate dispozitivele sunt conectate se pot\nforma grupuri, aici, folosind tab-ul 'Rețea locală', ca și când ați fi pe aceiași rețea Wi-Fi.\n\nPentru cele mai bune rezultate, host-ul Wi-Fi Direct ar trebui să fie și host-ul server-ului ${APP_NAME}.", + "wifiDirectDescriptionTopText": "Funcția de Wi-Fi direct se poate folosi la conectarea dispozitivelor Android fără\na folosi o rețea Wi-Fi. Aceasta funcționează cel mai bine de la Android 4.2 în sus.\n\nPentru a folosi funcția de Wi-Fi direct, deschide setările Wi-Fi și caută 'Wi-Fi Direct' în meniu.", + "wifiDirectOpenWiFiSettingsText": "Deschide setările Wi-Fi", + "wifiDirectText": "Wi-Fi Direct", + "worksBetweenAllPlatformsText": "(funcționează pe toate platformele)", + "worksWithGooglePlayDevicesText": "(funcționează pe orice dispozitiv care are versiunea Google Play (android) a jocului)", "youHaveBeenSentAPromoCodeText": "Ai primit un cod Promo ${APP_NAME}:" }, "getTicketsWindow": { "freeText": "GRATIS!", - "freeTicketsText": "Bilete gratis", + "freeTicketsText": "Bilete Gratis", "inProgressText": "O tranzacție e în progres; reîncearcă în câteva secunde.", - "purchasesRestoredText": "Cumpărări resetate.", - "receivedTicketsText": "Ai primit ${COUNT} bilete!", - "restorePurchasesText": "Resetează Cumpărări", + "purchasesRestoredText": "Cumpărături Resetate.", + "receivedTicketsText": "Ai primit ${COUNT} (de) bilete!", + "restorePurchasesText": "Resetează Cumpărături", "ticketDoublerText": "Dublator Bilete", - "ticketPack1Text": "Pachet bilete mic", - "ticketPack2Text": "Pachet bilete mediu", - "ticketPack3Text": "Pachet bilete mare", - "ticketPack4Text": "Super-pachet bilete", - "ticketPack5Text": "Pachet bilete MAMUT", - "ticketPack6Text": "Pachet bilete extrem", - "ticketsFromASponsorText": "Ia ${COUNT} bilete de\nla un sponsor", - "ticketsText": "${COUNT} Bilete", - "titleText": "Ia bilete", - "unavailableLinkAccountText": "Ne pare rău, achizițiile nu sunt disponibile pe această platformă.\nCa soluție, puteți conecta acest cont la un cont de pe\no altă platformă și faceți cumpărături acolo.", - "unavailableTemporarilyText": "Acest serviciu e indisponibil deocamdată; încearcă mai târziu.", - "unavailableText": "Scuze, aceasta e indisponibilă.", - "versionTooOldText": "Scuze, dar versiunea jocului e prea veche; dă update pentru a lua una mai nouă.", - "youHaveShortText": "tu ai ${COUNT}", - "youHaveText": "ai ${COUNT} bilete" + "ticketPack1Text": "Pachet de Bilete Mic", + "ticketPack2Text": "Pachet de Bilete Mediu", + "ticketPack3Text": "Pachet de Bilete Mare", + "ticketPack4Text": "Super-Pachet de Bilete", + "ticketPack5Text": "Pachet de Bilete MAMUT", + "ticketPack6Text": "Pachet de Bilete Suprem", + "ticketsFromASponsorText": "Ia ${COUNT} bilete\nde la un sponsor", + "ticketsText": "${COUNT} de Bilete", + "titleText": "Ia Bilete", + "unavailableLinkAccountText": "Ne pare rău, dar achizițiile nu sunt disponibile pe această platformă.\nCa soluție, puteți conecta acest cont la un cont de pe\no altă platformă și faceți cumpărături acolo.", + "unavailableTemporarilyText": "Acest serviciu este indisponibil deocamdată; încearcă din nou mai târziu.", + "unavailableText": "Scuze, această ofertă este indisponibilă.", + "versionTooOldText": "Scuze, dar versiunea jocului e prea veche; actualizează-l la o versiune mai nouă.", + "youHaveShortText": "ai ${COUNT}", + "youHaveText": "ai ${COUNT} (de) bilete" }, - "googleMultiplayerDiscontinuedText": "Ne pare rău, serviciul multiplayer Google nu mai este disponibil.\nLucrez la un înlocuitor cât mai repede posibil.\nPână atunci, vă rugăm să încercați o altă metodă de conectare.\n-Eric", + "googleMultiplayerDiscontinuedText": "Ne pare rău, serviciul multiplayer de pe Google nu mai este disponibil.\nLucrez la un înlocuitor cât mai repede posibil.\nPână atunci, te rog să încerci o altă metodă de conectare.\n-Eric", "googlePlayText": "Magazin Play", "graphicsSettingsWindow": { "alwaysText": "Întotdeauna", "fullScreenCmdText": "Fullscreen (Cmd+F)", "fullScreenCtrlText": "Fullscreen (Ctrl+F)", "gammaText": "Luminozitate", - "highText": "Înalt", - "higherText": "Mai înalt", - "lowText": "Slab", - "mediumText": "Mediu", + "highText": "Înalte", + "higherText": "Mai Înalte", + "lowText": "Slabe", + "mediumText": "Medii", "neverText": "Niciodată", "resolutionText": "Rezoluție", - "showFPSText": "Arată FPS", + "showFPSText": "Arată FPS-urile", "texturesText": "Texturi", - "titleText": "Grafică", - "tvBorderText": "Margine TV", + "titleText": "Grafici", + "tvBorderText": "Margine Televizor", "verticalSyncText": "V-sync", - "visualsText": "Vizual" + "visualsText": "Vizuale" }, "helpWindow": { - "bombInfoText": "- Bomba -\nMai puternică decât pumnii, dar poate\nrezulta în a te lovi pe tine însuți.\nPentru rezultate pozitive, aruncă\nînspre inamici înainte să se termine fitilul.", - "canHelpText": "${APP_NAME} poate ajuta.", - "controllersInfoText": "Puteți juca ${APP_NAME} cu prietenii dintr-o rețea sau dvs.\npot juca cu toții pe același dispozitiv dacă aveți suficiente controlere.\n${APP_NAME} acceptă o varietate de ele; puteți folosi chiar și telefoane\nca controlori prin intermediul aplicației gratuite „${REMOTE_APP_NAME}”.\nConsultați Setări-> Controlere pentru mai multe informații.", - "controllersInfoTextRemoteOnly": "Puteți juca ${APP_NAME} cu prietenii dintr-o rețea sau dvs.\ntoți pot reda pe același dispozitiv folosind telefoane ca\ncontrolere prin intermediul aplicației gratuite „${REMOTE_APP_NAME}”.", + "bombInfoText": "- Bomba -\nMai puternică decât pumnii, dar poate\nrezulta în a te lovi pe tine însuți.\nPentru rezultate pozitive, arunc-o înspre\ninamici înainte să se termine fitilul.", + "canHelpText": "${APP_NAME} te poate ajuta.", + "controllersInfoText": "Te poți juca ${APP_NAME} cu prietenii dintr-o rețea sau \nputeți juca cu toții pe același dispozitiv dacă aveți suficiente controllere.\n${APP_NAME} acceptă o varietate de ele; puteți folosi chiar și telefoane\ndrept controllere cu ajutorul aplicației gratuite „${REMOTE_APP_NAME}”.\nConsultă Setări-> Controlere pentru mai multe informații.", + "controllersInfoTextRemoteOnly": "Te poți juca ${APP_NAME} cu prietenii pe o rețea de Wi-Fi/Bluetooth, sau\nvă puteți juca cu toții pe același dispozitiv folosind telefoane \ndrept controllere cu ajutorul aplicației gratuite '${REMOTE_APP_NAME}'.", "controllersText": "Controllere", - "controlsSubtitleText": "Caracterul dvs. prietenos ${APP_NAME} are câteva acțiuni de bază:", - "controlsText": "Controluri", - "devicesInfoText": "Versiunea VR a ${APP_NAME} poate fi redată prin rețea cu\nversiunea obișnuită, așa că scoateți-vă telefoanele, tabletele,\nși computere și începe jocul. Poate fi chiar util\nconectați o versiune obișnuită a jocului la versiunea VR doar la\npermite oamenilor din exterior să urmărească acțiunea.", + "controlsSubtitleText": "Caracterul tău prietenos din ${APP_NAME} are câteva acțiuni de bază:", + "controlsText": "Controalele", + "devicesInfoText": "Te poți juca pe internet pe versiunea VR de ${APP_NAME}\nla fel ca pe cea originală așa că scoateți-vă telefoanele,tabletele,\nporniți computerele și începeți jocul. Poate fi folositor\nși să conectezi versiunea originală la cea VR doar ca cei\ndin afară să poată vdedea acțiunea.", "devicesText": "Dispozitive", - "friendsGoodText": "E bine să ai și de-aceștia. ${APP_NAME} e și mai amuzant cu mai\nmulți jucători și suportă până la 8 deodată, ce ne duce la:", + "friendsGoodText": "E bine să ai și din aceștia. ${APP_NAME} e și mai amuzant cu mai\nmulți jucători și suportă până la 8 deodată, ceea ce ne duce la:", "friendsText": "Prieteni", - "jumpInfoText": "- Sari -\nSari peste gropi mici,\naruncă lucruri mai înalt\nși exprimă-ți fericirea.", - "orPunchingSomethingText": "Sau să dai cu pumnii în ceva, să arunci acel cava într-o prăpastie și să explodeze până jos de la o bombă lipicioasă.", - "pickUpInfoText": "- Ridică -\nIa steaguri, inamici, sau orice\ncare nu e fixat de pământ.\nApasă încă odată pentru a arunca.", - "powerupBombDescriptionText": "Te lasă să poți arunca 3 bombe\ndeodată în loc de numai una.", - "powerupBombNameText": "Bombe triple", - "powerupCurseDescriptionText": "Ar trebui să eviți astea.\n ...sau oare?", + "jumpInfoText": "- Săritura -\nSari ca să trecipeste gropi mici,\nsă arunci lucruri mai sus,\nși să-ți exprimi fericirea.", + "orPunchingSomethingText": "Sau să dai cu pumnii în ceva, să arunci acel ceva într-o prăpastie și să explodeze până jos de la o bombă lipicioasă.", + "pickUpInfoText": "- Ridicarea -\nIa steaguri, inamici, sau orice \nlucru care nu e fixat de pământ.\nApasă-l încă odată pentru a arunca.", + "powerupBombDescriptionText": "Te lasă să arunci 3 bombe\nîn loc de una singură.", + "powerupBombNameText": "Bombe Triple", + "powerupCurseDescriptionText": "Ar fi mai bine să eviți astea.\n ...sau oare?", "powerupCurseNameText": "Blestem", - "powerupHealthDescriptionText": "Îți regenerează viața la maxim.\nNici nu ai fi ghicit.", - "powerupHealthNameText": "Trusă de prim-ajutor", + "powerupHealthDescriptionText": "Îți regenerează viața la maxim.\nNici n-ai fi ghicit.", + "powerupHealthNameText": "Trusă de Prim-Ajutor", "powerupIceBombsDescriptionText": "Mai slabe decât bombele\nnormale, dar îți lasă inamicii\nînghețați și aparent fragili.", - "powerupIceBombsNameText": "Bombe de gheață", - "powerupImpactBombsDescriptionText": "Mai slabe decât bombele normale,\ndar explodează la impact.", - "powerupImpactBombsNameText": "Bombe de impact", - "powerupLandMinesDescriptionText": "Acestea vin câte 3; Folositoare\npentru apărarea bazelor sau\npentru a opri inamici vitezomani.", + "powerupIceBombsNameText": "Bombe de Gheață", + "powerupImpactBombsDescriptionText": "Mai slabe decât bombele normale,\ndar explodează odată ce ating ceva.", + "powerupImpactBombsNameText": "Bombe cu Impact", + "powerupLandMinesDescriptionText": "Acestea vin câte 3; Folositoare\npentru apărarea bazelor sau\npentru oprirea inamicilor vitezomani.", "powerupLandMinesNameText": "Mine", - "powerupPunchDescriptionText": "Dai cu pumnii mai repede,\nmai bine și mai puternic.", - "powerupPunchNameText": "Mănuși de box", + "powerupPunchDescriptionText": "Îți va face pumnii mai tari,\nmai rapizi, mai buni și mai puternici.", + "powerupPunchNameText": "Mănuși de Box", "powerupShieldDescriptionText": "Absoarbe daunele ca să\nnu o faci tu.", "powerupShieldNameText": "Scut-Energic", "powerupStickyBombsDescriptionText": "Se lipesc de orice ating.\nHilaritate garantată.", "powerupStickyBombsNameText": "Bombe Lipicioase", - "powerupsSubtitleText": "Desigur, nici un joc e joc fără powerup-uri:", + "powerupsSubtitleText": "Desigur, nici un joc nu e complet fără powerup-uri:", "powerupsText": "Powerup-uri", - "punchInfoText": "- Pumnii -\nPumnii dăunează mai mult cu cât\nse mișcă mai repede, deci aleargă\nși rotește-te ca un dement!", - "runInfoText": "- Fugi -\nȚine apăsat ORICE buton pentru a fugi. Triggerele sau butoanele de umăr funcționează dacă le ai.\nFugitul te ajută să ajungi repede în locuri, deși virezi greu, deci ai grijă la prăpastii.", + "punchInfoText": "- Pumnii -\nPumnii dăunează mai mult cu cât\nse mișcă mai rapid, deci aleargă\nși rotește-te ca un dement!", + "runInfoText": "- Fuga -\nȚine apăsat ORICE buton pentru a fugi. Triggerele sau butoanele de umăr funcționează bine dacă le ai.\nFugitul te ajută să ajungi mai repede în alte locuri, deși virezi greu, deci ai grijă la prăpastii.", "someDaysText": "În unele zile pur și simplu vrei să lovești ceva. Sau să explodezi altceva.", - "titleText": "${APP_NAME} Ajutor", - "toGetTheMostText": "Pentru a vedea tot ce are jocul acesta, vei avea nevoie de:", - "welcomeText": "Bun venit la ${APP_NAME}!" + "titleText": "Ajutor pentru ${APP_NAME}", + "toGetTheMostText": "Pentru a vedea tot ce oferă jocul acesta, vei avea nevoie de:", + "welcomeText": "Bun venit în ${APP_NAME}!" }, "holdAnyButtonText": "<ține apăsat orice buton>", - "holdAnyKeyText": "<ține apăsată orice tastă>", - "hostIsNavigatingMenusText": "- ${HOST} navighează meniurile boss de boss -", - "importPlaylistCodeInstructionsText": "Utilizați următorul cod pentru a importa această listă de redare în altă parte:", - "importPlaylistSuccessText": "Lista de redare ${TYPE} importată „${NAME}”", - "importText": "Import", - "importingText": "Se importă ...", - "inGameClippedNameText": "în joc va fi\n„${NAME}”", - "installDiskSpaceErrorText": "EROARE: Nu s-a putut completa instalarea.\nSe poate să fi rămas fără spațiu pe dispozitiv.\nEliberează niște spațiu și reîncearcă.", + "holdAnyKeyText": "<ține apăsat pe orice tastă>", + "hostIsNavigatingMenusText": "- ${HOST} navighează meniurile ca un șmecher -", + "importPlaylistCodeInstructionsText": "Folosește următorul cod pentru a importa această listă în altă parte:", + "importPlaylistSuccessText": "Lista de tip ${TYPE} cu numele '${NAME}' a fost importată cu succes", + "importText": "Importă", + "importingText": "Se importă...", + "inGameClippedNameText": "va arăta astfel\n\"${NAME}\"", + "installDiskSpaceErrorText": "EROARE: Nu s-a putut completa instalarea.\nSe poate să fi rămas fără spațiu pe dispozitiv.\nEliberează niște spațiu și încearcă din nou.", "internal": { "arrowsToExitListText": "Apasă ${LEFT} sau ${RIGHT} pentru a ieși din listă", "buttonText": "buton", - "cantKickHostError": "Nu poți da afară gazda.", - "chatBlockedText": "${NAME} este blocat prin chat timp de ${TIME} secunde.", - "connectedToGameText": "S-a înscris la „${NAME}”", - "connectedToPartyText": "Ai intrat în grupul lui ${NAME}!", + "cantKickHostError": "Nu poți da afară creeatorul server-ului.", + "chatBlockedText": "${NAME} este blocat în chat timp de ${TIME} (de) secunde.", + "connectedToGameText": "a intrat în „${NAME}”", + "connectedToPartyText": "Ai intrat în server-ul lui ${NAME}!", "connectingToPartyText": "Se conectează...", - "connectionFailedHostAlreadyInPartyText": "Conexiunea a eşuat; hostul este în altă petrecere", - "connectionFailedPartyFullText": "Conexiune esuata; petrecerea este plină.", + "connectionFailedHostAlreadyInPartyText": "Conexiunea a eşuat; hostul este în alt joc.", + "connectionFailedPartyFullText": "Conexiune eșuată; server-ul este plin.", "connectionFailedText": "Conexiunea a eşuat.", - "connectionFailedVersionMismatchText": "Conexiunea a eşuat; hostul rulează o versiune diferită a jocului.\nAsigurați-vă ca aveți amândoi cea mai nouă versiune a jocului şi incercați din nou.", + "connectionFailedVersionMismatchText": "Conexiunea a eşuat; hostul rulează o versiune diferită a jocului.\nAsigurați-vă că ambii aveți cea mai nouă versiune a jocului şi încercați din nou.", "connectionRejectedText": "Conexiune Respinsă.", "controllerConnectedText": "${CONTROLLER} conectat.", "controllerDetectedText": "1 controller detectat.", - "controllerDisconnectedText": "${CONTROLLER} a ieşit.", - "controllerDisconnectedTryAgainText": "${CONTROLLER} a ieşit. Încearcă să-l conectezi din nou.", - "controllerForMenusOnlyText": "Acest controler nu poate fi folosit pentru a juca; doar pentru a naviga prin meniuri.", + "controllerDisconnectedText": "${CONTROLLER} a fost deconectat.", + "controllerDisconnectedTryAgainText": "${CONTROLLER} a fost deconectat. Încearcă să-l conectezi din nou.", + "controllerForMenusOnlyText": "Acest controller nu poate fi folosit pentru a juca; ci doar pentru navigarea meniurilor.", "controllerReconnectedText": "${CONTROLLER} reconectat.", "controllersConnectedText": "${COUNT} controllere conectate.", "controllersDetectedText": "${COUNT} controllere detectate.", - "controllersDisconnectedText": "${COUNT} controllere au ieşit.", - "corruptFileText": "Fişiere Corupte detectate. Reinstalează jocul, sau dă email la ${EMAIL}", - "errorPlayingMusicText": "Eroare la începerea muzicii 0: ${MUSIC}", + "controllersDisconnectedText": "${COUNT} controllere s-au deconectat.", + "corruptFileText": "Fişiere Corupte detectate. Reinstalează jocul, sau trimite un email la adresa ${EMAIL}", + "errorPlayingMusicText": "Eroare la pornirea muzicii: ${MUSIC}", "errorResettingAchievementsText": "Nu se pot reseta medaliile; încearcă din nou mai tărziu.", "hasMenuControlText": "${NAME} are controlul meniului.", - "incompatibleNewerVersionHostText": "Gazda rulează o versiune mai nouă a jocului.\nActualizați la cea mai recentă versiune și încercați din nou.", - "incompatibleVersionHostText": "Hostul rulează o versiune diferită a jocului.\nAsigurați-vă că aveți cea mai nouă versiune şi încercați din nou.", - "incompatibleVersionPlayerText": "${NAME} rulează o versiune diferită a jocului.\nAsigurați-vă că aveți cea mai nouă versiune si reîncercați.", + "incompatibleNewerVersionHostText": "Hostul rulează o versiune mai nouă a jocului.\nActualizează-ți jocul la cea mai recentă versiune și încearcă din nou.", + "incompatibleVersionHostText": "Hostul rulează o versiune diferită a jocului.\nAsigură-te că ai cea mai nouă versiune şi încearcă din nou.", + "incompatibleVersionPlayerText": "${NAME} rulează o versiune diferită a jocului.\nAsigură-te că ai cea mai nouă versiune si încearcă din nou.", "invalidAddressErrorText": "Eroare: adresă invalidă.", - "invalidNameErrorText": "Eroare: nume nevalid.", - "invalidPortErrorText": "Eroare: port nevalid.", + "invalidNameErrorText": "Eroare: nume invalid.", + "invalidPortErrorText": "Eroare: port invalid.", "invitationSentText": "Invitație Trimisă.", "invitationsSentText": "${COUNT} (de) invitații trimise.", - "joinedPartyInstructionsText": "Cineva s-a alăturat partidului tău.\nAccesați „Joacă” pentru a începe un joc.", + "joinedPartyInstructionsText": "Cineva s-a alăturat partidului tău.\nAccesează meniul „Joacă” pentru a începe un joc.", "keyboardText": "Tastatură", - "kickIdlePlayersKickedText": "Îl dăm afară pe ${NAME} pentru că nu face nimic.", - "kickIdlePlayersWarning1Text": "${NAME} va fi dat afară în ${COUNT} (de) secunde dacă tot nu face nimic.", - "kickIdlePlayersWarning2Text": "(poți opri aceasta în Setări->Avansat)", - "leftPartyText": "Ai ieşit din petrecerea lui ${NAME}.", - "noMusicFilesInFolderText": "Folderul nu conține niciun fişier de muzică.", - "playerJoinedPartyText": "${NAME} a venit la petrecere!", - "playerLeftPartyText": "${NAME} a plecat de la petrecere.", - "rejectingInviteAlreadyInPartyText": "Se declină invitația (eşti deja într-o petrecere).", + "kickIdlePlayersKickedText": "${NAME} va fi dat afară pentru că este inactiv.", + "kickIdlePlayersWarning1Text": "${NAME} va fi dat afară în ${COUNT} (de) secunde dacă continuă să fie inactiv.", + "kickIdlePlayersWarning2Text": "(poți opri asta în Setări->Avansat)", + "leftGameText": "A ieșit din ${NAME}", + "leftPartyText": "Ai ieşit din server-ul lui ${NAME}.", + "noMusicFilesInFolderText": "Folder-ul nu conține niciun fişier de muzică.", + "playerJoinedPartyText": "${NAME} a intrat în joc!", + "playerLeftPartyText": "${NAME} a ieșit.", + "rejectingInviteAlreadyInPartyText": "Se respinge invitația (eşti deja într-un alt server).", + "serverRestartingText": "Server-ul se restartează. Te rog să intri din nou într-o clipă...", + "serverShuttingDownText": "Server-ul se închide...", "signInErrorText": "Eroare la Conectare.", - "signInNoConnectionText": "Nu se poate conecta. (fără conexiune la internet?)", + "signInNoConnectionText": "Nu se poate conecta. (nu există o conexiune la internet?)", "telnetAccessDeniedText": "Eroare: utilizatorul nu are acces la telnet.", - "timeOutText": "(rămâne fără timp în ${TIME} (de) secunde)", - "touchScreenJoinWarningText": "Ai intrat cu touchscreen-ul.\nDacă a fost o greşeală, apasă 'Meniu-Sfârşeşte Joc'.", + "timeOutText": "(i se va pierde controlul meniului în ${TIME} (de) secunde)", + "touchScreenJoinWarningText": "Ai intrat cu touchscreen-ul.\nDacă ai făcut-o din greşeală, apasă 'Meniu->Sfârşeşte Joc' cu acesta.", "touchScreenText": "TouchScreen", - "unavailableNoConnectionText": "Aceasta nu este disponibilă acum (fără conexiune la internet?)", - "vrOrientationResetCardboardText": "Foloseşte această opțiune pentru a reseta orientatea RV.\nCa să joci jocul ai nevoie de un controller external.", - "vrOrientationResetText": "Orientare RV resetată.", - "willTimeOutText": "(se va reseta dacă nu face ceva)" + "unableToResolveHostText": "Eroare:imposibil de găsit hostul.", + "unavailableNoConnectionText": "Acest serviciu nu este disponibil acum (fără conexiune la internet?)", + "vrOrientationResetCardboardText": "Foloseşte această opțiune pentru resetare orientării VR.\nDacă vrei să te joci vei avea nevoie de un controller external.", + "vrOrientationResetText": "Orientare VR resetată.", + "willTimeOutText": "(se va reseta dacă este inactiv)" }, "jumpBoldText": "SARI", "jumpText": "Sari", "keepText": "Păstrează", - "keepTheseSettingsText": "Păstrează aceste setări?", + "keepTheseSettingsText": "Păstrezi aceste setări?", + "keyboardChangeInstructionsText": "Apasă tasta space de două ori pentru a schimba tastaturile.", + "keyboardNoOthersAvailableText": "Nu a fost detectată altă tastatură.", + "keyboardSwitchText": "Tastatura schimbată va fi \"${NAME}\".", + "kickOccurredText": "${NAME} a fost dat afară.", + "kickQuestionText": "Vrei să-l dai afară pe ${NAME}?", + "kickText": "Dă-l afară", + "kickVoteCantKickAdminsText": "Administratorii nu pot fi dați afară.", + "kickVoteCantKickSelfText": "Nu te poți da afară.", + "kickVoteFailedNotEnoughVotersText": "Nu sunt destui jucători pentru un vot.", + "kickVoteFailedText": "Votul a eșuat.", + "kickVoteStartedText": "un vot de eliminare pentru ${NAME} a fost cerut.", + "kickVoteText": "Votează-l afară", + "kickVotingDisabledText": "Votul de eliminare este dezactivat.", + "kickWithChatText": "Scrie ${YES} în chat pentru a-l vota sau scrie ${NO} pentru a nu-l vota.", "killsTallyText": "${COUNT} (de) ucideri", - "killsText": "Omoruri", + "killsText": "Ucideri", "kioskWindow": { "easyText": "Uşor", "epicModeText": "Modul Epic", - "fullMenuText": "Meniu Full", + "fullMenuText": "Meniul Întreg", "hardText": "Greu", "mediumText": "Mediu", - "singlePlayerExamplesText": "Singur / Mostre Co-Op", - "versusExamplesText": "Mostre Versus" + "singlePlayerExamplesText": "Exemple de jocuri Solo / Echipe", + "versusExamplesText": "Exemple de jocuri Versus" }, "languageSetText": "Limba este acum \"${LANGUAGE}\"", "lapNumberText": "Tura ${CURRENT}/${TOTAL}", - "lastGamesText": "(ultimele ${COUNT} (de) jocuri)", + "lastGamesText": "(ultimele ${COUNT} de jocuri)", "leaderboardsText": "Clasamente", "league": { "allTimeText": "Din totdeauna", "currentSeasonText": "Sezon curent (${NUMBER})", "leagueFullText": "Liga de ${NAME}", - "leagueRankText": "Rang în ligă", + "leagueRankText": "Rangul din ligă", "leagueText": "Liga", "rankInLeagueText": "#${RANK}, ${NAME} Liga${SUFFIX}", - "seasonEndedDaysAgoText": "Sezonul s-a sfârșit acum ${NUMBER} zile.", - "seasonEndsDaysText": "Sezonul se sfârșește în ${NUMBER} zile.", - "seasonEndsHoursText": "Sezonul se sfârșește în ${NUMBER} ore.", - "seasonEndsMinutesText": "Sezonul se sfârșește în ${NUMBER} minute.", + "seasonEndedDaysAgoText": "Sezonul s-a sfârșit acum ${NUMBER} (de) zile.", + "seasonEndsDaysText": "Sezonul se sfârșește în ${NUMBER} (de) zile.", + "seasonEndsHoursText": "Sezonul se sfârșește în ${NUMBER} (de) ore.", + "seasonEndsMinutesText": "Sezonul se sfârșește în ${NUMBER} (de) minute.", "seasonText": "Sezonul ${NUMBER}", - "tournamentLeagueText": "Trebuie să ajungi în liga ${NAME} pentru a intra în acest turneu.", + "tournamentLeagueText": "Trebuie să ajungi în liga ${NAME} dacă vrei să intri în acest turneu.", "trophyCountsResetText": "Numărul de trofee se va reseta la sfârșitul sezonului." }, - "levelBestScoresText": "Cele mai bune scoruri pe ${LEVEL}", - "levelBestTimesText": "Cele mai bune timpuri pe ${LEVEL}", + "levelBestScoresText": "Cele mai bune scoruri din ${LEVEL}", + "levelBestTimesText": "Cele mai scurte timpuri din ${LEVEL}", "levelFastestTimesText": "Cel mai rapid timp pe ${LEVEL}", "levelHighestScoresText": "Cel mai mare scor pe ${LEVEL}", "levelIsLockedText": "${LEVEL} este blocat.", - "levelMustBeCompletedFirstText": "${LEVEL} trebuie terminat întâi.", + "levelMustBeCompletedFirstText": "Mai întâi trebuie să termini ${LEVEL}.", "levelText": "Nivelul ${NUMBER}", "levelUnlockedText": "Nivel Deblocat!", - "livesBonusText": "Vieți Bonus", + "livesBonusText": "Bonus de Vieți", "loadingText": "se încarcă", + "loadingTryAgainText": "Se încarcă; așteaptă o clipă...", + "macControllerSubsystemBothText": "Ambele (nerecomandat)", + "macControllerSubsystemClassicText": "Simplu", + "macControllerSubsystemDescriptionText": "(încearcă să schimbi această opțiune dacă nu-ți funcționează controllerele)", + "macControllerSubsystemMFiNoteText": "Controller Făcut-Pentru-iOS/Mac detectat;\nPentru a-l porni mergi în Setări -> Controllere", + "macControllerSubsystemMFiText": "Făcut-Pentru-iOS/Mac", + "macControllerSubsystemTitleText": "Suport Pentru Controller", "mainMenu": { "creditsText": "Credite", "demoMenuText": "Meniu Demo", - "endGameText": "Sfârșește joc", - "exitGameText": "Ieși din joc", - "exitToMenuText": "Te întorci la meniu?", - "howToPlayText": "Cum joc?", + "endGameText": "Sfârșește Jocul", + "exitGameText": "Ieși Din Joc", + "exitToMenuText": "Revii la meniu?", + "howToPlayText": "Cum Se Joacă?", "justPlayerText": "(Doar ${NAME})", - "leaveGameText": "Părăsește joc", - "leavePartyConfirmText": "Sigur părăsești grupul?", - "leavePartyText": "Părăsește grup", + "leaveGameText": "Părăsește Jocul", + "leavePartyConfirmText": "Sigur vrei să părăsești grupul?", + "leavePartyText": "Părăsește Jocul", "quitText": "Ieși", "resumeText": "Continuă", "settingsText": "Setări" }, "makeItSoText": "Așa să fie!", - "mapSelectGetMoreMapsText": "Vezi mai multe...", - "mapSelectText": "Selectează", - "mapSelectTitleText": "Hărți ${GAME}", - "mapText": "Hartă", - "mostValuablePlayerText": "Cel mai valoros jucător", - "mostViolatedPlayerText": "Cel mai violat jucător", - "mostViolentPlayerText": "Cel mai violent jucător", - "moveText": "Mișcă-te", + "mapSelectGetMoreMapsText": "Ia Mai Multe Hărți...", + "mapSelectText": "Selectează...", + "mapSelectTitleText": "Hărți Pentru ${GAME}", + "mapText": "Harta", + "maxConnectionsText": "Număr De Locuri", + "maxPartySizeText": "Număr Maxim De Locuri", + "maxPlayersText": "Locuri", + "modeArcadeText": "Mod Pentru Arcade", + "modeClassicText": "Modul Clasic", + "modeDemoText": "Modul Demonstrativ", + "mostValuablePlayerText": "Cel mai valoros jucător este", + "mostViolatedPlayerText": "Cel mai ucis jucător este", + "mostViolentPlayerText": "Cel mai violent jucător este", + "moveText": "Te miști din", "multiKillText": "${COUNT} ucideri!!!", - "multiPlayerCountText": "${COUNT} (de) jucători", - "mustInviteFriendsText": "Notă: trebuie să inviți prieteni pe \npanelul \"${GATHER}\" sau ataşează c\ncontroalăre pentru a juca multiplayer.", + "multiPlayerCountText": "${COUNT} jucători", + "mustInviteFriendsText": "Notă: du-te în meniul \"${GATHER}\"\nsau conectează-ți câteva controllere\ndacă vrei să te joci multiplayer cu prietenii.", "nameBetrayedText": "${NAME} a trădat pe ${VICTIM}", "nameDiedText": "${NAME} a murit.", "nameKilledText": "${NAME} a omorât pe ${VICTIM}", - "nameNotEmptyText": "Numele nu poate fi gol!", + "nameNotEmptyText": "Trebubie să-ți pui un nume!", "nameScoresText": "${NAME} înscrie!", - "nameSuicideKidFriendlyText": "${NAME} a murit din greșeală.", + "nameSuicideKidFriendlyText": "${NAME} a pierit accidental.", "nameSuicideText": "${NAME} s-a sinucis.", - "nativeText": "nativ", - "newPersonalBestText": "Best Personal Nou!", - "newTestBuildAvailableText": "Un Test Build nou este lansat! (${VERSION} build ${BUILD}).\nIa-o pe ${ADDRESS}", + "nameText": "Numele", + "nativeText": "Nativă", + "newPersonalBestText": "Un nou record personal a fost atins!", + "newTestBuildAvailableText": "O nouă versiune Beta a fost lansată: (${VERSION} build ${BUILD}).\nIa-o de pe ${ADDRESS}", "newText": "Nou", - "newVersionAvailableText": "O versiune nouă pentru BombSquad este disponibila! (${VERSION})", - "nextAchievementsText": "Realizările următoare:", - "nextLevelText": "Nivelul următor", + "newVersionAvailableText": "O versiune nouă de ${APP_NAME} este disponibilă,aceasta fiind (${VERSION})!", + "nextAchievementsText": "Realizările Următoare:", + "nextLevelText": "Următorul Nivel", "noAchievementsRemainingText": "- niciunul", "noContinuesText": "(fără continuări)", - "noExternalStorageErrorText": "Nu a fost găsit niciun depozit External pe acest dispozitiv.", - "noGameCircleText": "Eroare: nu eşti logat în GameCircle", + "noExternalStorageErrorText": "Nu a fost găsită nicio stocare externă pe acest dispozitiv.", + "noGameCircleText": "Eroare: nu eşti logat cu GameCircle", "noProfilesErrorText": "Nu ai niciun Profil de Jucător, deci eşti blocat cu '${NAME}'.\nDute la Setări->Profile de Jucător pentru a-ți face un profil.", "noScoresYetText": "Niciun scor deocamdată.", - "noThanksText": "Nu mulțumesc", - "noValidMapsErrorText": "Nu s-a găsit nici-o hartă validă pentru acest mod de joc.", - "notEnoughPlayersRemainingText": "Nu au rămas destui jucători; ieşi şi începe un joc nou.", + "noThanksText": "Nu Mulțumesc", + "noTournamentsInTestBuildText": "ATENȚIE: Scorurile obținute în turnee vor fi ignorate în această versiune beta.", + "noValidMapsErrorText": "Nu sunt hărți disponibile pentru acest mod de joc.", + "notEnoughPlayersRemainingText": "Nu mai sunt destui jucători; ieși din joc și creează altul nou.", "notEnoughPlayersText": "Ai nevoie de cel puțin ${COUNT} jucători pentru a începe acest joc!", "notNowText": "Nu Acum", - "notSignedInErrorText": "Trebuie să fi conectat pentru a face asta.", - "notSignedInGooglePlayErrorText": "Trebuie să fi conectat prin Google Play pentru a face asta.", - "notSignedInText": "nu este conectat", - "nothingIsSelectedErrorText": "Nimic nu este selectat!", + "notSignedInErrorText": "Trebuie să fi conectat cu un cont dacă vrei să faci asta.", + "notSignedInGooglePlayErrorText": "Trebuie să fii conectat cu Google Play dacă vrei să faci asta.", + "notSignedInText": "nu te-ai conectat cu nici un cont", + "nothingIsSelectedErrorText": "Nu ai selectat nimic!", "numberText": "#${NUMBER}", "offText": "Oprit", "okText": "Ok", "onText": "Pornit", + "oneMomentText": "Un Moment...", "onslaughtRespawnText": "${PLAYER} va reveni în valul ${WAVE}", "orText": "${A} sau ${B}", + "otherText": "Altele...", "outOfText": "(#${RANK} din ${ALL})", "ownFlagAtYourBaseWarning": "Steagul tău trebuie să fie\nla bază pentru a înscrie!", - "packageModsEnabledErrorText": "Network-play nu este activat cănd modurile-local-package sunt active (vezi Setări->Avansat)", + "packageModsEnabledErrorText": "Network-play-ul nu poate fi pornit cât timp modurile-local-package sunt active (vezi Setări->Avansat)", "partyWindow": { - "chatMessageText": "Mesaje", + "chatMessageText": "Mesaj Prin Chat", "emptyText": "Petrecerea ta este goală", - "hostText": "(host)", + "hostText": "(hostul)", "sendText": "Trimite", "titleText": "Petrecerea Ta" }, - "pausedByHostText": "(pus pe pauză)", + "pausedByHostText": "(pus pe pauză de către host)", "perfectWaveText": "Val Perfect!", "pickUpText": "Ridică", "playModes": { - "coopText": "Co-operare", - "freeForAllText": "Fiecare pentru el", - "multiTeamText": "Mai multe echipe", + "coopText": "Cooperare", + "freeForAllText": "Fiecare-pentru-El", + "multiTeamText": "Cu mai multe echipe", "singlePlayerCoopText": "Un singur jucător / Cooperare", "teamsText": "Echipe" }, @@ -1057,115 +1096,123 @@ "titleText": "Joacă", "twoToEightPlayersText": "2-8 jucători" }, - "playerCountAbbreviatedText": "${COUNT} jucători", - "playerDelayedJoinText": "${PLAYER} va intra la începutul jocului următor.", - "playerInfoText": "Info Jucător", + "playerCountAbbreviatedText": "${COUNT}P", + "playerDelayedJoinText": "${PLAYER} va intra la începutul rundei următoare.", + "playerInfoText": "Informații Despre Jucător", "playerLeftText": "${PLAYER} a ieşit din joc.", - "playerLimitReachedText": "Limita de ${COUNT} jucători atinsă; nimeni nu mai are voie să intre.", + "playerLimitReachedText": "Limita de ${COUNT} jucători a fost atinsă; nimeni nu mai are voie să intre.", "playerProfilesWindow": { - "cantDeleteAccountProfileText": "Nu poți să-ți ștergi profilul de cont.", - "deleteButtonText": "Șterge\nprofil", - "deleteConfirmText": "Șterge '${PROFILE}'?", - "editButtonText": "Editează\nProfil", - "explanationText": "(crează nume & aparențe personalizate pentru jucătorii se pe acest dispozitiv)", + "cantDeleteAccountProfileText": "Nu poți să-ți ștergi profilul contului.", + "deleteButtonText": "Șterge\nprofilul", + "deleteConfirmText": "Ștergi profilul '${PROFILE}'?", + "editButtonText": "Editează\nProfilul", + "explanationText": "(nume și aparențe personalizate pe acest cont)", "newButtonText": "Profil\nNou", - "titleText": "Profile jucător" + "titleText": "Profilele Jucătorului" }, "playerText": "Jucător", - "playlistNoValidGamesErrorText": "Această listă de redare nu conține jocuri deblocate valide.", - "playlistNotFoundText": "lista de redare nu a fost găsită", - "playlistsText": "Liste de redare", - "pleaseRateText": "Dacă îți place BombSquad, consideră să-ți iei un moment să\nevaluezi jocul sau să scrii o revizuire. Aceasta furnizează\nfeedback folositor și ajută să suporte dezvoltarea jocului în viitor.\n\nmulțumesc!\n-eric", + "playlistNoValidGamesErrorText": "Această listă nu conține jocuri deblocate valide.", + "playlistNotFoundText": "lista nu a fost găsită", + "playlistText": "Lista de jocuri", + "playlistsText": "Liste de Jocuri", + "pleaseRateText": "Dacă îți place ${APP_NAME}, te rog să stai\no clipă și să evaluezi jocul scriind o recenzie pentru acesta.\nAceasta furnizează feedback folositor și ajută la dezvoltarea jocului în viitor.\n\nmulțumesc!\n-Eric", + "pleaseWaitText": "Te rog să aștepți...", + "pluginsDetectedText": "Plugin(uri) noi detectate. Activează-le/configurează-le în setări.", + "pluginsText": "Plugin-uri", "practiceText": "Antrenament", "pressAnyButtonPlayAgainText": "Apasă orice buton pentru a juca din nou...", "pressAnyButtonText": "Apasă orice buton pentru a continua...", - "pressAnyButtonToJoinText": "apasă orice buton pentru a veni...", + "pressAnyButtonToJoinText": "apasă orice buton pentru a intra...", "pressAnyKeyButtonPlayAgainText": "Apasă orice buton/tastă pentru a juca din nou...", "pressAnyKeyButtonText": "Apasă orice buton/tastă pentru a continua...", "pressAnyKeyText": "Apasă orice tastă...", - "pressJumpToFlyText": "** Apasă Săritura de multe ori pentru a zbura **", - "pressPunchToJoinText": "apasă PUMN pentru a veni...", - "pressToOverrideCharacterText": "apasă ${BUTTONS} pentru ați înlocuii caracterul", - "pressToSelectProfileText": "apasă ${BUTTONS} pentru ați selecta caracterul", - "pressToSelectTeamText": "apasă ${BUTTONS} pentru ați selecta echipa", + "pressJumpToFlyText": "** Apasă butonul de sărit repetat pentru a zbura **", + "pressPunchToJoinText": "apasă PUMN pentru a intra...", + "pressToOverrideCharacterText": "apasă ${BUTTONS} pentru a-ți schimba caracterul", + "pressToSelectProfileText": "apasă ${BUTTONS} pentru a-ți selecta caracterul", + "pressToSelectTeamText": "apasă ${BUTTONS} pentru a-ți selecta echipa", "promoCodeWindow": { - "codeText": "Cod", + "codeText": "Introdu Codul", "codeTextDescription": "Cod Promoțional", - "enterText": "Enter" + "enterText": "Trimite Codul" }, - "promoSubmitErrorText": "Eroare la introducerea codului; verifică conexiunea la internet", + "promoSubmitErrorText": "Eroare la trimiterea codului; verifică-ți conexiunea la internet", "ps3ControllersWindow": { - "macInstructionsText": "Închide sursa de putere din spatele PS3-ului, asigură-te că \nBluetooth-ul este pornit în Mac-ul tău, apoi conectează controllerul\nprintr-un cablu USB pentru a le conecta. De acum înainte vei putea\nfolosi butonul de home de pe controller pentru al conecta în Mac-ul tău\nprin USB sau prin Bluetooth (apăsând pe butonul HOME).\n\nÎn unele Mac-uri s-ar putea să apară o fereastră care va cere un cod când conectați controllerul.\nDacă se întâmplă acest lucru, vezi tutorialul de mai jos sau caută pe google.\n\n\n\n\nControllerele PS3 conectate fără fir as trebui să apară în\nDevice List în System Preferences->Bluetooth. Ar trebuii să le ştergi de\npe acea listă dacă vrei să le foloseşti cu PS3-ul tău din nou.\n\nDesigur asigură-te ca le desconectezi din Bluetooth când nu le foloseşti \nsau bateria lor va continua să scadă.\n\nBluetooth-ul ar trebuii să țină până la 7 dispozitive conectate,\ndar acest lucru s-ar putea să varieze.", - "ouyaInstructionsText": "Pentru a folosi un controller de PS3 cu OUYA-ul tău, conectează-l simplu printr-un cablu USB\no dată pentru al conecta. Acest lucru s-ar putea să-ți scoată celelalte controllere, deci \natunci ar trebuii să-ți restartezi OUYA-ul şi să scoți cablul USB.\n\nDupă vei putea conecta controllerul simplu prin apăsarea butonului HOME.\nCând ai terminat de jucat, ține apăsat pe butonul de HOME pentru\n10 secunde pentru a închide controllerul; sau va rămâne conectat\nşi va irosi baterii.", - "pairingTutorialText": "video tutorial pentru pairing", - "titleText": "Folosind controllere PS3 cu BombSquad:" + "macInstructionsText": "Scoate PS3-ul din priză, asigură-te că \nai Bluetooth-ul pornit pe Mac-ul tău, apoi conectează controllerul\nprintr-un cablu USB pentru a împerechea ambele dispozitive. De acum înainte vei putea\nfolosi butonul 'HOME' de pe controller pentru a-l conecta la Mac-ul tău\nprin USB sau prin Bluetooth (apăsând pe butonul HOME).\n\nPe unele Mac-uri s-ar putea să apară o fereastră care va cere un cod când conectezi controllerul.\nDacă se întâmplă acest lucru, uite-te la tutorialul de mai jos sau caută pe Google ce trebuie să faci.\n\n\n\n\nControllerele PS3 conectate fără fir as trebui să apară în\nlista dispozitivelor în System Preferences->Bluetooth. Ar trebui să le ştergi de\npe acea listă dacă vrei să le foloseşti la PS3-ul tău din nou.\n\nȘi asigură-te să le deconectezi de la Bluetooth când nu le foloseşti \nsau bateriile lor vor continua să se consume.\n\nBluetooth-ul poate ține în jur de 7 dispozitive conectate,\ndar acest lucru ar putea varia de la un dispozitiv la altul.", + "macInstructionsTextScale": 0.73, + "ouyaInstructionsText": "Pentru a folosi un controller de PS3 cu OUYA-ul tău, conectează-l pur și simplu printr-un cablu USB\no singură dată pentru a-l conecta. Acest lucru s-ar putea să-ți deconecteze celelalte controllere, deci \nva trebui să-ți restartezi OUYA-ul şi să scoți cablul USB.\n\nDupă aceea vei putea conecta controllerul prin apăsarea butonului HOME.\nCând nu mai vrei să te joci, ține apăsat pe butonul HOME timp de\n10 secunde ca să închizi controllerul; în caz contrar va continua să\nfie pornit,consumându-și bateriile.", + "ouyaInstructionsTextScale": 0.73, + "pairingTutorialText": "tutorial video pentru împerecherea dispozitivelor", + "titleText": "Controllere de PS3 active în ${APP_NAME}:" }, "punchBoldText": "PUMN", "punchText": "Pumn", "purchaseForText": "Cumpără pentru ${PRICE}", - "purchaseGameText": "Cumpără Joc", + "purchaseGameText": "Cumpără Jocul", "purchasingText": "Se cumpără...", - "quitGameText": "Părăsești ${APP_NAME}?", - "quittingIn5SecondsText": "Se închide în 5 secunde...", - "randomPlayerNamesText": "Andrei, Marius, Marian, Cosmin, Cristi, Ioana, Gabi, Călin, Teodor, Mihai, Alex, Alexandra, Bogdan, Cătălin, Ştefan, George.", + "quitGameText": "Ieși din ${APP_NAME}?", + "quittingIn5SecondsText": "Se iese în 5 secunde...", + "randomPlayerNamesText": "Andrei, Marius, Marian, Cosmin, Cristi, Ioana, Gabi, Călin, Teodor, Mihai, Alex, Alexandra, Bogdan, Cătălin, Ştefan, George, Nicoleta, Antonio, David, Teodora, Denisa, Iuliana, Mariana, Nicușor, Sebastian", "randomText": "La Nimereală", "rankText": "Rank", - "ratingText": "Evaluare", - "reachWave2Text": "Ajunge la valul 2 pentru ca scorul tău să fie rankat", + "ratingText": "Clasificare", + "reachWave2Text": "Trebuie să ajungi la valul 2 dacă vrei să ți se rankeze scorul.", "readyText": "pregătit", - "recentText": "Recent", + "recentText": "Recente", + "remoteAppInfoShortText": "${APP_NAME} este mult mai distractiv când este jucat cu familia & prietenii.\nConectează unul sau mai multe controllere sau instalează \naplicația ${REMOTE_APP_NAME} pe telefoane sau tablete\npentru a le folosi drept controllere.", "remote_app": { "app_name": "BombSquad Remote", "app_name_short": "BSRemote", - "button_position": "Poziție butoane", - "button_size": "Dimensiune butoane", - "cant_resolve_host": "Nu se poate găsi gazda.", - "capturing": "Se capturează...", + "button_position": "Poziția Butoanelor", + "button_size": "Dimensiunea Butoanelor", + "cant_resolve_host": "Nu se poate găsi hostul.", + "capturing": "Atribuie un buton...", "connected": "Conectat.", - "description": "Folosește-ți telefonul sau tableta ca un controller pt. BombSquad.\nPoți conecta până la 8 dispozitive simultan pentru o nebunie multiplayer pe un singur TV sau o tabletă.", + "description": "Folosește-ți telefonul sau tableta drept controller pentru BombSquad\nPoți conecta 8 dispozitive simultan pentru un mod multiplayer nebunesc pe un Televizor sau pe o tabletă.", "disconnected": "Deconectat de către server.", "dpad_fixed": "fixat", "dpad_floating": "liber", - "dpad_position": "Poziție D-Pad", - "dpad_size": "Dimensiune D-Pad", - "dpad_type": "Tip D-Pad", - "enter_an_address": "Introdu o adresă", - "game_full": "Jocul e plin sau nu acceptă conexiuni noi.", - "game_shut_down": "Jocul s-a oprit.", + "dpad_position": "Poziția D-Pad-ului", + "dpad_size": "Dimensiunea D-Pad-ului", + "dpad_type": "Tip de D-Pad", + "enter_an_address": "Introdu o Adresă", + "game_full": "Jocul este plin sau nu acceptă conexiuni noi.", + "game_shut_down": "Jocul a fost oprit.", "hardware_buttons": "Butoane Hardware", - "join_by_address": "Conectează-te după adresă...", + "join_by_address": "Conectează-te cu adresa...", "lag": "Lag: ${SECONDS} secunde", - "reset": "Resetează la valorile implicite", - "run1": "Alergat 1", - "run2": "Alergat 2", - "searching": "Se caută jocuri BombSquad...", - "searching_caption": "Apasă pe numele unui joc pentru a intra în el.\nFii sigur că ești pe aceiași rețea WiFi ca și jocul.", + "reset": "Resetează valorile la cele implicite", + "run1": "Buton de Alergare 1", + "run2": "Buton de Alergare 2", + "searching": "Se caută jocuri BombSquad prin internet...", + "searching_caption": "Apasă pe numele unui joc pentru a intra în el.\nFii sigur că ești pe aceiași rețea Wi-Fi ca și jocul hostului.", "start": "Start", - "version_mismatch": "Nepotrivire versiune.\nFii sigur că BombSquad și BombSquad Remote\nau ambele ultima versiune și reîncearcă." + "version_mismatch": "Versiuni Nepotrivite.\nAsigură-te că BombSquad și BombSquad Remote\nau cea mai nouă versiune și încearcă din nou." }, - "removeInGameAdsText": "Deblochează \"${PRO}\" în magazin pentru a şterge ad-urile din joc.", + "removeInGameAdsText": "Deblochează \"${PRO}\" în magazin pentru a şterge reclamele din joc.", "renameText": "Redenumeşte", - "replayEndText": "Sfărşeşte Reluarea", - "replayNameDefaultText": "Reluarea din ultimul joc", + "replayEndText": "Sfârşeşte Reluarea", + "replayNameDefaultText": "Reluarea Ultimului Joc", "replayReadErrorText": "Eroare la citirea fişierului de reluare.", - "replayRenameWarningText": "Redenumeşte \"${REPLAY}\" după un joc dacă vrei s-o păstrezi; altfel se va înlocui.", - "replayVersionErrorText": "Scuze, această reluare a fost făcută în altă versiune\nde joc şi nu poate fi folosită.", + "replayRenameWarningText": "Redenumeşte \"${REPLAY}\" după un joc dacă vrei s-o păstrezi; în caz contrar va fi înlocuită.", + "replayVersionErrorText": "Scuze, această reluare a fost făcută în altă versiune\na jocului şi nu poate fi pornită în aceasta.", "replayWatchText": "Vezi Reluarea", "replayWriteErrorText": "Eroare la scrierea fişierului de reluare.", "replaysText": "Reluări", - "reportPlayerExplanationText": "Foloseşte acest email pentru a raporta trişări, limbaj licențios, sau alte tipuri de comportament rău.\nTe rog descrie mai jos:", - "reportThisPlayerCheatingText": "Trișează", - "reportThisPlayerLanguageText": "Limbaj nepotrivit", - "reportThisPlayerReasonText": "Ce dorești să reclami?", - "reportThisPlayerText": "Reportează acest Jucător", - "requestingText": "Se încarcă...", + "reportPlayerExplanationText": "Foloseşte această adresă de E-Mail pentru a raporta trişori, limbaj vulgar, sau alte tipuri de comportamente inadecvate.\nTe rog descrie subiectul mai jos:", + "reportThisPlayerCheatingText": "Trișori", + "reportThisPlayerLanguageText": "Limbaj Vulgar", + "reportThisPlayerReasonText": "Ce ai vrea să reclami?", + "reportThisPlayerText": "Raportează Acest Jucător", + "requestingText": "Se ia...", "restartText": "Restart", "retryText": "Reîncearcă", - "revertText": "Revin-o la normal", - "runText": "Fugi", + "revertText": "Revino la setările normale", + "runText": "Pentru a fugi", "saveText": "Salvează", + "scanScriptsErrorText": "Una sau mai multe erori au fost detectate în timpul scanării scripturilor; vezi jurnalul de activități pentru detalii.", "scoreChallengesText": "Provocări de Scor", - "scoreListUnavailableText": "Listă de Scoruri nedisponibilă.", + "scoreListUnavailableText": "Lista de Scoruri este indisponibilă.", "scoreText": "Scor", "scoreUnits": { "millisecondsText": "Milisecunde", @@ -1177,123 +1224,138 @@ "seriesWinLine1PlayerText": "CÂŞTIGĂ", "seriesWinLine1TeamText": "CÂŞTIGĂ", "seriesWinLine1Text": "CÂŞTIGĂ", - "seriesWinLine2Text": "SERIILE", + "seriesWinLine2Text": "SERIILE!", "settingsWindow": { "accountText": "Cont", "advancedText": "Avansat", "audioText": "Audio", "controllersText": "Controllere", "graphicsText": "Grafici", + "playerProfilesMovedText": "Notă: Profilele de jucător au fost mutate în Fereastra conturilor din meniul principal.", "playerProfilesText": "Profile de Jucător", "titleText": "Setări" }, "settingsWindowAdvanced": { - "alwaysUseInternalKeyboardDescriptionText": "(o simplă, pentru controller tastatură pe-ecran pentru editarea textului)", - "alwaysUseInternalKeyboardText": "Foloseşte mereu tastatura Internală", + "alwaysUseInternalKeyboardDescriptionText": "(o tastatură simplă, în special pentru controllere, ce ajută la editarea textului)", + "alwaysUseInternalKeyboardText": "Foloseşte Mereu Tastatura Internală", "benchmarksText": "Teste-Stres şi referințe", - "enablePackageModsDescriptionText": "Activează mai multe capabilități dar dezactivează net-play)", - "enablePackageModsText": "Activează moduri cu pachete locale", - "enterPromoCodeText": "Introdu un cod Promo", - "forTestingText": "Notă: aceste valori sunt doar pentru teste şi for fi pierdute când aplicația se închide.", - "helpTranslateText": "Translatările BombSquad sunt un efort depus de comunitate.\nDacă ai vrea să te implici la translatarea unei limbi,\nurmează linkul de mai jos. Mulțumiri în plus!", - "kickIdlePlayersText": "Dă afară jucătorii care nu fac nimic", - "kidFriendlyModeText": "Modul Pentru Copii (mai puțina violența, etc)", + "disableCameraGyroscopeMotionText": "Oprește Camera De Tip Giroscop", + "disableCameraShakeText": "Oprește Zguduirea Camerei", + "disableThisNotice": "(poți opri această notificare în setările avansate)", + "enablePackageModsDescriptionText": "Permite mai multe capabilități pentru modare, dar dezactivează net-play-ul)", + "enablePackageModsText": "Activează Moduri cu Pachete Locale", + "enterPromoCodeText": "Introdu Codul", + "forTestingText": "Notă: aceste valori sunt doar pentru teste şi vor fi resetate când jocul va fi închis.", + "helpTranslateText": "Translațiile din ${APP_NAME} sunt un efort depus de comunitate.\nDacă ai dori să te implici la translatarea unei limbi,\nurmează linkul de mai jos. Multe mulțumiri!", + "kickIdlePlayersText": "Dă Afară Jucătorii Inactivi", + "kidFriendlyModeText": "Modul Pentru Copii (mai puțină violență, etc)", "languageText": "Limbă", - "moddingGuideText": "Ajutor pentru Modare", - "mustRestartText": "Va trebuii să restartezi jocul pentru ca acestea să aibă efect.", - "netTestingText": "Teste pentru Internet", - "resetText": "Reset", - "showPlayerNamesText": "Arată numele Jucătorilor", - "showUserModsText": "Arată folderul pentru moduri", + "moddingGuideText": "Ghid pentru Modare", + "mustRestartText": "Va trebui să restartezi jocul dacă vrei ca acest lucru să aibă efect.", + "netTestingText": "Testarea Internetului", + "resetText": "Resetează", + "showBombTrajectoriesText": "Arată Traiectoriile Bombelor", + "showPlayerNamesText": "Arată Numele Jucătorilor", + "showUserModsText": "Arată Folderul Pentru Moduri", "titleText": "Avansat", "translationEditorButtonText": "Editor de Translatări ${APP_NAME}", - "translationFetchErrorText": "status pentru translatare nedisponibil", - "translationFetchingStatusText": "Se verifică statusul...", - "translationNoUpdateNeededText": "Limba curentă are cea mai nouă versiune; uraaaaa!", + "translationFetchErrorText": "status pentru translatare indisponibil", + "translationFetchingStatusText": "Se verifică statusul limbii...", + "translationInformMe": "Informează-mă când limba mea are nevoie de actualizări", + "translationNoUpdateNeededText": "Limba curentă este actualizată; uraaaaa!", "translationUpdateNeededText": "** limba curentă are nevoie de update-uri!! **", - "vrTestingText": "Teste RV" + "vrTestingText": "Teste Pentru VR" }, + "shareText": "Partajează", + "sharingText": "Se partajează...", "showText": "Arată", - "signInForPromoCodeText": "Va trebuii să te conectezi la un cont pentru ca codurile-promo să aibă efect.", + "signInForPromoCodeText": "Va trebui să te conectezi cu un cont dacă vrei să funționeze codurile introduse.", "signInWithGameCenterText": "Pentru a folosi un cont Game Center\nconectează-te folosind aplicația Game Center.", "singleGamePlaylistNameText": "Doar ${GAME}", "singlePlayerCountText": "1 jucător", "soloNameFilterText": "${NAME} Solo", "soundtrackTypeNames": { - "CharSelect": "Selecție de Caracter", + "CharSelect": "Selecția Caracterului", "Chosen One": "Alesul", - "Epic": "Jocurile în mod Epic", + "Epic": "Jocurile în Slow Motion", "Epic Race": "Cursă Epică", "FlagCatcher": "Capturează Steagul", - "Flying": "Memorii Fericite", - "Football": "Fotbal", + "Flying": "Amintiri Fericite", + "Football": "TouchDown", "ForwardMarch": "Asalt", "GrandRomp": "Cucerire", "Hockey": "Hockey", "Keep Away": "Stai Departe", "Marching": "Runaround", - "Menu": "Meniul principal", + "Menu": "Meniu principal", "Onslaught": "Măcel", "Race": "Cursă", "Scary": "Regele Dealului", - "Scores": "Meniul pentru Scor", + "Scores": "Meniul de Scoruri", "Survival": "Eliminare", "ToTheDeath": "Meciul Morții", - "Victory": "Meniul pentru Scorul Final" + "Victory": "Meniul de Scoruri Finale" }, - "spaceKeyText": "space", + "spaceKeyText": "spacebar", + "statsText": "Statistici", + "storagePermissionAccessText": "Acest beneficiu are nevoie de permisiuni de stocare", "store": { - "alreadyOwnText": "Deja ai ${NAME}!", + "alreadyOwnText": "Ai cumpărat ${NAME} deja!", "bombSquadProDescriptionText": "•Dublează biletele primite\n•Şterge advertismentele din joc\n•Include ${COUNT} de bilete bonus\n•+${PERCENT}% la scorul de la ligi\n•Deblochează '${INF_ONSLAUGHT}' şi \n '${INF_RUNAROUND}' ca nivele co-op", "bombSquadProFeaturesText": "Caracteristici:", "bombSquadProNameText": "${APP_NAME} Pro", + "bombSquadProNewDescriptionText": "• Șterge reclamele și pop-up-urile enervante\n• Deblochează mai multe setări ale jocului\n• Acesta mai include și:", "buyText": "Cumpără", "charactersText": "Caractere", - "comingSoonText": "Va veni...", + "comingSoonText": "În Curând...", "extrasText": "Extra", - "freeBombSquadProText": "BombSquad este acum gratis, dar fiindcă tu l-ai cumpărat primeşti upgrade-ul \nla BombSquad Pro şi ${COUNT} de bilete ca un mulțumesc.\nMulțumesc pentru suportul tău!\n-Eric", + "freeBombSquadProText": "BombSquad este un joc gratuit, dar fiindcă tu l-ai cumpărat primeşti upgrade-ul \nla BombSquad Pro şi ${COUNT} de bilete drept mulțumire.\nÎți mulțumesc pentru suportul tău!\n-Eric", "gameUpgradesText": "Upgrade-uri pentru joc", - "holidaySpecialText": "Speciale pentru Sărbători", - "howToSwitchCharactersText": "(dute la \"${SETTINGS} -> ${PLAYER_PROFILES}\" pentru ați seta şi particulariza caractere)", - "howToUseIconsText": "(creează profile de jucător globale în \"${SETTINGS} -> ${PLAYER_PROFILES}\" pentru a folosi acestea)", - "howToUseMapsText": "(foloseşte aceste hărți în listele de redare Echipe/Fiecare Pentru El ale tale)", - "iconsText": "Imagini", - "loadErrorText": "Imposibil de încărcat pagina.\nVerifică-ți conexiunea la internet.", - "loadingText": "încărcare", - "mapsText": "Harti", + "holidaySpecialText": "Speciale pe timp de Sărbători", + "howToSwitchCharactersText": "(du-te la \"${SETTINGS} -> ${PLAYER_PROFILES}\" ca să-ți setezi & particularizezi caracterele)", + "howToUseIconsText": "(creează profile de jucător globale (în fereastra conturilor) pentru a le folosi)", + "howToUseMapsText": "(foloseşte aceste hărți în listele cu jocuri de Echipe/Fiecare-Pentru-El făcute de tine)", + "iconsText": "Iconițe", + "loadErrorText": "Nu se poate încărca pagina.\nVerifică-ți conexiunea la internet.", + "loadingText": "se încarcă", + "mapsText": "Hărți", "miniGamesText": "MiniJocuri", - "oneTimeOnlyText": "(doar o dată)", + "oneTimeOnlyText": "(o singură dată)", "purchaseAlreadyInProgressText": "Deja se cumpără acest obiect.", "purchaseConfirmText": "Cumperi ${ITEM}?", - "purchaseNotValidError": "Achiziționarea nu este validă.\nContactează ${EMAIL} dacă aceasta este o eroare.", + "purchaseNotValidError": "Achiziționarea nu este validă.\nContactează adresa de E-Mail ${EMAIL} dacă aceasta este o eroare.", "purchaseText": "Cumpără", - "saleBundleText": "Pachet de Vânzare!", - "saleExclaimText": "Vânzare!", + "saleBundleText": "Pachet La Reducere!", + "saleExclaimText": "Reducere!", "salePercentText": "(${PERCENT}% mai ieftin)", - "saleText": "VÂNZARE", + "saleText": "REDUCERE", "searchText": "Caută", - "teamsFreeForAllGamesText": "Joc în echipe / fiecare pentru el", - "winterSpecialText": "Speciale pentru iarnă", - "youOwnThisText": "-deja ai asta-" + "teamsFreeForAllGamesText": "Joc în echipe / Fiecare-Pentru-El", + "totalWorthText": "*** ofertă cu valoare de ${TOTAL_WORTH}! ***", + "upgradeQuestionText": "Vrei să-ți îmbunătățești versiunea?", + "winterSpecialText": "Speciale pe timp de Iarnă", + "youOwnThisText": "-deja ai cumpărat asta-" }, - "storeDescriptionText": "Nebunie pentru 8 Jucători!\n\nExplodează-ți prietenii (sau computerul) într-un concurs de mini-jocuri explozive ca Capturează Steagul, Hockey-Bombist, şi Meci-de-Moarte-În-Slow-Motion-Epic!\n\nControllurile simple şi suportul pentru diferite tipuri de controller fac posibilă jucarea cu un maxim de 8 jucători; poți chiar folosi şi telefonul ca controller prin aplicația 'BombSquad Remote'!\n\nBombele Afară!\n\nVezi www.froemling.net/bombsquad pentru mai multe informații.", + "storeDescriptionText": "Nebunie pentru 8 Jucători!\n\nExplodează-ți prietenii (sau computerul) într-un concurs de mini-jocuri explozive cum ar fi Capturează Steagul, Hockey-Bombist, şi Meci-de-Moarte-În-Slow-Motion-Epic!\n\nControllurile simple şi suportul pentru diferite tipuri de controller fac posibilă joaca cu un maxim de 8 jucători; poți folosi chiar şi telefonul drept controller cu ajutorul aplicației 'BombSquad Remote'!\n\nScoate Bombele Afară!\n\nVezi www.froemling.net/bombsquad pentru mai multe informații.", "storeDescriptions": { "blowUpYourFriendsText": "Explodează-ți prietenii.", - "competeInMiniGamesText": "Întrecete în mini-jocuri de la curse până la zbor.", - "customize2Text": "Particularizează caractere, mini-jocuri şi chiar soundtrack-ul.", - "customizeText": "Particularizează caractere şi creează-ți listele de redare cu mini-jocuri cum vrei tu.", - "sportsMoreFunText": "Sporturile sunt mai distractive cu explozibil.", + "competeInMiniGamesText": "Întrece-te în mini-jocuri începând de la curse până la zburat.", + "customize2Text": "Particularizează caractere, mini-jocuri, chiar și muzica jocului.", + "customizeText": "Particularizează-ți caracterele şi creează-ți listele de jocuri cu mini-jocuri cum vrei tu.", + "sportsMoreFunText": "Sporturile sunt mai distractive cu explozibile.", "teamUpAgainstComputerText": "Fă echipă contra computerului." }, "storeText": "Magazin", - "submittingPromoCodeText": "Se introduce Codul Promo...", - "telnetAccessGrantedText": "Acces la Telnet activat.", - "telnetAccessText": "Acces Telnet detectat; permite?", - "testBuildErrorText": "Acest Test Build nu mai este activ; te rog verifică pentru o versiune nouă.", - "testBuildText": "Test Build", - "testBuildValidateErrorText": "Nu se poate valida Test Build-ul. (fără conexiune la internet?)", - "testBuildValidatedText": "Test Build validat; bucură-te de el!", - "thankYouText": "Mulțumesc pentru suport! Bucură-te de joc!!", + "submitText": "Trimite", + "submittingPromoCodeText": "Se trimite Codul...", + "teamNamesColorText": "Numele/Culorile Echipelor", + "telnetAccessGrantedText": "Acces la Telnet permis.", + "telnetAccessText": "Acces Telnet detectat; îl permiți?", + "testBuildErrorText": "Acesastă versiune de test nu mai este activă; te rog să cauți alta mai nouă.", + "testBuildText": "Versiune de Test", + "testBuildValidateErrorText": "Nu se poate valida versiunea de test. (fără conexiune la internet?)", + "testBuildValidatedText": "Versiune de Test validată; bucură-te de ea!", + "thankYouText": "Îți mulțumesc pentru suport! Bucură-te de joc!!", "threeKillText": "TRIPLU-OMOR!!", "timeBonusText": "Timp Bonus", "timeElapsedText": "Timp Scurs", @@ -1304,100 +1366,118 @@ "timeSuffixSecondsText": "${COUNT}s", "tipText": "Sfat", "titleText": "BombSquad", - "titleVRText": "BombSquad RV", - "topFriendsText": "Prieteni Top", + "titleVRText": "BombSquad VR", + "topFriendsText": "Prieteni de Top", "tournamentCheckingStateText": "Se verifică starea campionatului; aşteaptă...", - "tournamentEndedText": "Acest campionat s-a terminat. Va începe un altul curând.", - "tournamentEntryText": "Preț pentru intrare", + "tournamentEndedText": "Acest campionat s-a terminat. Altul nou va începe în curând.", + "tournamentEntryText": "Preț Pentru Campionat", "tournamentResultsRecentText": "Rezultatele Recente ale Campionatului", - "tournamentStandingsText": "Clasament pentru Campionat", + "tournamentStandingsText": "Clasamentele Campionatului", "tournamentText": "Campionat", - "tournamentTimeExpiredText": "Timpul Concursului a Expirat", + "tournamentTimeExpiredText": "Timpul Campionatului a Expirat", "tournamentsText": "Campionate", "translations": { "characterNames": { + "Agent Johnson": "Agentul Johnson", + "B-9000": "B-9000", "Bernard": "Bernard", "Bones": "Oase", + "Butch": "Butch", + "Easter Bunny": "Iepurașul de Paște", + "Flopsy": "Flopsy", "Frosty": "Frosty", + "Gretel": "Gretel", + "Grumbledorf": "Grumbledorf", "Jack Morgan": "Jack Morgan", "Kronk": "Kronk", + "Lee": "Lee", + "Lucky": "Norocosul", "Mel": "Mel", + "Middle-Man": "Omul-Mijlociu", + "Minimus": "Minimus", + "Pascal": "Pascal", + "Pixel": "Pixel", + "Sammy Slam": "Sammy Aruncătorul", "Santa Claus": "Moş Crăciun", "Snake Shadow": "Umbra Şarpelui", "Spaz": "Spaz", - "Zoe": "Zoe" + "Taobao Mascot": "Mascota Taobao", + "Todd McBurton": "Todd McBurton", + "Zoe": "Zoe", + "Zola": "Zola" }, "coopLevelNames": { - "${GAME} Training": "${GAME} Antrenament", + "${GAME} Training": "Antrenament pentru ${GAME}", "Infinite ${GAME}": "${GAME} Infinit", "Infinite Onslaught": "Măcel Infinit", "Infinite Runaround": "Runaround Infinit", "Onslaught Training": "Antrenament Măcel", "Pro ${GAME}": "${GAME} Pro", - "Pro Football": "Fotbal Pro", + "Pro Football": "TouchDown Pro", "Pro Onslaught": "Măcel Pro", "Pro Runaround": "Runaround Pro", "Rookie ${GAME}": "${GAME} Începător", - "Rookie Football": "Fotbal Începător", + "Rookie Football": "TouchDown Începător", "Rookie Onslaught": "Măcel Începător", "The Last Stand": "Ultimul Rămas", "Uber ${GAME}": "MEGA ${GAME}", - "Uber Football": "MEGA Fotbal", + "Uber Football": "MEGA TouchDown", "Uber Onslaught": "MEGA Măcel", "Uber Runaround": "MEGA Runaround" }, "gameDescriptions": { - "Be the chosen one for a length of time to win.\nKill the chosen one to become it.": "Fi ales pentru o perioadă de timp pentru a câştiga.\nOmoară-l pe ales pentru a deveni tu.", + "Be the chosen one for a length of time to win.\nKill the chosen one to become it.": "Fii cel ales pentru o perioadă de timp pentru a câştiga.\nOmoară-l pe ales pentru a deveni tu acela.", "Bomb as many targets as you can.": "Bombează cât mai multe ținte.", "Carry the flag for ${ARG1} seconds.": "Ține steagul pentru ${ARG1} (de) secunde.", "Carry the flag for a set length of time.": "Ține steagul pentru o perioadă de timp.", "Crush ${ARG1} of your enemies.": "Ucide ${ARG1} (de) inamici.", "Defeat all enemies.": "Înfrânge toți inamicii.", "Dodge the falling bombs.": "Ai grijă la bombe.", - "Final glorious epic slow motion battle to the death.": "Bătaie finală glorioasă în slow motion epic până la moarte.", + "Final glorious epic slow motion battle to the death.": "Bătălie finală glorioasă până la moarte în slow motion epic .", + "Gather eggs!": "Colectează ouă!", "Get the flag to the enemy end zone.": "Cară steagul către partea inamică.", - "How fast can you defeat the ninjas?": "Cât de rapid îi poți doborî pe ninja?", - "Kill a set number of enemies to win.": "Ucide un număr de inamici pentru a câştiga.", + "How fast can you defeat the ninjas?": "Cât de rapid îi poți învinge pe ninja?", + "Kill a set number of enemies to win.": "Ucide un număr anumit de inamici pentru a câştiga.", "Last one standing wins.": "Ultimul rămas în picioare câştigă.", "Last remaining alive wins.": "Ultimul rămas în viață câştigă.", "Last team standing wins.": "Ultima echipă rămasă în picioare câştigă.", "Prevent enemies from reaching the exit.": "Nu lăsa inamicii să ajungă la sfârşit.", - "Reach the enemy flag to score.": "Ajunge la steagul inamic pentru a puncta.", - "Return the enemy flag to score.": "Returnează steagul inamic pentru a puncta.", - "Run ${ARG1} laps.": "Fugi ${ARG1} (de) ture.", - "Run ${ARG1} laps. Your entire team has to finish.": "Fugi ${ARG1} (de) ture. Toată echipa trebuie să termine.", + "Reach the enemy flag to score.": "Atinge steagul inamic pentru a înscrie.", + "Return the enemy flag to score.": "Returnează steagul inamicilor pentru a puncta.", + "Run ${ARG1} laps.": "Fugi ${ARG1} ture.", + "Run ${ARG1} laps. Your entire team has to finish.": "Fugi ${ARG1} ture. Toată echipa ta trebuie să termine.", "Run 1 lap.": "Fugi o tură.", - "Run 1 lap. Your entire team has to finish.": "Fugi o tură. Toată echipa trebuie să termine.", + "Run 1 lap. Your entire team has to finish.": "Fugi o tură. Toată echipa ta trebuie să termine.", "Run real fast!": "Fugi extrem de repede!", - "Score ${ARG1} goals.": "Înscrie ${ARG1} (de) goluri.", - "Score ${ARG1} touchdowns.": "Înscrie ${ARG1} (de) Touchdown-uri.", + "Score ${ARG1} goals.": "Înscrie ${ARG1} goluri.", + "Score ${ARG1} touchdowns.": "Înscrie ${ARG1} touchdown-uri.", "Score a goal.": "Înscrie un gol.", - "Score a touchdown.": "Înscrie un Touchdown.", + "Score a touchdown.": "Înscrie un touchdown.", "Score some goals.": "Înscrie nişte goluri.", - "Secure all ${ARG1} flags.": "Cucereşte toate cele ${ARG1} (de) steaguri.", - "Secure all flags on the map to win.": "Toate steagurile trebuie să fie ale tale pentru a câştiga.", + "Secure all ${ARG1} flags.": "Cucereşte cele ${ARG1} steaguri.", + "Secure all flags on the map to win.": "Toate steagurile trebuiesc cucerite de echipa ta pentru a câştiga.", "Secure the flag for ${ARG1} seconds.": "Ține steagul pentru ${ARG1} (de) secunde.", - "Secure the flag for a set length of time.": "Ține steagul pentru o perioadă de timp.", - "Steal the enemy flag ${ARG1} times.": "Fură steagul inamic de ${ARG1} (de) ori.", - "Steal the enemy flag.": "Fură steagul inamicilor", - "There can be only one.": "Aici poate fi doar unul.", - "Touch the enemy flag ${ARG1} times.": "Atinge steagul inamicului de ${ARG1} (de) ori", - "Touch the enemy flag.": "Atinge steagul inamicului", + "Secure the flag for a set length of time.": "Ține steagul pentru o perioadă anumită de timp.", + "Steal the enemy flag ${ARG1} times.": "Fură steagul inamic de ${ARG1} ori.", + "Steal the enemy flag.": "Fură steagul inamic.", + "There can be only one.": "Aici poate fi numai unul.", + "Touch the enemy flag ${ARG1} times.": "Atinge steagul inamic de ${ARG1} ori", + "Touch the enemy flag.": "Atinge steagul inamicilor.", "carry the flag for ${ARG1} seconds": "ține steagul pentru ${ARG1} (de) secunde", - "kill ${ARG1} enemies": "ucide ${ARG1} (de) inamici", + "kill ${ARG1} enemies": "omoară ${ARG1} (de) inamici", "last one standing wins": "ultimul rămas în picioare câştigă", "last team standing wins": "ultima echipă rămasă în picioare câştigă", "return ${ARG1} flags": "returnează ${ARG1} steaguri", "return 1 flag": "returnează un steag", - "run ${ARG1} laps": "fugi ${ARG1} (de) ture", + "run ${ARG1} laps": "fugi ${ARG1} ture", "run 1 lap": "fugi o tură", - "score ${ARG1} goals": "înscrie ${ARG1} (de) goluri", - "score ${ARG1} touchdowns": "înscrie ${ARG1} (de) touchdown-uri", + "score ${ARG1} goals": "înscrie ${ARG1} goluri", + "score ${ARG1} touchdowns": "înscrie ${ARG1} touchdown-uri", "score a goal": "înscrie un gol", - "score a touchdown": "înscrie un Touchdown", - "secure all ${ARG1} flags": "cucereşte toate cele ${ARG1} (de) steaguri.", + "score a touchdown": "înscrie un touchdown", + "secure all ${ARG1} flags": "cucereşte cele ${ARG1} steaguri.", "secure the flag for ${ARG1} seconds": "ține steagul pentru ${ARG1} (de) secunde", - "touch ${ARG1} flags": "atinge ${ARG1} (de) steaguri", + "touch ${ARG1} flags": "atinge ${ARG1} steaguri", "touch 1 flag": "atinge un steag" }, "gameNames": { @@ -1406,8 +1486,9 @@ "Chosen One": "Alesul", "Conquest": "Cucerire", "Death Match": "Meciul Morții", + "Easter Egg Hunt": "Vânătoarea De Ouă", "Elimination": "Eliminare", - "Football": "Fotbal", + "Football": "TouchDown", "Hockey": "Hockey", "Keep Away": "Stai Departe", "King of the Hill": "Regele Dealului", @@ -1421,33 +1502,46 @@ }, "inputDeviceNames": { "Keyboard": "Tastatură", - "Keyboard P2": "Tastatură 2" + "Keyboard P2": "Tastatură P2" }, "languages": { + "Arabic": "Arabă", "Belarussian": "Belarusă", - "Chinese": "Chineză", + "Chinese": "Chineză (Simplificată)", + "ChineseTraditional": "Chineză (Tradițională)", "Croatian": "Croată", "Czech": "Cehă", "Danish": "Daneză", "Dutch": "Olandeză", "English": "Engleză", "Esperanto": "Esperanto", + "Filipino": "Filipineză", "Finnish": "Finlandeză", "French": "Franceză", "German": "Germană", "Gibberish": "Bolboroseală", + "Greek": "Greacă", "Hindi": "Hindi", - "Hungarian": "Ungară", + "Hungarian": "Maghiară", + "Indonesian": "Indoneziană", "Italian": "Italiană", "Japanese": "Japoneză", "Korean": "Coreană", - "Persian": "Persian", + "Persian": "Persană", "Polish": "Poloneză", "Portuguese": "Portugheză", "Romanian": "Română", "Russian": "Rusă", + "Serbian": "Sârbă", + "Slovak": "Slovacă", "Spanish": "Spaniolă", - "Swedish": "Suedeză" + "Swedish": "Suedeză", + "Tamil": "Tamilă", + "Thai": "Thailandeză", + "Turkish": "Turcă", + "Ukrainian": "Ucraineană", + "Venetian": "Venețiană", + "Vietnamese": "Vietnameză" }, "leagueNames": { "Bronze": "Bronz", @@ -1456,26 +1550,26 @@ "Silver": "Argint" }, "mapsNames": { - "Big G": "G mare", - "Bridgit": "Bridgit", - "Courtyard": "Curte", + "Big G": "Marele G", + "Bridgit": "Podul", + "Courtyard": "Curtea", "Crag Castle": "Castelul Crag", - "Doom Shroom": "Shroom-ul Morții", - "Football Stadium": "Stadion de fotbal", + "Doom Shroom": "Ciuperca Morții", + "Football Stadium": "Stadion de TouchDown", "Happy Thoughts": "Amintiri Fericite", "Hockey Stadium": "Stadion de Hockey", "Lake Frigid": "Lacul Înghețat", "Monkey Face": "Față de Maimuță", "Rampage": "Nebunie", - "Roundabout": "Roundabout", + "Roundabout": "Giratorii", "Step Right Up": "Pășește-n sus", "The Pad": "Placa", - "Tip Top": "Tip top", + "Tip Top": "De sus-n jos", "Tower D": "Turnul D", "Zigzag": "Zig zag" }, "playlistNames": { - "Just Epic": "Doar Epic", + "Just Epic": "Doar Epice", "Just Sports": "Doar Sporturi" }, "scoreNames": { @@ -1487,255 +1581,297 @@ "Time Held": "Timp ținut" }, "serverResponses": { - "A code has already been used on this account.": "Un cod s-a folosit deja pe acest cont.", - "Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "Eşti sigur că vrei să conectezi aceste 2 conturi?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nAcest lucru nu poate fi şters!", - "BombSquad Pro unlocked!": "Versiunea BombSquad Pro deblocată!", - "Cheating detected; scores and prizes suspended for ${COUNT} days.": "Trişare detectată; scoruri şi premii suspendate pentru ${COUNT} (de) zile.", - "Daily maximum reached.": "Maxim pe zi ajuns.", + "A code has already been used on this account.": "Un cod a fost deja folosit pe acest cont.", + "A reward has already been given for that address.": "Un premiu a fost deja revendicat cu această adresă IP.", + "Account linking successful!": "Conectarea conturilor a fost reușită!", + "Account unlinking successful!": "Deconectarea contulurilor a fost reușită!", + "Accounts are already linked.": "Conturile sunt deja conectate între ele.", + "Ad view could not be verified.\nPlease be sure you are running an official and up-to-date version of the game.": "Vizualizarea reclamelor nu a putut fi verificată.\nTe rog să fii sigur că ai o versiune oficială și actualizată a jocului.", + "An error has occurred; (${ERROR})": "A intervenit o eroare; (${ERROR})", + "An error has occurred; please contact support. (${ERROR})": "A intervenit o eroare; Te rog să contactezi asistența. (${ERROR})", + "An error has occurred; please contact support@froemling.net.": "A apărut o eroare; te rog să contactezi support@froemling.net.", + "An error has occurred; please try again later.": "O eroare a intervenit; te rog să încerci din nou mai târziu.", + "Are you sure you want to link these accounts?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nThis cannot be undone!": "Eşti sigur că vrei să conectezi aceste 2 conturi între ele?\n\n${ACCOUNT1}\n${ACCOUNT2}\n\nacest lucru nu poate fi reversibil!", + "BombSquad Pro unlocked!": "Versiunea BombSquad Pro a fost deblocată!", + "Can't link 2 accounts of this type.": "Nu se pot conecta 2 conturi de acest fel.", + "Can't link 2 diamond league accounts.": "Nu se pot conecta 2 conturi cu liga de diamant.", + "Can't link; would surpass maximum of ${COUNT} linked accounts.": "Nu se poate conecta; s-ar depăși numărul maxim de ${COUNT} conturi conectate.", + "Cheating detected; scores and prizes suspended for ${COUNT} days.": "Trişare detectată; scorurile şi premiile sunt suspendate pentru ${COUNT} (de) zile.", + "Could not establish a secure connection.": "Nu s-a putut stabili o conexiune sigură.", + "Daily maximum reached.": "Limită Zilnică Atinsă.", "Entering tournament...": "Se intră în campionat...", - "Invalid code.": "Cod greșit.", - "Invalid promo code.": "Cod Promo invalid", + "Invalid code.": "Cod Invalid.", + "Invalid payment; purchase canceled.": "Plată invalidă; achiziționare anulată.", + "Invalid promo code.": "Cod Promo invalid.", "Invalid purchase.": "Achiziționare Invalidă.", - "Max number of playlists reached.": "Număr maxim de liste de redare ajuns.", - "Max number of profiles reached.": "Număr maxim de profile ajuns.", + "Invalid tournament entry; score will be ignored.": "Intrare invalidă în campionat; scorul va fi ignorat.", + "Item unlocked!": "Lucru deblocat!", + "LINKING DENIED. ${ACCOUNT} contains\nsignificant data that would ALL BE LOST.\nYou can link in the opposite order if you'd like\n(and lose THIS account's data instead)": "CONECTARE ÎNTRE CONTURI RESPINSĂ.Contul ${ACCOUNT} conține\ndate semnificative care ar putea FI PIERDUTE PE VECI.\nPoți să conectezi conturile în ordinea opusă acesteia dacă dorești\n(și să pierzi datele ACESTUI cont în locul celuilalt)", + "Link account ${ACCOUNT} to this account?\nAll existing data on ${ACCOUNT} will be lost.\nThis can not be undone. Are you sure?": "Îți legi progresul contului ${ACCOUNT} cu acest cont?\nTot progresul de pe ${ACCOUNT} va fi șters.\nAcest lucru nu poate fi reversibil. Ești sigur?", + "Max number of playlists reached.": "Număr maxim de liste atins.", + "Max number of profiles reached.": "Număr maxim de profile atins.", + "Maximum friend code rewards reached.": "Limita codurilor pentru prieteni atinsă.", "Message is too long.": "Mesajul este prea lung.", + "No servers are available. Please try again soon.": "Niciun server nu este disponibil. Încearcă din nou mai târziu.", "Profile \"${NAME}\" upgraded successfully.": "Profilul \"${NAME}\" a fost îmbunătățit cu succes.", "Profile could not be upgraded.": "Profilul nu a putut fi îmbunătățit.", "Purchase successful!": "Achiziționare reuşită!", - "Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "Ai primit ${COUNT} de bilete pentru conectare.\nRevin-o mâine pentru a primi ${TOMORROW_COUNT}.", + "Received ${COUNT} tickets for signing in.\nCome back tomorrow to receive ${TOMORROW_COUNT}.": "Ai primit ${COUNT} (de) bilete pentru conectare.\nRevino mâine pentru a primi ${TOMORROW_COUNT}.", + "Server functionality is no longer supported in this version of the game;\nPlease update to a newer version.": "Serverele nu mai sunt suportate în această versiune a jocului;\nTe rog să actualizezi jocul la o versiune mai nouă.", "Sorry, there are no uses remaining on this code.": "Scuze, codul nu mai poate fi folosit.", - "Sorry, this code has already been used.": "Scuze, codul acesta s-a folosit deja.", + "Sorry, this code has already been used.": "Scuze, codul acesta a fost folosit deja.", "Sorry, this code has expired.": "Scuze, acest cod a expirat.", "Sorry, this code only works for new accounts.": "Scuze, acest cod merge doar pentru conturile noi.", - "The tournament ended before you finished.": "Campionatul s-a sfârşit înainte să termini.", - "This code cannot be used on the account that created it.": "Acest cod nu poate fi folosit de contul care l-a creat.", - "This requires version ${VERSION} or newer.": "Acest lucru are nevoie de versiunea ${VERSION} sau mai nouă.", - "Would you like to link your device account to this one?\n\nYour device account is ${ACCOUNT1}\nThis account is ${ACCOUNT2}\n\nThis will allow you to keep your existing progress.\nWarning: this cannot be undone!\n": "Ai dori să iți conectezi contul tău de dispozitiv cu acesta?\n\nContul tău de dispozitiv este ${ACCOUNT1}\nAcest cont este ${ACCOUNT2}\n\nAcest lucru iți va salva progresul existent.\nAtenție: acest lucru nu poate fi şters!", + "Still searching for nearby servers; please try again soon.": "Încă se caută servere din apropiere; te rog să încerci din nou într-un moment.", + "Temporarily unavailable; please try again later.": "Nevalabil temporar; te rog să încerci din nou mai târziu.", + "The tournament ended before you finished.": "Campionatul s-a sfârşit înainte să-l termini.", + "This account cannot be unlinked for ${NUM} days.": "Acest cont nu poate fi deconectat timp de ${NUM} (de) zile.", + "This code cannot be used on the account that created it.": "Acest cod nu poate fi folosit pe contul pe care l-a creat.", + "This is currently unavailable; please try again later.": "Nevalabil momentan; te rog să încerci din nou mai târziu.", + "This requires version ${VERSION} or newer.": "Acest lucru are nevoie de versiunea ${VERSION} sau chiar una mai nouă.", + "Tournaments disabled due to rooted device.": "Campionatele sunt dezactivate deoarece dispozitivul este înrădăcinat (rootat).", + "Tournaments require ${VERSION} or newer": "Campionatele sunt valabile de la versiunea ${VERSION} în sus", + "Unlink ${ACCOUNT} from this account?\nAll data on ${ACCOUNT} will be reset.\n(except for achievements in some cases)": "Deconectezi contul ${ACCOUNT} de la acest cont?\nTot progresul de pe ${ACCOUNT} va fi resetat.\n(exceptând realizările în unele cazuri)", + "WARNING: complaints of hacking have been issued against your account.\nAccounts found to be hacking will be banned. Please play fair.": "ADVERTISMENT: Reclamații cum că ai fost acuzat de trișat/hackuit au fost legate de contul tău.\nConturile prinse trișând/hackuind vor fi restricționate. Te rog să joci cinstit.", + "Would you like to link your device account to this one?\n\nYour device account is ${ACCOUNT1}\nThis account is ${ACCOUNT2}\n\nThis will allow you to keep your existing progress.\nWarning: this cannot be undone!\n": "Ai dori să îți conectezi contul tău de pe dispozitiv cu acesta?\n\nContul tău de pe dispozitiv este ${ACCOUNT1}\nAcest cont este ${ACCOUNT2}\n\nAcest lucru îți va salva progresul existent.\nAtenție: acest lucru nu poate fi reversibil!", "You already own this!": "Deja ai acest lucru!", + "You can join in ${COUNT} seconds.": "Poți reintra în ${COUNT} secunde.", "You don't have enough tickets for this!": "Nu ai destule bilete pentru acest lucru!", - "You got ${COUNT} tickets!": "Ai primit ${COUNT} de bilete!", - "You got a ${ITEM}!": "Ai primit un/o ${ITEM}!", - "You have been promoted to a new league; congratulations!": "Ai fost promovat într-o ligă noua; felicitări!", + "You don't own that.": "Nu ai cumpărat asta.", + "You got ${COUNT} tickets!": "Ai primit ${COUNT} (de) bilete!", + "You got a ${ITEM}!": "Ai primit 1 ${ITEM}!", + "You have been promoted to a new league; congratulations!": "Ai fost promovat la o ligă noua; felicitări!", + "You must update to a newer version of the app to do this.": "Trebuie să-ți actualizezi aplicația la o versiune mai nouă pentru a face asta.", + "You must update to the newest version of the game to do this.": "Trebuie să-ți actualizezi jocul la o versiune mai nouă pentru a face asta.", "You must wait a few seconds before entering a new code.": "Va trebui să aştepți câteva secunde înainte să introduci un cod nou.", "You ranked #${RANK} in the last tournament. Thanks for playing!": "Ai avut rankul #${RANK} în ultimul campionat. Mulțumesc pentru participare!", - "Your copy of the game has been modified.\nPlease revert any changes and try again.": "Copia ta de joc a fost modificată.\nTe rog să treci la normal orice schimbâri şi încearcă din nou.", - "Your friend code was used by ${ACCOUNT}": "Codul tau de prieten a fost folosit de ${ACCOUNT}" + "Your account was rejected. Are you signed in?": "Contul tău a fost respins. Ești conectat?", + "Your copy of the game has been modified.\nPlease revert any changes and try again.": "Copia ta de joc a fost modificată.\nTe rog să treci la normal orice schimbare făcută şi să încerci din nou.", + "Your friend code was used by ${ACCOUNT}": "${ACCOUNT} a folosit codul tău de prieten" }, "settingNames": { - "1 Minute": "1 minut", - "1 Second": "o secundă", - "10 Minutes": "10 minute", - "2 Minutes": "2 minute", - "2 Seconds": "2 secunde", - "20 Minutes": "20 minute", - "4 Seconds": "4 secunde", - "5 Minutes": "5 minute", - "8 Seconds": "8 secunde", - "Balance Total Lives": "Balansează nr. de vieți", - "Chosen One Gets Gloves": "Alesul primește mănuși", - "Chosen One Gets Shield": "Alesul primește un scut", + "1 Minute": "Un minut", + "1 Second": "O secundă", + "10 Minutes": "10 Minute", + "2 Minutes": "2 Minute", + "2 Seconds": "2 Secunde", + "20 Minutes": "20 De Minute", + "4 Seconds": "4 Secunde", + "5 Minutes": "5 Minute", + "8 Seconds": "8 Secunde", + "Allow Negative Scores": "Permite Scoruri Negative", + "Balance Total Lives": "Balansează Numărul De Vieți", + "Bomb Spawning": "Spaunarea Bombelor", + "Chosen One Gets Gloves": "Alesul Primește Mănuși", + "Chosen One Gets Shield": "Alesul Primește Un Scut", "Chosen One Time": "Timpul Alesului", - "Enable Impact Bombs": "Permite Bombe de Impact", + "Enable Impact Bombs": "Permite Bombe cu Impact", "Enable Triple Bombs": "Permite Bombe Triple", + "Entire Team Must Finish": "Toată Echipa Ta Trebuie Să Termine", "Epic Mode": "Modul Epic", - "Flag Idle Return Time": "", - "Flag Touch Return Time": "Timpul de returnare a steagului atins", + "Flag Idle Return Time": "Timp Setat Pentru Reapariția Steagurilor", + "Flag Touch Return Time": "Timp Rămas Până la Respaunarea Steagurilor", "Hold Time": "Timp de Ținut", - "Kills to Win Per Player": "Omoruri pentru a câştiga pe jucător", + "Kills to Win Per Player": "Omoruri Pe Echipă/Jucător Pentru a Câștiga", "Laps": "Ture", - "Lives Per Player": "Vieți pe jucător", + "Lives Per Player": "Viețile Jucătorului", "Long": "Lung", "Longer": "Foarte Lung", - "Mine Spawning": "Apar Mine", + "Mine Spawning": "Spaunarea Minelor", "No Mines": "Fără Mine", - "None": "Deloc", + "None": "Niciuna", "Normal": "Normal", - "Respawn Times": "Timp de revenire", - "Score to Win": "Înscrie pentru a câştiga", + "Pro Mode": "Modul Profesionist", + "Respawn Times": "Timp de Revenire", + "Score to Win": "Înscrieri Pentru a Câştiga", "Short": "Scurt", "Shorter": "Foarte Scurt", "Solo Mode": "Mod Solo", "Target Count": "Număr de Ținte", - "Time Limit": "Limită de timp" + "Time Limit": "Limită de Timp" }, "statements": { - "Killing ${NAME} for skipping part of the track!": "${NAME} e mort deoarece a luat o scurtătură!" + "${TEAM} is disqualified because ${PLAYER} left": "Echipa ${TEAM} este descalificată deoarece ${PLAYER} a ieșit", + "Killing ${NAME} for skipping part of the track!": "${NAME} a murit deoarece a luat o scurtătură!", + "Warning to ${NAME}: turbo / button-spamming knocks you out.": "Atenție, ${NAME}: Apăsatul turbo/spamatul butoanelor te pune la pământ." }, "teamNames": { - "Bad Guys": "Tipii răi", + "Bad Guys": "Tipii Răi", "Blue": "Albastru", - "Good Guys": "Tipii buni", + "Good Guys": "Tipii Buni", "Red": "Roșu" }, "tips": { - "A perfectly timed running-jumping-spin-punch can kill in a single hit\nand earn you lifelong respect from your friends.": "O lovitură alergat-sărit-rotit-pumn perfect sincronizată poate omorî\ndintr-o singură lovitură și-ți poate primi respectul prietenilor.", + "A perfectly timed running-jumping-spin-punch can kill in a single hit\nand earn you lifelong respect from your friends.": "O lovitură alergat-sărit-rotit-pumn perfect sincronizată poate omorî\npe cineva dintr-o singură lovitură și-ți poate câștiga respectul prietenilor.", "Always remember to floss.": "Nu uita să te speli pe dinți.", - "Create player profiles for yourself and your friends with\nyour preferred names and appearances instead of using random ones.": "Creează-ți profile de jucător pentru tine şi prietenii tăi cu\nnumele şi caracterele voastre preferate în loc să le folosiți pe cele la nimereală.", - "Curse boxes turn you into a ticking time bomb.\nThe only cure is to quickly grab a health-pack.": "Blestemele te transformă înntr-o bombă cu timp.\nSingurul remediu este de a prinde rapid o trusă de prim-ajutor.", - "Despite their looks, all characters' abilities are identical,\nso just pick whichever one you most closely resemble.": "Înafară de look-ul lor, toate caracterele au abilități identice,\ndeci alegeți unul cu care te asemeni.", - "Don't get too cocky with that energy shield; you can still get yourself thrown off a cliff.": "Nu te împăuna cu scutul ală de energie; tot poți fi aruncat de pe un deal.", - "Don't run all the time. Really. You will fall off cliffs.": "Nu fugi tot timpul. Pe bune. Vei cădea de pe dealuri.", - "Don't spin for too long; you'll become dizzy and fall.": "Nu te învârti prea mult: o să amețești și vei cădea.", - "Hold any button to run. (Trigger buttons work well if you have them)": "Ține apăsat orice buton pentru a fugi. (Butoanele Trigger merg bine şi ele dacă le ai)", - "Hold down any button to run. You'll get places faster\nbut won't turn very well, so watch out for cliffs.": "Ține apăsat orice buton pentru a fugi. Vei ajunge mai repede unde vrei,\ndar nu vei face curba prea bine, deci ai grijă la dealuri.", - "Ice bombs are not very powerful, but they freeze\nwhoever they hit, leaving them vulnerable to shattering.": "Bombele de gheață nu sunt foarte puternice, dar îngheață\norice ating, lăsându-le vulnerabile la spargere.", - "If someone picks you up, punch them and they'll let go.\nThis works in real life too.": "Dacă cineva te ia pe sus, dă-i cu pumnul şi te va lăsa.\nMerge şi în viața reală apropo.", + "Create player profiles for yourself and your friends with\nyour preferred names and appearances instead of using random ones.": "Creează profile de jucător pentru tine şi prietenii tăi cu\nnumele şi caracterele voastre preferate în loc să le folosiți pe cele generate la nimereală.", + "Curse boxes turn you into a ticking time bomb.\nThe only cure is to quickly grab a health-pack.": "Blestemele te transformă înntr-o bombă cu ceas.\nSingurul remediu este de a prinde rapid o trusă de prim-ajutor.", + "Despite their looks, all characters' abilities are identical,\nso just pick whichever one you most closely resemble.": "Înafară de aparențele lor, toate caracterele au abilități identice,\nașa că alegeți unul cu care te asemeni cel mai mult.", + "Don't get too cocky with that energy shield; you can still get yourself thrown off a cliff.": "Nu te împăuna cu scutul ăla de energie; tot poți fi aruncat de pe hartă.", + "Don't run all the time. Really. You will fall off cliffs.": "Nu fugii tot timpul. Pe bune. Vei cădea de pe hărți.", + "Don't spin for too long; you'll become dizzy and fall.": "Nu te învârti prea mult timp; vei ameți și vei cădea la pământ.", + "Hold any button to run. (Trigger buttons work well if you have them)": "Ține apăsat orice buton pentru a fugi. (Butoanele 'Trigger' funcționează bine şi ele dacă le ai)", + "Hold down any button to run. You'll get places faster\nbut won't turn very well, so watch out for cliffs.": "Ține apăsat orice buton pentru a fugi. Vei ajunge mai repede unde vrei,\ndar nu vei flua curba prea bine, așa că ai grijă să nu cazi de pe hărți.", + "Ice bombs are not very powerful, but they freeze\nwhoever they hit, leaving them vulnerable to shattering.": "Bombele de gheață nu sunt foarte puternice, dar îngheață\npe oricine lovesc, lăsând victimele vulnerabile la spargere.", + "If someone picks you up, punch them and they'll let go.\nThis works in real life too.": "Dacă cineva te ia pe sus, dă-i un pumn și te va lăsa jos.\nApropo, merge și în viața reală.", + "If you are short on controllers, install the '${REMOTE_APP_NAME}' app\non your mobile devices to use them as controllers.": "Dacă nu ai destule controllere,instalează aplicația '${REMOTE_APP_NAME}' \npe dispozitivele tale mobile pentru a le folosi drept controllere.", "If you are short on controllers, install the 'BombSquad Remote' app\non your iOS or Android devices to use them as controllers.": "Dacă nu ai destule controllere, instalează 'BombSquad Remote' pe\nun dispozitiv Android sau iOS pentru a-l folosi ca pe un controller.", - "If you get a sticky-bomb stuck to you, jump around and spin in circles. You might\nshake the bomb off, or if nothing else your last moments will be entertaining.": "Dacă ți s-a lipit o bombă lipicoasă de tine, sari și învârte-te în cercuri. S-ar\nputea să scapi... și dacă nu, vei face un spectacol din ultimele tale momente.", - "If you kill an enemy in one hit you get double points for it.": "Dacă omori un inamic dintr-o singură lovitură primești dublu puncte.", - "If you pick up a curse, your only hope for survival is to\nfind a health powerup in the next few seconds.": "Dacă atingi un Blestem, singura ta şansă de viața este să\nprinzi o trusă de prim-ajutor în următoarele câteva secunde.", - "If you stay in one place, you're toast. Run and dodge to survive..": "Dacă stai într-un singur loc, vei fi pâine prăjită. Fugi şi fereşte pentru a supraviețuii..", - "If you've got lots of players coming and going, turn on 'auto-kick-idle-players'\nunder settings in case anyone forgets to leave the game.": "Dacă ai foarte mulți jucători care vin continuu, porneşte 'Dă afară jucătorii care nu fac nimic'\nîn Setări în caz ca cineva uită să iasă din joc.", - "If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "Dacă dispozitivul tău se încăljeşte prea tare sau ai vrea să conservezi baterie,\ndă mai jos opțiunile de \"Vizual\" sau \"Rezoluție\" în Setări->Grafici.", - "If your framerate is choppy, try turning down resolution\nor visuals in the game's graphics settings.": "Dacă jocul rulează mai încet, încearcă să dai mai jos rezoluția \nsau vizualele în setările grafice din joc.", - "In Capture-the-Flag, your own flag must be at your base to score, If the other\nteam is about to score, stealing their flag can be a good way to stop them.": "În Capturează-Steagul, steagul tău trebuie să fie la baza ta pentru a înscrie. Dacă\nechipa opusă e pe cale să înscrie, o opțiune bună pentru ai opri este să le furi steagul.", + "If you get a sticky-bomb stuck to you, jump around and spin in circles. You might\nshake the bomb off, or if nothing else your last moments will be entertaining.": "Dacă o bombă lipicioasă se lipește de tine,sari și rotește-te în cercuri.S-ar putea \nsă scapi de aceasta, în caz contrar vei face un spectacol din ultimele tale momente în viață", + "If you kill an enemy in one hit you get double points for it.": "Dacă omori un inamic dintr-o singură lovitură vei primi puncte duble.", + "If you pick up a curse, your only hope for survival is to\nfind a health powerup in the next few seconds.": "Dacă atingi un Blestem, singura ta şansă de viața este să\nprinzi o trusă de prim-ajutor în următoarele 5 secunde.", + "If you stay in one place, you're toast. Run and dodge to survive..": "Dacă stai într-un singur loc, vei ajunge ca o pâine prăjită. Fugi şi fereşte-te pentru a supraviețui..", + "If you've got lots of players coming and going, turn on 'auto-kick-idle-players'\nunder settings in case anyone forgets to leave the game.": "Dacă sunt foarte mulți jucători care intră și devin inactivi, bifează 'Dă afară jucătorii inactivi'\nîn Setări în caz că cineva uită să iasă din joc.", + "If your device gets too warm or you'd like to conserve battery power,\nturn down \"Visuals\" or \"Resolution\" in Settings->Graphics": "Dacă dispozitivul tău se încălzeşte prea rapid sau ai vrea să-i conservi bateria,\ndu-te în meniul de \"Vizuale\" sau \"Rezoluție\" în Setări->Grafici.", + "If your framerate is choppy, try turning down resolution\nor visuals in the game's graphics settings.": "Dacă jocul rulează mai puțin bine, încearcă să lași mai jos rezoluția \nsau vizualele din setările grafice ale jocului.", + "In Capture-the-Flag, your own flag must be at your base to score, If the other\nteam is about to score, stealing their flag can be a good way to stop them.": "În Capturează-Steagul, steagul tău trebuie să fie la baza ta pentru a înscrie. Dacă\nechipa opusă e pe cale să înscrie, o opțiune bună pentru a-i opri din a face asta este să le furi steagul.", "In hockey, you'll maintain more speed if you turn gradually.": "În Hockey, vei menține mai multă viteză dacă te roteşti când trebuie.", "It's easier to win with a friend or two helping.": "E mai ușor să câștigi cu un prieten sau 2 care te ajută.", - "Jump just as you're throwing to get bombs up to the highest levels.": "Sari fix înainte să arunci pentru a trimite bombele către cele mai înalte niveluri.", + "Jump just as you're throwing to get bombs up to the highest levels.": "Sari fix înainte să arunci pentru a trimite bombele către cele mai înalte nivele.", "Land-mines are a good way to stop speedy enemies.": "Minele sunt folositoare pentru a opri inamicii rapizi.", - "Many things can be picked up and thrown, including other players. Tossing\nyour enemies off cliffs can be an effective and emotionally fulfilling strategy.": "Multe lucruri pot fi ridicate şi aruncate, inclusiv alți jucători. Aruncarea\ninamicilor de pe dealuri poate fi o strategie efectivă şi plină de emoții.", - "No, you can't get up on the ledge. You have to throw bombs.": "Nu, nu te poți urca pe platformă. Trebuie să arunci bombe.", - "Players can join and leave in the middle of most games,\nand you can also plug and unplug controllers on the fly.": "Jucătorii pot intra şi ieşii în mijlocul jocului,\nşi poți şi să conectezi şi deconectezi controllere când vrei.", - "Practice using your momentum to throw bombs more accurately.": "Antrenează-te folosindu-ți momentum-ul pentru a arunca bombe mai corect.", + "Many things can be picked up and thrown, including other players. Tossing\nyour enemies off cliffs can be an effective and emotionally fulfilling strategy.": "Multe lucruri pot fi ridicate şi aruncate, inclusiv și alți jucători. Aruncarea\ninamicilor de pe hărți poate fi o strategie efectivă şi plină de emoții.", + "No, you can't get up on the ledge. You have to throw bombs.": "Nu, nu te poți urca pe platformă. Trebuie să arunci cu bombele.", + "Players can join and leave in the middle of most games,\nand you can also plug and unplug controllers on the fly.": "Jucătorii pot intra şi ieşii în mijlocul unelor jocuri,\nşi mai poți conecta/deconecta controllerele când vrei tu.", + "Practice using your momentum to throw bombs more accurately.": "Antrenează-te folosindu-ți momentum-ul pentru a arunca bombele mai corect.", "Punches do more damage the faster your fists are moving,\nso try running, jumping, and spinning like crazy.": "Pumnii cauzează mai multe daune când te mişti,\ndeci încearcă să fugi, să sari, şi să te învârți ca un nebun.", - "Run back and forth before throwing a bomb\nto 'whiplash' it and throw it farther.": "Fugi în față şi în spate înainte să arunci o bombă\npentru a o învârti şi arunca mai departe.", - "Take out a group of enemies by\nsetting off a bomb near a TNT box.": "Omoară un grupmde inamici printr-o\nbombă lângă o cutie de TNT.", - "The head is the most vulnerable area, so a sticky-bomb\nto the noggin usually means game-over.": "Capul este cea mai vulnerabilă parte, deci o Bombă Lipicioasă\nîn ceafă înseamnă game-over.", - "This level never ends, but a high score here\nwill earn you eternal respect throughout the world.": "Acest nivel nu se termină niciodată, dar un scor mare\niți va aduce respect eternal prin lume.", - "Throw strength is based on the direction you are holding.\nTo toss something gently in front of you, don't hold any direction.": "Puterea aruncării este bazată pe direcția care o ții.\nPentru a arunca ceva în fața ta frumuşel, nu ține nici-o direcție.", - "Tired of the soundtrack? Replace it with your own!\nSee Settings->Audio->Soundtrack": "Eşti săturat de coloana sonoră? Schimbăl cu al tău!\nVezi Setări->Audio->Coloană Sonoră", - "Try 'Cooking off' bombs for a second or two before throwing them.": "Încearcă să 'Prăjeşti' bombele pentru o secundă sau două înainte să le arunci.", - "Try tricking enemies into killing eachother or running off cliffs.": "Încearcă să păcăleşti inamicii să se omoare pe ei înşişi sau sa cadă de pe dealuri.", - "Use the pick-up button to grab the flag < ${PICKUP} >": "Foloseşte butonul Ridică pentru a ridica steagul < ${PICKUP} >", - "Whip back and forth to get more distance on your throws..": "Învârte-te în față şi în spate pentru a avea distanța mai mare la aruncări..", - "You can 'aim' your punches by spinning left or right.\nThis is useful for knocking bad guys off edges or scoring in hockey.": "Poți să dai cu pumnii în stânga sau dreapta dacă te învârți.\nAcest lucru este folositor pentru a jos de pe dealuri tipi răi sau a înscrie în hockey.", - "You can judge when a bomb is going to explode based on the\ncolor of sparks from its fuse: yellow..orange..red..BOOM.": "Poți să îti dai seama când o bombă va exploda dupa culoarea\nscânteilor de pe fitil: galben..portocaliu..roşu..BOOM.", - "You can throw bombs higher if you jump just before throwing.": "Poți arunca bombe mai sus dacă sari fix înainte să arunci.", - "You take damage when you whack your head on things,\nso try to not whack your head on things.": "Iei daune când iți trânteşti capul de lucruri,\ndeci nu-ți trânti capul de lucruri.", + "Run back and forth before throwing a bomb\nto 'whiplash' it and throw it farther.": "Fugi în față şi în spate înainte să arunci o bombă\npentru a învârti-o şi a o arunca mai departe.", + "Take out a group of enemies by\nsetting off a bomb near a TNT box.": "Omoară un grup de inamici cu ajutorul\nunei bombe lângă o cutie cu TNT.", + "The head is the most vulnerable area, so a sticky-bomb\nto the noggin usually means game-over.": "Capul este cea mai vulnerabilă parte a corpului tău, deci o Bombă Lipicioasă\nîn ceafă înseamnă în cele mai multe cazuri game-over.", + "This level never ends, but a high score here\nwill earn you eternal respect throughout the world.": "Acest nivel nu se termină niciodată, dar un scor mare\nîți poate aduce foarte mult respect prin lume.", + "Throw strength is based on the direction you are holding.\nTo toss something gently in front of you, don't hold any direction.": "Puterea aruncării este bazată pe direcția pe care o ții.\nDacă vrei să arunci ceva în fața ta într-un mod gentil, va trebui să nu te miști.", + "Tired of the soundtrack? Replace it with your own!\nSee Settings->Audio->Soundtrack": "Te-ai săturat de muzica originală din joc? Schimb-o cu a ta!\nVezi Setări->Audio->Coloană Sonoră", + "Try 'Cooking off' bombs for a second or two before throwing them.": "Încearcă să ții bombele în mână pentru o secundă sau două înainte să le arunci.", + "Try tricking enemies into killing eachother or running off cliffs.": "Încearcă să păcăleşti inamicii să se omoare între ei sau să cadă de pe hărți.", + "Use the pick-up button to grab the flag < ${PICKUP} >": "Foloseşte butonul de ridicare pentru a ridica steagul < ${PICKUP} >", + "Whip back and forth to get more distance on your throws..": "Mergi în față şi în spate pentru a avea o distanță mai mare la aruncări..", + "You can 'aim' your punches by spinning left or right.\nThis is useful for knocking bad guys off edges or scoring in hockey.": "Poți să dai cu pumnii în stânga sau în dreapta dacă te învârți.\nAcest lucru este folositor pentru a da tipii răi jos de pe dealuri sau pentru a înscrie în hockey.", + "You can judge when a bomb is going to explode based on the\ncolor of sparks from its fuse: yellow..orange..red..BOOM.": "Poți să îți dai seama când o bombă va exploda după culoarea\nscânteilor făcute de fitil: galben..portocaliu..roşu..BOOM.", + "You can throw bombs higher if you jump just before throwing.": "Poți arunca bombe mai sus dacă sari exact înainte să arunci.", + "You take damage when you whack your head on things,\nso try to not whack your head on things.": "Iei daune când îți trânteşti capul de lucruri,\ndeci nu-ți trânti capul de lucruri.", "Your punches do much more damage if you are running or spinning.": "Pumnii tăi dau mai multe daune dacă fugi sau te învârți." } }, "trophiesRequiredText": "Asta necesită măcar ${NUMBER} trofee.", "trophiesText": "Trofee", - "trophiesThisSeasonText": "Trofeele acestui Sezon", + "trophiesThisSeasonText": "Trofeele Din Acest Sezon", "tutorial": { - "cpuBenchmarkText": "Rulând tutorial la viteze ridiculoase (în principal testează viteza CPU)", + "cpuBenchmarkText": "Se rulează tutorialul la viteze ridicole (în principal testează viteza CPU-ului)", "phrase01Text": "Salut!", "phrase02Text": "Bun Venit în ${APP_NAME}!", "phrase03Text": "Uite niște sfaturi pentru a-ți controla caracterul:", "phrase04Text": "Multe lucruri din ${APP_NAME} sunt bazate pe FIZICĂ.", "phrase05Text": "De exemplu, când dai cu pumnul...", "phrase06Text": "...daunele sunt bazate pe viteza pumnilor tăi.", - "phrase07Text": "Vezi? Nu ne mișcăm, deci ${NAME} de abia dacă a simțit ceva.", - "phrase08Text": "Acum hai să sărim și sa ne rotim pentru a avea viteză mai mare.", - "phrase09Text": "Aha, e mai bine.", + "phrase07Text": "Vezi? Nu ne mișcăm, deci ${NAME} de-abia a simțit ceva.", + "phrase08Text": "Acum hai să sărim și să ne rotim pentru a avea viteză mai mare.", + "phrase09Text": "Aha, așa mai merge.", "phrase10Text": "De asemenea, și alergatul ajută.", - "phrase11Text": "Ține apăsat orice buton pentru a alerga.", - "phrase12Text": "Pentru pumni super tari, încearcă sa te rotești și să fugi.", - "phrase13Text": "Ups; scuze pentru aia, ${NAME}.", - "phrase14Text": "Poți ridica obiecte ca și steaguri... sau ${NAME}", + "phrase11Text": "Ține apăsat ORICE buton pentru a alerga.", + "phrase12Text": "Pentru pumni super puternici, încearcă să te rotești și să fugi.", + "phrase13Text": "Ups; scuze pentru asta, ${NAME}.", + "phrase14Text": "Poți ridica și arunca obiecte cum ar fi steaguri... sau îl poți arunca pe ${NAME}.", "phrase15Text": "În final, sunt bombele.", "phrase16Text": "Aruncatul lor are nevoie de antrenament.", - "phrase17Text": "Au! Nu a fost chiar o aruncare bună.", + "phrase17Text": "Au! Nu a fost o aruncare chiar bună.", "phrase18Text": "Mișcatul te ajută să arunci mai departe.", - "phrase19Text": "Săritul te ajută să arunci mai înalt.", - "phrase20Text": "Învârte bombele pentru a arunca și mai departe.", - "phrase21Text": "Sincronizarea bombelor poate fi complicată.", - "phrase22Text": "Fir-ar.", - "phrase23Text": "Încearcă sa-ți arzi fitilul pentru un moment.", + "phrase19Text": "Săritul te ajută să arunci mai sus.", + "phrase20Text": "Iar învârtirea lor te ajută să le arunci mult mai departe.", + "phrase21Text": "Cronometrarea bombelor poate fi complicată.", + "phrase22Text": "Fir-ar să fie.", + "phrase23Text": "Încearcă să lași fitilul să ardă pentru un moment.", "phrase24Text": "Ura! Bine ars.", "phrase25Text": "Păi, cam asta-i tot.", - "phrase26Text": "Acu ia-i, tigrule!", - "phrase27Text": "Ține-ți minte antrenamentul și vei supraviețui!", - "phrase28Text": "...poate...", - "phrase29Text": "Noroc!", + "phrase26Text": "Acu' ia-i, tigrule!", + "phrase27Text": "Ține minte antrenamentul și vei supraviețui!", + "phrase28Text": "...probabil...", + "phrase29Text": "Mult Noroc!", "randomName1Text": "Vasile", - "randomName2Text": "Virgilian", + "randomName2Text": "David", "randomName3Text": "Florin", - "randomName4Text": "Mircea", - "randomName5Text": "Filipin", - "skipConfirmText": "Sigur treci peste tutorial? Apasă pentru a confirma.", - "skipVoteCountText": "${COUNT}/${TOTAL} voturi pentru a trece", + "randomName4Text": "Marius", + "randomName5Text": "Ștefan", + "skipConfirmText": "Sigur vrei să treci peste tutorial? Apasă din nou orice buton pentru a confirma.", + "skipVoteCountText": "${COUNT}/${TOTAL} voturi pentru a trece peste", "skippingText": "Se trece peste tutorial...", - "toSkipPressAnythingText": "(apasă orice pentru a trece peste tutorial)" + "toSkipPressAnythingText": "(apasă orice buton pentru a trece peste tutorial)" }, "twoKillText": "DUBLU OMOR!", "unavailableText": "indisponibil", "unconfiguredControllerDetectedText": "Controller neconfigurat detectat:", - "unlockThisInTheStoreText": "Aceasta trebuie deblocată în magazin.", - "unlockThisProfilesText": "Că să creezi mai mult de ${NUM} profile, îți trebuie:", - "unlockThisText": "Pentru a debloca acest lucru, ai nevoie de:", - "unsupportedHardwareText": "Scuze, acest hardware nu este suportat de acest build al jocului.", + "unlockThisInTheStoreText": "Acest lucru trebuie deblocat din magazin.", + "unlockThisProfilesText": "Că să creezi mai mult de ${NUM} profile, va trebui să ai:", + "unlockThisText": "Pentru a debloca acest lucru, vei avea nevoie de:", + "unsupportedHardwareText": "Scuze, acest hardware nu este suportat de această versiune a jocului.", "upFirstText": "Primul joc:", - "upNextText": "În următorul joc cu nr ${COUNT}:", + "upNextText": "Următorul joc cu numărul ${COUNT} este:", "updatingAccountText": "Se îmbunătățeşte contul tău...", "upgradeText": "Îmbunătățeşte", "upgradeToPlayText": "Deblochează \"${PRO}\" în magazinul din joc pentru a juca această hartă.", "useDefaultText": "Folosește setările prestabilite", "usesExternalControllerText": "Acest joc folosește un controller extern ca dispozitiv de intrare.", - "usingItunesText": "Se folosește iTunes pentru coloana sonoră...", + "usingItunesText": "Se folosește Aplicația de Muzică pentru coloana sonoră...", "usingItunesTurnRepeatAndShuffleOnText": "Fii sigur(ă) că shuffle e activat și repeat e pus pe ALL în iTunes.", - "validatingTestBuildText": "Se validează versiune test...", + "validatingTestBuildText": "Se Validează Versiunea De Test...", "victoryText": "Victorie!", - "voteDelayText": "Poți începe alt vot peste ${NUMBER} secunde", - "votedAlreadyText": "Deja ai votat", + "voteDelayText": "Poți începe alt vot peste ${NUMBER} (de) secunde", + "voteInProgressText": "Un vot este deja în progres.", + "votedAlreadyText": "Ai votat deja", "votesNeededText": "${NUMBER} voturi necesare", - "vsText": "vs.", - "waitingForHostText": "(se așteaptă pentru ca ${HOST} să continue)", - "waitingForPlayersText": "se așteaptă să intre jucători...", - "waitingInLineText": "Așteaptă la coadă (grupul este plin)...", - "watchAVideoText": "Urmărește un Video", - "watchAnAdText": "Vezi o reclamă", + "vsText": "versus", + "waitingForHostText": "(așteaptă ca ${HOST} să continue)", + "waitingForPlayersText": "se așteaptă pentru jucători noi...", + "waitingInLineText": "Așteaptă la coadă (server-ul este plin)...", + "watchAVideoText": "Uită-te la o reclamă", + "watchAnAdText": "Uită-te la o Reclamă", "watchWindow": { - "deleteConfirmText": "Sigur ștergi \"${REPLAY}\"?", - "deleteReplayButtonText": "Șterge\nReluare", + "deleteConfirmText": "Sigur vrei să ștergi reluarea \"${REPLAY}\"?", + "deleteReplayButtonText": "Șterge\nReluarea", "myReplaysText": "Reluările mele", - "noReplaySelectedErrorText": "Nicio reluare selectată", - "playbackSpeedText": "Viteza de redare: ${SPEED}", - "renameReplayButtonText": "Redenumește\nReluare", + "noReplaySelectedErrorText": "Nicio rReluare Selectată", + "playbackSpeedText": "Viteză de redare: ${SPEED}", + "renameReplayButtonText": "Redenumește\nReluarea", "renameReplayText": "Redenumește \"${REPLAY}\" în:", "renameText": "Redenumește", "replayDeleteErrorText": "Eroare la ștergerea reluării.", - "replayNameText": "Nume reluare", - "replayRenameErrorAlreadyExistsText": "Nume reluare deja existent.", - "replayRenameErrorInvalidName": "Nu se poate redenumi; nume invalid.", + "replayNameText": "Numele reluării", + "replayRenameErrorAlreadyExistsText": "O reluare cu acel nume deja există.", + "replayRenameErrorInvalidName": "Nu se poate redenumi reluarea; numele este invalid.", "replayRenameErrorText": "Eroare la redenumirea reluării.", - "sharedReplaysText": "Reluări împărțite", + "sharedReplaysText": "Reluări împărțite cu alții", "titleText": "Vizionează", - "watchReplayButtonText": "Vezi\nReluare" + "watchReplayButtonText": "Vezi\nReluarea" }, "waveText": "Val", "wellSureText": "Sigur!", "wiimoteLicenseWindow": { - "titleText": "Copyright Darwiinmote" + "titleText": "Copyright de către DarwiinRemote" }, "wiimoteListenWindow": { - "listeningText": "Se ascultă după Wiimote-uri...", - "pressText": "Apasă butoanele 1 și 2 de pe wiimote simultan.", - "pressText2": "Pe Wiimote-urile noi cu Motion Plus, apasă butonul roșu 'sync' de pe spate.", + "listeningText": "Se ascultă pentru Wiimote-uri...", + "pressText": "Apasă butoanele 1 și 2 de pe wiimote în același timp.", + "pressText2": "Pe Wiimote-urile noi cu Motion Plus, apasă butonul roșu 'sync' de pe spatele acestora.", "pressTextScale": 1.0 }, "wiimoteSetupWindow": { - "copyrightText": "Copyright DarwiinRemote", + "copyrightText": "Copyright de către DarwiinRemote", "listenText": "Ascultă", - "macInstructionsText": "Asigură-te că Wii-ul e închis și Bluetooth e activat\npe Mac, apoi apasă 'Listen'. Suportul wiimote e cam\nslab, deci s-ar putea să trebuiască să încerci de câteva\nori până să meargă.\n\nBluetooth ar trebui să permită până la 7 dispozitive conectate,\nînsă acest număr poate varia.\n\nBombSquad suportă Wiimote-urile și Nunchuck-urile originale\nși controllerul clasic.\nNoul Wii Remote Plus funcționează și el,\nînsă fără atașamente.", - "thanksText": "Mulțumim echipei Darwiinmote pentru\na face asta posibil.", - "titleText": "Setări Wiimote" + "macInstructionsText": "Asigură-te că Wii-ul tău este închis și Bluetooth-ul este activat\npe Mac, apoi apasă pe 'Listen'. Suportul Wiimote e cam\nslab, deci s-ar putea să fie nevoie să încerci de câteva\nori până să meargă.\n\nBluetooth-ul ar trebui să permită până la 7 dispozitive conectate,\nînsă acest număr poate varia de la un dispozitiv la altul.\n\nBombSquad suportă Wiimote-urile, Nunchuck-urile originale\nși Controllerul Clasic.\nNoul Wii Remote Plus funcționează și el,\nînsă fără atașamente.", + "thanksText": "Multe mulțumiri către echipa DarwiinRemote pentru\ncă au făcut acest lucru posibil.", + "titleText": "Setarea Wiimote-ului" }, "winsPlayerText": "${NAME} Câștigă!", "winsTeamText": "${NAME} Câștigă!", - "winsText": "${NAME} câștigă!", - "worldScoresUnavailableText": "Scor global indisponibil.", - "worldsBestScoresText": "Top scoruri mondial", - "worldsBestTimesText": "Top timpi mondial", + "winsText": "${NAME} Câștigă!", + "worldScoresUnavailableText": "Scorurile globale sunt indisponibile.", + "worldsBestScoresText": "Top Scoruri Mondiale", + "worldsBestTimesText": "Top Timpi Mondiali", "xbox360ControllersWindow": { - "getDriverText": "Instaleaza driver-ul.", - "macInstructions2Text": "Pentru a folosi controllere fără fir, vei avea nevoie de un receptor\ncare vine cu pachetul 'Xbox 360 Wireless Controller for Windows'.\nFiecare receptor te lasă să conectezi până la 4 controllere.\n\nImportant: Receptoare third-party nu vor funcționa cu acest driver;\nAsigură-te că pe receptor scrie 'Microsoft', nu 'XBOX 360'.\nMicrosoft nu mai vinde acestea separat, deci va trebui să iei unul\nîmpreună cu controllerul sau de pe un site ca ebay.\n\nDacă ai găsit acest mesaj folositor, consideră să donezi programatorului\ndriverului pe site-ul lui.", - "macInstructionsText": "Pentru a folosi controalele Xbox 360, trebuie sa instalezi \ndriver-ul de Mac disponibil in link-ul de mai jos. \nFunctioneaza pentru controalele cu si fara fir.", - "ouyaInstructionsText": "Pentru a folosi controllere X-Box 360 cu fir, pur și simplu\nconectează-le la un port USB. Poți folosi un USB-hub pentru a\nconecta mai multe controllere.\n\nPentru a folosi controllere fără fir vei avea nevoie de un receptor\nwireless, valabil ca parte a pachetului \"Xbox 360 wireless controller\nfor Windows\" sau vândut separat. Fiecare receptor intră într-un port\nUSB și te lasă să conectezi până la 4 controllere.", - "titleText": "Folosind controllere XBox 360 cu ${APP_NAME}:" + "getDriverText": "Instalează Driver-ul.", + "macInstructions2Text": "Pentru a folosi controllerele fără fir, vei avea nevoie de un receptor\ncare vine cu pachetul 'Xbox 360 Wireless Controller for Windows'.\nFiecare receptor te lasă să conectezi până la 4 controllere.\n\nImportant: Receptoare de tip 3rd-party nu vor funcționa cu acest driver;\nAsigură-te că pe receptor scrie 'Microsoft', nu 'XBOX 360'.\nMicrosoft nu mai le vinde separat, deci va trebui să iei unul\nîmpreună cu controllerul sau de pe un site, cum ar fi Ebay.\n\nDacă ai găsit acest mesaj folositor, consideră faptul să-i donezi programatorului\ndriverului pe site-ul lui.", + "macInstructionsText": "Pentru a folosi controllere de Xbox 360, va trebui să instalezi \ndriver-ul pentru Mac disponibil din link-ul de mai jos. \nFuncționează pentru controalele cu/fără fir.", + "ouyaInstructionsText": "Pentru a folosi controllere de Xbox 360 cu fir, pur și simplu\nconectează-le la un port USB. Poți folosi un USB-hub pentru a\nconecta mai multe controllere.\n\nPentru a folosi controllere fără fir vei avea nevoie de un receptor\nwireless, valabil ca parte a pachetului \"Xbox 360 wireless controller\nfor Windows\" sau vândut separat. Fiecare receptor intră într-un port\nUSB și te lasă să conectezi până la 4 controllere.", + "titleText": "Se folosesc controllere de Xbox 360 cu ${APP_NAME}:" }, "yesAllowText": "Da, Permite!", - "yourBestScoresText": "Top Scor", - "yourBestTimesText": "Top Timpi" + "yourBestScoresText": "Cele Mai Bune Scoruri Ale Tale", + "yourBestTimesText": "Cei Mai Buni Timpi Ai Tăi" } \ No newline at end of file diff --git a/dist/ba_data/data/languages/russian.json b/dist/ba_data/data/languages/russian.json index d9977fe..58ec990 100644 --- a/dist/ba_data/data/languages/russian.json +++ b/dist/ba_data/data/languages/russian.json @@ -26,11 +26,13 @@ "signInInfoText": "Войдите в аккаунт, чтобы собирать билеты, \nсоревноваться онлайн и делиться успехами.", "signInText": "Войти", "signInWithDeviceInfoText": "(стандартный аккаунт только для этого устройства)", - "signInWithDeviceText": "Войти с аккаунта устройства", + "signInWithDeviceText": "Войти через аккаунт устройства", "signInWithGameCircleText": "Войти через Game Circle", "signInWithGooglePlayText": "Войти через Google Play", "signInWithTestAccountInfoText": "(устаревший тип аккаунта; в дальнейшем используйте аккаунт устройства)", "signInWithTestAccountText": "Войти через тестовый аккаунт", + "signInWithV2InfoText": "(аккаунт, который работает на всех платформах)", + "signInWithV2Text": "Войти через аккаунт BombSquad", "signOutText": "Выйти", "signingInText": "Вход...", "signingOutText": "Выход...", @@ -41,6 +43,7 @@ "titleText": "Аккаунт", "unlinkAccountsInstructionsText": "Выберите аккаунт, который хотите отвязать", "unlinkAccountsText": "Отвязать аккаунты", + "v2LinkInstructionsText": "Используйте эту ссылку чтобы создать аккаунт или войти", "viaAccount": "(через аккаунт ${NAME})", "youAreLoggedInAsText": "Вы зашли как:", "youAreSignedInAsText": "Вы вошли как:" @@ -947,8 +950,8 @@ "invitationsSentText": "Отправлено ${COUNT} приглашений.", "joinedPartyInstructionsText": "Кто-то вошел в ваше лобби.\nНажмите 'Играть' чтобы начать игру.", "keyboardText": "Клавиатура", - "kickIdlePlayersKickedText": "${NAME} выкинут за бездействие.", - "kickIdlePlayersWarning1Text": "${NAME} будет выкинут через ${COUNT} секунд при бездействии.", + "kickIdlePlayersKickedText": "${NAME} исключён за бездействие.", + "kickIdlePlayersWarning1Text": "${NAME} будет исключён через ${COUNT} секунд при бездействии.", "kickIdlePlayersWarning2Text": "(это можно выключить в Настройки -> Дополнительно)", "leftGameText": "Покинул '${NAME}'.", "leftPartyText": "Вышел из лобби ${NAME}.", @@ -1198,7 +1201,7 @@ "purchasingText": "Покупка...", "quitGameText": "Выйти из ${APP_NAME}?", "quittingIn5SecondsText": "Выход через 5 секунд...", - "randomPlayerNamesText": "Дима, Кузя, Вован, Маха, Русский, Какуля, Бибер, Борька, Няшка, Толян, Ержан", + "randomPlayerNamesText": "Дима, Кузя, Вован, Маха, Русский, Какуля, Бибер, Борька, Няшка, Толян, Ержан, Дибисяра, Вася, Морген, Серёга, Ваня, Кеша, Жорик, Стёпа, Эдгар, Циган", "randomText": "Случайный", "rankText": "Ранг", "ratingText": "Рейтинг", @@ -1583,6 +1586,7 @@ "Dutch": "Голландский", "English": "Английский", "Esperanto": "Эсперанто", + "Filipino": "Филипинский", "Finnish": "Финский", "French": "Французский", "German": "Немецкий", @@ -1603,6 +1607,7 @@ "Slovak": "Словацкий", "Spanish": "Испанский", "Swedish": "Шведский", + "Tamil": "Тамильский", "Thai": "Тайский", "Turkish": "Турецкий", "Ukrainian": "Украинский", diff --git a/dist/ba_data/data/languages/serbian.json b/dist/ba_data/data/languages/serbian.json index a3d1a89..4d11265 100644 --- a/dist/ba_data/data/languages/serbian.json +++ b/dist/ba_data/data/languages/serbian.json @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "Пријави се преко Гугл Плеја", "signInWithTestAccountInfoText": "(налог за тестирање нових ствари које ће ускоро изаћи)", "signInWithTestAccountText": "Пријави се са тест профилом", + "signInWithV2InfoText": "(налог који функционише на свим платформама)", + "signInWithV2Text": "Улогуј се помоћу Bombsquad налога", "signOutText": "Одјави се", "signingInText": "Пријављивање...", "signingOutText": "Одјављивање...", @@ -38,6 +40,7 @@ "titleText": "Налог", "unlinkAccountsInstructionsText": "Изабери налог за раздвајање", "unlinkAccountsText": "Раздвоји налоге", + "v2LinkInstructionsText": "Искористи овај линк да направиш налог или да се улогујеш.", "viaAccount": "(преко налога ${NAME})", "youAreSignedInAsText": "Пријављен си као:" }, @@ -498,6 +501,7 @@ "yourPowerRankingText": "Твој ранк:" }, "copyOfText": "Копирај \"${NAME}\"", + "copyText": "Копирај", "createEditPlayerText": "<Направи/измени играча>", "createText": "Направи", "creditsWindow": { @@ -1508,6 +1512,7 @@ "Dutch": "Холандски", "English": "Енглески", "Esperanto": "Есперантски", + "Filipino": "филипински", "Finnish": "Фински", "French": "Француски", "German": "Немачки", @@ -1528,6 +1533,7 @@ "Slovak": "Словачки", "Spanish": "Шпански", "Swedish": "Шведски", + "Tamil": "тамилски", "Thai": "Тхаи", "Turkish": "Турски", "Ukrainian": "Украјински", diff --git a/dist/ba_data/data/languages/slovak.json b/dist/ba_data/data/languages/slovak.json index 8e322ce..7cb7173 100644 --- a/dist/ba_data/data/languages/slovak.json +++ b/dist/ba_data/data/languages/slovak.json @@ -30,6 +30,8 @@ "signInWithGooglePlayText": "Príhlásit sa s Google Play", "signInWithTestAccountInfoText": "(starý typ účtu; v budúcnosti používajte účty zariadení)", "signInWithTestAccountText": "Prihlásit sa s testovacím účtom", + "signInWithV2InfoText": "(účet, ktorý funguje na všetkých platformách)", + "signInWithV2Text": "Prihláste sa pomocou účtu BombSquad", "signOutText": "Odhlasujem", "signingInText": "Prihlasujem", "signingOutText": "Odhlasujem", @@ -39,6 +41,7 @@ "titleText": "Konto", "unlinkAccountsInstructionsText": "Vyberte účet, s ktorým chcete zrušiť prepojenie", "unlinkAccountsText": "Zrušiť prepojenie účtov", + "v2LinkInstructionsText": "Pomocou tohto odkazu si vytvorte účet alebo sa prihláste.", "viaAccount": "(cez účet ${NAME})", "youAreLoggedInAsText": "Si prihlásený ako:", "youAreSignedInAsText": "Si prihlásený ako:" @@ -498,6 +501,7 @@ "yourPowerRankingText": "Tvoje Umiestnenie:" }, "copyOfText": "${NAME} Kópia", + "copyText": "Kopírovať", "createEditPlayerText": "", "createText": "Vytvoriť", "creditsWindow": { @@ -1498,6 +1502,7 @@ "Dutch": "Holandčina", "English": "Angličtina", "Esperanto": "Esperanto", + "Filipino": "Filipínsky", "Finnish": "Fínčina", "French": "Francúžtina", "German": "Nemčina", @@ -1518,6 +1523,7 @@ "Slovak": "Slovenčina", "Spanish": "Španielčina", "Swedish": "Švédčina", + "Tamil": "Tamilčina", "Thai": "Thajské", "Turkish": "Turečtina", "Ukrainian": "Ukrainčina", diff --git a/dist/ba_data/data/languages/spanish.json b/dist/ba_data/data/languages/spanish.json index cee3401..35859f4 100644 --- a/dist/ba_data/data/languages/spanish.json +++ b/dist/ba_data/data/languages/spanish.json @@ -1,12 +1,12 @@ { "accountSettingsWindow": { - "accountNameRules": "Los nombres no deben contener emoticonos o caracteres especiales", + "accountNameRules": "Los nombres no deben contener emojis o caracteres especiales", "accountProfileText": "(Perfil de la cuenta)", "accountsText": "Cuentas", "achievementProgressText": "Logros: ${COUNT} de ${TOTAL}", "campaignProgressText": "Progreso de campaña [Dificil]: ${PROGRESS}", "changeOncePerSeason": "Solamente puedes cambiarlo una vez por temporada.", - "changeOncePerSeasonError": "Debes esperar hasta la siguiente temporada para cambiarlo de nuevo (${NUM} días)", + "changeOncePerSeasonError": "Debes esperar hasta la siguiente temporada para cambiarlo de nuevo (en ${NUM} día/s)", "customName": "Nombre personalizado", "deviceSpecificAccountText": "Actualmente usando una cuenta específica de dispositivo: ${NAME}", "linkAccountsEnterCodeText": "Registrar Código", @@ -21,7 +21,7 @@ "resetProgressConfirmNoAchievementsText": "Esto reiniciará tu progreso en el modo\ncooperativo y tus puntajes (A excepción de tus tickets).\nNo podrás recuperar los cambios. ¿Estás seguro?", "resetProgressConfirmText": "Esto reiniciará tus logros, récords\ny progreso en el modo cooperativo.\nLos cambios no se pueden deshacer.\n¿Estás seguro?", "resetProgressText": "Reiniciar progreso", - "setAccountName": "Establecer nombre de cuenta", + "setAccountName": "Establecer nombre de la cuenta", "setAccountNameDesc": "Selecciona el nombre a mostrar para tu cuenta. \nPuedes usar el nombre de tu cuenta asociada\no crear un nombre personalizado.", "signInInfoText": "Inicia sesión para obtener tickets, competir en línea\ny compartir tu progreso en otras plataformas.", "signInText": "Iniciar sesión", @@ -29,8 +29,10 @@ "signInWithDeviceText": "Iniciar sesión con cuenta del dispositivo", "signInWithGameCircleText": "Iniciar sesión con Game Circle", "signInWithGooglePlayText": "Iniciar sesión con Google Play", - "signInWithTestAccountInfoText": "(Cuenta de herencia, usa la cuenta del dispositivo para avanzar)", + "signInWithTestAccountInfoText": "(Cuenta de prueba, usa la cuenta del dispositivo para avanzar)", "signInWithTestAccountText": "Registrarse con una Cuenta de Prueba", + "signInWithV2InfoText": "(una cuenta que funciona en todas las plataformas)", + "signInWithV2Text": "Inicie cesión con una cuenta de bosquad", "signOutText": "Cerrar Sesión", "signingInText": "Iniciando sesión...", "signingOutText": "Cerrando sesión...", @@ -41,6 +43,7 @@ "titleText": "Cuenta", "unlinkAccountsInstructionsText": "Selecciona una cuenta para dejar de enlazar con ella", "unlinkAccountsText": "Desenlazar cuentas.", + "v2LinkInstructionsText": "Usa este encale para crearte una cuenta o para iniciar sesión", "viaAccount": "(por cuenta ${NAME})", "youAreLoggedInAsText": "Estás conectado como:", "youAreSignedInAsText": "Has iniciado sesión como:" @@ -49,15 +52,15 @@ "achievementText": "Logro", "achievements": { "Boom Goes the Dynamite": { - "description": "Elimina 3 enemigos con TNT", - "descriptionComplete": "Eliminaste a 3 enemigos con TNT", - "descriptionFull": "Elimina 3 enemigos con TNT en ${LEVEL}", - "descriptionFullComplete": "Eliminaste 3 enemigos con TNT en ${LEVEL}", + "description": "Elimina 3 enemigos con una caja de TNT", + "descriptionComplete": "Eliminaste a 3 enemigos con una caja de TNT", + "descriptionFull": "Elimina 3 enemigos con una caja de TNT en ${LEVEL}", + "descriptionFullComplete": "Eliminaste 3 enemigos con una caja de TNT en ${LEVEL}", "name": "La dinamita hace Boom!" }, "Boxer": { "description": "Gana sin usar bombas", - "descriptionComplete": "Ganaste sin usar bombas", + "descriptionComplete": "Ganaste sin usar ninguna bomba", "descriptionFull": "Completa ${LEVEL} sin usar bombas", "descriptionFullComplete": "Completaste ${LEVEL} sin usar bombas", "name": "Boxeador" @@ -68,7 +71,7 @@ "name": "Juego Doble" }, "Flawless Victory": { - "description": "Gana sin ser golpeado", + "description": "Gana sin haber recibido ningún golpe", "descriptionComplete": "Ganaste sin ser golpeado", "descriptionFull": "Gana ${LEVEL} sin ser golpeado", "descriptionFullComplete": "Ganaste ${LEVEL} sin ser golpeado", @@ -1250,7 +1253,7 @@ "start": "Empezar", "version_mismatch": "Las versiones no coinciden.\nAsegurate que BombSquad y BombSquad Remote\nestán actuizados e intenta de nuevo." }, - "removeInGameAdsText": "Desbloquea \"${PRO}\" en la tienda para remover la publicidad del juego.", + "removeInGameAdsText": "Desbloquea \"${PRO}\" en la tienda para quitar la publicidad del juego.", "renameText": "Renombrar", "replayEndText": "Terminar Repetición", "replayNameDefaultText": "Repetición Último Juego", @@ -1598,6 +1601,7 @@ "Dutch": "Holandés", "English": "Inglés", "Esperanto": "Esperanto", + "Filipino": "filipino", "Finnish": "Finlandés", "French": "Francés", "German": "Alemán", @@ -1905,7 +1909,7 @@ "voteDelayText": "No puedes iniciar otra votación por ${NUMBER} segundos.", "voteInProgressText": "Ya hay una votación en progreso.", "votedAlreadyText": "Ya has votado.", - "votesNeededText": "Requiere ${NUMBER} votos", + "votesNeededText": "Se requiere ${NUMBER} votos", "vsText": "vs.", "waitingForHostText": "(esperando a que ${HOST} continúe)", "waitingForLocalPlayersText": "Esperando jugadores locales...", @@ -1956,7 +1960,7 @@ "winsPlayerText": "¡${NAME} Gana!", "winsTeamText": "¡${NAME} Gana!!", "winsText": "¡${NAME} Gana!", - "worldScoresUnavailableText": "Puntuaciones mundiales no disponibles.", + "worldScoresUnavailableText": "Puntuaciones globales no disponibles.", "worldsBestScoresText": "Mejores puntuaciones Mundiales", "worldsBestTimesText": "Mejores tiempos Mundiales", "xbox360ControllersWindow": { @@ -1965,7 +1969,7 @@ "macInstructions2TextScale": 0.76, "macInstructionsText": "Para usar controles de Xbox 360, necesitarás instalar\nel controlador para Mac disponible en el siguiente enlace.\nFunciona con controles con cable e inalámbricos.", "macInstructionsTextScale": 0.8, - "ouyaInstructionsText": "Para usar controles con cable de Xbox 360 con BombSquad, simplemente\nconéctalos al puerto USB de tu dispositivo. Puedes usar un concentrador USB\npara conectar múltiples controles.\n\nPara usar controles inalámbricos, necesitarás un receptor inalámbrico,\ndisponible como parte del paquete “Xbox 360 wireless Controller for\nWindows”, o vendido por separado. Cada receptor se conecta a un puerto\nUSB y permite que conectes hasta cuatro controles inalámbricos.", + "ouyaInstructionsText": "Para usar controles con cable de Xbox 360 con BombSquad, simplemente\nconéctalos al puerto USB de tu dispositivo. Puedes usar un conector USB\npara conectar múltiples controles.\n\nPara usar controles inalámbricos, necesitarás un receptor inalámbrico,\ndisponible como parte del paquete “Xbox 360 wireless Controller for\nWindows”, o vendido por separado. Cada receptor se conecta a un puerto\nUSB y permite que conectes hasta cuatro controles inalámbricos.", "ouyaInstructionsTextScale": 0.8, "titleText": "Controles de Xbox 360 con ${APP_NAME}:" }, diff --git a/dist/ba_data/data/languages/swedish.json b/dist/ba_data/data/languages/swedish.json index eab13e6..5c08754 100644 --- a/dist/ba_data/data/languages/swedish.json +++ b/dist/ba_data/data/languages/swedish.json @@ -30,6 +30,8 @@ "signInWithGooglePlayText": "Logga in med Google Play", "signInWithTestAccountInfoText": "(allmän konto typ; använd enhets konton för att fortsätta)", "signInWithTestAccountText": "Logga in med ett testkonto", + "signInWithV2InfoText": "(ett konto som fungerar på alla plattformar)", + "signInWithV2Text": "Logga in med ett BombSquad-konto", "signOutText": "Logga Ut", "signingInText": "Loggar in...", "signingOutText": "Loggar ut...", @@ -40,6 +42,7 @@ "titleText": "Konto", "unlinkAccountsInstructionsText": "Välj ett konto att avlänka", "unlinkAccountsText": "Avlänka Konton", + "v2LinkInstructionsText": "Använd den här länken för att skapa ett konto eller logga in.", "viaAccount": "(via konto ${NAME})", "youAreLoggedInAsText": "Du är inloggad som:", "youAreSignedInAsText": "Du är inloggad som:" @@ -363,6 +366,9 @@ "cancelText": "Avbryt", "cantConfigureDeviceText": "Tyvärr, ${DEVICE} är inte konfigurerbar", "challengeEndedText": "Denna utmaning är avslutad.", + "chatMuteText": "Stänga av chatten", + "chatMutedText": "Chatt dämpad", + "chatUnMuteText": "Avsluta chatt", "choosingPlayerText": "", "completeThisLevelToProceedText": "Du måste klara\ndenna nivå för att fortsätta!", "completionBonusText": "Slutbonus", @@ -552,6 +558,7 @@ "defaultNewTeamGameListNameText": "Mina Lagspel", "defaultTeamGameListNameText": "Standard Lagspel", "deleteText": "Radera", + "demoText": "Demo", "denyText": "Neka", "desktopResText": "Skrivbordsupplösning", "difficultyEasyText": "Lätt", @@ -616,7 +623,7 @@ "duplicateText": "Duplicera\nSoundtrack", "editSoundtrackText": "Soundtrack Editor", "editText": "Redigera\nSoundtrack", - "fetchingITunesText": "hämtar iTunes spellistor...", + "fetchingITunesText": "hämtar spellistor från Music App...", "musicVolumeZeroWarning": "Varning: Musikvolym är satt till 0", "nameText": "Namn", "newSoundtrackNameText": "Mitt Soundtrack ${COUNT}", @@ -628,7 +635,7 @@ "testText": "test", "titleText": "Soundtrack", "useDefaultGameMusicText": "Standard Spelmusik", - "useITunesPlaylistText": "iTunes Spellista", + "useITunesPlaylistText": "Musik-app spellista", "useMusicFileText": "Musikfil (mp3, etc)", "useMusicFolderText": "Mappnamn för Musikfiler" }, @@ -652,6 +659,7 @@ "titleFolderText": "Välj en Mapp", "useThisFolderButtonText": "Använd Denna Mapp" }, + "filterText": "Filter", "finalScoreText": "Slutgiltig Poäng", "finalScoresText": "Slutgiltiga Poäng", "finalTimeText": "Slutgiltig Tid", @@ -702,11 +710,15 @@ "bluetoothJoinText": "Anslut över Bluetooth", "bluetoothText": "Bluetooth", "checkingText": "kontrollerar...", + "copyCodeConfirmText": "Koden har kopierats till urklipp.", + "copyCodeText": "Kopiera kod", "dedicatedServerInfoText": "För bästa resultat, skapa en dedikerad server. Gå till bombsquadgame.com/server för att lära dig hur.", "disconnectClientsText": "Detta gör att ${COUNT} spelare kopplas \nifrån ditt sällskap. Är du säker?", "earnTicketsForRecommendingAmountText": "Vänner kommer få ${COUNT} biljetter om dom testar spelet\n(och du kommer få ${YOU_COUNT} för varje person som testar)", "earnTicketsForRecommendingText": "Dela spelet med andra\nOch få fribiljetter...", "emailItText": "Mejla Det", + "favoritesSaveText": "Spara som favorit", + "favoritesText": "Favoriter", "friendHasSentPromoCodeText": "${COUNT} ${APP_NAME}-biljetter från ${NAME}", "friendPromoCodeAwardText": "Du kommer få ${COUNT} biljetter varje gång den används.", "friendPromoCodeExpireText": "Den här koden kommer sluta fungera om ${EXPIRE_HOURS} timmar och fungerar bara för nya spelare.", @@ -1725,7 +1737,7 @@ "macInstructions2Text": "För att använda kontrollen trådlöst behöver du en mottagare \nsom kommer med 'Xbox 360 kontrollen för Windows'\nEn mottagare gör det möjligt för up till 4 kontroller.\n\nViktigt: 3:e part mottagare fungerar ej med denna drivrutin;\nse till att det står 'Microsoft', inte 'XBOX 360' på mottagaren.\nMicrosoft säljer inte längre dessa separat, så du behöver köpa\nen kontroll eller söka efter en på Ebay.\n\nOm du finner detta användbart, överväg gärna att donera till\nutvecklaren av drivrutinen på hans sida.", "macInstructionsText": "För att använda Xbox 360 kontroller behöver du\ninstallera Mac drivrutinen som är tillgänglig via\nlänken nedanför. Den fungerar både med och utan sladd", "ouyaInstructionsText": "Allt du behöver göra för att använda trådade Xbox 360-kontroller är att \nkoppla in dem i USB-porten. Du kan använda en USB-hub \nför att koppla in fler kontroller.\n\nFör att använda trådlösa kontroller behöver du en trådlös mottagare, \ndessa ingår om man köper en \"Xbox 360 Wireless Controller for Windows\" \nmen säljs också separat. Varje mottagare kopplas in i en USB-port \noch möjliggör användandet av upp till fyra stycken trådlösa kontroller.", - "titleText": "Använd Xbox 360-kontroller med BombSquad:" + "titleText": "Använda Xbox 360-kontroller med ${APP_NAME}:" }, "yesAllowText": "Ja, Tillåt!", "yourBestScoresText": "Dina Bästa Poäng", diff --git a/dist/ba_data/data/languages/tamil.json b/dist/ba_data/data/languages/tamil.json index 2b713ee..241e76f 100644 --- a/dist/ba_data/data/languages/tamil.json +++ b/dist/ba_data/data/languages/tamil.json @@ -27,6 +27,8 @@ "signInWithGooglePlayText": "Google Play உடன் உள்நுழைக", "signInWithTestAccountInfoText": "(மரபு கணக்கு வகை; முன்னோக்கி செல்லும் சாதனக் கணக்குகளைப் பயன்படுத்தவும்)", "signInWithTestAccountText": "சோதனைக் கணக்கில் உள்நுழைக", + "signInWithV2InfoText": "(அனைத்து தளங்களிலும் செயல்படும் கணக்கு)", + "signInWithV2Text": "BombSquad கணக்கில் உள்நுழையவும்", "signOutText": "வெளியேறு", "signingInText": "புகுபதிகை நடைபெறுகிறது...", "signingOutText": "விடுபதிகை நடைபெறுகிறது...", @@ -34,6 +36,7 @@ "titleText": "கணக்கு", "unlinkAccountsInstructionsText": "இணைப்பை நீக்குவதற்கான கணக்கைத் தேர்ந்தெடுக்கவும்", "unlinkAccountsText": "கணக்கை நீக்க", + "v2LinkInstructionsText": "கணக்கை உருவாக்க அல்லது உள்நுழைய இந்த இணைப்பைப் பயன்படுத்தவும்.", "viaAccount": "${NAME} கணக்கின் வழியாக", "youAreSignedInAsText": "நீங்கள் உள்நுழைந்துள்ளீர்கள்" }, @@ -494,6 +497,7 @@ "yourPowerRankingText": "உங்கள் சக்தி தரவரிசை:" }, "copyOfText": "${NAME} பிரதி", + "copyText": "நகல்", "createEditPlayerText": "<பிளேயரை உருவாக்கவும்/திருத்தவும்>", "createText": "உருவாக்கு", "creditsWindow": { @@ -952,7 +956,7 @@ "singlePlayerExamplesText": "ஒற்றை வீரர் / கூட்டுறவு உதாரணங்கள்", "versusExamplesText": "வெர்சஸ் உதாரணங்கள்" }, - "languageSetText": "மொழி இப்போது \"${LANGUAGE}\".", + "languageSetText": "மொழி இப்போது \"${LANGUAGE}\" இல் இருக்கிறது.", "lapNumberText": "சுற்று ${CURRENT}/${TOTAL}", "lastGamesText": "(கடைசி ${COUNT} விளையாட்டுகள்)", "leaderboardsText": "லீடர்போர்டுகள்", @@ -1497,6 +1501,7 @@ "Dutch": "டச்", "English": "ஆங்கிலம்", "Esperanto": "எசபராண்டோ", + "Filipino": "பிலிபினோ", "Finnish": "பின்னிஷ்", "French": "பிரெஞ்ச்", "German": "ஜெர்மன்", @@ -1517,6 +1522,7 @@ "Slovak": "ஸ்லோவக்", "Spanish": "ஸ்பானிஷ்", "Swedish": "ஸ்வீடிஷ்", + "Tamil": "தமிழ்", "Thai": "தாய்", "Turkish": "டர்கிஷ்", "Ukrainian": "உக்ரைனியன்", diff --git a/dist/ba_data/data/languages/thai.json b/dist/ba_data/data/languages/thai.json index 3dd2e77..bcd6c11 100644 --- a/dist/ba_data/data/languages/thai.json +++ b/dist/ba_data/data/languages/thai.json @@ -28,6 +28,8 @@ "signInWithGooglePlayText": "ลงชื่อเข้าใช้ด้วยบัญชี Google Play", "signInWithTestAccountInfoText": "(บัญชีทดลอง;เลือกตัวเลือกนี้เพื่อไปต่อ)", "signInWithTestAccountText": "ลงชื่อเข้าใช้เพื่อทดลอง", + "signInWithV2InfoText": "(บัญชีที่ใช้งานได้กับทุกแพลตฟอร์ม)", + "signInWithV2Text": "ลงชื่อเข้าใช้ด้วยบัญชี BombSquad", "signOutText": "ออกจากระบบ", "signingInText": "กำลังลงชื่อเข้าใช้...", "signingOutText": "กำลังออกจากระบบ...", @@ -35,6 +37,7 @@ "titleText": "บัญชี", "unlinkAccountsInstructionsText": "เลือกบัญชีที่จะยกเลิกการเชื่อมโยง", "unlinkAccountsText": "ยกเลิกการเชื่อมโยงบัญชี", + "v2LinkInstructionsText": "ใช้ลิงก์นี้เพื่อสร้างบัญชีหรือลงชื่อเข้าใช้", "viaAccount": "ผ่านบัญชี ${NAME}", "youAreSignedInAsText": "คุณลงชื่อเข้าใช้ในบัญชี:" }, @@ -493,6 +496,7 @@ "yourPowerRankingText": "อันดับของคุณ:" }, "copyOfText": "${NAME} ที่ถูกคัดลอก", + "copyText": "คัดลอก", "createEditPlayerText": "<สร้าง/แก้ไข ผู้เล่น>", "createText": "สร้าง", "creditsWindow": { @@ -1493,11 +1497,12 @@ "Dutch": "ภาษาดัตช์", "English": "ภาษาอังกฤษ", "Esperanto": "ภาษาเอสเปรันโต", + "Filipino": "ภาษาฟิลิปปินส์", "Finnish": "ภาษาฟินแลนด์", "French": "ภาษาฝรั่งเศส", "German": "ภาษาเยอรมัน", - "Gibberish": "Gibberish", - "Greek": "กรีก", + "Gibberish": "พูดไรสาระ", + "Greek": "ภาษากรีก", "Hindi": "ภาษาฮินดู", "Hungarian": "ภาษาฮังการี", "Indonesian": "ภาษาอินโดนีเซีย", @@ -1513,6 +1518,7 @@ "Slovak": "ภาษาสโลวัก", "Spanish": "ภาษาสเปน", "Swedish": "ภาษาสวีเดน", + "Tamil": "ภาษาทมิฬ", "Thai": "ภาษาไทย", "Turkish": "ภาษาตุรกี", "Ukrainian": "ยูเครน", diff --git a/dist/ba_data/data/languages/turkish.json b/dist/ba_data/data/languages/turkish.json index adde109..98961ee 100644 --- a/dist/ba_data/data/languages/turkish.json +++ b/dist/ba_data/data/languages/turkish.json @@ -15,7 +15,7 @@ "linkAccountsInstructionsText": "İki hesabı birbirine bağlamak için, birinde kod oluşturun\nve o kodu diğerinde girin.\nİlerlemeler ve envanterler birleşecektir.\n${COUNT} taneye kadar hesap bağlayabilirsiniz.\n\nÖNEMLİ: Yalnızca kendi hesaplarını bağla!\nEğer arkadaşınla hesapları bağlarsan\naynı anda oynayamayacaksınız!\n\nAyrıca: bu işlem şu anda geri alınamaz, yani dikkatli ol!", "linkAccountsText": "Hesapları Bağla", "linkedAccountsText": "Bağlı Hesaplar:", - "nameChangeConfirm": "Hesap adını ${NAME} olarak değiştir?", + "nameChangeConfirm": "Hesap adın ${NAME} olarak değiştirilsinmi ?", "resetProgressConfirmNoAchievementsText": "Bu co-op ilerlemeyi ve \nlokaldeki yüksek puanlarnı sıfırlar(ama biletlerini değil).\nBu geri alınamaz. Emin misiniz?", "resetProgressConfirmText": "Bu co-op ilerlemeyi, başarıları ve \nEn yüksek skorları sıfırlayacak \n(ama biletlerini değil). Bu işlem\ngeri alınamaz. Emin misin?", "resetProgressText": "İlerlemeyi Sıfırla", @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "Google Play ile Giriş yap", "signInWithTestAccountInfoText": "(miras hesabı;bu cihaz hesaplarını ileride de kullan)", "signInWithTestAccountText": "Test hesabı ile Giriş yap", + "signInWithV2InfoText": "(bütün platformlarda çalışan bir hesap)", + "signInWithV2Text": "BombSquad hesabıyla giriş yap", "signOutText": "Çıkış Yap", "signingInText": "Giriş yapılıyor...", "signingOutText": "Çıkış yapılıyor...", @@ -36,6 +38,7 @@ "titleText": "Hesap", "unlinkAccountsInstructionsText": "Ayırmak için bir hesap seç", "unlinkAccountsText": "Hesapları ayır", + "v2LinkInstructionsText": "Bu bağlantıyı kullanarak bir hesap oluşturun yada giriş yapın.", "viaAccount": "(${NAME}hesabı ile)", "youAreSignedInAsText": "Aşağıdaki ile giriş yapıldı" }, @@ -495,6 +498,7 @@ "yourPowerRankingText": "Oyuncu Sıralaman:" }, "copyOfText": "Kopya ${NAME}", + "copyText": "Kopyala", "createEditPlayerText": "", "createText": "Oluştur", "creditsWindow": { @@ -1496,6 +1500,7 @@ "Dutch": "Flemenkçe", "English": "İngilizce", "Esperanto": "Esperanto", + "Filipino": "Filipince", "Finnish": "Fince", "French": "Fransızca", "German": "Almanca", @@ -1516,6 +1521,7 @@ "Slovak": "Slovakça", "Spanish": "İspanyolca", "Swedish": "İsveççe", + "Tamil": "Tamilce", "Thai": "Tayland dili", "Turkish": "Türkçe", "Ukrainian": "Ukrayna", @@ -1846,7 +1852,7 @@ "macInstructions2Text": "Kablosuz olarak kullanmak için; ayrıca 'Xbox 360 Kontroller for Windows'\nile gelen bir alıcı kullanman lazım. \nBir alıcı sana 4 taneye kadar bağlantı sağlar.\n\nÖnemli: 3.şahıs alıcılar bu sürücü ile çalışmaz;\nAlıcının 'Microsoft' için olduğuna dikkat et 'XBOX 360' değil.\nMicrosoft bunu uzun süredir ayrı olarak satmıyor. Kontrolcüleri ile \nbirlikte alabilirsin ya da ebay de araştırabilirsin.\n\nEğer bunu kullanışlı bulduysan, lütfen değerlendirerek sürücü\ngeliştirilmesine bu siteden bağış yap.", "macInstructionsText": "Xbox 360 kolunu kullanmak için aşağıdaki bağlantıdaki\nMac sürücüsü yüklemen gerekiyor.\nKablolu ve Kablosuz kontroller de çalışır.", "ouyaInstructionsText": "BombSquad ile kablolu Xbox 360 kontrolcüsü kullanmak için basitçe\ncihazının USB girişine takın. Çoklu kontrolcü kullanmak için USB\nçoklayıcı kullanabilirsiniz.\n\nKablosuz kontrolcü için \"Xbox 360 Wireless Controller for Windows\"\nkablosuz alıcısına ihtiyacınız var. Her alıcıya\nUSB girişi ile bağlanır ve 4 kablosuz kontrolcüye\nkadar desteklenir.", - "titleText": "Xbox 360 Kontrolcüsünü ${APP_NAME} ile kullan:" + "titleText": "Xbox 360 Kontrolcüsü ${APP_NAME} ile kullanılıyor:" }, "yesAllowText": "Evet, Kabul!", "yourBestScoresText": "En-İyi Skorların", diff --git a/dist/ba_data/data/languages/ukrainian.json b/dist/ba_data/data/languages/ukrainian.json index 1af0ec2..009d31a 100644 --- a/dist/ba_data/data/languages/ukrainian.json +++ b/dist/ba_data/data/languages/ukrainian.json @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "Увійти через Google Play", "signInWithTestAccountInfoText": "(тест-аккаунт; надалі використовуйте акаунт пристрою)", "signInWithTestAccountText": "Увійти через тестовий акаунт", + "signInWithV2InfoText": "(обліковий запис, який працює на всіх платформах)", + "signInWithV2Text": "Увійдіть за допомогою облікового запису BombSquad", "signOutText": "Вийти", "signingInText": "Вхід…", "signingOutText": "Вихід…", @@ -38,6 +40,7 @@ "titleText": "Акаунт", "unlinkAccountsInstructionsText": "Виберіть акаунт, який хочете відв'язати", "unlinkAccountsText": "Відв'язати акаунт", + "v2LinkInstructionsText": "Скористайтеся цим посиланням, щоб створити обліковий запис або увійти.", "viaAccount": "(через акаунт ${NAME})", "youAreSignedInAsText": "Ви увійшли як:" }, @@ -496,6 +499,7 @@ "yourPowerRankingText": "Ваш ранг:" }, "copyOfText": "Копія ${NAME}", + "copyText": "Копія", "createEditPlayerText": "<Створення / редагування гравця>", "createText": "Створити", "creditsWindow": { @@ -1496,6 +1500,7 @@ "Dutch": "Голландська", "English": "Англійська", "Esperanto": "Есперанто", + "Filipino": "Філіппінський", "Finnish": "Фінська", "French": "Французька", "German": "Німецька", @@ -1516,6 +1521,7 @@ "Slovak": "Словацька", "Spanish": "Іспанська", "Swedish": "Шведська", + "Tamil": "тамільська", "Thai": "Тайська", "Turkish": "Турецька", "Ukrainian": "Українська", diff --git a/dist/ba_data/data/languages/venetian.json b/dist/ba_data/data/languages/venetian.json index b300229..30ea63e 100644 --- a/dist/ba_data/data/languages/venetian.json +++ b/dist/ba_data/data/languages/venetian.json @@ -27,6 +27,8 @@ "signInWithGooglePlayText": "Conétate co Google Play", "signInWithTestAccountInfoText": "(account de proa vecio: in fuduro dòpara i account de’l dispozitivo)", "signInWithTestAccountText": "Conétate co un account de proa", + "signInWithV2InfoText": "(un account che fusiona so tute łe piataforme)", + "signInWithV2Text": "Acedi co un account BombSquad", "signOutText": "Sortisi da l'account", "signingInText": "Conesion in corso...", "signingOutText": "Sortìa in corso...", @@ -34,6 +36,7 @@ "titleText": "Account", "unlinkAccountsInstructionsText": "Sełesiona un account da descołegar", "unlinkAccountsText": "Descołega account", + "v2LinkInstructionsText": "Acedi o dòpara 'sto link par crear un account.", "viaAccount": "(doparando ${NAME})", "youAreSignedInAsText": "A te zugarè cofà:" }, @@ -492,6 +495,7 @@ "yourPowerRankingText": "Ła to pozision:" }, "copyOfText": "Copia de ${NAME}", + "copyText": "Copia", "createEditPlayerText": "", "createText": "Crea", "creditsWindow": { @@ -1492,6 +1496,7 @@ "Dutch": "Ołandeze", "English": "Ingleze", "Esperanto": "Esperanto", + "Filipino": "Fiłipin", "Finnish": "Fiłandeze", "French": "Franseze", "German": "Todesco", @@ -1512,6 +1517,7 @@ "Slovak": "Zlovaco", "Spanish": "Spagnoło", "Swedish": "Zvedeze", + "Tamil": "Tamil", "Thai": "Thailandeze", "Turkish": "Turco", "Ukrainian": "Ucrain", diff --git a/dist/ba_data/data/languages/vietnamese.json b/dist/ba_data/data/languages/vietnamese.json index 9dc7444..92fd2af 100644 --- a/dist/ba_data/data/languages/vietnamese.json +++ b/dist/ba_data/data/languages/vietnamese.json @@ -29,6 +29,8 @@ "signInWithGooglePlayText": "đăng nhập bằng google chơi trò chơi", "signInWithTestAccountInfoText": "(loại tài khoản đặc biệt; chỉ đăng nhập trên máy này)", "signInWithTestAccountText": "Đăng nhập bằng tài khoản máy tính", + "signInWithV2InfoText": "(một tài khoản hoạt động trên tất cả các nền tảng)", + "signInWithV2Text": "Đăng nhập bằng tài khoản BombSquad", "signOutText": "Đăng Xuất", "signingInText": "Đang đăng nhập...", "signingOutText": "Đang Đăng xuất...", @@ -39,6 +41,7 @@ "titleText": "Tài Khoản", "unlinkAccountsInstructionsText": "Chọn tài khoản để hủy kết nối", "unlinkAccountsText": "Hủy kết nối", + "v2LinkInstructionsText": "Sử dụng liên kết này để tạo tài khoản hoặc đăng nhập.", "viaAccount": "(qua tài khoản ${NAME})", "youAreSignedInAsText": "Bạn đang đăng nhập tài khoản:" }, @@ -497,6 +500,7 @@ "yourPowerRankingText": "Xếp hạng sức mạnh của bạn" }, "copyOfText": "${NAME} copy", + "copyText": "Sao chép", "createEditPlayerText": "", "createText": "Tạo", "creditsWindow": { @@ -1498,6 +1502,7 @@ "Dutch": "Tiếng Hà Lan", "English": "Tiếng Anh", "Esperanto": "Quốc tế ngữ", + "Filipino": "Người Phi Luật Tân", "Finnish": "Tiếng Phần Lan", "French": "Tiếng Pháp", "German": "Tiếng Đức", @@ -1518,6 +1523,7 @@ "Slovak": "Tiếng Slovakia", "Spanish": "Tiếng Tây Ban Nha", "Swedish": "Tiếng Thụy Điển", + "Tamil": "Tamil", "Thai": "Tiếng thái", "Turkish": "Tiếng Thổ Nhĩ Kỳ", "Ukrainian": "Tiếng Ukraina", diff --git a/dist/ba_data/python-site-packages/certifi/__init__.py b/dist/ba_data/python-site-packages/certifi/__init__.py new file mode 100644 index 0000000..b700d3a --- /dev/null +++ b/dist/ba_data/python-site-packages/certifi/__init__.py @@ -0,0 +1,4 @@ +from .core import contents, where + +__all__ = ["contents", "where"] +__version__ = "2022.05.18.1" diff --git a/dist/ba_data/python-site-packages/certifi/__main__.py b/dist/ba_data/python-site-packages/certifi/__main__.py new file mode 100644 index 0000000..8945b5d --- /dev/null +++ b/dist/ba_data/python-site-packages/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/dist/ba_data/python-site-packages/certifi/cacert.pem b/dist/ba_data/python-site-packages/certifi/cacert.pem new file mode 100644 index 0000000..f597fb3 --- /dev/null +++ b/dist/ba_data/python-site-packages/certifi/cacert.pem @@ -0,0 +1,4530 @@ + +# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Label: "GlobalSign Root CA" +# Serial: 4835703278459707669005204 +# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a +# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c +# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Premium 2048 Secure Server CA" +# Serial: 946069240 +# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 +# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 +# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Label: "Entrust Root Certification Authority" +# Serial: 1164660820 +# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 +# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 +# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +# Issuer: CN=AAA Certificate Services O=Comodo CA Limited +# Subject: CN=AAA Certificate Services O=Comodo CA Limited +# Label: "Comodo AAA Services root" +# Serial: 1 +# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 +# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 +# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2" +# Serial: 1289 +# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b +# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 +# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3" +# Serial: 1478 +# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf +# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 +# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 +# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 +# Label: "Security Communication Root CA" +# Serial: 0 +# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a +# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 +# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- + +# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Label: "XRamp Global CA Root" +# Serial: 107108908803651509692980124233745014957 +# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 +# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 +# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Label: "Go Daddy Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 +# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 +# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Label: "Starfield Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 +# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a +# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root CA" +# Serial: 17154717934120587862167794914071425081 +# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 +# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 +# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root CA" +# Serial: 10944719598952040374951832963794454346 +# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e +# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 +# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert High Assurance EV Root CA" +# Serial: 3553400076410547919724730734378100087 +# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a +# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 +# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Label: "SwissSign Gold CA - G2" +# Serial: 13492815561806991280 +# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 +# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 +# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Label: "SwissSign Silver CA - G2" +# Serial: 5700383053117599563 +# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 +# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb +# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +# Issuer: CN=SecureTrust CA O=SecureTrust Corporation +# Subject: CN=SecureTrust CA O=SecureTrust Corporation +# Label: "SecureTrust CA" +# Serial: 17199774589125277788362757014266862032 +# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 +# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 +# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +# Issuer: CN=Secure Global CA O=SecureTrust Corporation +# Subject: CN=Secure Global CA O=SecureTrust Corporation +# Label: "Secure Global CA" +# Serial: 9751836167731051554232119481456978597 +# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de +# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b +# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO Certification Authority O=COMODO CA Limited +# Label: "COMODO Certification Authority" +# Serial: 104350513648249232941998508985834464573 +# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 +# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b +# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- + +# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Label: "Network Solutions Certificate Authority" +# Serial: 116697915152937497490437556386812487904 +# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e +# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce +# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Label: "COMODO ECC Certification Authority" +# Serial: 41578283867086692638256921589707938090 +# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 +# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 +# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +# Issuer: CN=Certigna O=Dhimyotis +# Subject: CN=Certigna O=Dhimyotis +# Label: "Certigna" +# Serial: 18364802974209362175 +# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff +# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 +# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Label: "ePKI Root Certification Authority" +# Serial: 28956088682735189655030529057352760477 +# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 +# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 +# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +# Issuer: O=certSIGN OU=certSIGN ROOT CA +# Subject: O=certSIGN OU=certSIGN ROOT CA +# Label: "certSIGN ROOT CA" +# Serial: 35210227249154 +# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 +# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b +# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" +# Serial: 80544274841616 +# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 +# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 +# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Label: "Hongkong Post Root CA 1" +# Serial: 1000 +# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca +# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 +# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx +FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg +Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG +A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr +b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ +jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn +PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh +ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 +nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h +q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED +MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC +mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 +7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB +oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs +EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO +fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi +AmvZWg== +-----END CERTIFICATE----- + +# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Label: "SecureSign RootCA11" +# Serial: 1 +# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 +# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 +# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Label: "Microsec e-Szigno Root CA 2009" +# Serial: 14014712776195784473 +# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 +# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e +# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Label: "GlobalSign Root CA - R3" +# Serial: 4835703278459759426209954 +# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 +# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad +# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 6047274297262753887 +# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 +# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa +# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +# Issuer: CN=Izenpe.com O=IZENPE S.A. +# Subject: CN=Izenpe.com O=IZENPE S.A. +# Label: "Izenpe.com" +# Serial: 917563065490389241595536686991402621 +# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 +# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 +# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Label: "Go Daddy Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 +# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b +# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 +# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e +# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Services Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 +# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f +# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Commercial O=AffirmTrust +# Subject: CN=AffirmTrust Commercial O=AffirmTrust +# Label: "AffirmTrust Commercial" +# Serial: 8608355977964138876 +# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 +# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 +# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Networking O=AffirmTrust +# Subject: CN=AffirmTrust Networking O=AffirmTrust +# Label: "AffirmTrust Networking" +# Serial: 8957382827206547757 +# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f +# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f +# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium O=AffirmTrust +# Subject: CN=AffirmTrust Premium O=AffirmTrust +# Label: "AffirmTrust Premium" +# Serial: 7893706540734352110 +# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 +# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 +# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust +# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust +# Label: "AffirmTrust Premium ECC" +# Serial: 8401224907861490260 +# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d +# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb +# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA" +# Serial: 279744 +# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 +# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e +# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Label: "TWCA Root Certification Authority" +# Serial: 1 +# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 +# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 +# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Label: "Security Communication RootCA2" +# Serial: 0 +# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 +# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 +# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +# Issuer: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Subject: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Label: "EC-ACC" +# Serial: -23701579247955709139626555126524820479 +# MD5 Fingerprint: eb:f5:9d:29:0d:61:f9:42:1f:7c:c2:ba:6d:e3:15:09 +# SHA1 Fingerprint: 28:90:3a:63:5b:52:80:fa:e6:77:4c:0b:6d:a7:d6:ba:a6:4a:f2:e8 +# SHA256 Fingerprint: 88:49:7f:01:60:2f:31:54:24:6a:e2:8c:4d:5a:ef:10:f1:d8:7e:bb:76:62:6f:4a:e0:b7:f9:5b:a7:96:87:99 +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB +8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy +dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 +YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 +dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh +IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD +LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG +EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g +KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD +ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu +bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg +ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R +85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm +4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV +HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd +QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t +lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB +o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 +opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo +dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW +ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN +AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y +/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k +SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy +Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS +Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl +nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2011" +# Serial: 0 +# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9 +# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d +# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71 +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix +RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p +YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw +NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK +EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl +cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz +dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ +fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns +bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD +75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP +FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp +5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu +b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA +A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p +6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 +dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys +Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI +l7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Label: "Actalis Authentication Root CA" +# Serial: 6271844772424770508 +# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 +# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac +# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 2 Root CA" +# Serial: 2 +# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 +# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 +# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 3 Root CA" +# Serial: 2 +# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec +# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 +# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 3" +# Serial: 1 +# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef +# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 +# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 2009" +# Serial: 623603 +# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f +# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 +# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 EV 2009" +# Serial: 623604 +# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 +# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 +# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +# Issuer: CN=CA Disig Root R2 O=Disig a.s. +# Subject: CN=CA Disig Root R2 O=Disig a.s. +# Label: "CA Disig Root R2" +# Serial: 10572350602393338211 +# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 +# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 +# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Label: "ACCVRAIZ1" +# Serial: 6828503384748696800 +# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 +# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 +# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Label: "TWCA Global Root CA" +# Serial: 3262 +# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 +# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 +# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE----- + +# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Label: "TeliaSonera Root CA v1" +# Serial: 199041966741090107964904287217786801558 +# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c +# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 +# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +# Issuer: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Subject: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Label: "E-Tugra Certification Authority" +# Serial: 7667447206703254355 +# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 +# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 +# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 2" +# Serial: 1 +# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a +# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 +# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- + +# Issuer: CN=Atos TrustedRoot 2011 O=Atos +# Subject: CN=Atos TrustedRoot 2011 O=Atos +# Label: "Atos TrustedRoot 2011" +# Serial: 6643877497813316402 +# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 +# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 +# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 1 G3" +# Serial: 687049649626669250736271037606554624078720034195 +# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab +# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 +# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2 G3" +# Serial: 390156079458959257446133169266079962026824725800 +# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 +# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 +# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3 G3" +# Serial: 268090761170461462463995952157327242137089239581 +# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 +# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d +# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G2" +# Serial: 15385348160840213938643033620894905419 +# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d +# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f +# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G3" +# Serial: 15459312981008553731928384953135426796 +# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb +# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 +# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G2" +# Serial: 4293743540046975378534879503202253541 +# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 +# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 +# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G3" +# Serial: 7089244469030293291760083333884364146 +# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca +# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e +# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Trusted Root G4" +# Serial: 7451500558977370777930084869016614236 +# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 +# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 +# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Label: "COMODO RSA Certification Authority" +# Serial: 101909084537582093308941363524873193117 +# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 +# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 +# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Label: "USERTrust RSA Certification Authority" +# Serial: 2645093764781058787591871645665788717 +# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 +# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e +# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Label: "USERTrust ECC Certification Authority" +# Serial: 123013823720199481456569720443997572134 +# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 +# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 +# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Label: "GlobalSign ECC Root CA - R5" +# Serial: 32785792099990507226680698011560947931244 +# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 +# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa +# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Label: "Staat der Nederlanden EV Root CA" +# Serial: 10000013 +# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba +# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb +# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Label: "IdenTrust Commercial Root CA 1" +# Serial: 13298821034946342390520003877796839426 +# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 +# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 +# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Label: "IdenTrust Public Sector Root CA 1" +# Serial: 13298821034946342390521976156843933698 +# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba +# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd +# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G2" +# Serial: 1246989352 +# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 +# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 +# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - EC1" +# Serial: 51543124481930649114116133369 +# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc +# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 +# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority +# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority +# Label: "CFCA EV ROOT" +# Serial: 407555286 +# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 +# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 +# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GB CA" +# Serial: 157768595616588414422159278966750757568 +# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d +# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed +# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Label: "SZAFIR ROOT CA2" +# Serial: 357043034767186914217277344587386743377558296292 +# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 +# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de +# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA 2" +# Serial: 44979900017204383099463764357512596969 +# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 +# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 +# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce +# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 +# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef +# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 +# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X1 O=Internet Security Research Group +# Subject: CN=ISRG Root X1 O=Internet Security Research Group +# Label: "ISRG Root X1" +# Serial: 172886928669790476064670243504169061120 +# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e +# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 +# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Label: "AC RAIZ FNMT-RCM" +# Serial: 485876308206448804701554682760554759 +# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d +# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 +# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 1 O=Amazon +# Subject: CN=Amazon Root CA 1 O=Amazon +# Label: "Amazon Root CA 1" +# Serial: 143266978916655856878034712317230054538369994 +# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 +# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 +# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 2 O=Amazon +# Subject: CN=Amazon Root CA 2 O=Amazon +# Label: "Amazon Root CA 2" +# Serial: 143266982885963551818349160658925006970653239 +# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 +# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a +# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 3 O=Amazon +# Subject: CN=Amazon Root CA 3 O=Amazon +# Label: "Amazon Root CA 3" +# Serial: 143266986699090766294700635381230934788665930 +# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 +# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e +# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 4 O=Amazon +# Subject: CN=Amazon Root CA 4 O=Amazon +# Label: "Amazon Root CA 4" +# Serial: 143266989758080763974105200630763877849284878 +# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd +# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be +# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" +# Serial: 1 +# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 +# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca +# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Label: "GDCA TrustAUTH R5 ROOT" +# Serial: 9009899650740120186 +# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 +# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 +# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 +MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w +HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj +Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj +TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u +KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj +qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm +MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 +ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP +zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk +L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC +jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA +HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC +AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm +DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 +COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry +L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf +JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg +IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io +2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV +09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ +XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq +T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe +MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-1" +# Serial: 15752444095811006489 +# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45 +# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a +# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y +IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB +pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h +IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG +A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU +cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid +RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V +seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme +9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV +EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW +hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ +DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD +ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I +/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ +yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts +L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN +zl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-2" +# Serial: 2711694510199101698 +# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64 +# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0 +# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65 +-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig +Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk +MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg +Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD +VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy +dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ +QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq +1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp +2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK +DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape +az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF +3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 +oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM +g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 +mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd +BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U +nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw +DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX +dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ +MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL +/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX +CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa +ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW +2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 +N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 +Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB +As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp +5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu +1uwJ +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor ECA-1" +# Serial: 9548242946988625984 +# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c +# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd +# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y +IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig +RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb +3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA +BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 +3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou +owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ +wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF +ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf +BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv +civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 +AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 +soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI +WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi +tJ/X5g== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Label: "SSL.com Root Certification Authority RSA" +# Serial: 8875640296558310041 +# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 +# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb +# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com Root Certification Authority ECC" +# Serial: 8495723813297216424 +# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e +# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a +# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority RSA R2" +# Serial: 6248227494352943350 +# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 +# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a +# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority ECC" +# Serial: 3182246526754555285 +# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 +# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d +# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Label: "GlobalSign Root CA - R6" +# Serial: 1417766617973444989252670301619537 +# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae +# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 +# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GC CA" +# Serial: 44084345621038548146064804565436152554 +# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 +# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 +# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +# Issuer: CN=UCA Global G2 Root O=UniTrust +# Subject: CN=UCA Global G2 Root O=UniTrust +# Label: "UCA Global G2 Root" +# Serial: 124779693093741543919145257850076631279 +# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 +# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a +# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Extended Validation Root O=UniTrust +# Subject: CN=UCA Extended Validation Root O=UniTrust +# Label: "UCA Extended Validation Root" +# Serial: 106100277556486529736699587978573607008 +# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 +# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a +# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- + +# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Label: "Certigna Root CA" +# Serial: 269714418870597844693661054334862075617 +# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 +# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 +# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign Root CA - G1" +# Serial: 235931866688319308814040 +# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac +# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c +# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign ECC Root CA - G3" +# Serial: 287880440101571086945156 +# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 +# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 +# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Label: "emSign Root CA - C1" +# Serial: 825510296613316004955058 +# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 +# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 +# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Label: "emSign ECC Root CA - C3" +# Serial: 582948710642506000014504 +# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 +# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 +# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Label: "Hongkong Post Root CA 3" +# Serial: 46170865288971385588281144162979347873371282084 +# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 +# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 +# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL +BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ +SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n +a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 +NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT +CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u +Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO +dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI +VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV +9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY +2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY +vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt +bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb +x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ +l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK +TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj +Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw +DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG +7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk +MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr +gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk +GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS +3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm +Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ +l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c +JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP +L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa +LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG +mpv0 +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G4" +# Serial: 289383649854506086828220374796556676440 +# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88 +# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01 +# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88 +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft ECC Root Certificate Authority 2017" +# Serial: 136839042543790627607696632466672567020 +# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 +# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 +# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft RSA Root Certificate Authority 2017" +# Serial: 40975477897264996090493496164228220339 +# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 +# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 +# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Label: "e-Szigno Root CA 2017" +# Serial: 411379200276854331539784714 +# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 +# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 +# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE----- + +# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Label: "certSIGN Root CA G2" +# Serial: 313609486401300475190 +# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 +# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 +# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global Certification Authority" +# Serial: 1846098327275375458322922162 +# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e +# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5 +# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8 +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw +CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x +ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 +c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx +OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI +SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn +swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu +7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 +1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW +80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP +JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l +RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw +hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 +coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc +BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n +twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W +0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe +uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q +lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB +aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE +sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT +MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe +qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh +VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 +h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 +EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK +yeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P256 Certification Authority" +# Serial: 4151900041497450638097112925 +# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54 +# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf +# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4 +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN +FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w +DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw +CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh +DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P384 Certification Authority" +# Serial: 2704997926503831671788816187 +# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6 +# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2 +# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97 +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB +BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ +j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF +1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G +A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 +AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC +MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu +Sw== +-----END CERTIFICATE----- + +# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Label: "NAVER Global Root Certification Authority" +# Serial: 9013692873798656336226253319739695165984492813 +# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b +# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 +# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM +BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG +T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx +CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD +b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA +iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH +38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE +HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz +kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP +szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq +vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf +nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG +YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo +0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a +CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K +AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I +36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN +qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj +cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm ++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL +hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe +lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 +p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 +piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR +LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX +5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO +dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul +9XXeifdy +-----END CERTIFICATE----- + +# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" +# Serial: 131542671362353147877283741781055151509 +# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb +# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a +# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw +CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw +FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S +Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 +MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL +DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS +QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH +sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK +Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu +SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC +MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy +v+c= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Label: "GlobalSign Root R46" +# Serial: 1552617688466950547958867513931858518042577 +# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef +# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 +# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Label: "GlobalSign Root E46" +# Serial: 1552617690338932563915843282459653771421763 +# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f +# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 +# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +# Issuer: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Subject: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Label: "GLOBALTRUST 2020" +# Serial: 109160994242082918454945253 +# MD5 Fingerprint: 8a:c7:6f:cb:6d:e3:cc:a2:f1:7c:83:fa:0e:78:d7:e8 +# SHA1 Fingerprint: d0:67:c1:13:51:01:0c:aa:d0:c7:6a:65:37:31:16:26:4f:53:71:a2 +# SHA256 Fingerprint: 9a:29:6a:51:82:d1:d4:51:a2:e3:7f:43:9b:74:da:af:a2:67:52:33:29:f9:0f:9a:0d:20:07:c3:34:e2:3c:9a +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG +A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw +FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx +MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u +aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b +RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z +YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 +QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw +yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ +BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ +SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH +r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 +4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me +dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw +q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 +nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu +H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC +XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd +6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf ++I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi +kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 +wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB +TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C +MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn +4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I +aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy +qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Label: "ANF Secure Server Root CA" +# Serial: 996390341000653745 +# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 +# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 +# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV +BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk +YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV +BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN +MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF +UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD +VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v +dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj +cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q +yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH +2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX +H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL +zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR +p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz +W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/ +SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn +LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3 +n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B +u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC +AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L +9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej +rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK +pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0 +vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq +OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ +/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9 +2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI ++PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 +MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo +tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- + +# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum EC-384 CA" +# Serial: 160250656287871593594747141429395092468 +# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 +# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed +# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw +CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw +JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT +EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 +WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT +LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX +BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE +KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm +Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 +EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J +UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn +nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Root CA" +# Serial: 40870380103424195783807378461123655149 +# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 +# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 +# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 +MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu +MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV +BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw +MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg +U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ +n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q +p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq +NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF +8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 +HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa +mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi +7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF +ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P +qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ +v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 +Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD +ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 +WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo +zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR +5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ +GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf +5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq +0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D +P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM +qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP +0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf +E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + +# Issuer: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique +# Subject: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique +# Label: "TunTrust Root CA" +# Serial: 108534058042236574382096126452369648152337120275 +# MD5 Fingerprint: 85:13:b9:90:5b:36:5c:b6:5e:b8:5a:f8:e0:31:57:b4 +# SHA1 Fingerprint: cf:e9:70:84:0f:e0:73:0f:9d:f6:0c:7f:2c:4b:ee:20:46:34:9c:bb +# SHA256 Fingerprint: 2e:44:10:2a:b5:8c:b8:54:19:45:1c:8e:19:d9:ac:f3:66:2c:af:bc:61:4b:6a:53:96:0a:30:f7:d0:e2:eb:41 +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL +BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg +Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv +b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG +EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u +IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ +n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd +2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF +VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ +GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF +li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU +r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 +eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb +MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg +jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB +7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW +5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE +ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z +xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu +QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 +FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH +22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP +xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn +dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 +Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b +nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ +CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH +u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj +d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +# Issuer: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Subject: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Label: "HARICA TLS RSA Root CA 2021" +# Serial: 76817823531813593706434026085292783742 +# MD5 Fingerprint: 65:47:9b:58:86:dd:2c:f0:fc:a2:84:1f:1e:96:c4:91 +# SHA1 Fingerprint: 02:2d:05:82:fa:88:ce:14:0c:06:79:de:7f:14:10:e9:45:d7:a5:6d +# SHA256 Fingerprint: d9:5d:0e:8e:da:79:52:5b:f9:be:b1:1b:14:d2:10:0d:32:94:98:5f:0c:62:d9:fa:bd:9c:d9:99:ec:cb:7b:1d +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg +Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL +MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l +mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE +4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv +a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M +pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw +Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b +LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY +AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB +AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq +E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr +W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ +CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU +X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 +f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja +H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP +JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P +zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt +jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 +/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT +BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 +aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW +xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU +63ZTGI0RmLo= +-----END CERTIFICATE----- + +# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Label: "HARICA TLS ECC Root CA 2021" +# Serial: 137515985548005187474074462014555733966 +# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0 +# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48 +# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01 +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw +CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh +cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v +dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG +A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 +KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y +STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD +AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw +SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN +nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 1977337328857672817 +# MD5 Fingerprint: 4e:6e:9b:54:4c:ca:b7:fa:48:e4:90:b1:15:4b:1c:a3 +# SHA1 Fingerprint: 0b:be:c2:27:22:49:cb:39:aa:db:35:5c:53:e3:8c:ae:78:ff:b6:fe +# SHA256 Fingerprint: 57:de:05:83:ef:d2:b2:6e:03:61:da:99:da:9d:f4:64:8d:ef:7e:e8:44:1c:3b:72:8a:fa:9b:cd:e0:f9:b2:6a +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 +MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc +tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd +IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC +AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw +ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m +iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF +Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ +hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P +Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE +EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV +1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t +CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR +5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw +f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 +ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK +GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- + +# Issuer: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. +# Subject: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. +# Label: "vTrus ECC Root CA" +# Serial: 630369271402956006249506845124680065938238527194 +# MD5 Fingerprint: de:4b:c1:f5:52:8c:9b:43:e1:3e:8f:55:54:17:8d:85 +# SHA1 Fingerprint: f6:9c:db:b0:fc:f6:02:13:b6:52:32:a6:a3:91:3f:16:70:da:c3:e1 +# SHA256 Fingerprint: 30:fb:ba:2c:32:23:8e:2a:98:54:7a:f9:79:31:e5:50:42:8b:9b:3f:1c:8e:eb:66:33:dc:fa:86:c5:b2:7d:d3 +-----BEGIN CERTIFICATE----- +MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw +RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY +BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz +MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u +LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0 +v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd +e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw +V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA +AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG +GJTO +-----END CERTIFICATE----- + +# Issuer: CN=vTrus Root CA O=iTrusChina Co.,Ltd. +# Subject: CN=vTrus Root CA O=iTrusChina Co.,Ltd. +# Label: "vTrus Root CA" +# Serial: 387574501246983434957692974888460947164905180485 +# MD5 Fingerprint: b8:c9:37:df:fa:6b:31:84:64:c5:ea:11:6a:1b:75:fc +# SHA1 Fingerprint: 84:1a:69:fb:f5:cd:1a:25:34:13:3d:e3:f8:fc:b8:99:d0:c9:14:b7 +# SHA256 Fingerprint: 8a:71:de:65:59:33:6f:42:6c:26:e5:38:80:d0:0d:88:a1:8d:a4:c6:a9:1f:0d:cb:61:94:e2:06:c5:c9:63:87 +-----BEGIN CERTIFICATE----- +MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL +BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x +FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx +MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s +THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc +IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU +AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+ +GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9 +8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH +flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt +J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim +0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN +pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ +UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW +OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB +AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet +8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd +nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j +bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM +Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv +TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS +S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr +I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9 +b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB +UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P +Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven +sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s= +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X2 O=Internet Security Research Group +# Subject: CN=ISRG Root X2 O=Internet Security Research Group +# Label: "ISRG Root X2" +# Serial: 87493402998870891108772069816698636114 +# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5 +# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af +# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70 +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- + +# Issuer: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. +# Subject: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. +# Label: "HiPKI Root CA - G1" +# Serial: 60966262342023497858655262305426234976 +# MD5 Fingerprint: 69:45:df:16:65:4b:e8:68:9a:8f:76:5f:ff:80:9e:d3 +# SHA1 Fingerprint: 6a:92:e4:a8:ee:1b:ec:96:45:37:e3:29:57:49:cd:96:e3:e5:d2:60 +# SHA256 Fingerprint: f0:15:ce:3c:c2:39:bf:ef:06:4b:e9:f1:d2:c4:17:e1:a0:26:4a:0a:94:be:1f:0c:8d:12:18:64:eb:69:49:cc +-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa +Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 +YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw +qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv +Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 +lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz +Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ +KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK +FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj +HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr +y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ +/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM +a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 +fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG +SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc +SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza +ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc +XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg +iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho +L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF +Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr +kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ +vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU +YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Label: "GlobalSign ECC Root CA - R4" +# Serial: 159662223612894884239637590694 +# MD5 Fingerprint: 26:29:f8:6d:e1:88:bf:a2:65:7f:aa:c4:cd:0f:7f:fc +# SHA1 Fingerprint: 6b:a0:b0:98:e1:71:ef:5a:ad:fe:48:15:80:77:10:f4:bd:6f:0b:28 +# SHA256 Fingerprint: b0:85:d7:0b:96:4f:19:1a:73:e4:af:0d:54:ae:7a:0e:07:aa:fd:af:9b:71:dd:08:62:13:8a:b7:32:5a:24:a2 +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD +VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw +MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g +UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx +uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV +HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ ++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 +bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R1 O=Google Trust Services LLC +# Subject: CN=GTS Root R1 O=Google Trust Services LLC +# Label: "GTS Root R1" +# Serial: 159662320309726417404178440727 +# MD5 Fingerprint: 05:fe:d0:bf:71:a8:a3:76:63:da:01:e0:d8:52:dc:40 +# SHA1 Fingerprint: e5:8c:1c:c4:91:3b:38:63:4b:e9:10:6e:e3:ad:8e:6b:9d:d9:81:4a +# SHA256 Fingerprint: d9:47:43:2a:bd:e7:b7:fa:90:fc:2e:6b:59:10:1b:12:80:e0:e1:c7:e4:e4:0f:a3:c6:88:7f:ff:57:a7:f4:cf +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R2 O=Google Trust Services LLC +# Subject: CN=GTS Root R2 O=Google Trust Services LLC +# Label: "GTS Root R2" +# Serial: 159662449406622349769042896298 +# MD5 Fingerprint: 1e:39:c0:53:e6:1e:29:82:0b:ca:52:55:36:5d:57:dc +# SHA1 Fingerprint: 9a:44:49:76:32:db:de:fa:d0:bc:fb:5a:7b:17:bd:9e:56:09:24:94 +# SHA256 Fingerprint: 8d:25:cd:97:22:9d:bf:70:35:6b:da:4e:b3:cc:73:40:31:e2:4c:f0:0f:af:cf:d3:2d:c7:6e:b5:84:1c:7e:a8 +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt +nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY +6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu +MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k +RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg +f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV ++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo +dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa +G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq +gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H +vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC +B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u +NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg +yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev +HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 +xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR +TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg +JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV +7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl +6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R3 O=Google Trust Services LLC +# Subject: CN=GTS Root R3 O=Google Trust Services LLC +# Label: "GTS Root R3" +# Serial: 159662495401136852707857743206 +# MD5 Fingerprint: 3e:e7:9d:58:02:94:46:51:94:e5:e0:22:4a:8b:e7:73 +# SHA1 Fingerprint: ed:e5:71:80:2b:c8:92:b9:5b:83:3c:d2:32:68:3f:09:cd:a0:1e:46 +# SHA256 Fingerprint: 34:d8:a7:3e:e2:08:d9:bc:db:0d:95:65:20:93:4b:4e:40:e6:94:82:59:6e:8b:6f:73:c8:42:6b:01:0a:6f:48 +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G +jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 +4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 +VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm +ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R4 O=Google Trust Services LLC +# Subject: CN=GTS Root R4 O=Google Trust Services LLC +# Label: "GTS Root R4" +# Serial: 159662532700760215368942768210 +# MD5 Fingerprint: 43:96:83:77:19:4d:76:b3:9d:65:52:e4:1d:22:a5:e8 +# SHA1 Fingerprint: 77:d3:03:67:b5:e0:0c:15:f6:0c:38:61:df:7c:e1:3b:92:46:4d:47 +# SHA256 Fingerprint: 34:9d:fa:40:58:c5:e2:63:12:3b:39:8a:e7:95:57:3c:4e:13:13:c8:3f:e6:8f:93:55:6c:d5:e8:03:1b:3c:7d +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE----- + +# Issuer: CN=Telia Root CA v2 O=Telia Finland Oyj +# Subject: CN=Telia Root CA v2 O=Telia Finland Oyj +# Label: "Telia Root CA v2" +# Serial: 7288924052977061235122729490515358 +# MD5 Fingerprint: 0e:8f:ac:aa:82:df:85:b1:f4:dc:10:1c:fc:99:d9:48 +# SHA1 Fingerprint: b9:99:cd:d1:73:50:8a:c4:47:05:08:9c:8c:88:fb:be:a0:2b:40:cd +# SHA256 Fingerprint: 24:2b:69:74:2f:cb:1e:5b:2a:bf:98:89:8b:94:57:21:87:54:4e:5b:4d:99:11:78:65:73:62:1f:6a:74:b8:2c +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx +CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE +AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 +NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ +MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq +AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 +vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 +lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD +n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT +7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o +6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC +TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 +WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R +DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI +pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj +YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy +rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi +0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM +A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS +SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K +TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF +6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er +3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt +Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT +VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW +ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA +rBPuUBQemMc= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH +# Subject: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH +# Label: "D-TRUST BR Root CA 1 2020" +# Serial: 165870826978392376648679885835942448534 +# MD5 Fingerprint: b5:aa:4b:d5:ed:f7:e3:55:2e:8f:72:0a:f3:75:b8:ed +# SHA1 Fingerprint: 1f:5b:98:f0:e3:b5:f7:74:3c:ed:e6:b0:36:7d:32:cd:f4:09:41:67 +# SHA256 Fingerprint: e5:9a:aa:81:60:09:c2:2b:ff:5b:25:ba:d3:7d:f3:06:f0:49:79:7c:1f:81:d8:5a:b0:89:e6:57:bd:8f:00:44 +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 +NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS +zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 +QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ +VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW +wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV +dWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH +# Subject: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH +# Label: "D-TRUST EV Root CA 1 2020" +# Serial: 126288379621884218666039612629459926992 +# MD5 Fingerprint: 8c:2d:9d:70:9f:48:99:11:06:11:fb:e9:cb:30:c0:6e +# SHA1 Fingerprint: 61:db:8c:21:59:69:03:90:d8:7c:9c:12:86:54:cf:9d:3d:f4:dd:07 +# SHA256 Fingerprint: 08:17:0d:1a:a3:64:53:90:1a:2f:95:92:45:e3:47:db:0c:8d:37:ab:aa:bc:56:b8:1a:a1:00:dc:95:89:70:db +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 +NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC +/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD +wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 +OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA +y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb +gfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE----- diff --git a/dist/ba_data/python-site-packages/certifi/core.py b/dist/ba_data/python-site-packages/certifi/core.py new file mode 100644 index 0000000..497d938 --- /dev/null +++ b/dist/ba_data/python-site-packages/certifi/core.py @@ -0,0 +1,68 @@ +""" +certifi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem or its contents. +""" +import os +import types +from typing import Union + +try: + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + + return _CACERT_PATH + + +except ImportError: + Package = Union[types.ModuleType, str] + Resource = Union[str, "os.PathLike"] + + # This fallback will work for Python versions prior to 3.7 that lack the + # importlib.resources module but relies on the existing `where` function + # so won't address issues with environments like PyOxidizer that don't set + # __file__ on modules. + def read_text( + package: Package, + resource: Resource, + encoding: str = 'utf-8', + errors: str = 'strict' + ) -> str: + with open(where(), encoding=encoding) as data: + return data.read() + + # If we don't have importlib.resources, then we will just do the old logic + # of assuming we're on the filesystem and munge the path directly. + def where() -> str: + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") + + +def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/dist/ba_data/python-site-packages/typing_extensions.py b/dist/ba_data/python-site-packages/typing_extensions.py index 95bb873..dc03881 100644 --- a/dist/ba_data/python-site-packages/typing_extensions.py +++ b/dist/ba_data/python-site-packages/typing_extensions.py @@ -1,115 +1,11 @@ import abc import collections -import contextlib -import sys -import typing -import collections.abc as collections_abc +import collections.abc +import functools import operator - -# These are used by Protocol implementation -# We use internal typing helpers here, but this significantly reduces -# code duplication. (Also this is only until Protocol is in typing.) -from typing import Generic, Callable, TypeVar, Tuple - -# After PEP 560, internal typing API was substantially reworked. -# This is especially important for Protocol class which uses internal APIs -# quite extensivelly. -PEP_560 = sys.version_info[:3] >= (3, 7, 0) - -if PEP_560: - GenericMeta = TypingMeta = type - from typing import _GenericAlias -else: - from typing import GenericMeta, TypingMeta -OLD_GENERICS = False -try: - from typing import _type_vars, _next_in_mro, _type_check -except ImportError: - OLD_GENERICS = True -try: - from typing import _subs_tree # noqa - SUBS_TREE = True -except ImportError: - SUBS_TREE = False -try: - from typing import _tp_cache -except ImportError: - def _tp_cache(x): - return x -try: - from typing import _TypingEllipsis, _TypingEmpty -except ImportError: - class _TypingEllipsis: - pass - - class _TypingEmpty: - pass - - -# The two functions below are copies of typing internal helpers. -# They are needed by _ProtocolMeta - - -def _no_slots_copy(dct): - dict_copy = dict(dct) - if '__slots__' in dict_copy: - for slot in dict_copy['__slots__']: - dict_copy.pop(slot, None) - return dict_copy - - -def _check_generic(cls, parameters): - if not cls.__parameters__: - raise TypeError("%s is not a generic class" % repr(cls)) - alen = len(parameters) - elen = len(cls.__parameters__) - if alen != elen: - raise TypeError("Too %s parameters for %s; actual %s, expected %s" % - ("many" if alen > elen else "few", repr(cls), alen, elen)) - - -if hasattr(typing, '_generic_new'): - _generic_new = typing._generic_new -else: - # Note: The '_generic_new(...)' function is used as a part of the - # process of creating a generic type and was added to the typing module - # as of Python 3.5.3. - # - # We've defined '_generic_new(...)' below to exactly match the behavior - # implemented in older versions of 'typing' bundled with Python 3.5.0 to - # 3.5.2. This helps eliminate redundancy when defining collection types - # like 'Deque' later. - # - # See https://github.com/python/typing/pull/308 for more details -- in - # particular, compare and contrast the definition of types like - # 'typing.List' before and after the merge. - - def _generic_new(base_cls, cls, *args, **kwargs): - return base_cls.__new__(cls, *args, **kwargs) - -# See https://github.com/python/typing/pull/439 -if hasattr(typing, '_geqv'): - from typing import _geqv - _geqv_defined = True -else: - _geqv = None - _geqv_defined = False - -if sys.version_info[:2] >= (3, 6): - import _collections_abc - _check_methods_in_mro = _collections_abc._check_methods -else: - def _check_methods_in_mro(C, *methods): - mro = C.__mro__ - for method in methods: - for B in mro: - if method in B.__dict__: - if B.__dict__[method] is None: - return NotImplemented - break - else: - return NotImplemented - return True +import sys +import types as _types +import typing # Please keep __all__ alphabetized within each category. @@ -118,19 +14,23 @@ __all__ = [ 'ClassVar', 'Concatenate', 'Final', + 'LiteralString', 'ParamSpec', + 'ParamSpecArgs', + 'ParamSpecKwargs', + 'Self', 'Type', + 'TypeVarTuple', + 'Unpack', # ABCs (from collections.abc). - # The following are added depending on presence - # of their non-generic counterparts in stdlib: - # 'Awaitable', - # 'AsyncIterator', - # 'AsyncIterable', - # 'Coroutine', - # 'AsyncGenerator', - # 'AsyncContextManager', - # 'ChainMap', + 'Awaitable', + 'AsyncIterator', + 'AsyncIterable', + 'Coroutine', + 'AsyncGenerator', + 'AsyncContextManager', + 'ChainMap', # Concrete collection types. 'ContextManager', @@ -144,85 +44,101 @@ __all__ = [ 'SupportsIndex', # One-off things. + 'Annotated', + 'assert_never', + 'assert_type', + 'clear_overloads', + 'dataclass_transform', + 'get_overloads', 'final', + 'get_args', + 'get_origin', + 'get_type_hints', 'IntVar', + 'is_typeddict', 'Literal', 'NewType', 'overload', + 'Protocol', + 'reveal_type', + 'runtime', + 'runtime_checkable', 'Text', 'TypeAlias', 'TypeGuard', 'TYPE_CHECKING', + 'Never', + 'NoReturn', + 'Required', + 'NotRequired', ] -# Annotated relies on substitution trees of pep 560. It will not work for -# versions of typing older than 3.5.3 -HAVE_ANNOTATED = PEP_560 or SUBS_TREE +# for backward compatibility +PEP_560 = True +GenericMeta = type -if PEP_560: - __all__.extend(["get_args", "get_origin", "get_type_hints"]) +# The functions below are modified copies of typing internal helpers. +# They are needed by _ProtocolMeta and they provide support for PEP 646. -if HAVE_ANNOTATED: - __all__.append("Annotated") - -# Protocols are hard to backport to the original version of typing 3.5.0 -HAVE_PROTOCOLS = sys.version_info[:3] != (3, 5, 0) - -if HAVE_PROTOCOLS: - __all__.extend(['Protocol', 'runtime', 'runtime_checkable']) +_marker = object() -# TODO -if hasattr(typing, 'NoReturn'): - NoReturn = typing.NoReturn -elif hasattr(typing, '_FinalTypingBase'): - class _NoReturn(typing._FinalTypingBase, _root=True): - """Special type indicating functions that never return. - Example:: +def _check_generic(cls, parameters, elen=_marker): + """Check correct count for parameters of a generic cls (internal helper). + This gives a nice error message in case of count mismatch. + """ + if not elen: + raise TypeError(f"{cls} is not a generic class") + if elen is _marker: + if not hasattr(cls, "__parameters__") or not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + elen = len(cls.__parameters__) + alen = len(parameters) + if alen != elen: + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) + if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): + return + raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};" + f" actual {alen}, expected {elen}") - from typing import NoReturn - def stop() -> NoReturn: - raise Exception('no way') - - This type is invalid in other positions, e.g., ``List[NoReturn]`` - will fail in static type checkers. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("NoReturn cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("NoReturn cannot be used with issubclass().") - - NoReturn = _NoReturn(_root=True) +if sys.version_info >= (3, 10): + def _should_collect_from_parameters(t): + return isinstance( + t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) + ) +elif sys.version_info >= (3, 9): + def _should_collect_from_parameters(t): + return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) else: - class _NoReturnMeta(typing.TypingMeta): - """Metaclass for NoReturn""" - def __new__(cls, name, bases, namespace, _root=False): - return super().__new__(cls, name, bases, namespace, _root=_root) + def _should_collect_from_parameters(t): + return isinstance(t, typing._GenericAlias) and not t._special - def __instancecheck__(self, obj): - raise TypeError("NoReturn cannot be used with isinstance().") - def __subclasscheck__(self, cls): - raise TypeError("NoReturn cannot be used with issubclass().") +def _collect_type_vars(types, typevar_types=None): + """Collect all type variable contained in types in order of + first appearance (lexicographic order). For example:: - class NoReturn(typing.Final, metaclass=_NoReturnMeta, _root=True): - """Special type indicating functions that never return. - Example:: + _collect_type_vars((T, List[S, T])) == (T, S) + """ + if typevar_types is None: + typevar_types = typing.TypeVar + tvars = [] + for t in types: + if ( + isinstance(t, typevar_types) and + t not in tvars and + not _is_unpack(t) + ): + tvars.append(t) + if _should_collect_from_parameters(t): + tvars.extend([t for t in t.__parameters__ if t not in tvars]) + return tuple(tvars) - from typing import NoReturn - - def stop() -> NoReturn: - raise Exception('no way') - - This type is invalid in other positions, e.g., ``List[NoReturn]`` - will fail in static type checkers. - """ - __slots__ = () +NoReturn = typing.NoReturn # Some unconstrained type variables. These are used by the container types. # (These are not for export.) @@ -230,143 +146,16 @@ T = typing.TypeVar('T') # Any type. KT = typing.TypeVar('KT') # Key type. VT = typing.TypeVar('VT') # Value type. T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. -V_co = typing.TypeVar('V_co', covariant=True) # Any type covariant containers. -VT_co = typing.TypeVar('VT_co', covariant=True) # Value type covariant containers. T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. - -if hasattr(typing, 'ClassVar'): - ClassVar = typing.ClassVar -elif hasattr(typing, '_FinalTypingBase'): - class _ClassVar(typing._FinalTypingBase, _root=True): - """Special type construct to mark class variables. - - An annotation wrapped in ClassVar indicates that a given - attribute is intended to be used as a class variable and - should not be set on instances of that class. Usage:: - - class Starship: - stats: ClassVar[Dict[str, int]] = {} # class variable - damage: int = 10 # instance variable - - ClassVar accepts only types and cannot be further subscribed. - - Note that ClassVar is not a class itself, and should not - be used with isinstance() or issubclass(). - """ - - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - '{} accepts only single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _ClassVar): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - ClassVar = _ClassVar(_root=True) -else: - class _ClassVarMeta(typing.TypingMeta): - """Metaclass for ClassVar""" - - def __new__(cls, name, bases, namespace, tp=None, _root=False): - self = super().__new__(cls, name, bases, namespace, _root=_root) - if tp is not None: - self.__type__ = tp - return self - - def __instancecheck__(self, obj): - raise TypeError("ClassVar cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("ClassVar cannot be used with issubclass().") - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is not None: - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - param = typing._type_check( - item, - '{} accepts only single type.'.format(cls.__name__[1:])) - return cls(self.__name__, self.__bases__, - dict(self.__dict__), tp=param, _root=True) - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(self.__name__, self.__bases__, - dict(self.__dict__), tp=self.__type__, - _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, ClassVar): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - class ClassVar(typing.Final, metaclass=_ClassVarMeta, _root=True): - """Special type construct to mark class variables. - - An annotation wrapped in ClassVar indicates that a given - attribute is intended to be used as a class variable and - should not be set on instances of that class. Usage:: - - class Starship: - stats: ClassVar[Dict[str, int]] = {} # class variable - damage: int = 10 # instance variable - - ClassVar accepts only types and cannot be further subscribed. - - Note that ClassVar is not a class itself, and should not - be used with isinstance() or issubclass(). - """ - - __type__ = None +ClassVar = typing.ClassVar # On older versions of typing there is an internal class named "Final". +# 3.8+ if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): Final = typing.Final -elif sys.version_info[:2] >= (3, 7): +# 3.7 +else: class _FinalForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -374,8 +163,8 @@ elif sys.version_info[:2] >= (3, 7): def __getitem__(self, parameters): item = typing._type_check(parameters, - '{} accepts only single type'.format(self._name)) - return _GenericAlias(self, (item,)) + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) Final = _FinalForm('Final', doc="""A special typing construct to indicate that a name @@ -391,134 +180,13 @@ elif sys.version_info[:2] >= (3, 7): TIMEOUT = 1 # Error reported by type checker There is no runtime checking of these properties.""") -elif hasattr(typing, '_FinalTypingBase'): - class _Final(typing._FinalTypingBase, _root=True): - """A special typing construct to indicate that a name - cannot be re-assigned or overridden in a subclass. - For example: - MAX_SIZE: Final = 9000 - MAX_SIZE += 1 # Error reported by type checker - - class Connection: - TIMEOUT: Final[int] = 10 - class FastConnector(Connection): - TIMEOUT = 1 # Error reported by type checker - - There is no runtime checking of these properties. - """ - - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - '{} accepts only single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _Final): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - Final = _Final(_root=True) -else: - class _FinalMeta(typing.TypingMeta): - """Metaclass for Final""" - - def __new__(cls, name, bases, namespace, tp=None, _root=False): - self = super().__new__(cls, name, bases, namespace, _root=_root) - if tp is not None: - self.__type__ = tp - return self - - def __instancecheck__(self, obj): - raise TypeError("Final cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Final cannot be used with issubclass().") - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is not None: - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - param = typing._type_check( - item, - '{} accepts only single type.'.format(cls.__name__[1:])) - return cls(self.__name__, self.__bases__, - dict(self.__dict__), tp=param, _root=True) - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(self.__name__, self.__bases__, - dict(self.__dict__), tp=self.__type__, - _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, Final): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - class Final(typing.Final, metaclass=_FinalMeta, _root=True): - """A special typing construct to indicate that a name - cannot be re-assigned or overridden in a subclass. - For example: - - MAX_SIZE: Final = 9000 - MAX_SIZE += 1 # Error reported by type checker - - class Connection: - TIMEOUT: Final[int] = 10 - class FastConnector(Connection): - TIMEOUT = 1 # Error reported by type checker - - There is no runtime checking of these properties. - """ - - __type__ = None - - -if hasattr(typing, 'final'): +if sys.version_info >= (3, 11): final = typing.final else: + # @final exists in 3.8+, but we backport it for all versions + # before 3.11 to keep support for the __final__ attribute. + # See https://bugs.python.org/issue46342 def final(f): """This decorator can be used to indicate to type checkers that the decorated method cannot be overridden, and decorated class @@ -537,25 +205,36 @@ else: class Other(Leaf): # Error reported by type checker ... - There is no runtime checking of these properties. + There is no runtime checking of these properties. The decorator + sets the ``__final__`` attribute to ``True`` on the decorated object + to allow runtime introspection. """ + try: + f.__final__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass return f def IntVar(name): - return TypeVar(name) + return typing.TypeVar(name) +# 3.8+: if hasattr(typing, 'Literal'): Literal = typing.Literal -elif sys.version_info[:2] >= (3, 7): +# 3.7: +else: class _LiteralForm(typing._SpecialForm, _root=True): def __repr__(self): return 'typing_extensions.' + self._name def __getitem__(self, parameters): - return _GenericAlias(self, parameters) + return typing._GenericAlias(self, parameters) Literal = _LiteralForm('Literal', doc="""A type that can be used to indicate to type checkers @@ -570,555 +249,106 @@ elif sys.version_info[:2] >= (3, 7): Literal[...] cannot be subclassed. There is no runtime checking verifying that the parameter is actually a value instead of a type.""") -elif hasattr(typing, '_FinalTypingBase'): - class _Literal(typing._FinalTypingBase, _root=True): - """A type that can be used to indicate to type checkers that the - corresponding value has a value literally equivalent to the - provided parameter. For example: - var: Literal[4] = 4 - The type checker understands that 'var' is literally equal to the - value 4 and no other value. +_overload_dummy = typing._overload_dummy # noqa - Literal[...] cannot be subclassed. There is no runtime checking - verifying that the parameter is actually a value instead of a type. - """ - __slots__ = ('__values__',) - - def __init__(self, values=None, **kwds): - self.__values__ = values - - def __getitem__(self, values): - cls = type(self) - if self.__values__ is None: - if not isinstance(values, tuple): - values = (values,) - return cls(values, _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - return self - - def __repr__(self): - r = super().__repr__() - if self.__values__ is not None: - r += '[{}]'.format(', '.join(map(typing._type_repr, self.__values__))) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__values__)) - - def __eq__(self, other): - if not isinstance(other, _Literal): - return NotImplemented - if self.__values__ is not None: - return self.__values__ == other.__values__ - return self is other - - Literal = _Literal(_root=True) +if hasattr(typing, "get_overloads"): # 3.11+ + overload = typing.overload + get_overloads = typing.get_overloads + clear_overloads = typing.clear_overloads else: - class _LiteralMeta(typing.TypingMeta): - """Metaclass for Literal""" + # {module: {qualname: {firstlineno: func}}} + _overload_registry = collections.defaultdict( + functools.partial(collections.defaultdict, dict) + ) - def __new__(cls, name, bases, namespace, values=None, _root=False): - self = super().__new__(cls, name, bases, namespace, _root=_root) - if values is not None: - self.__values__ = values - return self + def overload(func): + """Decorator for overloaded functions/methods. - def __instancecheck__(self, obj): - raise TypeError("Literal cannot be used with isinstance().") + In a stub file, place two or more stub definitions for the same + function in a row, each decorated with @overload. For example: - def __subclasscheck__(self, cls): - raise TypeError("Literal cannot be used with issubclass().") + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... - def __getitem__(self, item): - cls = type(self) - if self.__values__ is not None: - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) + In a non-stub file (i.e. a regular .py file), do the same but + follow it with an implementation. The implementation should *not* + be decorated with @overload. For example: - if not isinstance(item, tuple): - item = (item,) - return cls(self.__name__, self.__bases__, - dict(self.__dict__), values=item, _root=True) + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + def utf8(value): + # implementation goes here - def _eval_type(self, globalns, localns): - return self - - def __repr__(self): - r = super().__repr__() - if self.__values__ is not None: - r += '[{}]'.format(', '.join(map(typing._type_repr, self.__values__))) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__values__)) - - def __eq__(self, other): - if not isinstance(other, Literal): - return NotImplemented - if self.__values__ is not None: - return self.__values__ == other.__values__ - return self is other - - class Literal(typing.Final, metaclass=_LiteralMeta, _root=True): - """A type that can be used to indicate to type checkers that the - corresponding value has a value literally equivalent to the - provided parameter. For example: - - var: Literal[4] = 4 - - The type checker understands that 'var' is literally equal to the - value 4 and no other value. - - Literal[...] cannot be subclassed. There is no runtime checking - verifying that the parameter is actually a value instead of a type. + The overloads for a function can be retrieved at runtime using the + get_overloads() function. """ + # classmethod and staticmethod + f = getattr(func, "__func__", func) + try: + _overload_registry[f.__module__][f.__qualname__][ + f.__code__.co_firstlineno + ] = func + except AttributeError: + # Not a normal function; ignore. + pass + return _overload_dummy - __values__ = None + def get_overloads(func): + """Return all defined overloads for *func* as a sequence.""" + # classmethod and staticmethod + f = getattr(func, "__func__", func) + if f.__module__ not in _overload_registry: + return [] + mod_dict = _overload_registry[f.__module__] + if f.__qualname__ not in mod_dict: + return [] + return list(mod_dict[f.__qualname__].values()) - -def _overload_dummy(*args, **kwds): - """Helper for @overload to raise when called.""" - raise NotImplementedError( - "You should not call an overloaded function. " - "A series of @overload-decorated functions " - "outside a stub module should always be followed " - "by an implementation that is not @overload-ed.") - - -def overload(func): - """Decorator for overloaded functions/methods. - - In a stub file, place two or more stub definitions for the same - function in a row, each decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - - In a non-stub file (i.e. a regular .py file), do the same but - follow it with an implementation. The implementation should *not* - be decorated with @overload. For example: - - @overload - def utf8(value: None) -> None: ... - @overload - def utf8(value: bytes) -> bytes: ... - @overload - def utf8(value: str) -> bytes: ... - def utf8(value): - # implementation goes here - """ - return _overload_dummy + def clear_overloads(): + """Clear all overloads in the registry.""" + _overload_registry.clear() # This is not a real generic class. Don't use outside annotations. -if hasattr(typing, 'Type'): - Type = typing.Type -else: - # Internal type variable used for Type[]. - CT_co = typing.TypeVar('CT_co', covariant=True, bound=type) - - class Type(typing.Generic[CT_co], extra=type): - """A special construct usable to annotate class objects. - - For example, suppose we have the following classes:: - - class User: ... # Abstract base for User classes - class BasicUser(User): ... - class ProUser(User): ... - class TeamUser(User): ... - - And a function that takes a class argument that's a subclass of - User and returns an instance of the corresponding class:: - - U = TypeVar('U', bound=User) - def new_user(user_class: Type[U]) -> U: - user = user_class() - # (Here we could write the user object to a database) - return user - joe = new_user(BasicUser) - - At this point the type checker knows that joe has type BasicUser. - """ - - __slots__ = () - +Type = typing.Type # Various ABCs mimicking those in collections.abc. # A few are simply re-exported for completeness. -def _define_guard(type_name): - """ - Returns True if the given type isn't defined in typing but - is defined in collections_abc. - - Adds the type to __all__ if the collection is found in either - typing or collection_abc. - """ - if hasattr(typing, type_name): - __all__.append(type_name) - globals()[type_name] = getattr(typing, type_name) - return False - elif hasattr(collections_abc, type_name): - __all__.append(type_name) - return True - else: - return False - - -class _ExtensionsGenericMeta(GenericMeta): - def __subclasscheck__(self, subclass): - """This mimics a more modern GenericMeta.__subclasscheck__() logic - (that does not have problems with recursion) to work around interactions - between collections, typing, and typing_extensions on older - versions of Python, see https://github.com/python/typing/issues/501. - """ - if sys.version_info[:3] >= (3, 5, 3) or sys.version_info[:3] < (3, 5, 0): - if self.__origin__ is not None: - if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - return False - if not self.__extra__: - return super().__subclasscheck__(subclass) - res = self.__extra__.__subclasshook__(subclass) - if res is not NotImplemented: - return res - if self.__extra__ in subclass.__mro__: - return True - for scls in self.__extra__.__subclasses__(): - if isinstance(scls, GenericMeta): - continue - if issubclass(subclass, scls): - return True - return False - - -if _define_guard('Awaitable'): - class Awaitable(typing.Generic[T_co], metaclass=_ExtensionsGenericMeta, - extra=collections_abc.Awaitable): - __slots__ = () - - -if _define_guard('Coroutine'): - class Coroutine(Awaitable[V_co], typing.Generic[T_co, T_contra, V_co], - metaclass=_ExtensionsGenericMeta, - extra=collections_abc.Coroutine): - __slots__ = () - - -if _define_guard('AsyncIterable'): - class AsyncIterable(typing.Generic[T_co], - metaclass=_ExtensionsGenericMeta, - extra=collections_abc.AsyncIterable): - __slots__ = () - - -if _define_guard('AsyncIterator'): - class AsyncIterator(AsyncIterable[T_co], - metaclass=_ExtensionsGenericMeta, - extra=collections_abc.AsyncIterator): - __slots__ = () - - -if hasattr(typing, 'Deque'): - Deque = typing.Deque -elif _geqv_defined: - class Deque(collections.deque, typing.MutableSequence[T], - metaclass=_ExtensionsGenericMeta, - extra=collections.deque): - __slots__ = () - - def __new__(cls, *args, **kwds): - if _geqv(cls, Deque): - return collections.deque(*args, **kwds) - return _generic_new(collections.deque, cls, *args, **kwds) -else: - class Deque(collections.deque, typing.MutableSequence[T], - metaclass=_ExtensionsGenericMeta, - extra=collections.deque): - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Deque: - return collections.deque(*args, **kwds) - return _generic_new(collections.deque, cls, *args, **kwds) - - -if hasattr(typing, 'ContextManager'): - ContextManager = typing.ContextManager -elif hasattr(contextlib, 'AbstractContextManager'): - class ContextManager(typing.Generic[T_co], - metaclass=_ExtensionsGenericMeta, - extra=contextlib.AbstractContextManager): - __slots__ = () -else: - class ContextManager(typing.Generic[T_co]): - __slots__ = () - - def __enter__(self): - return self - - @abc.abstractmethod - def __exit__(self, exc_type, exc_value, traceback): - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is ContextManager: - # In Python 3.6+, it is possible to set a method to None to - # explicitly indicate that the class does not implement an ABC - # (https://bugs.python.org/issue25958), but we do not support - # that pattern here because this fallback class is only used - # in Python 3.5 and earlier. - if (any("__enter__" in B.__dict__ for B in C.__mro__) and - any("__exit__" in B.__dict__ for B in C.__mro__)): - return True - return NotImplemented - - -if hasattr(typing, 'AsyncContextManager'): - AsyncContextManager = typing.AsyncContextManager - __all__.append('AsyncContextManager') -elif hasattr(contextlib, 'AbstractAsyncContextManager'): - class AsyncContextManager(typing.Generic[T_co], - metaclass=_ExtensionsGenericMeta, - extra=contextlib.AbstractAsyncContextManager): - __slots__ = () - - __all__.append('AsyncContextManager') -elif sys.version_info[:2] >= (3, 5): - exec(""" -class AsyncContextManager(typing.Generic[T_co]): - __slots__ = () - - async def __aenter__(self): - return self - - @abc.abstractmethod - async def __aexit__(self, exc_type, exc_value, traceback): - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is AsyncContextManager: - return _check_methods_in_mro(C, "__aenter__", "__aexit__") - return NotImplemented - -__all__.append('AsyncContextManager') -""") - - -if hasattr(typing, 'DefaultDict'): - DefaultDict = typing.DefaultDict -elif _geqv_defined: - class DefaultDict(collections.defaultdict, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.defaultdict): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if _geqv(cls, DefaultDict): - return collections.defaultdict(*args, **kwds) - return _generic_new(collections.defaultdict, cls, *args, **kwds) -else: - class DefaultDict(collections.defaultdict, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.defaultdict): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is DefaultDict: - return collections.defaultdict(*args, **kwds) - return _generic_new(collections.defaultdict, cls, *args, **kwds) +Awaitable = typing.Awaitable +Coroutine = typing.Coroutine +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator +Deque = typing.Deque +ContextManager = typing.ContextManager +AsyncContextManager = typing.AsyncContextManager +DefaultDict = typing.DefaultDict +# 3.7.2+ if hasattr(typing, 'OrderedDict'): OrderedDict = typing.OrderedDict -elif (3, 7, 0) <= sys.version_info[:3] < (3, 7, 2): +# 3.7.0-3.7.2 +else: OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) -elif _geqv_defined: - class OrderedDict(collections.OrderedDict, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.OrderedDict): - __slots__ = () - - def __new__(cls, *args, **kwds): - if _geqv(cls, OrderedDict): - return collections.OrderedDict(*args, **kwds) - return _generic_new(collections.OrderedDict, cls, *args, **kwds) -else: - class OrderedDict(collections.OrderedDict, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.OrderedDict): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is OrderedDict: - return collections.OrderedDict(*args, **kwds) - return _generic_new(collections.OrderedDict, cls, *args, **kwds) - - -if hasattr(typing, 'Counter'): - Counter = typing.Counter -elif (3, 5, 0) <= sys.version_info[:3] <= (3, 5, 1): - assert _geqv_defined - _TInt = typing.TypeVar('_TInt') - - class _CounterMeta(typing.GenericMeta): - """Metaclass for Counter""" - def __getitem__(self, item): - return super().__getitem__((item, int)) - - class Counter(collections.Counter, - typing.Dict[T, int], - metaclass=_CounterMeta, - extra=collections.Counter): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if _geqv(cls, Counter): - return collections.Counter(*args, **kwds) - return _generic_new(collections.Counter, cls, *args, **kwds) - -elif _geqv_defined: - class Counter(collections.Counter, - typing.Dict[T, int], - metaclass=_ExtensionsGenericMeta, extra=collections.Counter): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if _geqv(cls, Counter): - return collections.Counter(*args, **kwds) - return _generic_new(collections.Counter, cls, *args, **kwds) - -else: - class Counter(collections.Counter, - typing.Dict[T, int], - metaclass=_ExtensionsGenericMeta, extra=collections.Counter): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Counter: - return collections.Counter(*args, **kwds) - return _generic_new(collections.Counter, cls, *args, **kwds) - - -if hasattr(typing, 'ChainMap'): - ChainMap = typing.ChainMap - __all__.append('ChainMap') -elif hasattr(collections, 'ChainMap'): - # ChainMap only exists in 3.3+ - if _geqv_defined: - class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.ChainMap): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if _geqv(cls, ChainMap): - return collections.ChainMap(*args, **kwds) - return _generic_new(collections.ChainMap, cls, *args, **kwds) - else: - class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.ChainMap): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is ChainMap: - return collections.ChainMap(*args, **kwds) - return _generic_new(collections.ChainMap, cls, *args, **kwds) - - __all__.append('ChainMap') - - -if _define_guard('AsyncGenerator'): - class AsyncGenerator(AsyncIterator[T_co], typing.Generic[T_co, T_contra], - metaclass=_ExtensionsGenericMeta, - extra=collections_abc.AsyncGenerator): - __slots__ = () - - -if hasattr(typing, 'NewType'): - NewType = typing.NewType -else: - def NewType(name, tp): - """NewType creates simple unique types with almost zero - runtime overhead. NewType(name, tp) is considered a subtype of tp - by static type checkers. At runtime, NewType(name, tp) returns - a dummy function that simply returns its argument. Usage:: - - UserId = NewType('UserId', int) - - def name_by_id(user_id: UserId) -> str: - ... - - UserId('user') # Fails type check - - name_by_id(42) # Fails type check - name_by_id(UserId(42)) # OK - - num = UserId(5) + 1 # type: int - """ - - def new_type(x): - return x - - new_type.__name__ = name - new_type.__supertype__ = tp - return new_type - - -if hasattr(typing, 'Text'): - Text = typing.Text -else: - Text = str - - -if hasattr(typing, 'TYPE_CHECKING'): - TYPE_CHECKING = typing.TYPE_CHECKING -else: - # Constant that's True when type checking, but False here. - TYPE_CHECKING = False - - -def _gorg(cls): - """This function exists for compatibility with old typing versions.""" - assert isinstance(cls, GenericMeta) - if hasattr(cls, '_gorg'): - return cls._gorg - while cls.__origin__ is not None: - cls = cls.__origin__ - return cls - - -if OLD_GENERICS: - def _next_in_mro(cls): # noqa - """This function exists for compatibility with old typing versions.""" - next_in_mro = object - for i, c in enumerate(cls.__mro__[:-1]): - if isinstance(c, GenericMeta) and _gorg(c) is Generic: - next_in_mro = cls.__mro__[i + 1] - return next_in_mro +Counter = typing.Counter +ChainMap = typing.ChainMap +AsyncGenerator = typing.AsyncGenerator +NewType = typing.NewType +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING _PROTO_WHITELIST = ['Callable', 'Awaitable', @@ -1150,257 +380,11 @@ def _is_callable_members_only(cls): return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) +# 3.8+ if hasattr(typing, 'Protocol'): Protocol = typing.Protocol -elif HAVE_PROTOCOLS and not PEP_560: - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - class _ProtocolMeta(GenericMeta): - """Internal metaclass for Protocol. - - This exists so Protocol classes can be generic without deriving - from Generic. - """ - if not OLD_GENERICS: - def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None, orig_bases=None): - # This is just a version copied from GenericMeta.__new__ that - # includes "Protocol" special treatment. (Comments removed for brevity.) - assert extra is None # Protocols should not have extra - if tvars is not None: - assert origin is not None - assert all(isinstance(t, TypeVar) for t in tvars), tvars - else: - tvars = _type_vars(bases) - gvars = None - for base in bases: - if base is Generic: - raise TypeError("Cannot inherit from plain Generic") - if (isinstance(base, GenericMeta) and - base.__origin__ in (Generic, Protocol)): - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...] or" - " Protocol[...] multiple times.") - gvars = base.__parameters__ - if gvars is None: - gvars = tvars - else: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - raise TypeError( - "Some type variables (%s) " - "are not listed in %s[%s]" % - (", ".join(str(t) for t in tvars if t not in gvarset), - "Generic" if any(b.__origin__ is Generic - for b in bases) else "Protocol", - ", ".join(str(g) for g in gvars))) - tvars = gvars - - initial_bases = bases - if (extra is not None and type(extra) is abc.ABCMeta and - extra not in bases): - bases = (extra,) + bases - bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b - for b in bases) - if any(isinstance(b, GenericMeta) and b is not Generic for b in bases): - bases = tuple(b for b in bases if b is not Generic) - namespace.update({'__origin__': origin, '__extra__': extra}) - self = super(GenericMeta, cls).__new__(cls, name, bases, namespace, - _root=True) - super(GenericMeta, self).__setattr__('_gorg', - self if not origin else - _gorg(origin)) - self.__parameters__ = tvars - self.__args__ = tuple(... if a is _TypingEllipsis else - () if a is _TypingEmpty else - a for a in args) if args else None - self.__next_in_mro__ = _next_in_mro(self) - if orig_bases is None: - self.__orig_bases__ = initial_bases - elif origin is not None: - self._abc_registry = origin._abc_registry - self._abc_cache = origin._abc_cache - if hasattr(self, '_subs_tree'): - self.__tree_hash__ = (hash(self._subs_tree()) if origin else - super(GenericMeta, self).__hash__()) - return self - - def __init__(cls, *args, **kwargs): - super().__init__(*args, **kwargs) - if not cls.__dict__.get('_is_protocol', None): - cls._is_protocol = any(b is Protocol or - isinstance(b, _ProtocolMeta) and - b.__origin__ is Protocol - for b in cls.__bases__) - if cls._is_protocol: - for base in cls.__mro__[1:]: - if not (base in (object, Generic) or - base.__module__ == 'collections.abc' and - base.__name__ in _PROTO_WHITELIST or - isinstance(base, TypingMeta) and base._is_protocol or - isinstance(base, GenericMeta) and - base.__origin__ is Generic): - raise TypeError('Protocols can only inherit from other' - ' protocols, got %r' % base) - - cls.__init__ = _no_init - - def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', None): - return NotImplemented - if not isinstance(other, type): - # Same error as for issubclass(1, int) - raise TypeError('issubclass() arg 1 must be a class') - for attr in _get_protocol_attrs(cls): - for base in other.__mro__: - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, typing.Mapping) and - attr in annotations and - isinstance(other, _ProtocolMeta) and - other._is_protocol): - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - def __instancecheck__(self, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if ((not getattr(self, '_is_protocol', False) or - _is_callable_members_only(self)) and - issubclass(instance.__class__, self)): - return True - if self._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(self, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(self)): - return True - return super(GenericMeta, self).__instancecheck__(instance) - - def __subclasscheck__(self, cls): - if self.__origin__ is not None: - if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - return False - if (self.__dict__.get('_is_protocol', None) and - not self.__dict__.get('_is_runtime_protocol', None)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: - return False - raise TypeError("Instance and class checks can only be used with" - " @runtime protocols") - if (self.__dict__.get('_is_runtime_protocol', None) and - not _is_callable_members_only(self)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: - return super(GenericMeta, self).__subclasscheck__(cls) - raise TypeError("Protocols with non-method members" - " don't support issubclass()") - return super(GenericMeta, self).__subclasscheck__(cls) - - if not OLD_GENERICS: - @_tp_cache - def __getitem__(self, params): - # We also need to copy this from GenericMeta.__getitem__ to get - # special treatment of "Protocol". (Comments removed for brevity.) - if not isinstance(params, tuple): - params = (params,) - if not params and _gorg(self) is not Tuple: - raise TypeError( - "Parameter list to %s[...] cannot be empty" % self.__qualname__) - msg = "Parameters to generic types must be types." - params = tuple(_type_check(p, msg) for p in params) - if self in (Generic, Protocol): - if not all(isinstance(p, TypeVar) for p in params): - raise TypeError( - "Parameters to %r[...] must all be type variables" % self) - if len(set(params)) != len(params): - raise TypeError( - "Parameters to %r[...] must all be unique" % self) - tvars = params - args = params - elif self in (Tuple, Callable): - tvars = _type_vars(params) - args = params - elif self.__origin__ in (Generic, Protocol): - raise TypeError("Cannot subscript already-subscripted %s" % - repr(self)) - else: - _check_generic(self, params) - tvars = _type_vars(params) - args = params - - prepend = (self,) if self.__origin__ is None else () - return self.__class__(self.__name__, - prepend + self.__bases__, - _no_slots_copy(self.__dict__), - tvars=tvars, - args=args, - origin=self, - extra=self.__extra__, - orig_bases=self.__orig_bases__) - - class Protocol(metaclass=_ProtocolMeta): - """Base class for protocol classes. Protocol classes are defined as:: - - class Proto(Protocol): - def meth(self) -> int: - ... - - Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: - - class C: - def meth(self) -> int: - return 0 - - def func(x: Proto) -> int: - return x.meth() - - func(C()) # Passes static type check - - See PEP 544 for details. Protocol classes decorated with - @typing_extensions.runtime act as simple-minded runtime protocol that checks - only the presence of given attributes, ignoring their type signatures. - - Protocol classes can be generic, they are defined as:: - - class GenProto({bases}): - def meth(self) -> T: - ... - """ - __slots__ = () - _is_protocol = True - - def __new__(cls, *args, **kwds): - if _gorg(cls) is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can be used only as a base class") - if OLD_GENERICS: - return _generic_new(_next_in_mro(cls), cls, *args, **kwds) - return _generic_new(cls.__next_in_mro__, cls, *args, **kwds) - if Protocol.__doc__ is not None: - Protocol.__doc__ = Protocol.__doc__.format(bases="Protocol, Generic[T]" if - OLD_GENERICS else "Protocol[T]") - - -elif PEP_560: - from typing import _type_check, _collect_type_vars # noqa +# 3.7 +else: def _no_init(self, *args, **kwargs): if type(self)._is_protocol: @@ -1413,14 +397,14 @@ elif PEP_560: # We need this method for situations where attributes are # assigned in __init__. if ((not getattr(cls, '_is_protocol', False) or - _is_callable_members_only(cls)) and + _is_callable_members_only(cls)) and issubclass(instance.__class__, cls)): return True if cls._is_protocol: if all(hasattr(instance, attr) and - (not callable(getattr(cls, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(cls)): + (not callable(getattr(cls, attr, None)) or + getattr(instance, attr) is not None) + for attr in _get_protocol_attrs(cls)): return True return super().__instancecheck__(instance) @@ -1465,42 +449,42 @@ elif PEP_560: "it can only be used as a base class") return super().__new__(cls) - @_tp_cache + @typing._tp_cache def __class_getitem__(cls, params): if not isinstance(params, tuple): params = (params,) - if not params and cls is not Tuple: + if not params and cls is not typing.Tuple: raise TypeError( - "Parameter list to {}[...] cannot be empty".format(cls.__qualname__)) + f"Parameter list to {cls.__qualname__}[...] cannot be empty") msg = "Parameters to generic types must be types." - params = tuple(_type_check(p, msg) for p in params) + params = tuple(typing._type_check(p, msg) for p in params) # noqa if cls is Protocol: # Generic can only be subscripted with unique type variables. - if not all(isinstance(p, TypeVar) for p in params): + if not all(isinstance(p, typing.TypeVar) for p in params): i = 0 - while isinstance(params[i], TypeVar): + while isinstance(params[i], typing.TypeVar): i += 1 raise TypeError( "Parameters to Protocol[...] must all be type variables." - " Parameter {} is {}".format(i + 1, params[i])) + f" Parameter {i + 1} is {params[i]}") if len(set(params)) != len(params): raise TypeError( "Parameters to Protocol[...] must all be unique") else: # Subscripting a regular Generic subclass. - _check_generic(cls, params) - return _GenericAlias(cls, params) + _check_generic(cls, params, len(cls.__parameters__)) + return typing._GenericAlias(cls, params) def __init_subclass__(cls, *args, **kwargs): tvars = [] if '__orig_bases__' in cls.__dict__: - error = Generic in cls.__orig_bases__ + error = typing.Generic in cls.__orig_bases__ else: - error = Generic in cls.__bases__ + error = typing.Generic in cls.__bases__ if error: raise TypeError("Cannot inherit from plain Generic") if '__orig_bases__' in cls.__dict__: - tvars = _collect_type_vars(cls.__orig_bases__) + tvars = typing._collect_type_vars(cls.__orig_bases__) # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. # If found, tvars must be a subset of it. # If not found, tvars is it. @@ -1508,10 +492,10 @@ elif PEP_560: # and reject multiple Generic[...] and/or Protocol[...]. gvars = None for base in cls.__orig_bases__: - if (isinstance(base, _GenericAlias) and - base.__origin__ in (Generic, Protocol)): + if (isinstance(base, typing._GenericAlias) and + base.__origin__ in (typing.Generic, Protocol)): # for error messages - the_base = 'Generic' if base.__origin__ is Generic else 'Protocol' + the_base = base.__origin__.__name__ if gvars is not None: raise TypeError( "Cannot inherit from Generic[...]" @@ -1525,9 +509,8 @@ elif PEP_560: if not tvarset <= gvarset: s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) s_args = ', '.join(str(g) for g in gvars) - raise TypeError("Some type variables ({}) are" - " not listed in {}[{}]".format(s_vars, - the_base, s_args)) + raise TypeError(f"Some type variables ({s_vars}) are" + f" not listed in {the_base}[{s_args}]") tvars = gvars cls.__parameters__ = tuple(tvars) @@ -1576,18 +559,20 @@ elif PEP_560: # Check consistency of bases. for base in cls.__bases__: - if not (base in (object, Generic) or + if not (base in (object, typing.Generic) or base.__module__ == 'collections.abc' and base.__name__ in _PROTO_WHITELIST or isinstance(base, _ProtocolMeta) and base._is_protocol): raise TypeError('Protocols can only inherit from other' - ' protocols, got %r' % base) + f' protocols, got {repr(base)}') cls.__init__ = _no_init +# 3.8+ if hasattr(typing, 'runtime_checkable'): runtime_checkable = typing.runtime_checkable -elif HAVE_PROTOCOLS: +# 3.7 +else: def runtime_checkable(cls): """Mark a protocol class as a runtime protocol, so that it can be used with isinstance() and issubclass(). Raise TypeError @@ -1598,19 +583,20 @@ elif HAVE_PROTOCOLS: """ if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol: raise TypeError('@runtime_checkable can be only applied to protocol classes,' - ' got %r' % cls) + f' got {cls!r}') cls._is_runtime_protocol = True return cls -if HAVE_PROTOCOLS: - # Exists for backwards compatibility. - runtime = runtime_checkable +# Exists for backwards compatibility. +runtime = runtime_checkable +# 3.8+ if hasattr(typing, 'SupportsIndex'): SupportsIndex = typing.SupportsIndex -elif HAVE_PROTOCOLS: +# 3.7 +else: @runtime_checkable class SupportsIndex(Protocol): __slots__ = () @@ -1620,12 +606,16 @@ elif HAVE_PROTOCOLS: pass -if sys.version_info >= (3, 9, 2): +if hasattr(typing, "Required"): # The standard library TypedDict in Python 3.8 does not store runtime information # about which (if any) keys are optional. See https://bugs.python.org/issue38834 # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 + # The standard library TypedDict below Python 3.11 does not store runtime + # information about optional and required keys when using Required or NotRequired. TypedDict = typing.TypedDict + _TypedDictMeta = typing._TypedDictMeta + is_typeddict = typing.is_typeddict else: def _check_fails(cls, other): try: @@ -1665,8 +655,8 @@ else: fields, = args # allow the "_fields" keyword be passed except ValueError: raise TypeError('TypedDict.__new__() takes from 2 to 3 ' - 'positional arguments but {} ' - 'were given'.format(len(args) + 2)) + f'positional arguments but {len(args) + 2} ' + 'were given') elif '_fields' in kwargs and len(kwargs) == 1: fields = kwargs.pop('_fields') import warnings @@ -1695,10 +685,7 @@ else: class _TypedDictMeta(type): def __init__(cls, name, bases, ns, total=True): - # In Python 3.4 and 3.5 the __init__ method also needs to support the - # keyword arguments. - # See https://www.python.org/dev/peps/pep-0487/#implementation-details - super(_TypedDictMeta, cls).__init__(name, bases, ns) + super().__init__(name, bases, ns) def __new__(cls, name, bases, ns, total=True): # Create new typed dict class object. @@ -1708,11 +695,10 @@ else: # Subclasses and instances of TypedDict return actual dictionaries # via _dict_new. ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new - tp_dict = super(_TypedDictMeta, cls).__new__(cls, name, (dict,), ns) + tp_dict = super().__new__(cls, name, (dict,), ns) annotations = {} own_annotations = ns.get('__annotations__', {}) - own_annotation_keys = set(own_annotations.keys()) msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" own_annotations = { n: typing._type_check(tp, msg) for n, tp in own_annotations.items() @@ -1726,10 +712,22 @@ else: optional_keys.update(base.__dict__.get('__optional_keys__', ())) annotations.update(own_annotations) - if total: - required_keys.update(own_annotation_keys) - else: - optional_keys.update(own_annotation_keys) + for annotation_key, annotation_type in own_annotations.items(): + annotation_origin = get_origin(annotation_type) + if annotation_origin is Annotated: + annotation_args = get_args(annotation_type) + if annotation_args: + annotation_type = annotation_args[0] + annotation_origin = get_origin(annotation_type) + + if annotation_origin is Required: + required_keys.add(annotation_key) + elif annotation_origin is NotRequired: + optional_keys.add(annotation_key) + elif total: + required_keys.add(annotation_key) + else: + optional_keys.add(annotation_key) tp_dict.__annotations__ = annotations tp_dict.__required_keys__ = frozenset(required_keys) @@ -1772,15 +770,127 @@ else: syntax forms work for Python 2.7 and 3.2+ """ + if hasattr(typing, "_TypedDictMeta"): + _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) + else: + _TYPEDDICT_TYPES = (_TypedDictMeta,) -# Python 3.9+ has PEP 593 (Annotated and modified get_type_hints) + def is_typeddict(tp): + """Check if an annotation is a TypedDict class + + For example:: + class Film(TypedDict): + title: str + year: int + + is_typeddict(Film) # => True + is_typeddict(Union[list, str]) # => False + """ + return isinstance(tp, tuple(_TYPEDDICT_TYPES)) + + +if hasattr(typing, "assert_type"): + assert_type = typing.assert_type + +else: + def assert_type(__val, __typ): + """Assert (to the type checker) that the value is of the given type. + + When the type checker encounters a call to assert_type(), it + emits an error if the value is not of the specified type:: + + def greet(name: str) -> None: + assert_type(name, str) # ok + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged and otherwise + does nothing. + """ + return __val + + +if hasattr(typing, "Required"): + get_type_hints = typing.get_type_hints +else: + import functools + import types + + # replaces _strip_annotations() + def _strip_extras(t): + """Strips Annotated, Required and NotRequired from a given type.""" + if isinstance(t, _AnnotatedAlias): + return _strip_extras(t.__origin__) + if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired): + return _strip_extras(t.__args__[0]) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return t.copy_with(stripped_args) + if hasattr(types, "GenericAlias") and isinstance(t, types.GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return types.GenericAlias(t.__origin__, stripped_args) + if hasattr(types, "UnionType") and isinstance(t, types.UnionType): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return functools.reduce(operator.or_, stripped_args) + + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' + (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + if hasattr(typing, "Annotated"): + hint = typing.get_type_hints( + obj, globalns=globalns, localns=localns, include_extras=True + ) + else: + hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) + if include_extras: + return hint + return {k: _strip_extras(t) for k, t in hint.items()} + + +# Python 3.9+ has PEP 593 (Annotated) if hasattr(typing, 'Annotated'): Annotated = typing.Annotated - get_type_hints = typing.get_type_hints # Not exported and not a public API, but needed for get_origin() and get_args() # to work. _AnnotatedAlias = typing._AnnotatedAlias -elif PEP_560: +# 3.7-3.8 +else: class _AnnotatedAlias(typing._GenericAlias, _root=True): """Runtime representation of an annotated type. @@ -1802,10 +912,8 @@ elif PEP_560: return _AnnotatedAlias(new_type, self.__metadata__) def __repr__(self): - return "typing_extensions.Annotated[{}, {}]".format( - typing._type_repr(self.__origin__), - ", ".join(repr(a) for a in self.__metadata__) - ) + return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " + f"{', '.join(repr(a) for a in self.__metadata__)}]") def __reduce__(self): return operator.getitem, ( @@ -1860,230 +968,44 @@ elif PEP_560: def __new__(cls, *args, **kwargs): raise TypeError("Type Annotated cannot be instantiated.") - @_tp_cache + @typing._tp_cache def __class_getitem__(cls, params): if not isinstance(params, tuple) or len(params) < 2: raise TypeError("Annotated[...] should be used " "with at least two arguments (a type and an " "annotation).") - msg = "Annotated[t, ...]: t must be a type." - origin = typing._type_check(params[0], msg) + allowed_special_forms = (ClassVar, Final) + if get_origin(params[0]) in allowed_special_forms: + origin = params[0] + else: + msg = "Annotated[t, ...]: t must be a type." + origin = typing._type_check(params[0], msg) metadata = tuple(params[1:]) return _AnnotatedAlias(origin, metadata) def __init_subclass__(cls, *args, **kwargs): raise TypeError( - "Cannot subclass {}.Annotated".format(cls.__module__) + f"Cannot subclass {cls.__module__}.Annotated" ) - def _strip_annotations(t): - """Strips the annotations from a given type. - """ - if isinstance(t, _AnnotatedAlias): - return _strip_annotations(t.__origin__) - if isinstance(t, typing._GenericAlias): - stripped_args = tuple(_strip_annotations(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - res = t.copy_with(stripped_args) - res._special = t._special - return res - return t - - def get_type_hints(obj, globalns=None, localns=None, include_extras=False): - """Return type hints for an object. - - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals, adds Optional[t] if a - default value equal to None is set and recursively replaces all - 'Annotated[T, ...]' with 'T' (unless 'include_extras=True'). - - The argument may be a module, class, method, or function. The annotations - are returned as a dictionary. For classes, annotations include also - inherited members. - - TypeError is raised if the argument is not of a type that can contain - annotations, and an empty dictionary is returned if no annotations are - present. - - BEWARE -- the behavior of globalns and localns is counterintuitive - (unless you are familiar with how eval() and exec() work). The - search order is locals first, then globals. - - - If no dict arguments are passed, an attempt is made to use the - globals from obj (or the respective module's globals for classes), - and these are also used as the locals. If the object does not appear - to have globals, an empty dictionary is used. - - - If one dict argument is passed, it is used for both globals and - locals. - - - If two dict arguments are passed, they specify globals and - locals, respectively. - """ - hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) - if include_extras: - return hint - return {k: _strip_annotations(t) for k, t in hint.items()} - -elif HAVE_ANNOTATED: - - def _is_dunder(name): - """Returns True if name is a __dunder_variable_name__.""" - return len(name) > 4 and name.startswith('__') and name.endswith('__') - - # Prior to Python 3.7 types did not have `copy_with`. A lot of the equality - # checks, argument expansion etc. are done on the _subs_tre. As a result we - # can't provide a get_type_hints function that strips out annotations. - - class AnnotatedMeta(typing.GenericMeta): - """Metaclass for Annotated""" - - def __new__(cls, name, bases, namespace, **kwargs): - if any(b is not object for b in bases): - raise TypeError("Cannot subclass " + str(Annotated)) - return super().__new__(cls, name, bases, namespace, **kwargs) - - @property - def __metadata__(self): - return self._subs_tree()[2] - - def _tree_repr(self, tree): - cls, origin, metadata = tree - if not isinstance(origin, tuple): - tp_repr = typing._type_repr(origin) - else: - tp_repr = origin[0]._tree_repr(origin) - metadata_reprs = ", ".join(repr(arg) for arg in metadata) - return '%s[%s, %s]' % (cls, tp_repr, metadata_reprs) - - def _subs_tree(self, tvars=None, args=None): # noqa - if self is Annotated: - return Annotated - res = super()._subs_tree(tvars=tvars, args=args) - # Flatten nested Annotated - if isinstance(res[1], tuple) and res[1][0] is Annotated: - sub_tp = res[1][1] - sub_annot = res[1][2] - return (Annotated, sub_tp, sub_annot + res[2]) - return res - - def _get_cons(self): - """Return the class used to create instance of this type.""" - if self.__origin__ is None: - raise TypeError("Cannot get the underlying type of a " - "non-specialized Annotated type.") - tree = self._subs_tree() - while isinstance(tree, tuple) and tree[0] is Annotated: - tree = tree[1] - if isinstance(tree, tuple): - return tree[0] - else: - return tree - - @_tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - if self.__origin__ is not None: # specializing an instantiated type - return super().__getitem__(params) - elif not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be instantiated " - "with at least two arguments (a type and an " - "annotation).") - else: - msg = "Annotated[t, ...]: t must be a type." - tp = typing._type_check(params[0], msg) - metadata = tuple(params[1:]) - return self.__class__( - self.__name__, - self.__bases__, - _no_slots_copy(self.__dict__), - tvars=_type_vars((tp,)), - # Metadata is a tuple so it won't be touched by _replace_args et al. - args=(tp, metadata), - origin=self, - ) - - def __call__(self, *args, **kwargs): - cons = self._get_cons() - result = cons(*args, **kwargs) - try: - result.__orig_class__ = self - except AttributeError: - pass - return result - - def __getattr__(self, attr): - # For simplicity we just don't relay all dunder names - if self.__origin__ is not None and not _is_dunder(attr): - return getattr(self._get_cons(), attr) - raise AttributeError(attr) - - def __setattr__(self, attr, value): - if _is_dunder(attr) or attr.startswith('_abc_'): - super().__setattr__(attr, value) - elif self.__origin__ is None: - raise AttributeError(attr) - else: - setattr(self._get_cons(), attr, value) - - def __instancecheck__(self, obj): - raise TypeError("Annotated cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Annotated cannot be used with issubclass().") - - class Annotated(metaclass=AnnotatedMeta): - """Add context specific metadata to a type. - - Example: Annotated[int, runtime_check.Unsigned] indicates to the - hypothetical runtime_check module that this type is an unsigned int. - Every other consumer of this type can ignore this metadata and treat - this type as int. - - The first argument to Annotated must be a valid type, the remaining - arguments are kept as a tuple in the __metadata__ field. - - Details: - - - It's an error to call `Annotated` with less than two arguments. - - Nested Annotated are flattened:: - - Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - - - Instantiating an annotated type is equivalent to instantiating the - underlying type:: - - Annotated[C, Ann1](5) == C(5) - - - Annotated can be used as a generic type alias:: - - Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] - - OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - """ - # Python 3.8 has get_origin() and get_args() but those implementations aren't -# Annotated-aware, so we can't use those, only Python 3.9 versions will do. -# Similarly, Python 3.9's implementation doesn't support ParamSpecArgs and -# ParamSpecKwargs. +# Annotated-aware, so we can't use those. Python 3.9's versions don't support +# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. if sys.version_info[:2] >= (3, 10): get_origin = typing.get_origin get_args = typing.get_args -elif PEP_560: +# 3.7-3.9 +else: try: # 3.9+ from typing import _BaseGenericAlias except ImportError: - _BaseGenericAlias = _GenericAlias + _BaseGenericAlias = typing._GenericAlias try: # 3.9+ - from typing import GenericAlias + from typing import GenericAlias as _typing_GenericAlias except ImportError: - GenericAlias = _GenericAlias + _typing_GenericAlias = typing._GenericAlias def get_origin(tp): """Get the unsubscripted version of a type. @@ -2102,11 +1024,11 @@ elif PEP_560: """ if isinstance(tp, _AnnotatedAlias): return Annotated - if isinstance(tp, (_GenericAlias, GenericAlias, _BaseGenericAlias, + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias, ParamSpecArgs, ParamSpecKwargs)): return tp.__origin__ - if tp is Generic: - return Generic + if tp is typing.Generic: + return typing.Generic return None def get_args(tp): @@ -2122,7 +1044,7 @@ elif PEP_560: """ if isinstance(tp, _AnnotatedAlias): return (tp.__origin__,) + tp.__metadata__ - if isinstance(tp, (_GenericAlias, GenericAlias)): + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)): if getattr(tp, "_special", False): return () res = tp.__args__ @@ -2132,8 +1054,10 @@ elif PEP_560: return () +# 3.10+ if hasattr(typing, 'TypeAlias'): TypeAlias = typing.TypeAlias +# 3.9 elif sys.version_info[:2] >= (3, 9): class _TypeAliasForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -2151,9 +1075,9 @@ elif sys.version_info[:2] >= (3, 9): It's invalid when used anywhere except as in the example above. """ - raise TypeError("{} is not subscriptable".format(self)) - -elif sys.version_info[:2] >= (3, 7): + raise TypeError(f"{self} is not subscriptable") +# 3.7-3.8 +else: class _TypeAliasForm(typing._SpecialForm, _root=True): def __repr__(self): return 'typing_extensions.' + self._name @@ -2170,67 +1094,12 @@ elif sys.version_info[:2] >= (3, 7): It's invalid when used anywhere except as in the example above.""") -elif hasattr(typing, '_FinalTypingBase'): - class _TypeAliasMeta(typing.TypingMeta): - """Metaclass for TypeAlias""" - - def __repr__(self): - return 'typing_extensions.TypeAlias' - - class _TypeAliasBase(typing._FinalTypingBase, metaclass=_TypeAliasMeta, _root=True): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example above. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("TypeAlias cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("TypeAlias cannot be used with issubclass().") - - def __repr__(self): - return 'typing_extensions.TypeAlias' - - TypeAlias = _TypeAliasBase(_root=True) -else: - class _TypeAliasMeta(typing.TypingMeta): - """Metaclass for TypeAlias""" - - def __instancecheck__(self, obj): - raise TypeError("TypeAlias cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("TypeAlias cannot be used with issubclass().") - - def __call__(self, *args, **kwargs): - raise TypeError("Cannot instantiate TypeAlias") - - class TypeAlias(metaclass=_TypeAliasMeta, _root=True): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example above. - """ - __slots__ = () - # Python 3.10+ has PEP 612 if hasattr(typing, 'ParamSpecArgs'): ParamSpecArgs = typing.ParamSpecArgs ParamSpecKwargs = typing.ParamSpecKwargs +# 3.7-3.9 else: class _Immutable: """Mixin to indicate that object should not be copied.""" @@ -2258,7 +1127,12 @@ else: self.__origin__ = origin def __repr__(self): - return "{}.args".format(self.__origin__.__name__) + return f"{self.__origin__.__name__}.args" + + def __eq__(self, other): + if not isinstance(other, ParamSpecArgs): + return NotImplemented + return self.__origin__ == other.__origin__ class ParamSpecKwargs(_Immutable): """The kwargs for a ParamSpec object. @@ -2276,10 +1150,17 @@ else: self.__origin__ = origin def __repr__(self): - return "{}.kwargs".format(self.__origin__.__name__) + return f"{self.__origin__.__name__}.kwargs" + def __eq__(self, other): + if not isinstance(other, ParamSpecKwargs): + return NotImplemented + return self.__origin__ == other.__origin__ + +# 3.10+ if hasattr(typing, 'ParamSpec'): ParamSpec = typing.ParamSpec +# 3.7-3.9 else: # Inherits from list as a workaround for Callable checks in Python < 3.9.2. @@ -2331,7 +1212,7 @@ else: """ # Trick Generic __parameters__. - __class__ = TypeVar + __class__ = typing.TypeVar @property def args(self): @@ -2381,62 +1262,44 @@ else: def __call__(self, *args, **kwargs): pass - if not PEP_560: - # Only needed in 3.6 and lower. - def _get_type_vars(self, tvars): - if self not in tvars: - tvars.append(self) +# 3.7-3.9 +if not hasattr(typing, 'Concatenate'): + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class _ConcatenateGenericAlias(list): -# Inherits from list as a workaround for Callable checks in Python < 3.9.2. -class _ConcatenateGenericAlias(list): - - # Trick Generic into looking into this for __parameters__. - if PEP_560: + # Trick Generic into looking into this for __parameters__. __class__ = typing._GenericAlias - elif sys.version_info[:3] == (3, 5, 2): - __class__ = typing.TypingMeta - else: - __class__ = typing._TypingBase - # Flag in 3.8. - _special = False - # Attribute in 3.6 and earlier. - if sys.version_info[:3] == (3, 5, 2): - _gorg = typing.GenericMeta - else: - _gorg = typing.Generic + # Flag in 3.8. + _special = False - def __init__(self, origin, args): - super().__init__(args) - self.__origin__ = origin - self.__args__ = args + def __init__(self, origin, args): + super().__init__(args) + self.__origin__ = origin + self.__args__ = args - def __repr__(self): - _type_repr = typing._type_repr - return '{origin}[{args}]' \ - .format(origin=_type_repr(self.__origin__), - args=', '.join(_type_repr(arg) for arg in self.__args__)) + def __repr__(self): + _type_repr = typing._type_repr + return (f'{_type_repr(self.__origin__)}' + f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') - def __hash__(self): - return hash((self.__origin__, self.__args__)) + def __hash__(self): + return hash((self.__origin__, self.__args__)) - # Hack to get typing._type_check to pass in Generic. - def __call__(self, *args, **kwargs): - pass + # Hack to get typing._type_check to pass in Generic. + def __call__(self, *args, **kwargs): + pass - @property - def __parameters__(self): - return tuple(tp for tp in self.__args__ if isinstance(tp, (TypeVar, ParamSpec))) - - if not PEP_560: - # Only required in 3.6 and lower. - def _get_type_vars(self, tvars): - if self.__origin__ and self.__parameters__: - typing._get_type_vars(self.__parameters__, tvars) + @property + def __parameters__(self): + return tuple( + tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) + ) -@_tp_cache +# 3.7-3.9 +@typing._tp_cache def _concatenate_getitem(self, parameters): if parameters == (): raise TypeError("Cannot take a Concatenate of no types.") @@ -2450,9 +1313,11 @@ def _concatenate_getitem(self, parameters): return _ConcatenateGenericAlias(self, parameters) +# 3.10+ if hasattr(typing, 'Concatenate'): Concatenate = typing.Concatenate _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa +# 3.9 elif sys.version_info[:2] >= (3, 9): @_TypeAliasForm def Concatenate(self, parameters): @@ -2467,8 +1332,8 @@ elif sys.version_info[:2] >= (3, 9): See PEP 612 for detailed information. """ return _concatenate_getitem(self, parameters) - -elif sys.version_info[:2] >= (3, 7): +# 3.7-8 +else: class _ConcatenateForm(typing._SpecialForm, _root=True): def __repr__(self): return 'typing_extensions.' + self._name @@ -2489,73 +1354,10 @@ elif sys.version_info[:2] >= (3, 7): See PEP 612 for detailed information. """) -elif hasattr(typing, '_FinalTypingBase'): - class _ConcatenateAliasMeta(typing.TypingMeta): - """Metaclass for Concatenate.""" - - def __repr__(self): - return 'typing_extensions.Concatenate' - - class _ConcatenateAliasBase(typing._FinalTypingBase, - metaclass=_ConcatenateAliasMeta, - _root=True): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("Concatenate cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Concatenate cannot be used with issubclass().") - - def __repr__(self): - return 'typing_extensions.Concatenate' - - def __getitem__(self, parameters): - return _concatenate_getitem(self, parameters) - - Concatenate = _ConcatenateAliasBase(_root=True) -# For 3.5.0 - 3.5.2 -else: - class _ConcatenateAliasMeta(typing.TypingMeta): - """Metaclass for Concatenate.""" - - def __instancecheck__(self, obj): - raise TypeError("TypeAlias cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("TypeAlias cannot be used with issubclass().") - - def __call__(self, *args, **kwargs): - raise TypeError("Cannot instantiate TypeAlias") - - def __getitem__(self, parameters): - return _concatenate_getitem(self, parameters) - - class Concatenate(metaclass=_ConcatenateAliasMeta, _root=True): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """ - __slots__ = () - +# 3.10+ if hasattr(typing, 'TypeGuard'): TypeGuard = typing.TypeGuard +# 3.9 elif sys.version_info[:2] >= (3, 9): class _TypeGuardForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -2605,10 +1407,10 @@ elif sys.version_info[:2] >= (3, 9): ``TypeGuard`` also works with type variables. For more information, see PEP 647 (User-Defined Type Guards). """ - item = typing._type_check(parameters, '{} accepts only single type.'.format(self)) - return _GenericAlias(self, (item,)) - -elif sys.version_info[:2] >= (3, 7): + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) +# 3.7-3.8 +else: class _TypeGuardForm(typing._SpecialForm, _root=True): def __repr__(self): @@ -2616,8 +1418,8 @@ elif sys.version_info[:2] >= (3, 7): def __getitem__(self, parameters): item = typing._type_check(parameters, - '{} accepts only a single type'.format(self._name)) - return _GenericAlias(self, (item,)) + f'{self._name} accepts only a single type') + return typing._GenericAlias(self, (item,)) TypeGuard = _TypeGuardForm( 'TypeGuard', @@ -2663,181 +1465,496 @@ elif sys.version_info[:2] >= (3, 7): ``TypeGuard`` also works with type variables. For more information, see PEP 647 (User-Defined Type Guards). """) -elif hasattr(typing, '_FinalTypingBase'): - class _TypeGuard(typing._FinalTypingBase, _root=True): - """Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. +# Vendored from cpython typing._SpecialFrom +class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') - Using ``-> TypeGuard`` tells the static type checker that for a given - function: + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name - For example:: + raise AttributeError(item) - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. + def __repr__(self): + return f'typing_extensions.{self._name}' - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """ + def __reduce__(self): + return self._name - __slots__ = ('__type__',) + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") - def __init__(self, tp=None, **kwds): - self.__type__ = tp + def __or__(self, other): + return typing.Union[self, other] - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - '{} accepts only a single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) + def __ror__(self, other): + return typing.Union[other, self] - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) - return r + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") - def __hash__(self): - return hash((type(self).__name__, self.__type__)) + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) - def __eq__(self, other): - if not isinstance(other, _TypeGuard): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - TypeGuard = _TypeGuard(_root=True) +if hasattr(typing, "LiteralString"): + LiteralString = typing.LiteralString else: - class _TypeGuardMeta(typing.TypingMeta): - """Metaclass for TypeGuard""" + @_SpecialForm + def LiteralString(self, params): + """Represents an arbitrary literal string. - def __new__(cls, name, bases, namespace, tp=None, _root=False): - self = super().__new__(cls, name, bases, namespace, _root=_root) - if tp is not None: - self.__type__ = tp - return self + Example:: - def __instancecheck__(self, obj): - raise TypeError("TypeGuard cannot be used with isinstance().") + from typing_extensions import LiteralString - def __subclasscheck__(self, cls): - raise TypeError("TypeGuard cannot be used with issubclass().") + def query(sql: LiteralString) -> ...: + ... - def __getitem__(self, item): - cls = type(self) - if self.__type__ is not None: - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) + query("SELECT * FROM table") # ok + query(f"SELECT * FROM {input()}") # not ok - param = typing._type_check( - item, - '{} accepts only single type.'.format(cls.__name__[1:])) - return cls(self.__name__, self.__bases__, - dict(self.__dict__), tp=param, _root=True) + See PEP 675 for details. - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(self.__name__, self.__bases__, - dict(self.__dict__), tp=self.__type__, - _root=True) + """ + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Self"): + Self = typing.Self +else: + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Never"): + Never = typing.Never +else: + @_SpecialForm + def Never(self, params): + """The bottom type, a type that has no members. + + This can be used to define a function that should never be + called, or a function that never returns:: + + from typing_extensions import Never + + def never_call_me(arg: Never) -> None: + pass + + def int_or_str(arg: int | str) -> None: + never_call_me(arg) # type checker error + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + never_call_me(arg) # ok, arg is of type Never + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, 'Required'): + Required = typing.Required + NotRequired = typing.NotRequired +elif sys.version_info[:2] >= (3, 9): + class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + @_ExtensionsSpecialForm + def Required(self, parameters): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + @_ExtensionsSpecialForm + def NotRequired(self, parameters): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + +else: + class _RequiredForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Required = _RequiredForm( + 'Required', + doc="""A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """) + NotRequired = _RequiredForm( + 'NotRequired', + doc="""A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """) + + +if hasattr(typing, "Unpack"): # 3.11+ + Unpack = typing.Unpack +elif sys.version_info[:2] >= (3, 9): + class _UnpackSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + @_UnpackSpecialForm + def Unpack(self, parameters): + """A special typing construct to unpack a variadic type. For example: + + Shape = TypeVarTuple('Shape') + Batch = NewType('Batch', int) + + def add_batch_axis( + x: Array[Unpack[Shape]] + ) -> Array[Batch, Unpack[Shape]]: ... + + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + +else: + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + class _UnpackForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + Unpack = _UnpackForm( + 'Unpack', + doc="""A special typing construct to unpack a variadic type. For example: + + Shape = TypeVarTuple('Shape') + Batch = NewType('Batch', int) + + def add_batch_axis( + x: Array[Unpack[Shape]] + ) -> Array[Batch, Unpack[Shape]]: ... + + """) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + + +if hasattr(typing, "TypeVarTuple"): # 3.11+ + TypeVarTuple = typing.TypeVarTuple +else: + class TypeVarTuple: + """Type variable tuple. + + Usage:: + + Ts = TypeVarTuple('Ts') + + In the same way that a normal type variable is a stand-in for a single + type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* + type such as ``Tuple[int, str]``. + + Type variable tuples can be used in ``Generic`` declarations. + Consider the following example:: + + class Array(Generic[*Ts]): ... + + The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, + where ``T1`` and ``T2`` are type variables. To use these type variables + as type parameters of ``Array``, we must *unpack* the type variable tuple using + the star operator: ``*Ts``. The signature of ``Array`` then behaves + as if we had simply written ``class Array(Generic[T1, T2]): ...``. + In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows + us to parameterise the class with an *arbitrary* number of type parameters. + + Type variable tuples can be used anywhere a normal ``TypeVar`` can. + This includes class definitions, as shown above, as well as function + signatures and variable annotations:: + + class Array(Generic[*Ts]): + + def __init__(self, shape: Tuple[*Ts]): + self._shape: Tuple[*Ts] = shape + + def get_shape(self) -> Tuple[*Ts]: + return self._shape + + shape = (Height(480), Width(640)) + x: Array[Height, Width] = Array(shape) + y = abs(x) # Inferred type is Array[Height, Width] + z = x + x # ... is Array[Height, Width] + x.get_shape() # ... is tuple[Height, Width] + + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + def __iter__(self): + yield self.__unpacked__ + + def __init__(self, name): + self.__name__ = name + + # for pickling: + try: + def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + def_mod = None + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + self.__unpacked__ = Unpack[self] def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) - return r + return self.__name__ def __hash__(self): - return hash((type(self).__name__, self.__type__)) + return object.__hash__(self) def __eq__(self, other): - if not hasattr(other, "__type__"): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ return self is other - class TypeGuard(typing.Final, metaclass=_TypeGuardMeta, _root=True): - """Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. + def __reduce__(self): + return self.__name__ - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". + def __init_subclass__(self, *args, **kwds): + if '_root' not in kwds: + raise TypeError("Cannot subclass special typing classes") - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - Using ``-> TypeGuard`` tells the static type checker that for a given - function: +if hasattr(typing, "reveal_type"): + reveal_type = typing.reveal_type +else: + def reveal_type(__obj: T) -> T: + """Reveal the inferred type of a variable. - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. + When a static type checker encounters a call to ``reveal_type()``, + it will emit the inferred type of the argument:: - For example:: + x: int = 1 + reveal_type(x) - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... + Running a static type checker (e.g., ``mypy``) on this example + will produce output similar to 'Revealed type is "builtins.int"'. - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. + At runtime, the function prints the runtime type of the + argument and returns it unchanged. - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). """ - __type__ = None + print(f"Runtime type is {type(__obj).__name__!r}", file=sys.stderr) + return __obj + + +if hasattr(typing, "assert_never"): + assert_never = typing.assert_never +else: + def assert_never(__arg: Never) -> Never: + """Assert to the type checker that a line of code is unreachable. + + Example:: + + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + assert_never(arg) + + If a type checker finds that a call to assert_never() is + reachable, it will emit an error. + + At runtime, this throws an exception when called. + + """ + raise AssertionError("Expected code to be unreachable") + + +if hasattr(typing, 'dataclass_transform'): + dataclass_transform = typing.dataclass_transform +else: + def dataclass_transform( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + field_specifiers: typing.Tuple[ + typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], + ... + ] = (), + **kwargs: typing.Any, + ) -> typing.Callable[[T], T]: + """Decorator that marks a function, class, or metaclass as providing + dataclass-like behavior. + + Example: + + from typing_extensions import dataclass_transform + + _T = TypeVar("_T") + + # Used on a decorator function + @dataclass_transform() + def create_model(cls: type[_T]) -> type[_T]: + ... + return cls + + @create_model + class CustomerModel: + id: int + name: str + + # Used on a base class + @dataclass_transform() + class ModelBase: ... + + class CustomerModel(ModelBase): + id: int + name: str + + # Used on a metaclass + @dataclass_transform() + class ModelMeta(type): ... + + class ModelBase(metaclass=ModelMeta): ... + + class CustomerModel(ModelBase): + id: int + name: str + + Each of the ``CustomerModel`` classes defined in this example will now + behave similarly to a dataclass created with the ``@dataclasses.dataclass`` + decorator. For example, the type checker will synthesize an ``__init__`` + method. + + The arguments to this decorator can be used to customize this behavior: + - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + True or False if it is omitted by the caller. + - ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + + See PEP 681 for details. + + """ + def decorator(cls_or_fn): + cls_or_fn.__dataclass_transform__ = { + "eq_default": eq_default, + "order_default": order_default, + "kw_only_default": kw_only_default, + "field_specifiers": field_specifiers, + "kwargs": kwargs, + } + return cls_or_fn + return decorator + + +# We have to do some monkey patching to deal with the dual nature of +# Unpack/TypeVarTuple: +# - We want Unpack to be a kind of TypeVar so it gets accepted in +# Generic[Unpack[Ts]] +# - We want it to *not* be treated as a TypeVar for the purposes of +# counting generic parameters, so that when we subscript a generic, +# the runtime doesn't try to substitute the Unpack with the subscripted type. +if not hasattr(typing, "TypeVarTuple"): + typing._collect_type_vars = _collect_type_vars + typing._check_generic = _check_generic diff --git a/dist/ba_data/python/ba/__init__.py b/dist/ba_data/python/ba/__init__.py index 24c1cee..89f8abb 100644 --- a/dist/ba_data/python/ba/__init__.py +++ b/dist/ba_data/python/ba/__init__.py @@ -6,7 +6,6 @@ This top level module is a collection of most commonly used functionality. For many modding purposes, the bits exposed here are all you'll need. In some specific cases you may need to pull in individual submodules instead. """ -# pylint: disable=unused-import # pylint: disable=redefined-builtin from _ba import ( @@ -18,7 +17,7 @@ from _ba import ( newnode, playsound, printnodes, printobjects, pushcall, quit, rowwidget, safecolor, screenmessage, scrollwidget, set_analytics_screen, charstr, textwidget, time, timer, open_url, widget, clipboard_is_supported, - clipboard_has_text, clipboard_get_text, clipboard_set_text) + clipboard_has_text, clipboard_get_text, clipboard_set_text, getdata) from ba._activity import Activity from ba._plugin import PotentialPlugin, Plugin, PluginSubsystem from ba._actor import Actor @@ -81,13 +80,64 @@ from ba._collision import Collision, getcollision app: App +__all__ = [ + 'Achievement', 'AchievementSubsystem', 'Activity', 'ActivityNotFoundError', + 'Actor', 'ActorNotFoundError', 'animate', 'animate_array', 'app', 'App', + 'AppConfig', 'AppDelegate', 'AssetPackage', 'BoolSetting', 'buttonwidget', + 'Call', 'cameraflash', 'camerashake', 'Campaign', 'CelebrateMessage', + 'charstr', 'checkboxwidget', 'ChoiceSetting', 'Chooser', + 'clipboard_get_text', 'clipboard_has_text', 'clipboard_is_supported', + 'clipboard_set_text', 'CollideModel', 'Collision', 'columnwidget', + 'containerwidget', 'Context', 'ContextCall', 'ContextError', + 'CoopGameActivity', 'CoopSession', 'Data', 'DeathType', + 'DelegateNotFoundError', 'Dependency', 'DependencyComponent', + 'DependencyError', 'DependencySet', 'DieMessage', 'do_once', 'DropMessage', + 'DroppedMessage', 'DualTeamSession', 'emitfx', 'EmptyPlayer', 'EmptyTeam', + 'Existable', 'existing', 'FloatChoiceSetting', 'FloatSetting', + 'FreeForAllSession', 'FreezeMessage', 'GameActivity', 'GameResults', + 'GameTip', 'garbage_collect', 'getactivity', 'getclass', 'getcollidemodel', + 'getcollision', 'getdata', 'getmaps', 'getmodel', 'getnodes', 'getsession', + 'getsound', 'gettexture', 'HitMessage', 'hscrollwidget', 'imagewidget', + 'ImpactDamageMessage', 'InputDevice', 'InputDeviceNotFoundError', + 'InputType', 'IntChoiceSetting', 'IntSetting', + 'is_browser_likely_available', 'is_point_in_box', 'Keyboard', + 'LanguageSubsystem', 'Level', 'Lobby', 'log', 'Lstr', 'Map', 'Material', + 'MetadataSubsystem', 'Model', 'MultiTeamSession', 'MusicPlayer', + 'MusicPlayMode', 'MusicSubsystem', 'MusicType', 'newactivity', 'newnode', + 'Node', 'NodeActor', 'NodeNotFoundError', 'normalized_color', + 'NotFoundError', 'open_url', 'OutOfBoundsMessage', 'Permission', + 'PickedUpMessage', 'PickUpMessage', 'Player', 'PlayerDiedMessage', + 'PlayerInfo', 'PlayerNotFoundError', 'PlayerRecord', 'PlayerScoredMessage', + 'playsound', 'Plugin', 'PluginSubsystem', 'PotentialPlugin', + 'PowerupAcceptMessage', 'PowerupMessage', 'print_error', 'print_exception', + 'printnodes', 'printobjects', 'pushcall', 'quit', 'rowwidget', 'safecolor', + 'ScoreConfig', 'ScoreType', 'screenmessage', 'scrollwidget', + 'ServerController', 'Session', 'SessionNotFoundError', 'SessionPlayer', + 'SessionPlayerNotFoundError', 'SessionTeam', 'SessionTeamNotFoundError', + 'set_analytics_screen', 'setmusic', 'Setting', 'ShouldShatterMessage', + 'show_damage_count', 'Sound', 'SpecialChar', 'StandLocation', + 'StandMessage', 'Stats', 'storagename', 'Team', 'TeamGameActivity', + 'TeamNotFoundError', 'Texture', 'textwidget', 'ThawMessage', 'time', + 'TimeFormat', 'Timer', 'timer', 'timestring', 'TimeType', 'uicleanupcheck', + 'UIController', 'UIScale', 'UISubsystem', 'UNHANDLED', 'Vec3', + 'vec3validate', 'verify_object_death', 'WeakCall', 'Widget', 'widget', + 'WidgetNotFoundError', 'Window' +] -# Change everything's listed module to simply 'ba' (instead of 'ba.foo.bar'). + +# Have these things present themselves cleanly as 'ba.Foo' +# instead of 'ba._submodule.Foo' def _simplify_module_names() -> None: - for attr, obj in globals().items(): - if not attr.startswith('_'): - if getattr(obj, '__module__', None) not in [None, 'ba']: - obj.__module__ = 'ba' + import os + + # Though pdoc gets confused when we override __module__, + # so let's make an exception for it. + if os.environ.get('BA_DOCS_GENERATION', '0') != '1': + from efro.util import set_canonical_module + globs = globals() + set_canonical_module( + module_globals=globs, + names=[n for n in globs.keys() if not n.startswith('_')]) _simplify_module_names() diff --git a/dist/ba_data/python/ba/_accountv1.py b/dist/ba_data/python/ba/_accountv1.py new file mode 100644 index 0000000..2f72f19 --- /dev/null +++ b/dist/ba_data/python/ba/_accountv1.py @@ -0,0 +1,267 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Account related functionality.""" + +from __future__ import annotations + +import copy +import time +from typing import TYPE_CHECKING + +import _ba + +if TYPE_CHECKING: + from typing import Any, Optional + + +class AccountV1Subsystem: + """Subsystem for legacy account handling in the app. + + Category: **App Classes** + + Access the single shared instance of this class at 'ba.app.accounts_v1'. + """ + + def __init__(self) -> None: + self.account_tournament_list: Optional[tuple[int, list[str]]] = None + + # FIXME: should abstract/structure these. + self.tournament_info: dict = {} + self.league_rank_cache: dict = {} + self.last_post_purchase_message_time: Optional[float] = None + + # If we try to run promo-codes due to launch-args/etc we might + # not be signed in yet; go ahead and queue them up in that case. + self.pending_promo_codes: list[str] = [] + + def on_app_launch(self) -> None: + """Called when the app is done bootstrapping.""" + + # Auto-sign-in to a local account in a moment if we're set to. + def do_auto_sign_in() -> None: + if _ba.app.headless_mode or _ba.app.config.get( + 'Auto Account State') == 'Local': + _ba.sign_in_v1('Local') + + _ba.pushcall(do_auto_sign_in) + + def on_app_resume(self) -> None: + """Should be called when the app is resumed.""" + + # Mark our cached tourneys as invalid so anyone using them knows + # they might be out of date. + for entry in list(self.tournament_info.values()): + entry['valid'] = False + + def handle_account_gained_tickets(self, count: int) -> None: + """Called when the current account has been awarded tickets. + + (internal) + """ + from ba._language import Lstr + _ba.screenmessage(Lstr(resource='getTicketsWindow.receivedTicketsText', + subs=[('${COUNT}', str(count))]), + color=(0, 1, 0)) + _ba.playsound(_ba.getsound('cashRegister')) + + def cache_league_rank_data(self, data: Any) -> None: + """(internal)""" + self.league_rank_cache['info'] = copy.deepcopy(data) + + def get_cached_league_rank_data(self) -> Any: + """(internal)""" + return self.league_rank_cache.get('info', None) + + def get_league_rank_points(self, + data: Optional[dict[str, Any]], + subset: str = None) -> int: + """(internal)""" + if data is None: + return 0 + + # If the data contains an achievement total, use that. otherwise calc + # locally. + if data['at'] is not None: + total_ach_value = data['at'] + else: + total_ach_value = 0 + for ach in _ba.app.ach.achievements: + if ach.complete: + total_ach_value += ach.power_ranking_value + + trophies_total: int = (data['t0a'] * data['t0am'] + + data['t0b'] * data['t0bm'] + + data['t1'] * data['t1m'] + + data['t2'] * data['t2m'] + + data['t3'] * data['t3m'] + + data['t4'] * data['t4m']) + if subset == 'trophyCount': + val: int = (data['t0a'] + data['t0b'] + data['t1'] + data['t2'] + + data['t3'] + data['t4']) + assert isinstance(val, int) + return val + if subset == 'trophies': + assert isinstance(trophies_total, int) + return trophies_total + if subset is not None: + raise ValueError('invalid subset value: ' + str(subset)) + + if data['p']: + pro_mult = 1.0 + float( + _ba.get_v1_account_misc_read_val('proPowerRankingBoost', + 0.0)) * 0.01 + else: + pro_mult = 1.0 + + # For final value, apply our pro mult and activeness-mult. + return int( + (total_ach_value + trophies_total) * + (data['act'] if data['act'] is not None else 1.0) * pro_mult) + + def cache_tournament_info(self, info: Any) -> None: + """(internal)""" + from ba._generated.enums import TimeType, TimeFormat + for entry in info: + cache_entry = self.tournament_info[entry['tournamentID']] = ( + copy.deepcopy(entry)) + + # Also store the time we received this, so we can adjust + # time-remaining values/etc. + cache_entry['timeReceived'] = _ba.time(TimeType.REAL, + TimeFormat.MILLISECONDS) + cache_entry['valid'] = True + + def get_purchased_icons(self) -> list[str]: + """(internal)""" + # pylint: disable=cyclic-import + from ba import _store + if _ba.get_v1_account_state() != 'signed_in': + return [] + icons = [] + store_items = _store.get_store_items() + for item_name, item in list(store_items.items()): + if item_name.startswith('icons.') and _ba.get_purchased(item_name): + icons.append(item['icon']) + return icons + + def ensure_have_account_player_profile(self) -> None: + """ + Ensure the standard account-named player profile exists; + creating if needed. + + (internal) + """ + # This only applies when we're signed in. + if _ba.get_v1_account_state() != 'signed_in': + return + + # If the short version of our account name currently cant be + # displayed by the game, cancel. + if not _ba.have_chars(_ba.get_v1_account_display_string(full=False)): + return + + config = _ba.app.config + if ('Player Profiles' not in config + or '__account__' not in config['Player Profiles']): + + # Create a spaz with a nice default purply color. + _ba.add_transaction({ + 'type': 'ADD_PLAYER_PROFILE', + 'name': '__account__', + 'profile': { + 'character': 'Spaz', + 'color': [0.5, 0.25, 1.0], + 'highlight': [0.5, 0.25, 1.0] + } + }) + _ba.run_transactions() + + def have_pro(self) -> bool: + """Return whether pro is currently unlocked.""" + + # Check our tickets-based pro upgrade and our two real-IAP based + # upgrades. Also always unlock this stuff in ballistica-core builds. + return bool( + _ba.get_purchased('upgrades.pro') + or _ba.get_purchased('static.pro') + or _ba.get_purchased('static.pro_sale') + or 'ballistica' + 'core' == _ba.appname()) + + def have_pro_options(self) -> bool: + """Return whether pro-options are present. + + This is True for owners of Pro or for old installs + before Pro was a requirement for these options. + """ + + # We expose pro options if the server tells us to + # (which is generally just when we own pro), + # or also if we've been grandfathered in or are using ballistica-core + # builds. + return self.have_pro() or bool( + _ba.get_v1_account_misc_read_val_2('proOptionsUnlocked', False) + or _ba.app.config.get('lc14292', 0) > 1) + + def show_post_purchase_message(self) -> None: + """(internal)""" + from ba._language import Lstr + from ba._generated.enums import TimeType + cur_time = _ba.time(TimeType.REAL) + if (self.last_post_purchase_message_time is None + or cur_time - self.last_post_purchase_message_time > 3.0): + self.last_post_purchase_message_time = cur_time + with _ba.Context('ui'): + _ba.screenmessage(Lstr(resource='updatingAccountText', + fallback_resource='purchasingText'), + color=(0, 1, 0)) + _ba.playsound(_ba.getsound('click01')) + + def on_account_state_changed(self) -> None: + """(internal)""" + from ba._language import Lstr + + # Run any pending promo codes we had queued up while not signed in. + if _ba.get_v1_account_state( + ) == 'signed_in' and self.pending_promo_codes: + for code in self.pending_promo_codes: + _ba.screenmessage(Lstr(resource='submittingPromoCodeText'), + color=(0, 1, 0)) + _ba.add_transaction({ + 'type': 'PROMO_CODE', + 'expire_time': time.time() + 5, + 'code': code + }) + _ba.run_transactions() + self.pending_promo_codes = [] + + def add_pending_promo_code(self, code: str) -> None: + """(internal)""" + from ba._language import Lstr + from ba._generated.enums import TimeType + + # If we're not signed in, queue up the code to run the next time we + # are and issue a warning if we haven't signed in within the next + # few seconds. + if _ba.get_v1_account_state() != 'signed_in': + + def check_pending_codes() -> None: + """(internal)""" + + # If we're still not signed in and have pending codes, + # inform the user that they need to sign in to use them. + if self.pending_promo_codes: + _ba.screenmessage(Lstr(resource='signInForPromoCodeText'), + color=(1, 0, 0)) + _ba.playsound(_ba.getsound('error')) + + self.pending_promo_codes.append(code) + _ba.timer(6.0, check_pending_codes, timetype=TimeType.REAL) + return + _ba.screenmessage(Lstr(resource='submittingPromoCodeText'), + color=(0, 1, 0)) + _ba.add_transaction({ + 'type': 'PROMO_CODE', + 'expire_time': time.time() + 5, + 'code': code + }) + _ba.run_transactions() diff --git a/dist/ba_data/python/ba/_accountv2.py b/dist/ba_data/python/ba/_accountv2.py new file mode 100644 index 0000000..36b776e --- /dev/null +++ b/dist/ba_data/python/ba/_accountv2.py @@ -0,0 +1,51 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Account related functionality.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Optional + + +class AccountV2Subsystem: + """Subsystem for modern account handling in the app. + + Category: **App Classes** + + Access the single shared instance of this class at 'ba.app.accounts_v2'. + """ + + def on_app_launch(self) -> None: + """Should be called at standard on_app_launch time.""" + + def set_primary_credentials(self, credentials: Optional[str]) -> None: + """Set credentials for the primary app account.""" + raise RuntimeError('This should be overridden.') + + def have_primary_credentials(self) -> bool: + """Are credentials currently set for the primary app account? + + Note that this does not mean these credentials are currently valid; + only that they exist. If/when credentials are validated, the 'primary' + account handle will be set. + """ + raise RuntimeError('This should be overridden.') + + @property + def primary(self) -> Optional[AccountV2Handle]: + """The primary account for the app, or None if not logged in.""" + return None + + def get_primary(self) -> Optional[AccountV2Handle]: + """Internal - should be overridden by subclass.""" + return None + + +class AccountV2Handle: + """Handle for interacting with a v2 account.""" + + def __init__(self) -> None: + self.tag = '?' diff --git a/dist/ba_data/python/ba/_achievement.py b/dist/ba_data/python/ba/_achievement.py index 13634cf..23e5d93 100644 --- a/dist/ba_data/python/ba/_achievement.py +++ b/dist/ba_data/python/ba/_achievement.py @@ -65,7 +65,7 @@ ACH_LEVEL_NAMES = { class AchievementSubsystem: """Subsystem for achievement handling. - Category: App Classes + Category: **App Classes** Access the single shared instance of this class at 'ba.app.ach'. """ @@ -409,9 +409,9 @@ def _get_ach_mult(include_pro_bonus: bool = False) -> int: (just for display; changing this here won't affect actual rewards) """ - val: int = _ba.get_account_misc_read_val('achAwardMult', 5) + val: int = _ba.get_v1_account_misc_read_val('achAwardMult', 5) assert isinstance(val, int) - if include_pro_bonus and _ba.app.accounts.have_pro(): + if include_pro_bonus and _ba.app.accounts_v1.have_pro(): val *= 2 return val @@ -436,7 +436,7 @@ def _display_next_achievement() -> None: class Achievement: """Represents attributes and state for an individual achievement. - Category: App Classes + Category: **App Classes** """ def __init__(self, @@ -496,7 +496,7 @@ class Achievement: # signed in, lets not show them (otherwise we tend to get # confusing 'controller connected' achievements popping up while # waiting to log in which can be confusing). - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': return # If we're being freshly complete, display/report it and whatnot. @@ -592,8 +592,8 @@ class Achievement: def get_award_ticket_value(self, include_pro_bonus: bool = False) -> int: """Get the ticket award value for this achievement.""" - val: int = (_ba.get_account_misc_read_val('achAward.' + self._name, - self._award) * + val: int = (_ba.get_v1_account_misc_read_val('achAward.' + self._name, + self._award) * _get_ach_mult(include_pro_bonus)) assert isinstance(val, int) return val @@ -601,7 +601,7 @@ class Achievement: @property def power_ranking_value(self) -> int: """Get the power-ranking award value for this achievement.""" - val: int = _ba.get_account_misc_read_val( + val: int = _ba.get_v1_account_misc_read_val( 'achLeaguePoints.' + self._name, self._award) assert isinstance(val, int) return val @@ -916,7 +916,6 @@ class Achievement: def show_completion_banner(self, sound: bool = True) -> None: """Create the banner/sound for an acquired achievement announcement.""" - from ba import _account from ba import _gameutils from bastd.actor.text import Text from bastd.actor.image import Image @@ -1177,7 +1176,7 @@ class Achievement: objt.node.host_only = True # Add the 'x 2' if we've got pro. - if app.accounts.have_pro(): + if app.accounts_v1.have_pro(): objt = Text('x 2', position=(-120 - 180 + 45, 80 + y_offs - 50), v_attach=Text.VAttach.BOTTOM, diff --git a/dist/ba_data/python/ba/_activity.py b/dist/ba_data/python/ba/_activity.py index 701de8e..f2d6034 100644 --- a/dist/ba_data/python/ba/_activity.py +++ b/dist/ba_data/python/ba/_activity.py @@ -18,10 +18,11 @@ from ba._messages import UNHANDLED if TYPE_CHECKING: from typing import Optional, Any import ba - from bastd.actor.respawnicon import RespawnIcon +# pylint: disable=invalid-name PlayerType = TypeVar('PlayerType', bound=Player) TeamType = TypeVar('TeamType', bound=Team) +# pylint: enable=invalid-name class Activity(DependencyComponent, Generic[PlayerType, TeamType]): @@ -32,104 +33,97 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): Examples of Activities include games, score-screens, cutscenes, etc. A ba.Session has one 'current' Activity at any time, though their existence can overlap during transitions. - - Attributes: - - settings_raw - The settings dict passed in when the activity was made. - This attribute is deprecated and should be avoided when possible; - activities should pull all values they need from the 'settings' arg - passed to the Activity __init__ call. - - teams - The list of ba.Teams in the Activity. This gets populated just before - before on_begin() is called and is updated automatically as players - join or leave the game. (at least in free-for-all mode where every - player gets their own team; in teams mode there are always 2 teams - regardless of the player count). - - players - The list of ba.Players in the Activity. This gets populated just - before on_begin() is called and is updated automatically as players - join or leave the game. """ # pylint: disable=too-many-public-methods - # Annotating attr types at the class level lets us introspect at runtime. settings_raw: dict[str, Any] + """The settings dict passed in when the activity was made. + This attribute is deprecated and should be avoided when possible; + activities should pull all values they need from the 'settings' arg + passed to the Activity __init__ call.""" + teams: list[TeamType] + """The list of ba.Team-s in the Activity. This gets populated just + before on_begin() is called and is updated automatically as players + join or leave the game. (at least in free-for-all mode where every + player gets their own team; in teams mode there are always 2 teams + regardless of the player count).""" + players: list[PlayerType] + """The list of ba.Player-s in the Activity. This gets populated just + before on_begin() is called and is updated automatically as players + join or leave the game.""" - # Whether to print every time a player dies. This can be pertinent - # in games such as Death-Match but can be annoying in games where it - # doesn't matter. announce_player_deaths = False + """Whether to print every time a player dies. This can be pertinent + in games such as Death-Match but can be annoying in games where it + doesn't matter.""" - # Joining activities are for waiting for initial player joins. - # They are treated slightly differently than regular activities, - # mainly in that all players are passed to the activity at once - # instead of as each joins. is_joining_activity = False + """Joining activities are for waiting for initial player joins. + They are treated slightly differently than regular activities, + mainly in that all players are passed to the activity at once + instead of as each joins.""" - # Whether game-time should still progress when in menus/etc. allow_pausing = False + """Whether game-time should still progress when in menus/etc.""" - # Whether idle players can potentially be kicked (should not happen in - # menus/etc). allow_kick_idle_players = True + """Whether idle players can potentially be kicked (should not happen in + menus/etc).""" - # In vr mode, this determines whether overlay nodes (text, images, etc) - # are created at a fixed position in space or one that moves based on - # the current map. Generally this should be on for games and off for - # transitions/score-screens/etc. that persist between maps. use_fixed_vr_overlay = False + """In vr mode, this determines whether overlay nodes (text, images, etc) + are created at a fixed position in space or one that moves based on + the current map. Generally this should be on for games and off for + transitions/score-screens/etc. that persist between maps.""" - # If True, runs in slow motion and turns down sound pitch. slow_motion = False + """If True, runs in slow motion and turns down sound pitch.""" - # Set this to True to inherit slow motion setting from previous - # activity (useful for transitions to avoid hitches). inherits_slow_motion = False + """Set this to True to inherit slow motion setting from previous + activity (useful for transitions to avoid hitches).""" - # Set this to True to keep playing the music from the previous activity - # (without even restarting it). inherits_music = False + """Set this to True to keep playing the music from the previous activity + (without even restarting it).""" - # Set this to true to inherit VR camera offsets from the previous - # activity (useful for preventing sporadic camera movement - # during transitions). inherits_vr_camera_offset = False + """Set this to true to inherit VR camera offsets from the previous + activity (useful for preventing sporadic camera movement + during transitions).""" - # Set this to true to inherit (non-fixed) VR overlay positioning from - # the previous activity (useful for prevent sporadic overlay jostling - # during transitions). inherits_vr_overlay_center = False + """Set this to true to inherit (non-fixed) VR overlay positioning from + the previous activity (useful for prevent sporadic overlay jostling + during transitions).""" - # Set this to true to inherit screen tint/vignette colors from the - # previous activity (useful to prevent sudden color changes during - # transitions). inherits_tint = False + """Set this to true to inherit screen tint/vignette colors from the + previous activity (useful to prevent sudden color changes during + transitions).""" - # Whether players should be allowed to join in the middle of this - # activity. Note that Sessions may not allow mid-activity-joins even - # if the activity says its ok. allow_mid_activity_joins: bool = True + """Whether players should be allowed to join in the middle of this + activity. Note that Sessions may not allow mid-activity-joins even + if the activity says its ok.""" - # If the activity fades or transitions in, it should set the length of - # time here so that previous activities will be kept alive for that - # long (avoiding 'holes' in the screen) - # This value is given in real-time seconds. transition_time = 0.0 + """If the activity fades or transitions in, it should set the length of + time here so that previous activities will be kept alive for that + long (avoiding 'holes' in the screen) + This value is given in real-time seconds.""" - # Is it ok to show an ad after this activity ends before showing - # the next activity? can_show_ad_on_death = False + """Is it ok to show an ad after this activity ends before showing + the next activity?""" def __init__(self, settings: dict): """Creates an Activity in the current ba.Session. - The activity will not be actually run until ba.Session.setactivity() + The activity will not be actually run until ba.Session.setactivity is called. 'settings' should be a dict of key/value pairs specific to the activity. @@ -369,8 +363,8 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): def on_transition_out(self) -> None: """Called when your activity begins transitioning out. - Note that this may happen at any time even if end() has not been - called. + Note that this may happen at any time even if ba.Activity.end() has + not been called. """ def on_begin(self) -> None: @@ -386,11 +380,12 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): return UNHANDLED def has_transitioned_in(self) -> bool: - """Return whether on_transition_in() has been called.""" + """Return whether ba.Activity.on_transition_in() + has been called.""" return self._has_transitioned_in def has_begun(self) -> bool: - """Return whether on_begin() has been called.""" + """Return whether ba.Activity.on_begin() has been called.""" return self._has_begun def has_ended(self) -> bool: @@ -398,7 +393,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): return self._has_ended def is_transitioning_out(self) -> bool: - """Return whether on_transition_out() has been called.""" + """Return whether ba.Activity.on_transition_out() has been called.""" return self._transitioning_out def transition_in(self, prev_globals: Optional[ba.Node]) -> None: @@ -517,8 +512,8 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): Subclasses can override this if the activity's player class requires a custom constructor; otherwise it will be called with no args. Note that the player object should not be used at this - point as it is not yet fully wired up; wait for on_player_join() - for that. + point as it is not yet fully wired up; wait for + ba.Activity.on_player_join() for that. """ del sessionplayer # Unused. player = self._playertype() @@ -681,6 +676,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): sessionplayer.setactivity(None) sessionplayer.activityplayer = None + # noinspection PyUnresolvedReferences def _setup_player_and_team_types(self) -> None: """Pull player and team types from our typing.Generic params.""" diff --git a/dist/ba_data/python/ba/_actor.py b/dist/ba_data/python/ba/_actor.py index 53cdca2..d6a7c19 100644 --- a/dist/ba_data/python/ba/_actor.py +++ b/dist/ba_data/python/ba/_actor.py @@ -21,7 +21,7 @@ TA = TypeVar('TA', bound='Actor') class Actor: """High level logical entities in a ba.Activity. - Category: Gameplay Classes + Category: **Gameplay Classes** Actors act as controllers, combining some number of ba.Nodes, ba.Textures, ba.Sounds, etc. into a high-level cohesive unit. @@ -33,15 +33,16 @@ class Actor: (killing off or transitioning out their nodes) when the last Python reference to them disappears, so you can use logic such as: - # Create a flag Actor in our game activity: - from bastd.actor.flag import Flag - self.flag = Flag(position=(0, 10, 0)) - - # Later, destroy the flag. - # (provided nothing else is holding a reference to it) - # We could also just assign a new flag to this value. - # Either way, the old flag disappears. - self.flag = None + ##### Example + >>> # Create a flag Actor in our game activity: + ... from bastd.actor.flag import Flag + ... self.flag = Flag(position=(0, 10, 0)) + ... + ... # Later, destroy the flag. + ... # (provided nothing else is holding a reference to it) + ... # We could also just assign a new flag to this value. + ... # Either way, the old flag disappears. + ... self.flag = None This is in contrast to the behavior of the more low level ba.Nodes, which are always explicitly created and destroyed and don't care @@ -51,18 +52,18 @@ class Actor: if you want an Actor to stick around until explicitly killed regardless of references. - Another key feature of ba.Actor is its handlemessage() method, which - takes a single arbitrary object as an argument. This provides a safe way - to communicate between ba.Actor, ba.Activity, ba.Session, and any other - class providing a handlemessage() method. The most universally handled + Another key feature of ba.Actor is its ba.Actor.handlemessage() method, + which takes a single arbitrary object as an argument. This provides a safe + way to communicate between ba.Actor, ba.Activity, ba.Session, and any other + class providing a handlemessage() method. The most universally handled message type for Actors is the ba.DieMessage. - # Another way to kill the flag from the example above: - # We can safely call this on any type with a 'handlemessage' method - # (though its not guaranteed to always have a meaningful effect). - # In this case the Actor instance will still be around, but its exists() - # and is_alive() methods will both return False. - self.flag.handlemessage(ba.DieMessage()) + Another way to kill the flag from the example above: + We can safely call this on any type with a 'handlemessage' method + (though its not guaranteed to always have a meaningful effect). + In this case the Actor instance will still be around, but its + ba.Actor.exists() and ba.Actor.is_alive() methods will both return False. + >>> self.flag.handlemessage(ba.DieMessage()) """ def __init__(self) -> None: @@ -112,7 +113,7 @@ class Actor: return self def on_expire(self) -> None: - """Called for remaining ba.Actors when their ba.Activity shuts down. + """Called for remaining `ba.Actor`s when their ba.Activity shuts down. Actors can use this opportunity to clear callbacks or other references which have the potential of keeping the ba.Activity diff --git a/dist/ba_data/python/ba/_ads.py b/dist/ba_data/python/ba/_ads.py index e591bbb..a44133c 100644 --- a/dist/ba_data/python/ba/_ads.py +++ b/dist/ba_data/python/ba/_ads.py @@ -15,7 +15,7 @@ if TYPE_CHECKING: class AdsSubsystem: """Subsystem for ads functionality in the app. - Category: App Classes + Category: **App Classes** Access the single shared instance of this class at 'ba.app.ads'. """ @@ -77,7 +77,7 @@ class AdsSubsystem: # No ads without net-connections, etc. if not _ba.can_show_ad(): show = False - if app.accounts.have_pro(): + if app.accounts_v1.have_pro(): show = False # Pro disables interstitials. try: session = _ba.get_foreground_host_session() @@ -93,15 +93,15 @@ class AdsSubsystem: launch_count = app.config.get('launchCount', 0) # If we're seeing short ads we may want to space them differently. - interval_mult = (_ba.get_account_misc_read_val( + interval_mult = (_ba.get_v1_account_misc_read_val( 'ads.shortIntervalMult', 1.0) if self.last_ad_was_short else 1.0) if self.ad_amt is None: if launch_count <= 1: - self.ad_amt = _ba.get_account_misc_read_val( + self.ad_amt = _ba.get_v1_account_misc_read_val( 'ads.startVal1', 0.99) else: - self.ad_amt = _ba.get_account_misc_read_val( + self.ad_amt = _ba.get_v1_account_misc_read_val( 'ads.startVal2', 1.0) interval = None else: @@ -110,15 +110,15 @@ class AdsSubsystem: # (we reach our threshold faster the longer we've been # playing). base = 'ads' if _ba.has_video_ads() else 'ads2' - min_lc = _ba.get_account_misc_read_val(base + '.minLC', 0.0) - max_lc = _ba.get_account_misc_read_val(base + '.maxLC', 5.0) - min_lc_scale = (_ba.get_account_misc_read_val( + min_lc = _ba.get_v1_account_misc_read_val(base + '.minLC', 0.0) + max_lc = _ba.get_v1_account_misc_read_val(base + '.maxLC', 5.0) + min_lc_scale = (_ba.get_v1_account_misc_read_val( base + '.minLCScale', 0.25)) - max_lc_scale = (_ba.get_account_misc_read_val( + max_lc_scale = (_ba.get_v1_account_misc_read_val( base + '.maxLCScale', 0.34)) - min_lc_interval = (_ba.get_account_misc_read_val( + min_lc_interval = (_ba.get_v1_account_misc_read_val( base + '.minLCInterval', 360)) - max_lc_interval = (_ba.get_account_misc_read_val( + max_lc_interval = (_ba.get_v1_account_misc_read_val( base + '.maxLCInterval', 300)) if launch_count < min_lc: lc_amt = 0.0 diff --git a/dist/ba_data/python/ba/_app.py b/dist/ba_data/python/ba/_app.py index bc197d3..b47e225 100644 --- a/dist/ba_data/python/ba/_app.py +++ b/dist/ba_data/python/ba/_app.py @@ -7,6 +7,7 @@ import random import logging from enum import Enum from typing import TYPE_CHECKING +from concurrent.futures import ThreadPoolExecutor import _ba from ba._music import MusicSubsystem @@ -14,21 +15,25 @@ from ba._language import LanguageSubsystem from ba._ui import UISubsystem from ba._achievement import AchievementSubsystem from ba._plugin import PluginSubsystem -from ba._account import AccountSubsystem +from ba._accountv1 import AccountV1Subsystem from ba._meta import MetadataSubsystem from ba._ads import AdsSubsystem from ba._net import NetworkSubsystem if TYPE_CHECKING: - import ba - from bastd.actor import spazappearance + import asyncio from typing import Optional, Any, Callable + import ba + from ba.cloud import CloudSubsystem + from bastd.actor import spazappearance + from ba._accountv2 import AccountV2Subsystem + class App: """A class for high level app functionality and state. - Category: App Classes + Category: **App Classes** Use ba.app to access the single shared instance of this class. @@ -38,6 +43,10 @@ class App: # pylint: disable=too-many-public-methods + # Implementations for these will be filled in by internal libs. + accounts_v2: AccountV2Subsystem + cloud: CloudSubsystem + class State(Enum): """High level state the app can be in.""" LAUNCHING = 0 @@ -45,6 +54,20 @@ class App: PAUSED = 2 SHUTTING_DOWN = 3 + @property + def aioloop(self) -> asyncio.AbstractEventLoop: + """The Logic Thread's Asyncio Event Loop. + + This allow async tasks to be run in the logic thread. + Note that, at this time, the asyncio loop is encapsulated + and explicitly stepped by the engine's logic thread loop and + thus things like asyncio.get_running_loop() will not return this + loop from most places in the logic thread; only from within a + task explicitly created in this loop. + """ + assert self._aioloop is not None + return self._aioloop + @property def build_number(self) -> int: """Integer build number. @@ -196,6 +219,8 @@ class App: # refreshed/etc. self.fg_state = 0 + self._aioloop: Optional[asyncio.AbstractEventLoop] = None + self._env = _ba.env() self.protocol_version: int = self._env['protocol_version'] assert isinstance(self.protocol_version, int) @@ -211,6 +236,11 @@ class App: assert isinstance(self.iircade_mode, bool) self.allow_ticket_purchases: bool = not self.iircade_mode + # Default executor which can be used for misc background processing. + # It should also be passed to any asyncio loops we create so that + # everything shares the same single set of threads. + self.threadpool = ThreadPoolExecutor(thread_name_prefix='baworker') + # Misc. self.tips: list[str] = [] self.stress_test_reset_timer: Optional[ba.Timer] = None @@ -235,7 +265,7 @@ class App: self.server: Optional[ba.ServerController] = None self.meta = MetadataSubsystem() - self.accounts = AccountSubsystem() + self.accounts_v1 = AccountV1Subsystem() self.plugins = PluginSubsystem() self.music = MusicSubsystem() self.lang = LanguageSubsystem() @@ -285,11 +315,11 @@ class App: """Runs after the app finishes bootstrapping. (internal)""" - # pylint: disable=too-many-locals # pylint: disable=cyclic-import + # pylint: disable=too-many-locals + from ba import _asyncio from ba import _apputils from ba import _appconfig - from ba import _achievement from ba import _map from ba import _campaign from bastd import appdelegate @@ -299,6 +329,8 @@ class App: import custom_hooks custom_hooks.on_app_launch() + self._aioloop = _asyncio.setup_asyncio() + cfg = self.config self.delegate = appdelegate.AppDelegate() @@ -369,7 +401,8 @@ class App: _ba.timer(3.0, check_special_offer, timetype=TimeType.REAL) self.meta.on_app_launch() - self.accounts.on_app_launch() + self.accounts_v2.on_app_launch() + self.accounts_v1.on_app_launch() self.plugins.on_app_launch() # See note below in on_app_pause. @@ -407,7 +440,7 @@ class App: self._app_paused = False self._update_state() self.fg_state += 1 - self.accounts.on_app_resume() + self.accounts_v1.on_app_resume() self.music.on_app_resume() self.plugins.on_app_resume() @@ -431,7 +464,6 @@ class App: activity: Optional[ba.Activity] = _ba.get_foreground_host_activity() if (activity is not None and activity.allow_pausing and not _ba.have_connected_clients()): - from ba import _gameutils from ba._language import Lstr from ba._nodeactor import NodeActor @@ -574,7 +606,7 @@ class App: appname = _ba.appname() if url.startswith(f'{appname}://code/'): code = url.replace(f'{appname}://code/', '') - self.accounts.add_pending_promo_code(code) + self.accounts_v1.add_pending_promo_code(code) else: _ba.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0)) _ba.playsound(_ba.getsound('error')) diff --git a/dist/ba_data/python/ba/_appconfig.py b/dist/ba_data/python/ba/_appconfig.py index 611483e..26d46b7 100644 --- a/dist/ba_data/python/ba/_appconfig.py +++ b/dist/ba_data/python/ba/_appconfig.py @@ -14,7 +14,7 @@ if TYPE_CHECKING: class AppConfig(dict): """A special dict that holds the game's persistent configuration values. - Category: App Classes + Category: **App Classes** It also provides methods for fetching values with app-defined fallback defaults, applying contained values to the game, and committing the @@ -126,14 +126,14 @@ def read_config() -> tuple[AppConfig, bool]: try: import shutil shutil.copyfile(config_file_path, config_file_path + '.broken') - except Exception as exc: - print('EXC copying broken config:', exc) + except Exception as exc2: + print('EXC copying broken config:', exc2) try: _ba.log('broken config contents:\n' + config_contents.replace('\000', ''), to_stdout=False) - except Exception as exc: - print('EXC logging broken config contents:', exc) + except Exception as exc2: + print('EXC logging broken config contents:', exc2) config = AppConfig() # Now attempt to read one of our 'prev' backup copies. @@ -147,15 +147,15 @@ def read_config() -> tuple[AppConfig, bool]: config = AppConfig() config_file_healthy = True print('successfully read backup config.') - except Exception as exc: - print('EXC reading prev backup config:', exc) + except Exception as exc2: + print('EXC reading prev backup config:', exc2) return config, config_file_healthy def commit_app_config(force: bool = False) -> None: """Commit the config to persistent storage. - Category: General Utility Functions + Category: **General Utility Functions** (internal) """ diff --git a/dist/ba_data/python/ba/_asyncio.py b/dist/ba_data/python/ba/_asyncio.py index 79407a7..40e53c9 100644 --- a/dist/ba_data/python/ba/_asyncio.py +++ b/dist/ba_data/python/ba/_asyncio.py @@ -21,11 +21,12 @@ _asyncio_timer: Optional[ba.Timer] = None _asyncio_event_loop: Optional[asyncio.AbstractEventLoop] = None -def setup_asyncio() -> None: - """Setup asyncio functionality for our game thread.""" +def setup_asyncio() -> asyncio.AbstractEventLoop: + """Setup asyncio functionality for the logic thread.""" # pylint: disable=global-statement import _ba + import ba from ba._generated.enums import TimeType assert _ba.in_game_thread() @@ -40,6 +41,7 @@ def setup_asyncio() -> None: global _asyncio_event_loop # pylint: disable=invalid-name _asyncio_event_loop = asyncio.new_event_loop() + _asyncio_event_loop.set_default_executor(ba.app.threadpool) # Ideally we should integrate asyncio into our C++ Thread class's # low level event loop so that asyncio timers/sockets/etc. could @@ -70,3 +72,5 @@ def setup_asyncio() -> None: print('TEST AIO TASK ENDING') _asyncio_event_loop.create_task(aio_test()) + + return _asyncio_event_loop diff --git a/dist/ba_data/python/ba/_campaign.py b/dist/ba_data/python/ba/_campaign.py index e7f5315..915fc4c 100644 --- a/dist/ba_data/python/ba/_campaign.py +++ b/dist/ba_data/python/ba/_campaign.py @@ -23,9 +23,9 @@ def getcampaign(name: str) -> ba.Campaign: class Campaign: - """Represents a unique set or series of ba.Levels. + """Represents a unique set or series of ba.Level-s. - Category: App Classes + Category: **App Classes** """ def __init__(self, name: str, sequential: bool = True): @@ -52,7 +52,7 @@ class Campaign: @property def levels(self) -> list[ba.Level]: - """The list of ba.Levels in the Campaign.""" + """The list of ba.Level-s in the Campaign.""" return self._levels def getlevel(self, name: str) -> ba.Level: diff --git a/dist/ba_data/python/ba/_collision.py b/dist/ba_data/python/ba/_collision.py index e9db1e8..d44c0f4 100644 --- a/dist/ba_data/python/ba/_collision.py +++ b/dist/ba_data/python/ba/_collision.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: class Collision: """A class providing info about occurring collisions. - Category: Gameplay Classes + Category: **Gameplay Classes** """ @property @@ -67,6 +67,6 @@ _collision = Collision() def getcollision() -> Collision: """Return the in-progress collision. - Category: Gameplay Functions + Category: **Gameplay Functions** """ return _collision diff --git a/dist/ba_data/python/ba/_coopgame.py b/dist/ba_data/python/ba/_coopgame.py index 1d771b5..c3435f3 100644 --- a/dist/ba_data/python/ba/_coopgame.py +++ b/dist/ba_data/python/ba/_coopgame.py @@ -14,14 +14,16 @@ if TYPE_CHECKING: from bastd.actor.playerspaz import PlayerSpaz import ba +# pylint: disable=invalid-name PlayerType = TypeVar('PlayerType', bound='ba.Player') TeamType = TypeVar('TeamType', bound='ba.Team') +# pylint: enable=invalid-name class CoopGameActivity(GameActivity[PlayerType, TeamType]): """Base class for cooperative-mode games. - Category: Gameplay Classes + Category: **Gameplay Classes** """ # We can assume our session is a CoopSession. diff --git a/dist/ba_data/python/ba/_coopsession.py b/dist/ba_data/python/ba/_coopsession.py index db762c9..6e9a1b2 100644 --- a/dist/ba_data/python/ba/_coopsession.py +++ b/dist/ba_data/python/ba/_coopsession.py @@ -132,7 +132,7 @@ class CoopSession(Session): # else: # nextlevel = None nextlevel=levels[(level.index+1)%len(levels)] - + if nextlevel: gametype = nextlevel.gametype settings = nextlevel.get_settings() @@ -284,12 +284,12 @@ class CoopSession(Session): if outcome=="victory" or outcome=="restart" or outcome=="defeat": outcome = 'next_level' - + if (isinstance(activity, (JoinActivity, CoopScoreScreen, TransitionActivity))) or True: - + from features import team_balancer team_balancer.checkToExitCoop() @@ -355,7 +355,7 @@ class CoopSession(Session): else: pass if False: - + playerinfos: list[ba.PlayerInfo] diff --git a/dist/ba_data/python/ba/_dependency.py b/dist/ba_data/python/ba/_dependency.py index 87a3116..c65912f 100644 --- a/dist/ba_data/python/ba/_dependency.py +++ b/dist/ba_data/python/ba/_dependency.py @@ -19,7 +19,7 @@ T = TypeVar('T', bound='DependencyComponent') class Dependency(Generic[T]): """A dependency on a DependencyComponent (with an optional config). - Category: Dependency Classes + Category: **Dependency Classes** This class is used to request and access functionality provided by other DependencyComponent classes from a DependencyComponent class. @@ -87,7 +87,7 @@ class Dependency(Generic[T]): class DependencyComponent: """Base class for all classes that can act as or use dependencies. - category: Dependency Classes + Category: **Dependency Classes** """ _dep_entry: weakref.ref[DependencyEntry] @@ -146,7 +146,7 @@ class DependencyEntry: # This allows us to inject its data properly before __init__(). print('creating', self.cls) instance = self.cls.__new__(self.cls) - # pylint: disable=protected-access + # pylint: disable=protected-access, unnecessary-dunder-call instance._dep_entry = weakref.ref(self) instance.__init__() # type: ignore @@ -165,7 +165,7 @@ class DependencyEntry: class DependencySet(Generic[T]): """Set of resolved dependencies and their associated data. - Category: Dependency Classes + Category: **Dependency Classes** To use DependencyComponents, a set must be created, resolved, and then loaded. The DependencyComponents are only valid while the set remains @@ -291,7 +291,7 @@ class DependencySet(Generic[T]): class AssetPackage(DependencyComponent): """ba.DependencyComponent representing a bundled package of game assets. - Category: Asset Classes + Category: **Asset Classes** """ def __init__(self) -> None: diff --git a/dist/ba_data/python/ba/_dualteamsession.py b/dist/ba_data/python/ba/_dualteamsession.py index 427e706..0b7a327 100644 --- a/dist/ba_data/python/ba/_dualteamsession.py +++ b/dist/ba_data/python/ba/_dualteamsession.py @@ -15,7 +15,7 @@ if TYPE_CHECKING: class DualTeamSession(MultiTeamSession): """ba.Session type for teams mode games. - Category: Gameplay Classes + Category: **Gameplay Classes** """ # Base class overrides: diff --git a/dist/ba_data/python/ba/_error.py b/dist/ba_data/python/ba/_error.py index c9e75fc..bb82a78 100644 --- a/dist/ba_data/python/ba/_error.py +++ b/dist/ba_data/python/ba/_error.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: class DependencyError(Exception): """Exception raised when one or more ba.Dependency items are missing. - category: Exception Classes + Category: **Exception Classes** (this will generally be missing assets). """ @@ -34,7 +34,7 @@ class DependencyError(Exception): class ContextError(Exception): """Exception raised when a call is made in an invalid context. - category: Exception Classes + Category: **Exception Classes** Examples of this include calling UI functions within an Activity context or calling scene manipulation functions outside of a game context. @@ -44,91 +44,91 @@ class ContextError(Exception): class NotFoundError(Exception): """Exception raised when a referenced object does not exist. - category: Exception Classes + Category: **Exception Classes** """ class PlayerNotFoundError(NotFoundError): """Exception raised when an expected ba.Player does not exist. - category: Exception Classes + Category: **Exception Classes** """ class SessionPlayerNotFoundError(NotFoundError): """Exception raised when an expected ba.SessionPlayer does not exist. - category: Exception Classes + Category: **Exception Classes** """ class TeamNotFoundError(NotFoundError): """Exception raised when an expected ba.Team does not exist. - category: Exception Classes + Category: **Exception Classes** """ class DelegateNotFoundError(NotFoundError): """Exception raised when an expected delegate object does not exist. - category: Exception Classes + Category: **Exception Classes** """ class SessionTeamNotFoundError(NotFoundError): """Exception raised when an expected ba.SessionTeam does not exist. - category: Exception Classes + Category: **Exception Classes** """ class NodeNotFoundError(NotFoundError): """Exception raised when an expected ba.Node does not exist. - category: Exception Classes + Category: **Exception Classes** """ class ActorNotFoundError(NotFoundError): """Exception raised when an expected ba.Actor does not exist. - category: Exception Classes + Category: **Exception Classes** """ class ActivityNotFoundError(NotFoundError): """Exception raised when an expected ba.Activity does not exist. - category: Exception Classes + Category: **Exception Classes** """ class SessionNotFoundError(NotFoundError): """Exception raised when an expected ba.Session does not exist. - category: Exception Classes + Category: **Exception Classes** """ class InputDeviceNotFoundError(NotFoundError): """Exception raised when an expected ba.InputDevice does not exist. - category: Exception Classes + Category: **Exception Classes** """ class WidgetNotFoundError(NotFoundError): """Exception raised when an expected ba.Widget does not exist. - category: Exception Classes + Category: **Exception Classes** """ def print_exception(*args: Any, **keywds: Any) -> None: """Print info about an exception along with pertinent context state. - category: General Utility Functions + Category: **General Utility Functions** Prints all arguments provided along with various info about the current context and the outstanding exception. @@ -168,7 +168,7 @@ def print_exception(*args: Any, **keywds: Any) -> None: def print_error(err_str: str, once: bool = False) -> None: """Print info about an error along with pertinent context state. - category: General Utility Functions + Category: **General Utility Functions** Prints all positional arguments provided along with various info about the current context. diff --git a/dist/ba_data/python/ba/_freeforallsession.py b/dist/ba_data/python/ba/_freeforallsession.py index c0ceee9..a33c827 100644 --- a/dist/ba_data/python/ba/_freeforallsession.py +++ b/dist/ba_data/python/ba/_freeforallsession.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: class FreeForAllSession(MultiTeamSession): """ba.Session type for free-for-all mode games. - Category: Gameplay Classes + Category: **Gameplay Classes** """ use_teams = False use_team_colors = False diff --git a/dist/ba_data/python/ba/_gameactivity.py b/dist/ba_data/python/ba/_gameactivity.py index c7d633e..419eae0 100644 --- a/dist/ba_data/python/ba/_gameactivity.py +++ b/dist/ba_data/python/ba/_gameactivity.py @@ -24,14 +24,16 @@ if TYPE_CHECKING: from bastd.actor.bomb import TNTSpawner import ba +# pylint: disable=invalid-name PlayerType = TypeVar('PlayerType', bound='ba.Player') TeamType = TypeVar('TeamType', bound='ba.Team') +# pylint: enable=invalid-name class GameActivity(Activity[PlayerType, TeamType]): """Common base class for all game ba.Activities. - category: Gameplay Classes + Category: **Gameplay Classes** """ # pylint: disable=too-many-public-methods @@ -237,11 +239,11 @@ class GameActivity(Activity[PlayerType, TeamType]): self._zoom_message_times: dict[int, float] = {} self._is_waiting_for_continue = False - self._continue_cost = _ba.get_account_misc_read_val( + self._continue_cost = _ba.get_v1_account_misc_read_val( 'continueStartCost', 25) - self._continue_cost_mult = _ba.get_account_misc_read_val( + self._continue_cost_mult = _ba.get_v1_account_misc_read_val( 'continuesMult', 2) - self._continue_cost_offset = _ba.get_account_misc_read_val( + self._continue_cost_offset = _ba.get_v1_account_misc_read_val( 'continuesOffset', 0) @property @@ -258,6 +260,7 @@ class GameActivity(Activity[PlayerType, TeamType]): """Return a name for this particular game instance.""" return self.get_display_string(self.settings_raw) + # noinspection PyUnresolvedReferences def get_instance_scoreboard_display_string(self) -> ba.Lstr: """Return a name for this particular game instance. @@ -387,7 +390,7 @@ class GameActivity(Activity[PlayerType, TeamType]): from ba._generated.enums import TimeType try: - if _ba.get_account_misc_read_val('enableContinues', False): + if _ba.get_v1_account_misc_read_val('enableContinues', False): session = self.session # We only support continuing in non-tournament games. @@ -464,7 +467,7 @@ class GameActivity(Activity[PlayerType, TeamType]): data_t = data['t'] # This used to be the whole payload. # Keep our cached tourney info up to date - _ba.app.accounts.cache_tournament_info(data_t) + _ba.app.accounts_v1.cache_tournament_info(data_t) self._setup_tournament_time_limit( max(5, data_t[0]['timeRemaining'])) diff --git a/dist/ba_data/python/ba/_gameresults.py b/dist/ba_data/python/ba/_gameresults.py index f4b3ebd..159a6d5 100644 --- a/dist/ba_data/python/ba/_gameresults.py +++ b/dist/ba_data/python/ba/_gameresults.py @@ -27,10 +27,10 @@ class GameResults: """ Results for a completed game. - Category: Gameplay Classes + Category: **Gameplay Classes** Upon completion, a game should fill one of these out and pass it to its - ba.Activity.end() call. + ba.Activity.end call. """ def __init__(self) -> None: diff --git a/dist/ba_data/python/ba/_gameutils.py b/dist/ba_data/python/ba/_gameutils.py index d337f3d..0a4c4ee 100644 --- a/dist/ba_data/python/ba/_gameutils.py +++ b/dist/ba_data/python/ba/_gameutils.py @@ -29,7 +29,7 @@ TROPHY_CHARS = { class GameTip: """Defines a tip presentable to the user at the start of a game. - Category: Gameplay Classes + Category: **Gameplay Classes** """ text: str icon: Optional[ba.Texture] = None @@ -53,7 +53,7 @@ def animate(node: ba.Node, suppress_format_warning: bool = False) -> ba.Node: """Animate values on a target ba.Node. - Category: Gameplay Functions + Category: **Gameplay Functions** Creates an 'animcurve' node with the provided values and time as an input, connect it to the provided attribute, and set it to die with the target. @@ -98,6 +98,7 @@ def animate(node: ba.Node, # FIXME: Even if we are looping we should have a way to die once we # get disconnected. if not loop: + # noinspection PyUnresolvedReferences _ba.timer(int(mult * items[-1][0]) + 1000, curve.delete, timeformat=TimeFormat.MILLISECONDS) @@ -127,9 +128,9 @@ def animate_array(node: ba.Node, suppress_format_warning: bool = False) -> None: """Animate an array of values on a target ba.Node. - Category: Gameplay Functions + Category: **Gameplay Functions** - Like ba.animate(), but operates on array attributes. + Like ba.animate, but operates on array attributes. """ # pylint: disable=too-many-locals combine = _ba.newnode('combine', owner=node, attrs={'size': size}) @@ -178,6 +179,7 @@ def animate_array(node: ba.Node, # curve after its done its job. if not loop: # (PyCharm seems to think item is a float, not a tuple) + # noinspection PyUnresolvedReferences _ba.timer(int(mult * items[-1][0]) + 1000, curve.delete, timeformat=TimeFormat.MILLISECONDS) @@ -189,6 +191,7 @@ def animate_array(node: ba.Node, # once we get disconnected. if not loop: # (PyCharm seems to think item is a float, not a tuple) + # noinspection PyUnresolvedReferences _ba.timer(int(mult * items[-1][0]) + 1000, combine.delete, timeformat=TimeFormat.MILLISECONDS) @@ -198,7 +201,7 @@ def show_damage_count(damage: str, position: Sequence[float], direction: Sequence[float]) -> None: """Pop up a damage count at a position in space. - Category: Gameplay Functions + Category: **Gameplay Functions** """ lifespan = 1.0 app = _ba.app @@ -253,7 +256,7 @@ def timestring(timeval: float, suppress_format_warning: bool = False) -> ba.Lstr: """Generate a ba.Lstr for displaying a time value. - Category: General Utility Functions + Category: **General Utility Functions** Given a time value, returns a ba.Lstr with: (hours if > 0 ) : minutes : seconds : (centiseconds if centi=True). @@ -321,7 +324,7 @@ def timestring(timeval: float, def cameraflash(duration: float = 999.0) -> None: """Create a strobing camera flash effect. - Category: Gameplay Functions + Category: **Gameplay Functions** (as seen when a team wins a game) Duration is in seconds. diff --git a/dist/ba_data/python/ba/_general.py b/dist/ba_data/python/ba/_general.py index e919138..e9462ee 100644 --- a/dist/ba_data/python/ba/_general.py +++ b/dist/ba_data/python/ba/_general.py @@ -24,22 +24,23 @@ if TYPE_CHECKING: class Existable(Protocol): """A Protocol for objects supporting an exists() method. - Category: Protocols + Category: **Protocols** """ def exists(self) -> bool: """Whether this object exists.""" - ... +# pylint: disable=invalid-name ExistableType = TypeVar('ExistableType', bound=Existable) +# pylint: enable=invalid-name T = TypeVar('T') def existing(obj: Optional[ExistableType]) -> Optional[ExistableType]: """Convert invalid references to None for any ba.Existable object. - Category: Gameplay Functions + Category: **Gameplay Functions** To best support type checking, it is important that invalid references not be passed around and instead get converted to values of None. @@ -59,7 +60,7 @@ def existing(obj: Optional[ExistableType]) -> Optional[ExistableType]: def getclass(name: str, subclassof: type[T]) -> type[T]: """Given a full class name such as foo.bar.MyClass, return the class. - Category: General Utility Functions + Category: **General Utility Functions** The class will be checked to make sure it is a subclass of the provided 'subclassof' class, and a TypeError will be raised if not. @@ -140,7 +141,7 @@ def get_type_name(cls: type) -> str: class _WeakCall: """Wrap a callable and arguments into a single callable object. - Category: General Utility Classes + Category: **General Utility Classes** When passed a bound method as the callable, the instance portion of it is weak-referenced, meaning the underlying instance is @@ -150,20 +151,30 @@ class _WeakCall: Think of this as a handy way to tell an object to do something at some point in the future if it happens to still exist. - # EXAMPLE A: this code will create a FooClass instance and call its - # bar() method 5 seconds later; it will be kept alive even though - # we overwrite its variable with None because the bound method - # we pass as a timer callback (foo.bar) strong-references it - foo = FooClass() - ba.timer(5.0, foo.bar) - foo = None + ##### Examples + **EXAMPLE A:** this code will create a FooClass instance and call its + bar() method 5 seconds later; it will be kept alive even though + we overwrite its variable with None because the bound method + we pass as a timer callback (foo.bar) strong-references it + >>> foo = FooClass() + ... ba.timer(5.0, foo.bar) + ... foo = None - # EXAMPLE B: this code will *not* keep our object alive; it will die - # when we overwrite it with None and the timer will be a no-op when it - # fires - foo = FooClass() - ba.timer(5.0, ba.WeakCall(foo.bar)) - foo = None + **EXAMPLE B:** This code will *not* keep our object alive; it will die + when we overwrite it with None and the timer will be a no-op when it + fires + >>> foo = FooClass() + ... ba.timer(5.0, ba.WeakCall(foo.bar)) + ... foo = None + + **EXAMPLE C:** Wrap a method call with some positional and keyword args: + >>> myweakcall = ba.WeakCall(self.dostuff, argval1, + ... namedarg=argval2) + ... # Now we have a single callable to run that whole mess. + ... # The same as calling myobj.dostuff(argval1, namedarg=argval2) + ... # (provided my_obj still exists; this will do nothing + ... # otherwise). + ... myweakcall() Note: additional args and keywords you provide to the WeakCall() constructor are stored as regular strong-references; you'll need @@ -175,15 +186,6 @@ class _WeakCall: Pass a callable as the first arg, followed by any number of arguments or keywords. - - # Example: wrap a method call with some positional and - # keyword args: - myweakcall = ba.WeakCall(myobj.dostuff, argval1, namedarg=argval2) - - # Now we have a single callable to run that whole mess. - # The same as calling myobj.dostuff(argval1, namedarg=argval2) - # (provided my_obj still exists; this will do nothing otherwise) - myweakcall() """ if hasattr(args[0], '__func__'): self._call = WeakMethod(args[0]) @@ -212,13 +214,13 @@ class _WeakCall: class _Call: """Wraps a callable and arguments into a single callable object. - Category: General Utility Classes + Category: **General Utility Classes** The callable is strong-referenced so it won't die until this object does. - Note that a bound method (ex: myobj.dosomething) contains a reference - to 'self' (myobj in that case), so you will be keeping that object + Note that a bound method (ex: ``myobj.dosomething``) contains a reference + to ``self`` (``myobj`` in that case), so you will be keeping that object alive too. Use ba.WeakCall if you want to pass a method to callback without keeping its object alive. """ @@ -229,12 +231,12 @@ class _Call: Pass a callable as the first arg, followed by any number of arguments or keywords. - # Example: wrap a method call with 1 positional and 1 keyword arg: - mycall = ba.Call(myobj.dostuff, argval1, namedarg=argval2) - - # Now we have a single callable to run that whole mess. - # ..the same as calling myobj.dostuff(argval1, namedarg=argval2) - mycall() + ##### Example + Wrap a method call with 1 positional and 1 keyword arg: + >>> mycall = ba.Call(myobj.dostuff, argval, namedarg=argval2) + ... # Now we have a single callable to run that whole mess. + ... # ..the same as calling myobj.dostuff(argval, namedarg=argval2) + ... mycall() """ self._call = args[0] self._args = args[1:] @@ -283,7 +285,7 @@ class WeakMethod: def verify_object_death(obj: object) -> None: """Warn if an object does not get freed within a short period. - Category: General Utility Functions + Category: **General Utility Functions** This can be handy to detect and prevent memory/resource leaks. """ @@ -304,7 +306,7 @@ def verify_object_death(obj: object) -> None: def print_active_refs(obj: Any) -> None: """Print info about things referencing a given object. - Category: General Utility Functions + Category: **General Utility Functions** Useful for tracking down cyclical references and causes for zombie objects. """ @@ -361,7 +363,7 @@ def _verify_object_death(wref: weakref.ref) -> None: def storagename(suffix: str = None) -> str: """Generate a unique name for storing class data in shared places. - Category: General Utility Functions + Category: **General Utility Functions** This consists of a leading underscore, the module path at the call site with dots replaced by underscores, the containing class's @@ -371,15 +373,17 @@ def storagename(suffix: str = None) -> str: Note that this will function even if called in the class definition. - # Example: generate a unique name for storage purposes: - class MyThingie: - - # This will give something like '_mymodule_submodule_mythingie_data'. - _STORENAME = ba.storagename('data') - - # Use that name to store some data in the Activity we were passed. - def __init__(self, activity): - activity.customdata[self._STORENAME] = {} + ##### Examples + Generate a unique name for storage purposes: + >>> class MyThingie: + ... # This will give something like + ... # '_mymodule_submodule_mythingie_data'. + ... _STORENAME = ba.storagename('data') + ... + ... # Use that name to store some data in the Activity we were + ... # passed. + ... def __init__(self, activity): + ... activity.customdata[self._STORENAME] = {} """ frame = inspect.currentframe() if frame is None: diff --git a/dist/ba_data/python/ba/_hooks.py b/dist/ba_data/python/ba/_hooks.py index 61a721a..f649f0a 100644 --- a/dist/ba_data/python/ba/_hooks.py +++ b/dist/ba_data/python/ba/_hooks.py @@ -24,12 +24,11 @@ if TYPE_CHECKING: def finish_bootstrapping() -> None: """Do final bootstrapping related bits.""" - from ba._asyncio import setup_asyncio assert _ba.in_game_thread() # Kick off our asyncio event handling, allowing us to use coroutines # in our game thread alongside our internal event handling. - setup_asyncio() + # setup_asyncio() # Ok, bootstrapping is done; time to get the show started. _ba.app.on_app_launch() @@ -337,6 +336,8 @@ def filter_chat_message(msg: str, client_id: int) -> Optional[str]: return chooks.filter_chat_message(msg,client_id) +def on_client_request(ip): + print("player requesting to join from ip = " + ip) def kick_vote_started(by:str,to:str) -> None: """ get account ids of who started kick vote for whom , @@ -385,3 +386,8 @@ def hash_strings(inputs: list[str]) -> str: sha.update(inp.encode()) return sha.hexdigest() + + +def have_account_v2_credentials() -> bool: + """Do we have primary account-v2 credentials set?""" + return _ba.app.accounts_v2.have_primary_credentials() diff --git a/dist/ba_data/python/ba/_input.py b/dist/ba_data/python/ba/_input.py index fcf96ef..bfea728 100644 --- a/dist/ba_data/python/ba/_input.py +++ b/dist/ba_data/python/ba/_input.py @@ -639,5 +639,5 @@ def get_last_player_name_from_input_device(device: ba.InputDevice) -> str: if profilename == '_random': profilename = device.get_default_player_name() if profilename == '__account__': - profilename = _ba.get_account_display_string() + profilename = _ba.get_v1_account_display_string() return profilename diff --git a/dist/ba_data/python/ba/_keyboard.py b/dist/ba_data/python/ba/_keyboard.py index 245cbea..36dfc18 100644 --- a/dist/ba_data/python/ba/_keyboard.py +++ b/dist/ba_data/python/ba/_keyboard.py @@ -13,23 +13,21 @@ if TYPE_CHECKING: class Keyboard: """Chars definitions for on-screen keyboard. - Category: App Classes + Category: **App Classes** Keyboards are discoverable by the meta-tag system and the user can select which one they want to use. On-screen keyboard uses chars from active ba.Keyboard. - Attributes: - name - Displays when user selecting this keyboard. - chars - Used for row/column lengths. - pages - Extra chars like emojis. - nums - The 'num' page. """ name: str + """Displays when user selecting this keyboard.""" + chars: list[tuple[str, ...]] + """Used for row/column lengths.""" + pages: dict[str, tuple[str, ...]] + """Extra chars like emojis.""" + nums: tuple[str, ...] + """The 'num' page.""" diff --git a/dist/ba_data/python/ba/_language.py b/dist/ba_data/python/ba/_language.py index b637bb4..e997191 100644 --- a/dist/ba_data/python/ba/_language.py +++ b/dist/ba_data/python/ba/_language.py @@ -17,7 +17,7 @@ if TYPE_CHECKING: class LanguageSubsystem: """Wraps up language related app functionality. - Category: App Classes + Category: **App Classes** To use this class, access the single instance of it at 'ba.app.lang'. """ @@ -367,7 +367,7 @@ class LanguageSubsystem: class Lstr: """Used to define strings in a language-independent way. - category: General Utility Classes + Category: **General Utility Classes** These should be used whenever possible in place of hard-coded strings so that in-game or UI elements show up correctly on all clients in their @@ -376,24 +376,28 @@ class Lstr: To see available resource keys, look at any of the bs_language_*.py files in the game or the translations pages at legacy.ballistica.net/translate. - # EXAMPLE 1: specify a string from a resource path - mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText') + ##### Examples + EXAMPLE 1: specify a string from a resource path + >>> mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText') - # EXAMPLE 2: specify a translated string via a category and english value; - # if a translated value is available, it will be used; otherwise the - # english value will be. To see available translation categories, look - # under the 'translations' resource section. - mynode.text = ba.Lstr(translate=('gameDescriptions', 'Defeat all enemies')) + EXAMPLE 2: specify a translated string via a category and english + value; if a translated value is available, it will be used; otherwise + the english value will be. To see available translation categories, + look under the 'translations' resource section. + >>> mynode.text = ba.Lstr(translate=('gameDescriptions', + ... 'Defeat all enemies')) - # EXAMPLE 3: specify a raw value and some substitutions. Substitutions can - # be used with resource and translate modes as well. - mynode.text = ba.Lstr(value='${A} / ${B}', - subs=[('${A}', str(score)), ('${B}', str(total))]) + EXAMPLE 3: specify a raw value and some substitutions. Substitutions + can be used with resource and translate modes as well. + >>> mynode.text = ba.Lstr(value='${A} / ${B}', + ... subs=[('${A}', str(score)), ('${B}', str(total))]) - # EXAMPLE 4: Lstrs can be nested. This example would display the resource - # at res_a but replace ${NAME} with the value of the resource at res_b - mytextnode.text = ba.Lstr(resource='res_a', - subs=[('${NAME}', ba.Lstr(resource='res_b'))]) + EXAMPLE 4: ba.Lstr's can be nested. This example would display the + resource at res_a but replace ${NAME} with the value of the + resource at res_b + >>> mytextnode.text = ba.Lstr( + ... resource='res_a', + ... subs=[('${NAME}', ba.Lstr(resource='res_b'))]) """ # pylint: disable=dangerous-default-value @@ -406,7 +410,6 @@ class Lstr: fallback_value: str = '', subs: Sequence[tuple[str, Union[str, Lstr]]] = []) -> None: """Create an Lstr from a string resource.""" - ... # noinspection PyShadowingNames,PyDefaultArgument @overload @@ -415,7 +418,6 @@ class Lstr: translate: tuple[str, str], subs: Sequence[tuple[str, Union[str, Lstr]]] = []) -> None: """Create an Lstr by translating a string in a category.""" - ... # noinspection PyDefaultArgument @overload @@ -424,7 +426,6 @@ class Lstr: value: str, subs: Sequence[tuple[str, Union[str, Lstr]]] = []) -> None: """Create an Lstr from a raw string value.""" - ... # pylint: enable=redefined-outer-name, dangerous-default-value diff --git a/dist/ba_data/python/ba/_level.py b/dist/ba_data/python/ba/_level.py index 53e67f1..968610a 100644 --- a/dist/ba_data/python/ba/_level.py +++ b/dist/ba_data/python/ba/_level.py @@ -17,7 +17,7 @@ if TYPE_CHECKING: class Level: """An entry in a ba.Campaign consisting of a name, game type, and settings. - category: Gameplay Classes + Category: **Gameplay Classes** """ def __init__(self, diff --git a/dist/ba_data/python/ba/_lobby.py b/dist/ba_data/python/ba/_lobby.py index f063f53..bd953b8 100644 --- a/dist/ba_data/python/ba/_lobby.py +++ b/dist/ba_data/python/ba/_lobby.py @@ -410,6 +410,7 @@ class Chooser: self._profileindex = self._profilenames.index(self._profilename) else: self._profileindex = 0 + # noinspection PyUnresolvedReferences self._profilename = self._profilenames[self._profileindex] def update_position(self) -> None: @@ -451,7 +452,8 @@ class Chooser: clamp = not full elif name == '__account__': try: - name = self._sessionplayer.inputdevice.get_account_name(full) + name = self._sessionplayer.inputdevice.get_v1_account_name( + full) except Exception: print_exception('Error getting account name for chooser.') name = 'Invalid' @@ -893,7 +895,7 @@ class Lobby: self.character_names_local_unlocked.sort(key=lambda x: x.lower()) # Do any overall prep we need to such as creating account profile. - _ba.app.accounts.ensure_have_account_player_profile() + _ba.app.accounts_v1.ensure_have_account_player_profile() for chooser in self.choosers: try: chooser.reload_profiles() diff --git a/dist/ba_data/python/ba/_map.py b/dist/ba_data/python/ba/_map.py index bb6454d..6236700 100644 --- a/dist/ba_data/python/ba/_map.py +++ b/dist/ba_data/python/ba/_map.py @@ -18,7 +18,7 @@ if TYPE_CHECKING: def preload_map_preview_media() -> None: """Preload media needed for map preview UIs. - Category: Asset Functions + Category: **Asset Functions** """ _ba.getmodel('level_select_button_opaque') _ba.getmodel('level_select_button_transparent') @@ -31,7 +31,7 @@ def preload_map_preview_media() -> None: def get_filtered_map_name(name: str) -> str: """Filter a map name to account for name changes, etc. - Category: Asset Functions + Category: **Asset Functions** This can be used to support old playlists, etc. """ @@ -46,7 +46,7 @@ def get_filtered_map_name(name: str) -> str: def get_map_display_string(name: str) -> ba.Lstr: """Return a ba.Lstr for displaying a given map\'s name. - Category: Asset Functions + Category: **Asset Functions** """ from ba import _language return _language.Lstr(translate=('mapsNames', name)) @@ -55,7 +55,7 @@ def get_map_display_string(name: str) -> ba.Lstr: def getmaps(playtype: str) -> list[str]: """Return a list of ba.Map types supporting a playtype str. - Category: Asset Functions + Category: **Asset Functions** Maps supporting a given playtype must provide a particular set of features and lend themselves to a certain style of play. @@ -104,7 +104,7 @@ def getmaps(playtype: str) -> list[str]: def get_unowned_maps() -> list[str]: """Return the list of local maps not owned by the current account. - Category: Asset Functions + Category: **Asset Functions** """ from ba import _store unowned_maps: set[str] = set() @@ -120,7 +120,7 @@ def get_unowned_maps() -> list[str]: def get_map_class(name: str) -> type[ba.Map]: """Return a map type given a name. - Category: Asset Functions + Category: **Asset Functions** """ name = get_filtered_map_name(name) try: @@ -133,7 +133,7 @@ def get_map_class(name: str) -> type[ba.Map]: class Map(Actor): """A game map. - Category: Gameplay Classes + Category: **Gameplay Classes** Consists of a collection of terrain nodes, metadata, and other functionality comprising a game map. @@ -189,7 +189,6 @@ class Map(Actor): def __init__(self, vr_overlay_offset: Optional[Sequence[float]] = None) -> None: """Instantiate a map.""" - from ba import _gameutils super().__init__() # This is expected to always be a ba.Node object (whether valid or not) @@ -348,7 +347,7 @@ class Map(Actor): self, players: Sequence[ba.Player]) -> Sequence[float]: """Return a random starting position in one of the FFA spawn areas. - If a list of ba.Players is provided; the returned points will be + If a list of ba.Player-s is provided; the returned points will be as far from these players as possible. """ diff --git a/dist/ba_data/python/ba/_messages.py b/dist/ba_data/python/ba/_messages.py index a871d4b..feebceb 100644 --- a/dist/ba_data/python/ba/_messages.py +++ b/dist/ba_data/python/ba/_messages.py @@ -50,45 +50,38 @@ class DeathType(Enum): class DieMessage: """A message telling an object to die. - Category: Message Classes - - Most ba.Actors respond to this. - - Attributes: - - immediate - If this is set to True, the actor should disappear immediately. - This is for 'removing' stuff from the game more so than 'killing' - it. If False, the actor should die a 'normal' death and can take - its time with lingering corpses, sound effects, etc. - - how - The particular reason for death. + Category: **Message Classes** + Most ba.Actor-s respond to this. """ + immediate: bool = False + """If this is set to True, the actor should disappear immediately. + This is for 'removing' stuff from the game more so than 'killing' + it. If False, the actor should die a 'normal' death and can take + its time with lingering corpses, sound effects, etc.""" + how: DeathType = DeathType.GENERIC + """The particular reason for death.""" +# pylint: disable=invalid-name PlayerType = TypeVar('PlayerType', bound='ba.Player') +# pylint: enable=invalid-name class PlayerDiedMessage: """A message saying a ba.Player has died. - category: Message Classes - - Attributes: - - killed - If True, the player was killed; - If False, they left the game or the round ended. - - how - The particular type of death. + Category: **Message Classes** """ + killed: bool + """If True, the player was killed; + If False, they left the game or the round ended.""" + how: ba.DeathType + """The particular type of death.""" def __init__(self, player: ba.Player, was_killed: bool, killerplayer: Optional[ba.Player], how: ba.DeathType): @@ -132,41 +125,34 @@ class PlayerDiedMessage: class StandMessage: """A message telling an object to move to a position in space. - Category: Message Classes + Category: **Message Classes** Used when teleporting players to home base, etc. - - Attributes: - - position - Where to move to. - - angle - The angle to face (in degrees) """ + position: Sequence[float] = (0.0, 0.0, 0.0) + """Where to move to.""" + angle: float = 0.0 + """The angle to face (in degrees)""" @dataclass class PickUpMessage: """Tells an object that it has picked something up. - Category: Message Classes - - Attributes: - - node - The ba.Node that is getting picked up. + Category: **Message Classes** """ + node: ba.Node + """The ba.Node that is getting picked up.""" @dataclass class DropMessage: """Tells an object that it has dropped what it was holding. - Category: Message Classes + Category: **Message Classes** """ @@ -174,35 +160,29 @@ class DropMessage: class PickedUpMessage: """Tells an object that it has been picked up by something. - Category: Message Classes - - Attributes: - - node - The ba.Node doing the picking up. + Category: **Message Classes** """ + node: ba.Node + """The ba.Node doing the picking up.""" @dataclass class DroppedMessage: """Tells an object that it has been dropped. - Category: Message Classes - - Attributes: - - node - The ba.Node doing the dropping. + Category: **Message Classes** """ + node: ba.Node + """The ba.Node doing the dropping.""" @dataclass class ShouldShatterMessage: """Tells an object that it should shatter. - Category: Message Classes + Category: **Message Classes** """ @@ -210,21 +190,18 @@ class ShouldShatterMessage: class ImpactDamageMessage: """Tells an object that it has been jarred violently. - Category: Message Classes - - Attributes: - - intensity - The intensity of the impact. + Category: **Message Classes** """ + intensity: float + """The intensity of the impact.""" @dataclass class FreezeMessage: """Tells an object to become frozen. - Category: Message Classes + Category: **Message Classes** As seen in the effects of an ice ba.Bomb. """ @@ -234,7 +211,7 @@ class FreezeMessage: class ThawMessage: """Tells an object to stop being frozen. - Category: Message Classes + Category: **Message Classes** """ @@ -242,20 +219,17 @@ class ThawMessage: class CelebrateMessage: """Tells an object to celebrate. - Category: Message Classes - - Attributes: - - duration - Amount of time to celebrate in seconds. + Category: **Message Classes** """ + duration: float = 10.0 + """Amount of time to celebrate in seconds.""" class HitMessage: """Tells an object it has been hit in some way. - Category: Message Classes + Category: **Message Classes** This is used by punches, explosions, etc to convey their effect to a target. diff --git a/dist/ba_data/python/ba/_meta.py b/dist/ba_data/python/ba/_meta.py index 7776a5b..017ff85 100644 --- a/dist/ba_data/python/ba/_meta.py +++ b/dist/ba_data/python/ba/_meta.py @@ -37,7 +37,7 @@ class ScanResults: class MetadataSubsystem: """Subsystem for working with script metadata in the app. - Category: App Classes + Category: **App Classes** Access the single shared instance of this class at 'ba.app.meta'. """ diff --git a/dist/ba_data/python/ba/_multiteamsession.py b/dist/ba_data/python/ba/_multiteamsession.py index 683ddde..29b4c1e 100644 --- a/dist/ba_data/python/ba/_multiteamsession.py +++ b/dist/ba_data/python/ba/_multiteamsession.py @@ -22,7 +22,7 @@ DEFAULT_TEAM_NAMES = ('Blue', 'Red') class MultiTeamSession(Session): """Common base class for ba.DualTeamSession and ba.FreeForAllSession. - Category: Gameplay Classes + Category: **Gameplay Classes** Free-for-all-mode is essentially just teams-mode with each ba.Player having their own ba.Team, so there is much overlap in functionality. @@ -141,7 +141,7 @@ class MultiTeamSession(Session): team.customdata['previous_score'] = team.customdata['score'] = 0 def get_max_players(self) -> int: - """Return max number of ba.Players allowed to join the game at once.""" + """Return max number of ba.Player-s allowed to join the game at once""" if self.use_teams: return _ba.app.config.get('Team Game Max Players', 8) return _ba.app.config.get('Free-for-All Max Players', 8) diff --git a/dist/ba_data/python/ba/_music.py b/dist/ba_data/python/ba/_music.py index 7cf3815..82f9c78 100644 --- a/dist/ba_data/python/ba/_music.py +++ b/dist/ba_data/python/ba/_music.py @@ -18,7 +18,7 @@ if TYPE_CHECKING: class MusicType(Enum): """Types of music available to play in-game. - Category: Enums + Category: **Enums** These do not correspond to specific pieces of music, but rather to 'situations'. The actual music played for each type can be overridden @@ -51,7 +51,7 @@ class MusicType(Enum): class MusicPlayMode(Enum): """Influences behavior when playing music. - Category: Enums + Category: **Enums** """ REGULAR = 'regular' TEST = 'test' @@ -61,7 +61,7 @@ class MusicPlayMode(Enum): class AssetSoundtrackEntry: """A music entry using an internal asset. - Category: App Classes + Category: **App Classes** """ assetname: str volume: float = 1.0 @@ -120,7 +120,7 @@ ASSET_SOUNDTRACK_ENTRIES: dict[MusicType, AssetSoundtrackEntry] = { class MusicSubsystem: """Subsystem for music playback in the app. - Category: App Classes + Category: **App Classes** Access the single shared instance of this class at 'ba.app.music'. """ @@ -385,7 +385,7 @@ class MusicSubsystem: class MusicPlayer: """Wrangles soundtrack music playback. - Category: App Classes + Category: **App Classes** Music can be played either through the game itself or via a platform-specific external player. @@ -474,7 +474,7 @@ def setmusic(musictype: Optional[ba.MusicType], continuous: bool = False) -> None: """Set the app to play (or stop playing) a certain type of music. - category: Gameplay Functions + category: **Gameplay Functions** This function will handle loading and playing sound assets as necessary, and also supports custom user soundtracks on specific platforms so the @@ -485,7 +485,6 @@ def setmusic(musictype: Optional[ba.MusicType], if 'continuous' is True and musictype is the same as what is already playing, the playing track will not be restarted. """ - from ba import _gameutils # All we do here now is set a few music attrs on the current globals # node. The foreground globals' current playing music then gets fed to diff --git a/dist/ba_data/python/ba/_net.py b/dist/ba_data/python/ba/_net.py index d427ccc..f6c05b9 100644 --- a/dist/ba_data/python/ba/_net.py +++ b/dist/ba_data/python/ba/_net.py @@ -14,7 +14,6 @@ import _ba if TYPE_CHECKING: from typing import Any, Union, Callable, Optional import socket - import ba MasterServerCallback = Callable[[Union[None, dict[str, Any]]], None] # Timeout for standard functions talking to the master-server/etc. @@ -26,9 +25,14 @@ class NetworkSubsystem: def __init__(self) -> None: - # Anyone accessing/modifying region_pings should hold this lock. - self.region_pings_lock = threading.Lock() - self.region_pings: dict[str, float] = {} + # Anyone accessing/modifying zone_pings should hold this lock, + # as it is updated by a background thread. + self.zone_pings_lock = threading.Lock() + + # Region IDs mapped to average pings. This will remain empty + # until enough pings have been run to be reasonably certain + # that a nearby server has been pinged. + self.zone_pings: dict[str, float] = {} # For debugging. self.v1_test_log: str = '' @@ -106,7 +110,7 @@ class MasterServerCallThread(threading.Thread): def run(self) -> None: # pylint: disable=too-many-branches, consider-using-with import urllib.request - import urllib.error + import urllib.parse import json from efro.error import is_urllib_network_error @@ -114,19 +118,19 @@ class MasterServerCallThread(threading.Thread): try: self._data = _general.utf8_all(self._data) _ba.set_thread_name('BA_ServerCallThread') - parse = urllib.parse if self._request_type == 'get': response = urllib.request.urlopen( urllib.request.Request( (_ba.get_master_server_address() + '/' + - self._request + '?' + parse.urlencode(self._data)), - None, {'User-Agent': _ba.app.user_agent_string}), + self._request + '?' + + urllib.parse.urlencode(self._data)), None, + {'User-Agent': _ba.app.user_agent_string}), timeout=DEFAULT_REQUEST_TIMEOUT_SECONDS) elif self._request_type == 'post': response = urllib.request.urlopen( urllib.request.Request( _ba.get_master_server_address() + '/' + self._request, - parse.urlencode(self._data).encode(), + urllib.parse.urlencode(self._data).encode(), {'User-Agent': _ba.app.user_agent_string}), timeout=DEFAULT_REQUEST_TIMEOUT_SECONDS) else: diff --git a/dist/ba_data/python/ba/_nodeactor.py b/dist/ba_data/python/ba/_nodeactor.py index 756a7fc..e9e78a2 100644 --- a/dist/ba_data/python/ba/_nodeactor.py +++ b/dist/ba_data/python/ba/_nodeactor.py @@ -17,7 +17,7 @@ if TYPE_CHECKING: class NodeActor(Actor): """A simple ba.Actor type that wraps a single ba.Node. - Category: Gameplay Classes + Category: **Gameplay Classes** This Actor will delete its Node when told to die, and it's exists() call will return whether the Node still exists or not. diff --git a/dist/ba_data/python/ba/_player.py b/dist/ba_data/python/ba/_player.py index a472853..965213d 100644 --- a/dist/ba_data/python/ba/_player.py +++ b/dist/ba_data/python/ba/_player.py @@ -16,8 +16,10 @@ if TYPE_CHECKING: from typing import Optional, Sequence, Any, Union, Callable import ba +# pylint: disable=invalid-name PlayerType = TypeVar('PlayerType', bound='ba.Player') TeamType = TypeVar('TeamType', bound='ba.Team') +# pylint: enable=invalid-name @dataclass @@ -48,18 +50,15 @@ class Player(Generic[TeamType]): These correspond to ba.SessionPlayer objects, but are associated with a single ba.Activity instance. This allows activities to specify their own custom ba.Player types. - - Attributes: - - actor - The ba.Actor associated with the player. - """ # These are instance attrs but we define them at the type level so # their type annotations are introspectable (for docs generation). character: str + actor: Optional[ba.Actor] + """The ba.Actor associated with the player.""" + color: Sequence[float] highlight: Sequence[float] @@ -225,8 +224,7 @@ class Player(Generic[TeamType]): return self._sessionplayer.exists() and not self._expired def getname(self, full: bool = False, icon: bool = True) -> str: - """getname(full: bool = False, icon: bool = True) -> str - + """ Returns the player's name. If icon is True, the long version of the name may include an icon. """ @@ -235,8 +233,7 @@ class Player(Generic[TeamType]): return self._sessionplayer.getname(full=full, icon=icon) def is_alive(self) -> bool: - """is_alive() -> bool - + """ Returns True if the player has a ba.Actor assigned and its is_alive() method return True. False is returned otherwise. """ @@ -245,8 +242,7 @@ class Player(Generic[TeamType]): return self.actor is not None and self.actor.is_alive() def get_icon(self) -> dict[str, Any]: - """get_icon() -> dict[str, Any] - + """ Returns the character's icon (images, colors, etc contained in a dict) """ assert self._postinited @@ -256,9 +252,7 @@ class Player(Generic[TeamType]): def assigninput(self, inputtype: Union[ba.InputType, tuple[ba.InputType, ...]], call: Callable) -> None: - """assigninput(type: Union[ba.InputType, Tuple[ba.InputType, ...]], - call: Callable) -> None - + """ Set the python callable to be run for one or more types of input. """ assert self._postinited @@ -266,8 +260,7 @@ class Player(Generic[TeamType]): return self._sessionplayer.assigninput(type=inputtype, call=call) def resetinput(self) -> None: - """resetinput() -> None - + """ Clears out the player's assigned input actions. """ assert self._postinited diff --git a/dist/ba_data/python/ba/_plugin.py b/dist/ba_data/python/ba/_plugin.py index 7637717..6de548a 100644 --- a/dist/ba_data/python/ba/_plugin.py +++ b/dist/ba_data/python/ba/_plugin.py @@ -16,9 +16,9 @@ if TYPE_CHECKING: class PluginSubsystem: """Subsystem for plugin handling in the app. - Category: App Classes + Category: **App Classes** - Access the single shared instance of this class at 'ba.app.plugins'. + Access the single shared instance of this class at `ba.app.plugins`. """ def __init__(self) -> None: @@ -96,7 +96,7 @@ class PluginSubsystem: class PotentialPlugin: """Represents a ba.Plugin which can potentially be loaded. - Category: App Classes + Category: **App Classes** These generally represent plugins which were detected by the meta-tag scan. However they may also represent plugins which @@ -111,7 +111,7 @@ class PotentialPlugin: class Plugin: """A plugin to alter app behavior in some way. - Category: App Classes + Category: **App Classes** Plugins are discoverable by the meta-tag system and the user can select which ones they want to activate. diff --git a/dist/ba_data/python/ba/_powerup.py b/dist/ba_data/python/ba/_powerup.py index 520d302..246cf7b 100644 --- a/dist/ba_data/python/ba/_powerup.py +++ b/dist/ba_data/python/ba/_powerup.py @@ -16,31 +16,27 @@ if TYPE_CHECKING: class PowerupMessage: """A message telling an object to accept a powerup. - Category: Message Classes + Category: **Message Classes** This message is normally received by touching a ba.PowerupBox. - - Attributes: - - poweruptype - The type of powerup to be granted (a string). - See ba.Powerup.poweruptype for available type values. - - sourcenode - The node the powerup game from, or None otherwise. - If a powerup is accepted, a ba.PowerupAcceptMessage should be sent - back to the sourcenode to inform it of the fact. This will generally - cause the powerup box to make a sound and disappear or whatnot. """ + poweruptype: str + """The type of powerup to be granted (a string). + See ba.Powerup.poweruptype for available type values.""" + sourcenode: Optional[ba.Node] = None + """The node the powerup game from, or None otherwise. + If a powerup is accepted, a ba.PowerupAcceptMessage should be sent + back to the sourcenode to inform it of the fact. This will generally + cause the powerup box to make a sound and disappear or whatnot.""" @dataclass class PowerupAcceptMessage: """A message informing a ba.Powerup that it was accepted. - Category: Message Classes + Category: **Message Classes** This is generally sent in response to a ba.PowerupMessage to inform the box (or whoever granted it) that it can go away. diff --git a/dist/ba_data/python/ba/_profile.py b/dist/ba_data/python/ba/_profile.py index 9f89a7f..6513eb6 100644 --- a/dist/ba_data/python/ba/_profile.py +++ b/dist/ba_data/python/ba/_profile.py @@ -73,7 +73,7 @@ def get_player_profile_colors( color = PLAYER_COLORS[random.randrange(6)] else: # First 6 are bright-ish. - color = PLAYER_COLORS[sum([ord(c) for c in profilename]) % 6] + color = PLAYER_COLORS[sum(ord(c) for c in profilename) % 6] try: assert profilename is not None @@ -86,8 +86,8 @@ def get_player_profile_colors( highlight = PLAYER_COLORS[random.randrange( len(PLAYER_COLORS) - 2)] else: - highlight = PLAYER_COLORS[sum( - [ord(c) + 1 - for c in profilename]) % (len(PLAYER_COLORS) - 2)] + highlight = PLAYER_COLORS[sum(ord(c) + 1 + for c in profilename) % + (len(PLAYER_COLORS) - 2)] return color, highlight diff --git a/dist/ba_data/python/ba/_score.py b/dist/ba_data/python/ba/_score.py index d1cbe52..8b8d009 100644 --- a/dist/ba_data/python/ba/_score.py +++ b/dist/ba_data/python/ba/_score.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: class ScoreType(Enum): """Type of scores. - Category: Enums + Category: **Enums** """ SECONDS = 's' MILLISECONDS = 'ms' @@ -27,30 +27,22 @@ class ScoreType(Enum): class ScoreConfig: """Settings for how a game handles scores. - Category: Gameplay Classes - - Attributes: - - label - A label show to the user for scores; 'Score', 'Time Survived', etc. - - scoretype - How the score value should be displayed. - - lower_is_better - Whether lower scores are preferable. Higher scores are by default. - - none_is_winner - Whether a value of None is considered better than other scores. - By default it is not. - - version - To change high-score lists used by a game without renaming the game, - change this. Defaults to an empty string. - + Category: **Gameplay Classes** """ + label: str = 'Score' + """A label show to the user for scores; 'Score', 'Time Survived', etc.""" + scoretype: ba.ScoreType = ScoreType.POINTS + """How the score value should be displayed.""" + lower_is_better: bool = False + """Whether lower scores are preferable. Higher scores are by default.""" + none_is_winner: bool = False + """Whether a value of None is considered better than other scores. + By default it is not.""" + version: str = '' + """To change high-score lists used by a game without renaming the game, + change this. Defaults to an empty string.""" diff --git a/dist/ba_data/python/ba/_servermode.py b/dist/ba_data/python/ba/_servermode.py index 6df38d7..37fad3c 100644 --- a/dist/ba_data/python/ba/_servermode.py +++ b/dist/ba_data/python/ba/_servermode.py @@ -77,7 +77,7 @@ def _cmd(command_data: bytes) -> None: class ServerController: """Overall controller for the app in server mode. - Category: App Classes + Category: **App Classes** """ def __init__(self, config: ServerConfig) -> None: @@ -227,7 +227,7 @@ class ServerController: def _prepare_to_serve(self) -> None: """Run in a timer to do prep before beginning to serve.""" - signed_in = _ba.get_account_state() == 'signed_in' + signed_in = _ba.get_v1_account_state() == 'signed_in' if not signed_in: # Signing in to the local server account should not take long; @@ -302,7 +302,7 @@ class ServerController: appcfg = app.config sessiontype = self._get_session_type() - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': print('WARNING: launch_server_session() expects to run ' 'with a signed in server account') diff --git a/dist/ba_data/python/ba/_session.py b/dist/ba_data/python/ba/_session.py index 0b59fed..d0ee126 100644 --- a/dist/ba_data/python/ba/_session.py +++ b/dist/ba_data/python/ba/_session.py @@ -17,9 +17,9 @@ if TYPE_CHECKING: class Session: - """Defines a high level series of ba.Activities with a common purpose. + """Defines a high level series of ba.Activity-es with a common purpose. - category: Gameplay Classes + Category: **Gameplay Classes** Examples of sessions are ba.FreeForAllSession, ba.DualTeamSession, and ba.CoopSession. @@ -27,58 +27,48 @@ class Session: A Session is responsible for wrangling and transitioning between various ba.Activity instances such as mini-games and score-screens, and for maintaining state between them (players, teams, score tallies, etc). - - Attributes: - - sessionteams - All the ba.SessionTeams in the Session. Most things should use the - list of ba.Teams in ba.Activity; not this. - - sessionplayers - All ba.SessionPlayers in the Session. Most things should use the - list of ba.Players in ba.Activity; not this. Some players, such as - those who have not yet selected a character, will only be - found on this list. - - min_players - The minimum number of players who must be present for the Session - to proceed past the initial joining screen. - - max_players - The maximum number of players allowed in the Session. - - lobby - The ba.Lobby instance where new ba.Players go to select a - Profile/Team/etc. before being added to games. - Be aware this value may be None if a Session does not allow - any such selection. - - use_teams - Whether this session groups players into an explicit set of - teams. If this is off, a unique team is generated for each - player that joins. - - use_team_colors - Whether players on a team should all adopt the colors of that - team instead of their own profile colors. This only applies if - use_teams is enabled. - - customdata - A shared dictionary for objects to use as storage on this session. - Ensure that keys here are unique to avoid collisions. - """ - use_teams: bool = False - use_team_colors: bool = True - # Note: even though these are instance vars, we annotate them at the - # class level so that docs generation can access their types. + use_teams: bool = False + """Whether this session groups players into an explicit set of + teams. If this is off, a unique team is generated for each + player that joins.""" + + use_team_colors: bool = True + """Whether players on a team should all adopt the colors of that + team instead of their own profile colors. This only applies if + use_teams is enabled.""" + + # Note: even though these are instance vars, we annotate and document them + # at the class level so that looks better and nobody get lost while + # reading large __init__ + lobby: ba.Lobby + """The ba.Lobby instance where new ba.Player-s go to select a + Profile/Team/etc. before being added to games. + Be aware this value may be None if a Session does not allow + any such selection.""" + max_players: int + """The maximum number of players allowed in the Session.""" + min_players: int + """The minimum number of players who must be present for the Session + to proceed past the initial joining screen""" + sessionplayers: list[ba.SessionPlayer] + """All ba.SessionPlayers in the Session. Most things should use the + list of ba.Player-s in ba.Activity; not this. Some players, such as + those who have not yet selected a character, will only be + found on this list.""" + customdata: dict + """A shared dictionary for objects to use as storage on this session. + Ensure that keys here are unique to avoid collisions.""" + sessionteams: list[ba.SessionTeam] + """All the ba.SessionTeams in the Session. Most things should use the + list of ba.Team-s in ba.Activity; not this.""" def __init__(self, depsets: Sequence[ba.DependencySet], diff --git a/dist/ba_data/python/ba/_stats.py b/dist/ba_data/python/ba/_stats.py index 486a39e..282545b 100644 --- a/dist/ba_data/python/ba/_stats.py +++ b/dist/ba_data/python/ba/_stats.py @@ -21,20 +21,17 @@ if TYPE_CHECKING: class PlayerScoredMessage: """Informs something that a ba.Player scored. - Category: Message Classes - - Attributes: - - score - The score value. + Category: **Message Classes** """ + score: int + """The score value.""" class PlayerRecord: """Stats for an individual player in a ba.Stats object. - Category: Gameplay Classes + Category: **Gameplay Classes** This does not necessarily correspond to a ba.Player that is still present (stats may be retained for players that leave @@ -232,7 +229,7 @@ class PlayerRecord: class Stats: """Manages scores and statistics for a ba.Session. - category: Gameplay Classes + Category: **Gameplay Classes** """ def __init__(self) -> None: diff --git a/dist/ba_data/python/ba/_store.py b/dist/ba_data/python/ba/_store.py index 0dc91f9..5c936bd 100644 --- a/dist/ba_data/python/ba/_store.py +++ b/dist/ba_data/python/ba/_store.py @@ -366,11 +366,11 @@ def get_store_layout() -> dict[str, list[dict[str, Any]]]: 'games.ninja_fight', 'games.meteor_shower', 'games.target_practice' ] }] - if _ba.get_account_misc_read_val('xmas', False): + if _ba.get_v1_account_misc_read_val('xmas', False): store_layout['characters'][0]['items'].append('characters.santa') store_layout['characters'][0]['items'].append('characters.wizard') store_layout['characters'][0]['items'].append('characters.cyborg') - if _ba.get_account_misc_read_val('easter', False): + if _ba.get_v1_account_misc_read_val('easter', False): store_layout['characters'].append({ 'title': 'store.holidaySpecialText', 'items': ['characters.bunny'] @@ -401,10 +401,10 @@ def get_clean_price(price_string: str) -> str: def get_available_purchase_count(tab: str = None) -> int: """(internal)""" try: - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': return 0 count = 0 - our_tickets = _ba.get_account_ticket_count() + our_tickets = _ba.get_v1_account_ticket_count() store_data = get_store_layout() if tab is not None: tabs = [(tab, store_data[tab])] @@ -425,7 +425,8 @@ def _calc_count_for_tab(tabval: list[dict[str, Any]], our_tickets: int, count: int) -> int: for section in tabval: for item in section['items']: - ticket_cost = _ba.get_account_misc_read_val('price.' + item, None) + ticket_cost = _ba.get_v1_account_misc_read_val( + 'price.' + item, None) if ticket_cost is not None: if (our_tickets >= ticket_cost and not _ba.get_purchased(item)): @@ -447,7 +448,7 @@ def get_available_sale_time(tab: str) -> Optional[int]: # Calc time for our pro sale (old special case). if tab == 'extras': config = app.config - if app.accounts.have_pro(): + if app.accounts_v1.have_pro(): return None # If we haven't calced/loaded start times yet. @@ -462,7 +463,7 @@ def get_available_sale_time(tab: str) -> Optional[int]: # We start the timer once we get the duration from # the server. - start_duration = _ba.get_account_misc_read_val( + start_duration = _ba.get_v1_account_misc_read_val( 'proSaleDurationMinutes', None) if start_duration is not None: app.pro_sale_start_time = int( @@ -488,7 +489,7 @@ def get_available_sale_time(tab: str) -> Optional[int]: sale_times.append(val) # Now look for sales in this tab. - sales_raw = _ba.get_account_misc_read_val('sales', {}) + sales_raw = _ba.get_v1_account_misc_read_val('sales', {}) store_layout = get_store_layout() for section in store_layout[tab]: for item in section['items']: diff --git a/dist/ba_data/python/ba/_team.py b/dist/ba_data/python/ba/_team.py index 0cdfbe7..71c6b66 100644 --- a/dist/ba_data/python/ba/_team.py +++ b/dist/ba_data/python/ba/_team.py @@ -17,39 +17,32 @@ if TYPE_CHECKING: class SessionTeam: """A team of one or more ba.SessionPlayers. - Category: Gameplay Classes + Category: **Gameplay Classes** Note that a SessionPlayer *always* has a SessionTeam; in some cases, such as free-for-all ba.Sessions, each SessionTeam consists of just one SessionPlayer. - - Attributes: - - name - The team's name. - - id - The unique numeric id of the team. - - color - The team's color. - - players - The list of ba.SessionPlayers on the team. - - customdata - A dict for use by the current ba.Session for - storing data associated with this team. - Unlike customdata, this persists for the duration - of the session. """ # Annotate our attr types at the class level so they're introspectable. + name: Union[ba.Lstr, str] + """The team's name.""" + color: tuple[float, ...] # FIXME: can't we make this fixed len? + """The team's color.""" + players: list[ba.SessionPlayer] + """The list of ba.SessionPlayer-s on the team.""" + customdata: dict + """A dict for use by the current ba.Session for + storing data associated with this team. + Unlike customdata, this persists for the duration + of the session.""" + id: int + """The unique numeric id of the team.""" def __init__(self, team_id: int = 0, @@ -73,13 +66,15 @@ class SessionTeam: self.customdata = {} +# pylint: disable=invalid-name PlayerType = TypeVar('PlayerType', bound='ba.Player') +# pylint: enable=invalid-name class Team(Generic[PlayerType]): """A team in a specific ba.Activity. - Category: Gameplay Classes + Category: **Gameplay Classes** These correspond to ba.SessionTeam objects, but are created per activity so that the activity can use its own custom team subclass. @@ -197,7 +192,7 @@ class Team(Generic[PlayerType]): class EmptyTeam(Team['ba.EmptyPlayer']): """An empty player for use by Activities that don't need to define one. - Category: Gameplay Classes + Category: **Gameplay Classes** ba.Player and ba.Team are 'Generic' types, and so passing those top level classes as type arguments when defining a ba.Activity reduces type safety. diff --git a/dist/ba_data/python/ba/_teamgame.py b/dist/ba_data/python/ba/_teamgame.py index 9307621..4efe5c8 100644 --- a/dist/ba_data/python/ba/_teamgame.py +++ b/dist/ba_data/python/ba/_teamgame.py @@ -17,14 +17,16 @@ if TYPE_CHECKING: from bastd.actor.playerspaz import PlayerSpaz import ba +# pylint: disable=invalid-name PlayerType = TypeVar('PlayerType', bound='ba.Player') TeamType = TypeVar('TeamType', bound='ba.Team') +# pylint: enable=invalid-name class TeamGameActivity(GameActivity[PlayerType, TeamType]): """Base class for teams and free-for-all mode games. - Category: Gameplay Classes + Category: **Gameplay Classes** (Free-for-all is essentially just a special case where every ba.Player has their own ba.Team) @@ -120,7 +122,7 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): unless 'announce_winning_team' is False. (for results without a single most-important winner). """ - # pylint: disable=arguments-differ + # pylint: disable=arguments-renamed from ba._coopsession import CoopSession from ba._multiteamsession import MultiTeamSession from ba._general import Call diff --git a/dist/ba_data/python/ba/_ui.py b/dist/ba_data/python/ba/_ui.py index bf01947..0629801 100644 --- a/dist/ba_data/python/ba/_ui.py +++ b/dist/ba_data/python/ba/_ui.py @@ -18,7 +18,7 @@ if TYPE_CHECKING: class UISubsystem: """Consolidated UI functionality for the app. - Category: App Classes + Category: **App Classes** To use this class, access the single instance of it at 'ba.app.ui'. """ diff --git a/dist/ba_data/python/ba/cloud.py b/dist/ba_data/python/ba/cloud.py new file mode 100644 index 0000000..da0057a --- /dev/null +++ b/dist/ba_data/python/ba/cloud.py @@ -0,0 +1,93 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality related to the cloud.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, overload + +import _ba + +if TYPE_CHECKING: + from typing import Union, Callable, Any + + from efro.message import Message + import bacommon.cloud + +# TODO: Should make it possible to define a protocol in bacommon.cloud and +# autogenerate this. That would give us type safety between this and +# internal protocols. + + +class CloudSubsystem: + """Used for communicating with the cloud.""" + + def is_connected(self) -> bool: + """Return whether a connection to the cloud is present. + + This is a good indicator (though not for certain) that sending + messages will succeed. + """ + return False # Needs to be overridden + + @overload + def send_message( + self, + msg: bacommon.cloud.LoginProxyRequestMessage, + on_response: Callable[ + [Union[bacommon.cloud.LoginProxyRequestResponse, + Exception]], None], + ) -> None: + ... + + @overload + def send_message( + self, + msg: bacommon.cloud.LoginProxyStateQueryMessage, + on_response: Callable[ + [Union[bacommon.cloud.LoginProxyStateQueryResponse, + Exception]], None], + ) -> None: + ... + + @overload + def send_message( + self, + msg: bacommon.cloud.LoginProxyCompleteMessage, + on_response: Callable[[Union[None, Exception]], None], + ) -> None: + ... + + @overload + def send_message( + self, + msg: bacommon.cloud.CredentialsCheckMessage, + on_response: Callable[ + [Union[bacommon.cloud.CredentialsCheckResponse, Exception]], None], + ) -> None: + ... + + @overload + def send_message( + self, + msg: bacommon.cloud.AccountSessionReleaseMessage, + on_response: Callable[[Union[None, Exception]], None], + ) -> None: + ... + + def send_message( + self, + msg: Message, + on_response: Callable[[Any], None], + ) -> None: + """Asynchronously send a message to the cloud from the game thread. + + The provided on_response call will be run in the logic thread + and passed either the response or the error that occurred. + """ + from ba._general import Call + del msg # Unused. + + _ba.pushcall( + Call(on_response, + RuntimeError('Cloud functionality is not available.'))) diff --git a/dist/ba_data/python/ba/internal.py b/dist/ba_data/python/ba/internal.py index 26fae04..95a7bfc 100644 --- a/dist/ba_data/python/ba/internal.py +++ b/dist/ba_data/python/ba/internal.py @@ -7,8 +7,6 @@ or disappear without warning, so should be avoided (or used sparingly and defensively) in mods. """ -# pylint: disable=unused-import - from ba._map import (get_unowned_maps, get_map_class, register_map, preload_map_preview_media, get_map_display_string, get_filtered_map_name) @@ -39,3 +37,24 @@ from ba._store import (get_available_sale_time, get_available_purchase_count, get_store_item, get_clean_price) from ba._tournament import get_tournament_prize_strings from ba._gameutils import get_trophy_string + +__all__ = [ + 'get_unowned_maps', 'get_map_class', 'register_map', + 'preload_map_preview_media', 'get_map_display_string', + 'get_filtered_map_name', 'commit_app_config', 'get_device_value', + 'get_input_map_hash', 'get_input_device_config', 'getclass', 'json_prep', + 'get_type_name', 'JoinActivity', 'ScoreScreenActivity', + 'is_browser_likely_available', 'get_remote_app_name', + 'should_submit_debug_info', 'run_gpu_benchmark', 'run_cpu_benchmark', + 'run_media_reload_benchmark', 'run_stress_test', 'getcampaign', + 'PlayerProfilesChangedMessage', 'DEFAULT_TEAM_COLORS', + 'DEFAULT_TEAM_NAMES', 'do_play_music', 'master_server_get', + 'master_server_post', 'get_ip_address_type', + 'DEFAULT_REQUEST_TIMEOUT_SECONDS', 'get_default_powerup_distribution', + 'get_player_profile_colors', 'get_player_profile_icon', + 'get_player_colors', 'get_next_tip', 'get_default_free_for_all_playlist', + 'get_default_teams_playlist', 'filter_playlist', 'get_available_sale_time', + 'get_available_purchase_count', 'get_store_item_name_translated', + 'get_store_item_display_size', 'get_store_layout', 'get_store_item', + 'get_clean_price', 'get_tournament_prize_strings', 'get_trophy_string' +] diff --git a/dist/ba_data/python/bacommon/bacloud.py b/dist/ba_data/python/bacommon/bacloud.py new file mode 100644 index 0000000..f22f7fe --- /dev/null +++ b/dist/ba_data/python/bacommon/bacloud.py @@ -0,0 +1,71 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality related to the bacloud tool.""" + +from __future__ import annotations +from dataclasses import dataclass +from typing import TYPE_CHECKING, Optional + +from efro.dataclassio import ioprepped + +if TYPE_CHECKING: + pass + + +@ioprepped +@dataclass +class Response: + # noinspection PyUnresolvedReferences + """Response sent from the bacloud server to the client. + + Attributes: + message: If present, client should print this message before any other + response processing (including error handling) occurs. + message_end: end arg for message print() call. + error: If present, client should abort with this error message. + delay_seconds: How long to wait before proceeding with remaining + response (can be useful when waiting for server progress in a loop). + login: If present, a token that should be stored client-side and passed + with subsequent commands. + logout: If True, any existing client-side token should be discarded. + dir_manifest: If present, client should generate a manifest of this dir. + It should be added to end_command args as 'manifest'. + uploads: If present, client should upload the requested files (arg1) + individually to a server command (arg2) with provided args (arg3). + uploads_inline: If present, a list of pathnames that should be base64 + gzipped and uploaded to an 'uploads_inline' dict in end_command args. + This should be limited to relatively small files. + downloads_inline: If present, pathnames mapped to base64 gzipped data to + be written to the client. This should only be used for relatively + small files as they are all included inline as part of the response. + deletes: If present, file paths that should be deleted on the client. + dir_prune_empty: If present, all empty dirs under this one should be + removed. + open_url: If present, url to display to the user. + input_prompt: If present, a line of input is read and placed into + end_command args as 'input'. The first value is the prompt printed + before reading and the second is whether it should be read as a + password (without echoing to the terminal). + end_message: If present, a message that should be printed after all other + response processing is done. + end_message_end: end arg for end_message print() call. + end_command: If present, this command is run with these args at the end + of response processing. + """ + message: Optional[str] = None + message_end: str = '\n' + error: Optional[str] = None + delay_seconds: float = 0.0 + login: Optional[str] = None + logout: bool = False + dir_manifest: Optional[str] = None + uploads: Optional[tuple[list[str], str, dict]] = None + uploads_inline: Optional[list[str]] = None + downloads_inline: Optional[dict[str, str]] = None + deletes: Optional[list[str]] = None + dir_prune_empty: Optional[str] = None + open_url: Optional[str] = None + input_prompt: Optional[tuple[str, bool]] = None + end_message: Optional[str] = None + end_message_end: str = '\n' + end_command: Optional[tuple[str, dict]] = None diff --git a/dist/ba_data/python/bacommon/cloud.py b/dist/ba_data/python/bacommon/cloud.py new file mode 100644 index 0000000..0e7b7ce --- /dev/null +++ b/dist/ba_data/python/bacommon/cloud.py @@ -0,0 +1,103 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality related to cloud functionality.""" + +from __future__ import annotations +from dataclasses import dataclass +from typing import TYPE_CHECKING, Annotated, Optional +from enum import Enum + +from efro.message import Message, Response +from efro.dataclassio import ioprepped, IOAttrs + +if TYPE_CHECKING: + pass + + +@ioprepped +@dataclass +class LoginProxyRequestMessage(Message): + """Request send to the cloud to ask for a login-proxy.""" + + @classmethod + def get_response_types(cls) -> list[type[Response]]: + return [LoginProxyRequestResponse] + + +@ioprepped +@dataclass +class LoginProxyRequestResponse(Response): + """Response to a request for a login proxy.""" + + # URL to direct the user to for login. + url: Annotated[str, IOAttrs('u')] + + # Proxy-Login id for querying results. + proxyid: Annotated[str, IOAttrs('p')] + + # Proxy-Login key for querying results. + proxykey: Annotated[str, IOAttrs('k')] + + +@ioprepped +@dataclass +class LoginProxyStateQueryMessage(Message): + """Soo.. how is that login proxy going?""" + proxyid: Annotated[str, IOAttrs('p')] + proxykey: Annotated[str, IOAttrs('k')] + + @classmethod + def get_response_types(cls) -> list[type[Response]]: + return [LoginProxyStateQueryResponse] + + +@ioprepped +@dataclass +class LoginProxyStateQueryResponse(Response): + """Here's the info on that login-proxy you asked about, boss.""" + + class State(Enum): + """States a login-proxy can be in.""" + WAITING = 'waiting' + SUCCESS = 'success' + FAIL = 'fail' + + state: Annotated[State, IOAttrs('s')] + + # On success, these will be filled out. + credentials: Annotated[Optional[str], IOAttrs('tk')] + + +@ioprepped +@dataclass +class LoginProxyCompleteMessage(Message): + """Just so you know, we're done with this proxy.""" + proxyid: Annotated[str, IOAttrs('p')] + + +@ioprepped +@dataclass +class AccountSessionReleaseMessage(Message): + """We're done using this particular session.""" + token: Annotated[str, IOAttrs('tk')] + + +@ioprepped +@dataclass +class CredentialsCheckMessage(Message): + """Are our current credentials valid?""" + + @classmethod + def get_response_types(cls) -> list[type[Response]]: + return [CredentialsCheckResponse] + + +@ioprepped +@dataclass +class CredentialsCheckResponse(Response): + """Info returned when checking credentials.""" + + verified: Annotated[bool, IOAttrs('v')] + + # Current account tag (good time to check if it has changed). + tag: Annotated[str, IOAttrs('t')] diff --git a/dist/ba_data/python/bacommon/net.py b/dist/ba_data/python/bacommon/net.py index bd4ef1c..5c48443 100644 --- a/dist/ba_data/python/bacommon/net.py +++ b/dist/ba_data/python/bacommon/net.py @@ -17,7 +17,7 @@ if TYPE_CHECKING: @dataclass class ServerNodeEntry: """Information about a specific server.""" - region: Annotated[str, IOAttrs('r')] + zone: Annotated[str, IOAttrs('r')] address: Annotated[str, IOAttrs('a')] port: Annotated[int, IOAttrs('p')] diff --git a/dist/ba_data/python/bastd/activity/coopscore.py b/dist/ba_data/python/bastd/activity/coopscore.py index 9df3bad..f578390 100644 --- a/dist/ba_data/python/bastd/activity/coopscore.py +++ b/dist/ba_data/python/bastd/activity/coopscore.py @@ -52,8 +52,9 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): ba.app.ach.achievements_for_coop_level(self._campaign.name + ':' + settings['level'])) - self._account_type = (_ba.get_account_type() if - _ba.get_account_state() == 'signed_in' else None) + self._account_type = (_ba.get_v1_account_type() + if _ba.get_v1_account_state() == 'signed_in' else + None) self._game_service_icon_color: Optional[Sequence[float]] self._game_service_achievements_texture: Optional[ba.Texture] @@ -631,7 +632,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): if ba.app.server is None: # If we're running in normal non-headless build, show this text # because only host can continue the game. - adisp = _ba.get_account_display_string() + adisp = _ba.get_v1_account_display_string() txt = Text(ba.Lstr(resource='waitingForHostText', subs=[('${HOST}', adisp)]), maxwidth=300, @@ -732,7 +733,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): 'scoreVersion': sver, 'scores': our_high_scores_all }) - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': # We expect this only in kiosk mode; complain otherwise. if not (ba.app.demo_mode or ba.app.arcade_mode): print('got not-signed-in at score-submit; unexpected') @@ -841,6 +842,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): if display_scores[i][1] is None: name_str = '-' else: + # noinspection PyUnresolvedReferences name_str = ', '.join([ p['name'] for p in display_scores[i][1]['players'] ]) @@ -1259,8 +1261,8 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): try: tournament_id = self.session.tournament_id if tournament_id is not None: - if tournament_id in ba.app.accounts.tournament_info: - tourney_info = ba.app.accounts.tournament_info[ + if tournament_id in ba.app.accounts_v1.tournament_info: + tourney_info = ba.app.accounts_v1.tournament_info[ tournament_id] # pylint: disable=unbalanced-tuple-unpacking pr1, pv1, pr2, pv2, pr3, pv3 = ( diff --git a/dist/ba_data/python/bastd/activity/multiteamscore.py b/dist/ba_data/python/bastd/activity/multiteamscore.py index 3701ff8..077141a 100644 --- a/dist/ba_data/python/bastd/activity/multiteamscore.py +++ b/dist/ba_data/python/bastd/activity/multiteamscore.py @@ -94,6 +94,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): assert self.stats valid_players = list(self.stats.get_records().items()) + # noinspection PyUnresolvedReferences def _get_player_score_set_entry( player: ba.SessionPlayer) -> Optional[ba.PlayerRecord]: for p_rec in valid_players: diff --git a/dist/ba_data/python/bastd/actor/bomb.py b/dist/ba_data/python/bastd/actor/bomb.py index 1c86f1f..7ab074b 100644 --- a/dist/ba_data/python/bastd/actor/bomb.py +++ b/dist/ba_data/python/bastd/actor/bomb.py @@ -16,118 +16,118 @@ from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Optional, Callable +# pylint: disable=invalid-name PlayerType = TypeVar('PlayerType', bound='ba.Player') +# pylint: enable=invalid-name class BombFactory: """Wraps up media and other resources used by ba.Bombs. - category: Gameplay Classes + Category: **Gameplay Classes** A single instance of this is shared between all bombs and can be retrieved via bastd.actor.bomb.get_factory(). - - Attributes: - - bomb_model - The ba.Model of a standard or ice bomb. - - sticky_bomb_model - The ba.Model of a sticky-bomb. - - impact_bomb_model - The ba.Model of an impact-bomb. - - land_mine_model - The ba.Model of a land-mine. - - tnt_model - The ba.Model of a tnt box. - - regular_tex - The ba.Texture for regular bombs. - - ice_tex - The ba.Texture for ice bombs. - - sticky_tex - The ba.Texture for sticky bombs. - - impact_tex - The ba.Texture for impact bombs. - - impact_lit_tex - The ba.Texture for impact bombs with lights lit. - - land_mine_tex - The ba.Texture for land-mines. - - land_mine_lit_tex - The ba.Texture for land-mines with the light lit. - - tnt_tex - The ba.Texture for tnt boxes. - - hiss_sound - The ba.Sound for the hiss sound an ice bomb makes. - - debris_fall_sound - The ba.Sound for random falling debris after an explosion. - - wood_debris_fall_sound - A ba.Sound for random wood debris falling after an explosion. - - explode_sounds - A tuple of ba.Sounds for explosions. - - freeze_sound - A ba.Sound of an ice bomb freezing something. - - fuse_sound - A ba.Sound of a burning fuse. - - activate_sound - A ba.Sound for an activating impact bomb. - - warn_sound - A ba.Sound for an impact bomb about to explode due to time-out. - - bomb_material - A ba.Material applied to all bombs. - - normal_sound_material - A ba.Material that generates standard bomb noises on impacts, etc. - - sticky_material - A ba.Material that makes 'splat' sounds and makes collisions softer. - - land_mine_no_explode_material - A ba.Material that keeps land-mines from blowing up. - Applied to land-mines when they are created to allow land-mines to - touch without exploding. - - land_mine_blast_material - A ba.Material applied to activated land-mines that causes them to - explode on impact. - - impact_blast_material - A ba.Material applied to activated impact-bombs that causes them to - explode on impact. - - blast_material - A ba.Material applied to bomb blast geometry which triggers impact - events with what it touches. - - dink_sounds - A tuple of ba.Sounds for when bombs hit the ground. - - sticky_impact_sound - The ba.Sound for a squish made by a sticky bomb hitting something. - - roll_sound - ba.Sound for a rolling bomb. """ + bomb_model: ba.Model + """The ba.Model of a standard or ice bomb.""" + + sticky_bomb_model: ba.Model + """The ba.Model of a sticky-bomb.""" + + impact_bomb_model: ba.Model + """The ba.Model of an impact-bomb.""" + + land_mine_model: ba.Model + """The ba.Model of a land-mine.""" + + tnt_model: ba.Model + """The ba.Model of a tnt box.""" + + regular_tex: ba.Texture + """The ba.Texture for regular bombs.""" + + ice_tex: ba.Texture + """The ba.Texture for ice bombs.""" + + sticky_tex: ba.Texture + """The ba.Texture for sticky bombs.""" + + impact_tex: ba.Texture + """The ba.Texture for impact bombs.""" + + impact_lit_tex: ba.Texture + """The ba.Texture for impact bombs with lights lit.""" + + land_mine_tex: ba.Texture + """The ba.Texture for land-mines.""" + + land_mine_lit_tex: ba.Texture + """The ba.Texture for land-mines with the light lit.""" + + tnt_tex: ba.Texture + """The ba.Texture for tnt boxes.""" + + hiss_sound: ba.Sound + """The ba.Sound for the hiss sound an ice bomb makes.""" + + debris_fall_sound: ba.Sound + """The ba.Sound for random falling debris after an explosion.""" + + wood_debris_fall_sound: ba.Sound + """A ba.Sound for random wood debris falling after an explosion.""" + + explode_sounds: Sequence[ba.Sound] + """A tuple of ba.Sound-s for explosions.""" + + freeze_sound: ba.Sound + """A ba.Sound of an ice bomb freezing something.""" + + fuse_sound: ba.Sound + """A ba.Sound of a burning fuse.""" + + activate_sound: ba.Sound + """A ba.Sound for an activating impact bomb.""" + + warn_sound: ba.Sound + """A ba.Sound for an impact bomb about to explode due to time-out.""" + + bomb_material: ba.Material + """A ba.Material applied to all bombs.""" + + normal_sound_material: ba.Material + """A ba.Material that generates standard bomb noises on impacts, etc.""" + + sticky_material: ba.Material + """A ba.Material that makes 'splat' sounds and makes collisions softer.""" + + land_mine_no_explode_material: ba.Material + """A ba.Material that keeps land-mines from blowing up. + Applied to land-mines when they are created to allow land-mines to + touch without exploding.""" + + land_mine_blast_material: ba.Material + """A ba.Material applied to activated land-mines that causes them to + explode on impact.""" + + impact_blast_material: ba.Material + """A ba.Material applied to activated impact-bombs that causes them to + explode on impact.""" + + blast_material: ba.Material + """A ba.Material applied to bomb blast geometry which triggers impact + events with what it touches.""" + + dink_sounds: Sequence[ba.Sound] + """A tuple of ba.Sound-s for when bombs hit the ground.""" + + sticky_impact_sound: ba.Sound + """The ba.Sound for a squish made by a sticky bomb hitting something.""" + + roll_sound: ba.Sound + """ba.Sound for a rolling bomb.""" + _STORENAME = ba.storagename() @classmethod diff --git a/dist/ba_data/python/bastd/actor/flag.py b/dist/ba_data/python/bastd/actor/flag.py index 417a3d4..6fae9d4 100644 --- a/dist/ba_data/python/bastd/actor/flag.py +++ b/dist/ba_data/python/bastd/actor/flag.py @@ -15,38 +15,36 @@ if TYPE_CHECKING: class FlagFactory: - """Wraps up media and other resources used by ba.Flags. + """Wraps up media and other resources used by `Flag`s. - category: Gameplay Classes + Category: **Gameplay Classes** A single instance of this is shared between all flags - and can be retrieved via bastd.actor.flag.get_factory(). - - Attributes: - - flagmaterial - The ba.Material applied to all ba.Flags. - - impact_sound - The ba.Sound used when a ba.Flag hits the ground. - - skid_sound - The ba.Sound used when a ba.Flag skids along the ground. - - no_hit_material - A ba.Material that prevents contact with most objects; - applied to 'non-touchable' flags. - - flag_texture - The ba.Texture for flags. + and can be retrieved via FlagFactory.get(). """ + flagmaterial: ba.Material + """The ba.Material applied to all `Flag`s.""" + + impact_sound: ba.Sound + """The ba.Sound used when a `Flag` hits the ground.""" + + skid_sound: ba.Sound + """The ba.Sound used when a `Flag` skids along the ground.""" + + no_hit_material: ba.Material + """A ba.Material that prevents contact with most objects; + applied to 'non-touchable' flags.""" + + flag_texture: ba.Texture + """The ba.Texture for flags.""" + _STORENAME = ba.storagename() def __init__(self) -> None: - """Instantiate a FlagFactory. + """Instantiate a `FlagFactory`. - You shouldn't need to do this; call bastd.actor.flag.get_factory() to + You shouldn't need to do this; call FlagFactory.get() to get a shared instance. """ shared = SharedObjects.get() @@ -109,7 +107,7 @@ class FlagFactory: @classmethod def get(cls) -> FlagFactory: - """Get/create a shared FlagFactory instance.""" + """Get/create a shared `FlagFactory` instance.""" activity = ba.getactivity() factory = activity.customdata.get(cls._STORENAME) if factory is None: @@ -121,58 +119,47 @@ class FlagFactory: @dataclass class FlagPickedUpMessage: - """A message saying a ba.Flag has been picked up. + """A message saying a `Flag` has been picked up. - category: Message Classes + Category: **Message Classes** + """ - Attributes: - - flag - The ba.Flag that has been picked up. - - node - The ba.Node doing the picking up. - """ flag: Flag + """The `Flag` that has been picked up.""" + node: ba.Node + """The ba.Node doing the picking up.""" @dataclass class FlagDiedMessage: - """A message saying a ba.Flag has died. + """A message saying a `Flag` has died. - category: Message Classes - - Attributes: - - flag - The ba.Flag that died. + Category: **Message Classes** """ + flag: Flag + """The `Flag` that died.""" @dataclass class FlagDroppedMessage: - """A message saying a ba.Flag has been dropped. + """A message saying a `Flag` has been dropped. - category: Message Classes - - Attributes: - - flag - The ba.Flag that was dropped. - - node - The ba.Node that was holding it. + Category: **Message Classes** """ + flag: Flag + """The `Flag` that was dropped.""" + node: ba.Node + """The ba.Node that was holding it.""" class Flag(ba.Actor): """A flag; used in games such as capture-the-flag or king-of-the-hill. - category: Gameplay Classes + Category: **Gameplay Classes** Can be stationary or carry-able by players. """ @@ -189,7 +176,7 @@ class Flag(ba.Actor): useful for things like king-of-the-hill where players should not be moving the flag around. - 'materials can be a list of extra ba.Materials to apply to the flag. + 'materials can be a list of extra `ba.Material`s to apply to the flag. If 'dropped_timeout' is provided (in seconds), the flag will die after remaining untouched for that long once it has been moved diff --git a/dist/ba_data/python/bastd/actor/playerspaz.py b/dist/ba_data/python/bastd/actor/playerspaz.py index d88a0a7..1f3f1b1 100644 --- a/dist/ba_data/python/bastd/actor/playerspaz.py +++ b/dist/ba_data/python/bastd/actor/playerspaz.py @@ -12,36 +12,36 @@ from spazmod import modifyspaz if TYPE_CHECKING: from typing import Any, Sequence, Optional, Literal +# pylint: disable=invalid-name PlayerType = TypeVar('PlayerType', bound=ba.Player) TeamType = TypeVar('TeamType', bound=ba.Team) +# pylint: enable=invalid-name class PlayerSpazHurtMessage: - """A message saying a ba.PlayerSpaz was hurt. + """A message saying a PlayerSpaz was hurt. - category: Message Classes - - Attributes: - - spaz - The ba.PlayerSpaz that was hurt + Category: **Message Classes** """ + spaz: PlayerSpaz + """The PlayerSpaz that was hurt""" + def __init__(self, spaz: PlayerSpaz): """Instantiate with the given ba.Spaz value.""" self.spaz = spaz class PlayerSpaz(Spaz): - """A ba.Spaz subclass meant to be controlled by a ba.Player. + """A Spaz subclass meant to be controlled by a ba.Player. - category: Gameplay Classes + Category: **Gameplay Classes** When a PlayerSpaz dies, it delivers a ba.PlayerDiedMessage to the current ba.Activity. (unless the death was the result of the player leaving the game, in which case no message is sent) - When a PlayerSpaz is hurt, it delivers a ba.PlayerSpazHurtMessage + When a PlayerSpaz is hurt, it delivers a PlayerSpazHurtMessage to the current ba.Activity. """ diff --git a/dist/ba_data/python/bastd/actor/powerupbox.py b/dist/ba_data/python/bastd/actor/powerupbox.py index bed2de5..cfd51e1 100644 --- a/dist/ba_data/python/bastd/actor/powerupbox.py +++ b/dist/ba_data/python/bastd/actor/powerupbox.py @@ -23,69 +23,67 @@ class _TouchedMessage: class PowerupBoxFactory: """A collection of media and other resources used by ba.Powerups. - category: Gameplay Classes + Category: **Gameplay Classes** A single instance of this is shared between all powerups and can be retrieved via ba.Powerup.get_factory(). - - Attributes: - - model - The ba.Model of the powerup box. - - model_simple - A simpler ba.Model of the powerup box, for use in shadows, etc. - - tex_bomb - Triple-bomb powerup ba.Texture. - - tex_punch - Punch powerup ba.Texture. - - tex_ice_bombs - Ice bomb powerup ba.Texture. - - tex_sticky_bombs - Sticky bomb powerup ba.Texture. - - tex_shield - Shield powerup ba.Texture. - - tex_impact_bombs - Impact-bomb powerup ba.Texture. - - tex_health - Health powerup ba.Texture. - - tex_land_mines - Land-mine powerup ba.Texture. - - tex_curse - Curse powerup ba.Texture. - - health_powerup_sound - ba.Sound played when a health powerup is accepted. - - powerup_sound - ba.Sound played when a powerup is accepted. - - powerdown_sound - ba.Sound that can be used when powerups wear off. - - powerup_material - ba.Material applied to powerup boxes. - - powerup_accept_material - Powerups will send a ba.PowerupMessage to anything they touch - that has this ba.Material applied. """ + model: ba.Model + """The ba.Model of the powerup box.""" + + model_simple: ba.Model + """A simpler ba.Model of the powerup box, for use in shadows, etc.""" + + tex_bomb: ba.Texture + """Triple-bomb powerup ba.Texture.""" + + tex_punch: ba.Texture + """Punch powerup ba.Texture.""" + + tex_ice_bombs: ba.Texture + """Ice bomb powerup ba.Texture.""" + + tex_sticky_bombs: ba.Texture + """Sticky bomb powerup ba.Texture.""" + + tex_shield: ba.Texture + """Shield powerup ba.Texture.""" + + tex_impact_bombs: ba.Texture + """Impact-bomb powerup ba.Texture.""" + + tex_health: ba.Texture + """Health powerup ba.Texture.""" + + tex_land_mines: ba.Texture + """Land-mine powerup ba.Texture.""" + + tex_curse: ba.Texture + """Curse powerup ba.Texture.""" + + health_powerup_sound: ba.Sound + """ba.Sound played when a health powerup is accepted.""" + + powerup_sound: ba.Sound + """ba.Sound played when a powerup is accepted.""" + + powerdown_sound: ba.Sound + """ba.Sound that can be used when powerups wear off.""" + + powerup_material: ba.Material + """ba.Material applied to powerup boxes.""" + + powerup_accept_material: ba.Material + """Powerups will send a ba.PowerupMessage to anything they touch + that has this ba.Material applied.""" + _STORENAME = ba.storagename() def __init__(self) -> None: """Instantiate a PowerupBoxFactory. - You shouldn't need to do this; call ba.Powerup.get_factory() + You shouldn't need to do this; call Powerup.get_factory() to get a shared instance. """ from ba.internal import get_default_powerup_distribution @@ -191,18 +189,16 @@ class PowerupBox(ba.Actor): This will deliver a ba.PowerupMessage to anything that touches it which has the ba.PowerupBoxFactory.powerup_accept_material applied. - - Attributes: - - poweruptype - The string powerup type. This can be 'triple_bombs', 'punch', - 'ice_bombs', 'impact_bombs', 'land_mines', 'sticky_bombs', 'shield', - 'health', or 'curse'. - - node - The 'prop' ba.Node representing this box. """ + poweruptype: str + """The string powerup type. This can be 'triple_bombs', 'punch', + 'ice_bombs', 'impact_bombs', 'land_mines', 'sticky_bombs', 'shield', + 'health', or 'curse'.""" + + node: ba.Node + """The 'prop' ba.Node representing this box.""" + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0), poweruptype: str = 'triple_bombs', diff --git a/dist/ba_data/python/bastd/actor/spawner.py b/dist/ba_data/python/bastd/actor/spawner.py index b1ed9c1..16693bd 100644 --- a/dist/ba_data/python/bastd/actor/spawner.py +++ b/dist/ba_data/python/bastd/actor/spawner.py @@ -16,29 +16,27 @@ if TYPE_CHECKING: class Spawner: """Utility for delayed spawning of objects. - category: Gameplay Classes + Category: **Gameplay Classes** - Creates a light flash and sends a ba.Spawner.SpawnMessage + Creates a light flash and sends a Spawner.SpawnMessage to the current activity after a delay. """ class SpawnMessage: - """Spawn message sent by a ba.Spawner after its delay has passed. + """Spawn message sent by a Spawner after its delay has passed. - category: Message Classes - - Attributes: - - spawner - The ba.Spawner we came from. - - data - The data object passed by the user. - - pt - The spawn position. + Category: **Message Classes** """ + spawner: Spawner + """The ba.Spawner we came from.""" + + data: Any + """The data object passed by the user.""" + + pt: Sequence[float] + """The spawn position.""" + def __init__( self, spawner: Spawner, diff --git a/dist/ba_data/python/bastd/actor/spaz.py b/dist/ba_data/python/bastd/actor/spaz.py index b1d42f3..46154a8 100644 --- a/dist/ba_data/python/bastd/actor/spaz.py +++ b/dist/ba_data/python/bastd/actor/spaz.py @@ -16,7 +16,6 @@ from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Optional, Union, Callable - from bastd.actor.spazfactory import SpazFactory POWERUP_WEAR_OFF_TIME = 20000 BASE_PUNCH_COOLDOWN = 400 @@ -42,23 +41,21 @@ class Spaz(ba.Actor): """ Base class for various Spazzes. - category: Gameplay Classes + Category: **Gameplay Classes** A Spaz is the standard little humanoid character in the game. It can be controlled by a player or by AI, and can have various different appearances. The name 'Spaz' is not to be confused with the 'Spaz' character in the game, which is just one of the skins available for instances of this class. - - Attributes: - - node - The 'spaz' ba.Node. """ # pylint: disable=too-many-public-methods # pylint: disable=too-many-locals + node: ba.Node + """The 'spaz' ba.Node.""" + points_mult = 1 curse_time: Optional[float] = 5.0 default_bomb_count = 1 diff --git a/dist/ba_data/python/bastd/actor/spazbot.py b/dist/ba_data/python/bastd/actor/spazbot.py index 9d4d92e..e9bb4bd 100644 --- a/dist/ba_data/python/bastd/actor/spazbot.py +++ b/dist/ba_data/python/bastd/actor/spazbot.py @@ -27,17 +27,15 @@ PRO_BOT_HIGHLIGHT = (0.6, 0.1, 0.05) class SpazBotPunchedMessage: """A message saying a ba.SpazBot got punched. - category: Message Classes - - Attributes: - - spazbot - The ba.SpazBot that got punched. - - damage - How much damage was done to the ba.SpazBot. + Category: **Message Classes** """ + spazbot: SpazBot + """The ba.SpazBot that got punched.""" + + damage: int + """How much damage was done to the SpazBot.""" + def __init__(self, spazbot: SpazBot, damage: int): """Instantiate a message with the given values.""" self.spazbot = spazbot @@ -47,20 +45,18 @@ class SpazBotPunchedMessage: class SpazBotDiedMessage: """A message saying a ba.SpazBot has died. - category: Message Classes - - Attributes: - - spazbot - The ba.SpazBot that was killed. - - killerplayer - The ba.Player that killed it (or None). - - how - The particular type of death. + Category: **Message Classes** """ + spazbot: SpazBot + """The SpazBot that was killed.""" + + killerplayer: Optional[ba.Player] + """The ba.Player that killed it (or None).""" + + how: ba.DeathType + """The particular type of death.""" + def __init__(self, spazbot: SpazBot, killerplayer: Optional[ba.Player], how: ba.DeathType): """Instantiate with given values.""" @@ -72,7 +68,7 @@ class SpazBotDiedMessage: class SpazBot(Spaz): """A really dumb AI version of ba.Spaz. - category: Bot Classes + Category: **Bot Classes** Add these to a ba.BotSet to use them. diff --git a/dist/ba_data/python/bastd/actor/spazfactory.py b/dist/ba_data/python/bastd/actor/spazfactory.py index ed06d72..0840d8f 100644 --- a/dist/ba_data/python/bastd/actor/spazfactory.py +++ b/dist/ba_data/python/bastd/actor/spazfactory.py @@ -11,72 +11,70 @@ from bastd.gameutils import SharedObjects import _ba if TYPE_CHECKING: - from typing import Any + from typing import Any, Sequence class SpazFactory: """Wraps up media and other resources used by ba.Spaz instances. - Category: Gameplay Classes + Category: **Gameplay Classes** Generally one of these is created per ba.Activity and shared - between all spaz instances. Use ba.Spaz.get_factory() to return + between all spaz instances. Use ba.Spaz.get_factory() to return the shared factory for the current activity. - - Attributes: - - impact_sounds_medium - A tuple of ba.Sounds for when a ba.Spaz hits something kinda hard. - - impact_sounds_hard - A tuple of ba.Sounds for when a ba.Spaz hits something really hard. - - impact_sounds_harder - A tuple of ba.Sounds for when a ba.Spaz hits something really - really hard. - - single_player_death_sound - The sound that plays for an 'important' spaz death such as in - co-op games. - - punch_sound - A standard punch ba.Sound. - - punch_sound_strong - A tuple of stronger sounding punch ba.Sounds. - - punch_sound_stronger - A really really strong sounding punch ba.Sound. - - swish_sound - A punch swish ba.Sound. - - block_sound - A ba.Sound for when an attack is blocked by invincibility. - - shatter_sound - A ba.Sound for when a frozen ba.Spaz shatters. - - splatter_sound - A ba.Sound for when a ba.Spaz blows up via curse. - - spaz_material - A ba.Material applied to all of parts of a ba.Spaz. - - roller_material - A ba.Material applied to the invisible roller ball body that - a ba.Spaz uses for locomotion. - - punch_material - A ba.Material applied to the 'fist' of a ba.Spaz. - - pickup_material - A ba.Material applied to the 'grabber' body of a ba.Spaz. - - curse_material - A ba.Material applied to a cursed ba.Spaz that triggers an explosion. """ + impact_sounds_medium: Sequence[ba.Sound] + """A tuple of ba.Sound-s for when a ba.Spaz hits something kinda hard.""" + + impact_sounds_hard: Sequence[ba.Sound] + """A tuple of ba.Sound-s for when a ba.Spaz hits something really hard.""" + + impact_sounds_harder: Sequence[ba.Sound] + """A tuple of ba.Sound-s for when a ba.Spaz hits something really + really hard.""" + + single_player_death_sound: ba.Sound + """The sound that plays for an 'important' spaz death such as in + co-op games.""" + + punch_sound: ba.Sound + """A standard punch ba.Sound.""" + + punch_sound_strong: Sequence[ba.Sound] + """A tuple of stronger sounding punch ba.Sounds.""" + + punch_sound_stronger: ba.Sound + """A really really strong sounding punch ba.Sound.""" + + swish_sound: ba.Sound + """A punch swish ba.Sound.""" + + block_sound: ba.Sound + """A ba.Sound for when an attack is blocked by invincibility.""" + + shatter_sound: ba.Sound + """A ba.Sound for when a frozen ba.Spaz shatters.""" + + splatter_sound: ba.Sound + """A ba.Sound for when a ba.Spaz blows up via curse.""" + + spaz_material: ba.Material + """A ba.Material applied to all of parts of a ba.Spaz.""" + + roller_material: ba.Material + """A ba.Material applied to the invisible roller ball body that + a ba.Spaz uses for locomotion.""" + + punch_material: ba.Material + """A ba.Material applied to the 'fist' of a ba.Spaz.""" + + pickup_material: ba.Material + """A ba.Material applied to the 'grabber' body of a ba.Spaz.""" + + curse_material: ba.Material + """A ba.Material applied to a cursed ba.Spaz that triggers an explosion.""" + _STORENAME = ba.storagename() def _preload(self, character: str) -> None: @@ -210,14 +208,14 @@ class SpazFactory: # Lets load some basic rules. # (allows them to be tweaked from the master server) - self.shield_decay_rate = _ba.get_account_misc_read_val('rsdr', 10.0) - self.punch_cooldown = _ba.get_account_misc_read_val('rpc', 400) - self.punch_cooldown_gloves = (_ba.get_account_misc_read_val( + self.shield_decay_rate = _ba.get_v1_account_misc_read_val('rsdr', 10.0) + self.punch_cooldown = _ba.get_v1_account_misc_read_val('rpc', 400) + self.punch_cooldown_gloves = (_ba.get_v1_account_misc_read_val( 'rpcg', 300)) - self.punch_power_scale = _ba.get_account_misc_read_val('rpp', 1.2) - self.punch_power_scale_gloves = (_ba.get_account_misc_read_val( + self.punch_power_scale = _ba.get_v1_account_misc_read_val('rpp', 1.2) + self.punch_power_scale_gloves = (_ba.get_v1_account_misc_read_val( 'rppg', 1.4)) - self.max_shield_spillover_damage = (_ba.get_account_misc_read_val( + self.max_shield_spillover_damage = (_ba.get_v1_account_misc_read_val( 'rsms', 500)) def get_style(self, character: str) -> str: diff --git a/dist/ba_data/python/bastd/game/assault.py b/dist/ba_data/python/bastd/game/assault.py index 6389b4b..0a56a07 100644 --- a/dist/ba_data/python/bastd/game/assault.py +++ b/dist/ba_data/python/bastd/game/assault.py @@ -175,12 +175,16 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): def _handle_base_collide(self, team: Team) -> None: try: - player = ba.getcollision().opposingnode.getdelegate( - PlayerSpaz, True).getplayer(Player, True) + spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True) except ba.NotFoundError: return - if not player.is_alive(): + if not spaz.is_alive(): + return + + try: + player = spaz.getplayer(Player, True) + except ba.NotFoundError: return # If its another team's player, they scored. diff --git a/dist/ba_data/python/bastd/game/capturetheflag.py b/dist/ba_data/python/bastd/game/capturetheflag.py index 0e91062..881d918 100644 --- a/dist/ba_data/python/bastd/game/capturetheflag.py +++ b/dist/ba_data/python/bastd/game/capturetheflag.py @@ -274,6 +274,11 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): # If the enemy flag is already here, score! if team.enemy_flag_at_base: + # And show team name which scored (but actually we could + # show here player who returned enemy flag). + self.show_zoom_message(ba.Lstr(resource='nameScoresText', + subs=[('${NAME}', team.name)]), + color=team.color) self._score(team) else: team.enemy_flag_at_base = True @@ -435,11 +440,14 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): """ player: Optional[Player] try: - player = ba.getcollision().sourcenode.getdelegate( - PlayerSpaz, True).getplayer(Player, True) + spaz = ba.getcollision().sourcenode.getdelegate(PlayerSpaz, True) except ba.NotFoundError: - # This can happen if the player leaves but his corpse touches/etc. - player = None + return + + if not spaz.is_alive(): + return + + player = spaz.getplayer(Player, True) if player: player.touching_own_flag += (1 if connecting else -1) diff --git a/dist/ba_data/python/bastd/game/kingofthehill.py b/dist/ba_data/python/bastd/game/kingofthehill.py index 9194f5a..1ea3e9a 100644 --- a/dist/ba_data/python/bastd/game/kingofthehill.py +++ b/dist/ba_data/python/bastd/game/kingofthehill.py @@ -239,11 +239,15 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): def _handle_player_flag_region_collide(self, colliding: bool) -> None: try: - player = ba.getcollision().opposingnode.getdelegate( - PlayerSpaz, True).getplayer(Player, True) + spaz = ba.getcollision().sourcenode.getdelegate(PlayerSpaz, True) except ba.NotFoundError: return + if not spaz.is_alive(): + return + + player = spaz.getplayer(Player, True) + # Different parts of us can collide so a single value isn't enough # also don't count it if we're dead (flying heads shouldn't be able to # win the game :-) diff --git a/dist/ba_data/python/bastd/game/race.py b/dist/ba_data/python/bastd/game/race.py index c8e6f3d..1aa3254 100644 --- a/dist/ba_data/python/bastd/game/race.py +++ b/dist/ba_data/python/bastd/game/race.py @@ -224,9 +224,15 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): collision = ba.getcollision() try: region = collision.sourcenode.getdelegate(RaceRegion, True) - player = collision.opposingnode.getdelegate(PlayerSpaz, - True).getplayer( - Player, True) + spaz = collision.opposingnode.getdelegate(PlayerSpaz, True) + except ba.NotFoundError: + return + + if not spaz.is_alive(): + return + + try: + player = spaz.getplayer(Player, True) except ba.NotFoundError: return @@ -263,9 +269,9 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): # Otherwise its the max. if isinstance(self.session, ba.DualTeamSession ) and self._entire_team_must_finish: - team.lap = min([p.lap for p in team.players]) + team.lap = min(p.lap for p in team.players) else: - team.lap = max([p.lap for p in team.players]) + team.lap = max(p.lap for p in team.players) # A player is finishing. if player.lap == self._laps: diff --git a/dist/ba_data/python/bastd/game/runaround.py b/dist/ba_data/python/bastd/game/runaround.py index e22d458..29779b2 100644 --- a/dist/ba_data/python/bastd/game/runaround.py +++ b/dist/ba_data/python/bastd/game/runaround.py @@ -51,6 +51,7 @@ class Point(Enum): @dataclass class Spawn: """Defines a bot spawn event.""" + # noinspection PyUnresolvedReferences type: type[SpazBot] path: int = 0 point: Optional[Point] = None diff --git a/dist/ba_data/python/bastd/mainmenu.py b/dist/ba_data/python/bastd/mainmenu.py index 86818e2..b32a937 100644 --- a/dist/ba_data/python/bastd/mainmenu.py +++ b/dist/ba_data/python/bastd/mainmenu.py @@ -67,7 +67,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): # host is navigating menus while they're just staring at an # empty-ish screen. tval = ba.Lstr(resource='hostIsNavigatingMenusText', - subs=[('${HOST}', _ba.get_account_display_string())]) + subs=[('${HOST}', _ba.get_v1_account_display_string())]) self._host_is_navigating_text = ba.NodeActor( ba.newnode('text', attrs={ @@ -274,7 +274,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): # We now want to wait until we're signed in before fetching news. def _try_fetching_news(self) -> None: - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': self._fetch_news() self._fetch_timer = None @@ -282,7 +282,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): ba.app.main_menu_last_news_fetch_time = time.time() # UPDATE - We now just pull news from MRVs. - news = _ba.get_account_misc_read_val('n', None) + news = _ba.get_v1_account_misc_read_val('n', None) if news is not None: self._got_news(news) @@ -757,7 +757,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): }) def _get_custom_logo_tex_name(self) -> Optional[str]: - if _ba.get_account_misc_read_val('easter', False): + if _ba.get_v1_account_misc_read_val('easter', False): return 'logoEaster' return None diff --git a/dist/ba_data/python/bastd/ui/account/__init__.py b/dist/ba_data/python/bastd/ui/account/__init__.py index 7bf7c13..9b56244 100644 --- a/dist/ba_data/python/bastd/ui/account/__init__.py +++ b/dist/ba_data/python/bastd/ui/account/__init__.py @@ -15,7 +15,7 @@ def show_sign_in_prompt(account_type: str = None) -> None: if account_type == 'Google Play': ConfirmWindow( ba.Lstr(resource='notSignedInGooglePlayErrorText'), - lambda: _ba.sign_in('Google Play'), + lambda: _ba.sign_in_v1('Google Play'), ok_text=ba.Lstr(resource='accountSettingsWindow.signInText'), width=460, height=130) diff --git a/dist/ba_data/python/bastd/ui/account/link.py b/dist/ba_data/python/bastd/ui/account/link.py index df01fc9..1e0b2b7 100644 --- a/dist/ba_data/python/bastd/ui/account/link.py +++ b/dist/ba_data/python/bastd/ui/account/link.py @@ -50,7 +50,7 @@ class AccountLinkWindow(ba.Window): autoselect=True, icon=ba.gettexture('crossOut'), iconscale=1.2) - maxlinks = _ba.get_account_misc_read_val('maxLinkAccounts', 5) + maxlinks = _ba.get_v1_account_misc_read_val('maxLinkAccounts', 5) ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height * 0.56), @@ -84,7 +84,7 @@ class AccountLinkWindow(ba.Window): def _generate_press(self) -> None: from bastd.ui import account - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': account.show_sign_in_prompt() return ba.screenmessage( diff --git a/dist/ba_data/python/bastd/ui/account/settings.py b/dist/ba_data/python/bastd/ui/account/settings.py index 1a7d264..901e0c8 100644 --- a/dist/ba_data/python/bastd/ui/account/settings.py +++ b/dist/ba_data/python/bastd/ui/account/settings.py @@ -45,10 +45,11 @@ class AccountSettingsWindow(ba.Window): self._r = 'accountSettingsWindow' self._modal = modal self._needs_refresh = False - self._signed_in = (_ba.get_account_state() == 'signed_in') - self._account_state_num = _ba.get_account_state_num() - self._show_linked = (self._signed_in and _ba.get_account_misc_read_val( - 'allowAccountLinking2', False)) + self._signed_in = (_ba.get_v1_account_state() == 'signed_in') + self._account_state_num = _ba.get_v1_account_state_num() + self._show_linked = (self._signed_in + and _ba.get_v1_account_misc_read_val( + 'allowAccountLinking2', False)) self._check_sign_in_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, @@ -57,7 +58,7 @@ class AccountSettingsWindow(ba.Window): # Currently we can only reset achievements on game-center. account_type: Optional[str] if self._signed_in: - account_type = _ba.get_account_type() + account_type = _ba.get_v1_account_type() else: account_type = None self._can_reset_achievements = (account_type == 'Game Center') @@ -91,7 +92,7 @@ class AccountSettingsWindow(ba.Window): self._show_sign_in_buttons.append('Local') # Ditto with shiny new V2 ones. - if bool(False): + if bool(True): self._show_sign_in_buttons.append('V2') top_extra = 15 if uiscale is ba.UIScale.SMALL else 0 @@ -158,10 +159,10 @@ class AccountSettingsWindow(ba.Window): # Hmm should update this to use get_account_state_num. # Theoretically if we switch from one signed-in account to another # in the background this would break. - account_state_num = _ba.get_account_state_num() - account_state = _ba.get_account_state() + account_state_num = _ba.get_v1_account_state_num() + account_state = _ba.get_v1_account_state() - show_linked = (self._signed_in and _ba.get_account_misc_read_val( + show_linked = (self._signed_in and _ba.get_v1_account_misc_read_val( 'allowAccountLinking2', False)) if (account_state_num != self._account_state_num @@ -190,8 +191,8 @@ class AccountSettingsWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui import confirm - account_state = _ba.get_account_state() - account_type = (_ba.get_account_type() + account_state = _ba.get_v1_account_state() + account_type = (_ba.get_v1_account_type() if account_state == 'signed_in' else 'unknown') is_google = account_type == 'Google Play' @@ -225,7 +226,7 @@ class AccountSettingsWindow(ba.Window): game_service_button_space = 60.0 show_linked_accounts_text = (self._signed_in - and _ba.get_account_misc_read_val( + and _ba.get_v1_account_misc_read_val( 'allowAccountLinking2', False)) linked_accounts_text_space = 60.0 @@ -254,17 +255,22 @@ class AccountSettingsWindow(ba.Window): player_profiles_button_space = 100.0 show_link_accounts_button = (self._signed_in - and _ba.get_account_misc_read_val( + and _ba.get_v1_account_misc_read_val( 'allowAccountLinking2', False)) link_accounts_button_space = 70.0 show_unlink_accounts_button = show_link_accounts_button unlink_accounts_button_space = 90.0 - show_sign_out_button = (self._signed_in - and account_type in ['Local', 'Google Play']) + show_sign_out_button = (self._signed_in and account_type + in ['Local', 'Google Play', 'V2']) sign_out_button_space = 70.0 + show_cancel_v2_sign_in_button = ( + account_state == 'signing_in' + and ba.app.accounts_v2.have_primary_credentials()) + cancel_v2_sign_in_button_space = 70.0 + if self._subcontainer is not None: self._subcontainer.delete() self._sub_height = 60.0 @@ -308,6 +314,8 @@ class AccountSettingsWindow(ba.Window): self._sub_height += unlink_accounts_button_space if show_sign_out_button: self._sub_height += sign_out_button_space + if show_cancel_v2_sign_in_button: + self._sub_height += cancel_v2_sign_in_button_space self._subcontainer = ba.containerwidget(parent=self._scrollwidget, size=(self._sub_width, self._sub_height), @@ -327,7 +335,7 @@ class AccountSettingsWindow(ba.Window): size=(0, 0), text=ba.Lstr( resource='accountSettingsWindow.deviceSpecificAccountText', - subs=[('${NAME}', _ba.get_account_display_string())]), + subs=[('${NAME}', _ba.get_v1_account_display_string())]), scale=0.7, color=(0.5, 0.5, 0.6), maxwidth=self._sub_width * 0.9, @@ -581,7 +589,7 @@ class AccountSettingsWindow(ba.Window): if show_game_service_button: button_width = 300 v -= game_service_button_space * 0.85 - account_type = _ba.get_account_type() + account_type = _ba.get_v1_account_type() if account_type == 'Game Center': account_type_name = ba.Lstr(resource='gameCenterText') elif account_type == 'Game Circle': @@ -849,6 +857,24 @@ class AccountSettingsWindow(ba.Window): right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=15) + if show_cancel_v2_sign_in_button: + v -= cancel_v2_sign_in_button_space + self._cancel_v2_sign_in_button = btn = ba.buttonwidget( + parent=self._subcontainer, + position=((self._sub_width - button_width) * 0.5, v), + size=(button_width, 60), + label=ba.Lstr(resource='cancelText'), + color=(0.55, 0.5, 0.6), + textcolor=(0.75, 0.7, 0.8), + autoselect=True, + on_activate_call=self._cancel_v2_sign_in_press) + if first_selectable is None: + first_selectable = btn + if ba.app.ui.use_toolbars: + ba.widget(edit=btn, + right_widget=_ba.get_special_widget('party_button')) + ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=15) + # Whatever the topmost selectable thing is, we want it to scroll all # the way up when we select it. if first_selectable is not None: @@ -863,8 +889,8 @@ class AccountSettingsWindow(ba.Window): def _on_achievements_press(self) -> None: # pylint: disable=cyclic-import from bastd.ui import achievements - account_state = _ba.get_account_state() - account_type = (_ba.get_account_type() + account_state = _ba.get_v1_account_state() + account_type = (_ba.get_v1_account_type() if account_state == 'signed_in' else 'unknown') # for google play we use the built-in UI; otherwise pop up our own if account_type == 'Google Play': @@ -889,7 +915,7 @@ class AccountSettingsWindow(ba.Window): # let's not proceed.. if _ba.get_public_login_id() is None: return False - accounts = _ba.get_account_misc_read_val_2('linkedAccounts', []) + accounts = _ba.get_v1_account_misc_read_val_2('linkedAccounts', []) return len(accounts) > 1 def _update_unlink_accounts_button(self) -> None: @@ -911,8 +937,8 @@ class AccountSettingsWindow(ba.Window): num = int(time.time()) % 4 accounts_str = num * '.' + (4 - num) * ' ' else: - accounts = _ba.get_account_misc_read_val_2('linkedAccounts', []) - # our_account = _bs.get_account_display_string() + accounts = _ba.get_v1_account_misc_read_val_2('linkedAccounts', []) + # our_account = _bs.get_v1_account_display_string() # accounts = [a for a in accounts if a != our_account] # accounts_str = u', '.join(accounts) if accounts else # ba.Lstr(translate=('settingNames', 'None')) @@ -951,7 +977,7 @@ class AccountSettingsWindow(ba.Window): if self._tickets_text is None: return try: - tc_str = str(_ba.get_account_ticket_count()) + tc_str = str(_ba.get_v1_account_ticket_count()) except Exception: ba.print_exception() tc_str = '-' @@ -963,7 +989,7 @@ class AccountSettingsWindow(ba.Window): if self._account_name_text is None: return try: - name_str = _ba.get_account_display_string() + name_str = _ba.get_v1_account_display_string() except Exception: ba.print_exception() name_str = '??' @@ -1005,22 +1031,37 @@ class AccountSettingsWindow(ba.Window): pbrowser.ProfileBrowserWindow( origin_widget=self._player_profiles_button) + def _cancel_v2_sign_in_press(self) -> None: + # Just say we don't wanna be signed in anymore. + ba.app.accounts_v2.set_primary_credentials(None) + + # Speed UI updates along. + ba.timer(0.1, ba.WeakCall(self._update), timetype=ba.TimeType.REAL) + def _sign_out_press(self) -> None: - _ba.sign_out() + + if ba.app.accounts_v2.have_primary_credentials(): + ba.app.accounts_v2.set_primary_credentials(None) + else: + _ba.sign_out_v1() + cfg = ba.app.config - # Take note that its our *explicit* intention to not be signed in at - # this point. + # Also take note that its our *explicit* intention to not be + # signed in at this point (affects v1 accounts). cfg['Auto Account State'] = 'signed_out' cfg.commit() ba.buttonwidget(edit=self._sign_out_button, label=ba.Lstr(resource=self._r + '.signingOutText')) + # Speed UI updates along. + ba.timer(0.1, ba.WeakCall(self._update), timetype=ba.TimeType.REAL) + def _sign_in_press(self, account_type: str, show_test_warning: bool = True) -> None: del show_test_warning # unused - _ba.sign_in(account_type) + _ba.sign_in_v1(account_type) # Make note of the type account we're *wanting* to be signed in with. cfg = ba.app.config diff --git a/dist/ba_data/python/bastd/ui/account/unlink.py b/dist/ba_data/python/bastd/ui/account/unlink.py index 8ef0451..83e00dd 100644 --- a/dist/ba_data/python/bastd/ui/account/unlink.py +++ b/dist/ba_data/python/bastd/ui/account/unlink.py @@ -81,7 +81,7 @@ class AccountUnlinkWindow(ba.Window): if our_login_id is None: entries = [] else: - account_infos = _ba.get_account_misc_read_val_2( + account_infos = _ba.get_v1_account_misc_read_val_2( 'linkedAccounts2', []) entries = [{ 'name': ai['d'], diff --git a/dist/ba_data/python/bastd/ui/account/v2.py b/dist/ba_data/python/bastd/ui/account/v2.py index 739edd4..e807050 100644 --- a/dist/ba_data/python/bastd/ui/account/v2.py +++ b/dist/ba_data/python/bastd/ui/account/v2.py @@ -4,36 +4,90 @@ from __future__ import annotations +import logging from typing import TYPE_CHECKING import ba import _ba +from efro.error import CommunicationError +import bacommon.cloud + if TYPE_CHECKING: - from typing import Any, Optional + from typing import Union, Optional + +STATUS_CHECK_INTERVAL_SECONDS = 2.0 class V2SignInWindow(ba.Window): """A window allowing signing in to a v2 account.""" def __init__(self, origin_widget: ba.Widget): - from ba.internal import is_browser_likely_available - logincode = '1412345' - address = ( - f'{_ba.get_master_server_address(version=2)}?login={logincode}') self._width = 600 - self._height = 500 + self._height = 550 + self._proxyid: Optional[str] = None + self._proxykey: Optional[str] = None + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_scale', scale_origin_stack_offset=origin_widget.get_screen_space_center(), scale=(1.25 if uiscale is ba.UIScale.SMALL else - 1.0 if uiscale is ba.UIScale.MEDIUM else 0.85))) + 1.05 if uiscale is ba.UIScale.MEDIUM else 0.9))) + + self._loading_text = ba.textwidget( + parent=self._root_widget, + position=(self._width * 0.5, self._height * 0.5), + h_align='center', + v_align='center', + size=(0, 0), + maxwidth=0.9 * self._width, + text=ba.Lstr(value='${A}...', + subs=[('${A}', ba.Lstr(resource='loadingText'))]), + ) + + self._cancel_button = ba.buttonwidget( + parent=self._root_widget, + position=(30, self._height - 65), + size=(130, 50), + scale=0.8, + label=ba.Lstr(resource='cancelText'), + on_activate_call=self._done, + autoselect=True, + textcolor=(0.75, 0.7, 0.8), + ) + ba.containerwidget(edit=self._root_widget, + cancel_button=self._cancel_button) + + self._update_timer: Optional[ba.Timer] = None + + # Ask the cloud for a proxy login id. + ba.app.cloud.send_message(bacommon.cloud.LoginProxyRequestMessage(), + on_response=ba.WeakCall( + self._on_proxy_request_response)) + + def _on_proxy_request_response( + self, response: Union[bacommon.cloud.LoginProxyRequestResponse, + Exception] + ) -> None: + from ba.internal import is_browser_likely_available + + # Something went wrong. Show an error message and that's it. + if isinstance(response, Exception): + ba.textwidget( + edit=self._loading_text, + text=ba.Lstr(resource='internal.unavailableNoConnectionText'), + color=(1, 0, 0)) + return + + # Show link(s) the user can use to log in. + address = _ba.get_master_server_address(version=2) + response.url + address_pretty = address.removeprefix('https://') ba.textwidget( parent=self._root_widget, - position=(self._width * 0.5, self._height - 85), + position=(self._width * 0.5, self._height - 95), size=(0, 0), text=ba.Lstr( resource='accountSettingsWindow.v2LinkInstructionsText'), @@ -45,19 +99,19 @@ class V2SignInWindow(ba.Window): if is_browser_likely_available(): ba.buttonwidget(parent=self._root_widget, position=((self._width * 0.5 - button_width * 0.5), - self._height - 175), + self._height - 185), autoselect=True, size=(button_width, 60), - label=ba.Lstr(value=address), + label=ba.Lstr(value=address_pretty), color=(0.55, 0.5, 0.6), textcolor=(0.75, 0.7, 0.8), on_activate_call=lambda: ba.open_url(address)) qroffs = 0.0 else: ba.textwidget(parent=self._root_widget, - position=(self._width * 0.5, self._height - 135), + position=(self._width * 0.5, self._height - 145), size=(0, 0), - text=ba.Lstr(value=address), + text=ba.Lstr(value=address_pretty), flatness=1.0, maxwidth=self._width, scale=0.75, @@ -65,28 +119,75 @@ class V2SignInWindow(ba.Window): v_align='center') qroffs = 20.0 - self._cancel_button = ba.buttonwidget( - parent=self._root_widget, - position=(30, self._height - 55), - size=(130, 50), - scale=0.8, - label=ba.Lstr(resource='cancelText'), - # color=(0.6, 0.5, 0.6), - on_activate_call=self._done, - autoselect=True, - textcolor=(0.75, 0.7, 0.8), - # icon=ba.gettexture('crossOut'), - # iconscale=1.2 - ) - ba.containerwidget(edit=self._root_widget, - cancel_button=self._cancel_button) - qr_size = 270 ba.imagewidget(parent=self._root_widget, position=(self._width * 0.5 - qr_size * 0.5, - self._height * 0.34 + qroffs - qr_size * 0.5), + self._height * 0.36 + qroffs - qr_size * 0.5), size=(qr_size, qr_size), texture=_ba.get_qrcode_texture(address)) + # Start querying for results. + self._proxyid = response.proxyid + self._proxykey = response.proxykey + ba.timer(STATUS_CHECK_INTERVAL_SECONDS, + ba.WeakCall(self._ask_for_status)) + + def _ask_for_status(self) -> None: + assert self._proxyid is not None + assert self._proxykey is not None + ba.app.cloud.send_message(bacommon.cloud.LoginProxyStateQueryMessage( + proxyid=self._proxyid, proxykey=self._proxykey), + on_response=ba.WeakCall(self._got_status)) + + def _got_status( + self, response: Union[bacommon.cloud.LoginProxyStateQueryResponse, + Exception] + ) -> None: + + # For now, if anything goes wrong on the server-side, just abort + # with a vague error message. Can be more verbose later if need be. + if (isinstance(response, bacommon.cloud.LoginProxyStateQueryResponse) + and response.state is response.State.FAIL): + ba.playsound(ba.getsound('error')) + ba.screenmessage(ba.Lstr(resource='errorText'), color=(1, 0, 0)) + self._done() + return + + # If we got a token, set ourself as signed in. Hooray! + if (isinstance(response, bacommon.cloud.LoginProxyStateQueryResponse) + and response.state is response.State.SUCCESS): + assert response.credentials is not None + ba.app.accounts_v2.set_primary_credentials(response.credentials) + + # As a courtesy, tell the server we're done with this proxy + # so it can clean up (not a huge deal if this fails) + assert self._proxyid is not None + try: + ba.app.cloud.send_message( + bacommon.cloud.LoginProxyCompleteMessage( + proxyid=self._proxyid), + on_response=ba.WeakCall(self._proxy_complete_response)) + except CommunicationError: + pass + except Exception: + logging.warning( + 'Unexpected error sending login-proxy-complete message', + exc_info=True) + + self._done() + return + + # If we're still waiting, ask again soon. + if (isinstance(response, Exception) + or response.state is response.State.WAITING): + ba.timer(STATUS_CHECK_INTERVAL_SECONDS, + ba.WeakCall(self._ask_for_status)) + + def _proxy_complete_response(self, response: Union[None, + Exception]) -> None: + del response # Not used. + # We could do something smart like retry on exceptions here, but + # this isn't critical so we'll just let anything slide. + def _done(self) -> None: ba.containerwidget(edit=self._root_widget, transition='out_scale') diff --git a/dist/ba_data/python/bastd/ui/account/viewer.py b/dist/ba_data/python/bastd/ui/account/viewer.py index 01f18c1..6464da2 100644 --- a/dist/ba_data/python/bastd/ui/account/viewer.py +++ b/dist/ba_data/python/bastd/ui/account/viewer.py @@ -91,7 +91,7 @@ class AccountViewerWindow(popup.PopupWindow): # In cases where the user most likely has a browser/email, lets # offer a 'report this user' button. - if (is_browser_likely_available() and _ba.get_account_misc_read_val( + if (is_browser_likely_available() and _ba.get_v1_account_misc_read_val( 'showAccountExtrasMenu', False)): self._extras_menu_button = ba.buttonwidget( diff --git a/dist/ba_data/python/bastd/ui/appinvite.py b/dist/ba_data/python/bastd/ui/appinvite.py index 9d3cb38..262a809 100644 --- a/dist/ba_data/python/bastd/ui/appinvite.py +++ b/dist/ba_data/python/bastd/ui/appinvite.py @@ -60,15 +60,14 @@ class AppInviteWindow(ba.Window): resource='gatherWindow.earnTicketsForRecommendingAmountText', fallback_resource=( 'gatherWindow.earnTicketsForRecommendingText'), - subs=[ - ('${COUNT}', - str(_ba.get_account_misc_read_val('friendTryTickets', - 300))), - ('${YOU_COUNT}', - str( - _ba.get_account_misc_read_val('friendTryAwardTickets', - 100))) - ])) + subs=[('${COUNT}', + str( + _ba.get_v1_account_misc_read_val( + 'friendTryTickets', 300))), + ('${YOU_COUNT}', + str( + _ba.get_v1_account_misc_read_val( + 'friendTryAwardTickets', 100)))])) or_text = ba.Lstr(resource='orText', subs=[('${A}', ''), @@ -129,17 +128,18 @@ class AppInviteWindow(ba.Window): ba.playsound(ba.getsound('error')) return - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': ba.set_analytics_screen('App Invite UI') _ba.show_app_invite( ba.Lstr(resource='gatherWindow.appInviteTitleText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText')) ]).evaluate(), ba.Lstr(resource='gatherWindow.appInviteMessageText', - subs=[('${COUNT}', str(self._data['tickets'])), - ('${NAME}', _ba.get_account_name().split()[0]), - ('${APP_NAME}', ba.Lstr(resource='titleText')) - ]).evaluate(), self._data['code']) + subs=[ + ('${COUNT}', str(self._data['tickets'])), + ('${NAME}', _ba.get_v1_account_name().split()[0]), + ('${APP_NAME}', ba.Lstr(resource='titleText')) + ]).evaluate(), self._data['code']) else: ba.playsound(ba.getsound('error')) @@ -256,7 +256,7 @@ class ShowFriendCodeWindow(ba.Window): ]).evaluate(), ba.Lstr(resource='gatherWindow.appInviteMessageText', subs=[('${COUNT}', str(self._data['tickets'])), - ('${NAME}', _ba.get_account_name().split()[0]), + ('${NAME}', _ba.get_v1_account_name().split()[0]), ('${APP_NAME}', ba.Lstr(resource='titleText')) ]).evaluate(), self._data['code']) @@ -264,7 +264,7 @@ class ShowFriendCodeWindow(ba.Window): import urllib.parse # If somehow we got signed out. - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': ba.screenmessage(ba.Lstr(resource='notSignedInText'), color=(1, 0, 0)) ba.playsound(ba.getsound('error')) @@ -273,7 +273,7 @@ class ShowFriendCodeWindow(ba.Window): ba.set_analytics_screen('Email Friend Code') subject = (ba.Lstr(resource='gatherWindow.friendHasSentPromoCodeText'). evaluate().replace( - '${NAME}', _ba.get_account_name()).replace( + '${NAME}', _ba.get_v1_account_name()).replace( '${APP_NAME}', ba.Lstr(resource='titleText').evaluate()).replace( '${COUNT}', str(self._data['tickets']))) @@ -304,7 +304,7 @@ def handle_app_invites_press(force_code: bool = False) -> None: """(internal)""" app = ba.app do_app_invites = (app.platform == 'android' and app.subplatform == 'google' - and _ba.get_account_misc_read_val( + and _ba.get_v1_account_misc_read_val( 'enableAppInvites', False) and not app.on_tv) if force_code: do_app_invites = False diff --git a/dist/ba_data/python/bastd/ui/characterpicker.py b/dist/ba_data/python/bastd/ui/characterpicker.py index b60a476..9fc9bac 100644 --- a/dist/ba_data/python/bastd/ui/characterpicker.py +++ b/dist/ba_data/python/bastd/ui/characterpicker.py @@ -156,7 +156,7 @@ class CharacterPicker(popup.PopupWindow): def _on_store_press(self) -> None: from bastd.ui.account import show_sign_in_prompt from bastd.ui.store.browser import StoreBrowserWindow - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return self._transition_out() diff --git a/dist/ba_data/python/bastd/ui/colorpicker.py b/dist/ba_data/python/bastd/ui/colorpicker.py index 14e935c..3f12ed0 100644 --- a/dist/ba_data/python/bastd/ui/colorpicker.py +++ b/dist/ba_data/python/bastd/ui/colorpicker.py @@ -94,7 +94,7 @@ class ColorPicker(PopupWindow): on_activate_call=ba.WeakCall(self._select_other)) # Custom colors are limited to pro currently. - if not ba.app.accounts.have_pro(): + if not ba.app.accounts_v1.have_pro(): ba.imagewidget(parent=self.root_widget, position=(50, 12), size=(30, 30), @@ -118,7 +118,7 @@ class ColorPicker(PopupWindow): from bastd.ui import purchase # Requires pro. - if not ba.app.accounts.have_pro(): + if not ba.app.accounts_v1.have_pro(): purchase.PurchaseWindow(items=['pro']) self._transition_out() return @@ -249,6 +249,7 @@ class ColorPickerExact(PopupWindow): # color to the delegate, so start doing that. self._update_for_color() + # noinspection PyUnresolvedReferences def _update_for_color(self) -> None: if not self.root_widget: return diff --git a/dist/ba_data/python/bastd/ui/config.py b/dist/ba_data/python/bastd/ui/config.py index b9e7400..d8567e5 100644 --- a/dist/ba_data/python/bastd/ui/config.py +++ b/dist/ba_data/python/bastd/ui/config.py @@ -17,13 +17,11 @@ class ConfigCheckBox: It will automatically save and apply the config when its value changes. - - Attributes: - - widget - The underlying ba.Widget instance. """ + widget: ba.Widget + """The underlying ba.Widget instance.""" + def __init__(self, parent: ba.Widget, configkey: str, @@ -65,22 +63,20 @@ class ConfigNumberEdit: It will automatically save and apply the config when its value changes. - - Attributes: - - nametext - The text widget displaying the name. - - valuetext - The text widget displaying the current value. - - minusbutton - The button widget used to reduce the value. - - plusbutton - The button widget used to increase the value. """ + nametext: ba.Widget + """The text widget displaying the name.""" + + valuetext: ba.Widget + """The text widget displaying the current value.""" + + minusbutton: ba.Widget + """The button widget used to reduce the value.""" + + plusbutton: ba.Widget + """The button widget used to increase the value.""" + def __init__(self, parent: ba.Widget, configkey: str, diff --git a/dist/ba_data/python/bastd/ui/continues.py b/dist/ba_data/python/bastd/ui/continues.py index d5644a1..2635d90 100644 --- a/dist/ba_data/python/bastd/ui/continues.py +++ b/dist/ba_data/python/bastd/ui/continues.py @@ -142,9 +142,9 @@ class ContinuesWindow(ba.Window): self._on_cancel() return - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': sval = (ba.charstr(ba.SpecialChar.TICKET) + - str(_ba.get_account_ticket_count())) + str(_ba.get_v1_account_ticket_count())) else: sval = '?' if self._tickets_text is not None: @@ -176,14 +176,14 @@ class ContinuesWindow(ba.Window): ba.playsound(ba.getsound('error')) else: # If somehow we got signed out... - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': ba.screenmessage(ba.Lstr(resource='notSignedInText'), color=(1, 0, 0)) ba.playsound(ba.getsound('error')) return # If it appears we don't have enough tickets, offer to buy more. - tickets = _ba.get_account_ticket_count() + tickets = _ba.get_v1_account_ticket_count() if tickets < self._cost: # FIXME: Should we start the timer back up again after? self._counting_down = False diff --git a/dist/ba_data/python/bastd/ui/coop/browser.py b/dist/ba_data/python/bastd/ui/coop/browser.py index 6fb34fe..d118b50 100644 --- a/dist/ba_data/python/bastd/ui/coop/browser.py +++ b/dist/ba_data/python/bastd/ui/coop/browser.py @@ -92,7 +92,7 @@ class CoopBrowserWindow(ba.Window): self._tourney_data_up_to_date = False - self._campaign_difficulty = _ba.get_account_misc_val( + self._campaign_difficulty = _ba.get_v1_account_misc_val( 'campaignDifficulty', 'easy') super().__init__(root_widget=ba.containerwidget( @@ -235,7 +235,7 @@ class CoopBrowserWindow(ba.Window): self._subcontainer: Optional[ba.Widget] = None # Take note of our account state; we'll refresh later if this changes. - self._account_state_num = _ba.get_account_state_num() + self._account_state_num = _ba.get_v1_account_state_num() # Same for fg/bg state. self._fg_state = app.fg_state @@ -251,14 +251,14 @@ class CoopBrowserWindow(ba.Window): # If we've got a cached tournament list for our account and info for # each one of those tournaments, go ahead and display it as a # starting point. - if (app.accounts.account_tournament_list is not None - and app.accounts.account_tournament_list[0] - == _ba.get_account_state_num() - and all(t_id in app.accounts.tournament_info - for t_id in app.accounts.account_tournament_list[1])): + if (app.accounts_v1.account_tournament_list is not None + and app.accounts_v1.account_tournament_list[0] + == _ba.get_v1_account_state_num() and all( + t_id in app.accounts_v1.tournament_info + for t_id in app.accounts_v1.account_tournament_list[1])): tourney_data = [ - app.accounts.tournament_info[t_id] - for t_id in app.accounts.account_tournament_list[1] + app.accounts_v1.tournament_info[t_id] + for t_id in app.accounts_v1.account_tournament_list[1] ] self._update_for_data(tourney_data) @@ -269,6 +269,7 @@ class CoopBrowserWindow(ba.Window): repeat=True) self._update() + # noinspection PyUnresolvedReferences @staticmethod def _preload_modules() -> None: """Preload modules we use (called in bg thread).""" @@ -299,7 +300,7 @@ class CoopBrowserWindow(ba.Window): self._tourney_data_up_to_date = False # If our account state has changed, do a full request. - account_state_num = _ba.get_account_state_num() + account_state_num = _ba.get_v1_account_state_num() if account_state_num != self._account_state_num: self._account_state_num = account_state_num self._save_state() @@ -357,7 +358,7 @@ class CoopBrowserWindow(ba.Window): try: ba.imagewidget( edit=self._hard_button_lock_image, - opacity=0.0 if ba.app.accounts.have_pro_options() else 1.0) + opacity=0.0 if ba.app.accounts_v1.have_pro_options() else 1.0) except Exception: ba.print_exception('Error updating campaign lock.') @@ -479,7 +480,7 @@ class CoopBrowserWindow(ba.Window): tbtn['required_league'] = (None if 'requiredLeague' not in entry else entry['requiredLeague']) - game = ba.app.accounts.tournament_info[ + game = ba.app.accounts_v1.tournament_info[ tbtn['tournament_id']]['game'] if game is None: @@ -490,7 +491,7 @@ class CoopBrowserWindow(ba.Window): else: campaignname, levelname = game.split(':') campaign = getcampaign(campaignname) - max_players = ba.app.accounts.tournament_info[ + max_players = ba.app.accounts_v1.tournament_info[ tbtn['tournament_id']]['maxPlayers'] txt = ba.Lstr( value='${A} ${B}', @@ -524,7 +525,7 @@ class CoopBrowserWindow(ba.Window): tbtn['allow_ads'] = allow_ads = entry['allowAds'] final_fee: Optional[int] = (None if fee_var is None else - _ba.get_account_misc_read_val( + _ba.get_v1_account_misc_read_val( fee_var, '?')) final_fee_str: Union[str, ba.Lstr] @@ -539,9 +540,9 @@ class CoopBrowserWindow(ba.Window): ba.charstr(ba.SpecialChar.TICKET_BACKING) + str(final_fee)) - ad_tries_remaining = ba.app.accounts.tournament_info[ + ad_tries_remaining = ba.app.accounts_v1.tournament_info[ tbtn['tournament_id']]['adTriesRemaining'] - free_tries_remaining = ba.app.accounts.tournament_info[ + free_tries_remaining = ba.app.accounts_v1.tournament_info[ tbtn['tournament_id']]['freeTriesRemaining'] # Now, if this fee allows ads and we support video ads, show @@ -591,7 +592,7 @@ class CoopBrowserWindow(ba.Window): def _on_tournament_query_response(self, data: Optional[dict[str, Any]]) -> None: - accounts = ba.app.accounts + accounts = ba.app.accounts_v1 if data is not None: tournament_data = data['t'] # This used to be the whole payload. self._last_tournament_query_response_time = ba.time( @@ -605,9 +606,11 @@ class CoopBrowserWindow(ba.Window): accounts.cache_tournament_info(tournament_data) # Also cache the current tourney list/order for this account. - accounts.account_tournament_list = (_ba.get_account_state_num(), [ - e['tournamentID'] for e in tournament_data - ]) + accounts.account_tournament_list = (_ba.get_v1_account_state_num(), + [ + e['tournamentID'] + for e in tournament_data + ]) self._doing_tournament_query = False self._update_for_data(tournament_data) @@ -616,7 +619,8 @@ class CoopBrowserWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.purchase import PurchaseWindow if difficulty != self._campaign_difficulty: - if difficulty == 'hard' and not ba.app.accounts.have_pro_options(): + if (difficulty == 'hard' + and not ba.app.accounts_v1.have_pro_options()): PurchaseWindow(items=['pro']) return ba.playsound(ba.getsound('gunCocking')) @@ -871,7 +875,7 @@ class CoopBrowserWindow(ba.Window): # no tournaments). if self._tournament_button_count == 0: unavailable_text = ba.Lstr(resource='unavailableText') - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': unavailable_text = ba.Lstr( value='${A} (${B})', subs=[('${A}', unavailable_text), @@ -942,7 +946,7 @@ class CoopBrowserWindow(ba.Window): ] # Show easter-egg-hunt either if its easter or we own it. - if _ba.get_account_misc_read_val( + if _ba.get_v1_account_misc_read_val( 'easter', False) or _ba.get_purchased('games.easter_egg_hunt'): items = [ 'Challenges:Easter Egg Hunt', 'Challenges:Pro Easter Egg Hunt' @@ -1345,7 +1349,7 @@ class CoopBrowserWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.account import show_sign_in_prompt from bastd.ui.league.rankwindow import LeagueRankWindow - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return self._save_state() @@ -1362,7 +1366,7 @@ class CoopBrowserWindow(ba.Window): ) -> None: # pylint: disable=cyclic-import from bastd.ui.account import show_sign_in_prompt - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return self._save_state() @@ -1426,7 +1430,7 @@ class CoopBrowserWindow(ba.Window): # Do a bit of pre-flight for tournament options. if tournament_button is not None: - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return @@ -1464,7 +1468,7 @@ class CoopBrowserWindow(ba.Window): return # Game is whatever the tournament tells us it is. - game = ba.app.accounts.tournament_info[ + game = ba.app.accounts_v1.tournament_info[ tournament_button['tournament_id']]['game'] if tournament_button is None and game == 'Easy:The Last Stand': @@ -1480,8 +1484,8 @@ class CoopBrowserWindow(ba.Window): if tournament_button is None and game in ( 'Challenges:Infinite Runaround', 'Challenges:Infinite Onslaught' - ) and not ba.app.accounts.have_pro(): - if _ba.get_account_state() != 'signed_in': + ) and not ba.app.accounts_v1.have_pro(): + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() else: PurchaseWindow(items=['pro']) @@ -1507,7 +1511,7 @@ class CoopBrowserWindow(ba.Window): if (tournament_button is None and required_purchase is not None and not _ba.get_purchased(required_purchase)): - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() else: PurchaseWindow(items=[required_purchase]) diff --git a/dist/ba_data/python/bastd/ui/coop/gamebutton.py b/dist/ba_data/python/bastd/ui/coop/gamebutton.py index 2a6a75b..026f4ce 100644 --- a/dist/ba_data/python/bastd/ui/coop/gamebutton.py +++ b/dist/ba_data/python/bastd/ui/coop/gamebutton.py @@ -199,7 +199,7 @@ class GameButton: # Hard-code games we haven't unlocked. if ((game in ('Challenges:Infinite Runaround', 'Challenges:Infinite Onslaught') - and not ba.app.accounts.have_pro()) + and not ba.app.accounts_v1.have_pro()) or (game in ('Challenges:Meteor Shower', ) and not _ba.get_purchased('games.meteor_shower')) or (game in ('Challenges:Target Practice', diff --git a/dist/ba_data/python/bastd/ui/gather/__init__.py b/dist/ba_data/python/bastd/ui/gather/__init__.py index 8dca6cc..c8de2ce 100644 --- a/dist/ba_data/python/bastd/ui/gather/__init__.py +++ b/dist/ba_data/python/bastd/ui/gather/__init__.py @@ -151,7 +151,7 @@ class GatherWindow(ba.Window): tabdefs: list[tuple[GatherWindow.TabID, ba.Lstr]] = [ (self.TabID.ABOUT, ba.Lstr(resource=self._r + '.aboutText')) ] - if _ba.get_account_misc_read_val('enablePublicParties', True): + if _ba.get_v1_account_misc_read_val('enablePublicParties', True): tabdefs.append((self.TabID.INTERNET, ba.Lstr(resource=self._r + '.publicText'))) tabdefs.append( diff --git a/dist/ba_data/python/bastd/ui/gather/abouttab.py b/dist/ba_data/python/bastd/ui/gather/abouttab.py index f185b90..87e0937 100644 --- a/dist/ba_data/python/bastd/ui/gather/abouttab.py +++ b/dist/ba_data/python/bastd/ui/gather/abouttab.py @@ -52,7 +52,8 @@ class AboutGatherTab(GatherTab): include_invite = True msc_scale = 1.1 c_height_2 = min(region_height, string_height * msc_scale + 100) - try_tickets = _ba.get_account_misc_read_val('friendTryTickets', None) + try_tickets = _ba.get_v1_account_misc_read_val('friendTryTickets', + None) if try_tickets is None: include_invite = False self._container = ba.containerwidget( @@ -106,7 +107,7 @@ class AboutGatherTab(GatherTab): def _invite_to_try_press(self) -> None: from bastd.ui.account import show_sign_in_prompt from bastd.ui.appinvite import handle_app_invites_press - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return handle_app_invites_press() diff --git a/dist/ba_data/python/bastd/ui/gather/manualtab.py b/dist/ba_data/python/bastd/ui/gather/manualtab.py index 798b11f..fe0a706 100644 --- a/dist/ba_data/python/bastd/ui/gather/manualtab.py +++ b/dist/ba_data/python/bastd/ui/gather/manualtab.py @@ -17,7 +17,6 @@ import ba if TYPE_CHECKING: from typing import Any, Optional, Union, Callable from bastd.ui.gather import GatherWindow - from bastd.ui.confirm import ConfirmWindow def _safe_set_text(txt: Optional[ba.Widget], diff --git a/dist/ba_data/python/bastd/ui/gather/privatetab.py b/dist/ba_data/python/bastd/ui/gather/privatetab.py index 839ba78..b1d047f 100644 --- a/dist/ba_data/python/bastd/ui/gather/privatetab.py +++ b/dist/ba_data/python/bastd/ui/gather/privatetab.py @@ -166,7 +166,7 @@ class PrivateGatherTab(GatherTab): elif hcfg.session_type == 'teams': sessiontype = ba.DualTeamSession else: - raise RuntimeError('fInvalid sessiontype: {hcfg.session_type}') + raise RuntimeError(f'Invalid sessiontype: {hcfg.session_type}') pvars = PlaylistTypeVars(sessiontype) playlist_name = ba.app.config.get( @@ -225,7 +225,7 @@ class PrivateGatherTab(GatherTab): def _update_currency_ui(self) -> None: # Keep currency count up to date if applicable. try: - t_str = str(_ba.get_account_ticket_count()) + t_str = str(_ba.get_v1_account_ticket_count()) except Exception: t_str = '?' if self._get_tickets_button: @@ -245,7 +245,7 @@ class PrivateGatherTab(GatherTab): if self._state.sub_tab is SubTabType.HOST: # If we're not signed in, just refresh to show that. - if (_ba.get_account_state() != 'signed_in' + if (_ba.get_v1_account_state() != 'signed_in' and self._showing_not_signed_in_screen): self._refresh_sub_tab() else: @@ -254,7 +254,7 @@ class PrivateGatherTab(GatherTab): if (self._last_hosting_state_query_time is None or now - self._last_hosting_state_query_time > 15.0): self._debug_server_comm('querying private party state') - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': _ba.add_transaction( { 'type': 'PRIVATE_PARTY_QUERY', @@ -437,7 +437,7 @@ class PrivateGatherTab(GatherTab): # pylint: disable=too-many-branches # pylint: disable=too-many-statements - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': ba.textwidget(parent=self._container, size=(0, 0), h_align='center', @@ -776,7 +776,7 @@ class PrivateGatherTab(GatherTab): or self._waiting_for_initial_state): return - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': ba.screenmessage(ba.Lstr(resource='notSignedInErrorText')) ba.playsound(ba.getsound('error')) self._refresh_sub_tab() @@ -795,7 +795,7 @@ class PrivateGatherTab(GatherTab): if self._hostingstate.tickets_to_host_now > 0: ticket_count: Optional[int] try: - ticket_count = _ba.get_account_ticket_count() + ticket_count = _ba.get_v1_account_ticket_count() except Exception: # FIXME: should add a ba.NotSignedInError we can use here. ticket_count = None @@ -809,7 +809,7 @@ class PrivateGatherTab(GatherTab): { 'type': 'PRIVATE_PARTY_START', 'config': dataclass_to_dict(self._hostingconfig), - 'region_pings': ba.app.net.region_pings, + 'region_pings': ba.app.net.zone_pings, 'expire_time': time.time() + 20, }, callback=ba.WeakCall(self._hosting_state_response)) diff --git a/dist/ba_data/python/bastd/ui/gather/publictab.py b/dist/ba_data/python/bastd/ui/gather/publictab.py index 2edb995..0261cef 100644 --- a/dist/ba_data/python/bastd/ui/gather/publictab.py +++ b/dist/ba_data/python/bastd/ui/gather/publictab.py @@ -88,8 +88,8 @@ class UIRow: if party.clean_display_index == index: return - ping_good = _ba.get_account_misc_read_val('pingGood', 100) - ping_med = _ba.get_account_misc_read_val('pingMed', 500) + ping_good = _ba.get_v1_account_misc_read_val('pingGood', 100) + ping_med = _ba.get_v1_account_misc_read_val('pingMed', 500) self._clear() hpos = 20 @@ -122,8 +122,8 @@ class UIRow: if party.stats_addr: url = party.stats_addr.replace( '${ACCOUNT}', - _ba.get_account_misc_read_val_2('resolvedAccountID', - 'UNKNOWN')) + _ba.get_v1_account_misc_read_val_2('resolvedAccountID', + 'UNKNOWN')) self._stats_button = ba.buttonwidget( color=(0.3, 0.6, 0.94), textcolor=(1.0, 1.0, 1.0), @@ -793,7 +793,7 @@ class PublicGatherTab(GatherTab): self._process_pending_party_infos() # Anytime we sign in/out, make sure we refresh our list. - signed_in = _ba.get_account_state() == 'signed_in' + signed_in = _ba.get_v1_account_state() == 'signed_in' if self._signed_in != signed_in: self._signed_in = signed_in self._party_lists_dirty = True @@ -986,7 +986,7 @@ class PublicGatherTab(GatherTab): p[1].index)) # If signed out or errored, show no parties. - if (_ba.get_account_state() != 'signed_in' + if (_ba.get_v1_account_state() != 'signed_in' or not self._have_valid_server_list): self._parties_displayed = {} else: @@ -1023,11 +1023,11 @@ class PublicGatherTab(GatherTab): # Fire off a new public-party query periodically. if (self._last_server_list_query_time is None or now - self._last_server_list_query_time > 0.001 * - _ba.get_account_misc_read_val('pubPartyRefreshMS', 10000)): + _ba.get_v1_account_misc_read_val('pubPartyRefreshMS', 10000)): self._last_server_list_query_time = now if DEBUG_SERVER_COMMUNICATION: print('REQUESTING SERVER LIST') - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': _ba.add_transaction( { 'type': 'PUBLIC_PARTY_QUERY', @@ -1156,7 +1156,7 @@ class PublicGatherTab(GatherTab): def _on_start_advertizing_press(self) -> None: from bastd.ui.account import show_sign_in_prompt - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return diff --git a/dist/ba_data/python/bastd/ui/getcurrency.py b/dist/ba_data/python/bastd/ui/getcurrency.py index d267406..040d1c1 100644 --- a/dist/ba_data/python/bastd/ui/getcurrency.py +++ b/dist/ba_data/python/bastd/ui/getcurrency.py @@ -179,22 +179,27 @@ class GetCurrencyWindow(ba.Window): c2txt = ba.Lstr( resource=rsrc, subs=[('${COUNT}', - str(_ba.get_account_misc_read_val('tickets2Amount', 500)))]) + str(_ba.get_v1_account_misc_read_val('tickets2Amount', + 500)))]) c3txt = ba.Lstr( resource=rsrc, - subs=[('${COUNT}', - str(_ba.get_account_misc_read_val('tickets3Amount', - 1500)))]) + subs=[ + ('${COUNT}', + str(_ba.get_v1_account_misc_read_val('tickets3Amount', 1500))) + ]) c4txt = ba.Lstr( resource=rsrc, - subs=[('${COUNT}', - str(_ba.get_account_misc_read_val('tickets4Amount', - 5000)))]) + subs=[ + ('${COUNT}', + str(_ba.get_v1_account_misc_read_val('tickets4Amount', 5000))) + ]) c5txt = ba.Lstr( resource=rsrc, - subs=[('${COUNT}', - str(_ba.get_account_misc_read_val('tickets5Amount', - 15000)))]) + subs=[ + ('${COUNT}', + str(_ba.get_v1_account_misc_read_val('tickets5Amount', + 15000))) + ]) h = 110.0 @@ -261,7 +266,7 @@ class GetCurrencyWindow(ba.Window): label=ba.Lstr(resource=self._r + '.ticketsFromASponsorText', subs=[('${COUNT}', str( - _ba.get_account_misc_read_val( + _ba.get_v1_account_misc_read_val( 'sponsorTickets', 5)))]), tex_name='ticketsMore', enabled=self._enable_ad_button, @@ -301,11 +306,10 @@ class GetCurrencyWindow(ba.Window): size=b_size_3, label=ba.Lstr( resource='gatherWindow.earnTicketsForRecommendingText', - subs=[ - ('${COUNT}', - str(_ba.get_account_misc_read_val( - 'sponsorTickets', 5))) - ]), + subs=[('${COUNT}', + str( + _ba.get_v1_account_misc_read_val( + 'sponsorTickets', 5)))]), tex_name='ticketsMore', enabled=True, tex_opacity=0.6, @@ -336,7 +340,7 @@ class GetCurrencyWindow(ba.Window): '.youHaveText').evaluate().partition('${COUNT}')[0].strip()) txt2 = (ba.Lstr( resource=self._r + - '.youHaveText').evaluate().rpartition('${COUNT}')[0].strip()) + '.youHaveText').evaluate().rpartition('${COUNT}')[-1].strip()) ba.textwidget(parent=self._root_widget, text=txt1, @@ -427,16 +431,16 @@ class GetCurrencyWindow(ba.Window): import datetime # if we somehow get signed out, just die.. - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': self._back() return - self._ticket_count = _ba.get_account_ticket_count() + self._ticket_count = _ba.get_v1_account_ticket_count() # update our incentivized ad button depending on whether ads are # available if self._ad_button is not None: - next_reward_ad_time = _ba.get_account_misc_read_val_2( + next_reward_ad_time = _ba.get_v1_account_misc_read_val_2( 'nextRewardAdTime', None) if next_reward_ad_time is not None: next_reward_ad_time = datetime.datetime.utcfromtimestamp( @@ -494,8 +498,9 @@ class GetCurrencyWindow(ba.Window): app = ba.app if ((app.test_build or (app.platform == 'android' - and app.subplatform in ['oculus', 'cardboard'])) and - _ba.get_account_misc_read_val('allowAccountLinking2', False)): + and app.subplatform in ['oculus', 'cardboard'])) + and _ba.get_v1_account_misc_read_val('allowAccountLinking2', + False)): ba.screenmessage(ba.Lstr(resource=self._r + '.unavailableLinkAccountText'), color=(1, 0.5, 0)) @@ -509,7 +514,7 @@ class GetCurrencyWindow(ba.Window): from bastd.ui import appinvite from ba.internal import master_server_get if item == 'app_invite': - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': account.show_sign_in_prompt() return appinvite.handle_app_invites_press() @@ -554,7 +559,7 @@ class GetCurrencyWindow(ba.Window): if item == 'ad': import datetime # if ads are disabled until some time, error.. - next_reward_ad_time = _ba.get_account_misc_read_val_2( + next_reward_ad_time = _ba.get_v1_account_misc_read_val_2( 'nextRewardAdTime', None) if next_reward_ad_time is not None: next_reward_ad_time = datetime.datetime.utcfromtimestamp( diff --git a/dist/ba_data/python/bastd/ui/iconpicker.py b/dist/ba_data/python/bastd/ui/iconpicker.py index 6c6f07d..a9d5727 100644 --- a/dist/ba_data/python/bastd/ui/iconpicker.py +++ b/dist/ba_data/python/bastd/ui/iconpicker.py @@ -40,7 +40,7 @@ class IconPicker(popup.PopupWindow): self._transitioning_out = False self._icons = [ba.charstr(ba.SpecialChar.LOGO) - ] + ba.app.accounts.get_purchased_icons() + ] + ba.app.accounts_v1.get_purchased_icons() count = len(self._icons) columns = 4 rows = int(math.ceil(float(count) / columns)) @@ -137,7 +137,7 @@ class IconPicker(popup.PopupWindow): def _on_store_press(self) -> None: from bastd.ui.account import show_sign_in_prompt from bastd.ui.store.browser import StoreBrowserWindow - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return self._transition_out() diff --git a/dist/ba_data/python/bastd/ui/kiosk.py b/dist/ba_data/python/bastd/ui/kiosk.py index c75caec..09f92aa 100644 --- a/dist/ba_data/python/bastd/ui/kiosk.py +++ b/dist/ba_data/python/bastd/ui/kiosk.py @@ -360,7 +360,7 @@ class KioskWindow(ba.Window): def _update(self) -> None: # Kiosk-mode is designed to be used signed-out... try for force # the issue. - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': # _bs.sign_out() # FIXME: Try to delete player profiles here too. pass diff --git a/dist/ba_data/python/bastd/ui/league/rankbutton.py b/dist/ba_data/python/bastd/ui/league/rankbutton.py index d7ab53e..3a6ffa5 100644 --- a/dist/ba_data/python/bastd/ui/league/rankbutton.py +++ b/dist/ba_data/python/bastd/ui/league/rankbutton.py @@ -94,7 +94,7 @@ class LeagueRankButton: self._smooth_update_timer: Optional[ba.Timer] = None # Take note of our account state; we'll refresh later if this changes. - self._account_state_num = _ba.get_account_state_num() + self._account_state_num = _ba.get_v1_account_state_num() self._last_power_ranking_query_time: Optional[float] = None self._doing_power_ranking_query = False self.set_position(position) @@ -106,7 +106,7 @@ class LeagueRankButton: self._update() # If we've got cached power-ranking data already, apply it. - data = ba.app.accounts.get_cached_league_rank_data() + data = ba.app.accounts_v1.get_cached_league_rank_data() if data is not None: self._update_for_league_rank_data(data) @@ -224,7 +224,7 @@ class LeagueRankButton: in_top = data is not None and data['rank'] is not None do_percent = False - if data is None or _ba.get_account_state() != 'signed_in': + if data is None or _ba.get_v1_account_state() != 'signed_in': self._percent = self._rank = None status_text = '-' elif in_top: @@ -248,7 +248,8 @@ class LeagueRankButton: self._percent = self._rank = None status_text = '-' else: - our_points = ba.app.accounts.get_league_rank_points(data) + our_points = ba.app.accounts_v1.get_league_rank_points( + data) progress = float(our_points) / data['scores'][-1][1] self._percent = int(progress * 100.0) self._rank = None @@ -327,14 +328,14 @@ class LeagueRankButton: def _on_power_ranking_query_response( self, data: Optional[dict[str, Any]]) -> None: self._doing_power_ranking_query = False - ba.app.accounts.cache_league_rank_data(data) + ba.app.accounts_v1.cache_league_rank_data(data) self._update_for_league_rank_data(data) def _update(self) -> None: cur_time = ba.time(ba.TimeType.REAL) # If our account state has changed, refresh our UI. - account_state_num = _ba.get_account_state_num() + account_state_num = _ba.get_v1_account_state_num() if account_state_num != self._account_state_num: self._account_state_num = account_state_num diff --git a/dist/ba_data/python/bastd/ui/league/rankwindow.py b/dist/ba_data/python/bastd/ui/league/rankwindow.py index d1e31c4..e1828ad 100644 --- a/dist/ba_data/python/bastd/ui/league/rankwindow.py +++ b/dist/ba_data/python/bastd/ui/league/rankwindow.py @@ -118,13 +118,13 @@ class LeagueRankWindow(ba.Window): self._season: Optional[str] = None # take note of our account state; we'll refresh later if this changes - self._account_state = _ba.get_account_state() + self._account_state = _ba.get_v1_account_state() self._refresh() self._restore_state() # if we've got cached power-ranking data already, display it - info = ba.app.accounts.get_cached_league_rank_data() + info = ba.app.accounts_v1.get_cached_league_rank_data() if info is not None: self._update_for_league_rank_data(info) @@ -155,7 +155,8 @@ class LeagueRankWindow(ba.Window): resource='coopSelectWindow.activenessAllTimeInfoText' if self._season == 'a' else 'coopSelectWindow.activenessInfoText', subs=[('${MAX}', - str(_ba.get_account_misc_read_val('activenessMax', 1.0)))]) + str(_ba.get_v1_account_misc_read_val('activenessMax', + 1.0)))]) confirm.ConfirmWindow(txt, cancel_button=False, width=460, @@ -164,17 +165,15 @@ class LeagueRankWindow(ba.Window): def _on_pro_mult_press(self) -> None: from bastd.ui import confirm - txt = ba.Lstr( - resource='coopSelectWindow.proMultInfoText', - subs=[ - ('${PERCENT}', - str(_ba.get_account_misc_read_val('proPowerRankingBoost', - 10))), - ('${PRO}', - ba.Lstr(resource='store.bombSquadProNameText', - subs=[('${APP_NAME}', ba.Lstr(resource='titleText')) - ])) - ]) + txt = ba.Lstr(resource='coopSelectWindow.proMultInfoText', + subs=[('${PERCENT}', + str( + _ba.get_v1_account_misc_read_val( + 'proPowerRankingBoost', 10))), + ('${PRO}', + ba.Lstr(resource='store.bombSquadProNameText', + subs=[('${APP_NAME}', + ba.Lstr(resource='titleText'))]))]) confirm.ConfirmWindow(txt, cancel_button=False, width=460, @@ -196,7 +195,7 @@ class LeagueRankWindow(ba.Window): self._doing_power_ranking_query = False # important: *only* cache this if we requested the current season.. if data is not None and data.get('s', None) is None: - ba.app.accounts.cache_league_rank_data(data) + ba.app.accounts_v1.cache_league_rank_data(data) # always store a copy locally though (even for other seasons) self._league_rank_data = copy.deepcopy(data) self._update_for_league_rank_data(data) @@ -209,7 +208,7 @@ class LeagueRankWindow(ba.Window): cur_time = ba.time(ba.TimeType.REAL) # if our account state has changed, refresh our UI - account_state = _ba.get_account_state() + account_state = _ba.get_v1_account_state() if account_state != self._account_state: self._account_state = account_state self._save_state() @@ -353,7 +352,7 @@ class LeagueRankWindow(ba.Window): maxwidth=200) self._activity_mult_button: Optional[ba.Widget] - if _ba.get_account_misc_read_val('act', False): + if _ba.get_v1_account_misc_read_val('act', False): self._activity_mult_button = ba.buttonwidget( parent=w_parent, position=(h2 - 60, v2 + 10), @@ -594,7 +593,7 @@ class LeagueRankWindow(ba.Window): # pylint: disable=too-many-locals if not self._root_widget: return - accounts = ba.app.accounts + accounts = ba.app.accounts_v1 in_top = (data is not None and data['rank'] is not None) eq_text = self._rdict.powerRankingPointsEqualsText pts_txt = self._rdict.powerRankingPointsText @@ -603,7 +602,7 @@ class LeagueRankWindow(ba.Window): finished_season_unranked = False self._can_do_more_button = True extra_text = '' - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': status_text = '(' + ba.Lstr( resource='notSignedInText').evaluate() + ')' elif in_top: @@ -790,7 +789,8 @@ class LeagueRankWindow(ba.Window): have_pro = False if data is None else data['p'] pro_mult = 1.0 + float( - _ba.get_account_misc_read_val('proPowerRankingBoost', 0.0)) * 0.01 + _ba.get_v1_account_misc_read_val('proPowerRankingBoost', + 0.0)) * 0.01 # pylint: disable=consider-using-f-string ba.textwidget(edit=self._pro_mult_text, text=' -' if diff --git a/dist/ba_data/python/bastd/ui/mainmenu.py b/dist/ba_data/python/bastd/ui/mainmenu.py index 420b6cf..155188b 100644 --- a/dist/ba_data/python/bastd/ui/mainmenu.py +++ b/dist/ba_data/python/bastd/ui/mainmenu.py @@ -67,15 +67,16 @@ class MainMenuWindow(ba.Window): self._restore_state() # Keep an eye on a few things and refresh if they change. - self._account_state = _ba.get_account_state() - self._account_state_num = _ba.get_account_state_num() - self._account_type = (_ba.get_account_type() + self._account_state = _ba.get_v1_account_state() + self._account_state_num = _ba.get_v1_account_state_num() + self._account_type = (_ba.get_v1_account_type() if self._account_state == 'signed_in' else None) self._refresh_timer = ba.Timer(1.0, ba.WeakCall(self._check_refresh), repeat=True, timetype=ba.TimeType.REAL) + # noinspection PyUnresolvedReferences @staticmethod def _preload_modules() -> None: """Preload modules we use (called in bg thread).""" @@ -121,9 +122,9 @@ class MainMenuWindow(ba.Window): ba.print_exception('Error showing get-remote-app info') def _get_store_char_tex(self) -> str: - return ('storeCharacterXmas' if _ba.get_account_misc_read_val( + return ('storeCharacterXmas' if _ba.get_v1_account_misc_read_val( 'xmas', False) else - 'storeCharacterEaster' if _ba.get_account_misc_read_val( + 'storeCharacterEaster' if _ba.get_v1_account_misc_read_val( 'easter', False) else 'storeCharacter') def _check_refresh(self) -> None: @@ -137,13 +138,13 @@ class MainMenuWindow(ba.Window): return store_char_tex = self._get_store_char_tex() - account_state_num = _ba.get_account_state_num() + account_state_num = _ba.get_v1_account_state_num() if (account_state_num != self._account_state_num or store_char_tex != self._store_char_tex): self._store_char_tex = store_char_tex self._account_state_num = account_state_num - account_state = self._account_state = (_ba.get_account_state()) - self._account_type = (_ba.get_account_type() + account_state = self._account_state = (_ba.get_v1_account_state()) + self._account_type = (_ba.get_v1_account_type() if account_state == 'signed_in' else None) self._save_state() self._refresh() @@ -212,8 +213,8 @@ class MainMenuWindow(ba.Window): on_activate_call=self._settings) # Scattered eggs on easter. - if _ba.get_account_misc_read_val('easter', - False) and not self._in_game: + if _ba.get_v1_account_misc_read_val('easter', + False) and not self._in_game: icon_size = 34 ba.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 - 15, @@ -309,7 +310,7 @@ class MainMenuWindow(ba.Window): transition_delay=self._tdelay) # Scattered eggs on easter. - if _ba.get_account_misc_read_val('easter', False): + if _ba.get_v1_account_misc_read_val('easter', False): icon_size = 30 ba.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 + 25, @@ -426,8 +427,8 @@ class MainMenuWindow(ba.Window): self._height = 200.0 enable_account_button = True account_type_name: Union[str, ba.Lstr] - if _ba.get_account_state() == 'signed_in': - account_type_name = _ba.get_account_display_string() + if _ba.get_v1_account_state() == 'signed_in': + account_type_name = _ba.get_v1_account_display_string() account_type_icon = None account_textcolor = (1.0, 1.0, 1.0) else: @@ -617,8 +618,8 @@ class MainMenuWindow(ba.Window): enable_sound=account_type_enable_button_sound) # Scattered eggs on easter. - if _ba.get_account_misc_read_val('easter', - False) and not self._in_game: + if _ba.get_v1_account_misc_read_val('easter', + False) and not self._in_game: icon_size = 32 ba.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 + 35, @@ -647,8 +648,8 @@ class MainMenuWindow(ba.Window): self._how_to_play_button = btn # Scattered eggs on easter. - if _ba.get_account_misc_read_val('easter', - False) and not self._in_game: + if _ba.get_v1_account_misc_read_val('easter', + False) and not self._in_game: icon_size = 28 ba.imagewidget(parent=self._root_widget, position=(h - icon_size * 0.5 + 30, @@ -850,7 +851,7 @@ class MainMenuWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.store.browser import StoreBrowserWindow from bastd.ui.account import show_sign_in_prompt - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return self._save_state() diff --git a/dist/ba_data/python/bastd/ui/partyqueue.py b/dist/ba_data/python/bastd/ui/partyqueue.py index f1b5a23..a44f92c 100644 --- a/dist/ba_data/python/bastd/ui/partyqueue.py +++ b/dist/ba_data/python/bastd/ui/partyqueue.py @@ -320,8 +320,8 @@ class PartyQueueWindow(ba.Window): if -1 not in self._dudes_by_id: dude = self.Dude( self, response['d'], self._initial_offset, True, - _ba.get_account_misc_read_val_2('resolvedAccountID', None), - _ba.get_account_display_string()) + _ba.get_v1_account_misc_read_val_2('resolvedAccountID', None), + _ba.get_v1_account_display_string()) self._dudes_by_id[-1] = dude self._dudes.append(dude) else: @@ -341,6 +341,7 @@ class PartyQueueWindow(ba.Window): self._dudes_by_id[enemy_id].claimed = True # remove unclaimed dudes from both of our lists + # noinspection PyUnresolvedReferences self._dudes_by_id = dict([ item for item in list(self._dudes_by_id.items()) if item[1].claimed ]) @@ -456,11 +457,11 @@ class PartyQueueWindow(ba.Window): """Boost was pressed.""" from bastd.ui import account from bastd.ui import getcurrency - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': account.show_sign_in_prompt() return - if _ba.get_account_ticket_count() < self._boost_tickets: + if _ba.get_v1_account_ticket_count() < self._boost_tickets: ba.playsound(ba.getsound('error')) getcurrency.show_get_tickets_prompt() return @@ -497,17 +498,17 @@ class PartyQueueWindow(ba.Window): # Update boost button color based on if we have enough moola. if self._boost_button is not None: can_boost = ( - (_ba.get_account_state() == 'signed_in' - and _ba.get_account_ticket_count() >= self._boost_tickets)) + (_ba.get_v1_account_state() == 'signed_in' + and _ba.get_v1_account_ticket_count() >= self._boost_tickets)) ba.buttonwidget(edit=self._boost_button, color=(0, 1, 0) if can_boost else (0.7, 0.7, 0.7)) # Update ticket-count. if self._tickets_text is not None: if self._boost_button is not None: - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': val = ba.charstr(ba.SpecialChar.TICKET) + str( - _ba.get_account_ticket_count()) + _ba.get_v1_account_ticket_count()) else: val = ba.charstr(ba.SpecialChar.TICKET) + '???' ba.textwidget(edit=self._tickets_text, text=val) @@ -517,7 +518,7 @@ class PartyQueueWindow(ba.Window): current_time = ba.time(ba.TimeType.REAL) if (self._last_transaction_time is None or current_time - self._last_transaction_time > - 0.001 * _ba.get_account_misc_read_val('pqInt', 5000)): + 0.001 * _ba.get_v1_account_misc_read_val('pqInt', 5000)): self._last_transaction_time = current_time _ba.add_transaction( { diff --git a/dist/ba_data/python/bastd/ui/play.py b/dist/ba_data/python/bastd/ui/play.py index adfeb3e..5fefb3e 100644 --- a/dist/ba_data/python/bastd/ui/play.py +++ b/dist/ba_data/python/bastd/ui/play.py @@ -417,6 +417,7 @@ class PlayWindow(ba.Window): self._restore_state() + # noinspection PyUnresolvedReferences @staticmethod def _preload_modules() -> None: """Preload modules we use (called in bg thread).""" @@ -446,7 +447,7 @@ class PlayWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.account import show_sign_in_prompt from bastd.ui.coop.browser import CoopBrowserWindow - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return self._save_state() diff --git a/dist/ba_data/python/bastd/ui/playlist/addgame.py b/dist/ba_data/python/bastd/ui/playlist/addgame.py index f12f26b..607226d 100644 --- a/dist/ba_data/python/bastd/ui/playlist/addgame.py +++ b/dist/ba_data/python/bastd/ui/playlist/addgame.py @@ -176,7 +176,7 @@ class PlaylistAddGameWindow(ba.Window): def _on_get_more_games_press(self) -> None: from bastd.ui.account import show_sign_in_prompt from bastd.ui.store.browser import StoreBrowserWindow - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return StoreBrowserWindow(modal=True, diff --git a/dist/ba_data/python/bastd/ui/playlist/browser.py b/dist/ba_data/python/bastd/ui/playlist/browser.py index 7646b3f..7ca0b33 100644 --- a/dist/ba_data/python/bastd/ui/playlist/browser.py +++ b/dist/ba_data/python/bastd/ui/playlist/browser.py @@ -140,7 +140,7 @@ class PlaylistBrowserWindow(ba.Window): def _ensure_standard_playlists_exist(self) -> None: # On new installations, go ahead and create a few playlists # besides the hard-coded default one: - if not _ba.get_account_misc_val('madeStandardPlaylists', False): + if not _ba.get_v1_account_misc_val('madeStandardPlaylists', False): _ba.add_transaction({ 'type': 'ADD_PLAYLIST', diff --git a/dist/ba_data/python/bastd/ui/playlist/customizebrowser.py b/dist/ba_data/python/bastd/ui/playlist/customizebrowser.py index 917e65e..e802521 100644 --- a/dist/ba_data/python/bastd/ui/playlist/customizebrowser.py +++ b/dist/ba_data/python/bastd/ui/playlist/customizebrowser.py @@ -253,7 +253,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): self._update() def _update(self) -> None: - have = ba.app.accounts.have_pro_options() + have = ba.app.accounts_v1.have_pro_options() for lock in self._lock_images: ba.imagewidget(edit=lock, opacity=0.0 if have else 1.0) @@ -383,7 +383,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.playlist.editcontroller import PlaylistEditController from bastd.ui.purchase import PurchaseWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return @@ -407,7 +407,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.playlist.editcontroller import PlaylistEditController from bastd.ui.purchase import PurchaseWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return if self._selected_playlist_name is None: @@ -445,7 +445,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): from bastd.ui.playlist import share # Gotta be signed in for this to work. - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': ba.screenmessage(ba.Lstr(resource='notSignedInErrorText'), color=(1, 0, 0)) ba.playsound(ba.getsound('error')) @@ -472,12 +472,12 @@ class PlaylistCustomizeBrowserWindow(ba.Window): def _share_playlist(self) -> None: # pylint: disable=cyclic-import from bastd.ui.purchase import PurchaseWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return # Gotta be signed in for this to work. - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': ba.screenmessage(ba.Lstr(resource='notSignedInErrorText'), color=(1, 0, 0)) ba.playsound(ba.getsound('error')) @@ -508,7 +508,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.purchase import PurchaseWindow from bastd.ui.confirm import ConfirmWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return @@ -534,7 +534,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): # pylint: disable=too-many-branches # pylint: disable=cyclic-import from bastd.ui.purchase import PurchaseWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return if self._selected_playlist_name is None: diff --git a/dist/ba_data/python/bastd/ui/playlist/mapselect.py b/dist/ba_data/python/bastd/ui/playlist/mapselect.py index fc79ce7..2464e0f 100644 --- a/dist/ba_data/python/bastd/ui/playlist/mapselect.py +++ b/dist/ba_data/python/bastd/ui/playlist/mapselect.py @@ -210,7 +210,7 @@ class PlaylistMapSelectWindow(ba.Window): def _on_store_press(self) -> None: from bastd.ui import account from bastd.ui.store.browser import StoreBrowserWindow - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': account.show_sign_in_prompt() return StoreBrowserWindow(modal=True, diff --git a/dist/ba_data/python/bastd/ui/playoptions.py b/dist/ba_data/python/bastd/ui/playoptions.py index e4b16d5..2d98d5d 100644 --- a/dist/ba_data/python/bastd/ui/playoptions.py +++ b/dist/ba_data/python/bastd/ui/playoptions.py @@ -250,7 +250,7 @@ class PlayOptionsWindow(popup.PopupWindow): autoselect=True, textcolor=(0.8, 0.8, 0.8), label=ba.Lstr(resource='teamNamesColorText')) - if not ba.app.accounts.have_pro(): + if not ba.app.accounts_v1.have_pro(): ba.imagewidget( parent=self.root_widget, size=(30, 30), @@ -348,8 +348,8 @@ class PlayOptionsWindow(popup.PopupWindow): from bastd.ui.account import show_sign_in_prompt from bastd.ui.teamnamescolors import TeamNamesColorsWindow from bastd.ui.purchase import PurchaseWindow - if not ba.app.accounts.have_pro(): - if _ba.get_account_state() != 'signed_in': + if not ba.app.accounts_v1.have_pro(): + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() else: PurchaseWindow(items=['pro']) diff --git a/dist/ba_data/python/bastd/ui/popup.py b/dist/ba_data/python/bastd/ui/popup.py index d89374b..8a50f8f 100644 --- a/dist/ba_data/python/bastd/ui/popup.py +++ b/dist/ba_data/python/bastd/ui/popup.py @@ -15,7 +15,9 @@ if TYPE_CHECKING: class PopupWindow: - """A transient window that positions and scales itself for visibility.""" + """A transient window that positions and scales itself for visibility. + + Category: UI Classes""" def __init__(self, position: tuple[float, float], diff --git a/dist/ba_data/python/bastd/ui/profile/browser.py b/dist/ba_data/python/bastd/ui/profile/browser.py index 8d0ac7e..e9aef0b 100644 --- a/dist/ba_data/python/bastd/ui/profile/browser.py +++ b/dist/ba_data/python/bastd/ui/profile/browser.py @@ -51,7 +51,7 @@ class ProfileBrowserWindow(ba.Window): self._r = 'playerProfilesWindow' # Ensure we've got an account-profile in cases where we're signed in. - ba.app.accounts.ensure_have_account_player_profile() + ba.app.accounts_v1.ensure_have_account_player_profile() top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 @@ -174,9 +174,9 @@ class ProfileBrowserWindow(ba.Window): from bastd.ui.purchase import PurchaseWindow # Limit to a handful profiles if they don't have pro-options. - max_non_pro_profiles = _ba.get_account_misc_read_val('mnpp', 5) + max_non_pro_profiles = _ba.get_v1_account_misc_read_val('mnpp', 5) assert self._profiles is not None - if (not ba.app.accounts.have_pro_options() + if (not ba.app.accounts_v1.have_pro_options() and len(self._profiles) >= max_non_pro_profiles): PurchaseWindow(items=['pro'], header_text=ba.Lstr( @@ -283,8 +283,8 @@ class ProfileBrowserWindow(ba.Window): items.sort(key=lambda x: asserttype(x[0], str).lower()) index = 0 account_name: Optional[str] - if _ba.get_account_state() == 'signed_in': - account_name = _ba.get_account_display_string() + if _ba.get_v1_account_state() == 'signed_in': + account_name = _ba.get_v1_account_display_string() else: account_name = None widget_to_select = None diff --git a/dist/ba_data/python/bastd/ui/profile/edit.py b/dist/ba_data/python/bastd/ui/profile/edit.py index d7df39a..d0df137 100644 --- a/dist/ba_data/python/bastd/ui/profile/edit.py +++ b/dist/ba_data/python/bastd/ui/profile/edit.py @@ -173,8 +173,8 @@ class EditProfileWindow(ba.Window): self._upgrade_button = None if self._is_account_profile: - if _ba.get_account_state() == 'signed_in': - sval = _ba.get_account_display_string() + if _ba.get_v1_account_state() == 'signed_in': + sval = _ba.get_v1_account_display_string() else: sval = '??' ba.textwidget(parent=self._root_widget, @@ -427,7 +427,7 @@ class EditProfileWindow(ba.Window): """Attempt to ugrade the profile to global.""" from bastd.ui import account from bastd.ui.profile import upgrade as pupgrade - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': account.show_sign_in_prompt() return @@ -593,8 +593,8 @@ class EditProfileWindow(ba.Window): return name = self.getname() if name == '__account__': - name = (_ba.get_account_name() - if _ba.get_account_state() == 'signed_in' else '???') + name = (_ba.get_v1_account_name() + if _ba.get_v1_account_state() == 'signed_in' else '???') if len(name) > 10 and not (self._global or self._is_account_profile): ba.textwidget(edit=self._clipped_name_text, text=ba.Lstr(resource='inGameClippedNameText', diff --git a/dist/ba_data/python/bastd/ui/profile/upgrade.py b/dist/ba_data/python/bastd/ui/profile/upgrade.py index 5d2c8f1..0dc86dd 100644 --- a/dist/ba_data/python/bastd/ui/profile/upgrade.py +++ b/dist/ba_data/python/bastd/ui/profile/upgrade.py @@ -126,7 +126,8 @@ class ProfileUpgradeWindow(ba.Window): 'b': ba.app.build_number }, callback=ba.WeakCall(self._profile_check_result)) - self._cost = _ba.get_account_misc_read_val('price.global_profile', 500) + self._cost = _ba.get_v1_account_misc_read_val('price.global_profile', + 500) self._status: Optional[str] = 'waiting' self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), @@ -169,7 +170,7 @@ class ProfileUpgradeWindow(ba.Window): from bastd.ui import getcurrency if self._status is None: # If it appears we don't have enough tickets, offer to buy more. - tickets = _ba.get_account_ticket_count() + tickets = _ba.get_v1_account_ticket_count() if tickets < self._cost: ba.playsound(ba.getsound('error')) getcurrency.show_get_tickets_prompt() @@ -204,7 +205,7 @@ class ProfileUpgradeWindow(ba.Window): def _update(self) -> None: try: - t_str = str(_ba.get_account_ticket_count()) + t_str = str(_ba.get_v1_account_ticket_count()) except Exception: t_str = '?' if self._tickets_text is not None: diff --git a/dist/ba_data/python/bastd/ui/purchase.py b/dist/ba_data/python/bastd/ui/purchase.py index c516b43..c1a28b1 100644 --- a/dist/ba_data/python/bastd/ui/purchase.py +++ b/dist/ba_data/python/bastd/ui/purchase.py @@ -72,7 +72,7 @@ class PurchaseWindow(ba.Window): pyoffs = -15 else: pyoffs = 0 - price = self._price = _ba.get_account_misc_read_val( + price = self._price = _ba.get_v1_account_misc_read_val( 'price.' + str(items[0]), -1) price_str = ba.charstr(ba.SpecialChar.TICKET) + str(price) self._price_text = ba.textwidget(parent=self._root_widget, @@ -118,7 +118,7 @@ class PurchaseWindow(ba.Window): # We go away if we see that our target item is owned. if self._items == ['pro']: - if ba.app.accounts.have_pro(): + if ba.app.accounts_v1.have_pro(): can_die = True else: if _ba.get_purchased(self._items[0]): @@ -134,7 +134,7 @@ class PurchaseWindow(ba.Window): else: ticket_count: Optional[int] try: - ticket_count = _ba.get_account_ticket_count() + ticket_count = _ba.get_v1_account_ticket_count() except Exception: ticket_count = None if ticket_count is not None and ticket_count < self._price: diff --git a/dist/ba_data/python/bastd/ui/settings/advanced.py b/dist/ba_data/python/bastd/ui/settings/advanced.py index 73a1338..f511a7d 100644 --- a/dist/ba_data/python/bastd/ui/settings/advanced.py +++ b/dist/ba_data/python/bastd/ui/settings/advanced.py @@ -149,6 +149,7 @@ class AdvancedSettingsWindow(ba.Window): master_server_get('bsLangGetCompleted', {'b': app.build_number}, callback=ba.WeakCall(self._completed_langs_cb)) + # noinspection PyUnresolvedReferences @staticmethod def _preload_modules() -> None: """Preload modules we use (called in bg thread).""" @@ -338,7 +339,7 @@ class AdvancedSettingsWindow(ba.Window): self._update_lang_status() v -= 40 - lang_inform = _ba.get_account_misc_val('langInform', False) + lang_inform = _ba.get_v1_account_misc_val('langInform', False) self._language_inform_checkbox = cbw = ba.checkboxwidget( parent=self._subcontainer, @@ -549,7 +550,7 @@ class AdvancedSettingsWindow(ba.Window): def _on_friend_promo_code_press(self) -> None: from bastd.ui import appinvite from bastd.ui import account - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': account.show_sign_in_prompt() return appinvite.handle_app_invites_press() @@ -567,7 +568,7 @@ class AdvancedSettingsWindow(ba.Window): from bastd.ui.account import show_sign_in_prompt # We have to be logged in for promo-codes to work. - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return self._save_state() diff --git a/dist/ba_data/python/bastd/ui/settings/allsettings.py b/dist/ba_data/python/bastd/ui/settings/allsettings.py index cf44b21..4c994ac 100644 --- a/dist/ba_data/python/bastd/ui/settings/allsettings.py +++ b/dist/ba_data/python/bastd/ui/settings/allsettings.py @@ -187,6 +187,7 @@ class AllSettingsWindow(ba.Window): draw_controller=avb) self._restore_state() + # noinspection PyUnresolvedReferences @staticmethod def _preload_modules() -> None: """Preload modules we use (called in bg thread).""" diff --git a/dist/ba_data/python/bastd/ui/settings/nettesting.py b/dist/ba_data/python/bastd/ui/settings/nettesting.py index 31dd809..0cfee59 100644 --- a/dist/ba_data/python/bastd/ui/settings/nettesting.py +++ b/dist/ba_data/python/bastd/ui/settings/nettesting.py @@ -192,18 +192,18 @@ def _run_diagnostics(weakwin: weakref.ref[NetTestingWindow]) -> None: _print(f'\nContacting V2 master-server ({baseaddr})...') _print_test_results(lambda: _test_fetch(baseaddr)) - # Get V2 nearby region - with ba.app.net.region_pings_lock: - region_pings = copy.deepcopy(ba.app.net.region_pings) - nearest_region = (None if not region_pings else sorted( - region_pings.items(), key=lambda i: i[1])[0]) + # Get V2 nearby zone + with ba.app.net.zone_pings_lock: + zone_pings = copy.deepcopy(ba.app.net.zone_pings) + nearest_zone = (None if not zone_pings else sorted( + zone_pings.items(), key=lambda i: i[1])[0]) - if nearest_region is not None: - nearstr = f'{nearest_region[0]}: {nearest_region[1]:.0f}ms' + if nearest_zone is not None: + nearstr = f'{nearest_zone[0]}: {nearest_zone[1]:.0f}ms' else: nearstr = '-' - _print(f'\nChecking nearest V2 region ping ({nearstr})...') - _print_test_results(lambda: _test_nearby_region_ping(nearest_region)) + _print(f'\nChecking nearest V2 zone ping ({nearstr})...') + _print_test_results(lambda: _test_nearby_zone_ping(nearest_zone)) if have_error[0]: _print('\nDiagnostics complete. Some diagnostics failed.', @@ -232,7 +232,7 @@ def _dummy_fail() -> None: def _test_v1_transaction() -> None: """Dummy fail test case.""" - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': raise RuntimeError('Not signed in.') starttime = time.monotonic() @@ -284,12 +284,11 @@ def _test_fetch(baseaddr: str) -> None: raise RuntimeError('Got unexpected response data.') -def _test_nearby_region_ping( - nearest_region: Optional[tuple[str, float]]) -> None: - """Try to ping nearest v2 region.""" - if nearest_region is None: - raise RuntimeError('No nearest region.') - if nearest_region[1] > 500: +def _test_nearby_zone_ping(nearest_zone: Optional[tuple[str, float]]) -> None: + """Try to ping nearest v2 zone.""" + if nearest_zone is None: + raise RuntimeError('No nearest zone.') + if nearest_zone[1] > 500: raise RuntimeError('Ping too high.') diff --git a/dist/ba_data/python/bastd/ui/soundtrack/browser.py b/dist/ba_data/python/bastd/ui/soundtrack/browser.py index cc12517..5cf74aa 100644 --- a/dist/ba_data/python/bastd/ui/soundtrack/browser.py +++ b/dist/ba_data/python/bastd/ui/soundtrack/browser.py @@ -211,7 +211,7 @@ class SoundtrackBrowserWindow(ba.Window): on_cancel_call=self._back) def _update(self) -> None: - have = ba.app.accounts.have_pro_options() + have = ba.app.accounts_v1.have_pro_options() for lock in self._lock_images: ba.imagewidget(edit=lock, opacity=0.0 if have else 1.0) @@ -232,7 +232,7 @@ class SoundtrackBrowserWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.purchase import PurchaseWindow from bastd.ui.confirm import ConfirmWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return if self._selected_soundtrack is None: @@ -251,7 +251,7 @@ class SoundtrackBrowserWindow(ba.Window): def _duplicate_soundtrack(self) -> None: # pylint: disable=cyclic-import from bastd.ui.purchase import PurchaseWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return cfg = ba.app.config @@ -322,7 +322,7 @@ class SoundtrackBrowserWindow(ba.Window): def _edit_soundtrack_with_sound(self) -> None: # pylint: disable=cyclic-import from bastd.ui.purchase import PurchaseWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return ba.playsound(ba.getsound('swish')) @@ -332,7 +332,7 @@ class SoundtrackBrowserWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.purchase import PurchaseWindow from bastd.ui.soundtrack.edit import SoundtrackEditWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return if self._selected_soundtrack is None: @@ -434,7 +434,7 @@ class SoundtrackBrowserWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.purchase import PurchaseWindow from bastd.ui.soundtrack.edit import SoundtrackEditWindow - if not ba.app.accounts.have_pro_options(): + if not ba.app.accounts_v1.have_pro_options(): PurchaseWindow(items=['pro']) return self._save_state() diff --git a/dist/ba_data/python/bastd/ui/specialoffer.py b/dist/ba_data/python/bastd/ui/specialoffer.py index 5b2c2ab..0457f4b 100644 --- a/dist/ba_data/python/bastd/ui/specialoffer.py +++ b/dist/ba_data/python/bastd/ui/specialoffer.py @@ -95,7 +95,7 @@ class SpecialOfferWindow(ba.Window): if ('bonusTickets' in offer and offer['bonusTickets'] is not None): self._is_bundle_sale = True - original_price = _ba.get_account_misc_read_val( + original_price = _ba.get_v1_account_misc_read_val( 'price.' + self._offer_item, 9999) # For pure ticket prices we can show a percent-off. @@ -341,7 +341,7 @@ class SpecialOfferWindow(ba.Window): # We go away if we see that our target item is owned. if self._offer_item == 'pro': - if _ba.app.accounts.have_pro(): + if _ba.app.accounts_v1.have_pro(): can_die = True else: if _ba.get_purchased(self._offer_item): @@ -364,9 +364,9 @@ class SpecialOfferWindow(ba.Window): if not self._root_widget: return sval: Union[str, ba.Lstr] - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': sval = (ba.charstr(SpecialChar.TICKET) + - str(_ba.get_account_ticket_count())) + str(_ba.get_v1_account_ticket_count())) else: sval = ba.Lstr(resource='getTicketsWindow.titleText') ba.buttonwidget(edit=self._get_tickets_button, label=sval) @@ -374,7 +374,7 @@ class SpecialOfferWindow(ba.Window): def _on_get_more_tickets_press(self) -> None: from bastd.ui import account from bastd.ui import getcurrency - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': account.show_sign_in_prompt() return getcurrency.GetCurrencyWindow(modal=True).get_root_widget() @@ -393,7 +393,7 @@ class SpecialOfferWindow(ba.Window): else: ticket_count: Optional[int] try: - ticket_count = _ba.get_account_ticket_count() + ticket_count = _ba.get_v1_account_ticket_count() except Exception: ticket_count = None if (ticket_count is not None diff --git a/dist/ba_data/python/bastd/ui/store/browser.py b/dist/ba_data/python/bastd/ui/store/browser.py index 6d757c2..9eb9f57 100644 --- a/dist/ba_data/python/bastd/ui/store/browser.py +++ b/dist/ba_data/python/bastd/ui/store/browser.py @@ -282,7 +282,7 @@ class StoreBrowserWindow(ba.Window): def _restore_purchases(self) -> None: from bastd.ui import account - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': account.show_sign_in_prompt() else: _ba.restore_purchases() @@ -323,9 +323,9 @@ class StoreBrowserWindow(ba.Window): if not self._root_widget: return sval: Union[str, ba.Lstr] - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': sval = ba.charstr(SpecialChar.TICKET) + str( - _ba.get_account_ticket_count()) + _ba.get_v1_account_ticket_count()) else: sval = ba.Lstr(resource='getTicketsWindow.titleText') if self._get_tickets_button: @@ -410,7 +410,7 @@ class StoreBrowserWindow(ba.Window): else: if is_ticket_purchase: if result['allow']: - price = _ba.get_account_misc_read_val( + price = _ba.get_v1_account_misc_read_val( 'price.' + item, None) if (price is None or not isinstance(price, int) or price <= 0): @@ -485,7 +485,7 @@ class StoreBrowserWindow(ba.Window): self._last_buy_time) < 2.0: ba.playsound(ba.getsound('error')) else: - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': account.show_sign_in_prompt() else: self._last_buy_time = curtime @@ -499,9 +499,9 @@ class StoreBrowserWindow(ba.Window): self._do_purchase_check('pro' if get_available_sale_time( 'extras') is None else 'pro_sale') else: - price = _ba.get_account_misc_read_val( + price = _ba.get_v1_account_misc_read_val( 'price.' + item, None) - our_tickets = _ba.get_account_ticket_count() + our_tickets = _ba.get_v1_account_ticket_count() if price is not None and our_tickets < price: ba.playsound(ba.getsound('error')) getcurrency.show_get_tickets_prompt() @@ -540,7 +540,7 @@ class StoreBrowserWindow(ba.Window): if not self._root_widget: return import datetime - sales_raw = _ba.get_account_misc_read_val('sales', {}) + sales_raw = _ba.get_v1_account_misc_read_val('sales', {}) sales = {} try: # Look at the current set of sales; filter any with time remaining. @@ -559,7 +559,7 @@ class StoreBrowserWindow(ba.Window): for b_type, b_info in self.button_infos.items(): if b_type in ['upgrades.pro', 'pro']: - purchased = _ba.app.accounts.have_pro() + purchased = _ba.app.accounts_v1.have_pro() else: purchased = _ba.get_purchased(b_type) @@ -606,14 +606,16 @@ class StoreBrowserWindow(ba.Window): price_text_left = '' price_text_right = '' else: - price = _ba.get_account_misc_read_val('price.' + b_type, 0) + price = _ba.get_v1_account_misc_read_val( + 'price.' + b_type, 0) # Color the button differently if we cant afford this. - if _ba.get_account_state() == 'signed_in': - if _ba.get_account_ticket_count() < price: + if _ba.get_v1_account_state() == 'signed_in': + if _ba.get_v1_account_ticket_count() < price: color = (0.6, 0.61, 0.6) price_text = ba.charstr(ba.SpecialChar.TICKET) + str( - _ba.get_account_misc_read_val('price.' + b_type, '?')) + _ba.get_v1_account_misc_read_val( + 'price.' + b_type, '?')) price_text_left = '' price_text_right = '' @@ -1062,7 +1064,7 @@ class StoreBrowserWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.account import show_sign_in_prompt from bastd.ui.getcurrency import GetCurrencyWindow - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return self._save_state() diff --git a/dist/ba_data/python/bastd/ui/store/button.py b/dist/ba_data/python/bastd/ui/store/button.py index 5aec050..3492563 100644 --- a/dist/ba_data/python/bastd/ui/store/button.py +++ b/dist/ba_data/python/bastd/ui/store/button.py @@ -197,7 +197,7 @@ class StoreButton: # pylint: disable=cyclic-import from bastd.ui.account import show_sign_in_prompt from bastd.ui.store.browser import StoreBrowserWindow - if _ba.get_account_state() != 'signed_in': + if _ba.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return StoreBrowserWindow(modal=True, origin_widget=self._button) @@ -216,9 +216,9 @@ class StoreButton: return # Our instance may outlive our UI objects. if self._ticket_text is not None: - if _ba.get_account_state() == 'signed_in': + if _ba.get_v1_account_state() == 'signed_in': sval = ba.charstr(SpecialChar.TICKET) + str( - _ba.get_account_ticket_count()) + _ba.get_v1_account_ticket_count()) else: sval = '-' ba.textwidget(edit=self._ticket_text, text=sval) @@ -230,7 +230,7 @@ class StoreButton: # ..also look for new style sales. if sale_time is None: import datetime - sales_raw = _ba.get_account_misc_read_val('sales', {}) + sales_raw = _ba.get_v1_account_misc_read_val('sales', {}) sale_times = [] try: # Look at the current set of sales; filter any with time diff --git a/dist/ba_data/python/bastd/ui/store/item.py b/dist/ba_data/python/bastd/ui/store/item.py index ea49ded..f7e6198 100644 --- a/dist/ba_data/python/bastd/ui/store/item.py +++ b/dist/ba_data/python/bastd/ui/store/item.py @@ -202,7 +202,7 @@ def instantiate_store_item_display(item_name: str, color=(1, 1, 1), texture=ba.gettexture('ticketsMore'))) bonus_tickets = str( - _ba.get_account_misc_read_val('proBonusTickets', 100)) + _ba.get_v1_account_misc_read_val('proBonusTickets', 100)) extra_texts.append( ba.textwidget(parent=parent_widget, draw_controller=btn, @@ -270,8 +270,8 @@ def instantiate_store_item_display(item_name: str, # If we have a 'total-worth' item-id for this id, show that price so # the user knows how much this is worth. - total_worth_item = _ba.get_account_misc_read_val('twrths', - {}).get(item_name) + total_worth_item = _ba.get_v1_account_misc_read_val('twrths', + {}).get(item_name) total_worth_price: Optional[str] if total_worth_item is not None: price = _ba.get_price(total_worth_item) diff --git a/dist/ba_data/python/bastd/ui/tournamententry.py b/dist/ba_data/python/bastd/ui/tournamententry.py index 1737387..7419c4c 100644 --- a/dist/ba_data/python/bastd/ui/tournamententry.py +++ b/dist/ba_data/python/bastd/ui/tournamententry.py @@ -33,7 +33,7 @@ class TournamentEntryWindow(popup.PopupWindow): self._tournament_id = tournament_id self._tournament_info = ( - ba.app.accounts.tournament_info[self._tournament_id]) + ba.app.accounts_v1.tournament_info[self._tournament_id]) # Set a few vars depending on the tourney fee. self._fee = self._tournament_info['fee'] @@ -274,13 +274,14 @@ class TournamentEntryWindow(popup.PopupWindow): # If there seems to be a relatively-recent valid cached info for this # tournament, use it. Otherwise we'll kick off a query ourselves. - if (self._tournament_id in ba.app.accounts.tournament_info and - ba.app.accounts.tournament_info[self._tournament_id]['valid'] + if (self._tournament_id in ba.app.accounts_v1.tournament_info + and ba.app.accounts_v1.tournament_info[ + self._tournament_id]['valid'] and (ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS) - - ba.app.accounts.tournament_info[self._tournament_id] + ba.app.accounts_v1.tournament_info[self._tournament_id] ['timeReceived'] < 1000 * 60 * 5)): try: - info = ba.app.accounts.tournament_info[self._tournament_id] + info = ba.app.accounts_v1.tournament_info[self._tournament_id] self._seconds_remaining = max( 0, info['timeRemaining'] - int( (ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS) @@ -304,7 +305,7 @@ class TournamentEntryWindow(popup.PopupWindow): def _on_tournament_query_response(self, data: Optional[dict[str, Any]]) -> None: - accounts = ba.app.accounts + accounts = ba.app.accounts_v1 self._running_query = False if data is not None: data = data['t'] # This used to be the whole payload. @@ -358,7 +359,7 @@ class TournamentEntryWindow(popup.PopupWindow): self._running_query = True # Grab the latest info on our tourney. - self._tournament_info = ba.app.accounts.tournament_info[ + self._tournament_info = ba.app.accounts_v1.tournament_info[ self._tournament_id] # If we don't have valid data always show a '-' for time. @@ -374,7 +375,7 @@ class TournamentEntryWindow(popup.PopupWindow): timeformat=ba.TimeFormat.MILLISECONDS)) # Keep price up-to-date and update the button with it. - self._purchase_price = _ba.get_account_misc_read_val( + self._purchase_price = _ba.get_v1_account_misc_read_val( self._purchase_price_name, None) ba.textwidget( @@ -422,7 +423,7 @@ class TournamentEntryWindow(popup.PopupWindow): color=(0, 0.8, 0) if enabled else (0.4, 0.4, 0.4)) try: - t_str = str(_ba.get_account_ticket_count()) + t_str = str(_ba.get_v1_account_ticket_count()) except Exception: t_str = '?' if self._get_tickets_button: @@ -512,7 +513,7 @@ class TournamentEntryWindow(popup.PopupWindow): # Deny if we don't have enough tickets. ticket_count: Optional[int] try: - ticket_count = _ba.get_account_ticket_count() + ticket_count = _ba.get_v1_account_ticket_count() except Exception: # FIXME: should add a ba.NotSignedInError we can use here. ticket_count = None diff --git a/dist/ba_data/python/efro/dataclassio/__init__.py b/dist/ba_data/python/efro/dataclassio/__init__.py index ac9e6c2..f88be16 100644 --- a/dist/ba_data/python/efro/dataclassio/__init__.py +++ b/dist/ba_data/python/efro/dataclassio/__init__.py @@ -10,152 +10,22 @@ data formats in a nondestructive manner. from __future__ import annotations -from enum import Enum -from typing import TYPE_CHECKING, TypeVar - -from efro.dataclassio._outputter import _Outputter -from efro.dataclassio._inputter import _Inputter -from efro.dataclassio._base import Codec, IOAttrs, IOExtendedData +from efro.util import set_canonical_module +from efro.dataclassio._base import (Codec, IOAttrs, IOExtendedData) from efro.dataclassio._prep import (ioprep, ioprepped, will_ioprep, is_ioprepped_dataclass) from efro.dataclassio._pathcapture import DataclassFieldLookup - -if TYPE_CHECKING: - from typing import Any, Optional +from efro.dataclassio._api import (JsonStyle, dataclass_to_dict, + dataclass_to_json, dataclass_from_dict, + dataclass_from_json, dataclass_validate) __all__ = [ - 'Codec', 'IOAttrs', 'IOExtendedData', 'ioprep', 'ioprepped', 'will_ioprep', - 'is_ioprepped_dataclass', 'DataclassFieldLookup', 'dataclass_to_dict', - 'dataclass_to_json', 'dataclass_from_dict', 'dataclass_from_json', - 'dataclass_validate' + 'JsonStyle', 'Codec', 'IOAttrs', 'IOExtendedData', 'ioprep', 'ioprepped', + 'will_ioprep', 'is_ioprepped_dataclass', 'DataclassFieldLookup', + 'dataclass_to_dict', 'dataclass_to_json', 'dataclass_from_dict', + 'dataclass_from_json', 'dataclass_validate' ] -T = TypeVar('T') - - -class JsonStyle(Enum): - """Different style types for json.""" - - # Single line, no spaces, no sorting. Not deterministic. - # Use this for most storage purposes. - FAST = 'fast' - - # Single line, no spaces, sorted keys. Deterministic. - # Use this when output may be hashed or compared for equality. - SORTED = 'sorted' - - # Multiple lines, spaces, sorted keys. Deterministic. - # Use this for pretty human readable output. - PRETTY = 'pretty' - - -def dataclass_to_dict(obj: Any, - codec: Codec = Codec.JSON, - coerce_to_float: bool = True) -> dict: - """Given a dataclass object, return a json-friendly dict. - - All values will be checked to ensure they match the types specified - on fields. Note that a limited set of types and data configurations is - supported. - - Values with type Any will be checked to ensure they match types supported - directly by json. This does not include types such as tuples which are - implicitly translated by Python's json module (as this would break - the ability to do a lossless round-trip with data). - - If coerce_to_float is True, integer values present on float typed fields - will be converted to float in the dict output. If False, a TypeError - will be triggered. - """ - - out = _Outputter(obj, - create=True, - codec=codec, - coerce_to_float=coerce_to_float).run() - assert isinstance(out, dict) - return out - - -def dataclass_to_json(obj: Any, - coerce_to_float: bool = True, - pretty: bool = False, - sort_keys: Optional[bool] = None) -> str: - """Utility function; return a json string from a dataclass instance. - - Basically json.dumps(dataclass_to_dict(...)). - By default, keys are sorted for pretty output and not otherwise, but - this can be overridden by supplying a value for the 'sort_keys' arg. - """ - import json - jdict = dataclass_to_dict(obj=obj, - coerce_to_float=coerce_to_float, - codec=Codec.JSON) - if sort_keys is None: - sort_keys = pretty - if pretty: - return json.dumps(jdict, indent=2, sort_keys=sort_keys) - return json.dumps(jdict, separators=(',', ':'), sort_keys=sort_keys) - - -def dataclass_from_dict(cls: type[T], - values: dict, - codec: Codec = Codec.JSON, - coerce_to_float: bool = True, - allow_unknown_attrs: bool = True, - discard_unknown_attrs: bool = False) -> T: - """Given a dict, return a dataclass of a given type. - - The dict must be formatted to match the specified codec (generally - json-friendly object types). This means that sequence values such as - tuples or sets should be passed as lists, enums should be passed as their - associated values, nested dataclasses should be passed as dicts, etc. - - All values are checked to ensure their types/values are valid. - - Data for attributes of type Any will be checked to ensure they match - types supported directly by json. This does not include types such - as tuples which are implicitly translated by Python's json module - (as this would break the ability to do a lossless round-trip with data). - - If coerce_to_float is True, int values passed for float typed fields - will be converted to float values. Otherwise, a TypeError is raised. - - If allow_unknown_attrs is False, AttributeErrors will be raised for - attributes present in the dict but not on the data class. Otherwise, they - will be preserved as part of the instance and included if it is - exported back to a dict, unless discard_unknown_attrs is True, in which - case they will simply be discarded. - """ - return _Inputter(cls, - codec=codec, - coerce_to_float=coerce_to_float, - allow_unknown_attrs=allow_unknown_attrs, - discard_unknown_attrs=discard_unknown_attrs).run(values) - - -def dataclass_from_json(cls: type[T], - json_str: str, - coerce_to_float: bool = True, - allow_unknown_attrs: bool = True, - discard_unknown_attrs: bool = False) -> T: - """Utility function; return a dataclass instance given a json string. - - Basically dataclass_from_dict(json.loads(...)) - """ - import json - return dataclass_from_dict(cls=cls, - values=json.loads(json_str), - coerce_to_float=coerce_to_float, - allow_unknown_attrs=allow_unknown_attrs, - discard_unknown_attrs=discard_unknown_attrs) - - -def dataclass_validate(obj: Any, - coerce_to_float: bool = True, - codec: Codec = Codec.JSON) -> None: - """Ensure that values in a dataclass instance are the correct types.""" - - # Simply run an output pass but tell it not to generate data; - # only run validation. - _Outputter(obj, create=False, codec=codec, - coerce_to_float=coerce_to_float).run() +# Have these things present themselves cleanly as 'thismodule.SomeClass' +# instead of 'thismodule._internalmodule.SomeClass' +set_canonical_module(module_globals=globals(), names=__all__) diff --git a/dist/ba_data/python/efro/dataclassio/_api.py b/dist/ba_data/python/efro/dataclassio/_api.py new file mode 100644 index 0000000..9c0597b --- /dev/null +++ b/dist/ba_data/python/efro/dataclassio/_api.py @@ -0,0 +1,151 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality for importing, exporting, and validating dataclasses. + +This allows complex nested dataclasses to be flattened to json-compatible +data and restored from said data. It also gracefully handles and preserves +unrecognized attribute data, allowing older clients to interact with newer +data formats in a nondestructive manner. +""" + +from __future__ import annotations + +from enum import Enum +from typing import TYPE_CHECKING, TypeVar + +from efro.dataclassio._outputter import _Outputter +from efro.dataclassio._inputter import _Inputter +from efro.dataclassio._base import Codec + +if TYPE_CHECKING: + from typing import Any, Optional + +T = TypeVar('T') + + +class JsonStyle(Enum): + """Different style types for json.""" + + # Single line, no spaces, no sorting. Not deterministic. + # Use this for most storage purposes. + FAST = 'fast' + + # Single line, no spaces, sorted keys. Deterministic. + # Use this when output may be hashed or compared for equality. + SORTED = 'sorted' + + # Multiple lines, spaces, sorted keys. Deterministic. + # Use this for pretty human readable output. + PRETTY = 'pretty' + + +def dataclass_to_dict(obj: Any, + codec: Codec = Codec.JSON, + coerce_to_float: bool = True) -> dict: + """Given a dataclass object, return a json-friendly dict. + + All values will be checked to ensure they match the types specified + on fields. Note that a limited set of types and data configurations is + supported. + + Values with type Any will be checked to ensure they match types supported + directly by json. This does not include types such as tuples which are + implicitly translated by Python's json module (as this would break + the ability to do a lossless round-trip with data). + + If coerce_to_float is True, integer values present on float typed fields + will be converted to float in the dict output. If False, a TypeError + will be triggered. + """ + + out = _Outputter(obj, + create=True, + codec=codec, + coerce_to_float=coerce_to_float).run() + assert isinstance(out, dict) + return out + + +def dataclass_to_json(obj: Any, + coerce_to_float: bool = True, + pretty: bool = False, + sort_keys: Optional[bool] = None) -> str: + """Utility function; return a json string from a dataclass instance. + + Basically json.dumps(dataclass_to_dict(...)). + By default, keys are sorted for pretty output and not otherwise, but + this can be overridden by supplying a value for the 'sort_keys' arg. + """ + import json + jdict = dataclass_to_dict(obj=obj, + coerce_to_float=coerce_to_float, + codec=Codec.JSON) + if sort_keys is None: + sort_keys = pretty + if pretty: + return json.dumps(jdict, indent=2, sort_keys=sort_keys) + return json.dumps(jdict, separators=(',', ':'), sort_keys=sort_keys) + + +def dataclass_from_dict(cls: type[T], + values: dict, + codec: Codec = Codec.JSON, + coerce_to_float: bool = True, + allow_unknown_attrs: bool = True, + discard_unknown_attrs: bool = False) -> T: + """Given a dict, return a dataclass of a given type. + + The dict must be formatted to match the specified codec (generally + json-friendly object types). This means that sequence values such as + tuples or sets should be passed as lists, enums should be passed as their + associated values, nested dataclasses should be passed as dicts, etc. + + All values are checked to ensure their types/values are valid. + + Data for attributes of type Any will be checked to ensure they match + types supported directly by json. This does not include types such + as tuples which are implicitly translated by Python's json module + (as this would break the ability to do a lossless round-trip with data). + + If coerce_to_float is True, int values passed for float typed fields + will be converted to float values. Otherwise, a TypeError is raised. + + If allow_unknown_attrs is False, AttributeErrors will be raised for + attributes present in the dict but not on the data class. Otherwise, they + will be preserved as part of the instance and included if it is + exported back to a dict, unless discard_unknown_attrs is True, in which + case they will simply be discarded. + """ + return _Inputter(cls, + codec=codec, + coerce_to_float=coerce_to_float, + allow_unknown_attrs=allow_unknown_attrs, + discard_unknown_attrs=discard_unknown_attrs).run(values) + + +def dataclass_from_json(cls: type[T], + json_str: str, + coerce_to_float: bool = True, + allow_unknown_attrs: bool = True, + discard_unknown_attrs: bool = False) -> T: + """Utility function; return a dataclass instance given a json string. + + Basically dataclass_from_dict(json.loads(...)) + """ + import json + return dataclass_from_dict(cls=cls, + values=json.loads(json_str), + coerce_to_float=coerce_to_float, + allow_unknown_attrs=allow_unknown_attrs, + discard_unknown_attrs=discard_unknown_attrs) + + +def dataclass_validate(obj: Any, + coerce_to_float: bool = True, + codec: Codec = Codec.JSON) -> None: + """Ensure that values in a dataclass instance are the correct types.""" + + # Simply run an output pass but tell it not to generate data; + # only run validation. + _Outputter(obj, create=False, codec=codec, + coerce_to_float=coerce_to_float).run() diff --git a/dist/ba_data/python/efro/dataclassio/_base.py b/dist/ba_data/python/efro/dataclassio/_base.py index 1353c36..0d0a8a9 100644 --- a/dist/ba_data/python/efro/dataclassio/_base.py +++ b/dist/ba_data/python/efro/dataclassio/_base.py @@ -13,7 +13,7 @@ from typing import TYPE_CHECKING, get_args from typing import _AnnotatedAlias # type: ignore if TYPE_CHECKING: - from typing import Any, Optional + from typing import Any, Optional, Callable, Union # Types which we can pass through as-is. SIMPLE_TYPES = {int, bool, str, float, type(None)} @@ -96,18 +96,54 @@ def _is_valid_for_codec(obj: Any, codec: Codec) -> bool: class IOAttrs: - """For specifying io behavior in annotations.""" + """For specifying io behavior in annotations. + + 'storagename', if passed, is the name used when storing to json/etc. + 'store_default' can be set to False to avoid writing values when equal + to the default value. Note that this requires the dataclass field + to define a default or default_factory or for its IOAttrs to + define a soft_default value. + 'whole_days', if True, requires datetime values to be exactly on day + boundaries (see efro.util.utc_today()). + 'whole_hours', if True, requires datetime values to lie exactly on hour + boundaries (see efro.util.utc_this_hour()). + 'soft_default', if passed, injects a default value into dataclass + instantiation when the field is not present in the input data. + This allows dataclasses to add new non-optional fields while + gracefully 'upgrading' old data. Note that when a soft_default is + present it will take precedence over field defaults when determining + whether to store a value for a field with store_default=False + (since the soft_default value is what we'll get when reading that + same data back in when the field is omitted). + 'soft_default_factory' is similar to 'default_factory' in dataclass + fields; it should be used instead of 'soft_default' for mutable types + such as lists to prevent a single default object from unintentionally + changing over time. + """ + + # A sentinel object to detect if a parameter is supplied or not. Use + # a class to give it a better repr. + class _MissingType: + pass + + MISSING = _MissingType() storagename: Optional[str] = None store_default: bool = True whole_days: bool = False whole_hours: bool = False + soft_default: Any = MISSING + soft_default_factory: Union[Callable[[], Any], _MissingType] = MISSING - def __init__(self, - storagename: Optional[str] = storagename, - store_default: bool = store_default, - whole_days: bool = whole_days, - whole_hours: bool = whole_hours): + def __init__( + self, + storagename: Optional[str] = storagename, + store_default: bool = store_default, + whole_days: bool = whole_days, + whole_hours: bool = whole_hours, + soft_default: Any = MISSING, + soft_default_factory: Union[Callable[[], Any], _MissingType] = MISSING, + ): # Only store values that differ from class defaults to keep # our instances nice and lean. @@ -120,18 +156,37 @@ class IOAttrs: self.whole_days = whole_days if whole_hours != cls.whole_hours: self.whole_hours = whole_hours + if soft_default is not cls.soft_default: + + # Do what dataclasses does with its default types and + # tell the user to use factory for mutable ones. + if isinstance(soft_default, (list, dict, set)): + raise ValueError( + f'mutable {type(soft_default)} is not allowed' + f' for soft_default; use soft_default_factory.') + self.soft_default = soft_default + if soft_default_factory is not cls.soft_default_factory: + self.soft_default_factory = soft_default_factory + if self.soft_default is not cls.soft_default: + raise ValueError('Cannot set both soft_default' + ' and soft_default_factory') def validate_for_field(self, cls: type, field: dataclasses.Field) -> None: """Ensure the IOAttrs instance is ok to use with the provided field.""" # Turning off store_default requires the field to have either - # a default_factory or a default + # a default or a a default_factory or for us to have soft equivalents. + if not self.store_default: - default_factory: Any = field.default_factory - if (default_factory is dataclasses.MISSING - and field.default is dataclasses.MISSING): + field_default_factory: Any = field.default_factory + if (field_default_factory is dataclasses.MISSING + and field.default is dataclasses.MISSING + and self.soft_default is self.MISSING + and self.soft_default_factory is self.MISSING): raise TypeError(f'Field {field.name} of {cls} has' - f' neither a default nor a default_factory;' + f' neither a default nor a default_factory' + f' and IOAttrs contains neither a soft_default' + f' nor a soft_default_factory;' f' store_default=False cannot be set for it.') def validate_datetime(self, value: datetime.datetime, diff --git a/dist/ba_data/python/efro/dataclassio/_inputter.py b/dist/ba_data/python/efro/dataclassio/_inputter.py index 274e168..34c1e5f 100644 --- a/dist/ba_data/python/efro/dataclassio/_inputter.py +++ b/dist/ba_data/python/efro/dataclassio/_inputter.py @@ -11,6 +11,7 @@ from __future__ import annotations from enum import Enum import dataclasses import typing +import types import datetime from typing import TYPE_CHECKING, Generic, TypeVar @@ -23,7 +24,9 @@ from efro.dataclassio._prep import PrepSession if TYPE_CHECKING: from typing import Any, Optional + from efro.dataclassio._base import IOAttrs + from efro.dataclassio._outputter import _Outputter T = TypeVar('T') @@ -41,6 +44,7 @@ class _Inputter(Generic[T]): self._coerce_to_float = coerce_to_float self._allow_unknown_attrs = allow_unknown_attrs self._discard_unknown_attrs = discard_unknown_attrs + self._soft_default_validator: Optional[_Outputter] = None if not allow_unknown_attrs and discard_unknown_attrs: raise ValueError('discard_unknown_attrs cannot be True' @@ -75,7 +79,7 @@ class _Inputter(Generic[T]): f' \'{type(value).__name__}\' which is not.') return value - if origin is typing.Union: + if origin is typing.Union or origin is types.UnionType: # Currently, the only unions we support are None/Value # (translated from Optional), which we verified on prep. # So let's treat this as a simple optional case. @@ -158,6 +162,7 @@ class _Inputter(Generic[T]): associated values, and nested dataclasses should be passed as dicts. """ # pylint: disable=too-many-locals + # pylint: disable=too-many-branches if not isinstance(values, dict): raise TypeError( f'Expected a dict for {fieldpath} on {cls.__name__};' @@ -172,6 +177,16 @@ class _Inputter(Generic[T]): # noinspection PyDataclass fields = dataclasses.fields(cls) fields_by_name = {f.name: f for f in fields} + + # Preprocess all fields to convert Annotated[] to contained types + # and IOAttrs. + parsed_field_annotations = { + f.name: _parse_annotated(prep.annotations[f.name]) + for f in fields + } + + # Go through all data in the input, converting it to either dataclass + # args or extra data. args: dict[str, Any] = {} for rawkey, value in values.items(): key = prep.storage_names_to_attr_names.get(rawkey, rawkey) @@ -197,22 +212,63 @@ class _Inputter(Generic[T]): f"'{cls.__name__}' has no '{key}' field.") else: fieldname = field.name - anntype = prep.annotations[fieldname] - anntype, ioattrs = _parse_annotated(anntype) - + anntype, ioattrs = parsed_field_annotations[fieldname] subfieldpath = (f'{fieldpath}.{fieldname}' if fieldpath else fieldname) args[key] = self._value_from_input(cls, subfieldpath, anntype, value, ioattrs) + + # Go through all fields looking for any not yet present in our data. + # If we find any such fields with a soft-default value or factory + # defined, inject that soft value into our args. + for key, aparsed in parsed_field_annotations.items(): + if key in args: + continue + ioattrs = aparsed[1] + if (ioattrs is not None and + (ioattrs.soft_default is not ioattrs.MISSING + or ioattrs.soft_default_factory is not ioattrs.MISSING)): + if ioattrs.soft_default is not ioattrs.MISSING: + soft_default = ioattrs.soft_default + else: + assert callable(ioattrs.soft_default_factory) + soft_default = ioattrs.soft_default_factory() + args[key] = soft_default + + # Make sure these values are valid since we didn't run + # them through our normal input type checking. + + self._type_check_soft_default( + value=soft_default, + anntype=aparsed[0], + fieldpath=(f'{fieldpath}.{key}' if fieldpath else key)) + try: out = cls(**args) except Exception as exc: - raise RuntimeError(f'Error instantiating class {cls.__name__}' - f' at {fieldpath}: {exc}') from exc + raise ValueError(f'Error instantiating class {cls.__name__}' + f' at {fieldpath}: {exc}') from exc if extra_attrs: setattr(out, EXTRA_ATTRS_ATTR, extra_attrs) return out + def _type_check_soft_default(self, value: Any, anntype: Any, + fieldpath: str) -> None: + from efro.dataclassio._outputter import _Outputter + + # Counter-intuitively, we create an outputter as part of + # our inputter. Soft-default values are already internal types; + # we need to make sure they can go out from there. + if self._soft_default_validator is None: + self._soft_default_validator = _Outputter( + obj=None, + create=False, + codec=self._codec, + coerce_to_float=self._coerce_to_float) + self._soft_default_validator.soft_default_check(value=value, + anntype=anntype, + fieldpath=fieldpath) + def _dict_from_input(self, cls: type, fieldpath: str, anntype: Any, value: Any, ioattrs: Optional[IOAttrs]) -> Any: # pylint: disable=too-many-branches diff --git a/dist/ba_data/python/efro/dataclassio/_outputter.py b/dist/ba_data/python/efro/dataclassio/_outputter.py index 746223d..e268d7d 100644 --- a/dist/ba_data/python/efro/dataclassio/_outputter.py +++ b/dist/ba_data/python/efro/dataclassio/_outputter.py @@ -11,6 +11,7 @@ from __future__ import annotations from enum import Enum import dataclasses import typing +import types import datetime from typing import TYPE_CHECKING @@ -39,12 +40,23 @@ class _Outputter: def run(self) -> Any: """Do the thing.""" + assert dataclasses.is_dataclass(self._obj) + # For special extended data types, call their 'will_output' callback. if isinstance(self._obj, IOExtendedData): self._obj.will_output() return self._process_dataclass(type(self._obj), self._obj, '') + def soft_default_check(self, value: Any, anntype: Any, + fieldpath: str) -> None: + """(internal)""" + self._process_value(type(value), + fieldpath=fieldpath, + anntype=anntype, + value=value, + ioattrs=None) + def _process_dataclass(self, cls: type, obj: Any, fieldpath: str) -> Any: # pylint: disable=too-many-locals # pylint: disable=too-many-branches @@ -67,19 +79,30 @@ class _Outputter: # If we're not storing default values for this fella, # we can skip all output processing if we've got a default value. if ioattrs is not None and not ioattrs.store_default: + # If both soft_defaults and regular field defaults + # are present we want to go with soft_defaults since + # those same values would be re-injected when reading + # the same data back in if we've omitted the field. default_factory: Any = field.default_factory - if default_factory is not dataclasses.MISSING: - if default_factory() == value: + if ioattrs.soft_default is not ioattrs.MISSING: + if ioattrs.soft_default == value: + continue + elif ioattrs.soft_default_factory is not ioattrs.MISSING: + assert callable(ioattrs.soft_default_factory) + if ioattrs.soft_default_factory() == value: continue elif field.default is not dataclasses.MISSING: if field.default == value: continue + elif default_factory is not dataclasses.MISSING: + if default_factory() == value: + continue else: raise RuntimeError( f'Field {fieldname} of {cls.__name__} has' - f' neither a default nor a default_factory;' - f' store_default=False cannot be set for it.' - f' (AND THIS SHOULD HAVE BEEN CAUGHT IN PREP!)') + f' no source of default values; store_default=False' + f' cannot be set for it. (AND THIS SHOULD HAVE BEEN' + f' CAUGHT IN PREP!)') outvalue = self._process_value(cls, subfieldpath, anntype, value, ioattrs) @@ -119,7 +142,7 @@ class _Outputter: f' found \'{type(value).__name__}\' which is not.') return value if self._create else None - if origin is typing.Union: + if origin is typing.Union or origin is types.UnionType: # Currently, the only unions we support are None/Value # (translated from Optional), which we verified on prep. # So let's treat this as a simple optional case. diff --git a/dist/ba_data/python/efro/dataclassio/_prep.py b/dist/ba_data/python/efro/dataclassio/_prep.py index 57785b1..c6fd503 100644 --- a/dist/ba_data/python/efro/dataclassio/_prep.py +++ b/dist/ba_data/python/efro/dataclassio/_prep.py @@ -12,14 +12,17 @@ import logging from enum import Enum import dataclasses import typing +import types import datetime from typing import TYPE_CHECKING, TypeVar, get_type_hints # noinspection PyProtectedMember -from efro.dataclassio._base import _parse_annotated, _get_origin, SIMPLE_TYPES +from efro.dataclassio._base import (_parse_annotated, _get_origin, + SIMPLE_TYPES) if TYPE_CHECKING: from typing import Any, Optional + from efro.dataclassio._base import IOAttrs T = TypeVar('T') @@ -214,6 +217,7 @@ class PrepSession: self.prep_type(cls, attrname, anntype, + ioattrs=ioattrs, recursion_level=recursion_level + 1) # Success! Store our resolved stuff with the class and we're done. @@ -228,19 +232,18 @@ class PrepSession: return prepdata def prep_type(self, cls: type, attrname: str, anntype: Any, - recursion_level: int) -> None: + ioattrs: Optional[IOAttrs], recursion_level: int) -> None: """Run prep on a dataclass.""" # pylint: disable=too-many-return-statements # pylint: disable=too-many-branches + # pylint: disable=too-many-statements - # If we run into classes containing themselves, we may have - # to do something smarter to handle it. if recursion_level > MAX_RECURSION: raise RuntimeError('Max recursion exceeded.') origin = _get_origin(anntype) - if origin is typing.Union: + if origin is typing.Union or origin is types.UnionType: self.prep_union(cls, attrname, anntype, @@ -257,6 +260,32 @@ class PrepSession: f'Unsupported type found for \'{attrname}\' on {cls}:' f' {anntype}') + # If a soft_default value/factory was passed, we do some basic + # type checking on the top-level value here. We also run full + # recursive validation on values later during inputting, but this + # should catch at least some errors early on, which can be + # useful since soft_defaults are not static type checked. + if ioattrs is not None: + have_soft_default = False + soft_default: Any = None + if ioattrs.soft_default is not ioattrs.MISSING: + have_soft_default = True + soft_default = ioattrs.soft_default + elif ioattrs.soft_default_factory is not ioattrs.MISSING: + assert callable(ioattrs.soft_default_factory) + have_soft_default = True + soft_default = ioattrs.soft_default_factory() + + # Do a simple type check for the top level to catch basic + # soft_default mismatches early; full check will happen at + # input time. + if have_soft_default: + if not isinstance(soft_default, origin): + raise TypeError( + f'{cls} attr {attrname} has type {origin}' + f' but soft_default value is type {type(soft_default)}' + ) + if origin in SIMPLE_TYPES: return @@ -273,6 +302,7 @@ class PrepSession: self.prep_type(cls, attrname, childtypes[0], + ioattrs=None, recursion_level=recursion_level + 1) return @@ -304,6 +334,7 @@ class PrepSession: self.prep_type(cls, attrname, childtypes[1], + ioattrs=None, recursion_level=recursion_level + 1) return @@ -325,6 +356,7 @@ class PrepSession: self.prep_type(cls, attrname, childtype, + ioattrs=None, recursion_level=recursion_level + 1) return @@ -362,6 +394,7 @@ class PrepSession: self.prep_type(cls, attrname, childtype, + None, recursion_level=recursion_level + 1) def prep_enum(self, enumtype: type[Enum]) -> None: diff --git a/dist/ba_data/python/efro/dataclassio/extras.py b/dist/ba_data/python/efro/dataclassio/extras.py index ed63939..cfa1992 100644 --- a/dist/ba_data/python/efro/dataclassio/extras.py +++ b/dist/ba_data/python/efro/dataclassio/extras.py @@ -8,7 +8,7 @@ import dataclasses from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any, Optional + from typing import Any def dataclass_diff(obj1: Any, obj2: Any) -> str: diff --git a/dist/ba_data/python/efro/error.py b/dist/ba_data/python/efro/error.py index 3bc1a54..2809b45 100644 --- a/dist/ba_data/python/efro/error.py +++ b/dist/ba_data/python/efro/error.py @@ -10,7 +10,7 @@ if TYPE_CHECKING: class CleanError(Exception): - """An error that should be presented to the user as a simple message. + """An error that can be presented to the user as a simple message. These errors should be completely self-explanatory, to the point where a traceback or other context would not be useful. @@ -41,7 +41,7 @@ class CommunicationError(Exception): This covers anything network-related going wrong in the sending of data or receiving of a response. This error does not imply that data was not received on the other end; only that a full - response round trip was not completed. + acknowledgement round trip was not completed. These errors should be gracefully handled whenever possible, as occasional network outages are generally unavoidable. @@ -55,9 +55,9 @@ class RemoteError(Exception): occurs remotely. The error string can consist of a remote stack trace or a simple message depending on the context. - Depending on the situation, more specific error types such as CleanError - may be raised due to the remote error, so this one is considered somewhat - of a catch-all. + Communication systems should raise more specific error types when + more introspection/control is needed; this is intended somewhat as + a catch-all. """ def __str__(self) -> str: @@ -65,6 +65,10 @@ class RemoteError(Exception): return f'Remote Exception Follows:\n{s}' +class IntegrityError(ValueError): + """Data has been tampered with or corrupted in some form.""" + + def is_urllib_network_error(exc: BaseException) -> bool: """Is the provided exception from urllib a network-related error? @@ -75,7 +79,6 @@ def is_urllib_network_error(exc: BaseException) -> bool: ignored or presented to the user as general 'network-unavailable' states. """ - import urllib.request import urllib.error import http.client import errno @@ -135,3 +138,45 @@ def is_udp_network_error(exc: BaseException) -> bool: }: return True return False + + +def is_asyncio_streams_network_error(exc: BaseException) -> bool: + """Is the provided exception a network-related error? + + This should be passed an exception which resulted from creating and + using asyncio streams. It should return True for any errors that could + conceivably arise due to unavailable/poor network connections, + firewall/connectivity issues, etc. These issues can often be safely + ignored or presented to the user as general 'connection-lost' events. + """ + import errno + import ssl + + if isinstance(exc, ( + ConnectionError, + TimeoutError, + EOFError, + )): + return True + + # Also some specific errno ones. + if isinstance(exc, OSError): + if exc.errno == 10051: # Windows unreachable network error. + return True + if exc.errno in { + errno.ETIMEDOUT, + errno.EHOSTUNREACH, + errno.ENETUNREACH, + }: + return True + + # Am occasionally getting a specific SSL error on shutdown which I + # believe is harmless (APPLICATION_DATA_AFTER_CLOSE_NOTIFY). + # It sounds like it may soon be ignored by Python (as of March 2022). + # Let's still complain, however, if we get any SSL errors besides + # this one. https://bugs.python.org/issue39951 + if isinstance(exc, ssl.SSLError): + if 'APPLICATION_DATA_AFTER_CLOSE_NOTIFY' in str(exc): + return True + + return False diff --git a/dist/ba_data/python/efro/message/__init__.py b/dist/ba_data/python/efro/message/__init__.py new file mode 100644 index 0000000..11a82fd --- /dev/null +++ b/dist/ba_data/python/efro/message/__init__.py @@ -0,0 +1,27 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality for sending and responding to messages. +Supports static typing for message types and possible return types. +""" + +from __future__ import annotations + +from efro.util import set_canonical_module +from efro.message._protocol import MessageProtocol +from efro.message._sender import (MessageSender, BoundMessageSender) +from efro.message._receiver import (MessageReceiver, BoundMessageReceiver) +from efro.message._module import (create_sender_module, create_receiver_module) +from efro.message._message import (Message, Response, EmptyResponse, + ErrorResponse, StringResponse, BoolResponse, + UnregisteredMessageIDError) + +__all__ = [ + 'Message', 'Response', 'EmptyResponse', 'ErrorResponse', 'StringResponse', + 'BoolResponse', 'MessageProtocol', 'MessageSender', 'BoundMessageSender', + 'MessageReceiver', 'BoundMessageReceiver', 'create_sender_module', + 'create_receiver_module', 'UnregisteredMessageIDError' +] + +# Have these things present themselves cleanly as 'thismodule.SomeClass' +# instead of 'thismodule._internalmodule.SomeClass' +set_canonical_module(module_globals=globals(), names=__all__) diff --git a/dist/ba_data/python/efro/message/_message.py b/dist/ba_data/python/efro/message/_message.py new file mode 100644 index 0000000..5c4700a --- /dev/null +++ b/dist/ba_data/python/efro/message/_message.py @@ -0,0 +1,86 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality for sending and responding to messages. +Supports static typing for message types and possible return types. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Annotated +from dataclasses import dataclass +from enum import Enum + +from efro.dataclassio import ioprepped, IOAttrs + +if TYPE_CHECKING: + pass + + +class UnregisteredMessageIDError(Exception): + """A message or response id is not covered by our protocol.""" + + +class Message: + """Base class for messages.""" + + @classmethod + def get_response_types(cls) -> list[type[Response]]: + """Return all message types this Message can result in when sent. + + The default implementation specifies EmptyResponse, so messages with + no particular response needs can leave this untouched. + Note that ErrorMessage is handled as a special case and does not + need to be specified here. + """ + return [EmptyResponse] + + +class Response: + """Base class for responses to messages.""" + + +# Some standard response types: + + +class ErrorType(Enum): + """Type of error that occurred in remote message handling.""" + OTHER = 0 + CLEAN = 1 + + +@ioprepped +@dataclass +class ErrorResponse(Response): + """Message saying some error has occurred on the other end. + + This type is unique in that it is not returned to the user; it + instead results in a local exception being raised. + """ + error_message: Annotated[str, IOAttrs('m')] + error_type: Annotated[ErrorType, IOAttrs('e')] = ErrorType.OTHER + + +@ioprepped +@dataclass +class EmptyResponse(Response): + """The response equivalent of None.""" + + +# TODO: could allow handlers to deal in raw values for these +# types similar to how we allow None in place of EmptyResponse. +# Though not sure if they are widely used enough to warrant the +# extra code complexity. +@ioprepped +@dataclass +class BoolResponse(Response): + """A simple bool value response.""" + + value: Annotated[bool, IOAttrs('v')] + + +@ioprepped +@dataclass +class StringResponse(Response): + """A simple string value response.""" + + value: Annotated[str, IOAttrs('v')] diff --git a/dist/ba_data/python/efro/message/_module.py b/dist/ba_data/python/efro/message/_module.py new file mode 100644 index 0000000..4e278bb --- /dev/null +++ b/dist/ba_data/python/efro/message/_module.py @@ -0,0 +1,102 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality for sending and responding to messages. +Supports static typing for message types and possible return types. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from efro.message._protocol import MessageProtocol + +if TYPE_CHECKING: + from typing import Optional + + +def create_sender_module( + basename: str, + protocol_create_code: str, + enable_sync_sends: bool, + enable_async_sends: bool, + private: bool = False, + protocol_module_level_import_code: Optional[str] = None, + build_time_protocol_create_code: Optional[str] = None, +) -> str: + """Create a Python module defining a MessageSender subclass. + + This class is primarily for type checking and will contain overrides + for the varieties of send calls for message/response types defined + in the protocol. + + Code passed for 'protocol_create_code' should import necessary + modules and assign an instance of the Protocol to a 'protocol' + variable. + + Class names are based on basename; a basename 'FooSender' will + result in classes FooSender and BoundFooSender. + + If 'private' is True, class-names will be prefixed with an '_'. + + Note that generated line lengths are not clipped, so output may need + to be run through a formatter to prevent lint warnings about excessive + line lengths. + """ + protocol = _protocol_from_code( + build_time_protocol_create_code if build_time_protocol_create_code + is not None else protocol_create_code) + return protocol.do_create_sender_module( + basename=basename, + protocol_create_code=protocol_create_code, + enable_sync_sends=enable_sync_sends, + enable_async_sends=enable_async_sends, + private=private, + protocol_module_level_import_code=protocol_module_level_import_code) + + +def create_receiver_module( + basename: str, + protocol_create_code: str, + is_async: bool, + private: bool = False, + protocol_module_level_import_code: Optional[str] = None, + build_time_protocol_create_code: Optional[str] = None, +) -> str: + """"Create a Python module defining a MessageReceiver subclass. + + This class is primarily for type checking and will contain overrides + for the register method for message/response types defined in + the protocol. + + Class names are based on basename; a basename 'FooReceiver' will + result in FooReceiver and BoundFooReceiver. + + If 'is_async' is True, handle_raw_message() will be an async method + and the @handler decorator will expect async methods. + + If 'private' is True, class-names will be prefixed with an '_'. + + Note that line lengths are not clipped, so output may need to be + run through a formatter to prevent lint warnings about excessive + line lengths. + """ + protocol = _protocol_from_code( + build_time_protocol_create_code if build_time_protocol_create_code + is not None else protocol_create_code) + return protocol.do_create_receiver_module( + basename=basename, + protocol_create_code=protocol_create_code, + is_async=is_async, + private=private, + protocol_module_level_import_code=protocol_module_level_import_code) + + +def _protocol_from_code(protocol_create_code: str) -> MessageProtocol: + env: dict = {} + exec(protocol_create_code, env) # pylint: disable=exec-used + protocol = env.get('protocol') + if not isinstance(protocol, MessageProtocol): + raise RuntimeError( + f'protocol_create_code yielded' + f' a {type(protocol)}; expected a MessageProtocol instance.') + return protocol diff --git a/dist/ba_data/python/efro/message/_protocol.py b/dist/ba_data/python/efro/message/_protocol.py new file mode 100644 index 0000000..1d35db4 --- /dev/null +++ b/dist/ba_data/python/efro/message/_protocol.py @@ -0,0 +1,513 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality for sending and responding to messages. +Supports static typing for message types and possible return types. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING +import traceback +import logging +import json + +from efro.error import CleanError +from efro.dataclassio import (is_ioprepped_dataclass, dataclass_to_dict, + dataclass_from_dict) +from efro.message._message import (Message, Response, ErrorResponse, + EmptyResponse, ErrorType, + UnregisteredMessageIDError) + +if TYPE_CHECKING: + from typing import Any, Literal + + +class MessageProtocol: + """Wrangles a set of message types, formats, and response types. + Both endpoints must be using a compatible Protocol for communication + to succeed. To maintain Protocol compatibility between revisions, + all message types must retain the same id, message attr storage names must + not change, newly added attrs must have default values, etc. + """ + + def __init__(self, + message_types: dict[int, type[Message]], + response_types: dict[int, type[Response]], + preserve_clean_errors: bool = True, + log_remote_exceptions: bool = True, + trusted_sender: bool = False) -> None: + """Create a protocol with a given configuration. + + Note that common response types are automatically registered + with (unchanging negative ids) so they don't need to be passed + explicitly (but can be if a different id is desired). + + If 'preserve_clean_errors' is True, efro.error.CleanError errors + on the remote end will result in the same error raised locally. + All other Exception types come across as efro.error.RemoteError. + + If 'trusted_sender' is True, stringified remote stack traces will + be included in the responses if errors occur. + """ + self.message_types_by_id: dict[int, type[Message]] = {} + self.message_ids_by_type: dict[type[Message], int] = {} + self.response_types_by_id: dict[int, type[Response]] = {} + self.response_ids_by_type: dict[type[Response], int] = {} + for m_id, m_type in message_types.items(): + + # Make sure only valid message types were passed and each + # id was assigned only once. + assert isinstance(m_id, int) + assert m_id >= 0 + assert (is_ioprepped_dataclass(m_type) + and issubclass(m_type, Message)) + assert self.message_types_by_id.get(m_id) is None + self.message_types_by_id[m_id] = m_type + self.message_ids_by_type[m_type] = m_id + + for r_id, r_type in response_types.items(): + assert isinstance(r_id, int) + assert r_id >= 0 + assert (is_ioprepped_dataclass(r_type) + and issubclass(r_type, Response)) + assert self.response_types_by_id.get(r_id) is None + self.response_types_by_id[r_id] = r_type + self.response_ids_by_type[r_type] = r_id + + # Go ahead and auto-register a few common response types + # if the user has not done so explicitly. Use unique negative + # IDs which will never change or overlap with user ids. + def _reg_if_not(reg_tp: type[Response], reg_id: int) -> None: + if reg_tp in self.response_ids_by_type: + return + assert self.response_types_by_id.get(reg_id) is None + self.response_types_by_id[reg_id] = reg_tp + self.response_ids_by_type[reg_tp] = reg_id + + _reg_if_not(ErrorResponse, -1) + _reg_if_not(EmptyResponse, -2) + + # Some extra-thorough validation in debug mode. + if __debug__: + # Make sure all Message types' return types are valid + # and have been assigned an ID as well. + all_response_types: set[type[Response]] = set() + for m_id, m_type in message_types.items(): + m_rtypes = m_type.get_response_types() + assert isinstance(m_rtypes, list) + assert m_rtypes, ( + f'Message type {m_type} specifies no return types.') + assert len(set(m_rtypes)) == len(m_rtypes) # check dups + all_response_types.update(m_rtypes) + for cls in all_response_types: + assert is_ioprepped_dataclass(cls) + assert issubclass(cls, Response) + if cls not in self.response_ids_by_type: + raise ValueError(f'Possible response type {cls}' + f' needs to be included in response_types' + f' for this protocol.') + + # Make sure all registered types have unique base names. + # We can take advantage of this to generate cleaner looking + # protocol modules. Can revisit if this is ever a problem. + mtypenames = set(tp.__name__ for tp in self.message_ids_by_type) + if len(mtypenames) != len(message_types): + raise ValueError( + 'message_types contains duplicate __name__s;' + ' all types are required to have unique names.') + + self.preserve_clean_errors = preserve_clean_errors + self.log_remote_exceptions = log_remote_exceptions + self.trusted_sender = trusted_sender + + @staticmethod + def encode_dict(obj: dict) -> str: + """Json-encode a provided dict.""" + return json.dumps(obj, separators=(',', ':')) + + def message_to_dict(self, message: Message) -> dict: + """Encode a message to a json ready dict.""" + return self._to_dict(message, self.message_ids_by_type, 'message') + + def response_to_dict(self, response: Response) -> dict: + """Encode a response to a json ready dict.""" + return self._to_dict(response, self.response_ids_by_type, 'response') + + def error_to_response(self, exc: Exception) -> Response: + """Translate an error to a response.""" + if self.log_remote_exceptions: + logging.exception('Error handling message.') + + # If anything goes wrong, return a ErrorResponse instead. + if isinstance(exc, CleanError) and self.preserve_clean_errors: + return ErrorResponse(error_message=str(exc), + error_type=ErrorType.CLEAN) + return ErrorResponse( + error_message=(traceback.format_exc() if self.trusted_sender else + 'An unknown error has occurred.'), + error_type=ErrorType.OTHER) + + def _to_dict(self, message: Any, ids_by_type: dict[type, int], + opname: str) -> dict: + """Encode a message to a json string for transport.""" + + m_id: int | None = ids_by_type.get(type(message)) + if m_id is None: + raise TypeError(f'{opname} type is not registered in protocol:' + f' {type(message)}') + out = {'t': m_id, 'm': dataclass_to_dict(message)} + return out + + @staticmethod + def decode_dict(data: str) -> dict: + """Decode data to a dict.""" + out = json.loads(data) + assert isinstance(out, dict) + return out + + def message_from_dict(self, data: dict) -> Message: + """Decode a message from a json string.""" + out = self._from_dict(data, self.message_types_by_id, 'message') + assert isinstance(out, Message) + return out + + def response_from_dict(self, data: dict) -> Response: + """Decode a response from a json string.""" + out = self._from_dict(data, self.response_types_by_id, 'response') + assert isinstance(out, Response) + return out + + # Weeeird; we get mypy errors returning dict[int, type] but + # dict[int, typing.Type] or dict[int, type[Any]] works.. + def _from_dict(self, data: dict, types_by_id: dict[int, type[Any]], + opname: str) -> Any: + """Decode a message from a json string.""" + msgdict: dict | None + + m_id = data.get('t') + # Allow omitting 'm' dict if its empty. + msgdict = data.get('m', {}) + + assert isinstance(m_id, int) + assert isinstance(msgdict, dict) + + # Decode this particular type. + msgtype = types_by_id.get(m_id) + if msgtype is None: + raise UnregisteredMessageIDError( + f'Got unregistered {opname} id of {m_id}.') + return dataclass_from_dict(msgtype, msgdict) + + def _get_module_header(self, + part: Literal['sender', 'receiver'], + extra_import_code: str | None = None) -> str: + """Return common parts of generated modules.""" + # pylint: disable=too-many-locals, too-many-branches + import textwrap + tpimports: dict[str, list[str]] = {} + imports: dict[str, list[str]] = {} + + single_message_type = len(self.message_ids_by_type) == 1 + + msgtypes = list(self.message_ids_by_type) + if part == 'sender': + msgtypes.append(Message) + for msgtype in msgtypes: + tpimports.setdefault(msgtype.__module__, + []).append(msgtype.__name__) + rsptypes = list(self.response_ids_by_type) + if part == 'sender': + rsptypes.append(Response) + for rsp_tp in rsptypes: + # Skip these as they don't actually show up in code. + if rsp_tp is EmptyResponse or rsp_tp is ErrorResponse: + continue + if (single_message_type and part == 'sender' + and rsp_tp is not Response): + # We need to cast to the single supported response type + # in this case so need response types at runtime. + imports.setdefault(rsp_tp.__module__, + []).append(rsp_tp.__name__) + else: + tpimports.setdefault(rsp_tp.__module__, + []).append(rsp_tp.__name__) + + import_lines = '' + tpimport_lines = '' + + for module, names in sorted(imports.items()): + jnames = ', '.join(names) + line = f'from {module} import {jnames}' + if len(line) > 79: + # Recreate in a wrapping-friendly form. + line = f'from {module} import ({jnames})' + import_lines += f'{line}\n' + for module, names in sorted(tpimports.items()): + jnames = ', '.join(names) + line = f'from {module} import {jnames}' + if len(line) > 75: # Account for indent + # Recreate in a wrapping-friendly form. + line = f'from {module} import ({jnames})' + tpimport_lines += f'{line}\n' + + if part == 'sender': + import_lines += ('from efro.message import MessageSender,' + ' BoundMessageSender') + tpimport_typing_extras = '' + else: + if single_message_type: + import_lines += ('from efro.message import (MessageReceiver,' + ' BoundMessageReceiver, Message, Response)') + else: + import_lines += ('from efro.message import MessageReceiver,' + ' BoundMessageReceiver') + tpimport_typing_extras = ', Awaitable' + + if extra_import_code is not None: + import_lines += f'\n{extra_import_code}\n' + + ovld = ', overload' if not single_message_type else '' + tpimport_lines = textwrap.indent(tpimport_lines, ' ') + + baseimps = ['Any'] + if part == 'receiver': + baseimps.append('Callable') + baseimps_s = ', '.join(baseimps) + out = ('# Released under the MIT License. See LICENSE for details.\n' + f'#\n' + f'"""Auto-generated {part} module. Do not edit by hand."""\n' + f'\n' + f'from __future__ import annotations\n' + f'\n' + f'from typing import TYPE_CHECKING{ovld}\n' + f'\n' + f'{import_lines}\n' + f'\n' + f'if TYPE_CHECKING:\n' + f' from typing import {baseimps_s}' + f'{tpimport_typing_extras}\n' + f'{tpimport_lines}' + f'\n' + f'\n') + return out + + def do_create_sender_module( + self, + basename: str, + protocol_create_code: str, + enable_sync_sends: bool, + enable_async_sends: bool, + private: bool = False, + protocol_module_level_import_code: str | None = None) -> str: + """Used by create_sender_module(); do not call directly.""" + # pylint: disable=too-many-locals + import textwrap + + msgtypes = list(self.message_ids_by_type.keys()) + + ppre = '_' if private else '' + out = self._get_module_header( + 'sender', extra_import_code=protocol_module_level_import_code) + ccind = textwrap.indent(protocol_create_code, ' ') + out += (f'class {ppre}{basename}(MessageSender):\n' + f' """Protocol-specific sender."""\n' + f'\n' + f' def __init__(self) -> None:\n' + f'{ccind}\n' + f' super().__init__(protocol)\n' + f'\n' + f' def __get__(self,\n' + f' obj: Any,\n' + f' type_in: Any = None)' + f' -> {ppre}Bound{basename}:\n' + f' return {ppre}Bound{basename}' + f'(obj, self)\n' + f'\n' + f'\n' + f'class {ppre}Bound{basename}(BoundMessageSender):\n' + f' """Protocol-specific bound sender."""\n') + + def _filt_tp_name(rtype: type[Response]) -> str: + # We accept None to equal EmptyResponse so reflect that + # in the type annotation. + return 'None' if rtype is EmptyResponse else rtype.__name__ + + # Define handler() overloads for all registered message types. + if msgtypes: + for async_pass in False, True: + if async_pass and not enable_async_sends: + continue + if not async_pass and not enable_sync_sends: + continue + pfx = 'async ' if async_pass else '' + sfx = '_async' if async_pass else '' + awt = 'await ' if async_pass else '' + how = 'asynchronously' if async_pass else 'synchronously' + + if len(msgtypes) == 1: + # Special case: with a single message types we don't + # use overloads. + msgtype = msgtypes[0] + msgtypevar = msgtype.__name__ + rtypes = msgtype.get_response_types() + if len(rtypes) > 1: + rtypevar = ' | '.join(_filt_tp_name(t) for t in rtypes) + else: + rtypevar = _filt_tp_name(rtypes[0]) + out += (f'\n' + f' {pfx}def send{sfx}(self,' + f' message: {msgtypevar})' + f' -> {rtypevar}:\n' + f' """Send a message {how}."""\n' + f' out = {awt}self._sender.' + f'send{sfx}(self._obj, message)\n' + f' assert isinstance(out, {rtypevar})\n' + f' return out\n') + else: + + for msgtype in msgtypes: + msgtypevar = msgtype.__name__ + rtypes = msgtype.get_response_types() + if len(rtypes) > 1: + rtypevar = ' | '.join( + _filt_tp_name(t) for t in rtypes) + else: + rtypevar = _filt_tp_name(rtypes[0]) + out += (f'\n' + f' @overload\n' + f' {pfx}def send{sfx}(self,' + f' message: {msgtypevar})' + f' -> {rtypevar}:\n' + f' ...\n') + out += (f'\n' + f' {pfx}def send{sfx}(self, message: Message)' + f' -> Response | None:\n' + f' """Send a message {how}."""\n' + f' return {awt}self._sender.' + f'send{sfx}(self._obj, message)\n') + + return out + + def do_create_receiver_module( + self, + basename: str, + protocol_create_code: str, + is_async: bool, + private: bool = False, + protocol_module_level_import_code: str | None = None) -> str: + """Used by create_receiver_module(); do not call directly.""" + # pylint: disable=too-many-locals + import textwrap + + desc = 'asynchronous' if is_async else 'synchronous' + ppre = '_' if private else '' + msgtypes = list(self.message_ids_by_type.keys()) + out = self._get_module_header( + 'receiver', extra_import_code=protocol_module_level_import_code) + ccind = textwrap.indent(protocol_create_code, ' ') + out += (f'class {ppre}{basename}(MessageReceiver):\n' + f' """Protocol-specific {desc} receiver."""\n' + f'\n' + f' is_async = {is_async}\n' + f'\n' + f' def __init__(self) -> None:\n' + f'{ccind}\n' + f' super().__init__(protocol)\n' + f'\n' + f' def __get__(\n' + f' self,\n' + f' obj: Any,\n' + f' type_in: Any = None,\n' + f' ) -> {ppre}Bound{basename}:\n' + f' return {ppre}Bound{basename}(' + f'obj, self)\n') + + # Define handler() overloads for all registered message types. + + def _filt_tp_name(rtype: type[Response]) -> str: + # We accept None to equal EmptyResponse so reflect that + # in the type annotation. + return 'None' if rtype is EmptyResponse else rtype.__name__ + + if msgtypes: + cbgn = 'Awaitable[' if is_async else '' + cend = ']' if is_async else '' + if len(msgtypes) == 1: + # Special case: when we have a single message type we don't + # use overloads. + msgtype = msgtypes[0] + msgtypevar = msgtype.__name__ + rtypes = msgtype.get_response_types() + if len(rtypes) > 1: + rtypevar = ' | '.join(_filt_tp_name(t) for t in rtypes) + else: + rtypevar = _filt_tp_name(rtypes[0]) + rtypevar = f'{cbgn}{rtypevar}{cend}' + out += ( + f'\n' + f' def handler(\n' + f' self,\n' + f' call: Callable[[Any, {msgtypevar}], ' + f'{rtypevar}],\n' + f' )' + f' -> Callable[[Any, {msgtypevar}], {rtypevar}]:\n' + f' """Decorator to register message handlers."""\n' + f' from typing import cast, Callable, Any\n' + f' self.register_handler(cast(Callable' + f'[[Any, Message], Response], call))\n' + f' return call\n') + else: + for msgtype in msgtypes: + msgtypevar = msgtype.__name__ + rtypes = msgtype.get_response_types() + if len(rtypes) > 1: + rtypevar = ' | '.join(_filt_tp_name(t) for t in rtypes) + else: + rtypevar = _filt_tp_name(rtypes[0]) + rtypevar = f'{cbgn}{rtypevar}{cend}' + out += (f'\n' + f' @overload\n' + f' def handler(\n' + f' self,\n' + f' call: Callable[[Any, {msgtypevar}], ' + f'{rtypevar}],\n' + f' )' + f' -> Callable[[Any, {msgtypevar}], {rtypevar}]:\n' + f' ...\n') + out += ( + '\n' + ' def handler(self, call: Callable) -> Callable:\n' + ' """Decorator to register message handlers."""\n' + ' self.register_handler(call)\n' + ' return call\n') + + out += (f'\n' + f'\n' + f'class {ppre}Bound{basename}(BoundMessageReceiver):\n' + f' """Protocol-specific bound receiver."""\n') + if is_async: + out += ( + '\n' + ' async def handle_raw_message(self,\n' + ' message: str,\n' + ' raise_unregistered: bool =' + ' False) -> str:\n' + ' """Asynchronously handle a raw incoming message."""\n' + ' return await self._receiver.handle_raw_message_async(' + '\n' + ' self._obj, message, raise_unregistered)\n') + + else: + out += ( + '\n' + ' def handle_raw_message(self,\n' + ' message: str,\n' + ' raise_unregistered: bool = False)' + ' -> str:\n' + ' """Synchronously handle a raw incoming message."""\n' + ' return self._receiver.handle_raw_message(' + 'self._obj, message,\n' + ' ' + 'raise_unregistered)\n') + + return out diff --git a/dist/ba_data/python/efro/message/_receiver.py b/dist/ba_data/python/efro/message/_receiver.py new file mode 100644 index 0000000..36cada0 --- /dev/null +++ b/dist/ba_data/python/efro/message/_receiver.py @@ -0,0 +1,298 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality for sending and responding to messages. +Supports static typing for message types and possible return types. +""" + +from __future__ import annotations + +import types +import inspect +import logging +from typing import TYPE_CHECKING + +from efro.message._message import (Message, Response, EmptyResponse, + ErrorResponse, UnregisteredMessageIDError) + +if TYPE_CHECKING: + from typing import Any, Callable, Optional, Union + + from efro.message._protocol import MessageProtocol + + +class MessageReceiver: + """Facilitates receiving & responding to messages from a remote source. + + This is instantiated at the class level with unbound methods registered + as handlers for different message types in the protocol. + + Example: + + class MyClass: + receiver = MyMessageReceiver() + + # MyMessageReceiver fills out handler() overloads to ensure all + # registered handlers have valid types/return-types. + @receiver.handler + def handle_some_message_type(self, message: SomeMsg) -> SomeResponse: + # Deal with this message type here. + + # This will trigger the registered handler being called. + obj = MyClass() + obj.receiver.handle_raw_message(some_raw_data) + + Any unhandled Exception occurring during message handling will result in + an Exception being raised on the sending end. + """ + + is_async = False + + def __init__(self, protocol: MessageProtocol) -> None: + self.protocol = protocol + self._handlers: dict[type[Message], Callable] = {} + self._decode_filter_call: Optional[Callable[[Any, dict, Message], + None]] = None + self._encode_filter_call: Optional[Callable[[Any, Response, dict], + None]] = None + + # noinspection PyProtectedMember + def register_handler( + self, call: Callable[[Any, Message], Optional[Response]]) -> None: + """Register a handler call. + + The message type handled by the call is determined by its + type annotation. + """ + # TODO: can use types.GenericAlias in 3.9. + # (hmm though now that we're there, it seems a drop-in + # replace gives us errors. Should re-test in 3.10 as it seems + # that typing_extensions handles it differently in that case) + from typing import _GenericAlias # type: ignore + from typing import get_type_hints, get_args + + sig = inspect.getfullargspec(call) + + # The provided callable should be a method taking one 'msg' arg. + expectedsig = ['self', 'msg'] + if sig.args != expectedsig: + raise ValueError(f'Expected callable signature of {expectedsig};' + f' got {sig.args}') + + # Make sure we are only given async methods if we are an async handler + # and sync ones otherwise. + is_async = inspect.iscoroutinefunction(call) + if self.is_async != is_async: + msg = ('Expected a sync method; found an async one.' if is_async + else 'Expected an async method; found a sync one.') + raise ValueError(msg) + + # Check annotation types to determine what message types we handle. + # Return-type annotation can be a Union, but we probably don't + # have it available at runtime. Explicitly pull it in. + # UPDATE: we've updated our pylint filter to where we should + # have all annotations available. + # anns = get_type_hints(call, localns={'Union': Union}) + anns = get_type_hints(call) + + msgtype = anns.get('msg') + if not isinstance(msgtype, type): + raise TypeError( + f'expected a type for "msg" annotation; got {type(msgtype)}.') + assert issubclass(msgtype, Message) + + ret = anns.get('return') + responsetypes: tuple[Union[type[Any], type[None]], ...] + + # Return types can be a single type or a union of types. + if isinstance(ret, (_GenericAlias, types.UnionType)): + targs = get_args(ret) + if not all(isinstance(a, type) for a in targs): + raise TypeError(f'expected only types for "return" annotation;' + f' got {targs}.') + responsetypes = targs + else: + if not isinstance(ret, type): + raise TypeError(f'expected one or more types for' + f' "return" annotation; got a {type(ret)}.') + # This seems like maybe a mypy bug. Appeared after adding + # types.UnionType above. + responsetypes = (ret, ) # type: ignore + + # Return type of None translates to EmptyResponse. + responsetypes = tuple(EmptyResponse if r is type(None) else r + for r in responsetypes) # noqa + + # Make sure our protocol has this message type registered and our + # return types exactly match. (Technically we could return a subset + # of the supported types; can allow this in the future if it makes + # sense). + registered_types = self.protocol.message_ids_by_type.keys() + + if msgtype not in registered_types: + raise TypeError(f'Message type {msgtype} is not registered' + f' in this Protocol.') + + if msgtype in self._handlers: + raise TypeError(f'Message type {msgtype} already has a registered' + f' handler.') + + # Make sure the responses exactly matches what the message expects. + if set(responsetypes) != set(msgtype.get_response_types()): + raise TypeError( + f'Provided response types {responsetypes} do not' + f' match the set expected by message type {msgtype}: ' + f'({msgtype.get_response_types()})') + + # Ok; we're good! + self._handlers[msgtype] = call + + def decode_filter_method( + self, call: Callable[[Any, dict, Message], None] + ) -> Callable[[Any, dict, Message], None]: + """Function decorator for defining a decode filter. + + Decode filters can be used to extract extra data from incoming + message dicts. + """ + assert self._decode_filter_call is None + self._decode_filter_call = call + return call + + def encode_filter_method( + self, call: Callable[[Any, Response, dict], None] + ) -> Callable[[Any, Response, dict], None]: + """Function decorator for defining an encode filter. + + Encode filters can be used to add extra data to the message + dict before is is encoded to a string and sent out. + """ + assert self._encode_filter_call is None + self._encode_filter_call = call + return call + + def validate(self, log_only: bool = False) -> None: + """Check for handler completeness, valid types, etc.""" + for msgtype in self.protocol.message_ids_by_type.keys(): + if issubclass(msgtype, Response): + continue + if msgtype not in self._handlers: + msg = (f'Protocol message type {msgtype} is not handled' + f' by receiver type {type(self)}.') + if log_only: + logging.error(msg) + else: + raise TypeError(msg) + + def _decode_incoming_message(self, bound_obj: Any, + msg: str) -> tuple[Message, type[Message]]: + # Decode the incoming message. + msg_dict = self.protocol.decode_dict(msg) + msg_decoded = self.protocol.message_from_dict(msg_dict) + msgtype = type(msg_decoded) + assert issubclass(msgtype, Message) + if self._decode_filter_call is not None: + self._decode_filter_call(bound_obj, msg_dict, msg_decoded) + + return msg_decoded, msgtype + + def encode_user_response(self, bound_obj: Any, + response: Optional[Response], + msgtype: type[Message]) -> str: + """Encode a response provided by the user for sending.""" + + # A return value of None equals EmptyResponse. + if response is None: + response = EmptyResponse() + + assert isinstance(response, Response) + # (user should never explicitly return error-responses) + assert not isinstance(response, ErrorResponse) + assert type(response) in msgtype.get_response_types() + response_dict = self.protocol.response_to_dict(response) + if self._encode_filter_call is not None: + self._encode_filter_call(bound_obj, response, response_dict) + return self.protocol.encode_dict(response_dict) + + def encode_error_response(self, bound_obj: Any, exc: Exception) -> str: + """Given an error, return a response ready for sending.""" + response = self.protocol.error_to_response(exc) + response_dict = self.protocol.response_to_dict(response) + if self._encode_filter_call is not None: + self._encode_filter_call(bound_obj, response, response_dict) + return self.protocol.encode_dict(response_dict) + + def handle_raw_message(self, + bound_obj: Any, + msg: str, + raise_unregistered: bool = False) -> str: + """Decode, handle, and return an response for a message. + + if 'raise_unregistered' is True, will raise an + efro.message.UnregisteredMessageIDError for messages not handled by + the protocol. In all other cases local errors will translate to + error responses returned to the sender. + """ + assert not self.is_async, "can't call sync handler on async receiver" + try: + msg_decoded, msgtype = self._decode_incoming_message( + bound_obj, msg) + handler = self._handlers.get(msgtype) + if handler is None: + raise RuntimeError(f'Got unhandled message type: {msgtype}.') + response = handler(bound_obj, msg_decoded) + assert isinstance(response, (Response, type(None))) + return self.encode_user_response(bound_obj, response, msgtype) + + except Exception as exc: + if (raise_unregistered + and isinstance(exc, UnregisteredMessageIDError)): + raise + return self.encode_error_response(bound_obj, exc) + + async def handle_raw_message_async( + self, + bound_obj: Any, + msg: str, + raise_unregistered: bool = False) -> str: + """Should be called when the receiver gets a message. + + The return value is the raw response to the message. + """ + assert self.is_async, "can't call async handler on sync receiver" + try: + msg_decoded, msgtype = self._decode_incoming_message( + bound_obj, msg) + handler = self._handlers.get(msgtype) + if handler is None: + raise RuntimeError(f'Got unhandled message type: {msgtype}.') + response = await handler(bound_obj, msg_decoded) + assert isinstance(response, (Response, type(None))) + return self.encode_user_response(bound_obj, response, msgtype) + + except Exception as exc: + if (raise_unregistered + and isinstance(exc, UnregisteredMessageIDError)): + raise + return self.encode_error_response(bound_obj, exc) + + +class BoundMessageReceiver: + """Base bound receiver class.""" + + def __init__( + self, + obj: Any, + receiver: MessageReceiver, + ) -> None: + assert obj is not None + self._obj = obj + self._receiver = receiver + + @property + def protocol(self) -> MessageProtocol: + """Protocol associated with this receiver.""" + return self._receiver.protocol + + def encode_error_response(self, exc: Exception) -> str: + """Given an error, return a response ready to send.""" + return self._receiver.encode_error_response(self._obj, exc) diff --git a/dist/ba_data/python/efro/message/_sender.py b/dist/ba_data/python/efro/message/_sender.py new file mode 100644 index 0000000..0a2c015 --- /dev/null +++ b/dist/ba_data/python/efro/message/_sender.py @@ -0,0 +1,190 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality for sending and responding to messages. +Supports static typing for message types and possible return types. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, TypeVar + +from efro.error import CleanError, RemoteError +from efro.message._message import (EmptyResponse, ErrorResponse, ErrorType) + +if TYPE_CHECKING: + from typing import Any, Callable, Optional, Awaitable + + from efro.message._message import Message, Response + from efro.message._protocol import MessageProtocol + +TM = TypeVar('TM', bound='MessageSender') + + +class MessageSender: + """Facilitates sending messages to a target and receiving responses. + This is instantiated at the class level and used to register unbound + class methods to handle raw message sending. + + Example: + + class MyClass: + msg = MyMessageSender(some_protocol) + + @msg.send_method + def send_raw_message(self, message: str) -> str: + # Actually send the message here. + + # MyMessageSender class should provide overloads for send(), send_bg(), + # etc. to ensure all sending happens with valid types. + obj = MyClass() + obj.msg.send(SomeMessageType()) + """ + + def __init__(self, protocol: MessageProtocol) -> None: + self.protocol = protocol + self._send_raw_message_call: Optional[Callable[[Any, str], str]] = None + self._send_async_raw_message_call: Optional[Callable[ + [Any, str], Awaitable[str]]] = None + self._encode_filter_call: Optional[Callable[[Any, Message, dict], + None]] = None + self._decode_filter_call: Optional[Callable[[Any, dict, Response], + None]] = None + + def send_method( + self, call: Callable[[Any, str], + str]) -> Callable[[Any, str], str]: + """Function decorator for setting raw send method.""" + assert self._send_raw_message_call is None + self._send_raw_message_call = call + return call + + def send_async_method( + self, call: Callable[[Any, str], Awaitable[str]] + ) -> Callable[[Any, str], Awaitable[str]]: + """Function decorator for setting raw send-async method.""" + assert self._send_async_raw_message_call is None + self._send_async_raw_message_call = call + return call + + def encode_filter_method( + self, call: Callable[[Any, Message, dict], None] + ) -> Callable[[Any, Message, dict], None]: + """Function decorator for defining an encode filter. + + Encode filters can be used to add extra data to the message + dict before is is encoded to a string and sent out. + """ + assert self._encode_filter_call is None + self._encode_filter_call = call + return call + + def decode_filter_method( + self, call: Callable[[Any, dict, Response], None] + ) -> Callable[[Any, dict, Response], None]: + """Function decorator for defining a decode filter. + + Decode filters can be used to extract extra data from incoming + message dicts. + """ + assert self._decode_filter_call is None + self._decode_filter_call = call + return call + + def send(self, bound_obj: Any, message: Message) -> Optional[Response]: + """Send a message and receive a response. + + Will encode the message for transport and call dispatch_raw_message() + """ + if self._send_raw_message_call is None: + raise RuntimeError('send() is unimplemented for this type.') + + msg_encoded = self.encode_message(bound_obj, message) + + response_encoded = self._send_raw_message_call(bound_obj, msg_encoded) + + response = self.decode_response(bound_obj, response_encoded) + assert (response is None + or type(response) in type(message).get_response_types()) + return response + + def encode_message(self, bound_obj: Any, message: Message) -> str: + """Encode a message for sending.""" + msg_dict = self.protocol.message_to_dict(message) + if self._encode_filter_call is not None: + self._encode_filter_call(bound_obj, message, msg_dict) + return self.protocol.encode_dict(msg_dict) + + def decode_response(self, bound_obj: Any, + response_encoded: str) -> Optional[Response]: + """Decode, filter, and possibly act on raw response data.""" + response_dict = self.protocol.decode_dict(response_encoded) + response = self.protocol.response_from_dict(response_dict) + if self._decode_filter_call is not None: + self._decode_filter_call(bound_obj, response_dict, response) + + # Special case: if we get EmptyResponse, we simply return None. + if isinstance(response, EmptyResponse): + return None + + # Special case: a remote error occurred. Raise a local Exception + # instead of returning the message. + if isinstance(response, ErrorResponse): + if (self.protocol.preserve_clean_errors + and response.error_type is ErrorType.CLEAN): + raise CleanError(response.error_message) + raise RemoteError(response.error_message) + + return response + + async def send_async(self, bound_obj: Any, + message: Message) -> Optional[Response]: + """Send a message asynchronously using asyncio. + + The message will be encoded for transport and passed to + dispatch_raw_message_async. + """ + if self._send_async_raw_message_call is None: + raise RuntimeError('send_async() is unimplemented for this type.') + + msg_encoded = self.encode_message(bound_obj, message) + + response_encoded = await self._send_async_raw_message_call( + bound_obj, msg_encoded) + + response = self.decode_response(bound_obj, response_encoded) + assert (response is None + or type(response) in type(message).get_response_types()) + return response + + +class BoundMessageSender: + """Base class for bound senders.""" + + def __init__(self, obj: Any, sender: MessageSender) -> None: + # Note: not checking obj here since we want to support + # at least our protocol property when accessed via type. + self._obj = obj + self._sender = sender + + @property + def protocol(self) -> MessageProtocol: + """Protocol associated with this sender.""" + return self._sender.protocol + + def send_untyped(self, message: Message) -> Optional[Response]: + """Send a message synchronously. + + Whenever possible, use the send() call provided by generated + subclasses instead of this; it will provide better type safety. + """ + assert self._obj is not None + return self._sender.send(self._obj, message) + + async def send_async_untyped(self, message: Message) -> Optional[Response]: + """Send a message asynchronously. + + Whenever possible, use the send_async() call provided by generated + subclasses instead of this; it will provide better type safety. + """ + assert self._obj is not None + return await self._sender.send_async(self._obj, message) diff --git a/dist/ba_data/python/efro/rpc.py b/dist/ba_data/python/efro/rpc.py new file mode 100644 index 0000000..3484eff --- /dev/null +++ b/dist/ba_data/python/efro/rpc.py @@ -0,0 +1,585 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Remote procedure call related functionality.""" + +from __future__ import annotations + +import time +import asyncio +import logging +import weakref +from enum import Enum +from dataclasses import dataclass +from threading import current_thread +from typing import TYPE_CHECKING, Annotated + +from efro.error import CommunicationError, is_asyncio_streams_network_error +from efro.util import assert_never +from efro.dataclassio import (dataclass_to_json, dataclass_from_json, + ioprepped, IOAttrs) + +if TYPE_CHECKING: + from typing import Literal, Awaitable, Callable, Optional + +# Terminology: +# Packet: A chunk of data consisting of a type and some type-dependent +# payload. Even though we use streams we organize our transmission +# into 'packets'. +# Message: User data which we transmit using one or more packets. + + +class _PacketType(Enum): + HANDSHAKE = 0 + KEEPALIVE = 1 + MESSAGE = 2 + RESPONSE = 3 + + +_BYTE_ORDER: Literal['big'] = 'big' + + +@ioprepped +@dataclass +class _PeerInfo: + + # So we can gracefully evolve how we communicate in the future. + protocol: Annotated[int, IOAttrs('p')] + + # How often we'll be sending out keepalives (in seconds). + keepalive_interval: Annotated[float, IOAttrs('k')] + + +OUR_PROTOCOL = 1 + + +class _InFlightMessage: + """Represents a message that is out on the wire.""" + + def __init__(self) -> None: + self._response: Optional[bytes] = None + self._got_response = asyncio.Event() + self.wait_task = asyncio.create_task(self._wait()) + + async def _wait(self) -> bytes: + await self._got_response.wait() + assert self._response is not None + return self._response + + def set_response(self, data: bytes) -> None: + """Set response data.""" + assert self._response is None + self._response = data + self._got_response.set() + + +class _KeepaliveTimeoutError(Exception): + """Raised if we time out due to not receiving keepalives.""" + + +class RPCEndpoint: + """Facilitates asynchronous multiplexed remote procedure calls. + + Be aware that, while multiple calls can be in flight in either direction + simultaneously, packets are still sent serially in a single + stream. So excessively long messages/responses will delay all other + communication. If/when this becomes an issue we can look into breaking up + long messages into multiple packets. + """ + + # Set to True on an instance to test keepalive failures. + test_suppress_keepalives: bool = False + + # How long we should wait before giving up on a message by default. + # Note this includes processing time on the other end. + DEFAULT_MESSAGE_TIMEOUT = 60.0 + + # How often we send out keepalive packets by default. + DEFAULT_KEEPALIVE_INTERVAL = 10.73 # (avoid too regular of values) + + # How long we can go without receiving a keepalive packet before we + # disconnect. + DEFAULT_KEEPALIVE_TIMEOUT = 30.0 + + def __init__(self, + handle_raw_message_call: Callable[[bytes], Awaitable[bytes]], + reader: asyncio.StreamReader, + writer: asyncio.StreamWriter, + label: str, + debug_print: bool = False, + debug_print_io: bool = False, + debug_print_call: Callable[[str], None] = None, + keepalive_interval: float = DEFAULT_KEEPALIVE_INTERVAL, + keepalive_timeout: float = DEFAULT_KEEPALIVE_TIMEOUT) -> None: + self._handle_raw_message_call = handle_raw_message_call + self._reader = reader + self._writer = writer + self._debug_print = debug_print + self._debug_print_io = debug_print_io + if debug_print_call is None: + debug_print_call = print + self._debug_print_call: Callable[[str], None] = debug_print_call + self._label = label + self._thread = current_thread() + self._closing = False + self._did_wait_closed = False + self._event_loop = asyncio.get_running_loop() + self._out_packets: list[bytes] = [] + self._have_out_packets = asyncio.Event() + self._run_called = False + self._peer_info: Optional[_PeerInfo] = None + self._keepalive_interval = keepalive_interval + self._keepalive_timeout = keepalive_timeout + + # Need to hold weak-refs to these otherwise it creates dep-loops + # which keeps us alive. + self._tasks: list[weakref.ref[asyncio.Task]] = [] + + # When we last got a keepalive or equivalent (time.monotonic value) + self._last_keepalive_receive_time: Optional[float] = None + + # (Start near the end to make sure our looping logic is sound). + self._next_message_id = 65530 + + self._in_flight_messages: dict[int, _InFlightMessage] = {} + + if self._debug_print: + peername = self._writer.get_extra_info('peername') + self._debug_print_call( + f'{self._label}: connected to {peername} at {self._tm()}.') + + async def run(self) -> None: + """Run the endpoint until the connection is lost or closed. + + Handles closing the provided reader/writer on close. + """ + self._check_env() + + if self._run_called: + raise RuntimeError('Run can be called only once per endpoint.') + self._run_called = True + + core_tasks = [ + asyncio.create_task( + self._run_core_task('keepalive', self._run_keepalive_task())), + asyncio.create_task( + self._run_core_task('read', self._run_read_task())), + asyncio.create_task( + self._run_core_task('write', self._run_write_task())) + ] + self._tasks += [weakref.ref(t) for t in core_tasks] + + # Run our core tasks until they all complete. + results = await asyncio.gather(*core_tasks, return_exceptions=True) + + # Core tasks should handle their own errors; the only ones + # we expect to bubble up are CancelledError. + for result in results: + # We want to know if any errors happened aside from CancelledError + # (which are BaseExceptions, not Exception). + if isinstance(result, Exception): + if self._debug_print: + logging.error('Got unexpected error from %s core task: %s', + self._label, result) + + # Shut ourself down. + try: + self.close() + await self.wait_closed() + except Exception: + logging.exception('Error closing %s.', self._label) + + if self._debug_print: + self._debug_print_call(f'{self._label}: finished.') + + async def send_message(self, + message: bytes, + timeout: Optional[float] = None) -> bytes: + """Send a message to the peer and return a response. + + If timeout is not provided, the default will be used. + Raises a CommunicationError if the round trip is not completed + for any reason. + """ + self._check_env() + if len(message) > 65535: + raise RuntimeError('Message cannot be larger than 65535 bytes') + + if self._closing: + raise CommunicationError('Endpoint is closed') + + # Go with 16 bit looping value for message_id. + message_id = self._next_message_id + self._next_message_id = (self._next_message_id + 1) % 65536 + + # Payload consists of type (1b), message_id (2b), len (2b), and data. + self._enqueue_outgoing_packet( + _PacketType.MESSAGE.value.to_bytes(1, _BYTE_ORDER) + + message_id.to_bytes(2, _BYTE_ORDER) + + len(message).to_bytes(2, _BYTE_ORDER) + message) + + # Make an entry so we know this message is out there. + assert message_id not in self._in_flight_messages + msgobj = self._in_flight_messages[message_id] = _InFlightMessage() + + # Also add its task to our list so we properly cancel it if we die. + self._prune_tasks() # Keep our list from filling with dead tasks. + self._tasks.append(weakref.ref(msgobj.wait_task)) + + # Note: we always want to incorporate a timeout. Individual + # messages may hang or error on the other end and this ensures + # we won't build up lots of zombie tasks waiting around for + # responses that will never arrive. + if timeout is None: + timeout = self.DEFAULT_MESSAGE_TIMEOUT + assert timeout is not None + try: + return await asyncio.wait_for(msgobj.wait_task, timeout=timeout) + except asyncio.CancelledError as exc: + if self._debug_print: + self._debug_print_call( + f'{self._label}: message {message_id} was cancelled.') + raise CommunicationError() from exc + except asyncio.TimeoutError as exc: + if self._debug_print: + self._debug_print_call( + f'{self._label}: message {message_id} timed out.') + + # Stop waiting on the response. + msgobj.wait_task.cancel() + + # Remove the record of this message. + del self._in_flight_messages[message_id] + + # Let the user know something went wrong. + raise CommunicationError() from exc + + def close(self) -> None: + """I said seagulls; mmmm; stop it now.""" + self._check_env() + + if self._closing: + return + + if self._debug_print: + self._debug_print_call(f'{self._label}: closing...') + + self._closing = True + + # Kill all of our in-flight tasks. + if self._debug_print: + self._debug_print_call(f'{self._label}: cancelling tasks...') + for task in self._get_live_tasks(): + task.cancel() + + if self._debug_print: + self._debug_print_call(f'{self._label}: closing writer...') + self._writer.close() + + # We don't need this anymore and it is likely to be creating a + # dependency loop. + del self._handle_raw_message_call + + def is_closing(self) -> bool: + """Have we begun the process of closing?""" + return self._closing + + async def wait_closed(self) -> None: + """I said seagulls; mmmm; stop it now.""" + self._check_env() + + # Make sure we only *enter* this call once. + if self._did_wait_closed: + return + self._did_wait_closed = True + + if not self._closing: + raise RuntimeError('Must be called after close()') + + live_tasks = self._get_live_tasks() + if self._debug_print: + self._debug_print_call( + f'{self._label}: waiting for tasks to finish: ' + f' ({live_tasks=})...') + + # Wait for all of our in-flight tasks to wrap up. + results = await asyncio.gather(*live_tasks, return_exceptions=True) + for result in results: + # We want to know if any errors happened aside from CancelledError + # (which are BaseExceptions, not Exception). + if isinstance(result, Exception): + if self._debug_print: + logging.error( + 'Got unexpected error cleaning up %s task: %s', + self._label, result) + + if self._debug_print: + self._debug_print_call( + f'{self._label}: tasks finished; waiting for writer close...') + + # Now wait for our writer to finish going down. + # When we close our writer it generally triggers errors + # in our current blocked read/writes. However that same + # error is also sometimes returned from _writer.wait_closed(). + # See connection_lost() in asyncio/streams.py to see why. + # So let's silently ignore it when that happens. + assert self._writer.is_closing() + try: + # It seems that as of Python 3.9.x it is possible for this to hang + # indefinitely. See https://github.com/python/cpython/issues/83939 + # It sounds like this should be fixed in 3.11 but for now just + # forcing the issue with a timeout here. + await asyncio.wait_for(self._writer.wait_closed(), timeout=10.0) + except asyncio.TimeoutError: + logging.info('Timeout on _writer.wait_closed() for %s.', + self._label) + if self._debug_print: + self._debug_print_call( + f'{self._label}: got timeout in _writer.wait_closed();' + ' This should be fixed in future Python versions.') + except Exception as exc: + if not self._is_expected_connection_error(exc): + logging.exception('Error closing _writer for %s.', self._label) + else: + if self._debug_print: + self._debug_print_call( + f'{self._label}: silently ignoring error in' + f' _writer.wait_closed(): {exc}.') + + def _tm(self) -> str: + """Simple readable time value for debugging.""" + tval = time.time() % 100.0 + return f'{tval:.2f}' + + async def _run_read_task(self) -> None: + """Read from the peer.""" + self._check_env() + assert self._peer_info is None + + # The first thing they should send us is their handshake; then + # we'll know if/how we can talk to them. + mlen = await self._read_int_32() + message = (await self._reader.readexactly(mlen)) + self._peer_info = dataclass_from_json(_PeerInfo, message.decode()) + self._last_keepalive_receive_time = time.monotonic() + if self._debug_print: + self._debug_print_call( + f'{self._label}: received handshake at {self._tm()}.') + + # Now just sit and handle stuff as it comes in. + while True: + assert not self._closing + + # Read message type. + mtype = _PacketType(await self._read_int_8()) + if mtype is _PacketType.HANDSHAKE: + raise RuntimeError('Got multiple handshakes') + + if mtype is _PacketType.KEEPALIVE: + if self._debug_print_io: + self._debug_print_call(f'{self._label}: received keepalive' + f' at {self._tm()}.') + self._last_keepalive_receive_time = time.monotonic() + + elif mtype is _PacketType.MESSAGE: + await self._handle_message_packet() + + elif mtype is _PacketType.RESPONSE: + await self._handle_response_packet() + + else: + assert_never(mtype) + + async def _handle_message_packet(self) -> None: + msgid = await self._read_int_16() + msglen = await self._read_int_16() + msg = await self._reader.readexactly(msglen) + if self._debug_print_io: + self._debug_print_call(f'{self._label}: received message {msgid}' + f' of size {msglen} at {self._tm()}.') + + # Create a message-task to handle this message and return + # a response (we don't want to block while that happens). + assert not self._closing + self._prune_tasks() # Keep from filling with dead tasks. + self._tasks.append( + weakref.ref( + asyncio.create_task( + self._handle_raw_message(message_id=msgid, message=msg)))) + self._debug_print_call( + f'{self._label}: done handling message at {self._tm()}.') + + async def _handle_response_packet(self) -> None: + msgid = await self._read_int_16() + rsplen = await self._read_int_16() + if self._debug_print_io: + self._debug_print_call(f'{self._label}: received response {msgid}' + f' of size {rsplen} at {self._tm()}.') + rsp = await self._reader.readexactly(rsplen) + msgobj = self._in_flight_messages.get(msgid) + if msgobj is None: + # It's possible for us to get a response to a message + # that has timed out. In this case we will have no local + # record of it. + if self._debug_print: + self._debug_print_call( + f'{self._label}: got response for nonexistent' + f' message id {msgid}; perhaps it timed out?') + else: + msgobj.set_response(rsp) + + async def _run_write_task(self) -> None: + """Write to the peer.""" + + self._check_env() + + # Introduce ourself so our peer knows how it can talk to us. + data = dataclass_to_json( + _PeerInfo(protocol=OUR_PROTOCOL, + keepalive_interval=self._keepalive_interval)).encode() + self._writer.write(len(data).to_bytes(4, _BYTE_ORDER) + data) + + # Now just write out-messages as they come in. + while True: + + # Wait until some data comes in. + await self._have_out_packets.wait() + + assert self._out_packets + data = self._out_packets.pop(0) + + # Important: only clear this once all packets are sent. + if not self._out_packets: + self._have_out_packets.clear() + + self._writer.write(data) + # await self._writer.drain() + + async def _run_keepalive_task(self) -> None: + """Send periodic keepalive packets.""" + self._check_env() + + # We explicitly send our own keepalive packets so we can stay + # more on top of the connection state and possibly decide to + # kill it when contact is lost more quickly than the OS would + # do itself (or at least keep the user informed that the + # connection is lagging). It sounds like we could have the TCP + # layer do this sort of thing itself but that might be + # OS-specific so gonna go this way for now. + while True: + assert not self._closing + await asyncio.sleep(self._keepalive_interval) + if not self.test_suppress_keepalives: + self._enqueue_outgoing_packet( + _PacketType.KEEPALIVE.value.to_bytes(1, _BYTE_ORDER)) + + # Also go ahead and handle dropping the connection if we + # haven't heard from the peer in a while. + # NOTE: perhaps we want to do something more exact than + # this which only checks once per keepalive-interval?.. + now = time.monotonic() + if (self._last_keepalive_receive_time is not None + and now - self._last_keepalive_receive_time > + self._keepalive_timeout): + if self._debug_print: + since = now - self._last_keepalive_receive_time + self._debug_print_call( + f'{self._label}: reached keepalive time-out' + f' ({since:.1f}s).') + raise _KeepaliveTimeoutError() + + async def _run_core_task(self, tasklabel: str, call: Awaitable) -> None: + try: + await call + except Exception as exc: + # We expect connection errors to put us here, but make noise + # if something else does. + if not self._is_expected_connection_error(exc): + logging.exception('Unexpected error in rpc %s %s task.', + self._label, tasklabel) + else: + if self._debug_print: + self._debug_print_call( + f'{self._label}: {tasklabel} task will exit cleanly' + f' due to {exc!r}.') + finally: + # Any core task exiting triggers shutdown. + if self._debug_print: + self._debug_print_call( + f'{self._label}: {tasklabel} task exiting...') + self.close() + + async def _handle_raw_message(self, message_id: int, + message: bytes) -> None: + try: + response = await self._handle_raw_message_call(message) + except Exception: + # We expect local message handler to always succeed. + # If that doesn't happen, make a fuss so we know to fix it. + # The other end will simply never get a response to this + # message. + logging.exception('Error handling message') + return + + # Now send back our response. + # Payload consists of type (1b), msgid (2b), len (2b), and data. + self._enqueue_outgoing_packet( + _PacketType.RESPONSE.value.to_bytes(1, _BYTE_ORDER) + + message_id.to_bytes(2, _BYTE_ORDER) + + len(response).to_bytes(2, _BYTE_ORDER) + response) + + async def _read_int_8(self) -> int: + return int.from_bytes(await self._reader.readexactly(1), _BYTE_ORDER) + + async def _read_int_16(self) -> int: + return int.from_bytes(await self._reader.readexactly(2), _BYTE_ORDER) + + async def _read_int_32(self) -> int: + return int.from_bytes(await self._reader.readexactly(4), _BYTE_ORDER) + + @classmethod + def _is_expected_connection_error(cls, exc: Exception) -> bool: + """Stuff we expect to end our connection in normal circumstances.""" + + if isinstance(exc, _KeepaliveTimeoutError): + return True + + return is_asyncio_streams_network_error(exc) + + def _check_env(self) -> None: + # I was seeing that asyncio stuff wasn't working as expected if + # created in one thread and used in another, so let's enforce + # a single thread for all use of an instance. + if current_thread() is not self._thread: + raise RuntimeError('This must be called from the same thread' + ' that the endpoint was created in.') + + # This should always be the case if thread is the same. + assert asyncio.get_running_loop() is self._event_loop + + def _enqueue_outgoing_packet(self, data: bytes) -> None: + """Enqueue a raw packet to be sent. Must be called from our loop.""" + self._check_env() + + if self._debug_print_io: + self._debug_print_call(f'{self._label}: enqueueing outgoing packet' + f' {data[:50]!r} at {self._tm()}.') + + # Add the data and let our write task know about it. + self._out_packets.append(data) + self._have_out_packets.set() + + def _prune_tasks(self) -> None: + out: list[weakref.ref[asyncio.Task]] = [] + for task_weak_ref in self._tasks: + task = task_weak_ref() + if task is not None and not task.done(): + out.append(task_weak_ref) + self._tasks = out + + def _get_live_tasks(self) -> list[asyncio.Task]: + out: list[asyncio.Task] = [] + for task_weak_ref in self._tasks: + task = task_weak_ref() + if task is not None and not task.done(): + out.append(task) + return out diff --git a/dist/ba_data/python/efro/util.py b/dist/ba_data/python/efro/util.py index 14d8bc1..d18e505 100644 --- a/dist/ba_data/python/efro/util.py +++ b/dist/ba_data/python/efro/util.py @@ -4,9 +4,10 @@ from __future__ import annotations -import datetime +import os import time import weakref +import datetime import functools from enum import Enum from typing import TYPE_CHECKING, cast, TypeVar, Generic @@ -23,7 +24,7 @@ except ModuleNotFoundError: if TYPE_CHECKING: import asyncio from efro.call import Call as Call # 'as Call' so we re-export. - from typing import Any, Callable, Optional, NoReturn + from typing import Any, Callable, NoReturn T = TypeVar('T') TVAL = TypeVar('TVAL') @@ -176,15 +177,15 @@ class DirtyBit: retry_interval: float = 5.0, use_lock: bool = False, auto_dirty_seconds: float = None, - min_update_interval: Optional[float] = None): + min_update_interval: float | None = None): curtime = time.time() self._retry_interval = retry_interval self._auto_dirty_seconds = auto_dirty_seconds self._min_update_interval = min_update_interval self._dirty = dirty - self._next_update_time: Optional[float] = (curtime if dirty else None) - self._last_update_time: Optional[float] = None - self._next_auto_dirty_time: Optional[float] = ( + self._next_update_time: float | None = (curtime if dirty else None) + self._last_update_time: float | None = None + self._next_auto_dirty_time: float | None = ( (curtime + self._auto_dirty_seconds) if (not dirty and self._auto_dirty_seconds is not None) else None) self._use_lock = use_lock @@ -475,7 +476,7 @@ def asserttype(obj: Any, typ: type[T]) -> T: return obj -def asserttype_o(obj: Any, typ: type[T]) -> Optional[T]: +def asserttype_o(obj: Any, typ: type[T]) -> T | None: """Return an object typed as a given optional type. Assert is used to check its actual type, so only use this when @@ -498,7 +499,7 @@ def checktype(obj: Any, typ: type[T]) -> T: return obj -def checktype_o(obj: Any, typ: type[T]) -> Optional[T]: +def checktype_o(obj: Any, typ: type[T]) -> T | None: """Return an object typed as a given optional type. Always checks the type at runtime with isinstance and throws a TypeError @@ -523,7 +524,7 @@ def warntype(obj: Any, typ: type[T]) -> T: return obj # type: ignore -def warntype_o(obj: Any, typ: type[T]) -> Optional[T]: +def warntype_o(obj: Any, typ: type[T]) -> T | None: """Return an object typed as a given type. Always checks the type at runtime and simply logs a warning if it is @@ -537,7 +538,7 @@ def warntype_o(obj: Any, typ: type[T]) -> Optional[T]: return obj # type: ignore -def assert_non_optional(obj: Optional[T]) -> T: +def assert_non_optional(obj: T | None) -> T: """Return an object with Optional typing removed. Assert is used to check its actual type, so only use this when @@ -547,7 +548,7 @@ def assert_non_optional(obj: Optional[T]) -> T: return obj -def check_non_optional(obj: Optional[T]) -> T: +def check_non_optional(obj: T | None) -> T: """Return an object with Optional typing removed. Always checks the actual type and throws a TypeError on failure. @@ -652,7 +653,6 @@ def unchanging_hostname() -> str: network conditions. (A Mac will tend to go from Foo to Foo.local, Foo.lan etc. throughout its various adventures) """ - import os import platform import subprocess @@ -663,3 +663,28 @@ def unchanging_hostname() -> str: check=True, capture_output=True).stdout.decode().strip().replace(' ', '-') return os.uname().nodename + + +def set_canonical_module(module_globals: dict[str, Any], + names: list[str]) -> None: + """Override any __module__ attrs on passed classes/etc. + + This allows classes to present themselves using clean paths such as + mymodule.MyClass instead of possibly ugly internal ones such as + mymodule._internal._stuff.MyClass. + """ + modulename = module_globals.get('__name__') + if not isinstance(modulename, str): + raise RuntimeError('Unable to get module name.') + for name in names: + obj = module_globals[name] + existing = getattr(obj, '__module__', None) + try: + if existing is not None and existing != modulename: + obj.__module__ = modulename + except Exception: + import logging + logging.warning( + 'set_canonical_module: unable to change __module__' + " from '%s' to '%s' on %s object at '%s'.", existing, + modulename, type(obj), name) diff --git a/dist/ba_root/mods/.idea/.gitignore b/dist/ba_root/mods/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/dist/ba_root/mods/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/dist/ba_root/mods/.idea/inspectionProfiles/profiles_settings.xml b/dist/ba_root/mods/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/dist/ba_root/mods/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/dist/ba_root/mods/.idea/misc.xml b/dist/ba_root/mods/.idea/misc.xml new file mode 100644 index 0000000..fa2a2fb --- /dev/null +++ b/dist/ba_root/mods/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dist/ba_root/mods/.idea/mods.iml b/dist/ba_root/mods/.idea/mods.iml new file mode 100644 index 0000000..8b8c395 --- /dev/null +++ b/dist/ba_root/mods/.idea/mods.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/dist/ba_root/mods/.idea/modules.xml b/dist/ba_root/mods/.idea/modules.xml new file mode 100644 index 0000000..51a65ae --- /dev/null +++ b/dist/ba_root/mods/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/dist/ba_root/mods/.idea/vcs.xml b/dist/ba_root/mods/.idea/vcs.xml new file mode 100644 index 0000000..c2365ab --- /dev/null +++ b/dist/ba_root/mods/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/dist/ba_root/mods/chatHandle/ChatCommands/commands/Management.py b/dist/ba_root/mods/chatHandle/ChatCommands/commands/Management.py index df3bad7..975bd7d 100644 --- a/dist/ba_root/mods/chatHandle/ChatCommands/commands/Management.py +++ b/dist/ba_root/mods/chatHandle/ChatCommands/commands/Management.py @@ -301,7 +301,7 @@ def add_role_to_player(arguments): session = _ba.get_foreground_host_session() for i in session.sessionplayers: if i.inputdevice.client_id== int(arguments[1]): - roles=pdata.add_player_role(arguments[0],i.get_account_id()) + roles=pdata.add_player_role(arguments[0],i.get_v1_account_id()) except: return @@ -312,7 +312,7 @@ def remove_role_from_player(arguments): session = _ba.get_foreground_host_session() for i in session.sessionplayers: if i.inputdevice.client_id== int(arguments[1]): - roles=pdata.remove_player_role(arguments[0],i.get_account_id()) + roles=pdata.remove_player_role(arguments[0],i.get_v1_account_id()) except: return @@ -323,7 +323,7 @@ def get_roles_of_player(arguments,clientid): reply="" for i in session.sessionplayers: if i.inputdevice.client_id== int(arguments[0]): - roles=pdata.get_player_roles(i.get_account_id()) + roles=pdata.get_player_roles(i.get_v1_account_id()) print(roles) for role in roles: reply=reply+role+"," @@ -341,7 +341,7 @@ def set_custom_tag(arguments): session = _ba.get_foreground_host_session() for i in session.sessionplayers: if i.inputdevice.client_id== int(arguments[1]): - roles=pdata.set_tag(arguments[0],i.get_account_id()) + roles=pdata.set_tag(arguments[0],i.get_v1_account_id()) except: return def set_custom_effect(arguments): @@ -349,7 +349,7 @@ def set_custom_effect(arguments): session = _ba.get_foreground_host_session() for i in session.sessionplayers: if i.inputdevice.client_id== int(arguments[1]): - roles=pdata.set_effect(arguments[0],i.get_account_id()) + roles=pdata.set_effect(arguments[0],i.get_v1_account_id()) except: return diff --git a/dist/ba_root/mods/chatHandle/ChatCommands/commands/NormalCommands.py b/dist/ba_root/mods/chatHandle/ChatCommands/commands/NormalCommands.py index b16042b..180be9b 100644 --- a/dist/ba_root/mods/chatHandle/ChatCommands/commands/NormalCommands.py +++ b/dist/ba_root/mods/chatHandle/ChatCommands/commands/NormalCommands.py @@ -80,7 +80,7 @@ def accountid_request(arguments, clientid, accountid): player = session.sessionplayers[int(arguments[0])] name = player.getname(full=True, icon=True) - accountid = player.get_account_id() + accountid = player.get_v1_account_id() send(f" {name}'s account id is '{accountid}' ", clientid) except: diff --git a/dist/ba_root/mods/features/StumbledScoreScreen.so b/dist/ba_root/mods/features/StumbledScoreScreen.so index cd70ca2..ce53e62 100644 Binary files a/dist/ba_root/mods/features/StumbledScoreScreen.so and b/dist/ba_root/mods/features/StumbledScoreScreen.so differ diff --git a/dist/ba_root/mods/features/afk_check.py b/dist/ba_root/mods/features/afk_check.py index 9a588d4..ad64e9d 100644 --- a/dist/ba_root/mods/features/afk_check.py +++ b/dist/ba_root/mods/features/afk_check.py @@ -18,7 +18,7 @@ class checkIdle(object): last_input=int(player.inputdevice.get_last_input_time()) afk_time=int((current-last_input)/1000) if afk_time in range(INGAME_TIME,INGAME_TIME+20): - self.warn_player(player.get_account_id(),"Press any button within "+str(INGAME_TIME+20-afk_time)+" secs") + self.warn_player(player.get_v1_account_id(),"Press any button within "+str(INGAME_TIME+20-afk_time)+" secs") if afk_time > INGAME_TIME+20: player.remove_from_game() if LOBBY_KICK: diff --git a/dist/ba_root/mods/features/team_balancer.py b/dist/ba_root/mods/features/team_balancer.py index b9764e8..ff2c335 100644 --- a/dist/ba_root/mods/features/team_balancer.py +++ b/dist/ba_root/mods/features/team_balancer.py @@ -42,8 +42,8 @@ def movePlayers(fromTeam,toTeam,count): toTeam=session.sessionteams[toTeam] for i in range(0,count): player=fromTeam.players.pop() - print("moved"+player.get_account_id()) - broadCastShiftMsg(player.get_account_id()) + print("moved"+player.get_v1_account_id()) + broadCastShiftMsg(player.get_v1_account_id()) player.setdata(team=toTeam,character=player.character,color=toTeam.color,highlight=player.highlight) iconinfo=player.get_icon_info() player.set_icon_info(iconinfo['texture'],iconinfo['tint_texture'],toTeam.color,player.highlight) diff --git a/dist/ba_root/mods/games/BlockDash.so b/dist/ba_root/mods/games/BlockDash.so new file mode 100644 index 0000000..97e7268 Binary files /dev/null and b/dist/ba_root/mods/games/BlockDash.so differ diff --git a/dist/ba_root/mods/games/CanonFight.so b/dist/ba_root/mods/games/CanonFight.so index e42aa43..01c3308 100644 Binary files a/dist/ba_root/mods/games/CanonFight.so and b/dist/ba_root/mods/games/CanonFight.so differ diff --git a/dist/ba_root/mods/games/DuelElimination.so b/dist/ba_root/mods/games/DuelElimination.so index 3a5acaa..e58fa98 100644 Binary files a/dist/ba_root/mods/games/DuelElimination.so and b/dist/ba_root/mods/games/DuelElimination.so differ diff --git a/dist/ba_root/mods/games/FlappyBird.so b/dist/ba_root/mods/games/FlappyBird.so index 9c7d37e..16f9c48 100644 Binary files a/dist/ba_root/mods/games/FlappyBird.so and b/dist/ba_root/mods/games/FlappyBird.so differ diff --git a/dist/ba_root/mods/games/MonkeyClimb.so b/dist/ba_root/mods/games/MonkeyClimb.so index 9df8122..c480b31 100644 Binary files a/dist/ba_root/mods/games/MonkeyClimb.so and b/dist/ba_root/mods/games/MonkeyClimb.so differ diff --git a/dist/ba_root/mods/games/OneNightNoStand.so b/dist/ba_root/mods/games/OneNightNoStand.so index 07a0abb..a96b2d6 100644 Binary files a/dist/ba_root/mods/games/OneNightNoStand.so and b/dist/ba_root/mods/games/OneNightNoStand.so differ diff --git a/dist/ba_root/mods/games/SquidRace.so b/dist/ba_root/mods/games/SquidRace.so index 108569c..79af31f 100644 Binary files a/dist/ba_root/mods/games/SquidRace.so and b/dist/ba_root/mods/games/SquidRace.so differ diff --git a/dist/ba_root/mods/games/StumbleRace.so b/dist/ba_root/mods/games/StumbleRace.so index 5169f9d..6a8eccf 100644 Binary files a/dist/ba_root/mods/games/StumbleRace.so and b/dist/ba_root/mods/games/StumbleRace.so differ diff --git a/dist/ba_root/mods/games/SubwayRun.so b/dist/ba_root/mods/games/SubwayRun.so index a3a7ce1..1e7e010 100644 Binary files a/dist/ba_root/mods/games/SubwayRun.so and b/dist/ba_root/mods/games/SubwayRun.so differ diff --git a/dist/ba_root/mods/games/UFOAttackGame.so b/dist/ba_root/mods/games/UFOAttackGame.so new file mode 100644 index 0000000..23fc6d2 Binary files /dev/null and b/dist/ba_root/mods/games/UFOAttackGame.so differ diff --git a/dist/ba_root/mods/maps/CreativeThoughts.so b/dist/ba_root/mods/maps/CreativeThoughts.so index f94b788..f84b2d6 100644 Binary files a/dist/ba_root/mods/maps/CreativeThoughts.so and b/dist/ba_root/mods/maps/CreativeThoughts.so differ diff --git a/dist/ba_root/mods/maps/FloatingIsland.so b/dist/ba_root/mods/maps/FloatingIsland.so index 31881b3..d5a9c18 100644 Binary files a/dist/ba_root/mods/maps/FloatingIsland.so and b/dist/ba_root/mods/maps/FloatingIsland.so differ diff --git a/dist/ba_root/mods/maps/InTheAir.so b/dist/ba_root/mods/maps/InTheAir.so index c716b35..adfb89a 100644 Binary files a/dist/ba_root/mods/maps/InTheAir.so and b/dist/ba_root/mods/maps/InTheAir.so differ diff --git a/dist/ba_root/mods/maps/soccerStadiumPro.so b/dist/ba_root/mods/maps/soccerStadiumPro.so new file mode 100644 index 0000000..e8c686c Binary files /dev/null and b/dist/ba_root/mods/maps/soccerStadiumPro.so differ diff --git a/dist/ba_root/mods/plugins/bcs_plugin.py b/dist/ba_root/mods/plugins/bcs_plugin.py index fd95ada..aee1a93 100644 --- a/dist/ba_root/mods/plugins/bcs_plugin.py +++ b/dist/ba_root/mods/plugins/bcs_plugin.py @@ -97,7 +97,7 @@ class BsDataThread(object): 'device_id':player.inputdevice.get_account_name(True), 'inGame':player.in_game, 'character':player.character, - 'account_id':player.get_account_id() + 'account_id':player.get_v1_account_id() } data[team.id]['players'].append(teamplayer) diff --git a/dist/ba_root/mods/spazmod/effects.py b/dist/ba_root/mods/spazmod/effects.py index 2ea1aa1..ddb5de7 100644 --- a/dist/ba_root/mods/spazmod/effects.py +++ b/dist/ba_root/mods/spazmod/effects.py @@ -160,7 +160,7 @@ class Effect(ba.Actor): if (c.activityplayer) and (c.activityplayer.node.playerID == node_id): profiles = c.inputdevice.get_player_profiles() clID = c.inputdevice.client_id - cl_str = c.get_account_id() + cl_str = c.get_v1_account_id() try: if cl_str in custom_effects: diff --git a/dist/ba_root/mods/spazmod/hitmessage.py b/dist/ba_root/mods/spazmod/hitmessage.py index abf3c1e..c1e03ba 100644 --- a/dist/ba_root/mods/spazmod/hitmessage.py +++ b/dist/ba_root/mods/spazmod/hitmessage.py @@ -20,7 +20,7 @@ def handle_hit(msg, hp, dmg, hit_by, msg_pos): hit_by_account_id = None for c in _ba.get_foreground_host_session().sessionplayers: if (c.activityplayer) and (c.activityplayer.node.playerID == hit_by_id): - hit_by_account_id = c.get_account_id() + hit_by_account_id = c.get_v1_account_id() if hit_by_account_id in damage_data: damage_data[hit_by_account_id] += float(dmg) else: damage_data[hit_by_account_id] = float(dmg) #Send Screen Texts in enabled diff --git a/dist/ba_root/mods/spazmod/tag.py b/dist/ba_root/mods/spazmod/tag.py index 544882c..447db86 100644 --- a/dist/ba_root/mods/spazmod/tag.py +++ b/dist/ba_root/mods/spazmod/tag.py @@ -3,7 +3,7 @@ from playersData import pdata import ba, setting def addtag(node,player): session_player=player.sessionplayer - account_id=session_player.get_account_id() + account_id=session_player.get_v1_account_id() customtag_=pdata.get_custom() customtag=customtag_['customtag'] roles=pdata.get_roles() @@ -25,7 +25,7 @@ def addtag(node,player): from stats import mystats def addrank(node,player): session_player=player.sessionplayer - account_id=session_player.get_account_id() + account_id=session_player.get_v1_account_id() rank=mystats.getRank(account_id) if rank: diff --git a/dist/ba_root/mods/stats/mystats.py b/dist/ba_root/mods/stats/mystats.py index e6eda33..092d27e 100644 --- a/dist/ba_root/mods/stats/mystats.py +++ b/dist/ba_root/mods/stats/mystats.py @@ -217,7 +217,7 @@ def update(score_set): account_scores = {} for p_entry in score_set.get_records().values(): - account_id = p_entry.player.get_account_id() + account_id = p_entry.player.get_v1_account_id() if account_id is not None: account_kills.setdefault(account_id, 0) # make sure exists account_kills[account_id] += p_entry.accum_kill_count diff --git a/dist/ba_root/mods/tools/corelib.so b/dist/ba_root/mods/tools/corelib.so index 0a38431..5694d6e 100644 Binary files a/dist/ba_root/mods/tools/corelib.so and b/dist/ba_root/mods/tools/corelib.so differ diff --git a/dist/bombsquad_headless b/dist/bombsquad_headless index f62f0b0..22c2e6d 100644 Binary files a/dist/bombsquad_headless and b/dist/bombsquad_headless differ