This is an automated email from the ASF dual-hosted git repository. mblow pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/asterixdb.git
commit ebef3b67cf21ec62bdb7d11b73636e99cc3aa4d9 Author: Dmitry Lychagin <[email protected]> AuthorDate: Mon Dec 2 13:30:00 2019 -0800 [NO ISSUE][COMP] Fix incorrect result of NTH_VALUE() FROM LAST - user model changes: no - storage format changes: no - interface changes: no Details: - Fix incorrect result of NTH_VALUE() FROM LAST with asymmetrical window frame Change-Id: I7f6a1b358441730cd33a0ff6bde2b34ad5a689a9 Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/4283 Tested-by: Jenkins <[email protected]> Integration-Tests: Jenkins <[email protected]> Reviewed-by: Michael Blow <[email protected]> --- .../SqlppExpressionToPlanTranslator.java | 28 ++++++++++- .../window/nth_value_01/nth_value_01.6.query.sqlpp | 52 ++++++++++++++++++++ .../window/nth_value_01/nth_value_01.7.query.sqlpp | 55 ++++++++++++++++++++++ .../window/nth_value_01/nth_value_01.8.query.sqlpp | 47 ++++++++++++++++++ .../window/nth_value_01/nth_value_01.9.query.sqlpp | 47 ++++++++++++++++++ .../results/window/nth_value_01/nth_value_01.6.adm | 10 ++++ .../results/window/nth_value_01/nth_value_01.7.adm | 10 ++++ .../results/window/nth_value_01/nth_value_01.8.adm | 10 ++++ .../results/window/nth_value_01/nth_value_01.9.adm | 10 ++++ 9 files changed, 268 insertions(+), 1 deletion(-) diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java index 6ec74cf..82dc344 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java @@ -1239,8 +1239,16 @@ public class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTransla } else if (BuiltinFunctions.NTH_VALUE_IMPL.equals(fi)) { nestedAggFunc = BuiltinFunctions.SCALAR_FIRST_ELEMENT; if (fromLast) { - // reverse order if FROM LAST modifier is present + // if FROM LAST modifier is present + // 1. reverse order reverseOrder(orderExprListOut); + // 2. reverse frame specification + WindowExpression.FrameBoundaryKind tmpFrameStartKind = winFrameStartKind; + Expression tmpFrameStartExpr = winFrameStartExpr; + winFrameStartKind = reverseFrameBoundaryKind(winFrameEndKind); + winFrameStartExpr = winFrameEndExpr; + winFrameEndKind = reverseFrameBoundaryKind(tmpFrameStartKind); + winFrameEndExpr = tmpFrameStartExpr; } if (respectNulls) { winFrameMaxOjbects = 1; @@ -1737,4 +1745,22 @@ public class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTransla throw new CompilationException(ErrorCode.COMPILATION_ERROR); } } + + private WindowExpression.FrameBoundaryKind reverseFrameBoundaryKind( + WindowExpression.FrameBoundaryKind frameBoundaryKind) throws CompilationException { + switch (frameBoundaryKind) { + case UNBOUNDED_PRECEDING: + return WindowExpression.FrameBoundaryKind.UNBOUNDED_FOLLOWING; + case BOUNDED_PRECEDING: + return WindowExpression.FrameBoundaryKind.BOUNDED_FOLLOWING; + case CURRENT_ROW: + return WindowExpression.FrameBoundaryKind.CURRENT_ROW; + case BOUNDED_FOLLOWING: + return WindowExpression.FrameBoundaryKind.BOUNDED_PRECEDING; + case UNBOUNDED_FOLLOWING: + return WindowExpression.FrameBoundaryKind.UNBOUNDED_PRECEDING; + default: + throw new CompilationException(ErrorCode.COMPILATION_ERROR); + } + } } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.6.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.6.query.sqlpp new file mode 100644 index 0000000..4656f74 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.6.query.sqlpp @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/* + * Description : NTH_VALUE() FROM LAST, from unbounded preceding + * Expected Res : SUCCESS + */ + +from [ + { "x": "a", "y": 1, "p": 0 }, + { "y": 2, "p": 0 }, + { "x": null, "y": 3, "p": 0 }, + { "x": "b", "y": 4, "p": 0 }, + { "x": "c", "y": 5, "p": 0 }, + + { "x": "a", "y": 6, "p": 1 }, + { "x": null, "y": 7, "p": 1 }, + { "y": 8, "p": 1 }, + { "x": "b", "y": 9, "p": 1 }, + { "x": "c", "y": 10, "p": 1 } +] t +select + // + nth_value(x, 2) from last respect nulls over (partition by p order by y range between unbounded preceding and 1 preceding) + as n_up_1p_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between unbounded preceding and 1 preceding) + as n_up_1p_i, + nth_value(x, 2) from last respect nulls over (partition by p order by y range between unbounded preceding and current row) + as n_up_cr_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between unbounded preceding and current row) + as n_up_cr_i, + nth_value(x, 2) from last respect nulls over (partition by p order by y range between unbounded preceding and 1 following) + as n_up_1f_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between unbounded preceding and 1 following) + as n_up_1f_i, + x, y, p +order by y \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.7.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.7.query.sqlpp new file mode 100644 index 0000000..f03711e --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.7.query.sqlpp @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/* + * Description : NTH_VALUE() FROM LAST, from bounded preceding + * Expected Res : SUCCESS + */ + +from [ + { "x": "a", "y": 1, "p": 0 }, + { "y": 2, "p": 0 }, + { "x": null, "y": 3, "p": 0 }, + { "x": "b", "y": 4, "p": 0 }, + { "x": "c", "y": 5, "p": 0 }, + + { "x": "a", "y": 6, "p": 1 }, + { "x": null, "y": 7, "p": 1 }, + { "y": 8, "p": 1 }, + { "x": "b", "y": 9, "p": 1 }, + { "x": "c", "y": 10, "p": 1 } +] t +select + nth_value(x, 2) from last respect nulls over (partition by p order by y range between 3 preceding and 1 preceding) + as n_3p_1p_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 3 preceding and 1 preceding) + as n_3p_1p_i, + nth_value(x, 2) from last respect nulls over (partition by p order by y range between 3 preceding and current row) + as n_3p_cr_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 3 preceding and current row) + as n_3p_cr_i, + nth_value(x, 2) from last respect nulls over (partition by p order by y range between 3 preceding and 1 following) + as n_3p_1f_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 3 preceding and 1 following) + as n_3p_1f_i, + nth_value(x, 2) from last respect nulls over (partition by p order by y range between 3 preceding and unbounded following) + as n_3p_uf_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 3 preceding and unbounded following) + as n_3p_uf_i, + x, y, p +order by y \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.8.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.8.query.sqlpp new file mode 100644 index 0000000..ec553e5 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.8.query.sqlpp @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/* + * Description : NTH_VALUE() FROM LAST, from current row + * Expected Res : SUCCESS + */ + +from [ + { "x": "a", "y": 1, "p": 0 }, + { "y": 2, "p": 0 }, + { "x": null, "y": 3, "p": 0 }, + { "x": "b", "y": 4, "p": 0 }, + { "x": "c", "y": 5, "p": 0 }, + + { "x": "a", "y": 6, "p": 1 }, + { "x": null, "y": 7, "p": 1 }, + { "y": 8, "p": 1 }, + { "x": "b", "y": 9, "p": 1 }, + { "x": "c", "y": 10, "p": 1 } +] t +select + nth_value(x, 2) from last respect nulls over (partition by p order by y range between current row and 3 following) + as n_cr_3f_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between current row and 3 following) + as n_cr_3f_i, + nth_value(x, 2) from last respect nulls over (partition by p order by y range between current row and unbounded following) + as n_cr_uf_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between current row and unbounded following) + as n_cr_uf_i, + x, y, p +order by y \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.9.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.9.query.sqlpp new file mode 100644 index 0000000..be7adca --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.9.query.sqlpp @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/* + * Description : NTH_VALUE() FROM LAST, from bounded following + * Expected Res : SUCCESS + */ + +from [ + { "x": "a", "y": 1, "p": 0 }, + { "y": 2, "p": 0 }, + { "x": null, "y": 3, "p": 0 }, + { "x": "b", "y": 4, "p": 0 }, + { "x": "c", "y": 5, "p": 0 }, + + { "x": "a", "y": 6, "p": 1 }, + { "x": null, "y": 7, "p": 1 }, + { "y": 8, "p": 1 }, + { "x": "b", "y": 9, "p": 1 }, + { "x": "c", "y": 10, "p": 1 } +] t +select + nth_value(x, 2) from last respect nulls over (partition by p order by y range between 1 following and 3 following) + as n_1f_3f_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 1 following and 3 following) + as n_1f_3f_i, + nth_value(x, 2) from last respect nulls over (partition by p order by y range between 1 following and unbounded following) + as n_1f_uf_r, + nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 1 following and unbounded following) + as n_1f_uf_i, + x, y, p +order by y \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.6.adm new file mode 100644 index 0000000..0d6ae8b --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.6.adm @@ -0,0 +1,10 @@ +{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_r": null, "n_up_cr_i": null, "n_up_1f_r": "a", "n_up_1f_i": null, "x": "a", "y": 1, "p": 0 } +{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_r": "a", "n_up_cr_i": null, "n_up_1f_i": null, "y": 2, "p": 0 } +{ "n_up_1p_r": "a", "n_up_1p_i": null, "n_up_cr_i": null, "n_up_1f_r": null, "n_up_1f_i": "a", "x": null, "y": 3, "p": 0 } +{ "n_up_1p_i": null, "n_up_cr_r": null, "n_up_cr_i": "a", "n_up_1f_r": "b", "n_up_1f_i": "b", "x": "b", "y": 4, "p": 0 } +{ "n_up_1p_r": null, "n_up_1p_i": "a", "n_up_cr_r": "b", "n_up_cr_i": "b", "n_up_1f_r": "b", "n_up_1f_i": "b", "x": "c", "y": 5, "p": 0 } +{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_r": null, "n_up_cr_i": null, "n_up_1f_r": "a", "n_up_1f_i": null, "x": "a", "y": 6, "p": 1 } +{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_r": "a", "n_up_cr_i": null, "n_up_1f_r": null, "n_up_1f_i": null, "x": null, "y": 7, "p": 1 } +{ "n_up_1p_r": "a", "n_up_1p_i": null, "n_up_cr_r": null, "n_up_cr_i": null, "n_up_1f_i": "a", "y": 8, "p": 1 } +{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_i": "a", "n_up_1f_r": "b", "n_up_1f_i": "b", "x": "b", "y": 9, "p": 1 } +{ "n_up_1p_i": "a", "n_up_cr_r": "b", "n_up_cr_i": "b", "n_up_1f_r": "b", "n_up_1f_i": "b", "x": "c", "y": 10, "p": 1 } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.7.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.7.adm new file mode 100644 index 0000000..2f7fdba --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.7.adm @@ -0,0 +1,10 @@ +{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": null, "n_3p_cr_i": null, "n_3p_1f_r": "a", "n_3p_1f_i": null, "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "a", "y": 1, "p": 0 } +{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": "a", "n_3p_cr_i": null, "n_3p_1f_i": null, "n_3p_uf_r": "b", "n_3p_uf_i": "b", "y": 2, "p": 0 } +{ "n_3p_1p_r": "a", "n_3p_1p_i": null, "n_3p_cr_i": null, "n_3p_1f_r": null, "n_3p_1f_i": "a", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": null, "y": 3, "p": 0 } +{ "n_3p_1p_i": null, "n_3p_cr_r": null, "n_3p_cr_i": "a", "n_3p_1f_r": "b", "n_3p_1f_i": "b", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "b", "y": 4, "p": 0 } +{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": "b", "n_3p_cr_i": "b", "n_3p_1f_r": "b", "n_3p_1f_i": "b", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "c", "y": 5, "p": 0 } +{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": null, "n_3p_cr_i": null, "n_3p_1f_r": "a", "n_3p_1f_i": null, "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "a", "y": 6, "p": 1 } +{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": "a", "n_3p_cr_i": null, "n_3p_1f_r": null, "n_3p_1f_i": null, "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": null, "y": 7, "p": 1 } +{ "n_3p_1p_r": "a", "n_3p_1p_i": null, "n_3p_cr_r": null, "n_3p_cr_i": null, "n_3p_1f_i": "a", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "y": 8, "p": 1 } +{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_i": "a", "n_3p_1f_r": "b", "n_3p_1f_i": "b", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "b", "y": 9, "p": 1 } +{ "n_3p_1p_i": null, "n_3p_cr_r": "b", "n_3p_cr_i": "b", "n_3p_1f_r": "b", "n_3p_1f_i": "b", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "c", "y": 10, "p": 1 } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.8.adm new file mode 100644 index 0000000..74de5a7 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.8.adm @@ -0,0 +1,10 @@ +{ "n_cr_3f_r": null, "n_cr_3f_i": "a", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": "a", "y": 1, "p": 0 } +{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "y": 2, "p": 0 } +{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": null, "y": 3, "p": 0 } +{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": "b", "y": 4, "p": 0 } +{ "n_cr_3f_r": null, "n_cr_3f_i": null, "n_cr_uf_r": null, "n_cr_uf_i": null, "x": "c", "y": 5, "p": 0 } +{ "n_cr_3f_i": "a", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": "a", "y": 6, "p": 1 } +{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": null, "y": 7, "p": 1 } +{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "y": 8, "p": 1 } +{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": "b", "y": 9, "p": 1 } +{ "n_cr_3f_r": null, "n_cr_3f_i": null, "n_cr_uf_r": null, "n_cr_uf_i": null, "x": "c", "y": 10, "p": 1 } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.9.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.9.adm new file mode 100644 index 0000000..8840079 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.9.adm @@ -0,0 +1,10 @@ +{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": "b", "n_1f_uf_i": "b", "x": "a", "y": 1, "p": 0 } +{ "n_1f_3f_r": "b", "n_1f_3f_i": "b", "n_1f_uf_r": "b", "n_1f_uf_i": "b", "y": 2, "p": 0 } +{ "n_1f_3f_r": "b", "n_1f_3f_i": "b", "n_1f_uf_r": "b", "n_1f_uf_i": "b", "x": null, "y": 3, "p": 0 } +{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": null, "n_1f_uf_i": null, "x": "b", "y": 4, "p": 0 } +{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": null, "n_1f_uf_i": null, "x": "c", "y": 5, "p": 0 } +{ "n_1f_3f_i": null, "n_1f_uf_r": "b", "n_1f_uf_i": "b", "x": "a", "y": 6, "p": 1 } +{ "n_1f_3f_r": "b", "n_1f_3f_i": "b", "n_1f_uf_r": "b", "n_1f_uf_i": "b", "x": null, "y": 7, "p": 1 } +{ "n_1f_3f_r": "b", "n_1f_3f_i": "b", "n_1f_uf_r": "b", "n_1f_uf_i": "b", "y": 8, "p": 1 } +{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": null, "n_1f_uf_i": null, "x": "b", "y": 9, "p": 1 } +{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": null, "n_1f_uf_i": null, "x": "c", "y": 10, "p": 1 } \ No newline at end of file
