From 628affa2610a1b0793b62b7d4c3ca9b5431eb2c5 Mon Sep 17 00:00:00 2001 From: Alberto Spelta Date: Fri, 1 Mar 2024 11:37:07 +0100 Subject: [PATCH 1/6] Add ObfuscatorTest PBIX --- assets/ObfuscatorTest.pbix | Bin 0 -> 15324 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/ObfuscatorTest.pbix diff --git a/assets/ObfuscatorTest.pbix b/assets/ObfuscatorTest.pbix new file mode 100644 index 0000000000000000000000000000000000000000..a413b4cd6331439a613276d3b0749d66b1d8a466 GIT binary patch literal 15324 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 literal 0 HcmV?d00001 From 58f08e3e2ab6729a548d43de770dc01b97b1d6d0 Mon Sep 17 00:00:00 2001 From: Alberto Spelta Date: Fri, 1 Mar 2024 13:38:00 +0100 Subject: [PATCH 2/6] Refactor rename vars/methods in unit test --- .../DaxModelObfuscatorTests.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Dax.Vpax.Obfuscator.Tests/DaxModelObfuscatorTests.cs b/tests/Dax.Vpax.Obfuscator.Tests/DaxModelObfuscatorTests.cs index cf39476..46b17a6 100644 --- a/tests/Dax.Vpax.Obfuscator.Tests/DaxModelObfuscatorTests.cs +++ b/tests/Dax.Vpax.Obfuscator.Tests/DaxModelObfuscatorTests.cs @@ -68,7 +68,7 @@ public void ObfuscateExpression_TableConstructorColumnName_IsNotObfuscated_Multi } [Fact] - public void ObfuscateExpression_ExtensionColumnNameWithDifferentCasings_ReturnsSameObfuscatedValue() + public void ObfuscateExpression_ExtensionColumnNameMultipleReferencesWithDifferentCasings_ReturnsSameObfuscatedValue() { var expression = """ SUMX(ADDCOLUMNS(Date, "@column", 1), [@COLUMN]) """; var expected = """ SUMX(ADDCOLUMNS(Date, "XXXXXXX", 1), [XXXXXXX]) """; @@ -81,13 +81,13 @@ public void ObfuscateExpression_ExtensionColumnNameWithDifferentCasings_ReturnsS } [Fact] - public void ObfuscateExpression_ExtensionColumnName_ReturnsObfuscatedTableNameAndColumnNameParts() + public void ObfuscateExpression_ExtensionColumnNameFullyQualified_ReturnsObfuscatedColumnNameParts() { - var expression = """ SUMX(ADDCOLUMNS(Date, "__rate[%]", 1), __rate[%]) """; - var expected = """ SUMX(ADDCOLUMNS(Date, "XXXXXX[Y]", 1), XXXXXX[Y]) """; + var expression = """ SUMX(ADDCOLUMNS(Date, "rate[%]", 1), rate[%]) """; + var expected = """ SUMX(ADDCOLUMNS(Date, "XXXX[Y]", 1), XXXX[Y]) """; var obfuscator = new DaxModelObfuscator(new Model()); - obfuscator.Texts.Add(new DaxText("__rate", "XXXXXX")); + obfuscator.Texts.Add(new DaxText("rate", "XXXX")); obfuscator.Texts.Add(new DaxText("%", "Y")); var actual = obfuscator.ObfuscateExpression(expression); @@ -95,7 +95,7 @@ public void ObfuscateExpression_ExtensionColumnName_ReturnsObfuscatedTableNameAn } [Fact] - public void ObfuscateExpression_ExtensionColumnName_ReturnsObfuscatedValuePreservingEscapeChar() + public void ObfuscateExpression_ExtensionColumnNameFullyQualified_ReturnsObfuscatedColumnNamePartsPreservingQuotationMarkEscapeChar() { var expression = """ SELECTCOLUMNS(ADDCOLUMNS(Date, "aaa[b""c]", 1), aaa[b"c]) """; var expected = """ SELECTCOLUMNS(ADDCOLUMNS(Date, "XXX[Y""Y]", 1), XXX[Y"Y]) """; @@ -122,7 +122,7 @@ public void ObfuscateExpression_TableNameWithDifferentCasings_ReturnsSameObfusca } [Fact] - public void ObfuscateExpression_ColumnNameWithEscapeSquareBracket_ReturnsObfuscatedValuePreservingEscapeChar() + public void ObfuscateExpression_ColumnName_ReturnsObfuscatedValuePreservingSquareBracketEscapeChar() { var expression = "RELATED( Sales[Rate[%]]] )"; var expected = "RELATED( XXXXX[YYYYYY]]] )"; From ec2a6bc56ee09c80c2fe68568087bc0f7e176df2 Mon Sep 17 00:00:00 2001 From: Alberto Spelta Date: Fri, 1 Mar 2024 20:17:05 +0100 Subject: [PATCH 3/6] Fix fully qualified extension column name obfuscation Table and column name parts are separately obfuscated when the name contains square brackets. e.g. Sales[Rate[%]]] > XXXXX[YYYY[Z]]] insted of previous XXXXX[YYYYYY]]] --- ...ModelDeobfuscator.DeobfuscateExpression.cs | 20 +++++++++++----- .../DaxModelObfuscator.ObfuscateExpression.cs | 24 ++++++++++++------- .../Extensions/DaxTokenExtensions.cs | 8 +++---- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/Dax.Vpax.Obfuscator/DaxModelDeobfuscator.DeobfuscateExpression.cs b/src/Dax.Vpax.Obfuscator/DaxModelDeobfuscator.DeobfuscateExpression.cs index f597444..7e9c8bf 100644 --- a/src/Dax.Vpax.Obfuscator/DaxModelDeobfuscator.DeobfuscateExpression.cs +++ b/src/Dax.Vpax.Obfuscator/DaxModelDeobfuscator.DeobfuscateExpression.cs @@ -38,7 +38,8 @@ internal string DeobfuscateExpression(string expression) case DaxToken.COLUMN_OR_MEASURE when token.IsReservedExtensionColumn(): tokenText = token.Replace(expression, tokenText); break; - case DaxToken.STRING_LITERAL when token.IsExtensionColumnName(): + case DaxToken.COLUMN_OR_MEASURE when token.IsFullyQualifiedColumnName(): + case DaxToken.STRING_LITERAL when token.IsFullyQualifiedColumnName(): tokenText = ReplaceExtensionColumnName(token); break; case DaxToken.TABLE_OR_VARIABLE when token.IsVariable(): @@ -59,12 +60,19 @@ internal string DeobfuscateExpression(string expression) string ReplaceExtensionColumnName(DaxToken token) { - var (tableName, columnName) = token.GetExtensionColumnNameParts(); - tableName = _dictionary.GetValue(tableName); - columnName = _dictionary.GetValue(columnName); + var (tableName, columnName) = token.GetFullyQualifiedColumnNameParts(); + var table = _dictionary.GetValue(tableName); + var column = _dictionary.GetValue(columnName); - var value = $"{tableName.DaxEscape()}[{columnName.DaxEscape()}]"; - return token.Replace(expression, value, escape: true); + var escape = token.Type == DaxToken.STRING_LITERAL; + if (escape) + { + table = table.DaxEscape(); + column = column.DaxEscape(); + } + + var value = $"{table}[{column}]"; + return token.Replace(expression, value, escape); } } } diff --git a/src/Dax.Vpax.Obfuscator/DaxModelObfuscator.ObfuscateExpression.cs b/src/Dax.Vpax.Obfuscator/DaxModelObfuscator.ObfuscateExpression.cs index 3fd3fa3..9459880 100644 --- a/src/Dax.Vpax.Obfuscator/DaxModelObfuscator.ObfuscateExpression.cs +++ b/src/Dax.Vpax.Obfuscator/DaxModelObfuscator.ObfuscateExpression.cs @@ -38,8 +38,9 @@ internal string ObfuscateExpression(string expression) case DaxToken.COLUMN_OR_MEASURE when token.IsReservedExtensionColumn(): tokenText = token.Replace(expression, tokenText); break; - case DaxToken.STRING_LITERAL when token.IsExtensionColumnName(): - tokenText = ReplaceExtensionColumnName(token); + case DaxToken.COLUMN_OR_MEASURE when token.IsFullyQualifiedColumnName(): + case DaxToken.STRING_LITERAL when token.IsFullyQualifiedColumnName(): + tokenText = ReplaceFullyQualifiedColumnName(token); break; case DaxToken.TABLE_OR_VARIABLE when token.IsVariable(): case DaxToken.TABLE: @@ -57,14 +58,21 @@ internal string ObfuscateExpression(string expression) return builder.ToString(); - string ReplaceExtensionColumnName(DaxToken token) + string ReplaceFullyQualifiedColumnName(DaxToken token) { - var (tableName, columnName) = token.GetExtensionColumnNameParts(); - var tableText = ObfuscateText(new DaxText(tableName)); - var columnText = ObfuscateText(new DaxText(columnName)); + var (tableName, columnName) = token.GetFullyQualifiedColumnNameParts(); + var table = ObfuscateText(new DaxText(tableName)).ObfuscatedValue; + var column = ObfuscateText(new DaxText(columnName)).ObfuscatedValue; - var value = $"{tableText.ObfuscatedValue.DaxEscape()}[{columnText.ObfuscatedValue.DaxEscape()}]"; - return token.Replace(expression, value, escape: true); + var escape = token.Type == DaxToken.STRING_LITERAL; + if (escape) + { + table = table.DaxEscape(); + column = column.DaxEscape(); + } + + var value = $"{table}[{column}]"; + return token.Replace(expression, value, escape); } } } diff --git a/src/Dax.Vpax.Obfuscator/Extensions/DaxTokenExtensions.cs b/src/Dax.Vpax.Obfuscator/Extensions/DaxTokenExtensions.cs index 0377fe2..8c6f3ed 100644 --- a/src/Dax.Vpax.Obfuscator/Extensions/DaxTokenExtensions.cs +++ b/src/Dax.Vpax.Obfuscator/Extensions/DaxTokenExtensions.cs @@ -5,8 +5,8 @@ namespace Dax.Vpax.Obfuscator.Extensions; internal static class DaxTokenExtensions { - public static bool IsExtensionColumnName(this DaxToken token) - => token.Type == DaxToken.STRING_LITERAL && token.Text.EndsWith("]") && token.Text.IndexOf('[') > 0; + public static bool IsFullyQualifiedColumnName(this DaxToken token) + => token.Text.EndsWith("]") && token.Text.IndexOf('[') > 0; public static bool IsVariable(this DaxToken token) => token.Type == DaxToken.TABLE_OR_VARIABLE && !IsFunction(token); @@ -44,9 +44,9 @@ public static bool IsReservedExtensionColumn(this DaxToken token) return false; } - public static (string tableName, string columnName) GetExtensionColumnNameParts(this DaxToken token) + public static (string tableName, string columnName) GetFullyQualifiedColumnNameParts(this DaxToken token) { - Debug.Assert(token.IsExtensionColumnName()); + Debug.Assert(token.IsFullyQualifiedColumnName()); var openIndex = token.Text.IndexOf('['); var closeIndex = token.Text.LastIndexOf(']'); From 646c2f0d95964e5970bdd8567c75ba010d550e3b Mon Sep 17 00:00:00 2001 From: Alberto Spelta Date: Fri, 1 Mar 2024 20:26:48 +0100 Subject: [PATCH 4/6] Reactor, rename unit test methods --- .../DaxModelDeobfuscatorTests.cs | 24 ++++++++----------- .../DaxModelObfuscatorTests.cs | 2 +- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/tests/Dax.Vpax.Obfuscator.Tests/DaxModelDeobfuscatorTests.cs b/tests/Dax.Vpax.Obfuscator.Tests/DaxModelDeobfuscatorTests.cs index 5553e4b..20a5bcf 100644 --- a/tests/Dax.Vpax.Obfuscator.Tests/DaxModelDeobfuscatorTests.cs +++ b/tests/Dax.Vpax.Obfuscator.Tests/DaxModelDeobfuscatorTests.cs @@ -1,10 +1,6 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Linq.Expressions; -using Dax.Metadata; +using Dax.Metadata; using Dax.Vpax.Obfuscator.Common; using Dax.Vpax.Obfuscator.Tests.TestUtils; -using Dax.Tokenizer; using Xunit; namespace Dax.Vpax.Obfuscator.Tests; @@ -81,7 +77,7 @@ public void DeobfuscateExpression_TableConstructorColumnName_IsNotDeobfuscatedBe } [Fact] - public void DeobfuscateExpression_ExtensionColumnNameWithDifferentCasings_ReturnsSameDeobfuscatedValue() + public void DeobfuscateExpression_ExtensionColumnNameMultipleReferencesWithDifferentCasings_ReturnsSameDeobfuscatedValue() { var expression = """ SUMX(ADDCOLUMNS(Date, "XXXXXXX", 1), [XXXXXXX]) """; var expected = """ SUMX(ADDCOLUMNS(Date, "@column", 1), [@COLUMN]) """; @@ -97,15 +93,15 @@ public void DeobfuscateExpression_ExtensionColumnNameWithDifferentCasings_Return } [Fact] - public void DeobfuscateExpression_ExtensionColumnName_ReturnsDeobfuscatedTableNameAndColumnNameParts() + public void DeobfuscateExpression_ExtensionColumnNameFullyQualified_ReturnsDeobfuscatedColumnNameParts() { - var expression = """ SUMX(ADDCOLUMNS(Date, "XXXXXX[Y]", 1), XXXXXX[Y]) """; - var expected = """ SUMX(ADDCOLUMNS(Date, "__rate[%]", 1), __rate[%]) """; + var expression = """ SUMX(ADDCOLUMNS(Date, "XXXX[Y]", 1), XXXX[Y]) """; + var expected = """ SUMX(ADDCOLUMNS(Date, "rate[%]", 1), rate[%]) """; var (_, _, deobfuscator) = CreateTest( [ new ObfuscationText("Date", "Date"), - new ObfuscationText("__rate", "XXXXXX"), + new ObfuscationText("rate", "XXXX"), new ObfuscationText("%", "Y"), ]); var actual = deobfuscator.DeobfuscateExpression(expression); @@ -114,7 +110,7 @@ public void DeobfuscateExpression_ExtensionColumnName_ReturnsDeobfuscatedTableNa } [Fact] - public void DeobfuscateExpression_ExtensionColumnName_ReturnsDeobfuscatedValuePreservingEscapeChar() + public void DeobfuscateExpression_ExtensionColumnNameFullyQualified_ReturnsDeobfuscatedColumnNamePartsPreservingQuotationMarkEscapeChar() { var expression = """ SELECTCOLUMNS(ADDCOLUMNS(Date, "XXX[Y""Y]", 1), XXX[Y"Y]) """; var expected = """ SELECTCOLUMNS(ADDCOLUMNS(Date, "aaa[b""c]", 1), aaa[b"c]) """; @@ -131,7 +127,7 @@ public void DeobfuscateExpression_ExtensionColumnName_ReturnsDeobfuscatedValuePr } [Fact] - public void DeobfuscateExpression_TableNameWithDifferentCasings_ReturnsSameDeobfuscatedValue() + public void DeobfuscateExpression_TableNameMultipleReferencesWithDifferentCasings_ReturnsSameDeobfuscatedValue() { var expression = "COUNTROWS('XXXXX') + COUNTROWS(XXXXX) + COUNTROWS(XXXXX) + COUNTROWS(XXXXX)"; var expected = "COUNTROWS('Sales') + COUNTROWS(sales) + COUNTROWS(SALES) + COUNTROWS(SaLeS)"; @@ -146,7 +142,7 @@ public void DeobfuscateExpression_TableNameWithDifferentCasings_ReturnsSameDeobf } [Fact] - public void DeobfuscateExpression_ColumnNameWithEscapeSquareBracket_ReturnsDeobfuscatedValuePreservingEscapeChar() + public void DeobfuscateExpression_ColumnName_ReturnsDeobfuscatedValuePreservingSquareBracketEscapeChar() { var expression = "RELATED( XXXXX[YYYYYY]]] )"; var expected = "RELATED( Sales[Rate[%]]] )"; @@ -162,7 +158,7 @@ public void DeobfuscateExpression_ColumnNameWithEscapeSquareBracket_ReturnsDeobf } [Fact] - public void DeobfuscateExpression_VariableNameWithDifferentCasings_ReturnsSameDeobfuscatedValue() + public void DeobfuscateExpression_VariableNameMultipleReferencesWithDifferentCasings_ReturnsSameDeobfuscatedValue() { var expression = "VAR XXXXXX = 1 RETURN XXXXXX + XXXXXX + XXXXXX"; var expected = "VAR Amount = 1 RETURN AMOUNT + AmOuNt + amount"; diff --git a/tests/Dax.Vpax.Obfuscator.Tests/DaxModelObfuscatorTests.cs b/tests/Dax.Vpax.Obfuscator.Tests/DaxModelObfuscatorTests.cs index 46b17a6..8710de6 100644 --- a/tests/Dax.Vpax.Obfuscator.Tests/DaxModelObfuscatorTests.cs +++ b/tests/Dax.Vpax.Obfuscator.Tests/DaxModelObfuscatorTests.cs @@ -136,7 +136,7 @@ public void ObfuscateExpression_ColumnName_ReturnsObfuscatedValuePreservingSquar } [Fact] - public void ObfuscateExpression_VariableNameWithDifferentCasings_ReturnsSameObfuscatedValue() + public void ObfuscateExpression_VariableNameMultipleReferencesWithDifferentCasings_ReturnsSameObfuscatedValue() { var expression = "VAR Amount = 1 RETURN AMOUNT + AmOuNt + amount"; var expected = "VAR XXXXXX = 1 RETURN XXXXXX + XXXXXX + XXXXXX"; From 8862ac9cd0ae493f96156e801a557e1c0a51c971 Mon Sep 17 00:00:00 2001 From: Alberto Spelta Date: Fri, 1 Mar 2024 21:57:56 +0100 Subject: [PATCH 5/6] Revert "Fix fully qualified extension column name obfuscation" This reverts commit ec2a6bc56ee09c80c2fe68568087bc0f7e176df2. --- ...ModelDeobfuscator.DeobfuscateExpression.cs | 20 +++++----------- .../DaxModelObfuscator.ObfuscateExpression.cs | 24 +++++++------------ .../Extensions/DaxTokenExtensions.cs | 8 +++---- 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/src/Dax.Vpax.Obfuscator/DaxModelDeobfuscator.DeobfuscateExpression.cs b/src/Dax.Vpax.Obfuscator/DaxModelDeobfuscator.DeobfuscateExpression.cs index 7e9c8bf..f597444 100644 --- a/src/Dax.Vpax.Obfuscator/DaxModelDeobfuscator.DeobfuscateExpression.cs +++ b/src/Dax.Vpax.Obfuscator/DaxModelDeobfuscator.DeobfuscateExpression.cs @@ -38,8 +38,7 @@ internal string DeobfuscateExpression(string expression) case DaxToken.COLUMN_OR_MEASURE when token.IsReservedExtensionColumn(): tokenText = token.Replace(expression, tokenText); break; - case DaxToken.COLUMN_OR_MEASURE when token.IsFullyQualifiedColumnName(): - case DaxToken.STRING_LITERAL when token.IsFullyQualifiedColumnName(): + case DaxToken.STRING_LITERAL when token.IsExtensionColumnName(): tokenText = ReplaceExtensionColumnName(token); break; case DaxToken.TABLE_OR_VARIABLE when token.IsVariable(): @@ -60,19 +59,12 @@ internal string DeobfuscateExpression(string expression) string ReplaceExtensionColumnName(DaxToken token) { - var (tableName, columnName) = token.GetFullyQualifiedColumnNameParts(); - var table = _dictionary.GetValue(tableName); - var column = _dictionary.GetValue(columnName); + var (tableName, columnName) = token.GetExtensionColumnNameParts(); + tableName = _dictionary.GetValue(tableName); + columnName = _dictionary.GetValue(columnName); - var escape = token.Type == DaxToken.STRING_LITERAL; - if (escape) - { - table = table.DaxEscape(); - column = column.DaxEscape(); - } - - var value = $"{table}[{column}]"; - return token.Replace(expression, value, escape); + var value = $"{tableName.DaxEscape()}[{columnName.DaxEscape()}]"; + return token.Replace(expression, value, escape: true); } } } diff --git a/src/Dax.Vpax.Obfuscator/DaxModelObfuscator.ObfuscateExpression.cs b/src/Dax.Vpax.Obfuscator/DaxModelObfuscator.ObfuscateExpression.cs index 9459880..3fd3fa3 100644 --- a/src/Dax.Vpax.Obfuscator/DaxModelObfuscator.ObfuscateExpression.cs +++ b/src/Dax.Vpax.Obfuscator/DaxModelObfuscator.ObfuscateExpression.cs @@ -38,9 +38,8 @@ internal string ObfuscateExpression(string expression) case DaxToken.COLUMN_OR_MEASURE when token.IsReservedExtensionColumn(): tokenText = token.Replace(expression, tokenText); break; - case DaxToken.COLUMN_OR_MEASURE when token.IsFullyQualifiedColumnName(): - case DaxToken.STRING_LITERAL when token.IsFullyQualifiedColumnName(): - tokenText = ReplaceFullyQualifiedColumnName(token); + case DaxToken.STRING_LITERAL when token.IsExtensionColumnName(): + tokenText = ReplaceExtensionColumnName(token); break; case DaxToken.TABLE_OR_VARIABLE when token.IsVariable(): case DaxToken.TABLE: @@ -58,21 +57,14 @@ internal string ObfuscateExpression(string expression) return builder.ToString(); - string ReplaceFullyQualifiedColumnName(DaxToken token) + string ReplaceExtensionColumnName(DaxToken token) { - var (tableName, columnName) = token.GetFullyQualifiedColumnNameParts(); - var table = ObfuscateText(new DaxText(tableName)).ObfuscatedValue; - var column = ObfuscateText(new DaxText(columnName)).ObfuscatedValue; + var (tableName, columnName) = token.GetExtensionColumnNameParts(); + var tableText = ObfuscateText(new DaxText(tableName)); + var columnText = ObfuscateText(new DaxText(columnName)); - var escape = token.Type == DaxToken.STRING_LITERAL; - if (escape) - { - table = table.DaxEscape(); - column = column.DaxEscape(); - } - - var value = $"{table}[{column}]"; - return token.Replace(expression, value, escape); + var value = $"{tableText.ObfuscatedValue.DaxEscape()}[{columnText.ObfuscatedValue.DaxEscape()}]"; + return token.Replace(expression, value, escape: true); } } } diff --git a/src/Dax.Vpax.Obfuscator/Extensions/DaxTokenExtensions.cs b/src/Dax.Vpax.Obfuscator/Extensions/DaxTokenExtensions.cs index 8c6f3ed..0377fe2 100644 --- a/src/Dax.Vpax.Obfuscator/Extensions/DaxTokenExtensions.cs +++ b/src/Dax.Vpax.Obfuscator/Extensions/DaxTokenExtensions.cs @@ -5,8 +5,8 @@ namespace Dax.Vpax.Obfuscator.Extensions; internal static class DaxTokenExtensions { - public static bool IsFullyQualifiedColumnName(this DaxToken token) - => token.Text.EndsWith("]") && token.Text.IndexOf('[') > 0; + public static bool IsExtensionColumnName(this DaxToken token) + => token.Type == DaxToken.STRING_LITERAL && token.Text.EndsWith("]") && token.Text.IndexOf('[') > 0; public static bool IsVariable(this DaxToken token) => token.Type == DaxToken.TABLE_OR_VARIABLE && !IsFunction(token); @@ -44,9 +44,9 @@ public static bool IsReservedExtensionColumn(this DaxToken token) return false; } - public static (string tableName, string columnName) GetFullyQualifiedColumnNameParts(this DaxToken token) + public static (string tableName, string columnName) GetExtensionColumnNameParts(this DaxToken token) { - Debug.Assert(token.IsFullyQualifiedColumnName()); + Debug.Assert(token.IsExtensionColumnName()); var openIndex = token.Text.IndexOf('['); var closeIndex = token.Text.LastIndexOf(']'); From d618fda4ab132a016354e2d00082ab2a12eb6e42 Mon Sep 17 00:00:00 2001 From: Alberto Spelta Date: Fri, 1 Mar 2024 22:19:23 +0100 Subject: [PATCH 6/6] Update unit test and PBIX --- assets/ObfuscatorTest.pbix | Bin 15324 -> 15497 bytes .../DaxModelDeobfuscatorTests.cs | 27 ++++++++---------- .../DaxModelObfuscatorTests.cs | 24 ++++++++-------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/assets/ObfuscatorTest.pbix b/assets/ObfuscatorTest.pbix index a413b4cd6331439a613276d3b0749d66b1d8a466..e8b9a11aaaa43e3e164b8b3ee019b8600e30a4ab 100644 GIT binary patch delta 12249 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 G6aF6rsy(g% delta 12058 zcmZ9y1xzJP(C>XX$l@%{B8&UtvbejuySuv`4({&G;_k9Ii@Pl@i@Uq?@w_)TdGFVm z$;@>AsZMGt)m@cexaXQXqJlIe6b1kQfCb3v#3M=qWp(P*IUznD4G9pH5J<8*h8pDT z6hUr40Dv)38j=NMHz)8lTVBxf2q6GUQNWj05>=w8N+K-in5R`TqpdLJswi0O$$c`5 zV70wWHHf6f{lM#f+@n4@hpfKGi_F(E+?`&U+JqF-&H0ppZ19D00h7(jlX?}TRi3R? z#PM(WH>L6KUQJ%?YuhP(W7+_vcL}ra_EeHY+9VOVyp6}8Ow*7V@`$2_?%4oqvV@S#qT(VN>^@=R{Wfpq#vOo>W?2 zxA3q}n)>p{W_+JBzR02HGK)!MZ@=cIw;`JcF=Rtm$X&*d{gAvbh%9qfSkb9yzLAGH zoHSCQGr)WuZf2GM{UOG;5+>GdwTJnQg#%Rg6egE42Tg!i#ys2vg&xF zVWZvrTCD$^v5g1Swe9<_jnFVcRPBDb@^;~iRx>v3X3`TAUwz&qN`39cnu(@=+_sY+ zf(Oq$^>T|{P8mxIR+Y8FU7MN$*Q*`R`}xdg(-EB@MqohD!`rUw(C@4GvA-35hVfFv zv=+KNd%sK;Fix={@GzUqJ-!D#u4Jz8QwpRiCK$+aLbN&ci?j+R5u1yTPTrHsMdjN? zArGbTRA<(>KHHds25}RsI#~7@&YeYgf~N=$693Il9_adSLOF$kCM}u3dm-);o6FI@ zk}+!_L>$NZfoseI(Y|@2VJ7%vZ^UA?tR~v$@-Az$p!AdT75_5rlk(d7EuP2>Pb|mx z{kXQaluDaJ?|&BiyYD!$e!r>XEiiqo-9LEZvRAqV9oiE+% zTpV}4TZ7r{0!IFDZJeag<*=P;MVNbx(ZGF+hZA7)`^juYfIl8k5%DwKM7KpjN=wb4 zoKB;`@?=D2OdUno&DNOn;bCXwaoapR`#^{T6npnl%+RKxTQBnWK1k;H55Kz>l-{y7 zUZy_g6~|kGvcitt1Y*0f651p`%AK8i?(K`$P?B-|RVpFxQ#x7kjS);YerR3#;_m{! z+3w|TFRx`+{EqwkG}XbbY5qwy*+neEi^}f3O@NE?`A!K;)!KP<%|jFJ0HNp8lV6~| z#NJ-aN$iR|u3du!cMqOh!5M3fz!X}0w7&Y=X4jh-+qt3Xyh94Fw30g#eI@!u*f2;^hPNzZa5A zeqI282)jcM4FaH-oO^NI8afu}eT<2tKI+)HbK`SEfAx0$wCVF@bC0JR9)R+I@LMHI z9T3vo1=)Sj#lYvY_Poi{D!OQ+uQ$V(9;`=3PNIaueH+s_F{$My0=lRjyk(tl#)lS7 z)-oJ%+ETQ)R~Gi3|CXs)Z2PTv<9F6Jn}ThwdSe`xN*vU*gwW&yuH^?LIOvhz^pWsY zwmr4Gni|(XzVVJmIqjGJqA!k7!}8J)&bXHaI}=5ru%VH$5>uKhf$@@Fjc_fKA!_kx}aBU8sx?fBQO>>26l7yH9llNqSsO|l~ zp(H2;1@Ipm?*M{Q;I_+88{6f^fL8Lte801<3CY7E(9iXWJ7`zEegQCZQ748A&2&4KY>&g&7QF!12M={bpa#w;u}7s$cz&(|-}E zfG>%zLgzZ(hDy)4T!?h$av*E;jxAiIXnhzjTO&n+W>W=Zt#ydWWu z%mby9M0yOC;Nl@V7=i92B+HLWX2Le&sfNR#1s7;9NiI_1JA4%S9AxseOhi%P3N#te z*f0bw*upAII1Blt4i9diON-4zL%htCW*RlR8i?UYR&Xifpd4!=isueBF)?G#6Z@fP zI-Es?TO!%=%kS z_VfP{hd4B{$uS1GS6dvqF@+Q$7<(K62}a7 zh1PI`4h~z9s9pmi>Y7F41sPqlR9<#3dhh&Y3L-I~E+_Udk#IOQOeHAMogggAVW)&c zah&HF7YI?yCXiN@X2X}XNE}73d(OtuAqlFKR~QcDZg#Z(Z?1nTIjNALKkY0Skh)MH zL~|3Up_Rz8)7mvEd1bjQ*?2|9EF8(i^u0z|hi@8lQZV|ic<;|zrchyC>4|YYXY-i3 zH&NvqttS1m}*cy;y`&!@AA8#NTwD+wgC z$QJ>x8;sc+URy`MDu=^MZj01*+BaW;0XOSVZQq~L6$DoFyK|$+!j2q%Q0zBp#@|6H zXWYFm` z5N;Q0(nL|kY(eYiPh2mSZr{CGLod*hFK#$w_X^TpXq)SXsF|j-$y=3-SuPBAy-oe% zJ2snmn`{uw z6sxb`_5+D%9R-k!bcxC7-fX+|*qQrr1bS7+;phEmt47uaO_+nO5A5DO^Io?NA1~u4 z*{JWL|(JTtV2_J@+2OXprQNm1qa5u+^o_WV6Yj~1_78p|E}SZ1_=$>^@|q-XjJ!c z?Nq&@#B^7DRUF91(64Ge;l=Z-VV9*)P9S5KBW20~)Jr7vcnP85_LG27J4h=~uzpvK z8&bQMj?yiVgjy}d8;Vq0rH%0k?cpk&;~Y{c?^USu+4vA)>{4WE8) zIa2Ogk_rB8)MPN}@QGd=<7i_VbXGRz>65DL#kh`9W=GzT3JP@DbB#|Zw|2B0L!B5l z#rx_vFrk(21|NesIxYD?gXG9YzI^=yFVXalik@x+QRVLL;le`To=Ol{IUCZ399tv{ zBNU4}0f${-H1f1A_aZ>gJ%VH~5EvbzD_D%SK1Ki!^9{WIRZ|`|J1vt@TFzUGH7arK zBgkO+8& z4vx4615LpQbWkhm=mLUCle)^ok5ZUFq8xo>k~iR{RfA4DUd+GILl)c&HX@5?h?d{y zaI8_;6mQ@o%WCDklCcmMl;hhJ{xjz8q_;8TlpMIEUQI0whQ{HWIlATCmaYJzp>c=_ zk-zh+_dA7^iR{VjA&5se#z5oia4^u~jzpPxZgJ;hp$`|+HiA;Alci4E&Pew_Em5Gi zAu=mLeymse+LPb-2nW#&mmp`_EHR}Z`2IAdrsm>A{ zihgp%KlzxdKg`bs^>&4`e)i%^KLJkOAllg}Hj!kr?vXGa73Mv^dq5HsI>Gxmu%FDx z8qMsBWEzDS(}3b@Bn_n{wgaR3z5cm)F>TRB-!vvtd*A)3t_tgLY>!oVX%HZY3-42c zb8^wMV9(i!b06ibsrYI9qVgcR>*wV2Rzvu6V0_6uY@2rHlCt=pwHzCtOEqB)m)SN; za}btKhz~N2d^5S~gLlVL5N8pY+lK0vdT1LSE^QN0fg?!S&(_vUqpaVriIh3>mbi)A z)EjMJhKmo8FEpfuee7STvtsV&?s_>u-t&v8q&f(A^XpO1m*~=_de0-l^7lYHhp^m^ zw;d9bk%UK;Q0$$OA0k?1b*kd4p__-5^K}4r_S?;mq8tDF>-;BsXl&O*3$Ef)MAa)H znQ?c9eNoUJ98sMKD;m^7sMhd2<I_jYCtQIkuO76YpYluz<)RAY)z+t_BV96J+ zl!bsl{rL%)*vKqoS21;!RJ;{bW`ilrKy=tV04>YY8O z+)=3A%Yi|U6CbPE8c~l_X#kw$ zD_N;W2pj+d32>|fP;mR=j~r=DB)uSc^)yZVQXJPAynP?>uc{Tiy%G^00bc&8y1Be+ zVh@7$hM9KL;i^_i*f2llmJr`vt1scvZ8=k@=mXi}?Naf1asIfCD@t_t4tXZ%782v4XK-#E zlODy#s<_cOmO7h5x~3kta^$WQC2#KibjbQ%ic{z|{j}=)AHURF7bNy*9`;L(cCUlR zTfQa127{0E2HAQn27!C_yvMtUOd1$!k%8w3z2#M^E}bi+h!dLT4N?!c&=6ABHV}gL zEIPPJO)^!Oj3E;Wtg7)$NPo&L6FyyBKU~VhIt1Y$sXA1Y; zcdd)d(RmXKBap$P>j?pHDeuEr1PrhlOgS9jB5GqM0i1rLF*93njWGSzp&v>j`hu9a zsEdPx8j9j-tR2&~cL)*uw*?~oCumfu>@S4Mh)2a(+{GUos`8gIGUA}?2VDqBVsQH< zm%ay*=vXk;>vVjRqt?Q$_3PsR;Idl2NRV}{WvltS@){1t&zKNpl!B{kv)ihR7xkFFTi^O=Yo(NSb}tT-~Qlj27*7$C`G8LhX# zISeNS9ckiN7@&TEvwlw-WC+AC%ii_4j12uy?fAKq|2VX>zQ6-P-*tXm`df@)l8m;Y zPllDf+Z#%zJt5#Bn%0i_H6!mQkqDC?`~w;Vf!xVA{&S{7iLC2mi$8~^h+ZO5s<+Tl z+2`hFW@e)&EKG>MIGA(>V?p20;JxDfmA!aPnbRscEYk)#ky!0qtdLqagtX|ygv{%Y zN1`wXYZAJ28a%josbsHA^Om%(OlKU9Eas{z5NlVqxPa_{Q#*GOgFMlwtK*uE&DS^sV#b7*UCHWa=(Dpe=%;pDgV#B}&LSOPY=P2his8yD%YNzche7J)#n zT~_>EL70jLrXqzUH`l7o!ra`p!tVgm{EiMERe)qUyyU!oawe^+Ix(jE)shf-ew|Vd zO&FON+julo3S2E72}r+}Rb&3+SF^cDPQ;#y@|hB94|zMh(!9PZarE$5uH<=DbF@jT z)UI-}x;pXQ&5Cp%m7gB$cclkgricEp*JySn!p_p0SmYTE%bn<(dW~wh3b*xH>^0Ch zA)H+Y%AmW_8m7roiT|JSR?$%X^d~&i>^VQAd+LaG_O-JSB9Iy&tWQ^vZ}bR2lnXme zeL_o&&i=(y?&V*GUgSF83;nVuf&J2!TCL{-fgq&sIepF4v(zcYD4%cbirj1_pe{@x z)-H8t>x&b@xe{}Tun_6Ir(+89>@b#Hx!cp8iBvQU-a*cj=7O{riseyw-Jh$H60jQZ z`AA8Bsci{<9u&5KC<3k#3Q+01Sreoa&crI-4gEV!!=q6YD6`x^=|-oyi&X97Q7=!e zk#H+O>)2@;W^P@5PALKAUx}4 zTlm7I`u#=IC;4|!bbb?wmro-B{|151u@}S=dE2tVJZOZC5?1^7iX*4}U9JsVtM8TQ z_rfrfaq-=kP& zFXcRA$qsH}R!mW;`2wzR>LITZ8cA%}l=)I%Us;(0XMNz^S*G+OI|a2fSn!p!G|Qf( zB+K5Y7?fqNL=N$;r?X_#8s3|y1@E8I&l1p)ugQP)eIG3!Hk)Vd(+RrDg-NJ|zqh~V zj5n;E#?mn;a}w;Mg7QQ3iXZk2kbQ84ZNY;A~Y z<5KLCL(LZ>pXTV80$7Dq_iHf-6p$x>dcwdXg0SHk`8n=evy%_Rp}!gay}@iaOG&Hq zP>ppAv1JR)I>6+|oxruJ6Q^5^%f=)%bb#nth%Bmi<1I7Go~-Zu`9%SBOf^J9(Wo;u zsRua)bE@3U#3I|}@D=6})m0lhtwH8>d~Z?p=QTNG{3W$5BfL$7#sJO~fmDU0jA>sjW7u!i zikW#THjYEVpj@negK`@UBHH(NxF&>S*8xXj_44lhI)%~po#BKkckt&i#)_5%D`uzY zse(^v?2TJ|gI}Avt7&yJPNFKK#nHjBR#5(c19ZB6`tM z;rOi$xDTi-hT2X4_RYyt1Nk#!>dJkEisl}a3e&Dkz~QCk9k5r#@ye_cx_ z{x-=#cr#SpfGzgH$1Qn6B_u!FI%Pe(!@4)OEmklU$r7bjVvI;uWPFI*e$G)$s>M80 zzDy@C@!cK&?aRA}Z))a8%pTkdsMHiu3#Gb*`ZHtmaINi9e#C#H7L9VJF*D6{W1Vs_I@3db&U;a+h#PyNCtIL{D-F=7M;Y>b1 zLlHX_*2uw(29sq*#cMbF42wTQvC^X;Rv;)ozjSv66C;IxJuG?av>Sy3y6VC6Iby4D z5$paZtw44@e{{zoI}NjD^6RS{t_A+CS_fDlb<4#CXHOd#QBc$G`aJ-?iKRRRqv`4iQ(7JAUJ+G=I;b@FGyr| zLV9SFIN8{qu6(?v*MI42)|=fdTvFT2@rSz?CHE^zeUjZM*yIj(M~-&Ga1f5|R8*SW z=iZ&Me~v8ph^<%g9sKmUiuO$!I{5k3OGi8rN-oh4?cp&V>tQZQ-TW5!4#uR?5ly%6 z4WdGmRtm$;7#McL1PaKG-w4UwISQb$=1!ha+Ql(yNt#F@f)h$k4ZD~TwoayOvi^t=o_*21>hEr@N+hMJNpdsrBwVKoa zMZL}*55sggH(u1tlC|6rGrFf7%!7`Tuhlv87%Ll=292E&3PNRZ$-Zj8A85vR9m_na z{&+#K=++k}{S#)5e(7Wd0U?^v9QAfL&2D}A<&-y=0ZUkUOC-2*Ac6@5_<9J)Lx`>KfOQs!J8mJ- zre^|Ce=T1{guLqZy~p{V1db4ZHDrvINEmbReDM@S=41`A!P!UqQ0Pa7jn~N1FZ_si zBmNG6OC&+ZJ`2FzB{Fl5l@l{_1G`f9*+<1o*$D8L|7Q;2U(zW&FX7{Voqw|OW*dUi ztfAEakzW?f*kygrfA3d|X}rqH)jf7mvVYwH5XshkqdL!9`hn}UUg7QC!zkT?saoz1 zFIcXVFi9K71KujE%ae*z)3Y3%rb&&Rl{>4yfQrDQ4WaTf`$vsCEWK|E2r(q}s`;Bu z<-yXIYAYb2N^dz#O9Zcx%O6GtGnLI1TAmD=nep;9QPz|Fmm|yZPIj)%Ca79du0CIJ zUN%bZI;D=NtE;9z=dEfwceilVMNq5lZ*+HR?eZKDlR46@(Cj!!+0-uk96j6o#|{E& z&EdYzL>a5;zj#B~$wluPj(_ARZ?QlYmE3L4e-sLhV z<>_1ZKy(MsfpO4r8s>#AOjq~Z{gN3!V~lo)pL7EM`H|~*LLu2$n`z~`G)jyB0jOo9YHrBnR1HLd&GqrQ1Z@ldhZhsS>P*qQ%zPYYlNeIJJg+Zkx;N=;t z=$caXFrcJUWIb|l5ho2Vg~gkiyJ;H%B~d7I;8>aokZQ-0ZHvTGO*F6Bv`)m>f5c&| zAlzTb&u0TusY)qCVHVAcYQ+L=+Z_8R=?OR|pS+T;`!)7_vj<28I*ufqf*a%M; zMCkvW56F-YNf8rzO`TVVp%#%UC;;Bh{5q1)%8JhN|gR`Y7!(tEY)eCzO~bk zkxF=XBvXxo-od-@EO1_$Cnkw})H$4#FGpB`)t@r1vwHGtM&cQibR%jsWb%o3{dO_+ zbhM#5*=rI83E7b3#KF_W(m74Uq^rD*g5L}`J7!;JjqWiR5TJ5OR<;7Z;hiz8 zRxyK(Qn*QFengv!BL8HNV7X$_eq^G%y-)l@WcDs@B&?#gONHRbgdkN2ikJ9mJc)?O z|JBiVCY=rLZ~@Y9ecR&syONzvl+-sc+#oCYnaw=;B;DIF>7>gIo$`R6=D3P#osQ|z zuvPpWGq^?PFzhx1I}3;|(nU6=uWcgXIN%_M%udg6y%Bj_(5i&yQ$aTakkps5F|{Y7 z@=mw5y*E;|Jduf*Flwm=5h>rFN6#b2yp9bJ{;rm!u&I|EY@(3vHIsH)Z*-8D1tD8M z|6q{zvv%@}rFohQeMAOq-siRYvifs*E$C8zsjT6VjWPW=z?=T2eFX7c!Ke5SI+7lH zg%>a-G2GM$V0kTrXdODTcP;bdOgj}4CL4qgcc0KQCL`Ux?>kfi61H7=tf-nrXH@iS z9Xj3v`Qg?jZl8I-)QC@6nyx(FVh(llmf`_i#wv$)(_Xvb1O_{j+b@EsyS`)ScMmb+ zir~Lx{H{l2l*ysKNa<3}FhWpRQ>+tZWo)-*fHp{9dOBxFHNIw5)zZ>xV{5TSfi}RQ z7-FuI`7Dd&waMu~J9u-OT--&}=YWVBUaMd z=z*V9UF^7N1g`ZPXAooke?9ASyiMo%9;A73cmN_9+n=?*aKtJrltoQi1HOS1r`yaU z!%0ehhFM25O$0ADt`h zb!gBiv1?~23!$~0QgMyom16K`79A6JFk|eJ-`+k#`O;)_NlR6SwM*d))j39l8CM2z z5MKLEqf9b^+;oOiO-7=jxb{bpYHESalCJ&HWIq!wbIZ*o%P<$T0<_xtBjZa;~!?o=xs&nvi5SKN|H7 zj7m-S=1oVteCr$wNSt+(NQj5&g_U^seG@kmxO&h*yIJz!32h*`F7Dw1Gb9~^0h(Dq zxn9XZ`*vVVMjhu?2ak=;zu~BT(`)C?Dro4D=3vy>U}y+8bXfgysiwFx74x20&Zy`Z zpO6Ib)1*(>U^8G%V*tM%L{F zb-ig=a^ww+5T6MgREB)xn^%bU!=TmT(pEf3yGk>kjzLO7b;)+QA_Tjmg6x_<>6SwH zVkb6{pKZdP8$v5ctUw@w>?q>f5i`b6FqVYT;)yGfWsq%Ee&a|vugNF`WUVzyOreTb zonpfxH7S#*qlx5M5E%v1ZDpa9Q6ME)hwIS|E2$No>mWSxr}bV(c6=I6L{Ty)A9Ww7 z$rQdxn)YbJsL$lK%6dI@i%87p=k6)g&#|{tZhRKEYaJSUwvmYRI?=F-Bryt~Fn3-m z9zgA`<0c#+o$C{r5} zk*wdKVQFv$4Iyl;&K}o~gPozq4T!pU324baUr!8_4kq#2g1Yf+LJZCTt%xpDhc-hVZ{-Dr;9HBsPwY z3eG9-)aowkewA&OwT!YU*w1Jm!Vu-0AIi@T$+FTKyivllc&iJBf^Y=Q$`4*XOda)) z6@M7Jix~w(5wZQz6T4o4fpMf@2K$Fz#n1>xEpc576-yT5vm;iRl0u?}LQ!09JuY{; zMo8PZz+}Cc{b+F1;Sq^GnO9F)!Qa6_22SvUc@MSaAo=pWOf0nNd&`&(f!qe>fQGV_kkFtMtwv zWA*Z8bVfTt{+l|A&6h-* z$wB&+kMEtH+%1aX$uP#lkYm+XNUN4Sfqmw#3lJDJzYQCu=2OWoByq$Ol#kYLw-A(o|glUhSe&H+9(4-z# zDZ0ER3ORf^muI7=?{PZ(+ML-`+P`AM7{h*1#@=X_5ES(R>YLsYh~Rws8GlC61cTEeaN`jyS%yQC;F3{TIXmzP}W zC&3LL+&3!Te`e;+$9-D18hCa85er70zXn_>BE@iSrbHOt8Dt^h`EaTfXMoKfom=`UKAGFKjk4y9$noq3^2kJ z*w6{EjH{{uz>ZBwc#COBAmOF~6u*Z60>|_w#ExEu;e7zA!zCD7A`c9NY4krY2;AcT zKpXkd%|SbXhKKZrAz4NV-ni!h!8}odNZ>HSU()D%PQXc;>?RmMR10iR?VGQq#}J+Y zF@(yZ(Yhvz){JLRhR<)TS=>q;6_M?)C07JX@x8N;eB`nOL7-3j`=?h3qHrAg1E9z@ zABuVb7@Gz_U|O5+2*>=lcNjFP%LPwAPOpSmb-e4yqr}H!3ikCSaZfXiFHi=8<+NE- zP>@|iGZ-%zOv0=PMesU3V8TZN`7JIGT3RnONzzo&*Nojiv>4~TC6TaeAE^l_U=joW zKq=UXlyzAfvP=me#EP>8*V4mgK~k)(I z@Yr-ag!@BsElnz{c+ul2TuFKovXRw^-5w3&?9ey*` z_xA^0W($(>g|OxRaBbU8qnhaCM~x51LNtH`x)=Zvru_ra@eOz<&4G9tCs78_@VBmH z96d1X(}B<~0)d~M-bR4b{c!qgWQ;P_`&TDqNN#d=3}I+Stbnf^eTqVx_<3_Sv=(3> zFiQZ8B{4lkz6Ic2>H$J6fk8e5d>LsRt23Nb@4-`hJvlo`ZuG?Hae0uCX#$`a{<^db z5OG2x=c(RQPi(H!FUiuv{*WT8N4@$^LFH6;UnM|JaJ_UCSa#tZ@(^5^ zNje0;ss$6=#vf+sSYWQ}h&-oDz1hTb{*d(!myyYjZ!km)W|2kU1QlDdfn7fn>XBr=nV-c@C+8FE<7;kZnVIR}UajU(!68)m$0@6;rWYo4|?HeLt@JFh* ztIJ=mf%P-ZNmq05uQtsL*-vlt5zmAs`UCToBe1u-$=_a1!%D7}P9)lrK5H!2RI>*I zxALJy2J^Y!*{ZE=9gB#n@*jft-v*7SgNj_w5n2%|5sXZMj%&W>9?fyKD&}x+lN9ZzkE19GdL78!lAV5w z0hp{}b)8X3rA}Zg8!>*MlHREpE_7&Y79kg<)L$>7oP$!S6b4&m^I(l#WKXKJA{>;o zlxhkHyfTAp6B*K{aa~qCRPyJ=8KPMQk4i24G$Nn-R9wu6s<0xMk0eTR3S|p>jT%l` zC@s0FF<=sBFgi)@puT1E5M}TZaW$aJMGlk}QT@p;Y7)y1Cz72BkN;~`U_EO>Ni|!x zXdSJlB@Q~N!YXm}mLilb<*X{;$7fHRFD!_rAjmJGE*P+AT5X|pRbgG2F>$eFj!O#u zC6PU1SOS+gZ{&K|EKf#tOJVDB*7z-(f>)FSj$2SW8YXhC_+Jh)s+baC3pPbIaho5D zxlGdMaq}ls(ufHo89mqQofh3ZV|DHdF3g>>sxY?v4VFP~&I8LQBnknf1N