From 7a45997d9c299bf55230c4f97fae7fadf78a6203 Mon Sep 17 00:00:00 2001 From: feiniaofeiafei Date: Wed, 11 Dec 2024 17:24:48 +0800 Subject: [PATCH 01/63] [enhance](nereids) remove first_value and second_value second parameter if the second parameter is false (#45264) ### What problem does this PR solve? Problem Summary: remove first_value and second_value second parameter if the second parameter is false --- .../rules/analysis/WindowFunctionChecker.java | 14 ++++++-- ...CheckAndStandardizeWindowFunctionTest.java | 26 +++++++++++++++ .../nereids_syntax_p0/window_function.out | 32 +++++++++++++++++++ .../nereids_syntax_p0/window_function.groovy | 3 ++ 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/WindowFunctionChecker.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/WindowFunctionChecker.java index d6904ae074c7da..2da28269fd711c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/WindowFunctionChecker.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/WindowFunctionChecker.java @@ -317,9 +317,15 @@ public Lead visitLead(Lead lead, Void ctx) { @Override public FirstOrLastValue visitFirstValue(FirstValue firstValue, Void ctx) { FirstOrLastValue.checkSecondParameter(firstValue); - if (2 == firstValue.arity() && firstValue.child(1).equals(BooleanLiteral.TRUE)) { - return firstValue; + if (2 == firstValue.arity()) { + if (firstValue.child(1).equals(BooleanLiteral.TRUE)) { + return firstValue; + } else { + firstValue = (FirstValue) firstValue.withChildren(firstValue.child(0)); + windowExpression = windowExpression.withFunction(firstValue); + } } + Optional windowFrame = windowExpression.getWindowFrame(); if (windowFrame.isPresent()) { WindowFrame wf = windowFrame.get(); @@ -347,6 +353,10 @@ public FirstOrLastValue visitFirstValue(FirstValue firstValue, Void ctx) { @Override public FirstOrLastValue visitLastValue(LastValue lastValue, Void ctx) { FirstOrLastValue.checkSecondParameter(lastValue); + if (2 == lastValue.arity() && lastValue.child(1).equals(BooleanLiteral.FALSE)) { + lastValue = (LastValue) lastValue.withChildren(lastValue.child(0)); + windowExpression = windowExpression.withFunction(lastValue); + } return lastValue; } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CheckAndStandardizeWindowFunctionTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CheckAndStandardizeWindowFunctionTest.java index ffe88af2fea0ba..2f3b133fdeb1ea 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CheckAndStandardizeWindowFunctionTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/CheckAndStandardizeWindowFunctionTest.java @@ -28,11 +28,14 @@ import org.apache.doris.nereids.trees.expressions.WindowFrame.FrameBoundary; import org.apache.doris.nereids.trees.expressions.WindowFrame.FrameUnitsType; import org.apache.doris.nereids.trees.expressions.functions.window.DenseRank; +import org.apache.doris.nereids.trees.expressions.functions.window.FirstValue; import org.apache.doris.nereids.trees.expressions.functions.window.Lag; +import org.apache.doris.nereids.trees.expressions.functions.window.LastValue; import org.apache.doris.nereids.trees.expressions.functions.window.Lead; import org.apache.doris.nereids.trees.expressions.functions.window.Rank; import org.apache.doris.nereids.trees.expressions.functions.window.RowNumber; import org.apache.doris.nereids.trees.expressions.functions.window.WindowFunction; +import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral; import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral; import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral; import org.apache.doris.nereids.trees.plans.Plan; @@ -240,6 +243,29 @@ public void testCheckWindowFrameBeforeFunc5() { forCheckWindowFrameBeforeFunc(windowFrame2, errorMsg2); } + @Test + public void testFirstValueRewrite() { + age = rStudent.getOutput().get(3).toSlot(); + WindowExpression window = new WindowExpression(new FirstValue(age, BooleanLiteral.FALSE), partitionKeyList, orderKeyList); + Alias windowAlias = new Alias(window, window.toSql()); + WindowExpression windowLastValue = new WindowExpression(new LastValue(age, BooleanLiteral.FALSE), partitionKeyList, orderKeyList); + Alias windowLastValueAlias = new Alias(windowLastValue, windowLastValue.toSql()); + List outputExpressions = Lists.newArrayList(windowAlias, windowLastValueAlias); + Plan root = new LogicalWindow<>(outputExpressions, rStudent); + + PlanChecker.from(MemoTestUtils.createConnectContext(), root) + .applyTopDown(new ExtractAndNormalizeWindowExpression()) + .applyTopDown(new CheckAndStandardizeWindowFunctionAndFrame()) + .matches( + logicalWindow() + .when(logicalWindow -> { + WindowExpression newWindowFirstValue = (WindowExpression) logicalWindow.getWindowExpressions().get(0).child(0); + WindowExpression newWindowLastValue = (WindowExpression) logicalWindow.getWindowExpressions().get(0).child(0); + return newWindowFirstValue.getFunction().arity() == 1 && newWindowLastValue.getFunction().arity() == 1; + }) + ); + } + private void forCheckWindowFrameBeforeFunc(WindowFrame windowFrame, String errorMsg) { WindowExpression window = new WindowExpression(new Rank(), partitionKeyList, orderKeyList, windowFrame); forCheckWindowFrameBeforeFunc(window, errorMsg); diff --git a/regression-test/data/nereids_syntax_p0/window_function.out b/regression-test/data/nereids_syntax_p0/window_function.out index 38eba68274e18f..378524125c9474 100644 --- a/regression-test/data/nereids_syntax_p0/window_function.out +++ b/regression-test/data/nereids_syntax_p0/window_function.out @@ -567,3 +567,35 @@ -- !multi_winf2 -- 1 35 +-- !first_value_false -- +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 + +-- !last_value_false -- +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 + diff --git a/regression-test/suites/nereids_syntax_p0/window_function.groovy b/regression-test/suites/nereids_syntax_p0/window_function.groovy index f2ce708f4c372a..bb19aba17c10fc 100644 --- a/regression-test/suites/nereids_syntax_p0/window_function.groovy +++ b/regression-test/suites/nereids_syntax_p0/window_function.groovy @@ -314,4 +314,7 @@ suite("window_function") { sql "select last_value(c1,false) over() from window_test" sql "select first_value(c1,1) over() from window_test" sql "select last_value(c1,0) over() from window_test" + + qt_first_value_false "select last_value(c1,false) over(partition by c2 order by c1) from window_test order by 1" + qt_last_value_false "select first_value(c1,false) over(partition by c2 order by c1) from window_test order by 1" } From 24eae4b3d0d5bda57664ab1c1e2166cb2b51fbe7 Mon Sep 17 00:00:00 2001 From: Calvin Kirs Date: Wed, 11 Dec 2024 17:47:35 +0800 Subject: [PATCH 02/63] [Job](Fix)Improve Event Publishing with Timeout (#45103) ### Summary: This PR refines the publishEvent method to improve event publishing reliability by introducing a timeout mechanism and enhanced logging. The changes allow for a more responsive system when attempting to publish events to the disruptor, especially in cases where the ring buffer may not have sufficient capacity at the time. #### Timeout Implementation: A 1-second timeout (in nanoseconds) is set, after which the event publishing attempt will stop if the required capacity is not available. The timeout is tracked using System.nanoTime() for precise elapsed time measurement. #### Remaining Capacity Check: The method checks if the remainingCapacity() of the ring buffer is greater than 1 (this can be adjusted based on your capacity requirements). If enough capacity is available, the event is published; otherwise, it waits and retries. --- .../doris/job/disruptor/ExecuteTaskEvent.java | 5 ++ .../doris/job/disruptor/TaskDisruptor.java | 48 +++++++--- .../executor/DefaultTaskExecutorHandler.java | 40 +++------ .../job/executor/DispatchTaskHandler.java | 7 +- .../doris/job/executor/TaskProcessor.java | 87 +++++++++++++++++++ .../manager/TaskDisruptorGroupManager.java | 48 +++------- 6 files changed, 158 insertions(+), 77 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/job/executor/TaskProcessor.java diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/disruptor/ExecuteTaskEvent.java b/fe/fe-core/src/main/java/org/apache/doris/job/disruptor/ExecuteTaskEvent.java index 3d8f9ed15349ae..ac67715d2ca18e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/disruptor/ExecuteTaskEvent.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/disruptor/ExecuteTaskEvent.java @@ -34,4 +34,9 @@ public static EventFactory> factory return ExecuteTaskEvent::new; } + public void clear() { + this.task = null; + this.jobConfig = null; + } + } diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/disruptor/TaskDisruptor.java b/fe/fe-core/src/main/java/org/apache/doris/job/disruptor/TaskDisruptor.java index 2b2e3df0418dd3..9fb9d94e8df70f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/disruptor/TaskDisruptor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/disruptor/TaskDisruptor.java @@ -19,7 +19,6 @@ import com.lmax.disruptor.EventFactory; import com.lmax.disruptor.EventTranslatorVararg; -import com.lmax.disruptor.RingBuffer; import com.lmax.disruptor.WaitStrategy; import com.lmax.disruptor.WorkHandler; import com.lmax.disruptor.dsl.Disruptor; @@ -28,6 +27,7 @@ import org.apache.logging.log4j.Logger; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; /** * Utility class for creating and managing a Disruptor instance. @@ -73,20 +73,42 @@ public void start() { */ public boolean publishEvent(Object... args) { try { - RingBuffer ringBuffer = disruptor.getRingBuffer(); - // Check if the RingBuffer has enough capacity to reserve 10 slots for tasks - // If there is insufficient capacity (less than 10 slots available) - // log a warning and drop the current task - if (!ringBuffer.hasAvailableCapacity(10)) { - LOG.warn("ring buffer has no available capacity,task will be dropped," - + "please check the task queue size."); - return false; + // Set the timeout to 1 second, converted to nanoseconds for precision + long timeoutInNanos = TimeUnit.SECONDS.toNanos(1); // Timeout set to 1 second + long startTime = System.nanoTime(); // Record the start time + + // Loop until the timeout is reached + while (System.nanoTime() - startTime < timeoutInNanos) { + // Check if there is enough remaining capacity in the ring buffer + // Adjusting to check if the required capacity is available (instead of hardcoding 1) + if (disruptor.getRingBuffer().remainingCapacity() > 1) { + // Publish the event if there is enough capacity + disruptor.getRingBuffer().publishEvent(eventTranslator, args); + if (LOG.isDebugEnabled()) { + LOG.debug("publishEvent success,the remaining buffer size is {}", + disruptor.getRingBuffer().remainingCapacity()); + } + return true; + } + + // Wait for a short period before retrying + try { + Thread.sleep(10); // Adjust the wait time as needed (maybe increase if not high-frequency) + } catch (InterruptedException e) { + // Log the exception and return false if interrupted + Thread.currentThread().interrupt(); // Restore interrupt status + LOG.warn("Thread interrupted while waiting to publish event", e); + return false; + } } - ringBuffer.publishEvent(eventTranslator, args); - return true; + + // Timeout reached without publishing the event + LOG.warn("Failed to publish event within the specified timeout (1 second)." + + "Queue may be full. the remaining buffer size is {}", + disruptor.getRingBuffer().remainingCapacity()); } catch (Exception e) { - LOG.warn("Failed to publish event", e); - // Handle the exception, e.g., retry or alert + // Catching general exceptions to handle unexpected errors + LOG.warn("Failed to publish event due to an unexpected error", e); } return false; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/executor/DefaultTaskExecutorHandler.java b/fe/fe-core/src/main/java/org/apache/doris/job/executor/DefaultTaskExecutorHandler.java index befa8cc35fcbcc..cdfe7c0fe08f63 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/executor/DefaultTaskExecutorHandler.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/executor/DefaultTaskExecutorHandler.java @@ -36,35 +36,23 @@ public class DefaultTaskExecutorHandler implements WorkH @Override public void onEvent(ExecuteTaskEvent executeTaskEvent) { - T task = executeTaskEvent.getTask(); - if (null == task) { - log.warn("task is null, ignore,maybe task has been canceled"); - return; - } - if (task.isCancelled()) { - log.info("task is canceled, ignore. task id is {}", task.getTaskId()); - return; - } - log.info("start to execute task, task id is {}", task.getTaskId()); - try { - task.runTask(); - } catch (Exception e) { - //if task.onFail() throw exception, we will catch it here - log.warn("task before error, task id is {}", task.getTaskId(), e); - } - //todo we need discuss whether we need to use semaphore to control the concurrent task num - /* Semaphore semaphore = null; - // get token try { - int maxConcurrentTaskNum = executeTaskEvent.getJobConfig().getMaxConcurrentTaskNum(); - semaphore = TaskTokenManager.tryAcquire(task.getJobId(), maxConcurrentTaskNum); + T task = executeTaskEvent.getTask(); + if (null == task) { + log.warn("task is null, ignore,maybe task has been canceled"); + return; + } + if (task.isCancelled()) { + log.info("task is canceled, ignore. task id is {}", task.getTaskId()); + return; + } + log.info("start to execute task, task id is {}", task.getTaskId()); task.runTask(); } catch (Exception e) { - task.onFail(); - log.error("execute task error, task id is {}", task.getTaskId(), e); + log.error("execute task error, task id is {}", executeTaskEvent.getTask().getTaskId(), e); } finally { - if (null != semaphore) { - semaphore.release(); - }*/ + executeTaskEvent.clear(); + } + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/executor/DispatchTaskHandler.java b/fe/fe-core/src/main/java/org/apache/doris/job/executor/DispatchTaskHandler.java index d93393aa0ef89f..b8f726c4a0c76f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/executor/DispatchTaskHandler.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/executor/DispatchTaskHandler.java @@ -21,7 +21,6 @@ import org.apache.doris.job.common.JobStatus; import org.apache.doris.job.common.JobType; import org.apache.doris.job.common.TaskType; -import org.apache.doris.job.disruptor.TaskDisruptor; import org.apache.doris.job.disruptor.TimerJobEvent; import org.apache.doris.job.task.AbstractTask; @@ -40,9 +39,9 @@ @Log4j2 public class DispatchTaskHandler implements WorkHandler> { - private final Map> disruptorMap; + private final Map disruptorMap; - public DispatchTaskHandler(Map> disruptorMap) { + public DispatchTaskHandler(Map disruptorMap) { this.disruptorMap = disruptorMap; } @@ -66,7 +65,7 @@ public void onEvent(TimerJobEvent event) { } JobType jobType = event.getJob().getJobType(); for (AbstractTask task : tasks) { - if (!disruptorMap.get(jobType).publishEvent(task, event.getJob().getJobConfig())) { + if (!disruptorMap.get(jobType).addTask(task)) { task.cancel(); continue; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/executor/TaskProcessor.java b/fe/fe-core/src/main/java/org/apache/doris/job/executor/TaskProcessor.java new file mode 100644 index 00000000000000..d9d3f25dcd8a80 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/job/executor/TaskProcessor.java @@ -0,0 +1,87 @@ +// 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. + +package org.apache.doris.job.executor; + +import org.apache.doris.job.task.AbstractTask; + +import lombok.extern.log4j.Log4j2; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +@Log4j2 +public class TaskProcessor { + private ExecutorService executor; + + public TaskProcessor(int numberOfThreads, int queueSize, ThreadFactory threadFactory) { + this.executor = new ThreadPoolExecutor( + numberOfThreads, + numberOfThreads, + 0L, TimeUnit.MILLISECONDS, + new ArrayBlockingQueue<>(queueSize), + threadFactory, + new ThreadPoolExecutor.AbortPolicy() + ); + } + + public boolean addTask(AbstractTask task) { + try { + executor.execute(() -> runTask(task)); + log.info("Add task to executor, task id: {}", task.getTaskId()); + return true; + } catch (RejectedExecutionException e) { + log.warn("Failed to add task to executor, task id: {}", task.getTaskId(), e); + return false; + } + } + + public void shutdown() { + log.info("Shutting down executor service..."); + executor.shutdown(); + try { + if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + log.info("Executor service shut down successfully."); + } + + private void runTask(AbstractTask task) { + try { + if (task == null) { + log.warn("Task is null, ignore. Maybe it has been canceled."); + return; + } + if (task.isCancelled()) { + log.info("Task is canceled, ignore. Task id: {}", task.getTaskId()); + return; + } + log.info("Start to execute task, task id: {}", task.getTaskId()); + task.runTask(); + } catch (Exception e) { + log.warn("Execute task error, task id: {}", task.getTaskId(), e); + } + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/manager/TaskDisruptorGroupManager.java b/fe/fe-core/src/main/java/org/apache/doris/job/manager/TaskDisruptorGroupManager.java index cc82b59a36a36f..e77dfbadcb3742 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/manager/TaskDisruptorGroupManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/manager/TaskDisruptorGroupManager.java @@ -22,13 +22,10 @@ import org.apache.doris.job.base.AbstractJob; import org.apache.doris.job.base.JobExecutionConfiguration; import org.apache.doris.job.common.JobType; -import org.apache.doris.job.disruptor.ExecuteTaskEvent; import org.apache.doris.job.disruptor.TaskDisruptor; import org.apache.doris.job.disruptor.TimerJobEvent; -import org.apache.doris.job.executor.DefaultTaskExecutorHandler; import org.apache.doris.job.executor.DispatchTaskHandler; -import org.apache.doris.job.extensions.insert.InsertTask; -import org.apache.doris.job.extensions.mtmv.MTMVTask; +import org.apache.doris.job.executor.TaskProcessor; import org.apache.doris.job.task.AbstractTask; import com.lmax.disruptor.EventFactory; @@ -44,7 +41,7 @@ public class TaskDisruptorGroupManager { - private final Map> disruptorMap = new EnumMap<>(JobType.class); + private final Map disruptorMap = new EnumMap<>(JobType.class); @Getter private TaskDisruptor> dispatchDisruptor; @@ -92,44 +89,27 @@ private void registerDispatchDisruptor() { } private void registerInsertDisruptor() { - EventFactory> insertEventFactory = ExecuteTaskEvent.factory(); ThreadFactory insertTaskThreadFactory = new CustomThreadFactory("insert-task-execute"); - WorkHandler[] insertTaskExecutorHandlers = new WorkHandler[DISPATCH_INSERT_THREAD_NUM]; - for (int i = 0; i < DISPATCH_INSERT_THREAD_NUM; i++) { - insertTaskExecutorHandlers[i] = new DefaultTaskExecutorHandler(); - } - EventTranslatorVararg> eventTranslator = - (event, sequence, args) -> { - event.setTask((InsertTask) args[0]); - event.setJobConfig((JobExecutionConfiguration) args[1]); - }; - TaskDisruptor insertDisruptor = new TaskDisruptor<>(insertEventFactory, DISPATCH_INSERT_TASK_QUEUE_SIZE, - insertTaskThreadFactory, new LiteTimeoutBlockingWaitStrategy(10, TimeUnit.MILLISECONDS), - insertTaskExecutorHandlers, eventTranslator); - disruptorMap.put(JobType.INSERT, insertDisruptor); + + + TaskProcessor insertTaskProcessor = new TaskProcessor(DISPATCH_INSERT_THREAD_NUM, + DISPATCH_INSERT_TASK_QUEUE_SIZE, insertTaskThreadFactory); + disruptorMap.put(JobType.INSERT, insertTaskProcessor); } private void registerMTMVDisruptor() { - EventFactory> mtmvEventFactory = ExecuteTaskEvent.factory(); + ThreadFactory mtmvTaskThreadFactory = new CustomThreadFactory("mtmv-task-execute"); - WorkHandler[] insertTaskExecutorHandlers = new WorkHandler[DISPATCH_MTMV_THREAD_NUM]; - for (int i = 0; i < DISPATCH_MTMV_THREAD_NUM; i++) { - insertTaskExecutorHandlers[i] = new DefaultTaskExecutorHandler(); - } - EventTranslatorVararg> eventTranslator = - (event, sequence, args) -> { - event.setTask((MTMVTask) args[0]); - event.setJobConfig((JobExecutionConfiguration) args[1]); - }; - TaskDisruptor mtmvDisruptor = new TaskDisruptor<>(mtmvEventFactory, DISPATCH_MTMV_TASK_QUEUE_SIZE, - mtmvTaskThreadFactory, new LiteTimeoutBlockingWaitStrategy(10, TimeUnit.MILLISECONDS), - insertTaskExecutorHandlers, eventTranslator); - disruptorMap.put(JobType.MV, mtmvDisruptor); + TaskProcessor mtmvTaskProcessor = new TaskProcessor(DISPATCH_MTMV_THREAD_NUM, + DISPATCH_MTMV_TASK_QUEUE_SIZE, mtmvTaskThreadFactory); + disruptorMap.put(JobType.MV, mtmvTaskProcessor); } public boolean dispatchInstantTask(AbstractTask task, JobType jobType, JobExecutionConfiguration jobExecutionConfiguration) { - return disruptorMap.get(jobType).publishEvent(task, jobExecutionConfiguration); + + + return disruptorMap.get(jobType).addTask(task); } From 47b2dddedcbd026a17442b1a5575f6aafb907ce2 Mon Sep 17 00:00:00 2001 From: zhangdong Date: Wed, 11 Dec 2024 17:48:28 +0800 Subject: [PATCH 03/63] [feat](mtmv)use real snapshot instead of optional.empty() (#45273) In the previous PR, a snapshot of the table was obtained and stored in the statementContext at the beginning of the query. The modification of this PR is to ensure that the same metadata is used during the query process. When calling the relevant interface, snapshot needs to be obtained from statementContext as a parameter and passed to the relevant method Related PR: #44911 #44673 --- .../doris/mtmv/MTMVPartitionExprDateTrunc.java | 3 ++- .../apache/doris/mtmv/MTMVPartitionInfo.java | 6 ++++-- .../apache/doris/mtmv/MTMVPartitionUtil.java | 18 +++++++++--------- .../MTMVRelatedPartitionDescInitGenerator.java | 5 +++-- ...TMVRelatedPartitionDescRollUpGenerator.java | 4 ++-- .../exploration/mv/MaterializedViewUtils.java | 6 ++++-- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionExprDateTrunc.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionExprDateTrunc.java index 95a8717e01c4c7..764c87c4b115fe 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionExprDateTrunc.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionExprDateTrunc.java @@ -27,6 +27,7 @@ import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.util.PropertyAnalyzer; +import org.apache.doris.datasource.mvcc.MvccUtil; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.executable.DateTimeArithmetic; import org.apache.doris.nereids.trees.expressions.functions.executable.DateTimeExtractAndTransform; @@ -69,7 +70,7 @@ public void analyze(MTMVPartitionInfo mvPartitionInfo) throws AnalysisException String.format("timeUnit not support: %s, only support: %s", this.timeUnit, timeUnits)); } MTMVRelatedTableIf relatedTable = mvPartitionInfo.getRelatedTable(); - PartitionType partitionType = relatedTable.getPartitionType(Optional.empty()); + PartitionType partitionType = relatedTable.getPartitionType(MvccUtil.getSnapshotFromContext(relatedTable)); if (partitionType == PartitionType.RANGE) { Type partitionColumnType = MTMVPartitionUtil .getPartitionColumnType(mvPartitionInfo.getRelatedTable(), mvPartitionInfo.getRelatedCol()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionInfo.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionInfo.java index 7eae44db0af4cc..5a14867c7e1ab3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionInfo.java @@ -21,11 +21,11 @@ import org.apache.doris.catalog.Column; import org.apache.doris.common.AnalysisException; import org.apache.doris.datasource.CatalogMgr; +import org.apache.doris.datasource.mvcc.MvccUtil; import com.google.gson.annotations.SerializedName; import java.util.List; -import java.util.Optional; /** * MTMVPartitionInfo @@ -116,7 +116,9 @@ public int getRelatedColPos() throws AnalysisException { if (partitionType == MTMVPartitionType.SELF_MANAGE) { throw new AnalysisException("partitionType is: " + partitionType); } - List partitionColumns = getRelatedTable().getPartitionColumns(Optional.empty()); + MTMVRelatedTableIf mtmvRelatedTableIf = getRelatedTable(); + List partitionColumns = mtmvRelatedTableIf.getPartitionColumns( + MvccUtil.getSnapshotFromContext(mtmvRelatedTableIf)); for (int i = 0; i < partitionColumns.size(); i++) { if (partitionColumns.get(i).getName().equalsIgnoreCase(relatedCol)) { return i; diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionUtil.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionUtil.java index 55ce86e75706c7..92436b063e0b49 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionUtil.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPartitionUtil.java @@ -32,6 +32,7 @@ import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.DdlException; +import org.apache.doris.datasource.mvcc.MvccUtil; import org.apache.doris.mtmv.MTMVPartitionInfo.MTMVPartitionType; import org.apache.doris.rpc.RpcException; @@ -50,7 +51,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -324,7 +324,7 @@ public static boolean isSyncWithPartitions(MTMVRefreshContext context, String mt } for (String relatedPartitionName : relatedPartitionNames) { MTMVSnapshotIf relatedPartitionCurrentSnapshot = relatedTable - .getPartitionSnapshot(relatedPartitionName, context, Optional.empty()); + .getPartitionSnapshot(relatedPartitionName, context, MvccUtil.getSnapshotFromContext(relatedTable)); if (!mtmv.getRefreshSnapshot() .equalsWithRelatedPartition(mtmvPartitionName, relatedPartitionName, relatedPartitionCurrentSnapshot)) { @@ -441,7 +441,8 @@ private static boolean isSyncWithBaseTable(MTMVRefreshContext context, String mt if (!baseTable.needAutoRefresh()) { return true; } - MTMVSnapshotIf baseTableCurrentSnapshot = baseTable.getTableSnapshot(context, Optional.empty()); + MTMVSnapshotIf baseTableCurrentSnapshot = baseTable.getTableSnapshot(context, + MvccUtil.getSnapshotFromContext(baseTable)); return mtmv.getRefreshSnapshot() .equalsWithBaseTable(mtmvPartitionName, new BaseTableInfo(baseTable), baseTableCurrentSnapshot); } @@ -476,10 +477,9 @@ private static MTMVRefreshPartitionSnapshot generatePartitionSnapshot(MTMVRefres if (mtmv.getMvPartitionInfo().getPartitionType() != MTMVPartitionType.SELF_MANAGE) { MTMVRelatedTableIf relatedTable = mtmv.getMvPartitionInfo().getRelatedTable(); for (String relatedPartitionName : relatedPartitionNames) { - MTMVSnapshotIf partitionSnapshot = relatedTable - .getPartitionSnapshot(relatedPartitionName, context, Optional.empty()); - refreshPartitionSnapshot.getPartitions() - .put(relatedPartitionName, partitionSnapshot); + MTMVSnapshotIf partitionSnapshot = relatedTable.getPartitionSnapshot(relatedPartitionName, context, + MvccUtil.getSnapshotFromContext(relatedTable)); + refreshPartitionSnapshot.getPartitions().put(relatedPartitionName, partitionSnapshot); } } for (BaseTableInfo baseTableInfo : baseTables) { @@ -492,13 +492,13 @@ private static MTMVRefreshPartitionSnapshot generatePartitionSnapshot(MTMVRefres continue; } refreshPartitionSnapshot.addTableSnapshot(baseTableInfo, - ((MTMVRelatedTableIf) table).getTableSnapshot(context, Optional.empty())); + ((MTMVRelatedTableIf) table).getTableSnapshot(context, MvccUtil.getSnapshotFromContext(table))); } return refreshPartitionSnapshot; } public static Type getPartitionColumnType(MTMVRelatedTableIf relatedTable, String col) throws AnalysisException { - List partitionColumns = relatedTable.getPartitionColumns(Optional.empty()); + List partitionColumns = relatedTable.getPartitionColumns(MvccUtil.getSnapshotFromContext(relatedTable)); for (Column column : partitionColumns) { if (column.getName().equals(col)) { return column.getType(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelatedPartitionDescInitGenerator.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelatedPartitionDescInitGenerator.java index c6b4e331184e2a..28900f38e59f62 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelatedPartitionDescInitGenerator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelatedPartitionDescInitGenerator.java @@ -18,9 +18,9 @@ package org.apache.doris.mtmv; import org.apache.doris.common.AnalysisException; +import org.apache.doris.datasource.mvcc.MvccUtil; import java.util.Map; -import java.util.Optional; /** * get all related partition descs @@ -30,6 +30,7 @@ public class MTMVRelatedPartitionDescInitGenerator implements MTMVRelatedPartiti @Override public void apply(MTMVPartitionInfo mvPartitionInfo, Map mvProperties, RelatedPartitionDescResult lastResult) throws AnalysisException { - lastResult.setItems(mvPartitionInfo.getRelatedTable().getAndCopyPartitionItems(Optional.empty())); + MTMVRelatedTableIf relatedTable = mvPartitionInfo.getRelatedTable(); + lastResult.setItems(relatedTable.getAndCopyPartitionItems(MvccUtil.getSnapshotFromContext(relatedTable))); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelatedPartitionDescRollUpGenerator.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelatedPartitionDescRollUpGenerator.java index 325fab819d9a09..71f7fc358f5975 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelatedPartitionDescRollUpGenerator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelatedPartitionDescRollUpGenerator.java @@ -21,6 +21,7 @@ import org.apache.doris.analysis.PartitionValue; import org.apache.doris.catalog.PartitionType; import org.apache.doris.common.AnalysisException; +import org.apache.doris.datasource.mvcc.MvccUtil; import org.apache.doris.mtmv.MTMVPartitionInfo.MTMVPartitionType; import com.google.common.base.Preconditions; @@ -31,7 +32,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Optional; import java.util.Set; /** @@ -46,7 +46,7 @@ public void apply(MTMVPartitionInfo mvPartitionInfo, Map mvPrope return; } MTMVRelatedTableIf relatedTable = mvPartitionInfo.getRelatedTable(); - PartitionType partitionType = relatedTable.getPartitionType(Optional.empty()); + PartitionType partitionType = relatedTable.getPartitionType(MvccUtil.getSnapshotFromContext(relatedTable)); if (partitionType == PartitionType.RANGE) { lastResult.setDescs(rollUpRange(lastResult.getDescs(), mvPartitionInfo)); } else if (partitionType == PartitionType.LIST) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java index 4c5703e27687e4..4ddb93409379e9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java @@ -24,6 +24,7 @@ import org.apache.doris.catalog.PartitionType; import org.apache.doris.catalog.TableIf; import org.apache.doris.catalog.constraint.TableIdentifier; +import org.apache.doris.datasource.mvcc.MvccUtil; import org.apache.doris.mtmv.BaseTableInfo; import org.apache.doris.mtmv.MTMVCache; import org.apache.doris.mtmv.MTMVRelatedTableIf; @@ -497,13 +498,14 @@ public Void visitLogicalRelation(LogicalRelation relation, IncrementCheckerConte return null; } MTMVRelatedTableIf relatedTable = (MTMVRelatedTableIf) table; - PartitionType type = relatedTable.getPartitionType(Optional.empty()); + PartitionType type = relatedTable.getPartitionType(MvccUtil.getSnapshotFromContext(relatedTable)); if (PartitionType.UNPARTITIONED.equals(type)) { context.addFailReason(String.format("related base table is not partition table, the table is %s", table.getName())); return null; } - Set partitionColumnSet = new HashSet<>(relatedTable.getPartitionColumns(Optional.empty())); + Set partitionColumnSet = new HashSet<>( + relatedTable.getPartitionColumns(MvccUtil.getSnapshotFromContext(relatedTable))); Column mvReferenceColumn = contextPartitionColumn.getColumn().get(); Expr definExpr = mvReferenceColumn.getDefineExpr(); if (definExpr instanceof SlotRef) { From ff090ff641ce8e96c3db918de84875632f453623 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Wed, 11 Dec 2024 17:55:56 +0800 Subject: [PATCH 04/63] =?UTF-8?q?[refactor](shuffle)=20(PART=20II)=20Split?= =?UTF-8?q?=20local=20exchange=20operators=20from=20loc=E2=80=A6=20(#45280?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …al exchanger This is a PR which wants to decouple the local exchanger and local exchange operators. Since all type of exchangers are similar as exchange sink does, I plan to use exchanger to split data in both local exchange operators and exchange sink operators. --- be/src/pipeline/dependency.cpp | 5 +- be/src/pipeline/dependency.h | 2 +- .../local_exchange_sink_operator.cpp | 5 +- .../local_exchange_sink_operator.h | 1 - .../local_exchange_source_operator.cpp | 8 +- .../local_exchange/local_exchanger.cpp | 367 +++++++++++------- .../pipeline/local_exchange/local_exchanger.h | 127 +++--- 7 files changed, 325 insertions(+), 190 deletions(-) diff --git a/be/src/pipeline/dependency.cpp b/be/src/pipeline/dependency.cpp index 5fef018423df25..dcf5c7a0a81d7c 100644 --- a/be/src/pipeline/dependency.cpp +++ b/be/src/pipeline/dependency.cpp @@ -179,12 +179,11 @@ void LocalExchangeSharedState::sub_running_sink_operators() { } } -void LocalExchangeSharedState::sub_running_source_operators( - LocalExchangeSourceLocalState& local_state) { +void LocalExchangeSharedState::sub_running_source_operators() { std::unique_lock lc(le_lock); if (exchanger->_running_source_operators.fetch_sub(1) == 1) { _set_always_ready(); - exchanger->finalize(local_state); + exchanger->finalize(); } } diff --git a/be/src/pipeline/dependency.h b/be/src/pipeline/dependency.h index ad018c8b4f8f3d..f1cfe2b02977e1 100644 --- a/be/src/pipeline/dependency.h +++ b/be/src/pipeline/dependency.h @@ -758,7 +758,7 @@ struct LocalExchangeSharedState : public BasicSharedState { } } void sub_running_sink_operators(); - void sub_running_source_operators(LocalExchangeSourceLocalState& local_state); + void sub_running_source_operators(); void _set_always_ready() { for (auto& dep : source_deps) { DCHECK(dep); diff --git a/be/src/pipeline/local_exchange/local_exchange_sink_operator.cpp b/be/src/pipeline/local_exchange/local_exchange_sink_operator.cpp index 22007a4b220348..b22ee9fd77e72f 100644 --- a/be/src/pipeline/local_exchange/local_exchange_sink_operator.cpp +++ b/be/src/pipeline/local_exchange/local_exchange_sink_operator.cpp @@ -144,7 +144,10 @@ Status LocalExchangeSinkOperatorX::sink(RuntimeState* state, vectorized::Block* auto& local_state = get_local_state(state); SCOPED_TIMER(local_state.exec_time_counter()); COUNTER_UPDATE(local_state.rows_input_counter(), (int64_t)in_block->rows()); - RETURN_IF_ERROR(local_state._exchanger->sink(state, in_block, eos, local_state)); + RETURN_IF_ERROR(local_state._exchanger->sink( + state, in_block, eos, + {local_state._compute_hash_value_timer, local_state._distribute_timer, nullptr}, + {&local_state._channel_id, local_state._partitioner.get(), &local_state})); // If all exchange sources ended due to limit reached, current task should also finish if (local_state._exchanger->_running_source_operators == 0) { diff --git a/be/src/pipeline/local_exchange/local_exchange_sink_operator.h b/be/src/pipeline/local_exchange/local_exchange_sink_operator.h index 435f7a410a4ca6..c067f023c8d420 100644 --- a/be/src/pipeline/local_exchange/local_exchange_sink_operator.h +++ b/be/src/pipeline/local_exchange/local_exchange_sink_operator.h @@ -65,7 +65,6 @@ class LocalExchangeSinkLocalState final : public PipelineXSinkLocalState _partitioner = nullptr; - std::vector _partition_rows_histogram; // Used by random passthrough exchanger int _channel_id = 0; diff --git a/be/src/pipeline/local_exchange/local_exchange_source_operator.cpp b/be/src/pipeline/local_exchange/local_exchange_source_operator.cpp index c4832b9958c00d..63e36cdfdb0c01 100644 --- a/be/src/pipeline/local_exchange/local_exchange_source_operator.cpp +++ b/be/src/pipeline/local_exchange/local_exchange_source_operator.cpp @@ -61,10 +61,10 @@ Status LocalExchangeSourceLocalState::close(RuntimeState* state) { } if (_exchanger) { - _exchanger->close(*this); + _exchanger->close({_channel_id, this}); } if (_shared_state) { - _shared_state->sub_running_source_operators(*this); + _shared_state->sub_running_source_operators(); } std::vector {}.swap(_local_merge_deps); @@ -116,7 +116,9 @@ Status LocalExchangeSourceOperatorX::get_block(RuntimeState* state, vectorized:: bool* eos) { auto& local_state = get_local_state(state); SCOPED_TIMER(local_state.exec_time_counter()); - RETURN_IF_ERROR(local_state._exchanger->get_block(state, block, eos, local_state)); + RETURN_IF_ERROR(local_state._exchanger->get_block( + state, block, eos, {nullptr, nullptr, local_state._copy_data_timer}, + {local_state._channel_id, &local_state})); local_state.reached_limit(block, eos); return Status::OK(); } diff --git a/be/src/pipeline/local_exchange/local_exchanger.cpp b/be/src/pipeline/local_exchange/local_exchanger.cpp index 647988f8b794cb..a963de8b684310 100644 --- a/be/src/pipeline/local_exchange/local_exchanger.cpp +++ b/be/src/pipeline/local_exchange/local_exchanger.cpp @@ -29,8 +29,12 @@ namespace doris::pipeline { #include "common/compile_check_begin.h" template void Exchanger::_enqueue_data_and_set_ready(int channel_id, - LocalExchangeSinkLocalState& local_state, + LocalExchangeSinkLocalState* local_state, BlockType&& block) { + if (local_state == nullptr) { + _enqueue_data_and_set_ready(channel_id, std::move(block)); + return; + } size_t allocated_bytes = 0; // PartitionedBlock is used by shuffle exchanger. // PartitionedBlock will be push into multiple queues with different row ranges, so it will be @@ -44,47 +48,47 @@ void Exchanger::_enqueue_data_and_set_ready(int channel_id, allocated_bytes = block->data_block.allocated_bytes(); } std::unique_lock l(_m); - local_state._shared_state->add_mem_usage(channel_id, allocated_bytes, - !std::is_same_v && - !std::is_same_v); + local_state->_shared_state->add_mem_usage(channel_id, allocated_bytes, + !std::is_same_v && + !std::is_same_v); if (_data_queue[channel_id].enqueue(std::move(block))) { - local_state._shared_state->set_ready_to_read(channel_id); + local_state->_shared_state->set_ready_to_read(channel_id); } else { - local_state._shared_state->sub_mem_usage(channel_id, allocated_bytes); + local_state->_shared_state->sub_mem_usage(channel_id, allocated_bytes); // `enqueue(block)` return false iff this queue's source operator is already closed so we // just unref the block. if constexpr (std::is_same_v || std::is_same_v) { - block.first->unref(local_state._shared_state, allocated_bytes, channel_id); + block.first->unref(local_state->_shared_state, allocated_bytes, channel_id); } else { - block->unref(local_state._shared_state, allocated_bytes, channel_id); + block->unref(local_state->_shared_state, allocated_bytes, channel_id); DCHECK_EQ(block->ref_value(), 0); } } } template -bool Exchanger::_dequeue_data(LocalExchangeSourceLocalState& local_state, - BlockType& block, bool* eos, - vectorized::Block* data_block) { - return _dequeue_data(local_state, block, eos, data_block, local_state._channel_id); -} - -template -bool Exchanger::_dequeue_data(LocalExchangeSourceLocalState& local_state, +bool Exchanger::_dequeue_data(LocalExchangeSourceLocalState* local_state, BlockType& block, bool* eos, vectorized::Block* data_block, int channel_id) { + if (local_state == nullptr) { + if (!_dequeue_data(block, eos, data_block, channel_id)) { + throw Exception(ErrorCode::INTERNAL_ERROR, "Exchanger has no data: {}", + data_queue_debug_string(channel_id)); + } + return true; + } bool all_finished = _running_sink_operators == 0; if (_data_queue[channel_id].try_dequeue(block)) { if constexpr (std::is_same_v || std::is_same_v) { - local_state._shared_state->sub_mem_usage(channel_id, - block.first->data_block.allocated_bytes()); + local_state->_shared_state->sub_mem_usage(channel_id, + block.first->data_block.allocated_bytes()); } else { - local_state._shared_state->sub_mem_usage(channel_id, - block->data_block.allocated_bytes()); + local_state->_shared_state->sub_mem_usage(channel_id, + block->data_block.allocated_bytes()); data_block->swap(block->data_block); - block->unref(local_state._shared_state, data_block->allocated_bytes(), channel_id); + block->unref(local_state->_shared_state, data_block->allocated_bytes(), channel_id); DCHECK_EQ(block->ref_value(), 0); } return true; @@ -95,54 +99,88 @@ bool Exchanger::_dequeue_data(LocalExchangeSourceLocalState& local_st if (_data_queue[channel_id].try_dequeue(block)) { if constexpr (std::is_same_v || std::is_same_v) { - local_state._shared_state->sub_mem_usage(channel_id, - block.first->data_block.allocated_bytes()); + local_state->_shared_state->sub_mem_usage( + channel_id, block.first->data_block.allocated_bytes()); } else { - local_state._shared_state->sub_mem_usage(channel_id, - block->data_block.allocated_bytes()); + local_state->_shared_state->sub_mem_usage(channel_id, + block->data_block.allocated_bytes()); data_block->swap(block->data_block); - block->unref(local_state._shared_state, data_block->allocated_bytes(), channel_id); + block->unref(local_state->_shared_state, data_block->allocated_bytes(), channel_id); DCHECK_EQ(block->ref_value(), 0); } return true; } - COUNTER_UPDATE(local_state._get_block_failed_counter, 1); - local_state._dependency->block(); + COUNTER_UPDATE(local_state->_get_block_failed_counter, 1); + local_state->_dependency->block(); + } + return false; +} + +template +void Exchanger::_enqueue_data_and_set_ready(int channel_id, BlockType&& block) { + if constexpr (!std::is_same_v && + !std::is_same_v) { + block->ref(1); + } + if (!_data_queue[channel_id].enqueue(std::move(block))) { + if constexpr (std::is_same_v || + std::is_same_v) { + block.first->unref(); + } else { + block->unref(); + DCHECK_EQ(block->ref_value(), 0); + } + } +} + +template +bool Exchanger::_dequeue_data(BlockType& block, bool* eos, vectorized::Block* data_block, + int channel_id) { + if (_data_queue[channel_id].try_dequeue(block)) { + if constexpr (!std::is_same_v && + !std::is_same_v) { + data_block->swap(block->data_block); + block->unref(); + DCHECK_EQ(block->ref_value(), 0); + } + return true; } return false; } Status ShuffleExchanger::sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) { + Profile&& profile, SinkInfo&& sink_info) { if (in_block->empty()) { return Status::OK(); } { - SCOPED_TIMER(local_state._compute_hash_value_timer); - RETURN_IF_ERROR(local_state._partitioner->do_partitioning(state, in_block)); + SCOPED_TIMER(profile.compute_hash_value_timer); + RETURN_IF_ERROR(sink_info.partitioner->do_partitioning(state, in_block)); } { - SCOPED_TIMER(local_state._distribute_timer); - RETURN_IF_ERROR(_split_rows(state, - local_state._partitioner->get_channel_ids().get(), - in_block, local_state)); + SCOPED_TIMER(profile.distribute_timer); + RETURN_IF_ERROR(_split_rows(state, sink_info.partitioner->get_channel_ids().get(), + in_block, *sink_info.channel_id, sink_info.local_state)); } return Status::OK(); } -void ShuffleExchanger::close(LocalExchangeSourceLocalState& local_state) { +void ShuffleExchanger::close(SourceInfo&& source_info) { PartitionedBlock partitioned_block; bool eos; vectorized::Block block; - _data_queue[local_state._channel_id].set_eos(); - while (_dequeue_data(local_state, partitioned_block, &eos, &block)) { - partitioned_block.first->unref(local_state._shared_state, local_state._channel_id); + _data_queue[source_info.channel_id].set_eos(); + while (_dequeue_data(source_info.local_state, partitioned_block, &eos, &block, + source_info.channel_id)) { + partitioned_block.first->unref( + source_info.local_state ? source_info.local_state->_shared_state : nullptr, + source_info.channel_id); } } Status ShuffleExchanger::get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) { + Profile&& profile, SourceInfo&& source_info) { PartitionedBlock partitioned_block; vectorized::MutableBlock mutable_block; @@ -153,14 +191,18 @@ Status ShuffleExchanger::get_block(RuntimeState* state, vectorized::Block* block auto block_wrapper = partitioned_block.first; RETURN_IF_ERROR(mutable_block.add_rows(&block_wrapper->data_block, offset_start, offset_start + partitioned_block.second.length)); - block_wrapper->unref(local_state._shared_state, local_state._channel_id); + block_wrapper->unref( + source_info.local_state ? source_info.local_state->_shared_state : nullptr, + source_info.channel_id); } while (mutable_block.rows() < state->batch_size() && !*eos && - _dequeue_data(local_state, partitioned_block, eos, block)); + _dequeue_data(source_info.local_state, partitioned_block, eos, block, + source_info.channel_id)); return Status::OK(); }; - if (_dequeue_data(local_state, partitioned_block, eos, block)) { - SCOPED_TIMER(local_state._copy_data_timer); + if (_dequeue_data(source_info.local_state, partitioned_block, eos, block, + source_info.channel_id)) { + SCOPED_TIMER(profile.copy_data_timer); mutable_block = vectorized::VectorizedUtils::build_mutable_mem_reuse_block( block, partitioned_block.first->data_block); RETURN_IF_ERROR(get_data()); @@ -169,22 +211,25 @@ Status ShuffleExchanger::get_block(RuntimeState* state, vectorized::Block* block } Status ShuffleExchanger::_split_rows(RuntimeState* state, const uint32_t* __restrict channel_ids, - vectorized::Block* block, - LocalExchangeSinkLocalState& local_state) { + vectorized::Block* block, int channel_id, + LocalExchangeSinkLocalState* local_state) { + if (local_state == nullptr) { + return _split_rows(state, channel_ids, block, channel_id); + } const auto rows = cast_set(block->rows()); auto row_idx = std::make_shared>(rows); + auto& partition_rows_histogram = _partition_rows_histogram[channel_id]; { - local_state._partition_rows_histogram.assign(_num_partitions + 1, 0); + partition_rows_histogram.assign(_num_partitions + 1, 0); for (int32_t i = 0; i < rows; ++i) { - local_state._partition_rows_histogram[channel_ids[i]]++; + partition_rows_histogram[channel_ids[i]]++; } for (int32_t i = 1; i <= _num_partitions; ++i) { - local_state._partition_rows_histogram[i] += - local_state._partition_rows_histogram[i - 1]; + partition_rows_histogram[i] += partition_rows_histogram[i - 1]; } for (int32_t i = rows - 1; i >= 0; --i) { - (*row_idx)[local_state._partition_rows_histogram[channel_ids[i]] - 1] = i; - local_state._partition_rows_histogram[channel_ids[i]]--; + (*row_idx)[partition_rows_histogram[channel_ids[i]] - 1] = i; + partition_rows_histogram[channel_ids[i]]--; } } @@ -200,10 +245,10 @@ Status ShuffleExchanger::_split_rows(RuntimeState* state, const uint32_t* __rest if (new_block_wrapper->data_block.empty()) { return Status::OK(); } - local_state._shared_state->add_total_mem_usage(new_block_wrapper->data_block.allocated_bytes(), - local_state._channel_id); + local_state->_shared_state->add_total_mem_usage(new_block_wrapper->data_block.allocated_bytes(), + channel_id); auto bucket_seq_to_instance_idx = - local_state._parent->cast()._bucket_seq_to_instance_idx; + local_state->_parent->cast()._bucket_seq_to_instance_idx; if (get_type() == ExchangeType::HASH_SHUFFLE) { /** * If type is `HASH_SHUFFLE`, data are hash-shuffled and distributed to all instances of @@ -211,32 +256,32 @@ Status ShuffleExchanger::_split_rows(RuntimeState* state, const uint32_t* __rest * For example, row 1 get a hash value 1 which means we should distribute to instance 1 on * BE 1 and row 2 get a hash value 2 which means we should distribute to instance 1 on BE 3. */ - const auto& map = local_state._parent->cast() + const auto& map = local_state->_parent->cast() ._shuffle_idx_to_instance_idx; new_block_wrapper->ref(cast_set(map.size())); for (const auto& it : map) { DCHECK(it.second >= 0 && it.second < _num_partitions) << it.first << " : " << it.second << " " << _num_partitions; - uint32_t start = local_state._partition_rows_histogram[it.first]; - uint32_t size = local_state._partition_rows_histogram[it.first + 1] - start; + uint32_t start = partition_rows_histogram[it.first]; + uint32_t size = partition_rows_histogram[it.first + 1] - start; if (size > 0) { _enqueue_data_and_set_ready(it.second, local_state, {new_block_wrapper, {row_idx, start, size}}); } else { - new_block_wrapper->unref(local_state._shared_state, local_state._channel_id); + new_block_wrapper->unref(local_state->_shared_state, channel_id); } } } else { DCHECK(!bucket_seq_to_instance_idx.empty()); new_block_wrapper->ref(_num_partitions); for (int i = 0; i < _num_partitions; i++) { - uint32_t start = local_state._partition_rows_histogram[i]; - uint32_t size = local_state._partition_rows_histogram[i + 1] - start; + uint32_t start = partition_rows_histogram[i]; + uint32_t size = partition_rows_histogram[i + 1] - start; if (size > 0) { _enqueue_data_and_set_ready(bucket_seq_to_instance_idx[i], local_state, {new_block_wrapper, {row_idx, start, size}}); } else { - new_block_wrapper->unref(local_state._shared_state, local_state._channel_id); + new_block_wrapper->unref(local_state->_shared_state, channel_id); } } } @@ -244,8 +289,53 @@ Status ShuffleExchanger::_split_rows(RuntimeState* state, const uint32_t* __rest return Status::OK(); } +Status ShuffleExchanger::_split_rows(RuntimeState* state, const uint32_t* __restrict channel_ids, + vectorized::Block* block, int channel_id) { + const auto rows = cast_set(block->rows()); + auto row_idx = std::make_shared>(rows); + auto& partition_rows_histogram = _partition_rows_histogram[channel_id]; + { + partition_rows_histogram.assign(_num_partitions + 1, 0); + for (int32_t i = 0; i < rows; ++i) { + partition_rows_histogram[channel_ids[i]]++; + } + for (int32_t i = 1; i <= _num_partitions; ++i) { + partition_rows_histogram[i] += partition_rows_histogram[i - 1]; + } + for (int32_t i = rows - 1; i >= 0; --i) { + (*row_idx)[partition_rows_histogram[channel_ids[i]] - 1] = i; + partition_rows_histogram[channel_ids[i]]--; + } + } + + vectorized::Block data_block; + std::shared_ptr new_block_wrapper; + if (_free_blocks.try_dequeue(data_block)) { + new_block_wrapper = BlockWrapper::create_shared(std::move(data_block)); + } else { + new_block_wrapper = BlockWrapper::create_shared(block->clone_empty()); + } + + new_block_wrapper->data_block.swap(*block); + if (new_block_wrapper->data_block.empty()) { + return Status::OK(); + } + new_block_wrapper->ref(cast_set(_num_partitions)); + for (int i = 0; i < _num_partitions; i++) { + uint32_t start = partition_rows_histogram[i]; + uint32_t size = partition_rows_histogram[i + 1] - start; + if (size > 0) { + _enqueue_data_and_set_ready(i, {new_block_wrapper, {row_idx, start, size}}); + } else { + new_block_wrapper->unref(); + } + } + + return Status::OK(); +} + Status PassthroughExchanger::sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) { + Profile&& profile, SinkInfo&& sink_info) { if (in_block->empty()) { return Status::OK(); } @@ -256,41 +346,43 @@ Status PassthroughExchanger::sink(RuntimeState* state, vectorized::Block* in_blo } new_block.swap(*in_block); wrapper = BlockWrapper::create_shared(std::move(new_block)); - auto channel_id = (local_state._channel_id++) % _num_partitions; - _enqueue_data_and_set_ready(channel_id, local_state, std::move(wrapper)); + auto channel_id = ((*sink_info.channel_id)++) % _num_partitions; + _enqueue_data_and_set_ready(channel_id, sink_info.local_state, std::move(wrapper)); return Status::OK(); } -void PassthroughExchanger::close(LocalExchangeSourceLocalState& local_state) { +void PassthroughExchanger::close(SourceInfo&& source_info) { vectorized::Block next_block; BlockWrapperSPtr wrapper; bool eos; - _data_queue[local_state._channel_id].set_eos(); - while (_dequeue_data(local_state, wrapper, &eos, &next_block)) { + _data_queue[source_info.channel_id].set_eos(); + while (_dequeue_data(source_info.local_state, wrapper, &eos, &next_block, + source_info.channel_id)) { // do nothing } } -void PassToOneExchanger::close(LocalExchangeSourceLocalState& local_state) { +void PassToOneExchanger::close(SourceInfo&& source_info) { vectorized::Block next_block; BlockWrapperSPtr wrapper; bool eos; - _data_queue[local_state._channel_id].set_eos(); - while (_dequeue_data(local_state, wrapper, &eos, &next_block)) { + _data_queue[source_info.channel_id].set_eos(); + while (_dequeue_data(source_info.local_state, wrapper, &eos, &next_block, + source_info.channel_id)) { // do nothing } } Status PassthroughExchanger::get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) { + Profile&& profile, SourceInfo&& source_info) { BlockWrapperSPtr next_block; - _dequeue_data(local_state, next_block, eos, block); + _dequeue_data(source_info.local_state, next_block, eos, block, source_info.channel_id); return Status::OK(); } Status PassToOneExchanger::sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) { + Profile&& profile, SinkInfo&& sink_info) { if (in_block->empty()) { return Status::OK(); } @@ -301,70 +393,72 @@ Status PassToOneExchanger::sink(RuntimeState* state, vectorized::Block* in_block new_block.swap(*in_block); BlockWrapperSPtr wrapper = BlockWrapper::create_shared(std::move(new_block)); - _enqueue_data_and_set_ready(0, local_state, std::move(wrapper)); + _enqueue_data_and_set_ready(0, sink_info.local_state, std::move(wrapper)); return Status::OK(); } Status PassToOneExchanger::get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) { - if (local_state._channel_id != 0) { + Profile&& profile, SourceInfo&& source_info) { + if (source_info.channel_id != 0) { *eos = true; return Status::OK(); } BlockWrapperSPtr next_block; - _dequeue_data(local_state, next_block, eos, block); + _dequeue_data(source_info.local_state, next_block, eos, block, source_info.channel_id); return Status::OK(); } Status LocalMergeSortExchanger::sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) { + Profile&& profile, SinkInfo&& sink_info) { if (!in_block->empty()) { vectorized::Block new_block; if (!_free_blocks.try_dequeue(new_block)) { new_block = {in_block->clone_empty()}; } - DCHECK_LE(local_state._channel_id, _data_queue.size()); + DCHECK_LE(*sink_info.channel_id, _data_queue.size()); new_block.swap(*in_block); - _enqueue_data_and_set_ready(local_state._channel_id, local_state, + _enqueue_data_and_set_ready(*sink_info.channel_id, sink_info.local_state, BlockWrapper::create_shared(std::move(new_block))); } - if (eos) { - local_state._shared_state->source_deps[local_state._channel_id]->set_always_ready(); + if (eos && sink_info.local_state) { + sink_info.local_state->_shared_state->source_deps[*sink_info.channel_id] + ->set_always_ready(); } return Status::OK(); } -void ExchangerBase::finalize(LocalExchangeSourceLocalState& local_state) { +void ExchangerBase::finalize() { DCHECK(_running_source_operators == 0); vectorized::Block block; while (_free_blocks.try_dequeue(block)) { // do nothing } } -void LocalMergeSortExchanger::finalize(LocalExchangeSourceLocalState& local_state) { + +void LocalMergeSortExchanger::finalize() { BlockWrapperSPtr next_block; vectorized::Block block; bool eos; int id = 0; for (auto& data_queue : _data_queue) { data_queue.set_eos(); - while (_dequeue_data(local_state, next_block, &eos, &block, id)) { + while (_dequeue_data(next_block, &eos, &block, id)) { block = vectorized::Block(); } id++; } - ExchangerBase::finalize(local_state); + ExchangerBase::finalize(); } Status LocalMergeSortExchanger::build_merger(RuntimeState* state, - LocalExchangeSourceLocalState& local_state) { - RETURN_IF_ERROR(_sort_source->build_merger(state, _merger, local_state.profile())); + LocalExchangeSourceLocalState* local_state) { + RETURN_IF_ERROR(_sort_source->build_merger(state, _merger, local_state->profile())); std::vector child_block_suppliers; for (int channel_id = 0; channel_id < _num_partitions; channel_id++) { - vectorized::BlockSupplier block_supplier = [&, id = channel_id](vectorized::Block* block, - bool* eos) { + vectorized::BlockSupplier block_supplier = [&, local_state, id = channel_id]( + vectorized::Block* block, bool* eos) { BlockWrapperSPtr next_block; _dequeue_data(local_state, next_block, eos, block, id); return Status::OK(); @@ -388,20 +482,21 @@ now sort(8) --> local merge(1) ---> datasink(1) [2] ----> */ Status LocalMergeSortExchanger::get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) { - if (local_state._channel_id != 0) { + Profile&& profile, SourceInfo&& source_info) { + if (source_info.channel_id != 0) { *eos = true; return Status::OK(); } if (!_merger) { - RETURN_IF_ERROR(build_merger(state, local_state)); + DCHECK(source_info.local_state); + RETURN_IF_ERROR(build_merger(state, source_info.local_state)); } RETURN_IF_ERROR(_merger->get_next(block, eos)); return Status::OK(); } Status BroadcastExchanger::sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) { + Profile&& profile, SinkInfo&& sink_info) { if (in_block->empty()) { return Status::OK(); } @@ -411,32 +506,40 @@ Status BroadcastExchanger::sink(RuntimeState* state, vectorized::Block* in_block } new_block.swap(*in_block); auto wrapper = BlockWrapper::create_shared(std::move(new_block)); - local_state._shared_state->add_total_mem_usage(wrapper->data_block.allocated_bytes(), - local_state._channel_id); + if (sink_info.local_state) { + sink_info.local_state->_shared_state->add_total_mem_usage( + wrapper->data_block.allocated_bytes(), *sink_info.channel_id); + } + wrapper->ref(_num_partitions); for (int i = 0; i < _num_partitions; i++) { - _enqueue_data_and_set_ready(i, local_state, {wrapper, {0, wrapper->data_block.rows()}}); + _enqueue_data_and_set_ready(i, sink_info.local_state, + {wrapper, {0, wrapper->data_block.rows()}}); } return Status::OK(); } -void BroadcastExchanger::close(LocalExchangeSourceLocalState& local_state) { +void BroadcastExchanger::close(SourceInfo&& source_info) { BroadcastBlock partitioned_block; bool eos; vectorized::Block block; - _data_queue[local_state._channel_id].set_eos(); - while (_dequeue_data(local_state, partitioned_block, &eos, &block)) { - partitioned_block.first->unref(local_state._shared_state, local_state._channel_id); + _data_queue[source_info.channel_id].set_eos(); + while (_dequeue_data(source_info.local_state, partitioned_block, &eos, &block, + source_info.channel_id)) { + partitioned_block.first->unref( + source_info.local_state ? source_info.local_state->_shared_state : nullptr, + source_info.channel_id); } } Status BroadcastExchanger::get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) { + Profile&& profile, SourceInfo&& source_info) { BroadcastBlock partitioned_block; - if (_dequeue_data(local_state, partitioned_block, eos, block)) { - SCOPED_TIMER(local_state._copy_data_timer); + if (_dequeue_data(source_info.local_state, partitioned_block, eos, block, + source_info.channel_id)) { + SCOPED_TIMER(profile.copy_data_timer); vectorized::MutableBlock mutable_block = vectorized::VectorizedUtils::build_mutable_mem_reuse_block( block, partitioned_block.first->data_block); @@ -444,7 +547,9 @@ Status BroadcastExchanger::get_block(RuntimeState* state, vectorized::Block* blo RETURN_IF_ERROR(mutable_block.add_rows(&block_wrapper->data_block, partitioned_block.second.offset_start, partitioned_block.second.length)); - block_wrapper->unref(local_state._shared_state, local_state._channel_id); + block_wrapper->unref( + source_info.local_state ? source_info.local_state->_shared_state : nullptr, + source_info.channel_id); } return Status::OK(); @@ -452,21 +557,21 @@ Status BroadcastExchanger::get_block(RuntimeState* state, vectorized::Block* blo Status AdaptivePassthroughExchanger::_passthrough_sink(RuntimeState* state, vectorized::Block* in_block, - LocalExchangeSinkLocalState& local_state) { + SinkInfo&& sink_info) { vectorized::Block new_block; if (!_free_blocks.try_dequeue(new_block)) { new_block = {in_block->clone_empty()}; } new_block.swap(*in_block); - auto channel_id = (local_state._channel_id++) % _num_partitions; - _enqueue_data_and_set_ready(channel_id, local_state, + auto channel_id = ((*sink_info.channel_id)++) % _num_partitions; + _enqueue_data_and_set_ready(channel_id, sink_info.local_state, BlockWrapper::create_shared(std::move(new_block))); return Status::OK(); } Status AdaptivePassthroughExchanger::_shuffle_sink(RuntimeState* state, vectorized::Block* block, - LocalExchangeSinkLocalState& local_state) { + SinkInfo&& sink_info) { std::vector channel_ids; const auto num_rows = block->rows(); channel_ids.resize(num_rows, 0); @@ -481,40 +586,39 @@ Status AdaptivePassthroughExchanger::_shuffle_sink(RuntimeState* state, vectoriz std::iota(channel_ids.begin() + i, channel_ids.end(), 0); } } - return _split_rows(state, channel_ids.data(), block, local_state); + return _split_rows(state, channel_ids.data(), block, std::move(sink_info)); } Status AdaptivePassthroughExchanger::_split_rows(RuntimeState* state, const uint32_t* __restrict channel_ids, - vectorized::Block* block, - LocalExchangeSinkLocalState& local_state) { + vectorized::Block* block, SinkInfo&& sink_info) { const auto rows = cast_set(block->rows()); auto row_idx = std::make_shared>(rows); + auto& partition_rows_histogram = _partition_rows_histogram[*sink_info.channel_id]; { - local_state._partition_rows_histogram.assign(_num_partitions + 1, 0); + partition_rows_histogram.assign(_num_partitions + 1, 0); for (int32_t i = 0; i < rows; ++i) { - local_state._partition_rows_histogram[channel_ids[i]]++; + partition_rows_histogram[channel_ids[i]]++; } for (int32_t i = 1; i <= _num_partitions; ++i) { - local_state._partition_rows_histogram[i] += - local_state._partition_rows_histogram[i - 1]; + partition_rows_histogram[i] += partition_rows_histogram[i - 1]; } for (int32_t i = rows - 1; i >= 0; --i) { - (*row_idx)[local_state._partition_rows_histogram[channel_ids[i]] - 1] = i; - local_state._partition_rows_histogram[channel_ids[i]]--; + (*row_idx)[partition_rows_histogram[channel_ids[i]] - 1] = i; + partition_rows_histogram[channel_ids[i]]--; } } for (int32_t i = 0; i < _num_partitions; i++) { - const size_t start = local_state._partition_rows_histogram[i]; - const size_t size = local_state._partition_rows_histogram[i + 1] - start; + const size_t start = partition_rows_histogram[i]; + const size_t size = partition_rows_histogram[i + 1] - start; if (size > 0) { std::unique_ptr mutable_block = vectorized::MutableBlock::create_unique(block->clone_empty()); RETURN_IF_ERROR(mutable_block->add_rows(block, start, size)); auto new_block = mutable_block->to_block(); - _enqueue_data_and_set_ready(i, local_state, + _enqueue_data_and_set_ready(i, sink_info.local_state, BlockWrapper::create_shared(std::move(new_block))); } } @@ -522,34 +626,35 @@ Status AdaptivePassthroughExchanger::_split_rows(RuntimeState* state, } Status AdaptivePassthroughExchanger::sink(RuntimeState* state, vectorized::Block* in_block, - bool eos, LocalExchangeSinkLocalState& local_state) { + bool eos, Profile&& profile, SinkInfo&& sink_info) { if (in_block->empty()) { return Status::OK(); } if (_is_pass_through) { - return _passthrough_sink(state, in_block, local_state); + return _passthrough_sink(state, in_block, std::move(sink_info)); } else { if (_total_block++ > _num_partitions) { _is_pass_through = true; } - return _shuffle_sink(state, in_block, local_state); + return _shuffle_sink(state, in_block, std::move(sink_info)); } } Status AdaptivePassthroughExchanger::get_block(RuntimeState* state, vectorized::Block* block, - bool* eos, - LocalExchangeSourceLocalState& local_state) { + bool* eos, Profile&& profile, + SourceInfo&& source_info) { BlockWrapperSPtr next_block; - _dequeue_data(local_state, next_block, eos, block); + _dequeue_data(source_info.local_state, next_block, eos, block, source_info.channel_id); return Status::OK(); } -void AdaptivePassthroughExchanger::close(LocalExchangeSourceLocalState& local_state) { +void AdaptivePassthroughExchanger::close(SourceInfo&& source_info) { vectorized::Block next_block; bool eos; BlockWrapperSPtr wrapper; - _data_queue[local_state._channel_id].set_eos(); - while (_dequeue_data(local_state, wrapper, &eos, &next_block)) { + _data_queue[source_info.channel_id].set_eos(); + while (_dequeue_data(source_info.local_state, wrapper, &eos, &next_block, + source_info.channel_id)) { // do nothing } } diff --git a/be/src/pipeline/local_exchange/local_exchanger.h b/be/src/pipeline/local_exchange/local_exchanger.h index 4d699baa52fb8b..d6871b2ba97cc3 100644 --- a/be/src/pipeline/local_exchange/local_exchanger.h +++ b/be/src/pipeline/local_exchange/local_exchanger.h @@ -20,14 +20,33 @@ #include "pipeline/dependency.h" #include "pipeline/exec/operator.h" -namespace doris::pipeline { +namespace doris { #include "common/compile_check_begin.h" - +namespace vectorized { +class PartitionerBase; +} +namespace pipeline { class LocalExchangeSourceLocalState; class LocalExchangeSinkLocalState; struct BlockWrapper; class SortSourceOperatorX; +struct Profile { + RuntimeProfile::Counter* compute_hash_value_timer = nullptr; + RuntimeProfile::Counter* distribute_timer = nullptr; + RuntimeProfile::Counter* copy_data_timer = nullptr; +}; + +struct SinkInfo { + int* channel_id; + vectorized::PartitionerBase* partitioner; + LocalExchangeSinkLocalState* local_state; +}; + +struct SourceInfo { + int channel_id; + LocalExchangeSourceLocalState* local_state; +}; /** * One exchanger is hold by one `LocalExchangeSharedState`. And one `LocalExchangeSharedState` is * shared by all local exchange sink operators and source operators with the same id. @@ -60,15 +79,15 @@ class ExchangerBase { _free_block_limit(free_block_limit) {} virtual ~ExchangerBase() = default; virtual Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) = 0; + Profile&& profile, SourceInfo&& source_info) = 0; virtual Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) = 0; + Profile&& profile, SinkInfo&& sink_info) = 0; virtual ExchangeType get_type() const = 0; // Called if a local exchanger source operator are closed. Free the unused data block in data_queue. - virtual void close(LocalExchangeSourceLocalState& local_state) = 0; + virtual void close(SourceInfo&& source_info) = 0; // Called if all local exchanger source operators are closed. We free the memory in // `_free_blocks` here. - virtual void finalize(LocalExchangeSourceLocalState& local_state); + virtual void finalize(); virtual std::string data_queue_debug_string(int i) = 0; @@ -155,12 +174,13 @@ class Exchanger : public ExchangerBase { protected: // Enqueue data block and set downstream source operator to read. - void _enqueue_data_and_set_ready(int channel_id, LocalExchangeSinkLocalState& local_state, + void _enqueue_data_and_set_ready(int channel_id, LocalExchangeSinkLocalState* local_state, BlockType&& block); - bool _dequeue_data(LocalExchangeSourceLocalState& local_state, BlockType& block, bool* eos, - vectorized::Block* data_block); - bool _dequeue_data(LocalExchangeSourceLocalState& local_state, BlockType& block, bool* eos, + bool _dequeue_data(LocalExchangeSourceLocalState* local_state, BlockType& block, bool* eos, vectorized::Block* data_block, int channel_id); + + void _enqueue_data_and_set_ready(int channel_id, BlockType&& block); + bool _dequeue_data(BlockType& block, bool* eos, vectorized::Block* data_block, int channel_id); std::vector> _data_queue; private: @@ -186,7 +206,7 @@ struct BlockWrapper { ~BlockWrapper() { DCHECK_EQ(ref_count.load(), 0); } void ref(int delta) { ref_count += delta; } void unref(LocalExchangeSharedState* shared_state, size_t allocated_bytes, int channel_id) { - if (ref_count.fetch_sub(1) == 1) { + if (ref_count.fetch_sub(1) == 1 && shared_state != nullptr) { DCHECK_GT(allocated_bytes, 0); shared_state->sub_total_mem_usage(allocated_bytes, channel_id); if (shared_state->exchanger->_free_block_limit == 0 || @@ -201,7 +221,7 @@ struct BlockWrapper { } } - void unref(LocalExchangeSharedState* shared_state, int channel_id) { + void unref(LocalExchangeSharedState* shared_state = nullptr, int channel_id = 0) { unref(shared_state, data_block.allocated_bytes(), channel_id); } int ref_value() const { return ref_count.load(); } @@ -219,19 +239,24 @@ class ShuffleExchanger : public Exchanger { DCHECK_GT(num_partitions, 0); DCHECK_GT(num_sources, 0); _data_queue.resize(num_sources); + _partition_rows_histogram.resize(running_sink_operators); } ~ShuffleExchanger() override = default; - Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) override; + Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, Profile&& profile, + SinkInfo&& sink_info) override; - Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) override; - void close(LocalExchangeSourceLocalState& local_state) override; + Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, Profile&& profile, + SourceInfo&& source_info) override; + void close(SourceInfo&& source_info) override; ExchangeType get_type() const override { return ExchangeType::HASH_SHUFFLE; } protected: Status _split_rows(RuntimeState* state, const uint32_t* __restrict channel_ids, - vectorized::Block* block, LocalExchangeSinkLocalState& local_state); + vectorized::Block* block, int channel_id, + LocalExchangeSinkLocalState* local_state); + Status _split_rows(RuntimeState* state, const uint32_t* __restrict channel_ids, + vectorized::Block* block, int channel_id); + std::vector> _partition_rows_histogram; }; class BucketShuffleExchanger final : public ShuffleExchanger { @@ -255,13 +280,13 @@ class PassthroughExchanger final : public Exchanger { _data_queue.resize(num_partitions); } ~PassthroughExchanger() override = default; - Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) override; + Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, Profile&& profile, + SinkInfo&& sink_info) override; - Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) override; + Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, Profile&& profile, + SourceInfo&& source_info) override; ExchangeType get_type() const override { return ExchangeType::PASSTHROUGH; } - void close(LocalExchangeSourceLocalState& local_state) override; + void close(SourceInfo&& source_info) override; }; class PassToOneExchanger final : public Exchanger { @@ -273,13 +298,13 @@ class PassToOneExchanger final : public Exchanger { _data_queue.resize(num_partitions); } ~PassToOneExchanger() override = default; - Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) override; + Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, Profile&& profile, + SinkInfo&& sink_info) override; - Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) override; + Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, Profile&& profile, + SourceInfo&& source_info) override; ExchangeType get_type() const override { return ExchangeType::PASS_TO_ONE; } - void close(LocalExchangeSourceLocalState& local_state) override; + void close(SourceInfo&& source_info) override; }; class LocalMergeSortExchanger final : public Exchanger { @@ -292,17 +317,17 @@ class LocalMergeSortExchanger final : public Exchanger { _data_queue.resize(num_partitions); } ~LocalMergeSortExchanger() override = default; - Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) override; + Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, Profile&& profile, + SinkInfo&& sink_info) override; - Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) override; + Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, Profile&& profile, + SourceInfo&& source_info) override; ExchangeType get_type() const override { return ExchangeType::LOCAL_MERGE_SORT; } - Status build_merger(RuntimeState* statem, LocalExchangeSourceLocalState& local_state); + Status build_merger(RuntimeState* statem, LocalExchangeSourceLocalState* local_state); - void close(LocalExchangeSourceLocalState& local_state) override {} - void finalize(LocalExchangeSourceLocalState& local_state) override; + void close(SourceInfo&& source_info) override {} + void finalize() override; private: std::unique_ptr _merger; @@ -318,13 +343,13 @@ class BroadcastExchanger final : public Exchanger { _data_queue.resize(num_partitions); } ~BroadcastExchanger() override = default; - Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) override; + Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, Profile&& profile, + SinkInfo&& sink_info) override; - Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) override; + Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, Profile&& profile, + SourceInfo&& source_info) override; ExchangeType get_type() const override { return ExchangeType::BROADCAST; } - void close(LocalExchangeSourceLocalState& local_state) override; + void close(SourceInfo&& source_info) override; }; //The code in AdaptivePassthroughExchanger is essentially @@ -337,26 +362,28 @@ class AdaptivePassthroughExchanger : public Exchanger { : Exchanger(running_sink_operators, num_partitions, free_block_limit) { _data_queue.resize(num_partitions); + _partition_rows_histogram.resize(running_sink_operators); } - Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, - LocalExchangeSinkLocalState& local_state) override; + Status sink(RuntimeState* state, vectorized::Block* in_block, bool eos, Profile&& profile, + SinkInfo&& sink_info) override; - Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, - LocalExchangeSourceLocalState& local_state) override; + Status get_block(RuntimeState* state, vectorized::Block* block, bool* eos, Profile&& profile, + SourceInfo&& source_info) override; ExchangeType get_type() const override { return ExchangeType::ADAPTIVE_PASSTHROUGH; } - void close(LocalExchangeSourceLocalState& local_state) override; + void close(SourceInfo&& source_info) override; private: Status _passthrough_sink(RuntimeState* state, vectorized::Block* in_block, - LocalExchangeSinkLocalState& local_state); - Status _shuffle_sink(RuntimeState* state, vectorized::Block* in_block, - LocalExchangeSinkLocalState& local_state); + SinkInfo&& sink_info); + Status _shuffle_sink(RuntimeState* state, vectorized::Block* in_block, SinkInfo&& sink_info); Status _split_rows(RuntimeState* state, const uint32_t* __restrict channel_ids, - vectorized::Block* block, LocalExchangeSinkLocalState& local_state); + vectorized::Block* block, SinkInfo&& sink_info); std::atomic_bool _is_pass_through = false; std::atomic_int32_t _total_block = 0; + std::vector> _partition_rows_histogram; }; #include "common/compile_check_end.h" -} // namespace doris::pipeline +} // namespace pipeline +} // namespace doris \ No newline at end of file From e8adcd7b2b3465489f7ffaa57fb1c19ed29a609a Mon Sep 17 00:00:00 2001 From: bobhan1 Date: Wed, 11 Dec 2024 18:49:04 +0800 Subject: [PATCH 05/63] [opt](compaction) Don't check missed rows in cumu compaction if input rowsets are not in tablet (#45279) Problem Summary: Suppose a heavy schema change process on BE converting tablet A to tablet B. 1. during schema change double write, new loads write [X-Y] on tablet B. 2. rowsets with version [a],[a+1],...,[b-1],[b] on tablet B are picked for cumu compaction(X<=atablet_meta()->tablet_schema()->cluster_key_uids().empty()) { merged_missed_rows_size += _stats.filtered_rows; } + + // Suppose a heavy schema change process on BE converting tablet A to tablet B. + // 1. during schema change double write, new loads write [X-Y] on tablet B. + // 2. rowsets with version [a],[a+1],...,[b-1],[b] on tablet B are picked for cumu compaction(X<=aget_header_lock()); + need_to_check_missed_rows = + std::all_of(_input_rowsets.begin(), _input_rowsets.end(), + [&](const RowsetSharedPtr& rowset) { + return tablet()->rowset_exists_unlocked(rowset); + }); + } + if (_tablet->tablet_state() == TABLET_RUNNING && - merged_missed_rows_size != missed_rows_size) { + merged_missed_rows_size != missed_rows_size && need_to_check_missed_rows) { std::stringstream ss; ss << "cumulative compaction: the merged rows(" << _stats.merged_rows << "), filtered rows(" << _stats.filtered_rows diff --git a/be/src/olap/cumulative_compaction.cpp b/be/src/olap/cumulative_compaction.cpp index 2dfd30fb86ed9a..a9509a005763f6 100644 --- a/be/src/olap/cumulative_compaction.cpp +++ b/be/src/olap/cumulative_compaction.cpp @@ -100,6 +100,20 @@ Status CumulativeCompaction::prepare_compact() { } Status CumulativeCompaction::execute_compact() { + DBUG_EXECUTE_IF("CumulativeCompaction::execute_compact.block", { + auto target_tablet_id = dp->param("tablet_id", -1); + if (target_tablet_id == _tablet->tablet_id()) { + LOG(INFO) << "start debug block " + << "CumulativeCompaction::execute_compact.block"; + while (DebugPoints::instance()->is_enable( + "CumulativeCompaction::execute_compact.block")) { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + LOG(INFO) << "end debug block " + << "CumulativeCompaction::execute_compact.block"; + } + }) + std::unique_lock lock(tablet()->get_cumulative_compaction_lock(), std::try_to_lock); if (!lock.owns_lock()) { return Status::Error( diff --git a/be/src/olap/cumulative_compaction_policy.cpp b/be/src/olap/cumulative_compaction_policy.cpp index ee7a2b1812a0ae..c812a12b656580 100644 --- a/be/src/olap/cumulative_compaction_policy.cpp +++ b/be/src/olap/cumulative_compaction_policy.cpp @@ -28,6 +28,7 @@ #include "olap/olap_common.h" #include "olap/tablet.h" #include "olap/tablet_meta.h" +#include "util/debug_points.h" namespace doris { @@ -246,6 +247,21 @@ int SizeBasedCumulativeCompactionPolicy::pick_input_rowsets( const int64_t max_compaction_score, const int64_t min_compaction_score, std::vector* input_rowsets, Version* last_delete_version, size_t* compaction_score, bool allow_delete) { + DBUG_EXECUTE_IF("SizeBasedCumulativeCompactionPolicy::pick_input_rowsets.set_input_rowsets", { + auto target_tablet_id = dp->param("tablet_id", -1); + if (target_tablet_id == tablet->tablet_id()) { + auto start_version = dp->param("start_version", -1); + auto end_version = dp->param("end_version", -1); + for (auto& rowset : candidate_rowsets) { + if (rowset->start_version() >= start_version && + rowset->end_version() <= end_version) { + input_rowsets->push_back(rowset); + } + } + } + return input_rowsets->size(); + }) + size_t promotion_size = tablet->cumulative_promotion_size(); auto max_version = tablet->max_version().first; int transient_size = 0; diff --git a/be/src/olap/schema_change.cpp b/be/src/olap/schema_change.cpp index cdb637b1c42647..08b9b9a93d90f5 100644 --- a/be/src/olap/schema_change.cpp +++ b/be/src/olap/schema_change.cpp @@ -867,6 +867,8 @@ Status SchemaChangeJob::_do_process_alter_tablet(const TAlterTabletReqV2& reques return_columns[i] = i; } + DBUG_EXECUTE_IF("SchemaChangeJob::_do_process_alter_tablet.block", DBUG_BLOCK); + // begin to find deltas to convert from base tablet to new tablet so that // obtain base tablet and new tablet's push lock and header write lock to prevent loading data { diff --git a/be/src/olap/tablet.cpp b/be/src/olap/tablet.cpp index 644ca9133eb885..a1a56507ffc67a 100644 --- a/be/src/olap/tablet.cpp +++ b/be/src/olap/tablet.cpp @@ -512,6 +512,15 @@ Status Tablet::add_rowset(RowsetSharedPtr rowset) { return Status::OK(); } +bool Tablet::rowset_exists_unlocked(const RowsetSharedPtr& rowset) { + if (auto it = _rs_version_map.find(rowset->version()); it == _rs_version_map.end()) { + return false; + } else if (rowset->rowset_id() != it->second->rowset_id()) { + return false; + } + return true; +} + Status Tablet::modify_rowsets(std::vector& to_add, std::vector& to_delete, bool check_delete) { // the compaction process allow to compact the single version, eg: version[4-4]. diff --git a/be/src/olap/tablet.h b/be/src/olap/tablet.h index 0b7d758ab8fd88..40b911d6391b9b 100644 --- a/be/src/olap/tablet.h +++ b/be/src/olap/tablet.h @@ -173,6 +173,7 @@ class Tablet final : public BaseTablet { // MUST hold EXCLUSIVE `_meta_lock`. Status modify_rowsets(std::vector& to_add, std::vector& to_delete, bool check_delete = false); + bool rowset_exists_unlocked(const RowsetSharedPtr& rowset); Status add_inc_rowset(const RowsetSharedPtr& rowset); /// Delete stale rowset by timing. This delete policy uses now() minutes diff --git a/regression-test/data/fault_injection_p0/test_compaction_on_sc_new_tablet.out b/regression-test/data/fault_injection_p0/test_compaction_on_sc_new_tablet.out new file mode 100644 index 00000000000000..e7188943a10a19 --- /dev/null +++ b/regression-test/data/fault_injection_p0/test_compaction_on_sc_new_tablet.out @@ -0,0 +1,25 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !sql -- +1 1 1 1 +2 2 2 2 +3 3 3 3 +4 4 4 4 +5 5 5 5 +6 6 6 6 +7 7 7 7 +8 8 8 8 +9 9 9 9 +10 10 10 10 + +-- !sql -- +1 9 9 9 +2 2 2 2 +3 3 3 3 +4 4 4 4 +5 5 5 5 +6 6 6 6 +7 7 7 7 +8 8 8 8 +9 9 9 9 +10 10 10 10 + diff --git a/regression-test/suites/fault_injection_p0/test_compaction_on_sc_new_tablet.groovy b/regression-test/suites/fault_injection_p0/test_compaction_on_sc_new_tablet.groovy new file mode 100644 index 00000000000000..2f3c44ef2dd00b --- /dev/null +++ b/regression-test/suites/fault_injection_p0/test_compaction_on_sc_new_tablet.groovy @@ -0,0 +1,149 @@ +// 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. + +import org.junit.Assert +import java.util.concurrent.TimeUnit +import org.awaitility.Awaitility +import org.apache.doris.regression.suite.ClusterOptions + +suite("test_compaction_on_sc_new_tablet", "docker") { + def options = new ClusterOptions() + options.setFeNum(1) + options.setBeNum(1) + options.enableDebugPoints() + options.cloudMode = false + options.beConfigs += [ + 'enable_java_support=false', + 'enable_mow_compaction_correctness_check_core=true' + ] + docker(options) { + try { + GetDebugPoint().clearDebugPointsForAllFEs() + GetDebugPoint().clearDebugPointsForAllBEs() + def table1 = "test_compaction_on_sc_new_tablet" + sql "DROP TABLE IF EXISTS ${table1} FORCE;" + sql """ CREATE TABLE IF NOT EXISTS ${table1} ( + `k` int, + `c1` int, + `c2` int, + `c3` int + ) UNIQUE KEY(k) + DISTRIBUTED BY HASH(k) BUCKETS 1 + PROPERTIES ( + "disable_auto_compaction" = "true", + "replication_num" = "1", + "enable_unique_key_merge_on_write" = "true"); """ + + // [2-11] + for (int i = 1; i <= 10; i++) { + sql "insert into ${table1} values($i,$i,$i,$i);" + } + qt_sql "select * from ${table1} order by k;" + + + def beNodes = sql_return_maparray("show backends;") + def tabletStats = sql_return_maparray("show tablets from ${table1};") + logger.info("tabletStats: \n${tabletStats}") + def tabletStat = tabletStats.get(0) + def tabletBackendId = tabletStat.BackendId + def tabletId = tabletStat.TabletId + def version = tabletStat.Version + def tabletBackend; + for (def be : beNodes) { + if (be.BackendId == tabletBackendId) { + tabletBackend = be + break; + } + } + logger.info("tablet ${tabletId} is on backend ${tabletBackend.Host} with backendId=${tabletBackend.BackendId}, version=${version}"); + + // blocking the schema change process before it gains max version + GetDebugPoint().enableDebugPointForAllBEs("SchemaChangeJob::_do_process_alter_tablet.block") + Thread.sleep(2000) + + sql "alter table ${table1} modify column c1 varchar(100);" + + Thread.sleep(4000) + + // double write [11-22] + for (int i = 20; i <= 30; i++) { + sql "insert into ${table1} values(1,9,9,9);" + } + + tabletStats = sql_return_maparray("show tablets from ${table1};") + logger.info("tabletStats: \n${tabletStats}") + assertEquals(2, tabletStats.size()) + + def oldTabletStat + def newTabletStat + for (def stat: tabletStats) { + if (!stat.TabletId.equals(tabletId)) { + newTabletStat = stat + } else { + oldTabletStat = stat + } + } + logger.info("old tablet=[tablet_id=${oldTabletStat.TabletId}, version=${oldTabletStat.Version}]") + logger.info("new tablet=[tablet_id=${newTabletStat.TabletId}, version=${newTabletStat.Version}]") + + + // trigger cumu compaction on new tablet + int start_version = 15 + int end_version = 17 + // block compaction process on new tablet + GetDebugPoint().enableDebugPointForAllBEs("CumulativeCompaction::execute_compact.block", [tablet_id: "${newTabletStat.TabletId}"]) + // manully set cumu compaction's input rowsets on new tablet + GetDebugPoint().enableDebugPointForAllBEs("SizeBasedCumulativeCompactionPolicy::pick_input_rowsets.set_input_rowsets", + [tablet_id:"${newTabletStat.TabletId}", start_version:"${start_version}", end_version:"${end_version}"]) + + Thread.sleep(2000) + + logger.info("trigger compaction [15-17] on new tablet ${newTabletStat.TabletId}") + def (code, out, err) = be_run_cumulative_compaction(tabletBackend.Host, tabletBackend.HttpPort, newTabletStat.TabletId) + logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) + Assert.assertEquals(code, 0) + def compactJson = parseJson(out.trim()) + Assert.assertEquals("success", compactJson.status.toLowerCase()) + + // make the schema change run to complete and wait for it + GetDebugPoint().disableDebugPointForAllBEs("SchemaChangeJob::_do_process_alter_tablet.block") + waitForSchemaChangeDone { + sql """ SHOW ALTER TABLE COLUMN WHERE TableName='${table1}' ORDER BY createtime DESC LIMIT 1 """ + time 2000 + } + + Thread.sleep(2000) + + // make the cumu compaction run to complete and wait for it + GetDebugPoint().disableDebugPointForAllBEs("CumulativeCompaction::execute_compact.block") + + + // BE should skip to check merged rows in cumu compaction, otherwise it will cause coredump + // becasue [11-22] in new tablet will skip to calc delete bitmap becase tablet is in NOT_READY state + Thread.sleep(7000) + + qt_sql "select * from ${table1} order by k;" + + } catch(Exception e) { + logger.info(e.getMessage()) + throw e + } finally { + GetDebugPoint().clearDebugPointsForAllFEs() + GetDebugPoint().clearDebugPointsForAllBEs() + } + } +} From 88b36177e81e7ab83a42ffb18322d990dd0d4c16 Mon Sep 17 00:00:00 2001 From: shuke Date: Wed, 11 Dec 2024 21:09:01 +0800 Subject: [PATCH 06/63] [regression-test](fix) two tests using same table (#45312) --- .../suites/correctness_p0/test_bitmap_intersect.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/regression-test/suites/correctness_p0/test_bitmap_intersect.groovy b/regression-test/suites/correctness_p0/test_bitmap_intersect.groovy index 4023e5dac8c85a..6d3866fea86655 100644 --- a/regression-test/suites/correctness_p0/test_bitmap_intersect.groovy +++ b/regression-test/suites/correctness_p0/test_bitmap_intersect.groovy @@ -16,7 +16,7 @@ // under the License. suite("test_bitmap_intersect") { - def tableName = "test_bitmap" + def tableName = "test_bitmap_intersect" sql """ DROP TABLE IF EXISTS ${tableName} """ @@ -35,4 +35,4 @@ select bitmap_to_string(bitmap_intersect(user_ids)) from ( select tag, bitmap_union(user_ids) user_ids from ${tableName} group by tag ) t; """ - } \ No newline at end of file + } From 279c5b7e50065ce2fadb2abd0c70d5281e98aa6d Mon Sep 17 00:00:00 2001 From: walter Date: Wed, 11 Dec 2024 21:59:22 +0800 Subject: [PATCH 07/63] [chore](regression) Enable batch_download_file in p0/p1 pipeline (#45295) --- regression-test/pipeline/p0/conf/be.conf | 4 ++++ regression-test/pipeline/p1/conf/be.conf | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/regression-test/pipeline/p0/conf/be.conf b/regression-test/pipeline/p0/conf/be.conf index 802ce4bc5f0f2a..760b8762430bd7 100644 --- a/regression-test/pipeline/p0/conf/be.conf +++ b/regression-test/pipeline/p0/conf/be.conf @@ -73,3 +73,7 @@ pipeline_task_leakage_detect_period_sec=1 crash_in_memory_tracker_inaccurate = true enable_table_size_correctness_check=true enable_brpc_connection_check=true + +# enable download small files in batch, see apache/doris#45061 for details +enable_batch_download = true + diff --git a/regression-test/pipeline/p1/conf/be.conf b/regression-test/pipeline/p1/conf/be.conf index 70dc4c23e1ac8c..4401bc36498422 100644 --- a/regression-test/pipeline/p1/conf/be.conf +++ b/regression-test/pipeline/p1/conf/be.conf @@ -65,3 +65,7 @@ pipeline_task_leakage_detect_period_sec=1 crash_in_memory_tracker_inaccurate = true enable_table_size_correctness_check=true enable_brpc_connection_check=true + +# enable download small files in batch, see apache/doris#45061 for details +enable_batch_download = true + From 32fa95d28623547395f5cc65ff16a32a1a24df69 Mon Sep 17 00:00:00 2001 From: Uniqueyou <134280716+wyxxxcat@users.noreply.github.com> Date: Wed, 11 Dec 2024 22:09:06 +0800 Subject: [PATCH 08/63] [Fix] Add column with default value string throw exception (#45000) ``` ALTER TABLE t ADD COLUMN create_time VARCHAR(20) DEFAULT "CURRENT_TIMESTAMP"; ``` ``` errCode = 2, detailMessage = Unexpected exception: Cannot invoke "org.apache.doris.analysis.DefaultValueExprDef.getExprName()" because "this.defaultValueExprDef" is null ``` --- .../org/apache/doris/analysis/ColumnDef.java | 3 +- ...est_alter_add_column_default_value_str.out | 14 ++++ ..._alter_add_column_default_value_str.groovy | 72 +++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 regression-test/data/alter_p0/test_alter_add_column_default_value_str.out create mode 100644 regression-test/suites/alter_p0/test_alter_add_column_default_value_str.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java index 93bcb92f58062a..c2c55c4ce7c955 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java @@ -134,7 +134,8 @@ public static DefaultValue currentTimeStampDefaultValueWithPrecision(Long precis } public boolean isCurrentTimeStamp() { - return "CURRENT_TIMESTAMP".equals(value) && NOW.equals(defaultValueExprDef.getExprName()); + return "CURRENT_TIMESTAMP".equals(value) && defaultValueExprDef != null + && NOW.equals(defaultValueExprDef.getExprName()); } public boolean isCurrentTimeStampWithPrecision() { diff --git a/regression-test/data/alter_p0/test_alter_add_column_default_value_str.out b/regression-test/data/alter_p0/test_alter_add_column_default_value_str.out new file mode 100644 index 00000000000000..b180902fd16246 --- /dev/null +++ b/regression-test/data/alter_p0/test_alter_add_column_default_value_str.out @@ -0,0 +1,14 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select1 -- +1 1 1 +2 2 2 +3 3 3 + +-- !select4 -- +1 1 1 CURRENT_TIMESTAMP BITMAP_EMPTY +2 2 2 CURRENT_TIMESTAMP BITMAP_EMPTY +3 3 3 CURRENT_TIMESTAMP BITMAP_EMPTY +4 4 4 4 4 +5 5 5 5 5 +6 6 6 6 6 + diff --git a/regression-test/suites/alter_p0/test_alter_add_column_default_value_str.groovy b/regression-test/suites/alter_p0/test_alter_add_column_default_value_str.groovy new file mode 100644 index 00000000000000..f3d0386498193b --- /dev/null +++ b/regression-test/suites/alter_p0/test_alter_add_column_default_value_str.groovy @@ -0,0 +1,72 @@ +// 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. + +suite('test_alter_add_column_default_value_str') { + def tbl = 'test_alter_add_column_default_value_str_tbl' + sql "DROP TABLE IF EXISTS ${tbl} FORCE" + sql """ + CREATE TABLE ${tbl} ( + `k1` BIGINT NOT NULL, + `v1` BIGINT NULL, + `v2` INT NULL, + ) ENGINE=OLAP + UNIQUE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + sql """ + INSERT INTO ${tbl} VALUES (1,1,1),(2,2,2),(3,3,3) + """ + + sql """ SYNC """ + + // Check data before ALTER TABLE + qt_select1 """ SELECT * FROM ${tbl} ORDER BY k1 """ + def tb1 = sql """ show create table ${tbl}""" + logger.info("tb1:{}", tb1[0][1]) + assertFalse(tb1[0][1].contains("varchar(20) NOT NULL DEFAULT \"CURRENT_TIMESTAMP\"")) + assertFalse(tb1[0][1].contains("varchar(20) NOT NULL DEFAULT \"BITMAP_EMPTY\"")) + + sql """ + ALTER TABLE ${tbl} add column timestamp_default varchar(20) NOT NULL default "CURRENT_TIMESTAMP"; + """ + + sql """ + ALTER TABLE ${tbl} add column bitmap_default varchar(20) NOT NULL default "BITMAP_EMPTY"; + """ + + waitForSchemaChangeDone { + sql """ SHOW ALTER TABLE COLUMN WHERE TableName='${tbl}' ORDER BY createtime DESC LIMIT 1 """ + time 600 + } + + // Check table structure after ALTER TABLE + def tb2 = sql """ show create table ${tbl}""" + logger.info("tb2:{}", tb2[0][1]) + assertTrue(tb2[0][1].contains("varchar(20) NOT NULL DEFAULT \"CURRENT_TIMESTAMP\"")) + assertTrue(tb2[0][1].contains("varchar(20) NOT NULL DEFAULT \"BITMAP_EMPTY\"")) + def resultCreate = sql """ SHOW CREATE TABLE ${tbl} """ + sql """insert into ${tbl} values (4,4,4,"4","4")""" + sql """insert into ${tbl} (k1,v1,v2,timestamp_default,bitmap_default) values (5,5,5,5,"5")""" + sql """insert into ${tbl} (k1,v1,v2,timestamp_default,bitmap_default) values (6,6,6,6,"6")""" + qt_select4 """ SELECT k1,v1,v2,timestamp_default,bitmap_default FROM ${tbl} ORDER BY k1 """ + + sql "DROP TABLE IF EXISTS ${tbl} FORCE" +} From a4681f3763d1fcb5ee1dea125f286af5da27be9f Mon Sep 17 00:00:00 2001 From: shuke Date: Wed, 11 Dec 2024 22:16:06 +0800 Subject: [PATCH 09/63] [regression-test](opt) add debug log (#45307) When running stream load in regression tests and loading same file into different tables, "org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 129,961,387; received: 125,351,592)" maybe met. This pr add log to try to debug this problem. --- .../org/apache/doris/regression/action/StreamLoadAction.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/StreamLoadAction.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/StreamLoadAction.groovy index 70a7f41e82b257..97b6d038fa701c 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/StreamLoadAction.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/StreamLoadAction.groovy @@ -279,6 +279,7 @@ class StreamLoadAction implements SuiteAction { fileName = cacheHttpFile(client, fileName) } else { entity = new InputStreamEntity(httpGetStream(client, fileName)) + log.info("http entity length is ${entity.contentLength}") return entity; } } From 1ee8d40617ba6fff14c7cf71ed2c8851126a1c40 Mon Sep 17 00:00:00 2001 From: meiyi Date: Wed, 11 Dec 2024 22:23:15 +0800 Subject: [PATCH 10/63] [fix](txn insert) txn insert show error url (#45254) ``` mysql> begin; mysql> insert into test values('a', 'a', 1); mysql> commit; ERROR 1105 (HY000): errCode = 2, detailMessage = [DATA_QUALITY_ERROR]too many filtered rows, url: http://172.21.16.12:9082/api/_load_error_log?file=__shard_110/error_log_insert_stmt_txn_insert_ef05df534f6b4ad7-8782cce460d85b4b_733cffdc9392473f_bd6b2ec40c621119 ``` --- .../runtime/stream_load/stream_load_executor.cpp | 9 +++++++-- .../insert_p0/transaction/txn_insert.groovy | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/be/src/runtime/stream_load/stream_load_executor.cpp b/be/src/runtime/stream_load/stream_load_executor.cpp index 482fadac44e051..ad4d22946f1b83 100644 --- a/be/src/runtime/stream_load/stream_load_executor.cpp +++ b/be/src/runtime/stream_load/stream_load_executor.cpp @@ -85,13 +85,18 @@ Status StreamLoadExecutor::execute_plan_fragment(std::shared_ptrnumber_unselected_rows = state->num_rows_load_unselected(); ctx->loaded_bytes = state->num_bytes_load_total(); int64_t num_selected_rows = ctx->number_total_rows - ctx->number_unselected_rows; + ctx->error_url = to_load_error_http_path(state->get_error_log_file_path()); if (!ctx->group_commit && num_selected_rows > 0 && (double)ctx->number_filtered_rows / num_selected_rows > ctx->max_filter_ratio) { // NOTE: Do not modify the error message here, for historical reasons, // some users may rely on this error message. - *status = Status::DataQualityError("too many filtered rows"); + if (ctx->need_commit_self) { + *status = + Status::DataQualityError("too many filtered rows, url: " + ctx->error_url); + } else { + *status = Status::DataQualityError("too many filtered rows"); + } } - ctx->error_url = to_load_error_http_path(state->get_error_log_file_path()); if (status->ok()) { DorisMetrics::instance()->stream_receive_bytes_total->increment(ctx->receive_bytes); diff --git a/regression-test/suites/insert_p0/transaction/txn_insert.groovy b/regression-test/suites/insert_p0/transaction/txn_insert.groovy index 424a03ee173f5a..f4c8caa35ba991 100644 --- a/regression-test/suites/insert_p0/transaction/txn_insert.groovy +++ b/regression-test/suites/insert_p0/transaction/txn_insert.groovy @@ -107,7 +107,7 @@ suite("txn_insert") { sql """ DROP TABLE IF EXISTS $tableMV """ sql """ create table $tableMV ( - id int default '10', + id int not null, c1 int default '10' ) distributed by hash(id, c1) properties('replication_num'="1"); @@ -122,6 +122,19 @@ suite("txn_insert") { order_qt_select5 """select * from $tableMV""" order_qt_select6 """select c1 from $tableMV""" } while (0); + do { + try { + sql "begin" + sql """insert into $tableMV values(9, 2), (10, 4)""" + sql """insert into $tableMV values('aa', 6)""" + sql "commit" + } catch (Exception e) { + sql "rollback" + logger.info("insert into $tableMV failed: " + e.getMessage()) + assertTrue(e.getMessage().contains("too many filtered rows")) + assertTrue(e.getMessage().contains("url")) + } + } while (0); // ------------------- insert into select ------------------- for (int j = 0; j < 3; j++) { From 02e8c8c547ee9cb4d893f4cb3befd7b53acc1f28 Mon Sep 17 00:00:00 2001 From: Xin Liao Date: Wed, 11 Dec 2024 22:35:51 +0800 Subject: [PATCH 11/63] [Chore](load) print error url to the log when encountering data quality issues during load (#45212) There has been an issue where load does not print the error URL. Printing the error URL in the log is convenient for locating the problem. --- be/src/http/action/stream_load.cpp | 3 ++- be/src/runtime/fragment_mgr.cpp | 14 +++++++++++--- be/src/runtime/runtime_state.cpp | 4 +++- .../main/java/org/apache/doris/qe/Coordinator.java | 1 + 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/be/src/http/action/stream_load.cpp b/be/src/http/action/stream_load.cpp index 7e71f3eb910053..e8db5cb542fb4b 100644 --- a/be/src/http/action/stream_load.cpp +++ b/be/src/http/action/stream_load.cpp @@ -145,7 +145,8 @@ void StreamLoadAction::handle(HttpRequest* req) { << ctx->commit_and_publish_txn_cost_nanos / 1000000 << ", number_total_rows=" << ctx->number_total_rows << ", number_loaded_rows=" << ctx->number_loaded_rows - << ", receive_bytes=" << ctx->receive_bytes << ", loaded_bytes=" << ctx->loaded_bytes; + << ", receive_bytes=" << ctx->receive_bytes << ", loaded_bytes=" << ctx->loaded_bytes + << ", error_url=" << ctx->error_url; // update statistics streaming_load_requests_total->increment(1); diff --git a/be/src/runtime/fragment_mgr.cpp b/be/src/runtime/fragment_mgr.cpp index ce18071fda0d07..19e8f76366c084 100644 --- a/be/src/runtime/fragment_mgr.cpp +++ b/be/src/runtime/fragment_mgr.cpp @@ -390,12 +390,20 @@ void FragmentMgr::coordinator_callback(const ReportStatusRequest& req) { params.load_counters.emplace(s_unselected_rows, std::to_string(num_rows_load_unselected)); if (!req.runtime_state->get_error_log_file_path().empty()) { - params.__set_tracking_url( - to_load_error_http_path(req.runtime_state->get_error_log_file_path())); + std::string error_log_url = + to_load_error_http_path(req.runtime_state->get_error_log_file_path()); + LOG(INFO) << "error log file path: " << error_log_url + << ", query id: " << print_id(req.query_id) + << ", fragment instance id: " << print_id(req.fragment_instance_id); + params.__set_tracking_url(error_log_url); } else if (!req.runtime_states.empty()) { for (auto* rs : req.runtime_states) { if (!rs->get_error_log_file_path().empty()) { - params.__set_tracking_url(to_load_error_http_path(rs->get_error_log_file_path())); + std::string error_log_url = to_load_error_http_path(rs->get_error_log_file_path()); + LOG(INFO) << "error log file path: " << error_log_url + << ", query id: " << print_id(req.query_id) + << ", fragment instance id: " << print_id(rs->fragment_instance_id()); + params.__set_tracking_url(error_log_url); } if (rs->wal_id() > 0) { params.__set_txn_id(rs->wal_id()); diff --git a/be/src/runtime/runtime_state.cpp b/be/src/runtime/runtime_state.cpp index ecaf99061a070b..df7c4141691d0b 100644 --- a/be/src/runtime/runtime_state.cpp +++ b/be/src/runtime/runtime_state.cpp @@ -341,7 +341,9 @@ Status RuntimeState::create_error_log_file() { LOG(WARNING) << error_msg.str(); return Status::InternalError(error_msg.str()); } - VLOG_FILE << "create error log file: " << _error_log_file_path; + LOG(INFO) << "create error log file: " << _error_log_file_path + << ", query id: " << print_id(_query_id) + << ", fragment instance id: " << print_id(_fragment_instance_id); return Status::OK(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java index 4905050e6e8cfe..42e2e0a3634870 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java @@ -2409,6 +2409,7 @@ public void updateFragmentExecStatus(TReportExecStatusParams params) { updateLoadCounters(params.getLoadCounters()); } if (params.isSetTrackingUrl()) { + LOG.info("query_id={} tracking_url: {}", DebugUtil.printId(queryId), params.getTrackingUrl()); trackingUrl = params.getTrackingUrl(); } if (params.isSetTxnId()) { From 1fafe516f8b1d42015cdb8a446f3a01bb4939162 Mon Sep 17 00:00:00 2001 From: walter Date: Thu, 12 Dec 2024 10:29:48 +0800 Subject: [PATCH 12/63] [chore](checkpoint) add enable_checkpoint config (#45301) Add a config `enable_checkpoint`, to support pause checkpoint, so that The user can verify the replay of edit logs easily. --- .../src/main/java/org/apache/doris/common/Config.java | 6 ++++++ .../src/main/java/org/apache/doris/master/Checkpoint.java | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java index c5c7023b20f54b..b02305bdbfc316 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java +++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java @@ -2950,6 +2950,12 @@ public class Config extends ConfigBase { }) public static long auto_analyze_interval_seconds = 86400; // 24 hours. + // A internal config to control whether to enable the checkpoint. + // + // ATTN: it only used in test environment. + @ConfField(mutable = true, masterOnly = true) + public static boolean enable_checkpoint = true; + //========================================================================== // begin of cloud config //========================================================================== diff --git a/fe/fe-core/src/main/java/org/apache/doris/master/Checkpoint.java b/fe/fe-core/src/main/java/org/apache/doris/master/Checkpoint.java index 4934f8fb0b340f..d3e133fda843f9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/master/Checkpoint.java +++ b/fe/fe-core/src/main/java/org/apache/doris/master/Checkpoint.java @@ -86,6 +86,11 @@ protected void runAfterCatalogReady() { // public for unit test, so that we can trigger checkpoint manually. // DO NOT call it manually outside the unit test. public synchronized void doCheckpoint() throws CheckpointException { + if (!Config.enable_checkpoint) { + LOG.warn("checkpoint is disabled. please enable the config 'enable_checkpoint'."); + return; + } + if (!Env.getServingEnv().isHttpReady()) { LOG.info("Http server is not ready."); return; From d775eb717208aa385d59d419f3177dd004bb6459 Mon Sep 17 00:00:00 2001 From: starocean999 Date: Thu, 12 Dec 2024 10:32:38 +0800 Subject: [PATCH 13/63] [fix](nereids) SqlBlockRuleCommand should implement ForwardWithSync (#45234) --- .../doris/nereids/trees/plans/commands/SqlBlockRuleCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/SqlBlockRuleCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/SqlBlockRuleCommand.java index 785da1aeb5861e..47be7f96b26b88 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/SqlBlockRuleCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/SqlBlockRuleCommand.java @@ -36,7 +36,7 @@ /** * Common class for SqlBlockRule Commands. */ -public abstract class SqlBlockRuleCommand extends Command { +public abstract class SqlBlockRuleCommand extends Command implements ForwardWithSync { public static final String SQL_PROPERTY = "sql"; public static final String SQL_HASH_PROPERTY = "sqlHash"; From e70175fc2d5d53ffe5b7b00c7c634ba6f3c3044e Mon Sep 17 00:00:00 2001 From: LiBinfeng Date: Thu, 12 Dec 2024 10:34:29 +0800 Subject: [PATCH 14/63] [fix](Nereids) fix create routine load forward strategy (#45253) --- .../trees/plans/commands/load/CreateRoutineLoadCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/load/CreateRoutineLoadCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/load/CreateRoutineLoadCommand.java index da7ab86c17abac..5632bdc2585ec0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/load/CreateRoutineLoadCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/load/CreateRoutineLoadCommand.java @@ -21,7 +21,7 @@ import org.apache.doris.catalog.Env; import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.commands.Command; -import org.apache.doris.nereids.trees.plans.commands.NoForward; +import org.apache.doris.nereids.trees.plans.commands.ForwardWithSync; import org.apache.doris.nereids.trees.plans.commands.info.CreateRoutineLoadInfo; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; import org.apache.doris.qe.ConnectContext; @@ -68,7 +68,7 @@ type of routine load: KAFKA */ -public class CreateRoutineLoadCommand extends Command implements NoForward { +public class CreateRoutineLoadCommand extends Command implements ForwardWithSync { CreateRoutineLoadInfo createRoutineLoadInfo; public CreateRoutineLoadCommand(CreateRoutineLoadInfo createRoutineLoadInfo) { From 3af5ef661fdd946772493bfe007e86e35153d822 Mon Sep 17 00:00:00 2001 From: walter Date: Thu, 12 Dec 2024 10:36:00 +0800 Subject: [PATCH 15/63] [improve](backup) Add config ignore_backup_tmp_partitions (#45240) To filter tmp partitions, instead of report exception. --- .../java/org/apache/doris/common/Config.java | 9 +++++ .../apache/doris/backup/BackupHandler.java | 4 +-- .../org/apache/doris/backup/BackupJob.java | 15 +++++--- .../org/apache/doris/catalog/OlapTable.java | 8 +++++ ...ackup_restore_backup_temp_partition.groovy | 34 +++++++++++++++++++ 5 files changed, 63 insertions(+), 7 deletions(-) diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java index b02305bdbfc316..42a64a2770ff69 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java +++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java @@ -1638,6 +1638,15 @@ public class Config extends ConfigBase { @ConfField(mutable = true, masterOnly = true) public static boolean ignore_backup_not_support_table_type = false; + /** + * whether to ignore temp partitions when backup, and not report exception. + */ + @ConfField(mutable = true, masterOnly = true, description = { + "是否忽略备份临时分区,不报异常", + "Whether to ignore temp partitions when backup, and not report exception." + }) + public static boolean ignore_backup_tmp_partitions = false; + /** * A internal config, to control the update interval of backup handler. Only used to speed up tests. */ diff --git a/fe/fe-core/src/main/java/org/apache/doris/backup/BackupHandler.java b/fe/fe-core/src/main/java/org/apache/doris/backup/BackupHandler.java index 6a12eee3a78cb3..6f88881e3cb2a3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/backup/BackupHandler.java +++ b/fe/fe-core/src/main/java/org/apache/doris/backup/BackupHandler.java @@ -446,14 +446,14 @@ private void backup(Repository repository, Database db, BackupStmt stmt) throws OlapTable olapTbl = (OlapTable) tbl; tbl.readLock(); try { - if (olapTbl.existTempPartitions()) { + if (!Config.ignore_backup_tmp_partitions && olapTbl.existTempPartitions()) { ErrorReport.reportDdlException(ErrorCode.ERR_COMMON_ERROR, "Do not support backup table " + olapTbl.getName() + " with temp partitions"); } PartitionNames partitionNames = tblRef.getPartitionNames(); if (partitionNames != null) { - if (partitionNames.isTemp()) { + if (!Config.ignore_backup_tmp_partitions && partitionNames.isTemp()) { ErrorReport.reportDdlException(ErrorCode.ERR_COMMON_ERROR, "Do not support backup temp partitions in table " + tblRef.getName()); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java b/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java index d0a957dcd9ae0d..1c897368624f11 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java @@ -597,10 +597,15 @@ private void prepareSnapshotTaskForOlapTableWithoutLock(Database db, OlapTable o // check backup table again if (backupTableRef.getPartitionNames() != null) { for (String partName : backupTableRef.getPartitionNames().getPartitionNames()) { - Partition partition = olapTable.getPartition(partName); + Partition partition = olapTable.getPartition(partName, false); // exclude tmp partitions if (partition == null) { - status = new Status(ErrCode.NOT_FOUND, "partition " + partName - + " does not exist in table" + backupTableRef.getName().getTbl()); + if (olapTable.getPartition(partName, true) != null) { + status = new Status(ErrCode.NOT_FOUND, "backup tmp partition " + partName + + " in table " + backupTableRef.getName().getTbl() + " is not supported"); + } else { + status = new Status(ErrCode.NOT_FOUND, "partition " + partName + + " does not exist in table " + backupTableRef.getName().getTbl()); + } return; } } @@ -609,10 +614,10 @@ private void prepareSnapshotTaskForOlapTableWithoutLock(Database db, OlapTable o // create snapshot tasks List partitions = Lists.newArrayList(); if (backupTableRef.getPartitionNames() == null) { - partitions.addAll(olapTable.getPartitions()); + partitions.addAll(olapTable.getPartitions()); // no temp partitions in OlapTable.getPartitions() } else { for (String partName : backupTableRef.getPartitionNames().getPartitionNames()) { - Partition partition = olapTable.getPartition(partName); + Partition partition = olapTable.getPartition(partName, false); // exclude tmp partitions partitions.add(partition); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java index f3d27908bdd3d8..92d9aa4e9c7f82 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java @@ -2023,6 +2023,14 @@ public OlapTable selectiveCopy(Collection reservedPartitions, IndexExtSt } } + if (isForBackup) { + // drop all tmp partitions in copied table + for (Partition partition : copied.tempPartitions.getAllPartitions()) { + copied.partitionInfo.dropPartition(partition.getId()); + } + copied.tempPartitions = new TempPartitions(); + } + if (reservedPartitions == null || reservedPartitions.isEmpty()) { // reserve all return copied; diff --git a/regression-test/suites/backup_restore/test_backup_restore_backup_temp_partition.groovy b/regression-test/suites/backup_restore/test_backup_restore_backup_temp_partition.groovy index 61514bedd88215..8f06ff4eb8bfa3 100644 --- a/regression-test/suites/backup_restore/test_backup_restore_backup_temp_partition.groovy +++ b/regression-test/suites/backup_restore/test_backup_restore_backup_temp_partition.groovy @@ -62,6 +62,7 @@ suite("test_backup_restore_backup_temp_partition", "backup_restore") { ALTER TABLE ${dbName}.${tableName} ADD TEMPORARY PARTITION tp1 VALUES LESS THAN ("70") """ + sql "ADMIN SET FRONTEND CONFIG ('ignore_backup_tmp_partitions' = 'false')" test { sql """ BACKUP SNAPSHOT ${dbName}.${snapshotName} @@ -71,6 +72,39 @@ suite("test_backup_restore_backup_temp_partition", "backup_restore") { exception "Do not support backup table ${tableName} with temp partitions" } + // ignore the tmp partitions + sql "ADMIN SET FRONTEND CONFIG ('ignore_backup_tmp_partitions' = 'true')" + sql """ + BACKUP SNAPSHOT ${dbName}.${snapshotName} + TO `${repoName}` + ON (${tableName}) + """ + + syncer.waitSnapshotFinish(dbName) + def snapshot = syncer.getSnapshotTimestamp(repoName, snapshotName) + assertTrue(snapshot != null) + + // The restored table has no tmp partitions + sql "DROP TABLE IF EXISTS ${dbName}.${tableName}" + + sql """ + RESTORE SNAPSHOT ${dbName}.${snapshotName} + FROM `${repoName}` + ON ( + `${tableName}` PARTITION (p1, p2, p3) + ) + PROPERTIES + ( + "backup_timestamp" = "${snapshot}", + "reserve_replica" = "true" + ) + """ + + syncer.waitAllRestoreFinish(dbName) + def res = sql "SHOW TEMPORARY PARTITIONS FROM ${dbName}.${tableName}" + assertTrue(res.size() == 0); + + sql "ADMIN SET FRONTEND CONFIG ('ignore_backup_tmp_partitions' = 'false')" sql "DROP TABLE ${dbName}.${tableName} FORCE" sql "DROP DATABASE ${dbName} FORCE" sql "DROP REPOSITORY `${repoName}`" From 5706b6bfe7c2f6115294167fb4cac0185799d061 Mon Sep 17 00:00:00 2001 From: chunping Date: Thu, 12 Dec 2024 10:39:26 +0800 Subject: [PATCH 16/63] [test](show_data) test the correctness of data statistics in cloud mode (#44947) --- aazcp.tar.gz | Bin 0 -> 4218 bytes regression-test/conf/regression-conf.groovy | 7 + regression-test/framework/pom.xml | 5 + regression-test/plugins/aliyunOssSdk.groovy | 169 ++++++++++++ .../suites/show_data/ddl/lineitem_delete.sql | 2 + .../suites/show_data/ddl/lineitem_dup.sql | 25 ++ .../suites/show_data/ddl/lineitem_mow.sql | 25 ++ .../show_data/test_show_mow_data.groovy | 240 ++++++++++++++++++ 8 files changed, 473 insertions(+) create mode 100644 aazcp.tar.gz create mode 100644 regression-test/plugins/aliyunOssSdk.groovy create mode 100644 regression-test/suites/show_data/ddl/lineitem_delete.sql create mode 100644 regression-test/suites/show_data/ddl/lineitem_dup.sql create mode 100644 regression-test/suites/show_data/ddl/lineitem_mow.sql create mode 100644 regression-test/suites/show_data/test_show_mow_data.groovy diff --git a/aazcp.tar.gz b/aazcp.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..681acf72cde8599720e938dcd7301612b5ec5f00 GIT binary patch literal 4218 zcmV-=5QXm_iwFP!000001MNF&j~mC4`nm*48~HQZmB0BfTvhkHIporc zq|4p00WHbys_J@oRnJJ%-qt7iYtMBQVC-yd@lP1(PyW5Qxl`QUE^U-{Hm((lh3)OF zYh>&BvL%McT+Jcmnq%AUBDky8|CbJp+rQs8pQ8^fYyZ-Av9z-Z^Tpz3skpNLix`pp zO~aywOUJ#wH&NM}=Cj)a4ZOX%InVyZjh$l3{+rvS(lt_eb}Y;v|Ih7TY1PV|8tIhx z8#PitAkCu=sl8rrciJR$h_O8-@){wH-chSsYu&BAL15IIo!aeMi(@pqjfTP@j?1l% z4=@L!-90{D4AH1JYt8QAJ}k_Ec&%G*cIq8Yq*|-g56ca?xTTbGDY)9}om#V6s~)%N zmD*y^YQ0@K>NY!9k?fRTC&5?**Q#~8t>!_ae4CKUopMVqrXf(wcBkCww&y{#@6?a0 zXdc`PKaigYJtxERaAa}~` zJ24tLvfr)Tt%1XCtR1(Gj%%$>z1HRqD>-yx8oK5hw$-z|u|)QWRFr_BwYC50!22f| z8TlW={RQX$?d>T4mo|9*-z={3|BD!_{J+Zo&p-cnoAuYatK|PrII`-0YEqXz!z18| z{9hlmk=3lpZGNVK6t>6ltBQweEP z%E?1nfW_FrFgbqTU;+;qm>TW~U<^j4w)21tfRxtn8@RP*62pRtF=qr39XiyUzF`ev z>&cm83`Z`prxtbC$e6%>9TcT~5HQ08;b2>k_00BsQDRd2%23F+fDnpYQVT=|07R1f zRVnuh#~y2E#IjxDF&a@P^evrETwoU%8$$`ASvtq|r3?1}9^deZ*r%=r@ER9|*n>D2 z(Oker0)&iQce0z$Pp4B=I5Ss-q5I0h!vVcJlJPrU#)3}ACa+}oK64@`e>urU6 zyWY8T)a{UOms>3?-=R)BYLUuOvs&-ekDBo7fRvkWAm-hAv#Jm%N8lg=eNG${0ys5L zpR^zIrho_Z72is1LUm(c=pddo^t2%*L;E3hEOeC#b;brm!!ls956&?*T<%f~QDawZ{k z%I`8@caMNY8T}@Fmj!kHd*Sz_M4 z2{IhF>5WgR)3II6Y}r%hQxvo4v9yoVi>P%RkII=?HW6mNzQIXigUMTM8 z;MDip;Im`xj>bm2>qUheYwl=QAr0mpXb@7|QFqY+V{?8b!Qmm}Y7lI@{y|>cDXFD` zy7_f=V|(}Oh0Q`f1Lyv(6)4_ZzBTYufnyF1YHI0c6%4%?x378BIlE)HY`370ifx;HsHLJ! zkpM@D3ln^gzDB#DPtx7yQR}eWhzO$iKusYtTmyG);ngv!6-Z^8jzKD1e6iZ}5IT5NK!-5VuyxI>!XeOxQw=3YdxpjZ9~J@?Q2%4wr4i^!G=!lMJkaQa3*4S_+B zjwgOz`>KjG$m0nWai~pv!Vpm;Bq)U3_Y4yYCUy$&7M&)i<=iVFJUfMgbpjTbCEasO zvi>@`UF(q8$sIuiLZ_`C7v2wbV0esW&>o^kNjI~4@L{7xsJ_tO0NGzs>04BX5;jHv zD=19T0#u!9hI;@ei~y+Pz#o>g2ExpjEo#}&hZf;NKgqCU!@Cjip;s54D=Fw)cB7i%XV(wv&3gMztvcJz&$g?b z5oC?N%1lZpa%lLZX!xK9?*Zf)-?_EG^)Q5F5j)szM_hs8668^95u6mjNm;#l!ep^{ z#v7gk!!pD8B&ntE0puCZyN+l)N61Z6Ee03}=h@^BM5mSt=>BtckG{jvV`YK-Nor=D#$6VXN zo7Lqt=3{iQe%s?u3*f|3;d5XNRi5fA{5wC*pjZ*$$BzBbfKxHXZ`JlN>H7fKjo|?k zxn4#SR_|ZYhRriyfW1UBmN;-?!e*Q=Hk>W#t@3&Olm(}x>EVSj@s%Bjnt<0HETcuB z+1@BWNcjj`9=Dyw1%4(r-hM7iq2?o`=$v{Wn~OJ|Kxs)*`y3}NOyDSVV7#?7R{~s0 zWh~t^C>ISfj(fydh5wed2MXv+31v?*fWDM0{QJ9+=VT?jxa-~ojx|#R+<}c{a)Vk! zcO(m5l$fHFl&nyDgIPZwFyE%j*x`T! zrwnSayVN#f0MEdEgEtJ8 z+w;I9d#>F(+>c*%Vp3Th!?;s^;%dUt=updqH9r1D-u ze3x-8NAgfwlr|$#2{rMd;0*D@ryzbc)!R?Q@(s?i|8eymoqu?bnXP8rfzz9RITt&I z@%e=}9QDR$>`n8^i*F9q20FprB|1T4*}HMhfq3wjctuD`5a4r2yAJgmkOG4DVmG7+ zGC*a9R~!NCJqf=_C&3j(y#Gft2rSj)DG^Ok%Ie8bE55P(ed4r;eU`Putl z{NQgFAO7_6=kHwn@CT1S`Q_tJeh;gcfBfqVrG#sW4YPbP7@0n~Gw)&J9N%0oop2EX z_TCBE`|`7QFMj!(i$8t%%|kHm5XAY=I1=6%6_maXAnSbN3TXe zV^vh(bc=E+Bod##!Z*9cqo74~+YybJ1g7MPfA`)AG^8RcM!&H__kW!v)0BAa0_+@a zpG&t<{@WJf(R`6#iz(nixHqAiKH|J2a2CED63MR+BR7)@F=fmD$4gZYD(xFN zqA~G3agwH849Dy>Spu4jfYM8kaBDc{?n#`ebaKv_NhK}J3E%$(&oTf0#czIn@!@|& z8T!e8e(&<C%;xp-YG9smjnd4j$QUs0LIFrFdj3h}j`1sod02aR{J8Q`I&Ik+^Z z4v1xW@F)L0vxsLnT?3Bx_GVfp9Er!0bA>BFTA3qEA$E)Nl*A%YN00000 literal 0 HcmV?d00001 diff --git a/regression-test/conf/regression-conf.groovy b/regression-test/conf/regression-conf.groovy index ab9bb0beb91869..bc001126bceadd 100644 --- a/regression-test/conf/regression-conf.groovy +++ b/regression-test/conf/regression-conf.groovy @@ -259,3 +259,10 @@ lakesoulMinioEndpoint="*******" metaServiceToken = "greedisgood9999" instanceId = "default_instance_id" multiClusterInstance = "default_instance_id" + +storageProvider = "oss" +cbsS3Ak = "*******" +cbsS3Sk = "*******" +cbsS3Endpoint = "oss-cn-beijing.aliyuncs.com" +cbsS3Bucket = "test-bucket" +cbsS3Prefix = "test-cluster-prefix" diff --git a/regression-test/framework/pom.xml b/regression-test/framework/pom.xml index 813659989ae60c..cad25df8ced92d 100644 --- a/regression-test/framework/pom.xml +++ b/regression-test/framework/pom.xml @@ -409,6 +409,11 @@ under the License. compile + + com.aliyun.oss + aliyun-sdk-oss + 3.18.1 + diff --git a/regression-test/plugins/aliyunOssSdk.groovy b/regression-test/plugins/aliyunOssSdk.groovy new file mode 100644 index 00000000000000..cbc132a088dffb --- /dev/null +++ b/regression-test/plugins/aliyunOssSdk.groovy @@ -0,0 +1,169 @@ + + +// 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. +import org.apache.doris.regression.suite.Suite; +import org.apache.doris.regression.Config; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import com.aliyun.oss.ClientException; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.OSSException; +import com.aliyun.oss.model.DeleteObjectsRequest; +import com.aliyun.oss.model.DeleteObjectsResult; +import com.aliyun.oss.model.ListObjectsRequest; +import com.aliyun.oss.model.OSSObjectSummary; +import com.aliyun.oss.model.ObjectListing; + +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import groovy.util.logging.Slf4j + +Suite.metaClass.initOssClient = { String accessKeyId, String accessKeySecret, String endpoint -> + return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret) +} + +Suite.metaClass.listOssObjectWithPrefix = { OSS client, String bucketName, String prefix="" -> + try { + ObjectListing objectListing = null; + String nextMarker = null; + final int maxKeys = 500; + List sums = null; + + if (!client.doesBucketExist(bucketName)) { + logger.info("no bucket named ${bucketName} in ${endpoint}") + return + } + + // Gets all object with specified marker by paging. Each page will have up to 100 entries. + logger.info("List all objects with prefix:"); + nextMarker = null; + do { + objectListing = client.listObjects(new ListObjectsRequest(bucketName). + withPrefix(prefix).withMarker(nextMarker).withMaxKeys(maxKeys)); + + sums = objectListing.getObjectSummaries(); + for (OSSObjectSummary s : sums) { + logger.info("\t" + s.getKey()); + } + + nextMarker = objectListing.getNextMarker(); + + } while (objectListing.isTruncated()); + } catch (OSSException oe) { + logger.error("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + logger.error("Error Message: " + oe.getErrorMessage()); + logger.error("Error Code: " + oe.getErrorCode()); + logger.error("Request ID: " + oe.getRequestId()); + logger.error("Host ID: " + oe.getHostId()); + } catch (ClientException ce) { + logger.error("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + logger.error("Error Message: " + ce.getMessage()); + } finally { + /* + * Do not forget to shut down the client finally to release all allocated resources. + */ + //client.shutdown(); + logger.info("Done!") + } + +} + +// get file size in a specific directory +Suite.metaClass.calculateFolderLength = { OSS client, String bucketName, String folder -> + long size = 0L; + ObjectListing objectListing = null; + do { + // The default value for MaxKey is 100, and the maximum value is 1000 + ListObjectsRequest request = new ListObjectsRequest(bucketName).withPrefix(folder).withMaxKeys(1000); + if (objectListing != null) { + request.setMarker(objectListing.getNextMarker()); + } + objectListing = client.listObjects(request); + List sums = objectListing.getObjectSummaries(); + for (OSSObjectSummary s : sums) { + size += s.getSize(); + } + } while (objectListing.isTruncated()); + return size; +} + +Suite.metaClass.shutDownOssClient = { OSS client -> + client.shutdown(); +} + + + +Suite.metaClass.getOssAllDirSizeWithPrefix = { OSS client, String bucketName, String prefix="" -> + try { + if (!client.doesBucketExist(bucketName)) { + logger.info("no bucket named ${bucketName} in ${endpoint}") + return + } + + // Gets all object with specified marker by paging. Each page will have up to 100 entries. + logger.info("List all objects with prefix:"); + ObjectListing objectListing = null; + do { + // By default, list 100 files or directories at a time + ListObjectsRequest request = new ListObjectsRequest(bucketName).withDelimiter("/").withPrefix(prefix); + if (objectListing != null) { + request.setMarker(objectListing.getNextMarker()); + } + objectListing = client.listObjects(request); + List folders = objectListing.getCommonPrefixes(); + for (String folder : folders) { + logger.info(folder + " : " + (calculateFolderLength(client, bucketName, folder) / (1024 * 1024 * 1024)) + "GB"); + } + List sums = objectListing.getObjectSummaries(); + for (OSSObjectSummary s : sums) { + logger.info(s.getKey() + " : " + (s.getSize() / (1024 * 1024 * 1024)) + "GB"); + } + } while (objectListing.isTruncated()); + + } catch (OSSException oe) { + logger.error("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + logger.error("Error Message: " + oe.getErrorMessage()); + logger.error("Error Code: " + oe.getErrorCode()); + logger.error("Request ID: " + oe.getRequestId()); + logger.error("Host ID: " + oe.getHostId()); + } catch (ClientException ce) { + logger.error("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + logger.error("Error Message: " + ce.getMessage()); + } finally { + /* + * Do not forget to shut down the client finally to release all allocated resources. + */ + //client.shutdown(); + logger.info("Done!") + } +} + + + diff --git a/regression-test/suites/show_data/ddl/lineitem_delete.sql b/regression-test/suites/show_data/ddl/lineitem_delete.sql new file mode 100644 index 00000000000000..df8b04056491e9 --- /dev/null +++ b/regression-test/suites/show_data/ddl/lineitem_delete.sql @@ -0,0 +1,2 @@ +DELETE from ${table} where L_ORDERKEY >= 0; + diff --git a/regression-test/suites/show_data/ddl/lineitem_dup.sql b/regression-test/suites/show_data/ddl/lineitem_dup.sql new file mode 100644 index 00000000000000..29ed215d2363fe --- /dev/null +++ b/regression-test/suites/show_data/ddl/lineitem_dup.sql @@ -0,0 +1,25 @@ +CREATE TABLE IF NOT EXISTS lineitem_mow ( + L_ORDERKEY INTEGER NOT NULL, + L_PARTKEY INTEGER NOT NULL, + L_SUPPKEY INTEGER NOT NULL, + L_LINENUMBER INTEGER NOT NULL, + L_QUANTITY DECIMAL(15,2) NOT NULL, + L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL, + L_DISCOUNT DECIMAL(15,2) NOT NULL, + L_TAX DECIMAL(15,2) NOT NULL, + L_RETURNFLAG CHAR(1) NOT NULL, + L_LINESTATUS CHAR(1) NOT NULL, + L_SHIPDATE DATE NOT NULL, + L_COMMITDATE DATE NOT NULL, + L_RECEIPTDATE DATE NOT NULL, + L_SHIPINSTRUCT CHAR(25) NOT NULL, + L_SHIPMODE CHAR(10) NOT NULL, + L_COMMENT VARCHAR(44) NOT NULL +) +DUPLICATE KEY(L_ORDERKEY, L_PARTKEY, L_SUPPKEY, L_LINENUMBER) +DISTRIBUTED BY HASH(L_ORDERKEY) BUCKETS 3 +PROPERTIES ( + "replication_num" = "1" +) + + diff --git a/regression-test/suites/show_data/ddl/lineitem_mow.sql b/regression-test/suites/show_data/ddl/lineitem_mow.sql new file mode 100644 index 00000000000000..1d29f44ac8fb6a --- /dev/null +++ b/regression-test/suites/show_data/ddl/lineitem_mow.sql @@ -0,0 +1,25 @@ +CREATE TABLE IF NOT EXISTS lineitem_mow ( + L_ORDERKEY INTEGER NOT NULL, + L_PARTKEY INTEGER NOT NULL, + L_SUPPKEY INTEGER NOT NULL, + L_LINENUMBER INTEGER NOT NULL, + L_QUANTITY DECIMAL(15,2) NOT NULL, + L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL, + L_DISCOUNT DECIMAL(15,2) NOT NULL, + L_TAX DECIMAL(15,2) NOT NULL, + L_RETURNFLAG CHAR(1) NOT NULL, + L_LINESTATUS CHAR(1) NOT NULL, + L_SHIPDATE DATE NOT NULL, + L_COMMITDATE DATE NOT NULL, + L_RECEIPTDATE DATE NOT NULL, + L_SHIPINSTRUCT CHAR(25) NOT NULL, + L_SHIPMODE CHAR(10) NOT NULL, + L_COMMENT VARCHAR(44) NOT NULL +) +UNIQUE KEY(L_ORDERKEY, L_PARTKEY, L_SUPPKEY, L_LINENUMBER) +DISTRIBUTED BY HASH(L_ORDERKEY) BUCKETS 3 +PROPERTIES ( + "replication_num" = "1" +) + + diff --git a/regression-test/suites/show_data/test_show_mow_data.groovy b/regression-test/suites/show_data/test_show_mow_data.groovy new file mode 100644 index 00000000000000..c94e5786d7efae --- /dev/null +++ b/regression-test/suites/show_data/test_show_mow_data.groovy @@ -0,0 +1,240 @@ +// 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. + +// The cases is copied from https://github.com/trinodb/trino/tree/master +// /testing/trino-product-tests/src/main/resources/sql-tests/testcases/tpcds +// and modified by Doris. +import org.codehaus.groovy.runtime.IOGroovyMethods + + // loading one data 10 times, expect data size not rising +suite("test_mow_show_data_in_cloud","p2") { + //cloud-mode + if (!isCloudMode()) { + logger.info("not cloud mode, not run") + return + } + + def repeate_stream_load_same_data = { String tableName, int loadTimes -> + for (int i = 0; i < loadTimes; i++) { + streamLoad { + table tableName + set 'column_separator', '|' + set 'compress_type', 'GZ' + file """${getS3Url()}/regression/tpch/sf1/lineitem.csv.split00.gz""" + time 10000 // limit inflight 10s + check { result, exception, startTime, endTime -> + if (exception != null) { + throw exception + } + log.info("Stream load result: ${result}".toString()) + def json = parseJson(result) + assertEquals("success", json.Status.toLowerCase()) + assertEquals(json.NumberTotalRows, json.NumberLoadedRows) + assertTrue(json.NumberLoadedRows > 0 && json.LoadBytes > 0) + } + } + } + } + + def get_tablets_from_table = { String table -> + def res = sql_return_maparray """show tablets from ${table}""" + return res + } + + def show_tablet_compaction = { HashMap tablet -> + StringBuilder sb = new StringBuilder(); + sb.append("curl -X GET ") + sb.append(tablet["CompactionStatus"]) + String command = sb.toString() + logger.info(command) + process = command.execute() + code = process.waitFor() + err = IOGroovyMethods.getText(new BufferedReader(new InputStreamReader(process.getErrorStream()))); + out = process.getText() + logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) + assertEquals(code, 0) + return parseJson(out.trim()) + } + + def trigger_tablet_compaction = { HashMap tablet, String compact_type -> + //support trigger base/cumulative/full compaction + def tabletStatusBeforeCompaction = show_tablet_compaction(tablet) + + String tabletInBe = tablet + String showCompactionStatus = tablet["CompactionStatus"] + String triggerCompactionUrl = showCompactionStatus.split("show")[0] + "run?tablet_id=" + tablet["TabletId"] + "&compact_type=" + compact_type + StringBuilder sb = new StringBuilder(); + sb.append("curl -X POST ") + sb.append(triggerCompactionUrl) + String command = sb.toString() + logger.info(command) + process = command.execute() + code = process.waitFor() + err = IOGroovyMethods.getText(new BufferedReader(new InputStreamReader(process.getErrorStream()))); + out = process.getText() + def outJson = parseJson(out) + logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) + // if code = 0 means compaction happend, need to check + // other condition may indicate no suitable compaction condition + if ( code == 0 && outJson.status.toLowerCase() == "success" ){ + def compactionStatus = "RUNNING" + def tabletStatusAfterCompaction = null + long startTime = System.currentTimeMillis() + long timeoutTimestamp = startTime + 5 * 60 * 1000 // 5 min + do { + tabletStatusAfterCompaction = show_tablet_compaction(tablet) + logger.info("tabletStatusAfterCompaction class: " + tabletStatusAfterCompaction.class) + logger.info("hhhhhh: " + tabletStatusAfterCompaction.toString()) + if (tabletStatusAfterCompaction.rowsets.size() < tabletStatusBeforeCompaction.rowsets.size()){ + compactionStatus = 'FINISHED' + } + Thread.sleep(60 * 1000) + } while (timeoutTimestamp > System.currentTimeMillis() && (status != 'FINISHED')) + + if (status != "FINISHED") { + logger.info("compaction not Finish or failed") + return false + } + } + } + + def trigger_compaction = { List> tablets -> + for(def tablet: tablets) { + trigger_tablet_compaction(tablet, "cumulative") + trigger_tablet_compaction(tablet, "base") + trigger_tablet_compaction(tablet, "full") + } + } + + def caculate_table_data_size_in_backend_storage = { List> tablets -> + storageType = context.config.otherConfigs.get("storageProvider") + Double storageSize = 0 + + List tabletIds = [] + for(def tablet: tablets) { + tabletIds.add(tablet["TabletId"]) + } + + if (storageType.toLowerCase() == "oss") { + //cbs means cluster backend storage + ak = context.config.otherConfigs.get("cbsS3Ak") + sk = context.config.otherConfigs.get("cbsS3Sk") + endpoint = context.config.otherConfigs.get("cbsS3Endpoint") + bucketName = context.config.otherConfigs.get("cbsS3Bucket") + storagePrefix = context.config.otherConfigs.get("cbsS3Prefix") + + client = initOssClient(ak, sk, endpoint) + for(String tabletId: tabletIds) { + storageSize += calculateFolderLength(client, bucketName, storagePrefix + "/data/" + tabletId) + } + shutDownOssClient(client) + } + + if (storageType.toLowerCase() == "hdfs") { + fsName = context.config.otherConfigs.get("cbsFsName") + isKerberosFs = context.config.otherConfigs.get("cbsFsKerberos") + fsUser = context.config.otherConfigs.get("cbsFsUser") + storagePrefix = context.config.otherConfigs.get("cbsFsPrefix") + } + + return storageSize + } + + def translate_different_unit_to_MB = { String size, String unitField -> + Double sizeKb = 0.0 + if (unitField == "KB") { + sizeKb = Double.parseDouble(size) / 1024 + } else if (unitField == "MB") { + sizeKb = Double.parseDouble(size) + } else if (unitField == "GB") { + sizeKb = Double.parseDouble(size) * 1024 * 1024 + } else if (unitField == "TB") { + sizeKb = Double.parseDouble(size) * 1024 * 1024 * 1024 + } + return sizeKb + } + + def show_table_data_size_through_mysql = { String table -> + def mysqlShowDataSize = 0L + def res = sql_return_maparray " show data from ${table}" + def tableSizeInfo = res[0] + def fields = tableSizeInfo["Size"].split(" ") + if (fields.length == 2 ){ + def sizeField = fields[0] + def unitField = fields[1] + mysqlShowDataSize = translate_different_unit_to_MB(sizeField, unitField) + } + return mysqlShowDataSize + } + + def caculate_table_data_size_through_api = { List> tablets -> + Double apiCaculateSize = 0 + for (HashMap tablet in tablets) { + def tabletStatus = show_tablet_compaction(tablet) + + for(String rowset: tabletStatus.rowsets){ + def fields = rowset.split(" ") + if (fields.length == 7) { + def sizeField = fields[-2] // the last field(size) + def unitField = fields[-1] // The second to last field(unit) + // 转换成 KB + apiCaculateSize += translate_different_unit_to_MB(sizeField, unitField ) + } + } + } + + return apiCaculateSize + } + + def main = { + tableName="lineitem_mow" + sql "DROP TABLE IF EXISTS ${tableName};" + sql new File("""${context.file.parent}/ddl/${tableName}.sql""").text + sql new File("""${context.file.parent}/ddl/lineitem_delete.sql""").text.replaceAll("\\\$\\{table\\}", tableName) + List tablets = get_tablets_from_table(tableName) + def loadTimes = [1, 10] + Map sizeRecords = ["apiSize":[], "mysqlSize":[], "cbsSize":[]] + for (int i in loadTimes){ + // stream load 1 time, record each size + repeate_stream_load_same_data(tableName, i) + def rows = sql_return_maparray "select count(*) as count from ${tableName};" + logger.info("table ${tableName} has ${rows[0]["count"]} rows") + // 加一下触发compaction的机制 + trigger_compaction(tablets) + + // 然后 sleep 5min, 等fe汇报完 + sleep(300 * 1000) + + sizeRecords["apiSize"].add(caculate_table_data_size_through_api(tablets)) + sizeRecords["cbsSize"].add(caculate_table_data_size_in_backend_storage(tablets)) + sizeRecords["mysqlSize"].add(show_table_data_size_through_mysql(tableName)) + sleep(300 * 1000) + logger.info("after ${i} times stream load, mysqlSize is: ${sizeRecords["mysqlSize"][-1]}, apiSize is: ${sizeRecords["apiSize"][-1]}, storageSize is: ${sizeRecords["cbsSize"][-1]}") + + } + + // expect mysqlSize == apiSize == storageSize + assertEquals(sizeRecords["mysqlSize"][0], sizeRecords["apiSize"][0]) + assertEquals(sizeRecords["mysqlSize"][0], sizeRecords["cbsSize"][0]) + // expect load 1 times == load 10 times + assertEquals(sizeRecords["mysqlSize"][0], sizeRecords["mysqlSize"][1]) + assertEquals(sizeRecords["apiSize"][0], sizeRecords["apiSize"][1]) + assertEquals(sizeRecords["cbsSize"][0], sizeRecords["cbsSize"][1]) + } + + main() +} From 5fcf945b7edceae331a926f4a1cbd17c6389a507 Mon Sep 17 00:00:00 2001 From: Pxl Date: Thu, 12 Dec 2024 11:47:49 +0800 Subject: [PATCH 17/63] =?UTF-8?q?[Bug](case)=20fix=20conflict=20table=20na?= =?UTF-8?q?me=20between=20test=5Fbitmap=5Fintersect=20and=20test=5Fbitmap?= =?UTF-8?q?=E2=80=A6=20(#45314)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix conflict table name between test_bitmap_intersect and test_bitmap_serialize --- .../suites/correctness_p0/test_bitmap_serialize.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression-test/suites/correctness_p0/test_bitmap_serialize.groovy b/regression-test/suites/correctness_p0/test_bitmap_serialize.groovy index d9d899f1706638..cf3b4b169d8e20 100644 --- a/regression-test/suites/correctness_p0/test_bitmap_serialize.groovy +++ b/regression-test/suites/correctness_p0/test_bitmap_serialize.groovy @@ -16,7 +16,7 @@ // under the License. suite("test_bitmap_serialize") { - def tableName = "test_bitmap" + def tableName = "test_bitmap_serialize" sql """ DROP TABLE IF EXISTS ${tableName} """ sql """ From e2c24e386ce15474ad18ae7663205439d854112a Mon Sep 17 00:00:00 2001 From: meiyi Date: Thu, 12 Dec 2024 12:02:19 +0800 Subject: [PATCH 18/63] [fix](cluster key) fix cluster key schema change (#45203) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem Summary: for schema change: add a key in the tail of all keys, may get: ``` F20241209 14:52:09.513403 3166619 segment_writer.cpp:1309] Check failed: key.compare(last_key) >= 0 key is not sorted! current key: ^A^B06olTqiL2rEn48nTpmP8, last key: ^B^@^OЭ^BxsmIHehvUnv *** Check failure stack trace: *** @ 0x563674f2dcc6 google::LogMessage::SendToLog() @ 0x563674f2a710 google::LogMessage::Flush() @ 0x563674f2e509 google::LogMessageFatal::~LogMessageFatal() @ 0x56366a8a72c0 doris::segment_v2::SegmentWriter::_generate_short_key_index() @ 0x56366a8a6032 doris::segment_v2::SegmentWriter::append_block() @ 0x56366a7624c9 doris::SegmentCreator::add_block() @ 0x56366a731d35 doris::BaseBetaRowsetWriter::add_block() @ 0x56366a94a233 doris::VSchemaChangeDirectly::_inner_process() @ 0x56366a95d558 doris::SchemaChange::process() @ 0x56366a9511e5 doris::SchemaChangeJob::_convert_historical_rowsets() @ 0x56366a94e5e2 doris::SchemaChangeJob::_do_process_alter_tablet() @ 0x56366a94cf22 doris::SchemaChangeJob::process_alter_tablet() @ 0x563669e9e857 doris::alter_tablet_callback() ``` --- be/src/cloud/cloud_schema_change_job.cpp | 9 + be/src/olap/memtable.cpp | 2 + be/src/olap/schema_change.cpp | 9 + .../test_schema_change_add_key_column.csv | 8192 +++++++ .../test_schema_change_add_key_column.out | 19 + .../test_schema_change_add_key_column1.csv | 20480 ++++++++++++++++ .../test_schema_change_add_key_column.groovy | 148 + 7 files changed, 28859 insertions(+) create mode 100644 regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column.csv create mode 100644 regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column.out create mode 100644 regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column1.csv create mode 100644 regression-test/suites/unique_with_mow_c_p0/test_schema_change_add_key_column.groovy diff --git a/be/src/cloud/cloud_schema_change_job.cpp b/be/src/cloud/cloud_schema_change_job.cpp index 1cc4d052a81d69..b086def3c03ee5 100644 --- a/be/src/cloud/cloud_schema_change_job.cpp +++ b/be/src/cloud/cloud_schema_change_job.cpp @@ -169,6 +169,15 @@ Status CloudSchemaChangeJob::process_alter_tablet(const TAlterTabletReqV2& reque reader_context.batch_size = ALTER_TABLE_BATCH_SIZE; reader_context.delete_bitmap = &_base_tablet->tablet_meta()->delete_bitmap(); reader_context.version = Version(0, start_resp.alter_version()); + std::vector cluster_key_idxes; + if (!_base_tablet_schema->cluster_key_uids().empty()) { + for (const auto& uid : _base_tablet_schema->cluster_key_uids()) { + cluster_key_idxes.emplace_back(_base_tablet_schema->field_index(uid)); + } + reader_context.read_orderby_key_columns = &cluster_key_idxes; + reader_context.is_unique = false; + reader_context.sequence_id_idx = -1; + } for (auto& split : rs_splits) { RETURN_IF_ERROR(split.rs_reader->init(&reader_context)); diff --git a/be/src/olap/memtable.cpp b/be/src/olap/memtable.cpp index 765f67a07c7884..f8cc79b205535f 100644 --- a/be/src/olap/memtable.cpp +++ b/be/src/olap/memtable.cpp @@ -34,6 +34,7 @@ #include "runtime/descriptors.h" #include "runtime/exec_env.h" #include "runtime/thread_context.h" +#include "util/debug_points.h" #include "util/runtime_profile.h" #include "util/stopwatch.hpp" #include "vec/aggregate_functions/aggregate_function_reader.h" @@ -589,6 +590,7 @@ void MemTable::shrink_memtable_by_agg() { } bool MemTable::need_flush() const { + DBUG_EXECUTE_IF("MemTable.need_flush", { return true; }); auto max_size = config::write_buffer_size; if (_partial_update_mode == UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS) { auto update_columns_size = _num_columns; diff --git a/be/src/olap/schema_change.cpp b/be/src/olap/schema_change.cpp index 08b9b9a93d90f5..7f947612eed4ac 100644 --- a/be/src/olap/schema_change.cpp +++ b/be/src/olap/schema_change.cpp @@ -866,6 +866,7 @@ Status SchemaChangeJob::_do_process_alter_tablet(const TAlterTabletReqV2& reques for (int i = 0; i < num_cols; ++i) { return_columns[i] = i; } + std::vector cluster_key_idxes; DBUG_EXECUTE_IF("SchemaChangeJob::_do_process_alter_tablet.block", DBUG_BLOCK); @@ -982,6 +983,14 @@ Status SchemaChangeJob::_do_process_alter_tablet(const TAlterTabletReqV2& reques reader_context.batch_size = ALTER_TABLE_BATCH_SIZE; reader_context.delete_bitmap = &_base_tablet->tablet_meta()->delete_bitmap(); reader_context.version = Version(0, end_version); + if (!_base_tablet_schema->cluster_key_uids().empty()) { + for (const auto& uid : _base_tablet_schema->cluster_key_uids()) { + cluster_key_idxes.emplace_back(_base_tablet_schema->field_index(uid)); + } + reader_context.read_orderby_key_columns = &cluster_key_idxes; + reader_context.is_unique = false; + reader_context.sequence_id_idx = -1; + } for (auto& rs_split : rs_splits) { res = rs_split.rs_reader->init(&reader_context); if (!res) { diff --git a/regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column.csv b/regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column.csv new file mode 100644 index 00000000000000..87e7cd5c2d9867 --- /dev/null +++ b/regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column.csv @@ -0,0 +1,8192 @@ +13668,20000,31000,40296 +14535,20001,30999,40697 +13905,20002,30998,40396 +13802,20003,30997,40727 +16784,20004,30996,40263 +12632,20005,30995,40595 +15749,20006,30994,40042 +15315,20007,30993,40226 +14984,20008,30992,40647 +15163,20009,30991,40976 +17216,20010,30990,40258 +13628,20011,30989,40024 +11832,20012,30988,40406 +14862,20013,30987,40038 +14799,20014,30986,40060 +17554,20015,30985,40437 +17259,20016,30984,40374 +13468,20017,30983,40268 +10251,20018,30982,40089 +16500,20019,30981,40674 +15808,20020,30980,40697 +10181,20021,30979,40899 +16206,20022,30978,40190 +11794,20023,30977,40643 +13606,20024,30976,40349 +13331,20025,30975,40952 +17016,20026,30974,40145 +17653,20027,30973,40132 +14528,20028,30972,40840 +12356,20029,30971,40271 +11340,20030,30970,40106 +16323,20031,30969,40123 +13513,20032,30968,40004 +16167,20033,30967,40521 +16005,20034,30966,40507 +11039,20035,30965,40145 +15207,20036,30964,40644 +13976,20037,30963,40662 +16340,20038,30962,40096 +13203,20039,30961,40928 +15528,20040,30960,40269 +16644,20041,30959,40971 +13555,20042,30958,40448 +13051,20043,30957,40597 +16595,20044,30956,40885 +15508,20045,30955,40589 +15392,20046,30954,40337 +17534,20047,30953,40391 +17483,20048,30952,40359 +14545,20049,30951,40564 +10667,20050,30950,40431 +13808,20051,30949,40622 +16938,20052,30948,40645 +12383,20053,30947,40168 +16701,20054,30946,40869 +12041,20055,30945,40180 +14781,20056,30944,40540 +13466,20057,30943,40591 +13395,20058,30942,40921 +16613,20059,30941,40215 +17849,20060,30940,40011 +11001,20061,30939,40268 +17222,20062,30938,40756 +13144,20063,30937,40724 +12276,20064,30936,40283 +17894,20065,30935,40113 +14610,20066,30934,40824 +15108,20067,30933,40757 +11162,20068,30932,40768 +11848,20069,30931,40822 +13165,20070,30930,40920 +16842,20071,30929,40268 +13411,20072,30928,40933 +14364,20073,30927,40110 +14137,20074,30926,40906 +17236,20075,30925,40381 +10087,20076,30924,40772 +13528,20077,30923,40961 +16860,20078,30922,40592 +11985,20079,30921,40495 +12828,20080,30920,40724 +10329,20081,30919,40372 +12021,20082,30918,40082 +14103,20083,30917,40763 +15160,20084,30916,40728 +16637,20085,30915,40106 +14893,20086,30914,40173 +11695,20087,30913,40147 +13755,20088,30912,40126 +12231,20089,30911,40686 +11608,20090,30910,40958 +13524,20091,30909,40516 +14629,20092,30908,40789 +15770,20093,30907,40622 +16967,20094,30906,40319 +17174,20095,30905,40052 +16949,20096,30904,40693 +13020,20097,30903,40593 +11880,20098,30902,40489 +16770,20099,30901,40339 +10762,20100,30900,40010 +10633,20101,30899,40921 +17889,20102,30898,40880 +14806,20103,30897,40638 +13501,20104,30896,40529 +16220,20105,30895,40034 +17404,20106,30894,40586 +15934,20107,30893,40767 +17688,20108,30892,40393 +10038,20109,30891,40416 +14309,20110,30890,40135 +17852,20111,30889,40990 +11215,20112,30888,40019 +10001,20113,30887,40028 +11191,20114,30886,40706 +16341,20115,30885,40890 +10681,20116,30884,40442 +12232,20117,30883,40936 +13669,20118,30882,40037 +10924,20119,30881,40944 +13584,20120,30880,40219 +13509,20121,30879,40846 +11433,20122,30878,40761 +13485,20123,30877,40139 +12264,20124,30876,40718 +13820,20125,30875,40972 +15473,20126,30874,40067 +11425,20127,30873,40969 +13034,20128,30872,40498 +11230,20129,30871,40618 +17820,20130,30870,40575 +11422,20131,30869,40500 +13597,20132,30868,40828 +13659,20133,30867,40369 +16185,20134,30866,40705 +15424,20135,30865,40166 +15003,20136,30864,40320 +10559,20137,30863,40445 +16050,20138,30862,40607 +13804,20139,30861,40363 +17691,20140,30860,40622 +11751,20141,30859,40684 +16628,20142,30858,40016 +16415,20143,30857,40954 +15822,20144,30856,40598 +10724,20145,30855,40717 +14457,20146,30854,40559 +10129,20147,30853,40972 +16739,20148,30852,40812 +16165,20149,30851,40977 +15488,20150,30850,40575 +17768,20151,30849,40427 +13876,20152,30848,40652 +13983,20153,30847,40157 +10896,20154,30846,40848 +10112,20155,30845,40084 +18163,20156,30844,40062 +12214,20157,30843,40006 +15597,20158,30842,40304 +16464,20159,30841,40701 +10004,20160,30840,40227 +11671,20161,30839,40266 +12022,20162,30838,40779 +17674,20163,30837,40743 +18030,20164,30836,40909 +14745,20165,30835,40877 +10936,20166,30834,40612 +16725,20167,30833,40532 +14336,20168,30832,40186 +16133,20169,30831,40673 +14350,20170,30830,40152 +18068,20171,30829,40137 +11504,20172,30828,40242 +11069,20173,30827,40260 +11698,20174,30826,40753 +17307,20175,30825,40021 +11134,20176,30824,40036 +12513,20177,30823,40054 +13786,20178,30822,40697 +12250,20179,30821,40560 +14766,20180,30820,40180 +12776,20181,30819,40031 +16904,20182,30818,40066 +16389,20183,30817,40236 +15280,20184,30816,40840 +16317,20185,30815,40317 +13244,20186,30814,40052 +13175,20187,30813,40495 +14254,20188,30812,40205 +10615,20189,30811,40739 +11870,20190,30810,40911 +10377,20191,30809,40591 +15435,20192,30808,40326 +17402,20193,30807,40603 +15056,20194,30806,40860 +17271,20195,30805,40979 +14597,20196,30804,40605 +15832,20197,30803,40653 +15616,20198,30802,40271 +12967,20199,30801,40808 +15656,20200,30800,40056 +17190,20201,30799,40013 +13721,20202,30798,40519 +12482,20203,30797,40657 +15480,20204,30796,40861 +15446,20205,30795,40496 +14571,20206,30794,40452 +12039,20207,30793,40182 +10870,20208,30792,40541 +10552,20209,30791,40566 +15540,20210,30790,40168 +17185,20211,30789,40926 +16930,20212,30788,40860 +15792,20213,30787,40785 +13170,20214,30786,40919 +13190,20215,30785,40740 +16417,20216,30784,40559 +11309,20217,30783,40317 +17955,20218,30782,40782 +15296,20219,30781,40708 +16520,20220,30780,40852 +14591,20221,30779,40598 +13826,20222,30778,40502 +15915,20223,30777,40958 +13441,20224,30776,40957 +10902,20225,30775,40444 +15384,20226,30774,40866 +16883,20227,30773,40122 +14935,20228,30772,40092 +15671,20229,30771,40505 +17277,20230,30770,40708 +14010,20231,30769,40155 +11944,20232,30768,40840 +10294,20233,30767,40577 +10648,20234,30766,40836 +14988,20235,30765,40412 +13780,20236,30764,40511 +11542,20237,30763,40432 +17396,20238,30762,40064 +13121,20239,30761,40565 +15447,20240,30760,40257 +13338,20241,30759,40159 +16924,20242,30758,40396 +16354,20243,30757,40294 +14541,20244,30756,40747 +17330,20245,30755,40432 +12284,20246,30754,40188 +17431,20247,30753,40777 +11518,20248,30752,40336 +10621,20249,30751,40564 +12046,20250,30750,40381 +10324,20251,30749,40028 +12381,20252,30748,40897 +12538,20253,30747,40644 +15543,20254,30746,40263 +13208,20255,30745,40796 +15134,20256,30744,40526 +10918,20257,30743,40797 +10261,20258,30742,40749 +18188,20259,30741,40123 +16907,20260,30740,40795 +13593,20261,30739,40673 +11335,20262,30738,40794 +16272,20263,30737,40779 +15465,20264,30736,40524 +16746,20265,30735,40348 +10209,20266,30734,40341 +11364,20267,30733,40224 +11956,20268,30732,40680 +17030,20269,30731,40892 +14305,20270,30730,40918 +17332,20271,30729,40770 +16351,20272,30728,40552 +13951,20273,30727,40712 +16169,20274,30726,40902 +15425,20275,30725,40096 +12107,20276,30724,40849 +14566,20277,30723,40138 +12611,20278,30722,40362 +16438,20279,30721,40541 +10416,20280,30720,40405 +10597,20281,30719,40933 +11498,20282,30718,40976 +15234,20283,30717,40598 +15956,20284,30716,40806 +10917,20285,30715,40006 +12498,20286,30714,40817 +12483,20287,30713,40505 +15381,20288,30712,40603 +14917,20289,30711,40750 +14652,20290,30710,40709 +16575,20291,30709,40686 +12797,20292,30708,40608 +12029,20293,30707,40109 +13526,20294,30706,40673 +12557,20295,30705,40162 +15791,20296,30704,40978 +10098,20297,30703,40617 +15512,20298,30702,40875 +11966,20299,30701,40399 +11891,20300,30700,40144 +13384,20301,30699,40957 +16577,20302,30698,40916 +13180,20303,30697,40525 +11817,20304,30696,40683 +11762,20305,30695,40073 +10328,20306,30694,40749 +13540,20307,30693,40140 +14197,20308,30692,40670 +11654,20309,30691,40600 +15289,20310,30690,40410 +13248,20311,30689,40198 +12103,20312,30688,40622 +14227,20313,30687,40349 +12993,20314,30686,40777 +11736,20315,30685,40705 +16170,20316,30684,40546 +15721,20317,30683,40580 +11861,20318,30682,40291 +16634,20319,30681,40355 +13347,20320,30680,40683 +14555,20321,30679,40327 +11872,20322,30678,40042 +15821,20323,30677,40540 +12509,20324,30676,40261 +15841,20325,30675,40022 +16066,20326,30674,40321 +15556,20327,30673,40487 +16647,20328,30672,40932 +15882,20329,30671,40797 +10291,20330,30670,40335 +10518,20331,30669,40016 +13174,20332,30668,40711 +14601,20333,30667,40473 +16979,20334,30666,40483 +17751,20335,30665,40198 +14423,20336,30664,40424 +13815,20337,30663,40131 +17752,20338,30662,40904 +10717,20339,30661,40578 +12395,20340,30660,40266 +14442,20341,30659,40283 +14643,20342,30658,40330 +10256,20343,30657,40726 +18170,20344,30656,40833 +12175,20345,30655,40837 +17998,20346,30654,40519 +10373,20347,30653,40127 +11046,20348,30652,40661 +15042,20349,30651,40519 +12009,20350,30650,40719 +10148,20351,30649,40755 +16507,20352,30648,40462 +16380,20353,30647,40720 +12707,20354,30646,40604 +13867,20355,30645,40563 +14511,20356,30644,40953 +12971,20357,30643,40739 +17067,20358,30642,40258 +10033,20359,30641,40394 +10238,20360,30640,40257 +11328,20361,30639,40393 +17352,20362,30638,40335 +10314,20363,30637,40843 +10076,20364,30636,40990 +15460,20365,30635,40410 +16151,20366,30634,40292 +11119,20367,30633,40222 +14332,20368,30632,40801 +17329,20369,30631,40332 +10579,20370,30630,40457 +17200,20371,30629,40011 +14289,20372,30628,40101 +14938,20373,30627,40089 +12037,20374,30626,40732 +14881,20375,30625,40228 +14026,20376,30624,40679 +17628,20377,30623,40173 +11356,20378,30622,40051 +15884,20379,30621,40903 +16056,20380,30620,40215 +17769,20381,30619,40278 +16093,20382,30618,40868 +14794,20383,30617,40834 +13601,20384,30616,40540 +12138,20385,30615,40562 +17754,20386,30614,40484 +16910,20387,30613,40645 +16419,20388,30612,40835 +15478,20389,30611,40075 +13748,20390,30610,40877 +17387,20391,30609,40939 +13739,20392,30608,40761 +12608,20393,30607,40406 +16875,20394,30606,40789 +15778,20395,30605,40808 +13530,20396,30604,40604 +17693,20397,30603,40543 +10485,20398,30602,40789 +13846,20399,30601,40131 +16547,20400,30600,40837 +15897,20401,30599,40582 +14008,20402,30598,40095 +13950,20403,30597,40573 +14480,20404,30596,40040 +12487,20405,30595,40948 +15268,20406,30594,40967 +16385,20407,30593,40240 +17059,20408,30592,40489 +10680,20409,30591,40694 +10128,20410,30590,40715 +10005,20411,30589,40913 +15047,20412,30588,40040 +17956,20413,30587,40760 +13811,20414,30586,40171 +10639,20415,30585,40230 +13414,20416,30584,40926 +15986,20417,30583,40923 +17476,20418,30582,40344 +11669,20419,30581,40576 +16474,20420,30580,40645 +16282,20421,30579,40024 +14698,20422,30578,40680 +17449,20423,30577,40410 +13707,20424,30576,40596 +15453,20425,30575,40946 +16513,20426,30574,40504 +15718,20427,30573,40495 +15260,20428,30572,40136 +14820,20429,30571,40927 +10000,20430,30570,40584 +16993,20431,30569,40111 +11275,20432,30568,40924 +15307,20433,30567,40231 +15165,20434,30566,40906 +11110,20435,30565,40810 +10908,20436,30564,40561 +10430,20437,30563,40139 +17557,20438,30562,40363 +18025,20439,30561,40467 +13731,20440,30560,40198 +17267,20441,30559,40887 +15479,20442,30558,40296 +13691,20443,30557,40773 +13518,20444,30556,40968 +16853,20445,30555,40599 +17548,20446,30554,40082 +14469,20447,30553,40209 +15870,20448,30552,40394 +15847,20449,30551,40821 +15083,20450,30550,40922 +16356,20451,30549,40086 +16555,20452,30548,40247 +18016,20453,30547,40297 +12504,20454,30546,40733 +14466,20455,30545,40871 +14269,20456,30544,40634 +14333,20457,30543,40287 +13232,20458,30542,40880 +16502,20459,30541,40680 +11256,20460,30540,40820 +14734,20461,30539,40116 +14779,20462,30538,40612 +14192,20463,30537,40321 +11341,20464,30536,40638 +11317,20465,30535,40505 +13661,20466,30534,40627 +15196,20467,30533,40753 +10950,20468,30532,40338 +10576,20469,30531,40110 +12305,20470,30530,40352 +13482,20471,30529,40315 +14005,20472,30528,40125 +12085,20473,30527,40079 +14839,20474,30526,40523 +10216,20475,30525,40940 +13902,20476,30524,40440 +13793,20477,30523,40882 +10637,20478,30522,40482 +16533,20479,30521,40274 +17000,20480,30520,40634 +16300,20481,30519,40391 +13326,20482,30518,40489 +17564,20483,30517,40966 +13898,20484,30516,40735 +16055,20485,30515,40838 +14857,20486,30514,40482 +12863,20487,30513,40506 +12516,20488,30512,40756 +12390,20489,30511,40948 +10674,20490,30510,40573 +12886,20491,30509,40652 +15483,20492,30508,40303 +14899,20493,30507,40454 +13806,20494,30506,40697 +17818,20495,30505,40209 +11991,20496,30504,40931 +17912,20497,30503,40075 +13388,20498,30502,40320 +11572,20499,30501,40506 +10773,20500,30500,40274 +13562,20501,30499,40629 +13689,20502,30498,40175 +13224,20503,30497,40809 +17233,20504,30496,40664 +10817,20505,30495,40040 +17655,20506,30494,40003 +17649,20507,30493,40076 +12014,20508,30492,40614 +17824,20509,30491,40442 +16528,20510,30490,40508 +15829,20511,30489,40105 +17140,20512,30488,40077 +10167,20513,30487,40569 +12689,20514,30486,40525 +10640,20515,30485,40872 +17118,20516,30484,40214 +12862,20517,30483,40543 +17065,20518,30482,40625 +17854,20519,30481,40228 +17602,20520,30480,40232 +15716,20521,30479,40865 +16743,20522,30478,40183 +11036,20523,30477,40033 +15328,20524,30476,40273 +12935,20525,30475,40819 +16297,20526,30474,40783 +16336,20527,30473,40903 +10064,20528,30472,40235 +13696,20529,30471,40437 +13599,20530,30470,40451 +12536,20531,30469,40501 +13596,20532,30468,40552 +17375,20533,30467,40481 +17060,20534,30466,40070 +15755,20535,30465,40894 +11602,20536,30464,40582 +16933,20537,30463,40601 +10540,20538,30462,40199 +11228,20539,30461,40039 +16115,20540,30460,40860 +12366,20541,30459,40573 +13769,20542,30458,40183 +14378,20543,30457,40998 +11696,20544,30456,40162 +14012,20545,30455,40387 +13343,20546,30454,40118 +14861,20547,30453,40980 +15992,20548,30452,40373 +17949,20549,30451,40597 +11600,20550,30450,40753 +13377,20551,30449,40252 +13516,20552,30448,40544 +13002,20553,30447,40358 +10039,20554,30446,40039 +14722,20555,30445,40169 +15383,20556,30444,40235 +11482,20557,30443,40044 +13979,20558,30442,40670 +15887,20559,30441,40219 +17621,20560,30440,40663 +17927,20561,30439,40831 +12146,20562,30438,40330 +17395,20563,30437,40258 +12457,20564,30436,40207 +16183,20565,30435,40384 +13917,20566,30434,40975 +15888,20567,30433,40577 +10365,20568,30432,40648 +16142,20569,30431,40435 +17916,20570,30430,40729 +13238,20571,30429,40308 +15470,20572,30428,40337 +15651,20573,30427,40740 +16217,20574,30426,40018 +11709,20575,30425,40921 +14526,20576,30424,40699 +12415,20577,30423,40125 +12032,20578,30422,40996 +13257,20579,30421,40202 +11458,20580,30420,40082 +13730,20581,30419,40366 +11592,20582,30418,40858 +10044,20583,30417,40529 +11132,20584,30416,40106 +16179,20585,30415,40123 +10060,20586,30414,40299 +17829,20587,30413,40123 +13787,20588,30412,40067 +13387,20589,30411,40186 +16636,20590,30410,40887 +13355,20591,30409,40765 +13225,20592,30408,40989 +17648,20593,30407,40793 +10454,20594,30406,40127 +17930,20595,30405,40873 +12812,20596,30404,40988 +16588,20597,30403,40219 +14518,20598,30402,40720 +13361,20599,30401,40410 +12590,20600,30400,40236 +12826,20601,30399,40092 +12683,20602,30398,40976 +17683,20603,30397,40611 +12210,20604,30396,40957 +17536,20605,30395,40712 +13075,20606,30394,40527 +16582,20607,30393,40891 +12386,20608,30392,40303 +14632,20609,30391,40895 +15303,20610,30390,40807 +17496,20611,30389,40483 +18186,20612,30388,40559 +15525,20613,30387,40212 +12639,20614,30386,40637 +11053,20615,30385,40501 +11533,20616,30384,40392 +18017,20617,30383,40377 +13097,20618,30382,40325 +11733,20619,30381,40943 +10347,20620,30380,40978 +13676,20621,30379,40115 +15639,20622,30378,40488 +16699,20623,30377,40070 +11443,20624,30376,40495 +15346,20625,30375,40436 +10631,20626,30374,40785 +11617,20627,30373,40899 +12389,20628,30372,40112 +12118,20629,30371,40771 +10863,20630,30370,40315 +17094,20631,30369,40993 +12269,20632,30368,40243 +12187,20633,30367,40717 +15091,20634,30366,40509 +17905,20635,30365,40772 +14553,20636,30364,40144 +17152,20637,30363,40664 +16424,20638,30362,40293 +14375,20639,30361,40146 +13756,20640,30360,40287 +15542,20641,30359,40858 +11997,20642,30358,40384 +10078,20643,30357,40133 +11874,20644,30356,40971 +10695,20645,30355,40909 +13605,20646,30354,40576 +17568,20647,30353,40351 +17143,20648,30352,40537 +12209,20649,30351,40614 +15601,20650,30350,40252 +17046,20651,30349,40781 +17582,20652,30348,40481 +14245,20653,30347,40617 +13839,20654,30346,40995 +12907,20655,30345,40972 +10832,20656,30344,40899 +15129,20657,30343,40934 +12293,20658,30342,40448 +17365,20659,30341,40542 +15907,20660,30340,40899 +13472,20661,30339,40127 +11404,20662,30338,40375 +14221,20663,30337,40150 +11082,20664,30336,40926 +14186,20665,30335,40559 +15835,20666,30334,40870 +11174,20667,30333,40807 +14179,20668,30332,40970 +15861,20669,30331,40915 +10201,20670,30330,40365 +12734,20671,30329,40704 +18082,20672,30328,40217 +13146,20673,30327,40980 +10413,20674,30326,40438 +14992,20675,30325,40194 +13391,20676,30324,40534 +16849,20677,30323,40635 +16550,20678,30322,40492 +11116,20679,30321,40935 +17354,20680,30320,40045 +10279,20681,30319,40692 +14235,20682,30318,40239 +11565,20683,30317,40037 +12244,20684,30316,40983 +13673,20685,30315,40451 +17567,20686,30314,40239 +10312,20687,30313,40873 +15965,20688,30312,40843 +12334,20689,30311,40633 +11599,20690,30310,40668 +16460,20691,30309,40300 +12165,20692,30308,40510 +12857,20693,30307,40951 +17095,20694,30306,40764 +11167,20695,30305,40553 +11444,20696,30304,40764 +13692,20697,30303,40744 +14042,20698,30302,40116 +16931,20699,30301,40708 +17480,20700,30300,40795 +15642,20701,30299,40971 +16440,20702,30298,40093 +14368,20703,30297,40652 +14764,20704,30296,40926 +11470,20705,30295,40839 +17172,20706,30294,40704 +14651,20707,30293,40113 +14224,20708,30292,40000 +15790,20709,30291,40861 +11200,20710,30290,40978 +14805,20711,30289,40510 +11281,20712,30288,40813 +14684,20713,30287,40353 +12861,20714,30286,40464 +11531,20715,30285,40951 +16147,20716,30284,40420 +16313,20717,30283,40977 +12855,20718,30282,40012 +10234,20719,30281,40596 +15405,20720,30280,40294 +11665,20721,30279,40708 +13382,20722,30278,40246 +17269,20723,30277,40460 +15271,20724,30276,40240 +12953,20725,30275,40651 +16601,20726,30274,40258 +17445,20727,30273,40554 +15193,20728,30272,40348 +15139,20729,30271,40138 +12193,20730,30270,40192 +10978,20731,30269,40251 +13206,20732,30268,40172 +10072,20733,30267,40135 +14726,20734,30266,40702 +17869,20735,30265,40230 +16337,20736,30264,40007 +15546,20737,30263,40738 +14664,20738,30262,40760 +13335,20739,30261,40114 +11627,20740,30260,40465 +13531,20741,30259,40867 +10783,20742,30258,40169 +11702,20743,30257,40482 +10356,20744,30256,40007 +17504,20745,30255,40135 +12311,20746,30254,40599 +15906,20747,30253,40516 +10574,20748,30252,40784 +11048,20749,30251,40747 +13757,20750,30250,40090 +16989,20751,30249,40813 +12317,20752,30248,40797 +12548,20753,30247,40390 +16004,20754,30246,40260 +15411,20755,30245,40262 +16345,20756,30244,40488 +15969,20757,30243,40883 +14129,20758,30242,40362 +10366,20759,30241,40858 +15218,20760,30240,40368 +14315,20761,30239,40476 +17238,20762,30238,40585 +16956,20763,30237,40421 +14405,20764,30236,40307 +10420,20765,30235,40616 +12230,20766,30234,40713 +17511,20767,30233,40654 +18113,20768,30232,40995 +12359,20769,30231,40797 +13626,20770,30230,40693 +11994,20771,30229,40109 +16127,20772,30228,40737 +12699,20773,30227,40758 +12915,20774,30226,40425 +14822,20775,30225,40725 +14185,20776,30224,40620 +10317,20777,30223,40773 +13310,20778,30222,40922 +14209,20779,30221,40002 +14548,20780,30220,40987 +17155,20781,30219,40897 +12827,20782,30218,40705 +16810,20783,30217,40788 +15475,20784,30216,40166 +14614,20785,30215,40809 +16022,20786,30214,40551 +17593,20787,30213,40986 +10425,20788,30212,40584 +12177,20789,30211,40839 +10979,20790,30210,40794 +15024,20791,30209,40471 +15984,20792,30208,40855 +16731,20793,30207,40750 +13842,20794,30206,40470 +16617,20795,30205,40872 +16221,20796,30204,40498 +13981,20797,30203,40724 +13357,20798,30202,40221 +12072,20799,30201,40668 +10582,20800,30200,40874 +10561,20801,30199,40192 +16693,20802,30198,40503 +12052,20803,30197,40594 +13675,20804,30196,40729 +15820,20805,30195,40556 +15922,20806,30194,40162 +13047,20807,30193,40741 +12613,20808,30192,40525 +13228,20809,30191,40931 +12553,20810,30190,40978 +11897,20811,30189,40403 +12401,20812,30188,40045 +13186,20813,30187,40268 +12531,20814,30186,40097 +11224,20815,30185,40569 +16572,20816,30184,40802 +13890,20817,30183,40093 +10595,20818,30182,40056 +15754,20819,30181,40880 +13643,20820,30180,40927 +10204,20821,30179,40928 +17825,20822,30178,40836 +17573,20823,30177,40443 +14762,20824,30176,40810 +13157,20825,30175,40928 +15663,20826,30174,40361 +12576,20827,30173,40702 +11334,20828,30172,40472 +12756,20829,30171,40692 +14869,20830,30170,40906 +16425,20831,30169,40248 +11006,20832,30168,40604 +17193,20833,30167,40715 +12642,20834,30166,40782 +10401,20835,30165,40329 +12033,20836,30164,40536 +12852,20837,30163,40638 +15200,20838,30162,40412 +10689,20839,30161,40156 +17624,20840,30160,40441 +16135,20841,30159,40730 +12296,20842,30158,40624 +12806,20843,30157,40318 +15774,20844,30156,40935 +13287,20845,30155,40322 +15735,20846,30154,40458 +12987,20847,30153,40612 +12082,20848,30152,40914 +11636,20849,30151,40976 +16329,20850,30150,40222 +14389,20851,30149,40425 +13378,20852,30148,40933 +12741,20853,30147,40884 +14493,20854,30146,40582 +16671,20855,30145,40397 +10928,20856,30144,40975 +14198,20857,30143,40347 +14331,20858,30142,40609 +14122,20859,30141,40974 +13177,20860,30140,40941 +15175,20861,30139,40217 +11802,20862,30138,40784 +16894,20863,30137,40866 +13048,20864,30136,40393 +13055,20865,30135,40247 +14302,20866,30134,40699 +17638,20867,30133,40466 +16126,20868,30132,40061 +17989,20869,30131,40301 +14109,20870,30130,40127 +12153,20871,30129,40113 +16614,20872,30128,40280 +12630,20873,30127,40000 +15952,20874,30126,40690 +16884,20875,30125,40627 +16819,20876,30124,40895 +11312,20877,30123,40445 +11813,20878,30122,40661 +14660,20879,30121,40446 +10545,20880,30120,40708 +13340,20881,30119,40491 +10708,20882,30118,40225 +10252,20883,30117,40379 +12932,20884,30116,40003 +10070,20885,30115,40389 +13624,20886,30114,40170 +12382,20887,30113,40093 +14386,20888,30112,40823 +16393,20889,30111,40421 +13013,20890,30110,40935 +15436,20891,30109,40312 +16098,20892,30108,40065 +15648,20893,30107,40338 +13358,20894,30106,40039 +16666,20895,30105,40483 +10460,20896,30104,40641 +11990,20897,30103,40786 +13030,20898,30102,40556 +14472,20899,30101,40350 +15564,20900,30100,40274 +12444,20901,30099,40536 +17144,20902,30098,40323 +14783,20903,30097,40828 +15032,20904,30096,40530 +15760,20905,30095,40694 +14380,20906,30094,40266 +17490,20907,30093,40962 +11398,20908,30092,40055 +14534,20909,30091,40276 +11290,20910,30090,40137 +17851,20911,30089,40117 +13329,20912,30088,40738 +11699,20913,30087,40343 +17790,20914,30086,40745 +12343,20915,30085,40336 +11124,20916,30084,40695 +15431,20917,30083,40186 +14213,20918,30082,40207 +13185,20919,30081,40843 +10287,20920,30080,40267 +12811,20921,30079,40512 +12870,20922,30078,40105 +18031,20923,30077,40364 +15107,20924,30076,40588 +16568,20925,30075,40102 +13315,20926,30074,40303 +17830,20927,30073,40633 +10467,20928,30072,40204 +14803,20929,30071,40046 +16653,20930,30070,40139 +14504,20931,30069,40524 +15018,20932,30068,40542 +16918,20933,30067,40903 +12164,20934,30066,40801 +15731,20935,30065,40221 +16247,20936,30064,40775 +13844,20937,30063,40909 +17945,20938,30062,40887 +12751,20939,30061,40739 +10854,20940,30060,40965 +11576,20941,30059,40182 +10441,20942,30058,40557 +14942,20943,30057,40443 +17083,20944,30056,40859 +14401,20945,30055,40714 +12074,20946,30054,40822 +14699,20947,30053,40830 +17878,20948,30052,40467 +12997,20949,30051,40931 +15030,20950,30050,40117 +17068,20951,30049,40783 +10231,20952,30048,40114 +10449,20953,30047,40642 +10478,20954,30046,40936 +13535,20955,30045,40754 +14519,20956,30044,40422 +11044,20957,30043,40383 +11246,20958,30042,40312 +14866,20959,30041,40838 +10810,20960,30040,40403 +16401,20961,30039,40713 +15689,20962,30038,40614 +11876,20963,30037,40299 +16874,20964,30036,40937 +16402,20965,30035,40890 +17275,20966,30034,40407 +11613,20967,30033,40701 +13421,20968,30032,40607 +17941,20969,30031,40468 +13812,20970,30030,40641 +11515,20971,30029,40214 +18062,20972,30028,40755 +13504,20973,30027,40589 +13094,20974,30026,40355 +14693,20975,30025,40815 +16161,20976,30024,40215 +13783,20977,30023,40638 +17634,20978,30022,40104 +11545,20979,30021,40423 +11152,20980,30020,40373 +12984,20981,30019,40840 +14275,20982,30018,40452 +17972,20983,30017,40873 +15550,20984,30016,40603 +18172,20985,30015,40413 +16453,20986,30014,40853 +14915,20987,30013,40835 +12387,20988,30012,40960 +14440,20989,30011,40660 +10364,20990,30010,40659 +14140,20991,30009,40625 +15143,20992,30008,40108 +12706,20993,30007,40165 +16873,20994,30006,40591 +13512,20995,30005,40293 +14895,20996,30004,40931 +16574,20997,30003,40313 +17890,20998,30002,40455 +16587,20999,30001,40450 +14542,21000,30000,40322 +17335,21001,31000,40123 +12246,21002,30999,40832 +17440,21003,30998,40340 +16733,21004,30997,40432 +17964,21005,30996,40457 +11065,21006,30995,40282 +17718,21007,30994,40385 +12794,21008,30993,40318 +17741,21009,30992,40810 +12895,21010,30991,40416 +15301,21011,30990,40338 +13127,21012,30989,40687 +13874,21013,30988,40361 +10635,21014,30987,40356 +12946,21015,30986,40346 +10345,21016,30985,40392 +12710,21017,30984,40784 +14459,21018,30983,40711 +11018,21019,30982,40701 +12546,21020,30981,40184 +10318,21021,30980,40662 +14381,21022,30979,40622 +13653,21023,30978,40002 +17673,21024,30977,40337 +15583,21025,30976,40257 +15839,21026,30975,40493 +16772,21027,30974,40521 +15519,21028,30973,40173 +10385,21029,30972,40092 +18125,21030,30971,40584 +11638,21031,30970,40854 +14874,21032,30969,40305 +15750,21033,30968,40018 +14617,21034,30967,40260 +14537,21035,30966,40291 +11789,21036,30965,40564 +18078,21037,30964,40432 +10638,21038,30963,40290 +12752,21039,30962,40049 +10989,21040,30961,40801 +17710,21041,30960,40542 +17974,21042,30959,40644 +16795,21043,30958,40311 +12591,21044,30957,40664 +10067,21045,30956,40998 +14088,21046,30955,40462 +13217,21047,30954,40473 +10427,21048,30953,40560 +12378,21049,30952,40459 +10477,21050,30951,40125 +13771,21051,30950,40882 +12676,21052,30949,40752 +16570,21053,30948,40971 +12473,21054,30947,40803 +17608,21055,30946,40065 +11351,21056,30945,40753 +10887,21057,30944,40917 +10105,21058,30943,40608 +15866,21059,30942,40759 +13978,21060,30941,40413 +12628,21061,30940,40587 +15330,21062,30939,40170 +12198,21063,30938,40607 +14413,21064,30937,40491 +14925,21065,30936,40657 +16723,21066,30935,40062 +12679,21067,30934,40205 +13339,21068,30933,40408 +15970,21069,30932,40563 +10391,21070,30931,40732 +10587,21071,30930,40751 +13713,21072,30929,40374 +12527,21073,30928,40754 +16146,21074,30927,40782 +13265,21075,30926,40758 +14488,21076,30925,40040 +11038,21077,30924,40751 +10009,21078,30923,40416 +15329,21079,30922,40597 +15007,21080,30921,40771 +17799,21081,30920,40254 +11418,21082,30919,40529 +10970,21083,30918,40768 +12674,21084,30917,40983 +16239,21085,30916,40900 +15582,21086,30915,40073 +15366,21087,30914,40294 +18128,21088,30913,40436 +17961,21089,30912,40297 +12539,21090,30911,40825 +11642,21091,30910,40112 +14101,21092,30909,40461 +14153,21093,30908,40791 +16672,21094,30907,40957 +10630,21095,30906,40911 +15650,21096,30905,40743 +10714,21097,30904,40192 +15046,21098,30903,40812 +13936,21099,30902,40825 +11908,21100,30901,40058 +11333,21101,30900,40683 +13758,21102,30899,40598 +13207,21103,30898,40939 +12084,21104,30897,40758 +11310,21105,30896,40990 +10968,21106,30895,40285 +14568,21107,30894,40560 +12947,21108,30893,40031 +10736,21109,30892,40821 +11468,21110,30891,40660 +13538,21111,30890,40672 +15232,21112,30889,40754 +11179,21113,30888,40546 +13071,21114,30887,40322 +11501,21115,30886,40537 +13886,21116,30885,40469 +14665,21117,30884,40866 +17090,21118,30883,40736 +11161,21119,30882,40578 +11452,21120,30881,40266 +13988,21121,30880,40654 +12367,21122,30879,40854 +16944,21123,30878,40546 +14845,21124,30877,40580 +10614,21125,30876,40838 +13539,21126,30875,40641 +13658,21127,30874,40109 +16492,21128,30873,40383 +11145,21129,30872,40975 +17513,21130,30871,40544 +11759,21131,30870,40767 +15520,21132,30869,40868 +14998,21133,30868,40126 +13138,21134,30867,40306 +16546,21135,30866,40398 +14216,21136,30865,40170 +16482,21137,30864,40699 +16277,21138,30863,40937 +13215,21139,30862,40235 +12445,21140,30861,40246 +11606,21141,30860,40575 +16705,21142,30859,40185 +14884,21143,30858,40169 +10670,21144,30857,40395 +16489,21145,30856,40573 +13649,21146,30855,40753 +11867,21147,30854,40348 +16539,21148,30853,40834 +12011,21149,30852,40732 +13007,21150,30851,40896 +11957,21151,30850,40795 +11777,21152,30849,40515 +10995,21153,30848,40322 +12739,21154,30847,40552 +15401,21155,30846,40343 +18074,21156,30845,40265 +14810,21157,30844,40138 +16862,21158,30843,40383 +15698,21159,30842,40113 +16278,21160,30841,40034 +15231,21161,30840,40615 +17816,21162,30839,40377 +10151,21163,30838,40639 +17803,21164,30837,40308 +18147,21165,30836,40054 +10330,21166,30835,40166 +17181,21167,30834,40286 +11889,21168,30833,40961 +16683,21169,30832,40663 +13619,21170,30831,40386 +17195,21171,30830,40257 +17977,21172,30829,40859 +15840,21173,30828,40372 +14897,21174,30827,40967 +11330,21175,30826,40736 +15382,21176,30825,40936 +14035,21177,30824,40656 +17122,21178,30823,40244 +14919,21179,30822,40793 +15066,21180,30821,40870 +17727,21181,30820,40121 +12769,21182,30819,40257 +14920,21183,30818,40907 +16007,21184,30817,40703 +15554,21185,30816,40719 +12986,21186,30815,40856 +11106,21187,30814,40045 +10957,21188,30813,40174 +12158,21189,30812,40538 +13435,21190,30811,40101 +12618,21191,30810,40107 +15490,21192,30809,40384 +17689,21193,30808,40998 +15727,21194,30807,40654 +15253,21195,30806,40833 +17282,21196,30805,40508 +14037,21197,30804,40346 +13954,21198,30803,40180 +17968,21199,30802,40037 +14700,21200,30801,40395 +11780,21201,30800,40220 +13128,21202,30799,40240 +12563,21203,30798,40160 +14110,21204,30797,40760 +13212,21205,30796,40710 +16076,21206,30795,40070 +10456,21207,30794,40933 +14067,21208,30793,40239 +12917,21209,30792,40676 +11346,21210,30791,40748 +12823,21211,30790,40329 +13760,21212,30789,40474 +17750,21213,30788,40883 +10369,21214,30787,40907 +12026,21215,30786,40121 +16016,21216,30785,40015 +17983,21217,30784,40491 +14532,21218,30783,40389 +14621,21219,30782,40790 +11520,21220,30781,40018 +17408,21221,30780,40446 +16455,21222,30779,40629 +13458,21223,30778,40147 +17508,21224,30777,40857 +17173,21225,30776,40286 +10651,21226,30775,40697 +11723,21227,30774,40173 +13502,21228,30773,40811 +17957,21229,30772,40986 +17003,21230,30771,40443 +17163,21231,30770,40218 +14552,21232,30769,40464 +16299,21233,30768,40401 +10245,21234,30767,40963 +12842,21235,30766,40330 +13742,21236,30765,40787 +13375,21237,30764,40924 +13943,21238,30763,40550 +13061,21239,30762,40825 +16597,21240,30761,40274 +16070,21241,30760,40168 +12221,21242,30759,40250 +11257,21243,30758,40082 +12876,21244,30757,40252 +10955,21245,30756,40873 +17251,21246,30755,40591 +12673,21247,30754,40749 +17091,21248,30753,40681 +10438,21249,30752,40344 +15784,21250,30751,40871 +14341,21251,30750,40433 +14116,21252,30749,40078 +14102,21253,30748,40766 +12588,21254,30747,40774 +13462,21255,30746,40506 +17104,21256,30745,40846 +15069,21257,30744,40350 +16854,21258,30743,40578 +15647,21259,30742,40124 +11151,21260,30741,40321 +10277,21261,30740,40598 +17537,21262,30739,40763 +13525,21263,30738,40661 +15008,21264,30737,40376 +12594,21265,30736,40678 +13885,21266,30735,40907 +12371,21267,30734,40822 +13294,21268,30733,40462 +16406,21269,30732,40102 +15111,21270,30731,40271 +11047,21271,30730,40426 +11562,21272,30729,40744 +13948,21273,30728,40572 +16156,21274,30727,40997 +13417,21275,30726,40926 +13102,21276,30725,40694 +12627,21277,30724,40892 +16512,21278,30723,40427 +14013,21279,30722,40551 +16253,21280,30721,40927 +11604,21281,30720,40125 +17531,21282,30719,40142 +15891,21283,30718,40054 +15929,21284,30717,40512 +17993,21285,30716,40138 +13394,21286,30715,40647 +12959,21287,30714,40278 +10823,21288,30713,40557 +10800,21289,30712,40590 +16717,21290,30711,40287 +17748,21291,30710,40316 +13091,21292,30709,40286 +17156,21293,30708,40894 +11927,21294,30707,40892 +10502,21295,30706,40502 +11626,21296,30705,40307 +16252,21297,30704,40043 +15775,21298,30703,40441 +14240,21299,30702,40084 +13745,21300,30701,40696 +12537,21301,30700,40613 +11442,21302,30699,40802 +13568,21303,30698,40530 +10392,21304,30697,40449 +13861,21305,30696,40504 +17007,21306,30695,40124 +17417,21307,30694,40347 +15205,21308,30693,40190 +14134,21309,30692,40106 +14701,21310,30691,40897 +11089,21311,30690,40823 +12874,21312,30689,40120 +14061,21313,30688,40010 +11616,21314,30687,40506 +17206,21315,30686,40557 +11373,21316,30685,40402 +13604,21317,30684,40810 +12024,21318,30683,40850 +17489,21319,30682,40905 +15589,21320,30681,40776 +10190,21321,30680,40606 +13461,21322,30679,40281 +14210,21323,30678,40287 +10393,21324,30677,40634 +13651,21325,30676,40091 +13611,21326,30675,40966 +13367,21327,30674,40373 +12981,21328,30673,40362 +16381,21329,30672,40464 +10222,21330,30671,40988 +14464,21331,30670,40660 +11220,21332,30669,40993 +12566,21333,30668,40951 +14286,21334,30667,40941 +12109,21335,30666,40328 +11512,21336,30665,40501 +14590,21337,30664,40532 +15576,21338,30663,40065 +10083,21339,30662,40755 +14596,21340,30661,40438 +15625,21341,30660,40348 +15903,21342,30659,40440 +10869,21343,30658,40157 +10802,21344,30657,40244 +11770,21345,30656,40119 +16878,21346,30655,40171 +15684,21347,30654,40646 +11090,21348,30653,40586 +11958,21349,30652,40295 +12159,21350,30651,40678 +13359,21351,30650,40362 +13402,21352,30649,40830 +15441,21353,30648,40838 +13299,21354,30647,40641 +13766,21355,30646,40476 +11910,21356,30645,40014 +14749,21357,30644,40827 +17383,21358,30643,40562 +15571,21359,30642,40026 +13889,21360,30641,40147 +14768,21361,30640,40141 +16469,21362,30639,40035 +13523,21363,30638,40271 +17170,21364,30637,40745 +11633,21365,30636,40334 +10710,21366,30635,40146 +16955,21367,30634,40003 +10998,21368,30633,40341 +11771,21369,30632,40624 +16289,21370,30631,40995 +13235,21371,30630,40173 +16896,21372,30629,40933 +11239,21373,30628,40363 +15968,21374,30627,40376 +12620,21375,30626,40705 +13672,21376,30625,40227 +15533,21377,30624,40637 +11005,21378,30623,40825 +17285,21379,30622,40658 +17744,21380,30621,40122 +16592,21381,30620,40823 +15757,21382,30619,40188 +13824,21383,30618,40209 +13105,21384,30617,40879 +16390,21385,30616,40359 +17175,21386,30615,40973 +14007,21387,30614,40082 +17943,21388,30613,40208 +12785,21389,30612,40112 +15988,21390,30611,40662 +17620,21391,30610,40406 +14371,21392,30609,40912 +15719,21393,30608,40898 +16113,21394,30607,40760 +13308,21395,30606,40507 +13585,21396,30605,40496 +12708,21397,30604,40072 +13496,21398,30603,40992 +13582,21399,30602,40589 +11552,21400,30601,40295 +17743,21401,30600,40749 +10660,21402,30599,40067 +14260,21403,30598,40313 +16505,21404,30597,40491 +14829,21405,30596,40446 +17258,21406,30595,40161 +11854,21407,30594,40524 +15222,21408,30593,40941 +15162,21409,30592,40138 +17088,21410,30591,40901 +15152,21411,30590,40007 +16889,21412,30589,40761 +13985,21413,30588,40716 +16388,21414,30587,40522 +11353,21415,30586,40438 +15355,21416,30585,40059 +12757,21417,30584,40983 +13881,21418,30583,40807 +14607,21419,30582,40004 +17603,21420,30581,40466 +16779,21421,30580,40712 +14074,21422,30579,40540 +11304,21423,30578,40631 +11823,21424,30577,40648 +11758,21425,30576,40504 +12282,21426,30575,40802 +12844,21427,30574,40274 +16517,21428,30573,40119 +14449,21429,30572,40047 +11781,21430,30571,40607 +11567,21431,30570,40325 +12438,21432,30569,40013 +12681,21433,30568,40441 +13569,21434,30567,40087 +14383,21435,30566,40207 +14796,21436,30565,40032 +12992,21437,30564,40996 +16053,21438,30563,40595 +11590,21439,30562,40900 +14512,21440,30561,40947 +10065,21441,30560,40592 +13219,21442,30559,40269 +14787,21443,30558,40495 +15148,21444,30557,40823 +16291,21445,30556,40773 +12941,21446,30555,40042 +16936,21447,30554,40513 +12397,21448,30553,40594 +11979,21449,30552,40000 +14156,21450,30551,40670 +18108,21451,30550,40807 +17685,21452,30549,40571 +18181,21453,30548,40981 +17250,21454,30547,40251 +17443,21455,30546,40007 +16839,21456,30545,40994 +15541,21457,30544,40590 +10284,21458,30543,40010 +11830,21459,30542,40011 +12236,21460,30541,40956 +10969,21461,30540,40146 +13801,21462,30539,40071 +11850,21463,30538,40452 +11197,21464,30537,40845 +17635,21465,30536,40990 +13941,21466,30535,40872 +15020,21467,30534,40751 +17386,21468,30533,40461 +12351,21469,30532,40039 +14609,21470,30531,40550 +17979,21471,30530,40579 +13761,21472,30529,40371 +15439,21473,30528,40565 +12754,21474,30527,40387 +15302,21475,30526,40985 +17523,21476,30525,40092 +12420,21477,30524,40762 +15572,21478,30523,40346 +16338,21479,30522,40394 +13106,21480,30521,40412 +13083,21481,30520,40752 +16404,21482,30519,40250 +16019,21483,30518,40436 +12515,21484,30517,40106 +10131,21485,30516,40014 +15895,21486,30515,40283 +13493,21487,30514,40829 +13541,21488,30513,40872 +12561,21489,30512,40851 +16168,21490,30511,40206 +15335,21491,30510,40421 +13302,21492,30509,40065 +16131,21493,30508,40673 +14445,21494,30507,40320 +14489,21495,30506,40336 +15025,21496,30505,40161 +11187,21497,30504,40067 +10159,21498,30503,40399 +11277,21499,30502,40049 +15398,21500,30501,40384 +14774,21501,30500,40062 +12478,21502,30499,40299 +15747,21503,30498,40320 +12271,21504,30497,40535 +10920,21505,30496,40995 +10082,21506,30495,40814 +13176,21507,30494,40477 +11071,21508,30493,40328 +10650,21509,30492,40987 +13424,21510,30491,40116 +16657,21511,30490,40234 +14348,21512,30489,40433 +16503,21513,30488,40489 +15185,21514,30487,40059 +17549,21515,30486,40419 +12169,21516,30485,40353 +10428,21517,30484,40003 +14009,21518,30483,40580 +12462,21519,30482,40865 +18066,21520,30481,40266 +14252,21521,30480,40681 +14458,21522,30479,40239 +12229,21523,30478,40706 +16843,21524,30477,40237 +13704,21525,30476,40964 +18042,21526,30475,40018 +18075,21527,30474,40387 +17459,21528,30473,40792 +17861,21529,30472,40144 +12440,21530,30471,40331 +17468,21531,30470,40302 +10150,21532,30469,40819 +12398,21533,30468,40546 +14694,21534,30467,40176 +16541,21535,30466,40075 +11196,21536,30465,40597 +16834,21537,30464,40865 +16600,21538,30463,40182 +13892,21539,30462,40963 +13578,21540,30461,40339 +14076,21541,30460,40008 +14785,21542,30459,40255 +15621,21543,30458,40447 +17245,21544,30457,40122 +12112,21545,30456,40770 +16616,21546,30455,40657 +17427,21547,30454,40749 +10161,21548,30453,40672 +16137,21549,30452,40629 +13650,21550,30451,40366 +17908,21551,30450,40635 +13715,21552,30449,40270 +15850,21553,30448,40711 +14050,21554,30447,40686 +14960,21555,30446,40225 +13344,21556,30445,40824 +11492,21557,30444,40507 +15732,21558,30443,40694 +11190,21559,30442,40411 +15780,21560,30441,40690 +17800,21561,30440,40005 +13271,21562,30439,40755 +14748,21563,30438,40565 +11959,21564,30437,40324 +10841,21565,30436,40681 +18144,21566,30435,40271 +10778,21567,30434,40004 +14223,21568,30433,40711 +16736,21569,30432,40911 +13982,21570,30431,40539 +13986,21571,30430,40083 +11057,21572,30429,40206 +14738,21573,30428,40218 +16827,21574,30427,40427 +11314,21575,30426,40123 +13489,21576,30425,40077 +13193,21577,30424,40195 +12835,21578,30423,40309 +11536,21579,30422,40265 +16296,21580,30421,40981 +14451,21581,30420,40122 +16015,21582,30419,40345 +14407,21583,30418,40475 +16738,21584,30417,40461 +17590,21585,30416,40805 +10019,21586,30415,40129 +14967,21587,30414,40851 +17471,21588,30413,40122 +14169,21589,30412,40791 +16327,21590,30411,40082 +17982,21591,30410,40706 +13260,21592,30409,40735 +10084,21593,30408,40226 +11074,21594,30407,40777 +14529,21595,30406,40757 +12350,21596,30405,40645 +17113,21597,30404,40836 +15619,21598,30403,40727 +12211,21599,30402,40956 +14842,21600,30401,40140 +12224,21601,30400,40421 +13139,21602,30399,40845 +16504,21603,30398,40341 +15456,21604,30397,40175 +17284,21605,30396,40847 +14658,21606,30395,40504 +14754,21607,30394,40269 +16857,21608,30393,40228 +15407,21609,30392,40989 +15457,21610,30391,40213 +10091,21611,30390,40654 +11659,21612,30389,40913 +17973,21613,30388,40244 +14436,21614,30387,40053 +17951,21615,30386,40937 +16410,21616,30385,40712 +15044,21617,30384,40780 +16408,21618,30383,40522 +11776,21619,30382,40806 +15668,21620,30381,40427 +13416,21621,30380,40654 +15595,21622,30379,40032 +18171,21623,30378,40239 +13831,21624,30377,40568 +13120,21625,30376,40215 +16148,21626,30375,40780 +10367,21627,30374,40712 +16898,21628,30373,40613 +15693,21629,30372,40284 +14708,21630,30371,40200 +16058,21631,30370,40657 +11847,21632,30369,40940 +17506,21633,30368,40708 +14500,21634,30367,40788 +16712,21635,30366,40345 +13851,21636,30365,40936 +14311,21637,30364,40777 +16475,21638,30363,40982 +16293,21639,30362,40804 +13529,21640,30361,40302 +10735,21641,30360,40198 +14995,21642,30359,40043 +11234,21643,30358,40310 +12623,21644,30357,40469 +13933,21645,30356,40465 +17132,21646,30355,40771 +16818,21647,30354,40678 +17413,21648,30353,40437 +16859,21649,30352,40978 +17862,21650,30351,40808 +16885,21651,30350,40843 +12451,21652,30349,40299 +10959,21653,30348,40906 +13911,21654,30347,40431 +13910,21655,30346,40506 +10048,21656,30345,40923 +15708,21657,30344,40277 +10063,21658,30343,40901 +16925,21659,30342,40893 +10687,21660,30341,40316 +12793,21661,30340,40600 +15758,21662,30339,40930 +12489,21663,30338,40836 +10198,21664,30337,40607 +11755,21665,30336,40194 +17262,21666,30335,40809 +10972,21667,30334,40200 +17909,21668,30333,40112 +12303,21669,30332,40198 +17775,21670,30331,40309 +13033,21671,30330,40818 +11730,21672,30329,40323 +11884,21673,30328,40807 +14756,21674,30327,40406 +13409,21675,30326,40912 +14691,21676,30325,40991 +11915,21677,30324,40827 +15746,21678,30323,40513 +11408,21679,30322,40384 +11440,21680,30321,40886 +17958,21681,30320,40113 +11285,21682,30319,40643 +10659,21683,30318,40259 +12748,21684,30317,40387 +17574,21685,30316,40794 +11690,21686,30315,40287 +15677,21687,30314,40947 +12686,21688,30313,40698 +17466,21689,30312,40362 +13481,21690,30311,40058 +16069,21691,30310,40676 +13781,21692,30309,40474 +13356,21693,30308,40215 +11488,21694,30307,40189 +14527,21695,30306,40718 +17791,21696,30305,40526 +10307,21697,30304,40657 +11289,21698,30303,40739 +17123,21699,30302,40921 +17435,21700,30301,40767 +14840,21701,30300,40304 +17150,21702,30299,40126 +10303,21703,30298,40199 +15953,21704,30297,40427 +17871,21705,30296,40001 +14742,21706,30295,40093 +17433,21707,30294,40109 +14530,21708,30293,40001 +11389,21709,30292,40297 +14830,21710,30291,40361 +11563,21711,30290,40785 +12610,21712,30289,40210 +10819,21713,30288,40311 +10280,21714,30287,40307 +13410,21715,30286,40301 +13213,21716,30285,40161 +16092,21717,30284,40910 +15531,21718,30283,40072 +18157,21719,30282,40626 +15022,21720,30281,40347 +10473,21721,30280,40016 +12508,21722,30279,40956 +15680,21723,30278,40597 +15548,21724,30277,40136 +10088,21725,30276,40939 +10140,21726,30275,40714 +15612,21727,30274,40782 +11586,21728,30273,40439 +13546,21729,30272,40080 +12781,21730,30271,40297 +14055,21731,30270,40243 +11456,21732,30269,40189 +17228,21733,30268,40590 +12733,21734,30267,40064 +12136,21735,30266,40009 +16846,21736,30265,40830 +16335,21737,30264,40563 +13953,21738,30263,40890 +14266,21739,30262,40867 +15246,21740,30261,40402 +16328,21741,30260,40395 +12315,21742,30259,40978 +12646,21743,30258,40104 +13251,21744,30257,40633 +17728,21745,30256,40486 +14126,21746,30255,40193 +12944,21747,30254,40897 +15599,21748,30253,40327 +13828,21749,30252,40726 +15930,21750,30251,40682 +16071,21751,30250,40175 +17231,21752,30249,40424 +15666,21753,30248,40710 +11376,21754,30247,40292 +17358,21755,30246,40697 +16646,21756,30245,40580 +17214,21757,30244,40035 +14876,21758,30243,40327 +11265,21759,30242,40436 +15281,21760,30241,40540 +13594,21761,30240,40830 +12191,21762,30239,40909 +15893,21763,30238,40920 +16478,21764,30237,40050 +12448,21765,30236,40608 +16806,21766,30235,40514 +13330,21767,30234,40593 +13480,21768,30233,40357 +14896,21769,30232,40317 +11772,21770,30231,40125 +17696,21771,30230,40387 +11952,21772,30229,40026 +12841,21773,30228,40729 +10812,21774,30227,40820 +16369,21775,30226,40245 +15137,21776,30225,40291 +15097,21777,30224,40909 +16046,21778,30223,40187 +15258,21779,30222,40295 +14100,21780,30221,40380 +12486,21781,30220,40026 +10880,21782,30219,40309 +14032,21783,30218,40243 +13392,21784,30217,40320 +12672,21785,30216,40796 +13816,21786,30215,40929 +10620,21787,30214,40646 +10052,21788,30213,40784 +10949,21789,30212,40272 +17836,21790,30211,40366 +10117,21791,30210,40488 +16606,21792,30209,40948 +17297,21793,30208,40693 +16691,21794,30207,40430 +18132,21795,30206,40407 +10011,21796,30205,40775 +10089,21797,30204,40334 +15918,21798,30203,40902 +16373,21799,30202,40888 +10302,21800,30201,40046 +11370,21801,30200,40887 +17237,21802,30199,40412 +15881,21803,30198,40222 +10058,21804,30197,40425 +11412,21805,30196,40147 +13819,21806,30195,40663 +11546,21807,30194,40776 +11352,21808,30193,40985 +10890,21809,30192,40644 +13336,21810,30191,40394 +12906,21811,30190,40263 +12335,21812,30189,40080 +15900,21813,30188,40322 +12913,21814,30187,40873 +14873,21815,30186,40260 +13776,21816,30185,40459 +13119,21817,30184,40778 +12571,21818,30183,40578 +16648,21819,30182,40030 +16250,21820,30181,40498 +12184,21821,30180,40472 +15080,21822,30179,40901 +13178,21823,30178,40402 +12544,21824,30177,40678 +18143,21825,30176,40108 +13267,21826,30175,40028 +15385,21827,30174,40632 +13226,21828,30173,40522 +14217,21829,30172,40617 +10926,21830,30171,40979 +16604,21831,30170,40533 +16361,21832,30169,40155 +15463,21833,30168,40129 +10753,21834,30167,40736 +11925,21835,30166,40067 +12327,21836,30165,40591 +17530,21837,30164,40858 +11532,21838,30163,40212 +14237,21839,30162,40529 +14971,21840,30161,40433 +11689,21841,30160,40763 +12467,21842,30159,40991 +10618,21843,30158,40961 +16534,21844,30157,40651 +17390,21845,30156,40351 +16488,21846,30155,40367 +14798,21847,30154,40180 +11198,21848,30153,40273 +12983,21849,30152,40792 +16100,21850,30151,40449 +10860,21851,30150,40832 +16906,21852,30149,40300 +12649,21853,30148,40036 +11369,21854,30147,40806 +11434,21855,30146,40298 +12883,21856,30145,40652 +13240,21857,30144,40140 +15077,21858,30143,40495 +14073,21859,30142,40156 +10538,21860,30141,40789 +10295,21861,30140,40959 +17553,21862,30139,40217 +17166,21863,30138,40767 +12437,21864,30137,40235 +13660,21865,30136,40955 +14358,21866,30135,40962 +11694,21867,30134,40057 +11153,21868,30133,40517 +11731,21869,30132,40884 +14293,21870,30131,40929 +12871,21871,30130,40520 +16935,21872,30129,40205 +17334,21873,30128,40898 +14923,21874,30127,40769 +17618,21875,30126,40613 +12279,21876,30125,40373 +12010,21877,30124,40479 +17784,21878,30123,40814 +12000,21879,30122,40306 +15987,21880,30121,40275 +13741,21881,30120,40646 +15233,21882,30119,40861 +14730,21883,30118,40244 +14441,21884,30117,40029 +11865,21885,30116,40669 +12202,21886,30115,40504 +17204,21887,30114,40272 +11657,21888,30113,40133 +15828,21889,30112,40131 +11514,21890,30111,40896 +17756,21891,30110,40057 +14093,21892,30109,40455 +12702,21893,30108,40738 +14688,21894,30107,40984 +11306,21895,30106,40128 +13293,21896,30105,40605 +14058,21897,30104,40941 +16409,21898,30103,40088 +14961,21899,30102,40386 +11478,21900,30101,40089 +11049,21901,30100,40827 +18091,21902,30099,40879 +12119,21903,30098,40262 +16280,21904,30097,40907 +14211,21905,30096,40170 +14450,21906,30095,40168 +10205,21907,30094,40796 +11648,21908,30093,40142 +17498,21909,30092,40508 +11252,21910,30091,40790 +13192,21911,30090,40502 +15654,21912,30089,40447 +15014,21913,30088,40124 +10176,21914,30087,40311 +16912,21915,30086,40034 +17366,21916,30085,40125 +13701,21917,30084,40482 +17474,21918,30083,40099 +16543,21919,30082,40333 +18121,21920,30081,40970 +15789,21921,30080,40554 +12059,21922,30079,40109 +15694,21923,30078,40089 +13129,21924,30077,40207 +12181,21925,30076,40273 +14321,21926,30075,40465 +10429,21927,30074,40999 +13947,21928,30073,40611 +16639,21929,30072,40088 +16315,21930,30071,40292 +14191,21931,30070,40421 +14172,21932,30069,40885 +17467,21933,30068,40845 +16804,21934,30067,40439 +10405,21935,30066,40913 +12357,21936,30065,40829 +12696,21937,30064,40081 +10990,21938,30063,40292 +10253,21939,30062,40044 +13799,21940,30061,40462 +13303,21941,30060,40716 +11692,21942,30059,40910 +13040,21943,30058,40608 +15507,21944,30057,40199 +16461,21945,30056,40203 +16793,21946,30055,40205 +16790,21947,30054,40530 +17422,21948,30053,40188 +10077,21949,30052,40490 +14962,21950,30051,40359 +12653,21951,30050,40544 +14637,21952,30049,40745 +17857,21953,30048,40194 +11933,21954,30047,40600 +13908,21955,30046,40922 +11421,21956,30045,40879 +10534,21957,30044,40403 +11171,21958,30043,40250 +15248,21959,30042,40596 +16612,21960,30041,40381 +14218,21961,30040,40082 +12130,21962,30039,40357 +15298,21963,30038,40091 +12255,21964,30037,40888 +16826,21965,30036,40076 +13290,21966,30035,40256 +17327,21967,30034,40531 +17086,21968,30033,40658 +15085,21969,30032,40865 +14147,21970,30031,40173 +10683,21971,30030,40615 +10838,21972,30029,40070 +13044,21973,30028,40193 +12277,21974,30027,40472 +14157,21975,30026,40472 +17666,21976,30025,40225 +13268,21977,30024,40938 +15226,21978,30023,40920 +12481,21979,30022,40404 +10932,21980,30021,40139 +12598,21981,30020,40487 +17601,21982,30019,40965 +14835,21983,30018,40024 +14544,21984,30017,40955 +14416,21985,30016,40410 +12253,21986,30015,40432 +18051,21987,30014,40830 +10645,21988,30013,40990 +11622,21989,30012,40554 +11929,21990,30011,40141 +12643,21991,30010,40696 +14715,21992,30009,40737 +11238,21993,30008,40701 +10792,21994,30007,40483 +10313,21995,30006,40642 +10596,21996,30005,40346 +13008,21997,30004,40015 +12758,21998,30003,40786 +10358,21999,30002,40875 +10137,22000,30001,40650 +16901,22001,30000,40849 +10288,22002,31000,40611 +17448,22003,30999,40916 +16782,22004,30998,40637 +17081,22005,30997,40538 +10611,22006,30996,40356 +16041,22007,30995,40487 +13967,22008,30994,40991 +16905,22009,30993,40097 +11678,22010,30992,40249 +13269,22011,30991,40888 +18184,22012,30990,40304 +15347,22013,30989,40824 +13039,22014,30988,40723 +10335,22015,30987,40031 +12275,22016,30986,40281 +12418,22017,30985,40905 +13963,22018,30984,40324 +12725,22019,30983,40516 +10173,22020,30982,40797 +12027,22021,30981,40725 +16003,22022,30980,40561 +10182,22023,30979,40033 +14491,22024,30978,40544 +12436,22025,30977,40248 +17663,22026,30976,40654 +17346,22027,30975,40795 +13100,22028,30974,40075 +14214,22029,30973,40942 +12831,22030,30972,40429 +12428,22031,30971,40537 +11247,22032,30970,40525 +11100,22033,30969,40384 +11030,22034,30968,40151 +13161,22035,30967,40091 +11154,22036,30966,40090 +10698,22037,30965,40184 +10541,22038,30964,40008 +18086,22039,30963,40795 +17796,22040,30962,40472 +14409,22041,30961,40167 +15824,22042,30960,40631 +15910,22043,30959,40087 +12890,22044,30958,40349 +14663,22045,30957,40350 +10481,22046,30956,40939 +14968,22047,30955,40780 +10414,22048,30954,40290 +16954,22049,30953,40761 +12808,22050,30952,40382 +12803,22051,30951,40156 +14615,22052,30950,40474 +16264,22053,30949,40621 +14760,22054,30948,40886 +15562,22055,30947,40265 +15159,22056,30946,40147 +12442,22057,30945,40315 +11307,22058,30944,40158 +12495,22059,30943,40919 +18104,22060,30942,40195 +11142,22061,30941,40482 +16786,22062,30940,40297 +16391,22063,30939,40629 +11127,22064,30938,40459 +13429,22065,30937,40632 +17045,22066,30936,40911 +17971,22067,30935,40980 +10361,22068,30934,40735 +17617,22069,30933,40921 +13324,22070,30932,40821 +13810,22071,30931,40710 +12430,22072,30930,40348 +14815,22073,30929,40982 +18013,22074,30928,40481 +13682,22075,30927,40903 +12691,22076,30926,40000 +12152,22077,30925,40127 +11079,22078,30924,40155 +12259,22079,30923,40647 +10085,22080,30922,40534 +12549,22081,30921,40081 +13749,22082,30920,40325 +17755,22083,30919,40814 +14097,22084,30918,40694 +16040,22085,30917,40688 +11467,22086,30916,40628 +17252,22087,30915,40486 +12500,22088,30914,40184 +13882,22089,30913,40214 +16985,22090,30912,40188 +17160,22091,30911,40468 +17661,22092,30910,40498 +17682,22093,30909,40257 +16332,22094,30908,40006 +10733,22095,30907,40143 +13325,22096,30906,40101 +13230,22097,30905,40017 +14330,22098,30904,40981 +11382,22099,30903,40175 +16596,22100,30902,40395 +12218,22101,30901,40286 +11349,22102,30900,40420 +12226,22103,30899,40334 +16128,22104,30898,40627 +12163,22105,30897,40438 +14175,22106,30896,40193 +18127,22107,30895,40994 +15561,22108,30894,40283 +14135,22109,30893,40788 +13365,22110,30892,40349 +11739,22111,30891,40521 +15095,22112,30890,40021 +11767,22113,30889,40554 +14906,22114,30888,40098 +15217,22115,30887,40010 +12380,22116,30886,40466 +15300,22117,30885,40312 +11343,22118,30884,40699 +12911,22119,30883,40778 +10765,22120,30882,40153 +15114,22121,30881,40097 +16620,22122,30880,40238 +14045,22123,30879,40636 +10162,22124,30878,40360 +11417,22125,30877,40925 +10451,22126,30876,40197 +17870,22127,30875,40999 +15706,22128,30874,40089 +10673,22129,30873,40537 +16244,22130,30872,40776 +15536,22131,30871,40156 +14337,22132,30870,40359 +11186,22133,30869,40024 +14125,22134,30868,40084 +17249,22135,30867,40917 +11556,22136,30866,40774 +11313,22137,30865,40237 +18033,22138,30864,40694 +16619,22139,30863,40815 +12182,22140,30862,40237 +10338,22141,30861,40782 +16271,22142,30860,40088 +10301,22143,30859,40176 +18007,22144,30858,40599 +15017,22145,30857,40810 +16565,22146,30856,40979 +10707,22147,30855,40553 +10825,22148,30854,40701 +14800,22149,30853,40267 +17901,22150,30852,40659 +18048,22151,30851,40140 +14563,22152,30850,40453 +13087,22153,30849,40677 +17412,22154,30848,40126 +12866,22155,30847,40558 +17856,22156,30846,40398 +12950,22157,30845,40004 +12042,22158,30844,40628 +10795,22159,30843,40878 +10223,22160,30842,40601 +11051,22161,30841,40697 +10967,22162,30840,40904 +13814,22163,30839,40228 +10281,22164,30838,40697 +13015,22165,30837,40589 +11258,22166,30836,40156 +16454,22167,30835,40594 +10135,22168,30834,40043 +15402,22169,30833,40956 +14412,22170,30832,40273 +11704,22171,30831,40342 +13925,22172,30830,40622 +16088,22173,30829,40251 +11436,22174,30828,40716 +13026,22175,30827,40101 +12530,22176,30826,40548 +16194,22177,30825,40570 +11582,22178,30824,40905 +13775,22179,30823,40689 +11982,22180,30822,40175 +14392,22181,30821,40851 +17207,22182,30820,40508 +17379,22183,30819,40508 +15863,22184,30818,40772 +13247,22185,30817,40168 +11251,22186,30816,40619 +12626,22187,30815,40194 +10975,22188,30814,40387 +15286,22189,30813,40032 +12759,22190,30812,40229 +13859,22191,30811,40667 +14892,22192,30810,40692 +11491,22193,30809,40346 +13734,22194,30808,40053 +15696,22195,30807,40013 +15062,22196,30806,40738 +15254,22197,30805,40087 +16990,22198,30804,40238 +13058,22199,30803,40157 +16470,22200,30802,40140 +10613,22201,30801,40148 +16688,22202,30800,40256 +16837,22203,30799,40351 +10200,22204,30798,40054 +14424,22205,30797,40701 +16942,22206,30796,40929 +12602,22207,30795,40697 +10240,22208,30794,40028 +16999,22209,30793,40235 +14231,22210,30792,40461 +10336,22211,30791,40060 +12227,22212,30790,40568 +12670,22213,30789,40511 +17642,22214,30788,40519 +17255,22215,30787,40978 +11283,22216,30786,40606 +11511,22217,30785,40020 +14633,22218,30784,40868 +10594,22219,30783,40712 +17630,22220,30782,40854 +10165,22221,30781,40920 +11260,22222,30780,40478 +12692,22223,30779,40245 +15834,22224,30778,40666 +12522,22225,30777,40722 +11391,22226,30776,40031 +12141,22227,30775,40089 +17211,22228,30774,40563 +13130,22229,30773,40061 +13939,22230,30772,40121 +11899,22231,30771,40439 +16376,22232,30770,40023 +15551,22233,30769,40580 +17032,22234,30768,40364 +14702,22235,30767,40314 +12015,22236,30766,40646 +17312,22237,30765,40811 +13214,22238,30764,40728 +11923,22239,30763,40035 +12868,22240,30762,40664 +16448,22241,30761,40388 +16350,22242,30760,40078 +10996,22243,30759,40321 +17315,22244,30758,40304 +16309,22245,30757,40095 +11170,22246,30756,40034 +12045,22247,30755,40590 +10239,22248,30754,40171 +13380,22249,30753,40199 +15673,22250,30752,40275 +14631,22251,30751,40841 +11981,22252,30750,40473 +17501,22253,30749,40636 +13172,22254,30748,40465 +13727,22255,30747,40814 +14603,22256,30746,40243 +14871,22257,30745,40123 +17641,22258,30744,40422 +12721,22259,30743,40839 +12018,22260,30742,40890 +12004,22261,30741,40439 +17279,22262,30740,40510 +15728,22263,30739,40198 +11263,22264,30738,40502 +11037,22265,30737,40219 +15711,22266,30736,40566 +17295,22267,30735,40152 +11204,22268,30734,40556 +12362,22269,30733,40221 +10348,22270,30732,40631 +13833,22271,30731,40419 +13503,22272,30730,40758 +17051,22273,30729,40973 +11999,22274,30728,40500 +17099,22275,30727,40328 +12873,22276,30726,40359 +16913,22277,30725,40659 +18041,22278,30724,40943 +16861,22279,30723,40377 +15223,22280,30722,40396 +13790,22281,30721,40395 +15966,22282,30720,40448 +11661,22283,30719,40019 +13381,22284,30718,40771 +14640,22285,30717,40740 +16091,22286,30716,40853 +10940,22287,30715,40557 +14879,22288,30714,40399 +14521,22289,30713,40884 +12637,22290,30712,40858 +16835,22291,30711,40911 +15333,22292,30710,40513 +16063,22293,30709,40557 +14533,22294,30708,40779 +12073,22295,30707,40627 +10352,22296,30706,40160 +10605,22297,30705,40299 +17939,22298,30704,40605 +10642,22299,30703,40599 +15171,22300,30702,40866 +12755,22301,30701,40819 +13753,22302,30700,40048 +10195,22303,30699,40377 +11114,22304,30698,40648 +10897,22305,30697,40974 +15624,22306,30696,40807 +16321,22307,30695,40881 +15943,22308,30694,40037 +11894,22309,30693,40187 +14395,22310,30692,40245 +15118,22311,30691,40969 +13872,22312,30690,40655 +11646,22313,30689,40071 +14168,22314,30688,40833 +11987,22315,30687,40688 +16992,22316,30686,40460 +17969,22317,30685,40480 +10850,22318,30684,40819 +13346,22319,30683,40738 +11547,22320,30682,40118 +16525,22321,30681,40109 +10913,22322,30680,40500 +12459,22323,30679,40065 +15275,22324,30678,40599 +13574,22325,30677,40336 +14875,22326,30676,40817 +10855,22327,30675,40767 +15332,22328,30674,40661 +12511,22329,30673,40475 +16108,22330,30672,40680 +11320,22331,30671,40545 +14176,22332,30670,40599 +13968,22333,30669,40406 +10785,22334,30668,40610 +13014,22335,30667,40749 +16926,22336,30666,40853 +12490,22337,30665,40007 +10965,22338,30664,40999 +11904,22339,30663,40788 +13729,22340,30662,40547 +15187,22341,30661,40631 +18060,22342,30660,40404 +16101,22343,30659,40472 +18165,22344,30658,40350 +17647,22345,30657,40195 +16987,22346,30656,40855 +10221,22347,30655,40614 +14716,22348,30654,40917 +15935,22349,30653,40208 +15991,22350,30652,40729 +10757,22351,30651,40653 +14997,22352,30650,40000 +15263,22353,30649,40534 +14689,22354,30648,40131 +14036,22355,30647,40933 +15101,22356,30646,40004 +12892,22357,30645,40718 +13576,22358,30644,40369 +16662,22359,30643,40185 +17374,22360,30642,40373 +15195,22361,30641,40955 +16036,22362,30640,40393 +12403,22363,30639,40813 +10230,22364,30638,40418 +10153,22365,30637,40508 +12763,22366,30636,40828 +16006,22367,30635,40447 +16755,22368,30634,40197 +12348,22369,30633,40288 +14248,22370,30632,40604 +11769,22371,30631,40081 +11269,22372,30630,40191 +13561,22373,30629,40456 +13712,22374,30628,40332 +15454,22375,30627,40301 +15511,22376,30626,40055 +16414,22377,30625,40120 +14584,22378,30624,40075 +16964,22379,30623,40599 +11868,22380,30622,40628 +10508,22381,30621,40709 +17012,22382,30620,40312 +17804,22383,30619,40735 +12731,22384,30618,40838 +15086,22385,30617,40079 +13312,22386,30616,40814 +16079,22387,30615,40803 +14902,22388,30614,40104 +11350,22389,30613,40377 +12372,22390,30612,40289 +11003,22391,30611,40921 +13938,22392,30610,40385 +16917,22393,30609,40004 +17551,22394,30608,40063 +10407,22395,30607,40026 +17347,22396,30606,40533 +11526,22397,30605,40055 +10466,22398,30604,40848 +12614,22399,30603,40423 +10549,22400,30602,40840 +14244,22401,30601,40641 +14628,22402,30600,40790 +11554,22403,30599,40496 +16483,22404,30598,40587 +15314,22405,30597,40740 +17202,22406,30596,40621 +17730,22407,30595,40232 +11799,22408,30594,40572 +12836,22409,30593,40188 +17676,22410,30592,40147 +17213,22411,30591,40978 +16445,22412,30590,40610 +17341,22413,30589,40326 +11177,22414,30588,40865 +10487,22415,30587,40438 +11383,22416,30586,40455 +17542,22417,30585,40185 +12454,22418,30584,40759 +11535,22419,30583,40204 +15871,22420,30582,40820 +11635,22421,30581,40975 +10840,22422,30580,40771 +12332,22423,30579,40583 +13341,22424,30578,40303 +15428,22425,30577,40132 +12778,22426,30576,40443 +15798,22427,30575,40922 +11610,22428,30574,40455 +16698,22429,30573,40237 +10701,22430,30572,40629 +13663,22431,30571,40254 +13012,22432,30570,40870 +17880,22433,30569,40291 +11837,22434,30568,40982 +15857,22435,30567,40034 +11393,22436,30566,40030 +13122,22437,30565,40365 +11476,22438,30564,40112 +14431,22439,30563,40953 +11728,22440,30562,40364 +14083,22441,30561,40088 +15667,22442,30560,40809 +10888,22443,30559,40207 +12240,22444,30558,40624 +16951,22445,30557,40522 +11240,22446,30556,40186 +15345,22447,30555,40524 +10236,22448,30554,40754 +11577,22449,30553,40242 +10981,22450,30552,40557 +11862,22451,30551,40215 +11463,22452,30550,40790 +11998,22453,30549,40698 +13450,22454,30548,40126 +13286,22455,30547,40523 +17925,22456,30546,40504 +17604,22457,30545,40725 +15723,22458,30544,40211 +11960,22459,30543,40332 +10154,22460,30542,40841 +17367,22461,30541,40248 +16838,22462,30540,40172 +13140,22463,30539,40931 +11163,22464,30538,40807 +13092,22465,30537,40100 +12322,22466,30536,40258 +10432,22467,30535,40502 +11668,22468,30534,40424 +17733,22469,30533,40882 +11339,22470,30532,40483 +13680,22471,30531,40344 +16589,22472,30530,40023 +13042,22473,30529,40581 +15430,22474,30528,40012 +14028,22475,30527,40894 +11173,22476,30526,40765 +17887,22477,30525,40243 +14206,22478,30524,40373 +14276,22479,30523,40655 +14678,22480,30522,40681 +12744,22481,30521,40404 +13088,22482,30520,40577 +13897,22483,30519,40467 +15409,22484,30518,40760 +15499,22485,30517,40393 +17418,22486,30516,40426 +10575,22487,30515,40109 +17438,22488,30514,40349 +15359,22489,30513,40461 +10034,22490,30512,40808 +17338,22491,30511,40025 +10513,22492,30510,40425 +12038,22493,30509,40207 +12612,22494,30508,40579 +13735,22495,30507,40325 +16428,22496,30506,40076 +15273,22497,30505,40134 +17503,22498,30504,40852 +14347,22499,30503,40843 +14581,22500,30502,40881 +15826,22501,30501,40523 +10922,22502,30500,40704 +14182,22503,30499,40613 +14031,22504,30498,40886 +17063,22505,30497,40434 +12905,22506,30496,40084 +15105,22507,30495,40096 +11651,22508,30494,40561 +10721,22509,30493,40184 +17186,22510,30492,40169 +12468,22511,30491,40969 +16697,22512,30490,40795 +12592,22513,30489,40542 +13817,22514,30488,40913 +10357,22515,30487,40338 +14586,22516,30486,40280 +12155,22517,30485,40572 +15604,22518,30484,40167 +17420,22519,30483,40021 +17822,22520,30482,40957 +17747,22521,30481,40470 +17057,22522,30480,40163 +14195,22523,30479,40215 +10934,22524,30478,40928 +12338,22525,30477,40946 +10492,22526,30476,40755 +11121,22527,30475,40046 +11575,22528,30474,40331 +13870,22529,30473,40480 +11916,22530,30472,40203 +13484,22531,30471,40971 +12880,22532,30470,40769 +13418,22533,30469,40248 +16481,22534,30468,40501 +12922,22535,30467,40937 +16498,22536,30466,40967 +11726,22537,30465,40215 +15978,22538,30464,40337 +17697,22539,30463,40987 +14727,22540,30462,40276 +12396,22541,30461,40033 +15773,22542,30460,40638 +11677,22543,30459,40553 +17538,22544,30458,40760 +15563,22545,30457,40824 +15257,22546,30456,40014 +11623,22547,30455,40827 +17287,22548,30454,40976 +15686,22549,30453,40379 +10822,22550,30452,40086 +14943,22551,30451,40404 +11481,22552,30450,40304 +11667,22553,30449,40871 +10217,22554,30448,40643 +11839,22555,30447,40528 +10498,22556,30446,40871 +11464,22557,30445,40945 +16658,22558,30444,40589 +11969,22559,30443,40485 +13028,22560,30442,40110 +13141,22561,30441,40874 +12453,22562,30440,40799 +12194,22563,30439,40565 +11914,22564,30438,40601 +10504,22565,30437,40225 +12316,22566,30436,40932 +10644,22567,30435,40826 +13522,22568,30434,40164 +15981,22569,30433,40868 +16934,22570,30432,40051 +18052,22571,30431,40577 +16400,22572,30430,40998 +13486,22573,30429,40215 +12178,22574,30428,40988 +15942,22575,30427,40319 +14162,22576,30426,40745 +11763,22577,30425,40906 +10738,22578,30424,40809 +13494,22579,30423,40166 +12942,22580,30422,40719 +16757,22581,30421,40118 +11713,22582,30420,40349 +18087,22583,30419,40928 +17306,22584,30418,40118 +11358,22585,30417,40752 +13420,22586,30416,40311 +12497,22587,30415,40978 +13852,22588,30414,40709 +12661,22589,30413,40349 +15297,22590,30412,40936 +14124,22591,30411,40498 +15422,22592,30410,40276 +17643,22593,30409,40404 +15867,22594,30408,40648 +17256,22595,30407,40377 +14316,22596,30406,40143 +13353,22597,30405,40814 +15172,22598,30404,40380 +15364,22599,30403,40002 +17179,22600,30402,40603 +14600,22601,30401,40217 +12113,22602,30400,40315 +17929,22603,30399,40848 +14668,22604,30398,40007 +11857,22605,30397,40416 +17301,22606,30396,40771 +11402,22607,30395,40475 +14947,22608,30394,40732 +15573,22609,30393,40684 +12814,22610,30392,40504 +10014,22611,30391,40283 +10816,22612,30390,40717 +13270,22613,30389,40638 +17525,22614,30388,40142 +12425,22615,30387,40827 +15931,22616,30386,40447 +14376,22617,30385,40241 +14557,22618,30384,40409 +17073,22619,30383,40167 +10786,22620,30382,40417 +14419,22621,30381,40020 +17814,22622,30380,40867 +10963,22623,30379,40926 +11413,22624,30378,40549 +17981,22625,30377,40662 +10505,22626,30376,40942 +18085,22627,30375,40800 +10625,22628,30374,40781 +17827,22629,30373,40112 +10289,22630,30372,40301 +12369,22631,30371,40120 +13017,22632,30370,40374 +15188,22633,30369,40070 +14813,22634,30368,40127 +18099,22635,30367,40410 +15442,22636,30366,40687 +14065,22637,30365,40045 +14752,22638,30364,40884 +17645,22639,30363,40870 +12400,22640,30362,40691 +10804,22641,30361,40606 +17463,22642,30360,40837 +15707,22643,30359,40475 +14570,22644,30358,40866 +17897,22645,30357,40145 +17296,22646,30356,40327 +15210,22647,30355,40836 +11905,22648,30354,40139 +17176,22649,30353,40307 +13018,22650,30352,40672 +16975,22651,30351,40790 +11653,22652,30350,40749 +12172,22653,30349,40440 +11020,22654,30348,40184 +12648,22655,30347,40151 +15450,22656,30346,40425 +15767,22657,30345,40920 +11081,22658,30344,40409 +15600,22659,30343,40160 +10497,22660,30342,40913 +11324,22661,30341,40110 +12768,22662,30340,40936 +11601,22663,30339,40580 +12117,22664,30338,40404 +17771,22665,30337,40955 +12288,22666,30336,40417 +15530,22667,30335,40406 +16395,22668,30334,40831 +16681,22669,30333,40935 +14771,22670,30332,40181 +17672,22671,30331,40230 +14319,22672,30330,40524 +16622,22673,30329,40544 +15117,22674,30328,40399 +17776,22675,30327,40804 +10397,22676,30326,40014 +16976,22677,30325,40361 +15836,22678,30324,40026 +16497,22679,30323,40995 +11756,22680,30322,40531 +10815,22681,30321,40356 +17137,22682,30320,40453 +17898,22683,30319,40895 +13877,22684,30318,40752 +14717,22685,30317,40287 +11977,22686,30316,40487 +18050,22687,30315,40039 +14690,22688,30314,40232 +17591,22689,30313,40107 +12698,22690,30312,40746 +13256,22691,30311,40707 +11084,22692,30310,40029 +16346,22693,30309,40415 +10096,22694,30308,40395 +15092,22695,30307,40726 +14398,22696,30306,40013 +12575,22697,30305,40585 +14226,22698,30304,40264 +16802,22699,30303,40988 +12047,22700,30302,40262 +16506,22701,30301,40325 +16263,22702,30300,40120 +14987,22703,30299,40445 +15700,22704,30298,40009 +10693,22705,30297,40747 +11270,22706,30296,40414 +14481,22707,30295,40896 +11378,22708,30294,40786 +14843,22709,30293,40157 +16412,22710,30292,40934 +14819,22711,30291,40360 +13750,22712,30290,40397 +14656,22713,30289,40102 +14516,22714,30288,40398 +15769,22715,30287,40922 +13931,22716,30286,40851 +11397,22717,30285,40347 +16122,22718,30284,40862 +12204,22719,30283,40076 +14944,22720,30282,40227 +17984,22721,30281,40805 +14577,22722,30280,40256 +15349,22723,30279,40967 +11181,22724,30278,40688 +17042,22725,30277,40349 +13089,22726,30276,40495 +11484,22727,30275,40478 +15136,22728,30274,40617 +13227,22729,30273,40934 +11367,22730,30272,40500 +17831,22731,30271,40756 +15168,22732,30270,40371 +16841,22733,30269,40039 +10879,22734,30268,40788 +15121,22735,30267,40217 +17316,22736,30266,40809 +12289,22737,30265,40126 +16800,22738,30264,40834 +12792,22739,30263,40453 +14149,22740,30262,40020 +17757,22741,30261,40941 +17667,22742,30260,40187 +14789,22743,30259,40443 +11479,22744,30258,40523 +18049,22745,30257,40447 +16180,22746,30256,40156 +11480,22747,30255,40543 +10527,22748,30254,40428 +15388,22749,30253,40139 +17704,22750,30252,40838 +13446,22751,30251,40488 +13784,22752,30250,40712 +11863,22753,30249,40816 +11439,22754,30248,40642 +14474,22755,30247,40782 +14958,22756,30246,40010 +10134,22757,30245,40319 +12028,22758,30244,40557 +10779,22759,30243,40708 +13813,22760,30242,40344 +18146,22761,30241,40772 +10643,22762,30240,40405 +14075,22763,30239,40407 +13665,22764,30238,40568 +16384,22765,30237,40109 +12715,22766,30236,40961 +15521,22767,30235,40876 +15010,22768,30234,40052 +10177,22769,30233,40680 +17960,22770,30232,40700 +15913,22771,30231,40341 +14215,22772,30230,40478 +17736,22773,30229,40657 +16578,22774,30228,40097 +10371,22775,30227,40396 +15251,22776,30226,40124 +17218,22777,30225,40177 +16953,22778,30224,40584 +13737,22779,30223,40118 +13275,22780,30222,40844 +17033,22781,30221,40183 +13977,22782,30220,40840 +17926,22783,30219,40442 +13298,22784,30218,40425 +15704,22785,30217,40515 +11035,22786,30216,40178 +13899,22787,30215,40023 +17520,22788,30214,40948 +13767,22789,30213,40149 +10472,22790,30212,40876 +13617,22791,30211,40400 +17191,22792,30210,40786 +11912,22793,30209,40858 +16367,22794,30208,40723 +13888,22795,30207,40291 +11273,22796,30206,40988 +12270,22797,30205,40551 +14482,22798,30204,40127 +12197,22799,30203,40205 +11271,22800,30202,40818 +11566,22801,30201,40667 +12101,22802,30200,40298 +17817,22803,30199,40167 +11534,22804,30198,40399 +11208,22805,30197,40161 +13965,22806,30196,40897 +15229,22807,30195,40868 +12541,22808,30194,40944 +11446,22809,30193,40907 +15147,22810,30192,40513 +15419,22811,30191,40712 +16706,22812,30190,40492 +13916,22813,30189,40159 +12241,22814,30188,40962 +13354,22815,30187,40042 +17031,22816,30186,40476 +14575,22817,30185,40054 +10867,22818,30184,40431 +11550,22819,30183,40098 +14758,22820,30182,40484 +14573,22821,30181,40095 +16775,22822,30180,40292 +13850,22823,30179,40147 +17240,22824,30178,40976 +13586,22825,30177,40408 +17401,22826,30176,40350 +14400,22827,30175,40946 +13245,22828,30174,40063 +13919,22829,30173,40277 +14138,22830,30172,40366 +18028,22831,30171,40780 +11156,22832,30170,40891 +12154,22833,30169,40846 +15626,22834,30168,40757 +16728,22835,30167,40891 +12300,22836,30166,40679 +16094,22837,30165,40989 +12201,22838,30164,40649 +17766,22839,30163,40066 +17535,22840,30162,40799 +17225,22841,30161,40357 +11274,22842,30160,40542 +15552,22843,30159,40428 +10893,22844,30158,40579 +13984,22845,30157,40404 +18175,22846,30156,40958 +16099,22847,30155,40120 +11683,22848,30154,40507 +12645,22849,30153,40785 +16668,22850,30152,40201 +16920,22851,30151,40255 +14234,22852,30150,40139 +10619,22853,30149,40774 +13369,22854,30148,40541 +11883,22855,30147,40428 +17039,22856,30146,40257 +16609,22857,30145,40766 +11262,22858,30144,40414 +17018,22859,30143,40122 +13969,22860,30142,40466 +11210,22861,30141,40751 +17942,22862,30140,40382 +11853,22863,30139,40161 +10488,22864,30138,40608 +14989,22865,30137,40177 +17891,22866,30136,40382 +12465,22867,30135,40881 +16742,22868,30134,40662 +10632,22869,30133,40557 +10720,22870,30132,40115 +16411,22871,30131,40141 +16900,22872,30130,40553 +18118,22873,30129,40479 +16124,22874,30128,40281 +17882,22875,30127,40841 +14905,22876,30126,40824 +17077,22877,30125,40428 +13487,22878,30124,40243 +12036,22879,30123,40940 +15609,22880,30122,40805 +16783,22881,30121,40340 +18159,22882,30120,40312 +11203,22883,30119,40558 +16077,22884,30118,40346 +15274,22885,30117,40872 +18083,22886,30116,40591 +15379,22887,30115,40802 +13670,22888,30114,40604 +18029,22889,30113,40988 +14506,22890,30112,40732 +11287,22891,30111,40493 +12364,22892,30110,40147 +11245,22893,30109,40022 +12957,22894,30108,40319 +13706,22895,30107,40277 +15063,22896,30106,40303 +12809,22897,30105,40485 +12720,22898,30104,40420 +10410,22899,30103,40106 +11093,22900,30102,40492 +11543,22901,30101,40754 +17787,22902,30100,40245 +14791,22903,30099,40727 +13137,22904,30098,40486 +13397,22905,30097,40849 +16516,22906,30096,40961 +16809,22907,30095,40569 +15041,22908,30094,40957 +15495,22909,30093,40409 +16033,22910,30092,40945 +10423,22911,30091,40927 +13671,22912,30090,40986 +14811,22913,30089,40935 +13862,22914,30088,40893 +10097,22915,30087,40072 +11792,22916,30086,40368 +12523,22917,30085,40439 +13674,22918,30084,40818 +17588,22919,30083,40791 +11975,22920,30082,40155 +11487,22921,30081,40747 +17999,22922,30080,40526 +17139,22923,30079,40210 +18071,22924,30078,40756 +16735,22925,30077,40849 +15905,22926,30076,40730 +16140,22927,30075,40622 +13768,22928,30074,40578 +10422,22929,30073,40736 +10719,22930,30072,40463 +15068,22931,30071,40956 +13992,22932,30070,40617 +12302,22933,30069,40667 +14146,22934,30068,40057 +17509,22935,30067,40143 +16048,22936,30066,40743 +14894,22937,30065,40972 +12570,22938,30064,40207 +18173,22939,30063,40931 +14635,22940,30062,40937 +17837,22941,30061,40417 +14755,22942,30060,40088 +15119,22943,30059,40135 +14228,22944,30058,40994 +18111,22945,30057,40107 +10542,22946,30056,40934 +17381,22947,30055,40547 +11428,22948,30054,40965 +13401,22949,30053,40473 +11530,22950,30052,40630 +15830,22951,30051,40650 +10093,22952,30050,40405 +11643,22953,30049,40033 +15590,22954,30048,40710 +14303,22955,30047,40673 +13279,22956,30046,40555 +10208,22957,30045,40559 +10737,22958,30044,40342 +11073,22959,30043,40526 +16010,22960,30042,40160 +14594,22961,30041,40828 +12927,22962,30040,40151 +11722,22963,30039,40265 +10283,22964,30038,40078 +17319,22965,30037,40999 +17745,22966,30036,40174 +15797,22967,30035,40813 +17084,22968,30034,40578 +10522,22969,30033,40494 +15491,22970,30032,40769 +13900,22971,30031,40527 +15051,22972,30030,40629 +18180,22973,30029,40790 +12162,22974,30028,40224 +11788,22975,30027,40750 +11992,22976,30026,40198 +16605,22977,30025,40766 +16850,22978,30024,40637 +10723,22979,30023,40841 +14292,22980,30022,40377 +16754,22981,30021,40504 +15620,22982,30020,40708 +15793,22983,30019,40892 +17416,22984,30018,40026 +16096,22985,30017,40888 +16675,22986,30016,40315 +12299,22987,30015,40082 +11920,22988,30014,40666 +15862,22989,30013,40114 +14498,22990,30012,40666 +16258,22991,30011,40875 +10360,22992,30010,40217 +14291,22993,30009,40743 +15713,22994,30008,40452 +13777,22995,30007,40656 +14547,22996,30006,40241 +18120,22997,30005,40624 +14996,22998,30004,40356 +16727,22999,30003,40889 +13101,23000,30002,40577 +12470,23001,30001,40745 +14056,23002,30000,40880 +17778,23003,31000,40782 +17075,23004,30999,40551 +13080,23005,30998,40591 +15082,23006,30997,40033 +13566,23007,30996,40898 +10776,23008,30995,40860 +12737,23009,30994,40242 +14524,23010,30993,40665 +12143,23011,30992,40185 +15131,23012,30991,40572 +10991,23013,30990,40131 +15323,23014,30989,40154 +12900,23015,30988,40011 +13922,23016,30987,40075 +17002,23017,30986,40630 +10010,23018,30985,40005 +14979,23019,30984,40621 +10768,23020,30983,40752 +18097,23021,30982,40025 +16887,23022,30981,40296 +16215,23023,30980,40447 +10747,23024,30979,40821 +15899,23025,30978,40107 +13603,23026,30977,40966 +13592,23027,30976,40384 +12921,23028,30975,40100 +10584,23029,30974,40525 +11507,23030,30973,40275 +11666,23031,30972,40900 +11973,23032,30971,40131 +13211,23033,30970,40068 +12212,23034,30969,40053 +14034,23035,30968,40158 +10510,23036,30967,40024 +11095,23037,30966,40340 +13311,23038,30965,40188 +13514,23039,30964,40213 +15138,23040,30963,40878 +10241,23041,30962,40566 +16741,23042,30961,40793 +14494,23043,30960,40315 +17377,23044,30959,40646 +11299,23045,30958,40890 +13560,23046,30957,40506 +14382,23047,30956,40592 +15432,23048,30955,40686 +17353,23049,30954,40117 +15566,23050,30953,40388 +11297,23051,30952,40427 +11400,23052,30951,40845 +17151,23053,30950,40244 +12237,23054,30949,40519 +14827,23055,30948,40977 +13459,23056,30947,40548 +15438,23057,30946,40871 +12713,23058,30945,40662 +13980,23059,30944,40867 +15628,23060,30943,40886 +11165,23061,30942,40822 +17161,23062,30941,40923 +16876,23063,30940,40900 +12205,23064,30939,40776 +14158,23065,30938,40127 +16678,23066,30937,40959 +17556,23067,30936,40008 +12782,23068,30935,40041 +16807,23069,30934,40413 +10387,23070,30933,40015 +11818,23071,30932,40118 +12732,23072,30931,40963 +17966,23073,30930,40746 +10671,23074,30929,40751 +17044,23075,30928,40623 +15306,23076,30927,40303 +15367,23077,30926,40326 +14365,23078,30925,40523 +18169,23079,30924,40916 +16822,23080,30923,40460 +17273,23081,30922,40444 +12342,23082,30921,40944 +12345,23083,30920,40410 +18014,23084,30919,40857 +11102,23085,30918,40724 +17423,23086,30917,40959 +16021,23087,30916,40201 +14788,23088,30915,40766 +16816,23089,30914,40099 +15638,23090,30913,40538 +12484,23091,30912,40696 +13857,23092,30911,40303 +14123,23093,30910,40540 +11655,23094,30909,40453 +17792,23095,30908,40539 +11580,23096,30907,40200 +14268,23097,30906,40530 +10906,23098,30905,40461 +15261,23099,30904,40077 +14298,23100,30903,40049 +14522,23101,30902,40947 +10654,23102,30901,40652 +11785,23103,30900,40917 +11059,23104,30899,40610 +16531,23105,30898,40062 +10028,23106,30897,40154 +10075,23107,30896,40757 +10495,23108,30895,40376 +12339,23109,30894,40269 +16043,23110,30893,40261 +11724,23111,30892,40181 +11390,23112,30891,40390 +15412,23113,30890,40323 +17772,23114,30889,40274 +12582,23115,30888,40348 +15919,23116,30887,40524 +14411,23117,30886,40311 +12499,23118,30885,40257 +17739,23119,30884,40047 +13284,23120,30883,40707 +12854,23121,30882,40719 +15035,23122,30881,40780 +10966,23123,30880,40992 +10242,23124,30879,40855 +12173,23125,30878,40805 +13937,23126,30877,40519 +13705,23127,30876,40088 +11217,23128,30875,40755 +15766,23129,30874,40253 +14592,23130,30873,40969 +10556,23131,30872,40876 +12634,23132,30871,40480 +12463,23133,30870,40300 +13374,23134,30869,40826 +10040,23135,30868,40611 +15262,23136,30867,40757 +15898,23137,30866,40330 +12207,23138,30865,40947 +10828,23139,30864,40005 +10260,23140,30863,40831 +13363,23141,30862,40144 +14272,23142,30861,40336 +10415,23143,30860,40941 +14937,23144,30859,40307 +16008,23145,30858,40315 +17363,23146,30857,40792 +10480,23147,30856,40880 +14338,23148,30855,40151 +15113,23149,30854,40838 +10590,23150,30853,40883 +11607,23151,30852,40260 +10862,23152,30851,40636 +17157,23153,30850,40187 +12667,23154,30849,40115 +12365,23155,30848,40833 +14468,23156,30847,40310 +11761,23157,30846,40499 +13425,23158,30845,40539 +12567,23159,30844,40330 +17841,23160,30843,40937 +18006,23161,30842,40032 +10956,23162,30841,40234 +12464,23163,30840,40141 +13791,23164,30839,40821 +18038,23165,30838,40898 +14082,23166,30837,40129 +15574,23167,30836,40806 +16660,23168,30835,40867 +17052,23169,30834,40966 +15317,23170,30833,40624 +17272,23171,30832,40015 +15029,23172,30831,40526 +15009,23173,30830,40368 +12088,23174,30829,40284 +12129,23175,30828,40203 +10484,23176,30827,40339 +11826,23177,30826,40786 +16212,23178,30825,40396 +17317,23179,30824,40662 +13644,23180,30823,40912 +11995,23181,30822,40954 +17959,23182,30821,40055 +10188,23183,30820,40822 +10062,23184,30819,40392 +12948,23185,30818,40064 +16392,23186,30817,40623 +10022,23187,30816,40252 +15800,23188,30815,40500 +14280,23189,30814,40572 +14072,23190,30813,40560 +11909,23191,30812,40123 +17493,23192,30811,40723 +17486,23193,30810,40724 +16398,23194,30809,40585 +14520,23195,30808,40664 +11185,23196,30807,40267 +15725,23197,30806,40163 +13519,23198,30805,40033 +17657,23199,30804,40304 +13198,23200,30803,40877 +13974,23201,30802,40075 +15198,23202,30801,40554 +11784,23203,30800,40356 +18158,23204,30799,40516 +15777,23205,30798,40180 +11589,23206,30797,40242 +17578,23207,30796,40335 +12669,23208,30795,40294 +11887,23209,30794,40857 +13313,23210,30793,40501 +17382,23211,30792,40358 +16171,23212,30791,40297 +13292,23213,30790,40274 +14599,23214,30789,40259 +10439,23215,30788,40943 +12654,23216,30787,40678 +11278,23217,30786,40204 +13478,23218,30785,40032 +11679,23219,30784,40138 +16057,23220,30783,40962 +12729,23221,30782,40522 +12851,23222,30781,40102 +14686,23223,30780,40754 +16855,23224,30779,40575 +14539,23225,30778,40167 +11010,23226,30777,40604 +13166,23227,30776,40109 +10285,23228,30775,40959 +12903,23229,30774,40833 +14540,23230,30773,40282 +17340,23231,30772,40295 +11529,23232,30771,40993 +13773,23233,30770,40335 +16847,23234,30769,40970 +12705,23235,30768,40059 +14444,23236,30767,40505 +17049,23237,30766,40220 +11445,23238,30765,40480 +12622,23239,30764,40937 +15580,23240,30763,40716 +12377,23241,30762,40593 +16344,23242,30761,40123 +17895,23243,30760,40912 +16932,23244,30759,40473 +11937,23245,30758,40446 +17305,23246,30757,40161 +12363,23247,30756,40301 +15752,23248,30755,40840 +14105,23249,30754,40809 +12180,23250,30753,40702 +15568,23251,30752,40290 +12556,23252,30751,40558 +13656,23253,30750,40236 +15690,23254,30749,40741 +11176,23255,30748,40272 +16303,23256,30747,40311 +14359,23257,30746,40611 +17899,23258,30745,40780 +11094,23259,30744,40612 +15434,23260,30743,40170 +18161,23261,30742,40067 +17583,23262,30741,40140 +17472,23263,30740,40365 +12278,23264,30739,40520 +11741,23265,30738,40620 +16086,23266,30737,40759 +10770,23267,30736,40299 +13181,23268,30735,40629 +11753,23269,30734,40184 +13035,23270,30733,40208 +14193,23271,30732,40386 +14471,23272,30731,40669 +11466,23273,30730,40769 +16813,23274,30729,40334 +10304,23275,30728,40548 +16844,23276,30727,40495 +17260,23277,30726,40070 +11055,23278,30725,40488 +11166,23279,30724,40378 +17324,23280,30723,40677 +15295,23281,30722,40438 +18134,23282,30721,40633 +15744,23283,30720,40556 +11918,23284,30719,40946 +14801,23285,30718,40938 +15859,23286,30717,40773 +13652,23287,30716,40835 +17717,23288,30715,40818 +14002,23289,30714,40215 +14274,23290,30713,40066 +16203,23291,30712,40181 +17100,23292,30711,40669 +13437,23293,30710,40641 +12019,23294,30709,40848 +12424,23295,30708,40457 +16716,23296,30707,40539 +16923,23297,30706,40761 +15493,23298,30705,40041 +11259,23299,30704,40286 +12399,23300,30703,40616 +15529,23301,30702,40872 +13490,23302,30701,40689 +15227,23303,30700,40120 +17576,23304,30699,40913 +13827,23305,30698,40537 +11840,23306,30697,40686 +12257,23307,30696,40443 +12532,23308,30695,40669 +17623,23309,30694,40938 +13156,23310,30693,40112 +15361,23311,30692,40413 +12013,23312,30691,40581 +17835,23313,30690,40586 +16074,23314,30689,40089 +13296,23315,30688,40471 +10696,23316,30687,40133 +14888,23317,30686,40212 +17187,23318,30685,40438 +10079,23319,30684,40461 +11214,23320,30683,40264 +17428,23321,30682,40947 +10255,23322,30681,40349 +16195,23323,30680,40177 +14183,23324,30679,40774 +12108,23325,30678,40531 +11631,23326,30677,40452 +11140,23327,30676,40867 +15801,23328,30675,40497 +11141,23329,30674,40230 +10690,23330,30673,40432 +18089,23331,30672,40891 +14428,23332,30671,40155 +18178,23333,30670,40668 +13427,23334,30669,40922 +16359,23335,30668,40309 +12940,23336,30667,40753 +16965,23337,30666,40425 +12238,23338,30665,40675 +17500,23339,30664,40491 +10206,23340,30663,40467 +14844,23341,30662,40834 +17111,23342,30661,40929 +14776,23343,30660,40502 +10374,23344,30659,40697 +14495,23345,30658,40527 +11684,23346,30657,40375 +12321,23347,30656,40406 +12286,23348,30655,40302 +12171,23349,30654,40178 +11980,23350,30653,40649 +15319,23351,30652,40436 +13789,23352,30651,40177 +17872,23353,30650,40151 +12064,23354,30649,40188 +13093,23355,30648,40422 +14954,23356,30647,40143 +16611,23357,30646,40522 +12931,23358,30645,40794 +11754,23359,30644,40331 +15176,23360,30643,40418 +10296,23361,30642,40787 +10653,23362,30641,40036 +11760,23363,30640,40474 +14247,23364,30639,40932 +14549,23365,30638,40876 +14023,23366,30637,40421 +17539,23367,30636,40775 +13616,23368,30635,40739 +16664,23369,30634,40065 +15819,23370,30633,40749 +17021,23371,30632,40342 +12248,23372,30631,40359 +10656,23373,30630,40302 +15094,23374,30629,40243 +14264,23375,30628,40493 +14655,23376,30627,40767 +16548,23377,30626,40061 +13637,23378,30625,40634 +12879,23379,30624,40782 +11548,23380,30623,40199 +10043,23381,30622,40581 +15241,23382,30621,40684 +12324,23383,30620,40410 +10300,23384,30619,40533 +17120,23385,30618,40435 +13864,23386,30617,40465 +17391,23387,30616,40918 +16444,23388,30615,40759 +15807,23389,30614,40076 +16916,23390,30613,40697 +10337,23391,30612,40081 +13607,23392,30611,40965 +13342,23393,30610,40984 +16603,23394,30609,40997 +14757,23395,30608,40692 +10921,23396,30607,40125 +16261,23397,30606,40209 +13131,23398,30605,40474 +14564,23399,30604,40672 +13634,23400,30603,40105 +18117,23401,30602,40129 +16223,23402,30601,40245 +16828,23403,30600,40803 +10544,23404,30599,40730 +16467,23405,30598,40863 +15267,23406,30597,40231 +11135,23407,30596,40611 +12961,23408,30595,40473 +11637,23409,30594,40474 +14743,23410,30593,40449 +12087,23411,30592,40752 +18139,23412,30591,40296 +11115,23413,30590,40195 +12554,23414,30589,40209 +16545,23415,30588,40222 +13657,23416,30587,40364 +11822,23417,30586,40247 +17294,23418,30585,40531 +16527,23419,30584,40184 +16023,23420,30583,40486 +10868,23421,30582,40123 +16456,23422,30581,40241 +17350,23423,30580,40870 +16085,23424,30579,40477 +17158,23425,30578,40694 +17154,23426,30577,40259 +10340,23427,30576,40087 +15691,23428,30575,40500 +12615,23429,30574,40353 +10446,23430,30573,40855 +13581,23431,30572,40991 +10474,23432,30571,40290 +12414,23433,30570,40881 +17612,23434,30569,40217 +16439,23435,30568,40698 +15756,23436,30567,40773 +13463,23437,30566,40956 +16281,23438,30565,40851 +11041,23439,30564,40414 +10187,23440,30563,40509 +12427,23441,30562,40527 +12597,23442,30561,40470 +14980,23443,30560,40189 +17351,23444,30559,40183 +10202,23445,30558,40686 +13272,23446,30557,40327 +15831,23447,30556,40112 +16748,23448,30555,40263 +17457,23449,30554,40700 +13537,23450,30553,40499 +12213,23451,30552,40332 +10272,23452,30551,40588 +12133,23453,30550,40285 +14323,23454,30549,40074 +17867,23455,30548,40792 +12985,23456,30547,40311 +11509,23457,30546,40083 +12494,23458,30545,40295 +11783,23459,30544,40189 +17006,23460,30543,40603 +10796,23461,30542,40990 +10682,23462,30541,40453 +15878,23463,30540,40412 +17384,23464,30539,40438 +17242,23465,30538,40826 +16064,23466,30537,40963 +16899,23467,30536,40043 +11708,23468,30535,40166 +18070,23469,30534,40332 +17378,23470,30533,40785 +12170,23471,30532,40952 +11748,23472,30531,40045 +15920,23473,30530,40237 +10183,23474,30529,40888 +10593,23475,30528,40587 +12789,23476,30527,40565 +10006,23477,30526,40597 +10164,23478,30525,40534 +16768,23479,30524,40488 +12116,23480,30523,40628 +17555,23481,30522,40320 +13301,23482,30521,40159 +17512,23483,30520,40290 +14931,23484,30519,40809 +13621,23485,30518,40604 +16988,23486,30517,40564 +14964,23487,30516,40545 +15074,23488,30515,40596 +15578,23489,30514,40265 +11131,23490,30513,40039 +12048,23491,30512,40812 +10799,23492,30511,40921 +11540,23493,30510,40831 +10125,23494,30509,40213 +10791,23495,30508,40639 +10464,23496,30507,40453 +14473,23497,30506,40250 +13645,23498,30505,40506 +14052,23499,30504,40838 +14284,23500,30503,40911 +17289,23501,30502,40233 +13923,23502,30501,40816 +10945,23503,30500,40655 +11972,23504,30499,40976 +17491,23505,30498,40922 +11150,23506,30497,40536 +14826,23507,30496,40828 +14624,23508,30495,40291 +10254,23509,30494,40384 +14703,23510,30493,40894 +13854,23511,30492,40902 +11080,23512,30491,40181 +10157,23513,30490,40589 +10452,23514,30489,40336 +17561,23515,30488,40458 +14780,23516,30487,40309 +14334,23517,30486,40943 +11811,23518,30485,40231 +12147,23519,30484,40424 +11303,23520,30483,40405 +14579,23521,30482,40150 +14940,23522,30481,40797 +15423,23523,30480,40686 +14903,23524,30479,40486 +10833,23525,30478,40812 +13579,23526,30477,40877 +12488,23527,30476,40424 +13451,23528,30475,40431 +16285,23529,30474,40291 +10509,23530,30473,40462 +10571,23531,30472,40603 +11000,23532,30471,40831 +14804,23533,30470,40250 +14956,23534,30469,40944 +11123,23535,30468,40501 +11461,23536,30467,40854 +16740,23537,30466,40280 +10528,23538,30465,40188 +16945,23539,30464,40959 +12820,23540,30463,40760 +17770,23541,30462,40415 +17575,23542,30461,40815 +14165,23543,30460,40642 +13258,23544,30459,40145 +10319,23545,30458,40682 +11117,23546,30457,40799 +17168,23547,30456,40053 +11494,23548,30455,40625 +17782,23549,30454,40182 +17571,23550,30453,40372 +10953,23551,30452,40644 +10663,23552,30451,40376 +12603,23553,30450,40276 +16405,23554,30449,40296 +13866,23555,30448,40282 +10024,23556,30447,40387 +15923,23557,30446,40605 +12104,23558,30445,40815 +12790,23559,30444,40616 +14171,23560,30443,40837 +11344,23561,30442,40948 +14415,23562,30441,40647 +10842,23563,30440,40755 +15156,23564,30439,40230 +10739,23565,30438,40215 +13062,23566,30437,40353 +16552,23567,30436,40489 +16558,23568,30435,40023 +16576,23569,30434,40958 +10375,23570,30433,40485 +17934,23571,30432,40428 +17626,23572,30431,40723 +12810,23573,30430,40994 +13236,23574,30429,40105 +10948,23575,30428,40941 +15133,23576,30427,40232 +17370,23577,30426,40423 +12035,23578,30425,40731 +13145,23579,30424,40529 +16640,23580,30423,40131 +16759,23581,30422,40801 +13554,23582,30421,40425 +10697,23583,30420,40575 +14108,23584,30419,40071 +13740,23585,30418,40482 +11381,23586,30417,40472 +11301,23587,30416,40968 +15391,23588,30415,40430 +12847,23589,30414,40042 +10894,23590,30413,40290 +16139,23591,30412,40877 +12542,23592,30411,40645 +12837,23593,30410,40085 +17779,23594,30409,40357 +10229,23595,30408,40668 +16031,23596,30407,40812 +10207,23597,30406,40408 +11706,23598,30405,40587 +15979,23599,30404,40331 +10395,23600,30403,40371 +10781,23601,30402,40988 +15630,23602,30401,40116 +12124,23603,30400,40691 +14496,23604,30399,40278 +11235,23605,30398,40537 +15304,23606,30397,40869 +13920,23607,30396,40629 +13045,23608,30395,40354 +16186,23609,30394,40500 +17587,23610,30393,40115 +18088,23611,30392,40160 +12307,23612,30391,40477 +11766,23613,30390,40489 +15204,23614,30389,40960 +13738,23615,30388,40881 +11932,23616,30387,40121 +18162,23617,30386,40856 +17226,23618,30385,40997 +12092,23619,30384,40904 +16652,23620,30383,40128 +17853,23621,30382,40691 +13413,23622,30381,40702 +12128,23623,30380,40153 +11454,23624,30379,40161 +10149,23625,30378,40510 +14099,23626,30377,40209 +15631,23627,30376,40176 +10763,23628,30375,40329 +11976,23629,30374,40214 +11810,23630,30373,40990 +15842,23631,30372,40699 +15075,23632,30371,40291 +13959,23633,30370,40242 +12062,23634,30369,40855 +13317,23635,30368,40028 +17415,23636,30367,40840 +16721,23637,30366,40309 +15124,23638,30365,40441 +17665,23639,30364,40284 +14505,23640,30363,40727 +17369,23641,30362,40945 +11508,23642,30361,40329 +12179,23643,30360,40929 +11207,23644,30359,40870 +17985,23645,30358,40364 +12234,23646,30357,40032 +17707,23647,30356,40336 +11472,23648,30355,40646 +15005,23649,30354,40350 +10055,23650,30353,40943 +15055,23651,30352,40130 +15164,23652,30351,40594 +12416,23653,30350,40865 +14208,23654,30349,40091 +11681,23655,30348,40803 +15178,23656,30347,40688 +17097,23657,30346,40207 +13223,23658,30345,40649 +12426,23659,30344,40806 +17167,23660,30343,40862 +11787,23661,30342,40391 +10808,23662,30341,40874 +14550,23663,30340,40794 +16298,23664,30339,40901 +17380,23665,30338,40800 +11241,23666,30337,40928 +13132,23667,30336,40863 +10080,23668,30335,40905 +15228,23669,30334,40476 +10634,23670,30333,40703 +16771,23671,30332,40001 +16950,23672,30331,40055 +15505,23673,30330,40934 +17774,23674,30329,40164 +16787,23675,30328,40987 +11063,23676,30327,40038 +16308,23677,30326,40060 +17546,23678,30325,40529 +18039,23679,30324,40333 +17223,23680,30323,40286 +14982,23681,30322,40437 +13447,23682,30321,40431 +14020,23683,30320,40935 +13255,23684,30319,40347 +10380,23685,30318,40370 +16305,23686,30317,40497 +14921,23687,30316,40003 +14370,23688,30315,40002 +10074,23689,30314,40889 +11820,23690,30313,40511 +14177,23691,30312,40750 +11160,23692,30311,40345 +15201,23693,30310,40077 +10244,23694,30309,40024 +17950,23695,30308,40414 +11085,23696,30307,40539 +11291,23697,30306,40119 +10409,23698,30305,40574 +14786,23699,30304,40517 +15865,23700,30303,40962 +15738,23701,30302,40432 +17565,23702,30301,40302 +13796,23703,30300,40716 +17900,23704,30299,40571 +14991,23705,30298,40979 +10748,23706,30297,40781 +13183,23707,30296,40376 +14558,23708,30295,40637 +14188,23709,30294,40655 +11087,23710,30293,40115 +15627,23711,30292,40873 +11268,23712,30291,40849 +16711,23713,30290,40955 +13708,23714,30289,40763 +17215,23715,30288,40709 +16713,23716,30287,40035 +16788,23717,30286,40584 +17533,23718,30285,40640 +10725,23719,30284,40057 +11938,23720,30283,40367 +11011,23721,30282,40050 +13506,23722,30281,40050 +16663,23723,30280,40336 +11276,23724,30279,40732 +10604,23725,30278,40767 +14922,23726,30277,40279 +10598,23727,30276,40297 +16487,23728,30275,40156 +10589,23729,30274,40277 +10376,23730,30273,40881 +14144,23731,30272,40292 +17110,23732,30271,40609 +12001,23733,30270,40264 +10901,23734,30269,40030 +14908,23735,30268,40453 +15937,23736,30267,40337 +15141,23737,30266,40905 +11585,23738,30265,40962 +17368,23739,30264,40896 +14092,23740,30263,40739 +15825,23741,30262,40399 +10047,23742,30261,40046 +15523,23743,30260,40058 +15838,23744,30259,40111 +15167,23745,30258,40298 +10475,23746,30257,40013 +14814,23747,30256,40958 +13930,23748,30255,40010 +10066,23749,30254,40842 +15954,23750,30253,40513 +10555,23751,30252,40213 +10876,23752,30251,40127 +14229,23753,30250,40052 +11282,23754,30249,40082 +12965,23755,30248,40764 +13622,23756,30247,40286 +10215,23757,30246,40493 +11798,23758,30245,40030 +14882,23759,30244,40121 +11144,23760,30243,40632 +11852,23761,30242,40972 +11058,23762,30241,40529 +12665,23763,30240,40702 +11261,23764,30239,40056 +15659,23765,30238,40547 +16371,23766,30237,40575 +17652,23767,30236,40820 +16856,23768,30235,40763 +16166,23769,30234,40975 +12604,23770,30233,40948 +17392,23771,30232,40409 +11596,23772,30231,40120 +16530,23773,30230,40411 +11521,23774,30229,40939 +10732,23775,30228,40450 +16274,23776,30227,40289 +15872,23777,30226,40024 +12261,23778,30225,40867 +14559,23779,30224,40457 +11490,23780,30223,40336 +13266,23781,30222,40576 +10685,23782,30221,40827 +13788,23783,30220,40207 +13010,23784,30219,40730 +10419,23785,30218,40294 +10976,23786,30217,40439 +14270,23787,30216,40458 +15354,23788,30215,40623 +11222,23789,30214,40391 +16879,23790,30213,40279 +12730,23791,30212,40024 +16919,23792,30211,40351 +17874,23793,30210,40291 +12963,23794,30209,40799 +10118,23795,30208,40546 +15209,23796,30207,40117 +13973,23797,30206,40051 +15498,23798,30205,40777 +17056,23799,30204,40194 +11804,23800,30203,40376 +12127,23801,30202,40932 +16937,23802,30201,40700 +11886,23803,30200,40188 +14053,23804,30199,40869 +14387,23805,30198,40227 +15658,23806,30197,40464 +15636,23807,30196,40032 +17712,23808,30195,40365 +15206,23809,30194,40927 +15858,23810,30193,40151 +12740,23811,30192,40958 +15169,23812,30191,40781 +16974,23813,30190,40530 +12745,23814,30189,40077 +16083,23815,30188,40904 +16306,23816,30187,40776 +12656,23817,30186,40879 +17883,23818,30185,40633 +14429,23819,30184,40275 +15504,23820,30183,40775 +15004,23821,30182,40941 +15736,23822,30181,40193 +13640,23823,30180,40613 +10342,23824,30179,40633 +10898,23825,30178,40178 +16591,23826,30177,40433 +10489,23827,30176,40792 +16602,23828,30175,40778 +11394,23829,30174,40352 +10124,23830,30173,40796 +14985,23831,30172,40165 +17970,23832,30171,40272 +15120,23833,30170,40010 +15202,23834,30169,40777 +17789,23835,30168,40042 +11835,23836,30167,40440 +15506,23837,30166,40383 +16136,23838,30165,40535 +17559,23839,30164,40556 +15514,23840,30163,40037 +16959,23841,30162,40766 +12805,23842,30161,40144 +17371,23843,30160,40765 +13173,23844,30159,40353 +12058,23845,30158,40184 +16232,23846,30157,40225 +14724,23847,30156,40958 +14342,23848,30155,40698 +10406,23849,30154,40561 +10692,23850,30153,40432 +15264,23851,30152,40029 +14164,23852,30151,40462 +12994,23853,30150,40415 +12063,23854,30149,40692 +10191,23855,30148,40120 +13153,23856,30147,40894 +13627,23857,30146,40385 +17788,23858,30145,40233 +11561,23859,30144,40536 +10546,23860,30143,40718 +15011,23861,30142,40064 +12599,23862,30141,40305 +17598,23863,30140,40071 +17975,23864,30139,40715 +12319,23865,30138,40144 +11438,23866,30137,40258 +16160,23867,30136,40593 +12864,23868,30135,40203 +14222,23869,30134,40080 +12923,23870,30133,40230 +13334,23871,30132,40518 +16824,23872,30131,40976 +16030,23873,30130,40565 +12120,23874,30129,40518 +16051,23875,30128,40854 +14104,23876,30127,40469 +17662,23877,30126,40331 +16310,23878,30125,40286 +17560,23879,30124,40043 +16707,23880,30123,40870 +16312,23881,30122,40875 +14625,23882,30121,40460 +14886,23883,30120,40234 +13770,23884,30119,40332 +15477,23885,30118,40293 +15990,23886,30117,40649 +16246,23887,30116,40945 +17008,23888,30115,40847 +13110,23889,30114,40408 +16446,23890,30113,40333 +12818,23891,30112,40114 +14585,23892,30111,40105 +10308,23893,30110,40172 +16815,23894,30109,40422 +17323,23895,30108,40966 +15739,23896,30107,40593 +13476,23897,30106,40751 +15701,23898,30105,40857 +17600,23899,30104,40715 +10871,23900,30103,40669 +12031,23901,30102,40292 +12956,23902,30101,40455 +12856,23903,30100,40382 +14408,23904,30099,40430 +12973,23905,30098,40468 +10941,23906,30097,40593 +18122,23907,30096,40089 +15109,23908,30095,40255 +15374,23909,30094,40081 +13695,23910,30093,40724 +10193,23911,30092,40278 +14287,23912,30091,40398 +16370,23913,30090,40022 +14318,23914,30089,40542 +16982,23915,30088,40393 +12434,23916,30087,40001 +15587,23917,30086,40832 +12796,23918,30085,40478 +10310,23919,30084,40817 +10156,23920,30083,40130 +12100,23921,30082,40319 +10547,23922,30081,40679 +10171,23923,30080,40830 +12186,23924,30079,40891 +15904,23925,30078,40197 +17336,23926,30077,40325 +17699,23927,30076,40108 +18102,23928,30075,40010 +17205,23929,30074,40525 +16544,23930,30073,40717 +11615,23931,30072,40447 +11067,23932,30071,40454 +17773,23933,30070,40909 +15064,23934,30069,40449 +11569,23935,30068,40493 +12409,23936,30067,40127 +13276,23937,30066,40564 +11431,23938,30065,40450 +15061,23939,30064,40814 +12853,23940,30063,40657 +13364,23941,30062,40916 +14930,23942,30061,40628 +10443,23943,30060,40926 +12225,23944,30059,40881 +11896,23945,30058,40712 +14425,23946,30057,40420 +10655,23947,30056,40618 +15501,23948,30055,40174 +15845,23949,30054,40062 +11963,23950,30053,40868 +16654,23951,30052,40622 +15549,23952,30051,40449 +15544,23953,30050,40526 +12773,23954,30049,40830 +17248,23955,30048,40597 +10115,23956,30047,40781 +12573,23957,30046,40105 +10267,23958,30045,40877 +18141,23959,30044,40624 +10042,23960,30043,40919 +10563,23961,30042,40339 +17429,23962,30041,40239 +14084,23963,30040,40253 +11881,23964,30039,40686 +11964,23965,30038,40721 +13072,23966,30037,40804 +14620,23967,30036,40953 +16290,23968,30035,40699 +15123,23969,30034,40507 +17505,23970,30033,40951 +10958,23971,30032,40838 +12078,23972,30031,40506 +12263,23973,30030,40162 +12638,23974,30029,40276 +16903,23975,30028,40766 +14929,23976,30027,40023 +15249,23977,30026,40987 +13614,23978,30025,40392 +12514,23979,30024,40101 +11710,23980,30023,40153 +16316,23981,30022,40129 +11902,23982,30021,40252 +10412,23983,30020,40098 +18148,23984,30019,40618 +12144,23985,30018,40078 +11111,23986,30017,40146 +11052,23987,30016,40837 +13383,23988,30015,40053 +11386,23989,30014,40730 +13305,23990,30013,40653 +14772,23991,30012,40818 +17809,23992,30011,40422 +18018,23993,30010,40866 +12795,23994,30009,40221 +11066,23995,30008,40061 +15481,23996,30007,40197 +12323,23997,30006,40386 +11587,23998,30005,40208 +11243,23999,30004,40828 +17545,24000,30003,40299 +17705,24001,30002,40579 +16914,24002,30001,40330 +14220,24003,30000,40200 +17349,24004,31000,40450 +14041,24005,30999,40981 +13022,24006,30998,40437 +13099,24007,30997,40899 +16848,24008,30996,40280 +10309,24009,30995,40533 +10315,24010,30994,40089 +12368,24011,30993,40850 +16387,24012,30992,40140 +17243,24013,30991,40760 +16349,24014,30990,40357 +14913,24015,30989,40371 +17706,24016,30988,40231 +16991,24017,30987,40598 +16580,24018,30986,40235 +14420,24019,30985,40600 +17128,24020,30984,40301 +14910,24021,30983,40727 +11216,24022,30982,40288 +10003,24023,30981,40851 +14018,24024,30980,40993 +18109,24025,30979,40352 +16068,24026,30978,40344 +17860,24027,30977,40399 +12662,24028,30976,40403 +15494,24029,30975,40535 +15994,24030,30974,40638 +16286,24031,30973,40493 +11424,24032,30972,40013 +17938,24033,30971,40834 +17485,24034,30970,40442 +10857,24035,30969,40387 +13234,24036,30968,40257 +11451,24037,30967,40852 +15158,24038,30966,40168 +10665,24039,30965,40542 +13031,24040,30964,40996 +14593,24041,30963,40272 +15877,24042,30962,40287 +17477,24043,30961,40041 +13751,24044,30960,40974 +15588,24045,30959,40187 +14174,24046,30958,40855 +16465,24047,30957,40939 +13632,24048,30956,40879 +13510,24049,30955,40765 +14453,24050,30954,40905 +10232,24051,30953,40933 +12578,24052,30952,40539 +11793,24053,30951,40112 +15527,24054,30950,40483 +14613,24055,30949,40737 +14085,24056,30948,40895 +13063,24057,30947,40719 +12770,24058,30946,40897 +17278,24059,30945,40908 +15318,24060,30944,40321 +14462,24061,30943,40560 +13246,24062,30942,40276 +16318,24063,30941,40011 +17212,24064,30940,40547 +11574,24065,30939,40930 +17828,24066,30938,40230 +11388,24067,30937,40521 +14912,24068,30936,40511 +17014,24069,30935,40551 +12374,24070,30934,40820 +17758,24071,30933,40831 +17918,24072,30932,40876 +12285,24073,30931,40555 +13237,24074,30930,40922 +16011,24075,30929,40227 +10440,24076,30928,40495 +14697,24077,30927,40090 +14777,24078,30926,40330 +14959,24079,30925,40625 +10829,24080,30924,40939 +13723,24081,30923,40781 +18002,24082,30922,40141 +10269,24083,30921,40580 +13635,24084,30920,40305 +17906,24085,30919,40341 +14741,24086,30918,40831 +17613,24087,30917,40389 +15598,24088,30916,40336 +11387,24089,30915,40158 +10646,24090,30914,40783 +10169,24091,30913,40946 +10626,24092,30912,40269 +13095,24093,30911,40661 +11812,24094,30910,40532 +14793,24095,30909,40608 +15559,24096,30908,40515 +10744,24097,30907,40098 +14836,24098,30906,40048 +14391,24099,30905,40857 +17786,24100,30904,40741 +15269,24101,30903,40702 +16722,24102,30902,40481 +15448,24103,30901,40319 +15150,24104,30900,40830 +13946,24105,30899,40334 +17013,24106,30898,40018 +16451,24107,30897,40566 +15418,24108,30896,40815 +14853,24109,30895,40989 +13629,24110,30894,40862 +17424,24111,30893,40733 +16062,24112,30892,40729 +15290,24113,30891,40261 +10095,24114,30890,40173 +13515,24115,30889,40181 +10881,24116,30888,40350 +17944,24117,30887,40727 +14159,24118,30886,40244 +11860,24119,30885,40848 +14605,24120,30884,40956 +15287,24121,30883,40053 +15743,24122,30882,40665 +12565,24123,30881,40987 +15462,24124,30880,40713 +11430,24125,30879,40047 +10760,24126,30878,40428 +16175,24127,30877,40276 +12016,24128,30876,40951 +10057,24129,30875,40850 +11159,24130,30874,40647 +10435,24131,30873,40331 +12605,24132,30872,40049 +14695,24133,30871,40930 +15023,24134,30870,40455 +11571,24135,30869,40605 +12012,24136,30868,40500 +11775,24137,30867,40721 +10899,24138,30866,40176 +13926,24139,30865,40452 +14212,24140,30864,40207 +16176,24141,30863,40013 +17298,24142,30862,40467 +11029,24143,30861,40239 +15012,24144,30860,40362 +12727,24145,30859,40637 +14646,24146,30858,40635 +13520,24147,30857,40680 +17478,24148,30856,40914 +14301,24149,30855,40932 +14329,24150,30854,40707 +11360,24151,30853,40145 +17127,24152,30852,40099 +13408,24153,30851,40460 +10273,24154,30850,40561 +13681,24155,30849,40749 +10123,24156,30848,40196 +12057,24157,30847,40156 +17010,24158,30846,40150 +10486,24159,30845,40069 +13423,24160,30844,40718 +14325,24161,30843,40778 +13532,24162,30842,40028 +10306,24163,30841,40296 +14024,24164,30840,40605 +17400,24165,30839,40345 +16792,24166,30838,40766 +18177,24167,30837,40472 +15130,24168,30836,40405 +15742,24169,30835,40684 +12970,24170,30834,40082 +14765,24171,30833,40620 +16832,24172,30832,40901 +12304,24173,30831,40464 +13406,24174,30830,40154 +12775,24175,30829,40008 +15605,24176,30828,40079 +14907,24177,30827,40822 +11183,24178,30826,40510 +17517,24179,30825,40166 +17656,24180,30824,40837 +15557,24181,30823,40382 +14426,24182,30822,40123 +16870,24183,30821,40360 +17469,24184,30820,40293 +13154,24185,30819,40796 +17047,24186,30818,40454 +17848,24187,30817,40010 +16877,24188,30816,40246 +18126,24189,30815,40038 +14262,24190,30814,40905 +13558,24191,30813,40780 +13445,24192,30812,40600 +16266,24193,30811,40083 +13491,24194,30810,40901 +13201,24195,30809,40942 +12587,24196,30808,40207 +13150,24197,30807,40005 +17855,24198,30806,40870 +11984,24199,30805,40530 +18092,24200,30804,40400 +15817,24201,30803,40895 +10384,24202,30802,40418 +17138,24203,30801,40301 +12200,24204,30800,40042 +10339,24205,30799,40176 +15052,24206,30798,40185 +11206,24207,30797,40270 +10706,24208,30796,40622 +17320,24209,30795,40782 +10026,24210,30794,40110 +15489,24211,30793,40397 +16114,24212,30792,40767 +17406,24213,30791,40467 +17290,24214,30790,40299 +16961,24215,30789,40013 +12767,24216,30788,40291 +15294,24217,30787,40547 +18040,24218,30786,40009 +11122,24219,30785,40617 +15510,24220,30784,40247 +10514,24221,30783,40747 +11893,24222,30782,40349 +16684,24223,30781,40226 +14003,24224,30780,40837 +15515,24225,30779,40195 +17393,24226,30778,40419 +15191,24227,30777,40103 +12095,24228,30776,40249 +15983,24229,30775,40093 +17767,24230,30774,40039 +18138,24231,30773,40226 +13830,24232,30772,40007 +16710,24233,30771,40787 +17798,24234,30770,40895 +15594,24235,30769,40810 +15088,24236,30768,40423 +15737,24237,30767,40844 +15661,24238,30766,40370 +16747,24239,30765,40259 +16501,24240,30764,40457 +15337,24241,30763,40031 +14863,24242,30762,40443 +11528,24243,30761,40119 +15469,24244,30760,40689 +14345,24245,30759,40725 +11486,24246,30758,40917 +13316,24247,30757,40184 +16216,24248,30756,40611 +16155,24249,30755,40139 +11672,24250,30754,40416 +16213,24251,30753,40826 +10884,24252,30752,40167 +14439,24253,30751,40901 +13291,24254,30750,40627 +14288,24255,30749,40629 +11583,24256,30748,40334 +17629,24257,30747,40188 +12655,24258,30746,40407 +12945,24259,30745,40257 +12023,24260,30744,40754 +13809,24261,30743,40792 +15373,24262,30742,40546 +15208,24263,30741,40072 +18045,24264,30740,40930 +13577,24265,30739,40278 +13837,24266,30738,40041 +11951,24267,30737,40512 +17026,24268,30736,40555 +15031,24269,30735,40092 +13550,24270,30734,40444 +16729,24271,30733,40157 +11396,24272,30732,40911 +14418,24273,30731,40727 +11676,24274,30730,40477 +15726,24275,30729,40762 +15570,24276,30728,40713 +10332,24277,30727,40739 +11061,24278,30726,40040 +13379,24279,30725,40249 +10608,24280,30724,40519 +10471,24281,30723,40706 +17914,24282,30722,40228 +14294,24283,30721,40734 +10606,24284,30720,40142 +13613,24285,30719,40195 +16386,24286,30718,40209 +10320,24287,30717,40439 +11549,24288,30716,40129 +12461,24289,30715,40813 +13887,24290,30714,40264 +14414,24291,30713,40102 +16267,24292,30712,40570 +10264,24293,30711,40592 +12924,24294,30710,40165 +15420,24295,30709,40725 +11719,24296,30708,40375 +10585,24297,30707,40010 +17009,24298,30706,40656 +12714,24299,30705,40888 +15417,24300,30704,40230 +14094,24301,30703,40856 +16255,24302,30702,40182 +17742,24303,30701,40374 +15593,24304,30700,40864 +10008,24305,30699,40696 +10562,24306,30698,40628 +11658,24307,30697,40936 +16656,24308,30696,40377 +12405,24309,30695,40381 +10503,24310,30694,40261 +11827,24311,30693,40008 +13855,24312,30692,40150 +14308,24313,30691,40194 +14653,24314,30690,40086 +11652,24315,30689,40843 +11703,24316,30688,40141 +10270,24317,30687,40485 +11384,24318,30686,40112 +15181,24319,30685,40999 +14770,24320,30684,40376 +11906,24321,30683,40141 +13838,24322,30682,40782 +14828,24323,30681,40141 +11473,24324,30680,40474 +14981,24325,30679,40092 +17023,24326,30678,40890 +17414,24327,30677,40383 +10731,24328,30676,40583 +16610,24329,30675,40894 +14606,24330,30674,40476 +11284,24331,30673,40794 +14750,24332,30672,40120 +17024,24333,30671,40216 +11825,24334,30670,40666 +12330,24335,30669,40501 +11764,24336,30668,40180 +15553,24337,30667,40945 +14098,24338,30666,40440 +13250,24339,30665,40712 +16571,24340,30664,40904 +10859,24341,30663,40483 +13107,24342,30662,40626 +13994,24343,30661,40654 +17740,24344,30660,40087 +17177,24345,30659,40658 +17447,24346,30658,40669 +12161,24347,30657,40026 +16495,24348,30656,40426 +12071,24349,30655,40483 +12869,24350,30654,40025 +15073,24351,30653,40317 +12749,24352,30652,40985 +15006,24353,30651,40134 +10942,24354,30650,40465 +17439,24355,30649,40374 +15033,24356,30648,40648 +16796,24357,30647,40077 +10298,24358,30646,40608 +16177,24359,30645,40808 +14435,24360,30644,40083 +14671,24361,30643,40874 +15362,24362,30642,40509 +14608,24363,30641,40879 +13551,24364,30640,40161 +13073,24365,30639,40492 +15524,24366,30638,40808 +14029,24367,30637,40114 +14142,24368,30636,40755 +17986,24369,30635,40562 +16694,24370,30634,40362 +15340,24371,30633,40122 +16902,24372,30632,40438 +13457,24373,30631,40365 +16089,24374,30630,40776 +11506,24375,30629,40425 +16110,24376,30628,40189 +12920,24377,30627,40538 +15305,24378,30626,40952 +13278,24379,30625,40860 +14314,24380,30624,40287 +10426,24381,30623,40662 +15854,24382,30622,40587 +13059,24383,30621,40321 +16044,24384,30620,40430 +15142,24385,30619,40991 +14487,24386,30618,40169 +12765,24387,30617,40009 +16029,24388,30616,40501 +10997,24389,30615,40145 +12684,24390,30614,40991 +11375,24391,30613,40430 +11878,24392,30612,40337 +17701,24393,30611,40598 +13440,24394,30610,40411 +13719,24395,30609,40726 +11934,24396,30608,40329 +13349,24397,30607,40012 +11331,24398,30606,40198 +17876,24399,30605,40725 +14251,24400,30604,40182 +11227,24401,30603,40763 +12877,24402,30602,40897 +16633,24403,30601,40326 +18000,24404,30600,40075 +10713,24405,30599,40220 +11824,24406,30598,40880 +11363,24407,30597,40995 +10688,24408,30596,40277 +11869,24409,30595,40026 +11594,24410,30594,40985 +18124,24411,30593,40408 +15127,24412,30592,40675 +15946,24413,30591,40124 +14403,24414,30590,40341 +11012,24415,30589,40619 +15902,24416,30588,40918 +15485,24417,30587,40009 +10145,24418,30586,40654 +13507,24419,30585,40030 +10274,24420,30584,40082 +13210,24421,30583,40314 +11513,24422,30582,40999 +10742,24423,30581,40195 +12579,24424,30580,40531 +10539,24425,30579,40706 +10368,24426,30578,40759 +11941,24427,30577,40150 +11448,24428,30576,40144 +13254,24429,30575,40089 +13404,24430,30574,40813 +15912,24431,30573,40535 +13800,24432,30572,40675 +18020,24433,30571,40852 +10994,24434,30570,40500 +13464,24435,30569,40397 +10875,24436,30568,40567 +17266,24437,30567,40574 +16715,24438,30566,40001 +12354,24439,30565,40707 +11225,24440,30564,40032 +14823,24441,30563,40571 +17035,24442,30562,40615 +13556,24443,30561,40790 +11539,24444,30560,40166 +11133,24445,30559,40687 +17729,24446,30558,40897 +11953,24447,30557,40708 +13927,24448,30556,40665 +11244,24449,30555,40050 +14250,24450,30554,40696 +13511,24451,30553,40086 +12872,24452,30552,40366 +17702,24453,30551,40174 +11182,24454,30550,40592 +15090,24455,30549,40310 +15685,24456,30548,40040 +16374,24457,30547,40679 +18009,24458,30546,40599 +15852,24459,30545,40761 +10938,24460,30544,40327 +15985,24461,30543,40553 +15039,24462,30542,40278 +17405,24463,30541,40670 +14477,24464,30540,40156 +14081,24465,30539,40262 +16080,24466,30538,40557 +17937,24467,30537,40493 +17274,24468,30536,40938 +17599,24469,30535,40501 +10864,24470,30534,40562 +17446,24471,30533,40433 +14713,24472,30532,40030 +13714,24473,30531,40123 +12283,24474,30530,40203 +12249,24475,30529,40790 +12054,24476,30528,40072 +13725,24477,30527,40869 +10108,24478,30526,40054 +13295,24479,30525,40258 +11523,24480,30524,40600 +18008,24481,30523,40579 +14721,24482,30522,40408 +15184,24483,30521,40935 +12061,24484,30520,40089 +17785,24485,30519,40911 +13575,24486,30518,40355 +13123,24487,30517,40503 +10580,24488,30516,40688 +13559,24489,30515,40947 +13407,24490,30514,40789 +13000,24491,30513,40542 +12419,24492,30512,40477 +10404,24493,30511,40150 +13779,24494,30510,40095 +15225,24495,30509,40116 +12079,24496,30508,40056 +10521,24497,30507,40575 +12431,24498,30506,40563 +16560,24499,30505,40584 +15989,24500,30504,40605 +10712,24501,30503,40496 +13860,24502,30502,40189 +12938,24503,30501,40285 +11970,24504,30500,40344 +15375,24505,30499,40060 +13069,24506,30498,40355 +15378,24507,30497,40840 +10073,24508,30496,40873 +10276,24509,30495,40800 +17994,24510,30494,40733 +12410,24511,30493,40319 +11009,24512,30492,40457 +14990,24513,30491,40605 +10037,24514,30490,40636 +18057,24515,30489,40699 +15393,24516,30488,40675 +10824,24517,30487,40692 +17670,24518,30486,40494 +14936,24519,30485,40190 +14352,24520,30484,40099 +13118,24521,30483,40864 +14091,24522,30482,40128 +10186,24523,30481,40422 +10982,24524,30480,40201 +12308,24525,30479,40063 +15002,24526,30478,40794 +14598,24527,30477,40664 +14351,24528,30476,40871 +13085,24529,30475,40689 +16422,24530,30474,40463 +14934,24531,30473,40092 +11738,24532,30472,40222 +15040,24533,30471,40623 +12329,24534,30470,40993 +17055,24535,30469,40351 +16397,24536,30468,40109 +17203,24537,30467,40660 +15917,24538,30466,40632 +12761,24539,30465,40564 +11673,24540,30464,40505 +17846,24541,30463,40495 +12577,24542,30462,40980 +15976,24543,30461,40258 +12089,24544,30460,40253 +13918,24545,30459,40239 +11773,24546,30458,40054 +16138,24547,30457,40241 +14205,24548,30456,40132 +11720,24549,30455,40861 +11453,24550,30454,40235 +15674,24551,30453,40724 +13956,24552,30452,40721 +10323,24553,30451,40693 +16649,24554,30450,40520 +16508,24555,30449,40495 +15049,24556,30448,40917 +11420,24557,30447,40780 +11126,24558,30446,40278 +17529,24559,30445,40833 +12753,24560,30444,40497 +10197,24561,30443,40123 +11380,24562,30442,40711 +14841,24563,30441,40387 +15535,24564,30440,40927 +13686,24565,30439,40162 +16038,24566,30438,40886 +14115,24567,30437,40175 +14709,24568,30436,40245 +14446,24569,30435,40797 +16035,24570,30434,40347 +15699,24571,30433,40882 +16173,24572,30432,40673 +11578,24573,30431,40474 +11137,24574,30430,40076 +11716,24575,30429,40899 +14437,24576,30428,40021 +14044,24577,30427,40464 +13688,24578,30426,40677 +14353,24579,30425,40593 +17037,24580,30424,40156 +16962,24581,30423,40802 +15724,24582,30422,40232 +12657,24583,30421,40327 +16343,24584,30420,40819 +14180,24585,30419,40457 +16292,24586,30418,40229 +17903,24587,30417,40714 +16573,24588,30416,40616 +14859,24589,30415,40981 +10228,24590,30414,40203 +15276,24591,30413,40889 +12636,24592,30412,40958 +11921,24593,30411,40596 +17610,24594,30410,40844 +12096,24595,30409,40716 +12272,24596,30408,40711 +12989,24597,30407,40873 +17407,24598,30406,40157 +14720,24599,30405,40078 +14054,24600,30404,40959 +16680,24601,30403,40998 +12233,24602,30402,40739 +10120,24603,30401,40731 +17965,24604,30400,40255 +12999,24605,30399,40865 +14463,24606,30398,40366 +14095,24607,30397,40290 +14851,24608,30396,40992 +14148,24609,30395,40226 +12280,24610,30394,40241 +16553,24611,30393,40107 +16756,24612,30392,40611 +11842,24613,30391,40603 +17441,24614,30390,40607 +17308,24615,30389,40408 +18135,24616,30388,40799 +15799,24617,30387,40350 +17877,24618,30386,40271 +11015,24619,30385,40176 +16026,24620,30384,40378 +17826,24621,30383,40394 +15426,24622,30382,40041 +16458,24623,30381,40991 +17257,24624,30380,40214 +12736,24625,30379,40222 +10766,24626,30378,40903 +12292,24627,30377,40463 +17411,24628,30376,40486 +14460,24629,30375,40636 +13499,24630,30374,40140 +15070,24631,30373,40755 +14406,24632,30372,40237 +16969,24633,30371,40551 +16302,24634,30370,40415 +13148,24635,30369,40989 +17106,24636,30368,40741 +15999,24637,30367,40013 +12391,24638,30366,40185 +18106,24639,30365,40903 +16764,24640,30364,40509 +17915,24641,30363,40964 +16319,24642,30362,40786 +15993,24643,30361,40111 +15837,24644,30360,40050 +14849,24645,30359,40800 +11500,24646,30358,40479 +10782,24647,30357,40840 +14623,24648,30356,40495 +11629,24649,30355,40108 +17625,24650,30354,40495 +17096,24651,30353,40208 +17103,24652,30352,40964 +14049,24653,30351,40804 +12139,24654,30350,40392 +17586,24655,30349,40628 +16471,24656,30348,40010 +12070,24657,30347,40553 +16259,24658,30346,40286 +10224,24659,30345,40557 +16864,24660,30344,40932 +17141,24661,30343,40427 +10848,24662,30342,40325 +17995,24663,30341,40717 +13703,24664,30340,40871 +13436,24665,30339,40448 +11517,24666,30338,40945 +18115,24667,30337,40674 +10882,24668,30336,40626 +16434,24669,30335,40884 +14680,24670,30334,40461 +17093,24671,30333,40394 +14747,24672,30332,40150 +10437,24673,30331,40935 +10100,24674,30330,40856 +10178,24675,30329,40533 +16032,24676,30328,40663 +18003,24677,30327,40866 +15444,24678,30326,40120 +10132,24679,30325,40686 +11372,24680,30324,40017 +12131,24681,30323,40593 +17074,24682,30322,40035 +12777,24683,30321,40257 +14636,24684,30320,40908 +17698,24685,30319,40025 +16692,24686,30318,40873 +14433,24687,30317,40998 +12007,24688,30316,40968 +12816,24689,30315,40595 +11955,24690,30314,40355 +12441,24691,30313,40900 +16830,24692,30312,40145 +17310,24693,30311,40783 +11032,24694,30310,40958 +11377,24695,30309,40182 +11236,24696,30308,40715 +11072,24697,30307,40313 +12435,24698,30306,40064 +13847,24699,30305,40801 +12916,24700,30304,40206 +16599,24701,30303,40264 +13971,24702,30302,40985 +18131,24703,30301,40515 +16630,24704,30300,40699 +12291,24705,30299,40865 +17309,24706,30298,40668 +14173,24707,30297,40325 +11831,24708,30296,40740 +14634,24709,30295,40775 +11718,24710,30294,40667 +16608,24711,30293,40250 +12030,24712,30292,40751 +10946,24713,30291,40998 +10056,24714,30290,40389 +12747,24715,30289,40565 +17169,24716,30288,40588 +17675,24717,30287,40443 +12373,24718,30286,40546 +18027,24719,30285,40270 +16635,24720,30284,40210 +15908,24721,30283,40037 +12558,24722,30282,40349 +16915,24723,30281,40365 +16334,24724,30280,40197 +16045,24725,30279,40711 +18164,24726,30278,40865 +17362,24727,30277,40573 +16000,24728,30276,40602 +18055,24729,30275,40171 +13970,24730,30274,40205 +12086,24731,30273,40938 +11968,24732,30272,40449 +10554,24733,30271,40687 +11621,24734,30270,40672 +13025,24735,30269,40459 +10515,24736,30268,40738 +17318,24737,30267,40803 +13929,24738,30266,40780 +14349,24739,30265,40728 +15336,24740,30264,40736 +10641,24741,30263,40673 +14356,24742,30262,40502 +11560,24743,30261,40092 +17217,24744,30260,40144 +16322,24745,30259,40956 +15048,24746,30258,40932 +17759,24747,30257,40283 +14486,24748,30256,40786 +17254,24749,30255,40513 +17935,24750,30254,40693 +18160,24751,30253,40789 +17581,24752,30252,40863 +10577,24753,30251,40496 +14761,24754,30250,40516 +17025,24755,30249,40641 +11838,24756,30248,40720 +16939,24757,30247,40162 +16720,24758,30246,40581 +17813,24759,30245,40586 +16189,24760,30244,40533 +17722,24761,30243,40604 +13792,24762,30242,40174 +11778,24763,30241,40005 +13348,24764,30240,40427 +15190,24765,30239,40107 +10116,24766,30238,40055 +13027,24767,30237,40536 +14190,24768,30236,40620 +14448,24769,30235,40654 +11742,24770,30234,40386 +12742,24771,30233,40109 +17461,24772,30232,40203 +16201,24773,30231,40911 +12043,24774,30230,40442 +14047,24775,30229,40844 +12423,24776,30228,40524 +13934,24777,30227,40857 +16676,24778,30226,40520 +13736,24779,30225,40564 +12281,24780,30224,40936 +17746,24781,30223,40770 +12203,24782,30222,40657 +10390,24783,30221,40154 +14654,24784,30220,40022 +17130,24785,30219,40450 +15687,24786,30218,40968 +17954,24787,30217,40047 +16181,24788,30216,40939 +11864,24789,30215,40586 +16237,24790,30214,40402 +15980,24791,30213,40925 +17263,24792,30212,40835 +16773,24793,30211,40534 +14040,24794,30210,40860 +15975,24795,30209,40002 +12503,24796,30208,40308 +11844,24797,30207,40003 +11950,24798,30206,40431 +18129,24799,30205,40348 +13188,24800,30204,40066 +13966,24801,30203,40033 +12411,24802,30202,40156 +17376,24803,30201,40643 +13772,24804,30200,40685 +13444,24805,30199,40945 +11801,24806,30198,40240 +13570,24807,30197,40698 +16751,24808,30196,40660 +15238,24809,30195,40143 +13077,24810,30194,40481 +10362,24811,30193,40910 +16059,24812,30192,40861 +15503,24813,30191,40512 +12800,24814,30190,40606 +12912,24815,30189,40604 +10027,24816,30188,40977 +15516,24817,30187,40373 +13054,24818,30186,40874 +13280,24819,30185,40966 +10235,24820,30184,40021 +12352,24821,30183,40222 +12904,24822,30182,40640 +15940,24823,30181,40487 +11796,24824,30180,40403 +13818,24825,30179,40720 +13220,24826,30178,40680 +16295,24827,30177,40170 +13505,24828,30176,40501 +15440,24829,30175,40519 +16378,24830,30174,40777 +13350,24831,30173,40398 +13765,24832,30172,40362 +14711,24833,30171,40796 +14953,24834,30170,40468 +10386,24835,30169,40204 +12318,24836,30168,40934 +16983,24837,30167,40439 +17040,24838,30166,40295 +16304,24839,30165,40455 +16157,24840,30164,40158 +14322,24841,30163,40501 +12914,24842,30162,40391 +14986,24843,30161,40330 +15471,24844,30160,40489 +13371,24845,30159,40627 +15146,24846,30158,40092 +12091,24847,30157,40333 +13955,24848,30156,40992 +12801,24849,30155,40952 +11070,24850,30154,40136 +16785,24851,30153,40728 +15702,24852,30152,40749 +12220,24853,30151,40071 +12624,24854,30150,40144 +10237,24855,30149,40862 +11075,24856,30148,40039 +14320,24857,30147,40658 +11898,24858,30146,40865 +10699,24859,30145,40059 +17708,24860,30144,40636 +14249,24861,30143,40751 +10119,24862,30142,40763 +12564,24863,30141,40974 +10142,24864,30140,40142 +11685,24865,30139,40070 +10152,24866,30138,40257 +14928,24867,30137,40047 +13732,24868,30136,40815 +13370,24869,30135,40097 +14682,24870,30134,40335 +14230,24871,30133,40833 +15614,24872,30132,40796 +13103,24873,30131,40275 +17886,24874,30130,40002 +16886,24875,30129,40273 +18112,24876,30128,40532 +13752,24877,30127,40449 +14150,24878,30126,40931 +17840,24879,30125,40172 +17866,24880,30124,40409 +12952,24881,30123,40171 +10399,24882,30122,40468 +13679,24883,30121,40565 +17664,24884,30120,40885 +12412,24885,30119,40067 +17162,24886,30118,40728 +11105,24887,30117,40164 +16529,24888,30116,40342 +17765,24889,30115,40444 +17815,24890,30114,40678 +17528,24891,30113,40759 +12341,24892,30112,40483 +14078,24893,30111,40412 +12126,24894,30110,40151 +15692,24895,30109,40700 +13764,24896,30108,40349 +12002,24897,30107,40794 +12693,24898,30106,40179 +13717,24899,30105,40172 +16416,24900,30104,40102 +14027,24901,30103,40887 +10814,24902,30102,40304 +10987,24903,30101,40642 +10036,24904,30100,40740 +16858,24905,30099,40841 +11503,24906,30098,40378 +14141,24907,30097,40305 +16082,24908,30096,40910 +10764,24909,30095,40419 +13438,24910,30094,40051 +13096,24911,30093,40306 +15311,24912,30092,40317 +14630,24913,30091,40526 +16116,24914,30090,40596 +15945,24915,30089,40779 +16871,24916,30088,40772 +17197,24917,30087,40227 +13452,24918,30086,40578 +12678,24919,30085,40296 +11385,24920,30084,40689 +17987,24921,30083,40718 +12600,24922,30082,40585 +13942,24923,30081,40141 +17619,24924,30080,40753 +15876,24925,30079,40292 +13222,24926,30078,40740 +10586,24927,30077,40480 +13011,24928,30076,40303 +15950,24929,30075,40677 +15464,24930,30074,40642 +17357,24931,30073,40300 +10400,24932,30072,40213 +10136,24933,30071,40346 +17082,24934,30070,40866 +17276,24935,30069,40617 +13557,24936,30068,40816 +14265,24937,30067,40191 +13273,24938,30066,40000 +17686,24939,30065,40468 +16661,24940,30064,40256 +12569,24941,30063,40762 +17516,24942,30062,40548 +14878,24943,30061,40373 +16690,24944,30060,40365 +11188,24945,30059,40225 +15240,24946,30058,40810 +14733,24947,30057,40715 +13283,24948,30056,40523 +17244,24949,30055,40296 +10704,24950,30054,40852 +13880,24951,30053,40897 +18167,24952,30052,40598 +16368,24953,30051,40536 +17716,24954,30050,40641 +13321,24955,30049,40964 +14285,24956,30048,40190 +11674,24957,30047,40345 +17558,24958,30046,40122 +12711,24959,30045,40283 +11625,24960,30044,40084 +12432,24961,30043,40624 +14189,24962,30042,40383 +18065,24963,30041,40997 +11426,24964,30040,40474 +16655,24965,30039,40385 +12589,24966,30038,40765 +13082,24967,30037,40414 +12123,24968,30036,40143 +14945,24969,30035,40781 +16121,24970,30034,40482 +16679,24971,30033,40833 +13869,24972,30032,40272 +10551,24973,30031,40020 +11462,24974,30030,40895 +13006,24975,30029,40598 +15765,24976,30028,40303 +10007,24977,30027,40525 +16413,24978,30026,40581 +15998,24979,30025,40102 +12617,24980,30024,40392 +16703,24981,30023,40416 +10675,24982,30022,40152 +14523,24983,30021,40849 +10874,24984,30020,40830 +11489,24985,30019,40899 +14328,24986,30018,40727 +15021,24987,30017,40246 +13434,24988,30016,40202 +15613,24989,30015,40729 +11803,24990,30014,40161 +16144,24991,30013,40259 +11841,24992,30012,40068 +12840,24993,30011,40116 +13043,24994,30010,40728 +10292,24995,30009,40129 +11017,24996,30008,40087 +10059,24997,30007,40307 +15071,24998,30006,40209 +15369,24999,30005,40977 +10507,25000,30004,40521 +16256,25001,30003,40700 +16243,25002,30002,40506 +10350,25003,30001,40976 +11757,25004,30000,40712 +11223,25005,31000,40211 +11172,25006,30999,40227 +15285,25007,30998,40126 +15102,25008,30997,40389 +16659,25009,30996,40216 +13906,25010,30995,40045 +10612,25011,30994,40954 +12393,25012,30993,40548 +10797,25013,30992,40309 +15957,25014,30991,40061 +10468,25015,30990,40335 +12832,25016,30989,40042 +14427,25017,30988,40093 +11597,25018,30987,40281 +14802,25019,30986,40539 +12361,25020,30985,40181 +10045,25021,30984,40718 +17947,25022,30983,40625 +15106,25023,30982,40002 +11675,25024,30981,40839 +17092,25025,30980,40151 +12076,25026,30979,40999 +12252,25027,30978,40918 +12320,25028,30977,40515 +15675,25029,30976,40258 +12110,25030,30975,40703 +16061,25031,30974,40354 +13259,25032,30973,40358 +12865,25033,30972,40579 +17484,25034,30971,40655 +18152,25035,30970,40473 +12671,25036,30969,40854 +11019,25037,30968,40478 +15350,25038,30967,40839 +16235,25039,30966,40380 +13960,25040,30965,40342 +15221,25041,30964,40676 +15099,25042,30963,40450 +17875,25043,30962,40745 +14911,25044,30961,40568 +17700,25045,30960,40654 +10925,25046,30959,40731 +13399,25047,30958,40228 +16339,25048,30957,40537 +17005,25049,30956,40696 +12581,25050,30955,40192 +11495,25051,30954,40769 +12268,25052,30953,40496 +17996,25053,30952,40215 +16522,25054,30951,40546 +11109,25055,30950,40839 +15697,25056,30949,40310 +12051,25057,30948,40163 +14000,25058,30947,40947 +11435,25059,30946,40462 +17737,25060,30945,40566 +16593,25061,30944,40301 +14014,25062,30943,40549 +16260,25063,30942,40185 +11570,25064,30941,40174 +16518,25065,30940,40585 +12476,25066,30939,40113 +12651,25067,30938,40141 +14068,25068,30937,40012 +15089,25069,30936,40477 +10268,25070,30935,40781 +11640,25071,30934,40111 +16709,25072,30933,40570 +11033,25073,30932,40528 +10160,25074,30931,40460 +14300,25075,30930,40666 +12621,25076,30929,40378 +10588,25077,30928,40259 +10789,25078,30927,40250 +13896,25079,30926,40270 +10262,25080,30925,40562 +12625,25081,30924,40147 +17658,25082,30923,40117 +17637,25083,30922,40457 +10293,25084,30921,40097 +12760,25085,30920,40484 +17499,25086,30919,40565 +13996,25087,30918,40210 +10448,25088,30917,40343 +17552,25089,30916,40079 +11649,25090,30915,40627 +15695,25091,30914,40968 +11510,25092,30913,40368 +12846,25093,30912,40692 +15459,25094,30911,40325 +13067,25095,30910,40751 +16650,25096,30909,40593 +15177,25097,30908,40680 +11750,25098,30907,40848 +15327,25099,30906,40946 +10114,25100,30905,40833 +10774,25101,30904,40208 +12528,25102,30903,40636 +11027,25103,30902,40345 +13320,25104,30901,40657 +10275,25105,30900,40924 +17115,25106,30899,40076 +17322,25107,30898,40789 +13944,25108,30897,40580 +16047,25109,30896,40860 +10851,25110,30895,40459 +11900,25111,30894,40695 +10476,25112,30893,40535 +14307,25113,30892,40814 +15964,25114,30891,40895 +15065,25115,30890,40620 +17268,25116,30889,40042 +16598,25117,30888,40197 +14914,25118,30887,40168 +16521,25119,30886,40547 +13600,25120,30885,40756 +13439,25121,30884,40707 +15722,25122,30883,40017 +14017,25123,30882,40148 +10325,25124,30881,40626 +15896,25125,30880,40247 +13542,25126,30879,40742 +13373,25127,30878,40578 +17731,25128,30877,40192 +10299,25129,30876,40207 +12834,25130,30875,40372 +16911,25131,30874,40890 +16908,25132,30873,40630 +17102,25133,30872,40815 +14867,25134,30871,40940 +14327,25135,30870,40601 +17125,25136,30869,40764 +16766,25137,30868,40736 +13306,25138,30867,40760 +15122,25139,30866,40746 +13187,25140,30865,40917 +18043,25141,30864,40706 +15394,25142,30863,40380 +12055,25143,30862,40821 +13743,25144,30861,40103 +15250,25145,30860,40561 +15974,25146,30859,40637 +16511,25147,30858,40808 +16890,25148,30857,40457 +17692,25149,30856,40986 +11441,25150,30855,40621 +16238,25151,30854,40474 +10977,25152,30853,40468 +10494,25153,30852,40791 +13264,25154,30851,40356 +11371,25155,30850,40282 +14509,25156,30849,40954 +15087,25157,30848,40623 +10388,25158,30847,40000 +17442,25159,30846,40372 +17823,25160,30845,40906 +17607,25161,30844,40086 +12526,25162,30843,40694 +10143,25163,30842,40387 +16353,25164,30841,40561 +10535,25165,30840,40003 +17615,25166,30839,40382 +17687,25167,30838,40848 +17990,25168,30837,40937 +10506,25169,30836,40844 +11088,25170,30835,40594 +17482,25171,30834,40417 +13879,25172,30833,40013 +12772,25173,30832,40403 +13952,25174,30831,40622 +16407,25175,30830,40202 +15353,25176,30829,40603 +12784,25177,30828,40172 +15660,25178,30827,40025 +14891,25179,30826,40303 +10297,25180,30825,40648 +15001,25181,30824,40372 +11815,25182,30823,40211 +11062,25183,30822,40103 +15745,25184,30821,40975 +16880,25185,30820,40699 +14618,25186,30819,40349 +11004,25187,30818,40434 +15748,25188,30817,40482 +10583,25189,30816,40322 +11895,25190,30815,40179 +16977,25191,30814,40740 +13935,25192,30813,40294 +14388,25193,30812,40693 +17669,25194,30811,40716 +18005,25195,30810,40271 +16102,25196,30809,40787 +17980,25197,30808,40954 +13932,25198,30807,40504 +14775,25199,30806,40476 +16452,25200,30805,40337 +11928,25201,30804,40320 +17348,25202,30803,40873 +15182,25203,30802,40786 +11483,25204,30801,40188 +16152,25205,30800,40160 +15814,25206,30799,40634 +16106,25207,30798,40453 +12898,25208,30797,40945 +16562,25209,30796,40095 +16357,25210,30795,40162 +12559,25211,30794,40864 +14281,25212,30793,40238 +15252,25213,30792,40025 +17885,25214,30791,40466 +10852,25215,30790,40114 +18054,25216,30789,40325 +14111,25217,30788,40063 +13064,25218,30787,40626 +15565,25219,30786,40989 +11936,25220,30785,40249 +17264,25221,30784,40394 +16758,25222,30783,40063 +10754,25223,30782,40593 +12297,25224,30781,40238 +11630,25225,30780,40653 +12762,25226,30779,40256 +13639,25227,30778,40997 +12704,25228,30777,40069 +16584,25229,30776,40926 +15288,25230,30775,40676 +11697,25231,30774,40910 +13631,25232,30773,40077 +13822,25233,30772,40836 +12439,25234,30771,40677 +16645,25235,30770,40398 +11347,25236,30769,40499 +12344,25237,30768,40162 +10030,25238,30767,40575 +17967,25239,30766,40166 +13385,25240,30765,40250 +12893,25241,30764,40803 +12859,25242,30763,40161 +15272,25243,30762,40451 +15703,25244,30761,40099 +17219,25245,30760,40635 +17342,25246,30759,40874 +18114,25247,30758,40580 +10573,25248,30757,40414 +10943,25249,30756,40700 +12093,25250,30755,40068 +12456,25251,30754,40393 +16251,25252,30753,40982 +16973,25253,30752,40261 +13152,25254,30751,40357 +10101,25255,30750,40165 +13117,25256,30749,40025 +17426,25257,30748,40356 +11879,25258,30747,40321 +14824,25259,30746,40173 +13053,25260,30745,40501 +11721,25261,30744,40046 +12460,25262,30743,40616 +17911,25263,30742,40463 +13972,25264,30741,40564 +16665,25265,30740,40265 +12115,25266,30739,40110 +16952,25267,30738,40147 +12083,25268,30737,40136 +15717,25269,30736,40392 +15868,25270,30735,40045 +10676,25271,30734,40861 +13323,25272,30733,40855 +11961,25273,30732,40246 +13989,25274,30731,40060 +14580,25275,30730,40856 +17337,25276,30729,40671 +13545,25277,30728,40697 +17760,25278,30727,40275 +15308,25279,30726,40220 +11112,25280,30725,40194 +13904,25281,30724,40312 +10447,25282,30723,40796 +10032,25283,30722,40576 +14868,25284,30721,40379 +10210,25285,30720,40653 +15762,25286,30719,40331 +12449,25287,30718,40472 +16642,25288,30717,40815 +15715,25289,30716,40284 +12195,25290,30715,40303 +10558,25291,30714,40295 +11250,25292,30713,40645 +11846,25293,30712,40969 +13070,25294,30711,40542 +10500,25295,30710,40118 +10536,25296,30709,40222 +17066,25297,30708,40726 +17208,25298,30707,40988 +15284,25299,30706,40803 +11888,25300,30705,40701 +10885,25301,30704,40426 +13202,25302,30703,40188 +14432,25303,30702,40186 +16831,25304,30701,40471 +16581,25305,30700,40802 +11155,25306,30699,40588 +16084,25307,30698,40191 +14089,25308,30697,40955 +15751,25309,30696,40387 +11129,25310,30695,40053 +17304,25311,30694,40993 +13762,25312,30693,40738 +11611,25313,30692,40941 +13483,25314,30691,40721 +14374,25315,30690,40753 +10915,25316,30689,40648 +11139,25317,30688,40905 +13636,25318,30687,40979 +15015,25319,30686,40504 +10865,25320,30685,40961 +10457,25321,30684,40236 +17131,25322,30683,40674 +14737,25323,30682,40100 +17343,25324,30681,40620 +15376,25325,30680,40617 +12991,25326,30679,40221 +12631,25327,30678,40506 +11931,25328,30677,40307 +18151,25329,30676,40954 +12926,25330,30675,40143 +10172,25331,30674,40085 +10846,25332,30673,40960 +17585,25333,30672,40432 +12417,25334,30671,40596 +12156,25335,30670,40341 +11209,25336,30669,40369 +12480,25337,30668,40902 +12020,25338,30667,40610 +10483,25339,30666,40753 +10434,25340,30665,40173 +10185,25341,30664,40049 +10827,25342,30663,40001 +11715,25343,30662,40533 +14877,25344,30661,40973 +15084,25345,30660,40546 +10023,25346,30659,40307 +10146,25347,30658,40076 +16869,25348,30657,40315 +17753,25349,30656,40361 +17519,25350,30655,40020 +13297,25351,30654,40222 +11986,25352,30653,40533 +16928,25353,30652,40235 +14087,25354,30651,40762 +16968,25355,30650,40418 +16394,25356,30649,40578 +12799,25357,30648,40654 +14946,25358,30647,40941 +13309,25359,30646,40981 +11403,25360,30645,40099 +11650,25361,30644,40471 +12125,25362,30643,40104 +16820,25363,30642,40545 +15802,25364,30641,40707 +11189,25365,30640,40490 +11342,25366,30639,40125 +17036,25367,30638,40639 +14219,25368,30637,40367 +15322,25369,30636,40337 +17356,25370,30635,40709 +16119,25371,30634,40628 +16866,25372,30633,40831 +12562,25373,30632,40779 +16805,25374,30631,40093 +17359,25375,30630,40967 +14641,25376,30629,40218 +11068,25377,30628,40223 +17171,25378,30627,40298 +13194,25379,30626,40969 +10482,25380,30625,40949 +16702,25381,30624,40558 +13548,25382,30623,40285 +12779,25383,30622,40923 +16363,25384,30621,40932 +11988,25385,30620,40995 +13189,25386,30619,40327 +13277,25387,30618,40355 +11028,25388,30617,40159 +16719,25389,30616,40934 +13433,25390,30615,40686 +16623,25391,30614,40598 +17043,25392,30613,40654 +15761,25393,30612,40532 +14363,25394,30611,40109 +11829,25395,30610,40231 +13907,25396,30609,40397 +15468,25397,30608,40768 +12545,25398,30607,40088 +12413,25399,30606,40918 +16193,25400,30605,40832 +14645,25401,30604,40589 +10372,25402,30603,40516 +15053,25403,30602,40738 +15334,25404,30601,40495 +17109,25405,30600,40089 +11125,25406,30599,40123 +15038,25407,30598,40119 +17134,25408,30597,40155 +14499,25409,30596,40316 +16673,25410,30595,40598 +12601,25411,30594,40488 +15054,25412,30593,40847 +13432,25413,30592,40390 +10603,25414,30591,40552 +11989,25415,30590,40350 +15646,25416,30589,40887 +15532,25417,30588,40828 +14901,25418,30587,40697 +14718,25419,30586,40725 +15352,25420,30585,40195 +11288,25421,30584,40978 +10041,25422,30583,40984 +14818,25423,30582,40774 +10346,25424,30581,40413 +14838,25425,30580,40713 +14817,25426,30579,40024 +17821,25427,30578,40743 +11455,25428,30577,40070 +17907,25429,30576,40611 +13993,25430,30575,40595 +10086,25431,30574,40932 +15342,25432,30573,40196 +13218,25433,30572,40194 +17430,25434,30571,40657 +16897,25435,30570,40617 +12190,25436,30569,40143 +12584,25437,30568,40020 +11680,25438,30567,40002 +10046,25439,30566,40566 +14854,25440,30565,40127 +10147,25441,30564,40161 +11628,25442,30563,40935 +14847,25443,30562,40297 +15873,25444,30561,40463 +14385,25445,30560,40178 +12867,25446,30559,40805 +10566,25447,30558,40942 +10015,25448,30557,40829 +10560,25449,30556,40340 +12422,25450,30555,40225 +15427,25451,30554,40706 +13961,25452,30553,40343 +12447,25453,30552,40483 +13595,25454,30551,40908 +13419,25455,30550,40147 +16984,25456,30549,40070 +12075,25457,30548,40095 +15787,25458,30547,40175 +17129,25459,30546,40665 +17726,25460,30545,40870 +10104,25461,30544,40649 +14753,25462,30543,40112 +17108,25463,30542,40176 +12980,25464,30541,40788 +12216,25465,30540,40190 +15709,25466,30539,40771 +13962,25467,30538,40283 +13300,25468,30537,40654 +12222,25469,30536,40274 +16510,25470,30535,40922 +14304,25471,30534,40250 +11221,25472,30533,40934 +15586,25473,30532,40966 +10184,25474,30531,40861 +13090,25475,30530,40500 +10790,25476,30529,40687 +12647,25477,30528,40067 +10383,25478,30527,40482 +11296,25479,30526,40069 +17182,25480,30525,40774 +13572,25481,30524,40932 +13700,25482,30523,40357 +10354,25483,30522,40745 +12333,25484,30521,40553 +10470,25485,30520,40671 +12496,25486,30519,40392 +15443,25487,30518,40950 +15377,25488,30517,40827 +18098,25489,30516,40372 +13884,25490,30515,40388 +10572,25491,30514,40206 +18072,25492,30513,40493 +16763,25493,30512,40308 +11357,25494,30511,40030 +12056,25495,30510,40450 +14069,25496,30509,40814 +16494,25497,30508,40074 +14021,25498,30507,40467 +15963,25499,30506,40895 +11834,25500,30505,40444 +16228,25501,30504,40269 +15569,25502,30503,40723 +13351,25503,30502,40772 +16347,25504,30501,40368 +17922,25505,30500,40492 +12328,25506,30499,40241 +10722,25507,30498,40386 +15879,25508,30497,40798 +10749,25509,30496,40448 +14576,25510,30495,40272 +18063,25511,30494,40154 +16744,25512,30493,40226 +17159,25513,30492,40853 +14225,25514,30491,40159 +10600,25515,30490,40978 +11327,25516,30489,40643 +10751,25517,30488,40336 +14367,25518,30487,40174 +15072,25519,30486,40160 +13052,25520,30485,40323 +14048,25521,30484,40402 +10745,25522,30483,40054 +16103,25523,30482,40044 +16284,25524,30481,40772 +17952,25525,30480,40091 +16111,25526,30479,40453 +15321,25527,30478,40626 +13667,25528,30477,40020 +14279,25529,30476,40423 +14993,25530,30475,40575 +13995,25531,30474,40333 +16081,25532,30473,40025 +11192,25533,30472,40276 +15194,25534,30471,40989 +11729,25535,30470,40125 +17991,25536,30469,40126 +15623,25537,30468,40641 +14232,25538,30467,40721 +13678,25539,30466,40730 +14622,25540,30465,40804 +17510,25541,30464,40241 +10985,25542,30463,40944 +12694,25543,30462,40085 +16225,25544,30461,40825 +15149,25545,30460,40629 +17902,25546,30459,40206 +17793,25547,30458,40133 +12954,25548,30457,40476 +12404,25549,30456,40549 +15173,25550,30455,40821 +16037,25551,30454,40632 +12142,25552,30453,40710 +13116,25553,30452,40303 +14143,25554,30451,40638 +15855,25555,30450,40205 +12664,25556,30449,40817 +16803,25557,30448,40966 +12050,25558,30447,40837 +13508,25559,30446,40920 +11205,25560,30445,40900 +16812,25561,30444,40260 +16362,25562,30443,40928 +11474,25563,30442,40502 +16348,25564,30441,40814 +11497,25565,30440,40351 +13654,25566,30439,40888 +11632,25567,30438,40860 +13159,25568,30437,40870 +17098,25569,30436,40375 +15714,25570,30435,40103 +17843,25571,30434,40531 +10265,25572,30433,40337 +16112,25573,30432,40254 +17777,25574,30431,40496 +15455,25575,30430,40407 +11361,25576,30429,40779 +11800,25577,30428,40950 +14246,25578,30427,40986 +12663,25579,30426,40363 +14317,25580,30425,40820 +12998,25581,30424,40046 +13702,25582,30423,40493 +16845,25583,30422,40373 +17781,25584,30421,40876 +16556,25585,30420,40069 +16638,25586,30419,40570 +14673,25587,30418,40376 +13032,25588,30417,40910 +16564,25589,30416,40773 +14679,25590,30415,40006 +15100,25591,30414,40893 +17451,25592,30413,40184 +12996,25593,30412,40208 +15585,25594,30411,40439 +17946,25595,30410,40320 +11505,25596,30409,40977 +12385,25597,30408,40766 +16882,25598,30407,40093 +11553,25599,30406,40649 +15212,25600,30405,40970 +10599,25601,30404,40829 +12309,25602,30403,40986 +16621,25603,30402,40383 +16714,25604,30401,40109 +17858,25605,30400,40823 +15256,25606,30399,40930 +14497,25607,30398,40366 +16172,25608,30397,40392 +11663,25609,30396,40863 +12137,25610,30395,40971 +11138,25611,30394,40914 +17678,25612,30393,40243 +17455,25613,30392,40707 +14152,25614,30391,40262 +11457,25615,30390,40321 +14692,25616,30389,40173 +13231,25617,30388,40547 +10952,25618,30387,40579 +17810,25619,30386,40957 +16268,25620,30385,40170 +16762,25621,30384,40784 +12939,25622,30383,40968 +15526,25623,30382,40543 +17011,25624,30381,40815 +14236,25625,30380,40445 +10909,25626,30379,40107 +16145,25627,30378,40557 +12433,25628,30377,40252 +15309,25629,30376,40297 +11040,25630,30375,40443 +14751,25631,30374,40924 +16449,25632,30373,40328 +16538,25633,30372,40347 +14071,25634,30371,40554 +17845,25635,30370,40973 +16257,25636,30369,40632 +11786,25637,30368,40052 +12982,25638,30367,40869 +11471,25639,30366,40876 +16927,25640,30365,40265 +11765,25641,30364,40888 +15856,25642,30363,40489 +17487,25643,30362,40604 +16218,25644,30361,40905 +10662,25645,30360,40708 +13036,25646,30359,40288 +15019,25647,30358,40971 +15371,25648,30357,40281 +13875,25649,30356,40225 +12394,25650,30355,40466 +11866,25651,30354,40852 +12843,25652,30353,40733 +16134,25653,30352,40639 +15936,25654,30351,40348 +18140,25655,30350,40136 +12701,25656,30349,40609 +11199,25657,30348,40914 +14744,25658,30347,40811 +14443,25659,30346,40699 +10411,25660,30345,40669 +12958,25661,30344,40184 +15916,25662,30343,40041 +13390,25663,30342,40613 +10666,25664,30341,40058 +15413,25665,30340,40073 +14657,25666,30339,40863 +13405,25667,30338,40093 +13865,25668,30337,40499 +15547,25669,30336,40389 +18067,25670,30335,40801 +13200,25671,30334,40327 +15037,25672,30333,40996 +17481,25673,30332,40041 +11219,25674,30331,40269 +12455,25675,30330,40551 +18105,25676,30329,40278 +17409,25677,30328,40530 +13393,25678,30327,40315 +11449,25679,30326,40388 +13386,25680,30325,40704 +17124,25681,30324,40335 +16781,25682,30323,40901 +18076,25683,30322,40341 +17027,25684,30321,40839 +16468,25685,30320,40378 +15214,25686,30319,40784 +17962,25687,30318,40118 +12882,25688,30317,40470 +14554,25689,30316,40159 +11045,25690,30315,40257 +12080,25691,30314,40796 +13285,25692,30313,40606 +14677,25693,30312,40300 +13567,25694,30311,40801 +11477,25695,30310,40604 +13664,25696,30309,40487 +17069,25697,30308,40215 +14278,25698,30307,40337 +17924,25699,30306,40208 +11169,25700,30305,40685 +12176,25701,30304,40171 +17453,25702,30303,40582 +14880,25703,30302,40841 +18133,25704,30301,40563 +10455,25705,30300,40362 +16226,25706,30299,40893 +14160,25707,30298,40477 +16052,25708,30297,40002 +12219,25709,30296,40395 +14963,25710,30295,40375 +11705,25711,30294,40714 +15389,25712,30293,40163 +10905,25713,30292,40165 +17344,25714,30291,40030 +16624,25715,30290,40161 +15678,25716,30289,40184 +14025,25717,30288,40554 +17235,25718,30287,40190 +12160,25719,30286,40475 +15781,25720,30285,40871 +17460,25721,30284,40013 +13196,25722,30283,40884 +10069,25723,30282,40319 +12466,25724,30281,40630 +18011,25725,30280,40227 +15219,25726,30279,40250 +13891,25727,30278,40713 +16929,25728,30277,40839 +17372,25729,30276,40461 +12506,25730,30275,40233 +12918,25731,30274,40692 +10166,25732,30273,40245 +15833,25733,30272,40188 +16696,25734,30271,40796 +10591,25735,30270,40849 +14957,25736,30269,40253 +15135,25737,30268,40579 +17597,25738,30267,40115 +15076,25739,30266,40669 +13443,25740,30265,40190 +10403,25741,30264,40289 +10029,25742,30263,40053 +11315,25743,30262,40542 +10194,25744,30261,40617 +14746,25745,30260,40636 +14649,25746,30259,40388 +14132,25747,30258,40086 +10463,25748,30257,40128 +10530,25749,30256,40086 +11359,25750,30255,40917 +15265,25751,30254,40470 +17004,25752,30253,40834 +11712,25753,30252,40306 +10389,25754,30251,40989 +12168,25755,30250,40180 +15911,25756,30249,40373 +13360,25757,30248,40663 +10929,25758,30247,40364 +16107,25759,30246,40213 +13396,25760,30245,40587 +13253,25761,30244,40716 +12510,25762,30243,40365 +12607,25763,30242,40523 +15093,25764,30241,40093 +15813,25765,30240,40002 +14578,25766,30239,40788 +13549,25767,30238,40167 +14121,25768,30237,40106 +10844,25769,30236,40053 +10759,25770,30235,40782 +11401,25771,30234,40807 +14659,25772,30233,40160 +10225,25773,30232,40923 +14043,25774,30231,40772 +12838,25775,30230,40417 +16018,25776,30229,40017 +10526,25777,30228,40842 +15316,25778,30227,40143 +10716,25779,30226,40134 +14638,25780,30225,40632 +13084,25781,30224,40549 +13677,25782,30223,40949 +12370,25783,30222,40471 +17806,25784,30221,40945 +13191,25785,30220,40328 +17724,25786,30219,40458 +10479,25787,30218,40307 +13517,25788,30217,40907 +15128,25789,30216,40559 +11664,25790,30215,40847 +14062,25791,30214,40735 +10421,25792,30213,40841 +16769,25793,30212,40690 +10780,25794,30211,40399 +14394,25795,30210,40339 +12771,25796,30209,40628 +14046,25797,30208,40684 +13903,25798,30207,40900 +15192,25799,30206,40459 +16262,25800,30205,40026 +17749,25801,30204,40263 +12306,25802,30203,40086 +17184,25803,30202,40291 +12450,25804,30201,40162 +11319,25805,30200,40040 +11911,25806,30199,40531 +13521,25807,30198,40266 +16109,25808,30197,40325 +11255,25809,30196,40105 +17311,25810,30195,40431 +15416,25811,30194,40135 +11168,25812,30193,40286 +14932,25813,30192,40209 +16462,25814,30191,40838 +16686,25815,30190,40927 +13046,25816,30189,40858 +12551,25817,30188,40413 +10179,25818,30187,40772 +10775,25819,30186,40188 +14667,25820,30185,40385 +12298,25821,30184,40107 +17034,25822,30183,40084 +15406,25823,30182,40214 +18130,25824,30181,40642 +17148,25825,30180,40113 +15013,25826,30179,40341 +16677,25827,30178,40366 +11971,25828,30177,40634 +10278,25829,30176,40010 +13843,25830,30175,40870 +12376,25831,30174,40077 +12507,25832,30173,40805 +16466,25833,30172,40336 +11229,25834,30171,40259 +10973,25835,30170,40353 +16200,25836,30169,40579 +14948,25837,30168,40394 +18064,25838,30167,40612 +14096,25839,30166,40081 +13233,25840,30165,40732 +13038,25841,30164,40632 +13957,25842,30163,40661 +14238,25843,30162,40355 +12550,25844,30161,40964 +14616,25845,30160,40481 +12786,25846,30159,40664 +12682,25847,30158,40252 +11407,25848,30157,40135 +10837,25849,30156,40283 +14924,25850,30155,40508 +16326,25851,30154,40735 +14790,25852,30153,40997 +10951,25853,30152,40707 +11395,25854,30151,40297 +11338,25855,30150,40972 +12188,25856,30149,40119 +16311,25857,30148,40256 +15539,25858,30147,40713 +14241,25859,30146,40947 +13288,25860,30145,40031 +17562,25861,30144,40916 +11701,25862,30143,40056 +15395,25863,30142,40406 +15415,25864,30141,40356 +13608,25865,30140,40194 +16355,25866,30139,40589 +11295,25867,30138,40506 +10726,25868,30137,40939 +16963,25869,30136,40336 +10931,25870,30135,40950 +11819,25871,30134,40229 +17654,25872,30133,40798 +11734,25873,30132,40446 +14131,25874,30131,40543 +10012,25875,30130,40185 +14639,25876,30129,40193 +14951,25877,30128,40381 +17570,25878,30127,40963 +11557,25879,30126,40391 +13527,25880,30125,40575 +11749,25881,30124,40345 +12909,25882,30123,40217 +15618,25883,30122,40837 +15683,25884,30121,40737 +12295,25885,30120,40367 +17518,25886,30119,40328 +17888,25887,30118,40592 +13322,25888,30117,40895 +10961,25889,30116,40503 +15928,25890,30115,40218 +17524,25891,30114,40586 +11026,25892,30113,40004 +15151,25893,30112,40330 +17328,25894,30111,40900 +13113,25895,30110,40228 +11157,25896,30109,40205 +12346,25897,30108,40476 +15115,25898,30107,40756 +13243,25899,30106,40180 +15189,25900,30105,40186 +16236,25901,30104,40211 +14355,25902,30103,40961 +15145,25903,30102,40257 +17547,25904,30101,40148 +14890,25905,30100,40525 +16994,25906,30099,40463 +11406,25907,30098,40345 +16829,25908,30097,40869 +12633,25909,30096,40574 +11226,25910,30095,40400 +11833,25911,30094,40881 +10886,25912,30093,40874 +15617,25913,30092,40263 +15768,25914,30091,40698 +12256,25915,30090,40805 +12974,25916,30089,40587 +17923,25917,30088,40663 +14604,25918,30087,40911 +15144,25919,30086,40362 +10564,25920,30085,40241 +15941,25921,30084,40462 +15344,25922,30083,40736 +15112,25923,30082,40659 +15058,25924,30081,40279 +17762,25925,30080,40044 +15313,25926,30079,40681 +17928,25927,30078,40137 +15615,25928,30077,40554 +12697,25929,30076,40694 +15414,25930,30075,40968 +13497,25931,30074,40649 +17234,25932,30073,40216 +14569,25933,30072,40769 +10718,25934,30071,40630 +15729,25935,30070,40074 +18056,25936,30069,40188 +12934,25937,30068,40605 +17149,25938,30067,40275 +16893,25939,30066,40051 +17811,25940,30065,40808 +17280,25941,30064,40050 +14255,25942,30063,40925 +16958,25943,30062,40177 +15909,25944,30061,40784 +12174,25945,30060,40789 +10111,25946,30059,40817 +15408,25947,30058,40806 +13821,25948,30057,40645 +16892,25949,30056,40148 +12185,25950,30055,40688 +17644,25951,30054,40739 +11836,25952,30053,40143 +17019,25953,30052,40061 +15170,25954,30051,40467 +14739,25955,30050,40038 +18153,25956,30049,40266 +16017,25957,30048,40075 +11034,25958,30047,40207 +16229,25959,30046,40188 +16383,25960,30045,40706 +17640,25961,30044,40336 +16563,25962,30043,40362 +12555,25963,30042,40136 +16265,25964,30041,40030 +16851,25965,30040,40556 +10752,25966,30039,40027 +12703,25967,30038,40233 +11096,25968,30037,40928 +13179,25969,30036,40084 +14199,25970,30035,40021 +11856,25971,30034,40040 +12902,25972,30033,40634 +16463,25973,30032,40483 +13565,25974,30031,40924 +15199,25975,30030,40895 +12529,25976,30029,40298 +15846,25977,30028,40156 +17715,25978,30027,40893 +14773,25979,30026,40970 +11254,25980,30025,40598 +15545,25981,30024,40540 +15995,25982,30023,40658 +16314,25983,30022,40257 +14837,25984,30021,40032 +16324,25985,30020,40372 +17566,25986,30019,40100 +15236,25987,30018,40572 +11411,25988,30017,40324 +14417,25989,30016,40357 +17690,25990,30015,40583 +11544,25991,30014,40077 +17497,25992,30013,40189 +11634,25993,30012,40603 +17107,25994,30011,40776 +15672,25995,30010,40025 +10031,25996,30009,40682 +18077,25997,30008,40626 +12375,25998,30007,40762 +12493,25999,30006,40942 +14397,26000,30005,40222 +14267,26001,30004,40067 +14434,26002,30003,40732 +18061,26003,30002,40854 +14455,26004,30001,40155 +15180,26005,30000,40543 +16269,26006,31000,40788 +13050,26007,30999,40723 +13655,26008,30998,40686 +10657,26009,30997,40026 +14372,26010,30996,40287 +11711,26011,30995,40864 +17631,26012,30994,40022 +16162,26013,30993,40369 +15629,26014,30992,40605 +13728,26015,30991,40821 +16774,26016,30990,40733 +10092,26017,30989,40996 +17514,26018,30988,40833 +11475,26019,30987,40179 +17550,26020,30986,40372 +12976,26021,30985,40580 +17145,26022,30984,40887 +14151,26023,30983,40916 +15437,26024,30982,40363 +12090,26025,30981,40573 +15370,26026,30980,40924 +10727,26027,30979,40980 +18036,26028,30978,40318 +12936,26029,30977,40813 +15848,26030,30976,40025 +15277,26031,30975,40810 +14154,26032,30974,40712 +13079,26033,30973,40091 +11892,26034,30972,40672 +18107,26035,30971,40807 +10622,26036,30970,40780 +12978,26037,30969,40432 +17495,26038,30968,40757 +13573,26039,30967,40077 +16585,26040,30966,40750 +11147,26041,30965,40361 +15059,26042,30964,40725 +10843,26043,30963,40664 +15555,26044,30962,40221 +14887,26045,30961,40522 +15961,26046,30960,40785 +17432,26047,30959,40848 +13893,26048,30958,40260 +10453,26049,30957,40356 +15509,26050,30956,40020 +14196,26051,30955,40917 +14324,26052,30954,40636 +15197,26053,30953,40463 +17632,26054,30952,40064 +12813,26055,30951,40697 +14001,26056,30950,40476 +14361,26057,30949,40880 +15324,26058,30948,40637 +16279,26059,30947,40441 +12097,26060,30946,40353 +18191,26061,30945,40436 +11942,26062,30944,40978 +13333,26063,30943,40148 +17611,26064,30942,40245 +17569,26065,30941,40874 +17261,26066,30940,40377 +10189,26067,30939,40737 +13794,26068,30938,40011 +10793,26069,30937,40613 +12262,26070,30936,40855 +17805,26071,30935,40133 +17220,26072,30934,40384 +13829,26073,30933,40359 +11940,26074,30932,40304 +12901,26075,30931,40402 +17058,26076,30930,40868 +10984,26077,30929,40823 +10624,26078,30928,40823 +11768,26079,30927,40265 +18021,26080,30926,40647 +12502,26081,30925,40203 +16674,26082,30924,40012 +12659,26083,30923,40489 +12728,26084,30922,40724 +16998,26085,30921,40358 +16372,26086,30920,40371 +11943,26087,30919,40132 +12025,26088,30918,40928 +15403,26089,30917,40291 +10602,26090,30916,40267 +11143,26091,30915,40160 +17976,26092,30914,40163 +10021,26093,30913,40815 +17053,26094,30912,40100 +12887,26095,30911,40724 +10798,26096,30910,40397 +14767,26097,30909,40098 +16209,26098,30908,40367 +16001,26099,30907,40038 +13602,26100,30906,40746 +18156,26101,30905,40926 +17209,26102,30904,40202 +11164,26103,30903,40827 +16358,26104,30902,40358 +12121,26105,30901,40038 +17978,26106,30900,40401 +10529,26107,30899,40775 +13318,26108,30898,40905 +11913,26109,30897,40760 +12314,26110,30896,40925 +15000,26111,30895,40296 +16105,26112,30894,40268 +14030,26113,30893,40443 +14377,26114,30892,40568 +10548,26115,30891,40135 +17434,26116,30890,40898 +15815,26117,30889,40353 +11231,26118,30888,40847 +13086,26119,30887,40350 +16881,26120,30886,40319 +14687,26121,30885,40262 +15712,26122,30884,40702 +12850,26123,30883,40226 +11097,26124,30882,40612 +10491,26125,30881,40326 +12471,26126,30880,40567 +10883,26127,30879,40353 +13997,26128,30878,40256 +15843,26129,30877,40810 +11195,26130,30876,40659 +12353,26131,30875,40349 +18001,26132,30874,40592 +13078,26133,30873,40443 +11316,26134,30872,40534 +10444,26135,30871,40544 +15140,26136,30870,40407 +13345,26137,30869,40941 +15688,26138,30868,40791 +18168,26139,30867,40805 +17594,26140,30866,40366 +13307,26141,30865,40125 +12764,26142,30864,40605 +16542,26143,30863,40877 +11737,26144,30862,40493 +15211,26145,30861,40811 +11948,26146,30860,40698 +10081,26147,30859,40135 +10168,26148,30858,40039 +15853,26149,30857,40752 +16540,26150,30856,40588 +16549,26151,30855,40205 +14163,26152,30854,40482 +12065,26153,30853,40992 +11735,26154,30852,40702 +17679,26155,30851,40533 +15399,26156,30850,40860 +16294,26157,30849,40385 +12518,26158,30848,40075 +14461,26159,30847,40774 +12540,26160,30846,40878 +10158,26161,30845,40434 +14421,26162,30844,40299 +16360,26163,30843,40110 +16190,26164,30842,40340 +14128,26165,30841,40700 +12008,26166,30840,40691 +10567,26167,30839,40346 +10218,26168,30838,40131 +10669,26169,30837,40356 +13221,26170,30836,40329 +10910,26171,30835,40126 +12925,26172,30834,40746 +12017,26173,30833,40030 +14860,26174,30832,40365 +11499,26175,30831,40560 +14422,26176,30830,40129 +11337,26177,30829,40227 +13124,26178,30828,40777 +16643,26179,30827,40705 +17085,26180,30826,40684 +16943,26181,30825,40948 +16947,26182,30824,40634 +10219,26183,30823,40747 +11021,26184,30822,40647 +12068,26185,30821,40508 +13835,26186,30820,40628 +11791,26187,30819,40115 +14975,26188,30818,40955 +15786,26189,30817,40273 +17303,26190,30816,40336 +13823,26191,30815,40352 +16537,26192,30814,40544 +15771,26193,30813,40410 +11983,26194,30812,40465 +16366,26195,30811,40322 +13470,26196,30810,40000 +12735,26197,30809,40842 +10445,26198,30808,40258 +10127,26199,30807,40899 +18069,26200,30806,40210 +13167,26201,30805,40499 +15216,26202,30804,40713 +14118,26203,30803,40225 +14161,26204,30802,40108 +18073,26205,30801,40316 +16583,26206,30800,40951 +12157,26207,30799,40217 +15161,26208,30798,40248 +17028,26209,30797,40891 +10933,26210,30796,40214 +12897,26211,30795,40621 +11025,26212,30794,40159 +10784,26213,30793,40483 +14669,26214,30792,40825 +10992,26215,30791,40463 +12485,26216,30790,40472 +14187,26217,30789,40183 +17116,26218,30788,40950 +17079,26219,30787,40899 +14795,26220,30786,40281 +14326,26221,30785,40052 +13848,26222,30784,40431 +13683,26223,30783,40248 +11740,26224,30782,40388 +16872,26225,30781,40506 +10907,26226,30780,40060 +17022,26227,30779,40623 +12166,26228,30778,40964 +17015,26229,30777,40267 +11178,26230,30776,40522 +13019,26231,30775,40410 +16808,26232,30774,40293 +12746,26233,30773,40850 +13999,26234,30772,40222 +11855,26235,30771,40846 +17563,26236,30770,40878 +12443,26237,30769,40037 +13281,26238,30768,40858 +18022,26239,30767,40417 +14257,26240,30766,40218 +12199,26241,30765,40164 +15607,26242,30764,40207 +14184,26243,30763,40811 +14470,26244,30762,40506 +15591,26245,30761,40047 +14736,26246,30760,40217 +14456,26247,30759,40273 +17920,26248,30758,40156 +15400,26249,30757,40354 +15759,26250,30756,40974 +16450,26251,30755,40917 +16948,26252,30754,40919 +14856,26253,30753,40404 +15579,26254,30752,40774 +15116,26255,30751,40486 +11965,26256,30750,40132 +18166,26257,30749,40859 +10912,26258,30748,40044 +14133,26259,30747,40934 +15763,26260,30746,40806 +17997,26261,30745,40953 +17270,26262,30744,40642 +18012,26263,30743,40135 +10581,26264,30742,40514 +16198,26265,30741,40810 +14723,26266,30740,40657 +13056,26267,30739,40413 +10519,26268,30738,40007 +10729,26269,30737,40107 +10266,26270,30736,40110 +17425,26271,30735,40190 +15644,26272,30734,40239 +11248,26273,30733,40948 +10524,26274,30732,40718 +15927,26275,30731,40044 +17241,26276,30730,40028 +14543,26277,30729,40654 +15157,26278,30728,40650 +17071,26279,30727,40785 +11568,26280,30726,40107 +15682,26281,30725,40670 +13901,26282,30724,40299 +11064,26283,30723,40777 +10249,26284,30722,40620 +16141,26285,30721,40239 +10813,26286,30720,40407 +10212,26287,30719,40403 +14763,26288,30718,40887 +15057,26289,30717,40347 +14732,26290,30716,40153 +16420,26291,30715,40064 +14090,26292,30714,40815 +16817,26293,30713,40923 +11882,26294,30712,40844 +15610,26295,30711,40146 +11875,26296,30710,40675 +12512,26297,30709,40969 +16426,26298,30708,40664 +15584,26299,30707,40254 +14384,26300,30706,40760 +12690,26301,30705,40253 +12629,26302,30704,40540 +10398,26303,30703,40346 +14233,26304,30702,40311 +14833,26305,30701,40877 +16027,26306,30700,40513 +17720,26307,30699,40286 +13711,26308,30698,40149 +17884,26309,30697,40930 +17543,26310,30696,40749 +16090,26311,30695,40927 +18015,26312,30694,40589 +16342,26313,30693,40817 +12718,26314,30692,40181 +11967,26315,30691,40399 +16129,26316,30690,40583 +11366,26317,30689,40247 +17794,26318,30688,40969 +12265,26319,30687,40134 +12908,26320,30686,40765 +14369,26321,30685,40700 +14502,26322,30684,40459 +15230,26323,30683,40412 +17522,26324,30682,40488 +13274,26325,30681,40801 +15104,26326,30680,40351 +18119,26327,30679,40603 +12798,26328,30678,40934 +15951,26329,30677,40185 +12475,26330,30676,40036 +17614,26331,30675,40497 +17321,26332,30674,40407 +13798,26333,30673,40187 +13004,26334,30672,40442 +12650,26335,30671,40355 +11118,26336,30670,40891 +13733,26337,30669,40981 +14296,26338,30668,40314 +14648,26339,30667,40979 +15451,26340,30666,40733 +11527,26341,30665,40354 +10353,26342,30664,40368 +17714,26343,30663,40619 +17101,26344,30662,40746 +14011,26345,30661,40109 +15948,26346,30660,40820 +12235,26347,30659,40423 +14207,26348,30658,40018 +13108,26349,30657,40627 +12724,26350,30656,40275 +16996,26351,30655,40239 +10257,26352,30654,40750 +13242,26353,30653,40565 +15043,26354,30652,40562 +16554,26355,30651,40753 +12962,26356,30650,40120 +13098,26357,30649,40699 +12312,26358,30648,40700 +15676,26359,30647,40106 +10550,26360,30646,40405 +12609,26361,30645,40729 +10462,26362,30644,40326 +12700,26363,30643,40526 +15449,26364,30642,40669 +11555,26365,30641,40685 +15939,26366,30640,40737 +12336,26367,30639,40195 +10233,26368,30638,40329 +14704,26369,30637,40054 +10750,26370,30636,40608 +15567,26371,30635,40922 +15458,26372,30634,40764 +16490,26373,30633,40718 +14490,26374,30632,40605 +16476,26375,30631,40637 +13498,26376,30630,40539 +15634,26377,30629,40737 +12896,26378,30628,40080 +13263,26379,30627,40010 +16174,26380,30626,40796 +16073,26381,30625,40979 +14728,26382,30624,40767 +16039,26383,30623,40422 +17070,26384,30622,40594 +17580,26385,30621,40326 +10891,26386,30620,40567 +13690,26387,30619,40529 +14525,26388,30618,40774 +13455,26389,30617,40297 +15245,26390,30616,40961 +15410,26391,30615,40144 +10944,26392,30614,40431 +12535,26393,30613,40833 +13991,26394,30612,40909 +12787,26395,30611,40702 +13109,26396,30610,40995 +15467,26397,30609,40579 +14283,26398,30608,40338 +15500,26399,30607,40113 +14402,26400,30606,40059 +13029,26401,30605,40735 +13500,26402,30604,40323 +17020,26403,30603,40259 +13037,26404,30602,40546 +15947,26405,30601,40902 +10983,26406,30600,40235 +11076,26407,30599,40462 +11264,26408,30598,40886 +17694,26409,30597,40069 +10847,26410,30596,40177 +14740,26411,30595,40718 +13832,26412,30594,40021 +11175,26413,30593,40048 +10520,26414,30592,40501 +16227,26415,30591,40275 +17627,26416,30590,40457 +17038,26417,30589,40351 +16184,26418,30588,40912 +17865,26419,30587,40099 +15078,26420,30586,40164 +13149,26421,30585,40259 +13469,26422,30584,40119 +16382,26423,30583,40804 +14978,26424,30582,40596 +11502,26425,30581,40313 +17527,26426,30580,40480 +16230,26427,30579,40935 +10094,26428,30578,40584 +14970,26429,30577,40365 +14410,26430,30576,40540 +17904,26431,30575,40773 +17838,26432,30574,40208 +16579,26433,30573,40752 +14019,26434,30572,40171 +12501,26435,30571,40654 +12208,26436,30570,40504 +12331,26437,30569,40211 +17577,26438,30568,40194 +13759,26439,30567,40501 +14572,26440,30566,40077 +14759,26441,30565,40489 +17797,26442,30564,40055 +10986,26443,30563,40301 +11593,26444,30562,40622 +10771,26445,30561,40488 +18026,26446,30560,40291 +13553,26447,30559,40118 +17711,26448,30558,40275 +12003,26449,30557,40336 +11232,26450,30556,40767 +12223,26451,30555,40152 +14360,26452,30554,40033 +12675,26453,30553,40786 +14263,26454,30552,40823 +11237,26455,30551,40565 +17713,26456,30550,40940 +12053,26457,30549,40049 +13873,26458,30548,40889 +17164,26459,30547,40883 +13709,26460,30546,40379 +10243,26461,30545,40428 +18190,26462,30544,40974 +11249,26463,30543,40776 +11806,26464,30542,40016 +16551,26465,30541,40241 +11746,26466,30540,40792 +11410,26467,30539,40396 +17850,26468,30538,40612 +10192,26469,30537,40859 +13774,26470,30536,40730 +10138,26471,30535,40281 +15622,26472,30534,40495 +17526,26473,30533,40221 +16618,26474,30532,40251 +13171,26475,30531,40238 +14681,26476,30530,40149 +10343,26477,30529,40141 +17940,26478,30528,40306 +13352,26479,30527,40327 +14848,26480,30526,40633 +16241,26481,30525,40729 +12802,26482,30524,40034 +10705,26483,30523,40190 +10051,26484,30522,40453 +15809,26485,30521,40556 +15028,26486,30520,40992 +13209,26487,30519,40725 +10418,26488,30518,40384 +10334,26489,30517,40025 +13114,26490,30516,40511 +11202,26491,30515,40161 +10964,26492,30514,40326 +16631,26493,30513,40710 +14565,26494,30512,40010 +16301,26495,30511,40160 +18187,26496,30510,40459 +15016,26497,30509,40699 +16150,26498,30508,40570 +17465,26499,30507,40339 +16789,26500,30506,40264 +10316,26501,30505,40248 +12260,26502,30504,40875 +16778,26503,30503,40444 +10873,26504,30502,40147 +11946,26505,30501,40882 +17572,26506,30500,40555 +17458,26507,30499,40465 +16276,26508,30498,40732 +15390,26509,30497,40565 +16561,26510,30496,40851 +10113,26511,30495,40295 +10617,26512,30494,40250 +13197,26513,30493,40842 +15387,26514,30492,40275 +10835,26515,30491,40358 +17893,26516,30490,40905 +11042,26517,30489,40403 +13327,26518,30488,40633 +11083,26519,30487,40419 +14253,26520,30486,40470 +12677,26521,30485,40282 +12595,26522,30484,40963 +16330,26523,30483,40249 +17333,26524,30482,40832 +15179,26525,30481,40117 +17475,26526,30480,40935 +10809,26527,30479,40751 +13229,26528,30478,40601 +10061,26529,30477,40532 +10923,26530,30476,40362 +16966,26531,30475,40653 +15827,26532,30474,40987 +15224,26533,30473,40921 +16191,26534,30472,40662 +13687,26535,30471,40701 +13662,26536,30470,40811 +13694,26537,30469,40294 +12929,26538,30468,40593 +17879,26539,30467,40382 +13913,26540,30466,40401 +16486,26541,30465,40546 +14170,26542,30464,40132 +15237,26543,30463,40284 +11747,26544,30462,40733 +10282,26545,30461,40156 +17783,26546,30460,40833 +10807,26547,30459,40161 +12977,26548,30458,40283 +15962,26549,30457,40430 +13143,26550,30456,40684 +16205,26551,30455,40519 +11336,26552,30454,40616 +17677,26553,30453,40890 +15795,26554,30452,40187 +16430,26555,30451,40179 +17734,26556,30450,40202 +18034,26557,30449,40416 +17419,26558,30448,40294 +14467,26559,30447,40891 +18174,26560,30446,40394 +12134,26561,30445,40542 +11233,26562,30444,40374 +16836,26563,30443,40824 +15331,26564,30442,40373 +10311,26565,30441,40957 +13492,26566,30440,40121 +18176,26567,30439,40413 +11598,26568,30438,40551 +16708,26569,30437,40107 +10805,26570,30436,40364 +17681,26571,30435,40701 +10636,26572,30434,40630 +14850,26573,30433,40507 +13125,26574,30432,40463 +14683,26575,30431,40864 +14531,26576,30430,40836 +11849,26577,30429,40662 +18080,26578,30428,40637 +15972,26579,30427,40166 +14343,26580,30426,40749 +14582,26581,30425,40916 +17224,26582,30424,40592 +11086,26583,30423,40129 +11949,26584,30422,40380 +14916,26585,30421,40323 +16248,26586,30420,40752 +12098,26587,30419,40783 +15497,26588,30418,40978 +13479,26589,30417,40759 +12821,26590,30416,40077 +16163,26591,30415,40910 +16214,26592,30414,40151 +15045,26593,30413,40535 +14390,26594,30412,40776 +10684,26595,30411,40934 +13074,26596,30410,40326 +16509,26597,30409,40870 +13987,26598,30408,40382 +11591,26599,30407,40018 +16002,26600,30406,40925 +10993,26601,30405,40079 +11522,26602,30404,40996 +16651,26603,30403,40094 +18096,26604,30402,40482 +16242,26605,30401,40672 +13716,26606,30400,40907 +15657,26607,30399,40234 +10394,26608,30398,40438 +11890,26609,30397,40175 +13975,26610,30396,40445 +16825,26611,30395,40733 +16130,26612,30394,40781 +12888,26613,30393,40559 +10801,26614,30392,40093 +10900,26615,30391,40418 +11101,26616,30390,40892 +14735,26617,30389,40956 +16972,26618,30388,40411 +17863,26619,30387,40686 +13883,26620,30386,40089 +10290,26621,30385,40762 +15292,26622,30384,40293 +17540,26623,30383,40383 +10678,26624,30382,40222 +17291,26625,30381,40801 +13216,26626,30380,40807 +13623,26627,30379,40486 +15487,26628,30378,40222 +12215,26629,30377,40059 +18093,26630,30376,40083 +12543,26631,30375,40789 +13845,26632,30374,40390 +11871,26633,30373,40988 +17064,26634,30372,40761 +14976,26635,30371,40050 +11007,26636,30370,40565 +15110,26637,30369,40473 +16995,26638,30368,40008 +11279,26639,30367,40946 +10121,26640,30366,40571 +12933,26641,30365,40321 +10512,26642,30364,40882 +13807,26643,30363,40358 +17361,26644,30362,40629 +11016,26645,30361,40495 +13618,26646,30360,40268 +17873,26647,30359,40120 +16034,26648,30358,40535 +10246,26649,30357,40613 +14016,26650,30356,40627 +15154,26651,30355,40782 +14846,26652,30354,40128 +10954,26653,30353,40201 +10370,26654,30352,40335 +16840,26655,30351,40422 +12928,26656,30350,40593 +17695,26657,30349,40731 +11687,26658,30348,40803 +12889,26659,30347,40504 +13928,26660,30346,40574 +11901,26661,30345,40237 +13453,26662,30344,40706 +13262,26663,30343,40087 +16245,26664,30342,40923 +14808,26665,30341,40329 +12849,26666,30340,40355 +15705,26667,30339,40751 +14858,26668,30338,40655 +12824,26669,30337,40830 +14650,26670,30336,40558 +17253,26671,30335,40592 +15581,26672,30334,40284 +15710,26673,30333,40963 +13825,26674,30332,40805 +15166,26675,30331,40521 +16095,26676,30330,40004 +17192,26677,30329,40418 +13205,26678,30328,40675 +11098,26679,30327,40661 +18101,26680,30326,40253 +14670,26681,30325,40894 +13763,26682,30324,40199 +17462,26683,30323,40817 +12247,26684,30322,40022 +12583,26685,30321,40916 +16153,26686,30320,40722 +15649,26687,30319,40411 +17605,26688,30318,40383 +13746,26689,30317,40173 +14966,26690,30316,40428 +16078,26691,30315,40892 +15067,26692,30314,40068 +12069,26693,30313,40762 +15734,26694,30312,40106 +16682,26695,30311,40878 +12788,26696,30310,40354 +16730,26697,30309,40694 +17325,26698,30308,40387 +16485,26699,30307,40815 +10834,26700,30306,40992 +13612,26701,30305,40032 +10668,26702,30304,40150 +16325,26703,30303,40756 +17017,26704,30302,40895 +17515,26705,30301,40013 +17076,26706,30300,40452 +11647,26707,30299,40558 +18136,26708,30298,40354 +17302,26709,30297,40489 +14181,26710,30296,40108 +17919,26711,30295,40184 +17388,26712,30294,40174 +15368,26713,30293,40543 +12641,26714,30292,40321 +12446,26715,30291,40925 +13368,26716,30290,40378 +14066,26717,30289,40628 +17355,26718,30288,40942 +14707,26719,30287,40526 +13467,26720,30286,40376 +11120,26721,30285,40343 +17135,26722,30284,40690 +18023,26723,30283,40706 +15772,26724,30282,40706 +12709,26725,30281,40540 +14685,26726,30280,40371 +13147,26727,30279,40988 +11432,26728,30278,40173 +14438,26729,30277,40708 +15372,26730,30276,40831 +16960,26731,30275,40881 +11907,26732,30274,40265 +12290,26733,30273,40245 +16117,26734,30272,40526 +10025,26735,30271,40526 +13722,26736,30270,40814 +15126,26737,30269,40040 +10099,26738,30268,40809 +13009,26739,30267,40277 +11211,26740,30266,40623 +16254,26741,30265,40869 +12833,26742,30264,40493 +11419,26743,30263,40032 +16399,26744,30262,40923 +13239,26745,30261,40952 +15776,26746,30260,40784 +14769,26747,30259,40036 +10523,26748,30258,40390 +15513,26749,30257,40479 +12111,26750,30256,40723 +12606,26751,30255,40888 +11354,26752,30254,40940 +10035,26753,30253,40834 +17844,26754,30252,40534 +15823,26755,30251,40987 +17921,26756,30250,40367 +13442,26757,30249,40121 +12910,26758,30248,40886 +14536,26759,30247,40328 +17868,26760,30246,40515 +10122,26761,30245,40225 +17932,26762,30244,40401 +14644,26763,30243,40637 +13163,26764,30242,40784 +12243,26765,30241,40815 +14714,26766,30240,40847 +17146,26767,30239,40271 +14483,26768,30238,40191 +15670,26769,30237,40194 +10730,26770,30236,40059 +15608,26771,30235,40063 +13583,26772,30234,40812 +13065,26773,30233,40500 +15894,26774,30232,40064 +14313,26775,30231,40015 +13021,26776,30230,40770 +12094,26777,30229,40706 +14855,26778,30228,40101 +10746,26779,30227,40349 +16689,26780,30226,40945 +14949,26781,30225,40863 +16797,26782,30224,40345 +11962,26783,30223,40959 +14379,26784,30222,40323 +10911,26785,30221,40404 +15183,26786,30220,40086 +17650,26787,30219,40205 +11326,26788,30218,40066 +14396,26789,30217,40891 +13646,26790,30216,40305 +14256,26791,30215,40266 +11136,26792,30214,40012 +14346,26793,30213,40094 +11300,26794,30212,40120 +11416,26795,30211,40235 +10170,26796,30210,40943 +17454,26797,30209,40004 +13945,26798,30208,40626 +13314,26799,30207,40029 +10214,26800,30206,40156 +17133,26801,30205,40108 +17847,26802,30204,40234 +16519,26803,30203,40962 +16283,26804,30202,40207 +12574,26805,30201,40824 +14513,26806,30200,40844 +17188,26807,30199,40820 +15386,26808,30198,40236 +11947,26809,30197,40907 +10322,26810,30196,40886 +17896,26811,30195,40152 +16182,26812,30194,40116 +10054,26813,30193,40843 +17839,26814,30192,40736 +11212,26815,30191,40229 +15320,26816,30190,40918 +16627,26817,30189,40927 +10831,26818,30188,40076 +12189,26819,30187,40570 +12580,26820,30186,40405 +17807,26821,30185,40585 +12242,26822,30184,40094 +16442,26823,30183,40850 +14130,26824,30182,40200 +16287,26825,30181,40476 +17464,26826,30180,40460 +12067,26827,30179,40731 +15343,26828,30178,40860 +11292,26829,30177,40766 +10553,26830,30176,40166 +11945,26831,30175,40762 +11193,26832,30174,40532 +11859,26833,30173,40535 +11023,26834,30172,40494 +12966,26835,30171,40264 +15534,26836,30170,40066 +11365,26837,30169,40624 +13016,26838,30168,40345 +13797,26839,30167,40640 +12930,26840,30166,40954 +15886,26841,30165,40549 +17819,26842,30164,40564 +15967,26843,30163,40830 +15357,26844,30162,40797 +14647,26845,30161,40915 +12875,26846,30160,40664 +11732,26847,30159,40080 +18037,26848,30158,40211 +11903,26849,30157,40593 +16403,26850,30156,40550 +15944,26851,30155,40353 +15050,26852,30154,40351 +15869,26853,30153,40651 +16123,26854,30152,40435 +12593,26855,30151,40241 +13895,26856,30150,40191 +15874,26857,30149,40834 +15720,26858,30148,40205 +15977,26859,30147,40029 +15098,26860,30146,40481 +16196,26861,30145,40660 +15380,26862,30144,40619 +11272,26863,30143,40157 +14904,26864,30142,40767 +13199,26865,30141,40770 +13126,26866,30140,40544 +11873,26867,30139,40816 +15397,26868,30138,40371 +17864,26869,30137,40084 +16921,26870,30136,40767 +14927,26871,30135,40761 +16211,26872,30134,40795 +16159,26873,30133,40663 +12687,26874,30132,40520 +10664,26875,30131,40149 +11538,26876,30130,40205 +12340,26877,30129,40791 +13456,26878,30128,40954 +16737,26879,30127,40946 +18155,26880,30126,40988 +14145,26881,30125,40684 +10570,26882,30124,40526 +17029,26883,30123,40665 +14077,26884,30122,40753 +12774,26885,30121,40649 +16024,26886,30120,40834 +14507,26887,30119,40109 +14864,26888,30118,40554 +12135,26889,30117,40432 +13289,26890,30116,40763 +14977,26891,30115,40850 +10821,26892,30114,40877 +11670,26893,30113,40798 +11924,26894,30112,40249 +14501,26895,30111,40518 +16986,26896,30110,40309 +15645,26897,30109,40173 +12313,26898,30108,40198 +10980,26899,30107,40074 +14277,26900,30106,40340 +14086,26901,30105,40700 +15901,26902,30104,40983 +13589,26903,30103,40481 +17910,26904,30102,40263 +13134,26905,30101,40921 +10433,26906,30100,40625 +11808,26907,30099,40503 +13724,26908,30098,40453 +12477,26909,30097,40039 +14974,26910,30096,40908 +15235,26911,30095,40002 +14057,26912,30094,40159 +17646,26913,30093,40303 +10892,26914,30092,40419 +14430,26915,30091,40317 +13430,26916,30090,40057 +13005,26917,30089,40027 +12492,26918,30088,40906 +17048,26919,30087,40600 +16197,26920,30086,40511 +14454,26921,30085,40742 +10458,26922,30084,40038 +11551,26923,30083,40552 +13160,26924,30082,40632 +11885,26925,30081,40885 +12652,26926,30080,40368 +11002,26927,30079,40693 +12167,26928,30078,40118 +15326,26929,30077,40064 +16749,26930,30076,40810 +13261,26931,30075,40894 +14033,26932,30074,40356 +14155,26933,30073,40809 +12267,26934,30072,40559 +14588,26935,30071,40406 +17398,26936,30070,40094 +13858,26937,30069,40203 +15794,26938,30068,40918 +18116,26939,30067,40962 +16154,26940,30066,40276 +14015,26941,30065,40395 +12685,26942,30064,40296 +10623,26943,30063,40608 +13135,26944,30062,40270 +15310,26945,30061,40266 +14719,26946,30060,40037 +15925,26947,30059,40706 +17761,26948,30058,40241 +16049,26949,30057,40105 +14204,26950,30056,40507 +14051,26951,30055,40496 +17651,26952,30054,40056 +17988,26953,30053,40172 +12452,26954,30052,40382 +12988,26955,30051,40521 +13598,26956,30050,40619 +17660,26957,30049,40687 +11790,26958,30048,40424 +18090,26959,30047,40378 +13471,26960,30046,40275 +11399,26961,30045,40715 +15445,26962,30044,40122 +14784,26963,30043,40404 +15741,26964,30042,40707 +15885,26965,30041,40321 +18182,26966,30040,40105 +12310,26967,30039,40546 +10962,26968,30038,40824 +16472,26969,30037,40781 +16435,26970,30036,40961 +17117,26971,30035,40696 +10381,26972,30034,40970 +10103,26973,30033,40228 +17292,26974,30032,40893 +13328,26975,30031,40365 +15662,26976,30030,40672 +13863,26977,30029,40774 +10382,26978,30028,40372 +15125,26979,30027,40857 +16523,26980,30026,40111 +16499,26981,30025,40324 +10974,26982,30024,40293 +11688,26983,30023,40063 +11108,26984,30022,40211 +17541,26985,30021,40298 +16240,26986,30020,40940 +13849,26987,30019,40460 +16288,26988,30018,40148 +10349,26989,30017,40661 +11308,26990,30016,40410 +14797,26991,30015,40629 +18185,26992,30014,40146 +17444,26993,30013,40774 +11525,26994,30012,40520 +15860,26995,30011,40732 +10866,26996,30010,40529 +14696,26997,30009,40894 +15299,26998,30008,40635 +11978,26999,30007,40548 +15788,27000,30006,40565 +13426,27001,30005,40599 +14310,27002,30004,40337 +16765,27003,30003,40904 +11579,27004,30002,40702 +17078,27005,30001,40672 +14006,27006,30000,40811 +11077,27007,31000,40079 +10305,27008,30999,40853 +15259,27009,30998,40417 +10175,27010,30997,40065 +17178,27011,30996,40898 +16199,27012,30995,40357 +15266,27013,30994,40698 +16231,27014,30993,40728 +10351,27015,30992,40444 +10858,27016,30991,40674 +12251,27017,30990,40768 +17153,27018,30989,40718 +13625,27019,30988,40064 +12845,27020,30987,40685 +15875,27021,30986,40432 +16234,27022,30985,40772 +10327,27023,30984,40047 +15472,27024,30983,40285 +12099,27025,30982,40138 +16075,27026,30981,40299 +10691,27027,30980,40943 +11493,27028,30979,40478 +12005,27029,30978,40726 +14064,27030,30977,40687 +10772,27031,30976,40500 +14484,27032,30975,40694 +13666,27033,30974,40393 +11329,27034,30973,40535 +13856,27035,30972,40354 +11926,27036,30971,40627 +16891,27037,30970,40921 +11660,27038,30969,40050 +11148,27039,30968,40408 +17671,27040,30967,40029 +12474,27041,30966,40212 +11917,27042,30965,40186 +10557,27043,30964,40806 +17913,27044,30963,40970 +11447,27045,30962,40597 +14515,27046,30961,40764 +11060,27047,30960,40215 +17397,27048,30959,40308 +14022,27049,30958,40359 +12106,27050,30957,40166 +10396,27051,30956,40440 +18103,27052,30955,40060 +15669,27053,30954,40999 +15356,27054,30953,40408 +14485,27055,30952,40646 +15291,27056,30951,40123 +10431,27057,30950,40437 +14562,27058,30949,40147 +16219,27059,30948,40587 +11624,27060,30947,40259 +12995,27061,30946,40147 +16104,27062,30945,40100 +10133,27063,30944,40402 +14139,27064,30943,40561 +16632,27065,30942,40148 +16895,27066,30941,40625 +12392,27067,30940,40494 +15606,27068,30939,40958 +12472,27069,30938,40534 +13591,27070,30937,40002 +11323,27071,30936,40238 +12479,27072,30935,40649 +17300,27073,30934,40008 +16941,27074,30933,40121 +14510,27075,30932,40763 +14546,27076,30931,40582 +13647,27077,30930,40372 +14362,27078,30929,40786 +14479,27079,30928,40016 +10020,27080,30927,40849 +11662,27081,30926,40997 +17229,27082,30925,40715 +15803,27083,30924,40833 +16187,27084,30923,40475 +12716,27085,30922,40746 +10629,27086,30921,40988 +14731,27087,30920,40980 +11682,27088,30919,40284 +18189,27089,30918,40793 +16320,27090,30917,40592 +10271,27091,30916,40578 +15433,27092,30915,40598 +17126,27093,30914,40756 +14909,27094,30913,40122 +11325,27095,30912,40438 +11828,27096,30911,40952 +11641,27097,30910,40983 +10711,27098,30909,40560 +12979,27099,30908,40460 +13580,27100,30907,40320 +12860,27101,30906,40903 +15883,27102,30905,40939 +12408,27103,30904,40507 +13066,27104,30903,40919 +13049,27105,30902,40580 +12183,27106,30901,40765 +14870,27107,30900,40139 +16210,27108,30899,40601 +10769,27109,30898,40607 +14831,27110,30897,40001 +17331,27111,30896,40631 +11022,27112,30895,40986 +14612,27113,30894,40700 +11345,27114,30893,40829 +15785,27115,30892,40340 +17544,27116,30891,40777 +13164,27117,30890,40473 +11935,27118,30889,40130 +12635,27119,30888,40536 +13252,27120,30887,40808 +17089,27121,30886,40828 +16224,27122,30885,40658 +16833,27123,30884,40803 +15611,27124,30883,40065 +10107,27125,30882,40425 +10110,27126,30881,40257 +10627,27127,30880,40976 +14574,27128,30879,40858 +10999,27129,30878,40489 +14965,27130,30877,40085 +10743,27131,30876,40828 +15215,27132,30875,40946 +12858,27133,30874,40388 +16745,27134,30873,40934 +15592,27135,30872,40110 +12616,27136,30871,40377 +12968,27137,30870,40103 +10259,27138,30869,40693 +13564,27139,30868,40557 +15283,27140,30867,40427 +17119,27141,30866,40574 +12640,27142,30865,40912 +11146,27143,30864,40685 +15632,27144,30863,40181 +17892,27145,30862,40123 +17112,27146,30861,40076 +13142,27147,30860,40465 +14194,27148,30859,40638 +12660,27149,30858,40820 +15421,27150,30857,40249 +11427,27151,30856,40514 +13362,27152,30855,40343 +10649,27153,30854,40248 +15653,27154,30853,40730 +10248,27155,30852,40878 +15637,27156,30851,40923 +13372,27157,30850,40858 +13609,27158,30849,40490 +14297,27159,30848,40017 +10408,27160,30847,40631 +16865,27161,30846,40036 +15452,27162,30845,40559 +11355,27163,30844,40575 +11727,27164,30843,40898 +10013,27165,30842,40605 +15270,27166,30841,40873 +16207,27167,30840,40191 +14672,27168,30839,40886 +16868,27169,30838,40947 +16013,27170,30837,40835 +12458,27171,30836,40105 +15358,27172,30835,40468 +16020,27173,30834,40713 +17364,27174,30833,40297 +10578,27175,30832,40952 +14107,27176,30831,40283 +17780,27177,30830,40970 +15955,27178,30829,40352 +14136,27179,30828,40649 +16909,27180,30827,40418 +12688,27181,30826,40883 +12726,27182,30825,40201 +16867,27183,30824,40274 +14242,27184,30823,40137 +13998,27185,30822,40028 +16143,27186,30821,40086 +16396,27187,30820,40939 +16566,27188,30819,40308 +15811,27189,30818,40583 +17680,27190,30817,40419 +13684,27191,30816,40607 +17723,27192,30815,40527 +12148,27193,30814,40743 +13964,27194,30813,40989 +14898,27195,30812,40468 +12943,27196,30811,40394 +13718,27197,30810,40090 +11128,27198,30809,40150 +13720,27199,30808,40934 +10761,27200,30807,40845 +15060,27201,30806,40503 +16375,27202,30805,40462 +12829,27203,30804,40991 +11693,27204,30803,40477 +17881,27205,30802,40856 +11031,27206,30801,40443 +16208,27207,30800,40642 +10826,27208,30799,40821 +17210,27209,30798,40665 +16526,27210,30797,40778 +15396,27211,30796,40243 +10734,27212,30795,40053 +16333,27213,30794,40814 +11485,27214,30793,40723 +10700,27215,30792,40528 +13620,27216,30791,40406 +17288,27217,30790,40057 +10090,27218,30789,40648 +17639,27219,30788,40866 +14583,27220,30787,40668 +17492,27221,30786,40929 +10469,27222,30785,40606 +12520,27223,30784,40228 +12533,27224,30783,40570 +16957,27225,30782,40555 +14399,27226,30781,40681 +14167,27227,30780,40498 +13204,27228,30779,40201 +12586,27229,30778,40708 +10820,27230,30777,40316 +13921,27231,30776,40971 +13136,27232,30775,40608 +15486,27233,30774,40156 +13805,27234,30773,40631 +14900,27235,30772,40056 +10496,27236,30771,40036 +14344,27237,30770,40884 +13782,27238,30769,40894 +16204,27239,30768,40714 +14626,27240,30767,40786 +13115,27241,30766,40344 +15220,27242,30765,40744 +16273,27243,30764,40270 +10102,27244,30763,40208 +13041,27245,30762,40854 +16125,27246,30761,40429 +13024,27247,30760,40908 +10686,27248,30759,40207 +12791,27249,30758,40965 +14587,27250,30757,40983 +18110,27251,30756,40252 +15889,27252,30755,40467 +12105,27253,30754,40190 +11805,27254,30753,40529 +12151,27255,30752,40327 +10878,27256,30751,40384 +16437,27257,30750,40926 +14373,27258,30749,40442 +11816,27259,30748,40099 +16532,27260,30747,40839 +12817,27261,30746,40545 +12949,27262,30745,40835 +11744,27263,30744,40703 +10002,27264,30743,40806 +13840,27265,30742,40344 +15880,27266,30741,40108 +15243,27267,30740,40418 +16700,27268,30739,40427 +17609,27269,30738,40828 +15213,27270,30737,40330 +16365,27271,30736,40392 +17265,27272,30735,40810 +16473,27273,30734,40296 +14306,27274,30733,40284 +16188,27275,30732,40636 +13449,27276,30731,40225 +14335,27277,30730,40866 +18100,27278,30729,40137 +13151,27279,30728,40687 +15996,27280,30727,40923 +16060,27281,30726,40889 +10226,27282,30725,40523 +10853,27283,30724,40447 +11725,27284,30723,40393 +14729,27285,30722,40728 +11107,27286,30721,40406 +10658,27287,30720,40880 +14676,27288,30719,40938 +12975,27289,30718,40945 +11619,27290,30717,40465 +15960,27291,30716,40102 +15602,27292,30715,40100 +14834,27293,30714,40443 +13133,27294,30713,40563 +12919,27295,30712,40824 +18047,27296,30711,40000 +10568,27297,30710,40652 +10937,27298,30709,40639 +17616,27299,30708,40814 +13104,27300,30707,40345 +14366,27301,30706,40943 +10213,27302,30705,40728 +15753,27303,30704,40068 +12972,27304,30703,40365 +15730,27305,30702,40127 +14178,27306,30701,40349 +15949,27307,30700,40948 +14004,27308,30699,40810 +13112,27309,30698,40785 +12783,27310,30697,40149 +13454,27311,30696,40223 +10106,27312,30695,40313 +16704,27313,30694,40070 +15247,27314,30693,40044 +15132,27315,30692,40765 +16791,27316,30691,40591 +16028,27317,30690,40366 +18032,27318,30689,40676 +10679,27319,30688,40047 +17842,27320,30687,40382 +16615,27321,30686,40437 +10628,27322,30685,40948 +11184,27323,30684,40075 +16120,27324,30683,40424 +11218,27325,30682,40009 +12150,27326,30681,40380 +16823,27327,30680,40880 +17105,27328,30679,40180 +14354,27329,30678,40753 +18183,27330,30677,40582 +17198,27331,30676,40957 +13533,27332,30675,40774 +15971,27333,30674,40399 +13552,27334,30673,40062 +10856,27335,30672,40174 +13403,27336,30671,40819 +12217,27337,30670,40735 +17054,27338,30669,40355 +15538,27339,30668,40607 +11745,27340,30667,40914 +13909,27341,30666,40037 +18154,27342,30665,40291 +11293,27343,30664,40158 +13495,27344,30663,40883 +14950,27345,30662,40898 +11113,27346,30661,40170 +15560,27347,30660,40884 +12360,27348,30659,40043 +11559,27349,30658,40368 +12839,27350,30657,40995 +11242,27351,30656,40316 +11922,27352,30655,40030 +10490,27353,30654,40793 +15681,27354,30653,40804 +13834,27355,30652,40163 +11013,27356,30651,40891 +13697,27357,30650,40139 +15664,27358,30649,40142 +14113,27359,30648,40910 +10163,27360,30647,40187 +13319,27361,30646,40558 +16718,27362,30645,40523 +13795,27363,30644,40806 +11194,27364,30643,40050 +12325,27365,30642,40171 +11496,27366,30641,40350 +16429,27367,30640,40966 +14475,27368,30639,40460 +14514,27369,30638,40998 +14611,27370,30637,40526 +15279,27371,30636,40747 +17147,27372,30635,40072 +15558,27373,30634,40805 +10610,27374,30633,40314 +14661,27375,30632,40627 +11656,27376,30631,40048 +12878,27377,30630,40879 +17293,27378,30629,40917 +13249,27379,30628,40046 +10872,27380,30627,40279 +10677,27381,30626,40494 +12750,27382,30625,40547 +12658,27383,30624,40280 +17201,27384,30623,40185 +12355,27385,30622,40420 +12804,27386,30621,40218 +12274,27387,30620,40836 +14070,27388,30619,40830 +12807,27389,30618,40393 +17001,27390,30617,40546 +11437,27391,30616,40177 +13571,27392,30615,40150 +17360,27393,30614,40451 +13162,27394,30613,40917 +17795,27395,30612,40809 +17299,27396,30611,40501 +15603,27397,30610,40499 +17917,27398,30609,40471 +17808,27399,30608,40981 +14295,27400,30607,40784 +10227,27401,30606,40814 +11797,27402,30605,40022 +17812,27403,30604,40265 +17606,27404,30603,40230 +15921,27405,30602,40921 +12884,27406,30601,40570 +15338,27407,30600,40390 +16087,27408,30599,40273 +16732,27409,30598,40964 +11286,27410,30597,40022 +16569,27411,30596,40226 +17196,27412,30595,40986 +11939,27413,30594,40672 +12519,27414,30593,40212 +10363,27415,30592,40249 +10601,27416,30591,40663 +15804,27417,30590,40640 +11332,27418,30589,40413 +11877,27419,30588,40375 +15652,27420,30587,40927 +11814,27421,30586,40635 +13376,27422,30585,40438 +18058,27423,30584,40699 +12196,27424,30583,40612 +16997,27425,30582,40855 +15849,27426,30581,40636 +14941,27427,30580,40238 +16149,27428,30579,40224 +10355,27429,30578,40311 +11605,27430,30577,40440 +14059,27431,30576,40881 +15740,27432,30575,40880 +12534,27433,30574,40670 +16025,27434,30573,40403 +15733,27435,30572,40474 +10250,27436,30571,40308 +14080,27437,30570,40666 +17992,27438,30569,40835 +17936,27439,30568,40815 +14551,27440,30567,40876 +16685,27441,30566,40985 +11564,27442,30565,40067 +17684,27443,30564,40392 +10895,27444,30563,40132 +15282,27445,30562,40766 +16760,27446,30561,40703 +14809,27447,30560,40617 +12572,27448,30559,40672 +16491,27449,30558,40660 +10378,27450,30557,40740 +11294,27451,30556,40685 +12407,27452,30555,40664 +15242,27453,30554,40105 +17142,27454,30553,40324 +15764,27455,30552,40036 +12738,27456,30551,40853 +10465,27457,30550,40349 +10709,27458,30549,40088 +15575,27459,30548,40253 +15351,27460,30547,40769 +17385,27461,30546,40560 +11311,27462,30545,40651 +16496,27463,30544,40444 +13536,27464,30543,40651 +16352,27465,30542,40614 +17456,27466,30541,40637 +10694,27467,30540,40709 +14120,27468,30539,40680 +11743,27469,30538,40886 +15278,27470,30537,40157 +14952,27471,30536,40886 +12668,27472,30535,40642 +11253,27473,30534,40054 +18081,27474,30533,40230 +10758,27475,30532,40728 +12132,27476,30531,40405 +15155,27477,30530,40424 +15474,27478,30529,40202 +12666,27479,30528,40534 +10811,27480,30527,40452 +11843,27481,30526,40352 +13633,27482,30525,40033 +10927,27483,30524,40245 +13747,27484,30523,40008 +16427,27485,30522,40772 +17239,27486,30521,40147 +14666,27487,30520,40106 +16432,27488,30519,40953 +15812,27489,30518,40050 +15655,27490,30517,40233 +10141,27491,30516,40822 +17087,27492,30515,40930 +11469,27493,30514,40764 +14243,27494,30513,40024 +15363,27495,30512,40285 +16493,27496,30511,40080 +12885,27497,30510,40487 +16594,27498,30509,40093 +11519,27499,30508,40809 +15466,27500,30507,40387 +10740,27501,30506,40806 +16270,27502,30505,40857 +14393,27503,30504,40011 +12491,27504,30503,40988 +15203,27505,30502,40283 +11092,27506,30501,40638 +17403,27507,30500,40547 +17189,27508,30499,40621 +11362,27509,30498,40431 +13337,27510,30497,40087 +15325,27511,30496,40506 +11996,27512,30495,40571 +13588,27513,30494,40293 +13642,27514,30493,40347 +15914,27515,30492,40863 +15959,27516,30491,40559 +15482,27517,30490,40170 +10359,27518,30489,40211 +13924,27519,30488,40750 +14939,27520,30487,40120 +13428,27521,30486,40855 +17061,27522,30485,40583 +12287,27523,30484,40906 +10849,27524,30483,40305 +17326,27525,30482,40229 +10180,27526,30481,40773 +14994,27527,30480,40259 +15982,27528,30479,40761 +15239,27529,30478,40527 +11423,27530,30477,40905 +12034,27531,30476,40144 +12891,27532,30475,40790 +15036,27533,30474,40083 +16536,27534,30473,40901 +17452,27535,30472,40743 +17596,27536,30471,40208 +14675,27537,30470,40009 +11930,27538,30469,40938 +18095,27539,30468,40039 +18035,27540,30467,40580 +16726,27541,30466,40674 +14404,27542,30465,40629 +14517,27543,30464,40892 +16459,27544,30463,40206 +12585,27545,30462,40417 +12266,27546,30461,40307 +15103,27547,30460,40747 +16307,27548,30459,40773 +17668,27549,30458,40045 +16559,27550,30457,40548 +10053,27551,30456,40313 +11516,27552,30455,40282 +13068,27553,30454,40765 +13853,27554,30453,40339 +10109,27555,30452,40551 +15517,27556,30451,40968 +12644,27557,30450,40649 +11414,27558,30449,40331 +17521,27559,30448,40425 +15779,27560,30447,40205 +16814,27561,30446,40375 +11581,27562,30445,40259 +12081,27563,30444,40377 +11415,27564,30443,40135 +14602,27565,30442,40844 +10263,27566,30441,40027 +14642,27567,30440,40632 +11807,27568,30439,40176 +10930,27569,30438,40630 +16421,27570,30437,40724 +12149,27571,30436,40478 +14112,27572,30435,40946 +11180,27573,30434,40560 +11305,27574,30433,40892 +12680,27575,30432,40028 +13894,27576,30431,40147 +10904,27577,30430,40590 +14117,27578,30429,40319 +14478,27579,30428,40433 +14038,27580,30427,40746 +10914,27581,30426,40660 +11158,27582,30425,40310 +11374,27583,30424,40489 +12881,27584,30423,40703 +11050,27585,30422,40826 +11149,27586,30421,40915 +17470,27587,30420,40255 +17725,27588,30419,40446 +11379,27589,30418,40266 +11595,27590,30417,40291 +14273,27591,30416,40260 +11348,27592,30415,40140 +12358,27593,30414,40152 +14492,27594,30413,40930 +15518,27595,30412,40613 +10609,27596,30411,40856 +11298,27597,30410,40401 +11392,27598,30409,40234 +17281,27599,30408,40312 +13610,27600,30407,40595 +17399,27601,30406,40012 +13400,27602,30405,40388 +16670,27603,30404,40622 +14619,27604,30403,40336 +15932,27605,30402,40979 +14674,27606,30401,40428 +15348,27607,30400,40147 +17833,27608,30399,40316 +17080,27609,30398,40138 +18053,27610,30397,40984 +12830,27611,30396,40921 +10939,27612,30395,40742 +10531,27613,30394,40911 +10424,27614,30393,40314 +16750,27615,30392,40088 +14973,27616,30391,40992 +11700,27617,30390,40696 +10661,27618,30389,40905 +17450,27619,30388,40177 +17180,27620,30387,40619 +10331,27621,30386,40295 +12524,27622,30385,40259 +16753,27623,30384,40453 +14710,27624,30383,40535 +10543,27625,30382,40745 +15665,27626,30381,40982 +12347,27627,30380,40282 +12421,27628,30379,40608 +13431,27629,30378,40578 +11460,27630,30377,40194 +18044,27631,30376,40822 +16441,27632,30375,40633 +13587,27633,30374,40794 +13754,27634,30373,40424 +17221,27635,30372,40857 +13940,27636,30371,40317 +10919,27637,30370,40482 +16794,27638,30369,40773 +17389,27639,30368,40023 +17633,27640,30367,40592 +14627,27641,30366,40783 +10493,27642,30365,40303 +18046,27643,30364,40595 +15796,27644,30363,40210 +10174,27645,30362,40110 +15938,27646,30361,40902 +15484,27647,30360,40237 +17479,27648,30359,40835 +13003,27649,30358,40462 +11450,27650,30357,40780 +13282,27651,30356,40084 +10715,27652,30355,40824 +12254,27653,30354,40848 +11409,27654,30353,40517 +16515,27655,30352,40596 +16821,27656,30351,40236 +11954,27657,30350,40954 +12040,27658,30349,40839 +10203,27659,30348,40817 +11280,27660,30347,40983 +11043,27661,30346,40303 +11558,27662,30345,40219 +12384,27663,30344,40034 +15522,27664,30343,40410 +16233,27665,30342,40728 +15153,27666,30341,40593 +11537,27667,30340,40478 +12722,27668,30339,40024 +10341,27669,30338,40069 +14589,27670,30337,40783 +10916,27671,30336,40185 +16012,27672,30335,40799 +17703,27673,30334,40700 +17802,27674,30333,40443 +10787,27675,30332,40480 +13778,27676,30331,40244 +15844,27677,30330,40033 +15461,27678,30329,40372 +14825,27679,30328,40376 +12990,27680,30327,40242 +10788,27681,30326,40916 +15027,27682,30325,40380 +13785,27683,30324,40986 +10741,27684,30323,40923 +11130,27685,30322,40950 +10755,27686,30321,40048 +17437,27687,30320,40850 +15890,27688,30319,40412 +17199,27689,30318,40547 +16798,27690,30317,40565 +12077,27691,30316,40123 +13638,27692,30315,40837 +14119,27693,30314,40296 +17659,27694,30313,40437 +10569,27695,30312,40228 +11644,27696,30311,40638 +12206,27697,30310,40054 +16249,27698,30309,40512 +12547,27699,30308,40189 +16484,27700,30307,40339 +10935,27701,30306,40197 +16054,27702,30305,40659 +10532,27703,30304,40218 +12695,27704,30303,40361 +12228,27705,30302,40441 +11714,27706,30301,40180 +10333,27707,30300,40926 +11752,27708,30299,40966 +17283,27709,30298,40768 +12402,27710,30297,40658 +14538,27711,30296,40049 +16863,27712,30295,40748 +18150,27713,30294,40314 +13474,27714,30293,40033 +18142,27715,30292,40603 +10379,27716,30291,40645 +14340,27717,30290,40519 +17494,27718,30289,40780 +10436,27719,30288,40110 +14807,27720,30287,40664 +17948,27721,30286,40100 +16192,27722,30285,40297 +14290,27723,30284,40606 +14816,27724,30283,40770 +11620,27725,30282,40245 +13155,27726,30281,40936 +16761,27727,30280,40212 +11008,27728,30279,40046 +10767,27729,30278,40660 +15816,27730,30277,40043 +17859,27731,30276,40326 +11584,27732,30275,40621 +17072,27733,30274,40088 +15633,27734,30273,40639 +14889,27735,30272,40201 +10211,27736,30271,40574 +15892,27737,30270,40358 +12960,27738,30269,40193 +13460,27739,30268,40103 +17062,27740,30267,40567 +14662,27741,30266,40940 +13915,27742,30265,40178 +15339,27743,30264,40312 +17595,27744,30263,40889 +14706,27745,30262,40120 +16377,27746,30261,40571 +10326,27747,30260,40229 +15997,27748,30259,40775 +13195,27749,30258,40676 +15404,27750,30257,40033 +10877,27751,30256,40847 +14312,27752,30255,40343 +16971,27753,30254,40117 +12102,27754,30253,40457 +16364,27755,30252,40532 +15818,27756,30251,40223 +14933,27757,30250,40023 +16946,27758,30249,40820 +16433,27759,30248,40018 +15186,27760,30247,40544 +12258,27761,30246,40098 +14972,27762,30245,40252 +11779,27763,30244,40530 +15293,27764,30243,40063 +10461,27765,30242,40920 +13488,27766,30241,40669 +10402,27767,30240,40598 +14258,27768,30239,40270 +15958,27769,30238,40996 +17345,27770,30237,40629 +14339,27771,30236,40098 +17953,27772,30235,40159 +14821,27773,30234,40139 +16524,27774,30233,40803 +13168,27775,30232,40350 +13630,27776,30231,40825 +10442,27777,30230,40886 +16418,27778,30229,40739 +16178,27779,30228,40921 +10616,27780,30227,40256 +17227,27781,30226,40790 +15496,27782,30225,40287 +16423,27783,30224,40159 +13685,27784,30223,40137 +10672,27785,30222,40582 +13422,27786,30221,40015 +15810,27787,30220,40988 +17394,27788,30219,40946 +17121,27789,30218,40573 +18179,27790,30217,40178 +10803,27791,30216,40143 +17592,27792,30215,40366 +14725,27793,30214,40752 +12825,27794,30213,40026 +17709,27795,30212,40031 +14595,27796,30211,40655 +10017,27797,30210,40547 +13868,27798,30209,40508 +16641,27799,30208,40761 +11054,27800,30207,40618 +16801,27801,30206,40097 +15679,27802,30205,40157 +16514,27803,30204,40047 +17507,27804,30203,40294 +10794,27805,30202,40567 +11429,27806,30201,40821 +10247,27807,30200,40409 +12766,27808,30199,40988 +12552,27809,30198,40581 +17165,27810,30197,40511 +16811,27811,30196,40592 +12429,27812,30195,40264 +17834,27813,30194,40308 +15255,27814,30193,40159 +12140,27815,30192,40317 +12560,27816,30191,40622 +13184,27817,30190,40480 +11845,27818,30189,40114 +12066,27819,30188,40246 +12192,27820,30187,40517 +11809,27821,30186,40766 +13710,27822,30185,40313 +17313,27823,30184,40473 +16477,27824,30183,40167 +10652,27825,30182,40735 +11609,27826,30181,40557 +11213,27827,30180,40319 +12521,27828,30179,40958 +11201,27829,30178,40683 +16667,27830,30177,40276 +14872,27831,30176,40642 +10196,27832,30175,40424 +16695,27833,30174,40471 +14271,27834,30173,40882 +11405,27835,30172,40302 +11618,27836,30171,40044 +11368,27837,30170,40695 +16940,27838,30169,40680 +11588,27839,30168,40947 +11267,27840,30167,40586 +13958,27841,30166,40883 +13057,27842,30165,40145 +14885,27843,30164,40720 +14166,27844,30163,40599 +14203,27845,30162,40390 +15341,27846,30161,40991 +18145,27847,30160,40401 +11573,27848,30159,40614 +15643,27849,30158,40353 +10049,27850,30157,40266 +11707,27851,30156,40962 +10960,27852,30155,40871 +13543,27853,30154,40412 +18004,27854,30153,40128 +13182,27855,30152,40242 +15641,27856,30151,40987 +17589,27857,30150,40638 +15924,27858,30149,40085 +17732,27859,30148,40081 +13473,27860,30147,40301 +10839,27861,30146,40983 +16687,27862,30145,40741 +16626,27863,30144,40881 +10728,27864,30143,40242 +13081,27865,30142,40524 +15926,27866,30141,40116 +17764,27867,30140,40383 +13726,27868,30139,40289 +13699,27869,30138,40971 +16777,27870,30137,40589 +16776,27871,30136,40627 +15596,27872,30135,40372 +14812,27873,30134,40098 +13949,27874,30133,40615 +11851,27875,30132,40627 +16590,27876,30131,40061 +12822,27877,30130,40452 +16535,27878,30129,40953 +18149,27879,30128,40084 +10845,27880,30127,40489 +11974,27881,30126,40003 +15537,27882,30125,40455 +10647,27883,30124,40825 +13448,27884,30123,40512 +16479,27885,30122,40230 +12406,27886,30121,40945 +12719,27887,30120,40297 +13544,27888,30119,40826 +15973,27889,30118,40788 +16431,27890,30117,40907 +10988,27891,30116,40804 +15026,27892,30115,40666 +16625,27893,30114,40047 +17246,27894,30113,40575 +13912,27895,30112,40990 +16978,27896,30111,40311 +10592,27897,30110,40250 +14106,27898,30109,40052 +10286,27899,30108,40083 +10018,27900,30107,40030 +14357,27901,30106,40771 +15783,27902,30105,40618 +17963,27903,30104,40456 +16607,27904,30103,40024 +11858,27905,30102,40217 +15806,27906,30101,40843 +11465,27907,30100,40544 +14299,27908,30099,40426 +10516,27909,30098,40974 +13914,27910,30097,40507 +10321,27911,30096,40916 +14782,27912,30095,40527 +10861,27913,30094,40981 +14560,27914,30093,40153 +16852,27915,30092,40705 +15577,27916,30091,40112 +12114,27917,30090,40388 +17584,27918,30089,40411 +10517,27919,30088,40766 +10971,27920,30087,40780 +16752,27921,30086,40291 +11691,27922,30085,40589 +10126,27923,30084,40954 +10155,27924,30083,40423 +14039,27925,30082,40147 +17436,27926,30081,40986 +17502,27927,30080,40210 +15782,27928,30079,40487 +17622,27929,30078,40584 +18059,27930,30077,40233 +12815,27931,30076,40776 +11302,27932,30075,40441 +13158,27933,30074,40871 +12819,27934,30073,40537 +11993,27935,30072,40148 +13803,27936,30071,40392 +14063,27937,30070,40656 +16014,27938,30069,40604 +12937,27939,30068,40527 +12964,27940,30067,40054 +16275,27941,30066,40332 +14969,27942,30065,40983 +11099,27943,30064,40107 +14926,27944,30063,40353 +17532,27945,30062,40647 +17232,27946,30061,40544 +12894,27947,30060,40892 +12060,27948,30059,40487 +10417,27949,30058,40655 +13169,27950,30057,40734 +12517,27951,30056,40505 +14200,27952,30055,40737 +10806,27953,30054,40698 +13001,27954,30053,40509 +10889,27955,30052,40874 +15096,27956,30051,40035 +16724,27957,30050,40291 +18079,27958,30049,40039 +13076,27959,30048,40627 +12044,27960,30047,40194 +15429,27961,30046,40622 +15174,27962,30045,40235 +13615,27963,30044,40112 +15864,27964,30043,40364 +13836,27965,30042,40519 +11774,27966,30041,40088 +14447,27967,30040,40487 +16072,27968,30039,40699 +16042,27969,30038,40903 +12245,27970,30037,40634 +16202,27971,30036,40056 +14832,27972,30035,40930 +13304,27973,30034,40318 +13415,27974,30033,40220 +14852,27975,30032,40927 +12049,27976,30031,40637 +12349,27977,30030,40953 +17247,27978,30029,40772 +10258,27979,30028,40528 +18123,27980,30027,40485 +13475,27981,30026,40461 +14883,27982,30025,40123 +16480,27983,30024,40994 +14261,27984,30023,40098 +14556,27985,30022,40929 +11524,27986,30021,40241 +14476,27987,30020,40309 +17373,27988,30019,40262 +17183,27989,30018,40072 +13871,27990,30017,40108 +17286,27991,30016,40099 +11014,27992,30015,40104 +16888,27993,30014,40100 +17136,27994,30013,40017 +13060,27995,30012,40498 +17194,27996,30011,40294 +14503,27997,30010,40900 +16980,27998,30009,40297 +18094,27999,30008,40215 +10533,28000,30007,40961 +14561,28001,30006,40318 +15805,28002,30005,40013 +11603,28003,30004,40956 +16970,28004,30003,40148 +12301,28005,30002,40149 +14567,28006,30001,40018 +16222,28007,30000,40962 +18010,28008,31000,40885 +16922,28009,30999,40915 +14712,28010,30998,40286 +10525,28011,30997,40855 +15502,28012,30996,40786 +14705,28013,30995,40175 +15360,28014,30994,40840 +13477,28015,30993,40497 +14983,28016,30992,40293 +13332,28017,30991,40825 +15476,28018,30990,40867 +16734,28019,30989,40073 +16379,28020,30988,40104 +12596,28021,30987,40016 +13990,28022,30986,40787 +16065,28023,30985,40305 +14282,28024,30984,40097 +16447,28025,30983,40082 +10071,28026,30982,40782 +13412,28027,30981,40909 +11717,28028,30980,40231 +16981,28029,30979,40564 +17763,28030,30978,40275 +17488,28031,30977,40413 +11686,28032,30976,40722 +17933,28033,30975,40661 +13547,28034,30974,40742 +13698,28035,30973,40633 +14060,28036,30972,40430 +15492,28037,30971,40271 +16799,28038,30970,40554 +13023,28039,30969,40339 +10702,28040,30968,40256 +11459,28041,30967,40278 +12899,28042,30966,40668 +11103,28043,30965,40176 +15312,28044,30964,40207 +10511,28045,30963,40990 +15933,28046,30962,40879 +12337,28047,30961,40599 +13744,28048,30960,40572 +12145,28049,30959,40072 +17579,28050,30958,40946 +14452,28051,30957,40399 +16669,28052,30956,40770 +13563,28053,30955,40909 +10220,28054,30954,40403 +10607,28055,30953,40085 +17410,28056,30952,40710 +14127,28057,30951,40025 +17114,28058,30950,40791 +14778,28059,30949,40963 +17230,28060,30948,40551 +16567,28061,30947,40369 +10139,28062,30946,40646 +11024,28063,30945,40138 +12743,28064,30944,40590 +12780,28065,30943,40477 +13878,28066,30942,40355 +10130,28067,30941,40768 +17719,28068,30940,40839 +12951,28069,30939,40030 +11919,28070,30938,40002 +16457,28071,30937,40210 +13841,28072,30936,40118 +18137,28073,30935,40160 +11645,28074,30934,40400 +13648,28075,30933,40979 +10344,28076,30932,40323 +10818,28077,30931,40073 +16557,28078,30930,40430 +10199,28079,30929,40482 +10459,28080,30928,40806 +10501,28081,30927,40047 +12388,28082,30926,40294 +10565,28083,30925,40136 +14865,28084,30924,40146 +12239,28085,30923,40206 +13590,28086,30922,40804 +15034,28087,30921,40671 +12326,28088,30920,40141 +11318,28089,30919,40583 +15365,28090,30918,40405 +16164,28091,30917,40732 +14918,28092,30916,40030 +17421,28093,30915,40842 +10144,28094,30914,40234 +11639,28095,30913,40452 +15635,28096,30912,40150 +12723,28097,30911,40628 +10703,28098,30910,40622 +10756,28099,30909,40730 +15079,28100,30908,40415 +11614,28101,30907,40761 +12525,28102,30906,40131 +15640,28103,30905,40103 +14201,28104,30904,40047 +10836,28105,30903,40787 +12969,28106,30902,40513 +14999,28107,30901,40432 +12273,28108,30900,40413 +10050,28109,30899,40576 +12294,28110,30898,40735 +12505,28111,30897,40532 +10947,28112,30896,40746 +11266,28113,30895,40975 +14259,28114,30894,40375 +17339,28115,30893,40211 +13641,28116,30892,40650 +10499,28117,30891,40939 +17314,28118,30890,40702 +11056,28119,30889,40607 +15244,28120,30888,40360 +13241,28121,30887,40150 +18084,28122,30886,40488 +17041,28123,30885,40806 +12568,28124,30884,40596 +11795,28125,30883,40999 +12619,28126,30882,40312 +16629,28127,30881,40893 +12469,28128,30880,40376 +16118,28129,30879,40916 +13398,28130,30878,40038 +12955,28131,30877,40790 +12848,28132,30876,40718 +13389,28133,30875,40280 +18019,28134,30874,40806 +17832,28135,30873,40227 +16331,28136,30872,40315 +16586,28137,30871,40125 +17735,28138,30870,40583 +12712,28139,30869,40920 +12717,28140,30868,40151 +16780,28141,30867,40019 +10830,28142,30866,40841 +12122,28143,30865,40604 +14114,28144,30864,40602 +14079,28145,30863,40775 +14239,28146,30862,40069 +11541,28147,30861,40064 +14955,28148,30860,40112 +17473,28149,30859,40364 +13366,28150,30858,40041 +13534,28151,30857,40693 +17636,28152,30856,40638 +16436,28153,30855,40541 +16443,28154,30854,40153 +16097,28155,30853,40586 +17721,28156,30852,40122 +11321,28157,30851,40368 +11821,28158,30850,40462 +17738,28159,30849,40436 +13465,28160,30848,40318 +16767,28161,30847,40196 +11104,28162,30846,40586 +10903,28163,30845,40364 +14202,28164,30844,40932 +16067,28165,30843,40043 +11091,28166,30842,40346 +13111,28167,30841,40052 +14508,28168,30840,40659 +11078,28169,30839,40032 +11322,28170,30838,40506 +15851,28171,30837,40361 +11612,28172,30836,40664 +17801,28173,30835,40418 +12006,28174,30834,40460 +10777,28175,30833,40042 +18024,28176,30832,40822 +13693,28177,30831,40751 +17931,28178,30830,40129 +16132,28179,30829,40231 +14465,28180,30828,40454 +16158,28181,30827,40873 +12379,28182,30826,40349 +16009,28183,30825,40842 +15081,28184,30824,40943 +10537,28185,30823,40004 +10068,28186,30822,40343 +10016,28187,30821,40057 +11782,28188,30820,40998 +14792,28189,30819,40741 +17050,28190,30818,40950 +10450,28191,30817,40433 diff --git a/regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column.out b/regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column.out new file mode 100644 index 00000000000000..34b36e765f4728 --- /dev/null +++ b/regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column.out @@ -0,0 +1,19 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select1 -- +12345 23083 \N 30920 40410 + +-- !select2 -- +17320 24209 \N 30795 40000 + +-- !select3 -- +59832 36673 \N 30343 40299 + +-- !select1 -- +12345 23083 \N 30920 40410 + +-- !select2 -- +17320 24209 \N 30795 40782 + +-- !select3 -- +59832 36673 \N 30586 40739 + diff --git a/regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column1.csv b/regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column1.csv new file mode 100644 index 00000000000000..6cd6e2aec3c033 --- /dev/null +++ b/regression-test/data/unique_with_mow_c_p0/test_schema_change_add_key_column1.csv @@ -0,0 +1,20480 @@ +50019,20000,31000,40444 +57401,20001,30999,40084 +58347,20002,30998,40429 +52118,20003,30997,40438 +57056,20004,30996,40132 +54769,20005,30995,40174 +58735,20006,30994,40013 +56920,20007,30993,40432 +51358,20008,30992,40513 +59832,20009,30991,40589 +51219,20010,30990,40032 +52735,20011,30989,40174 +50975,20012,30988,40889 +57635,20013,30987,40742 +52952,20014,30986,40473 +57067,20015,30985,40642 +55892,20016,30984,40445 +57819,20017,30983,40389 +57041,20018,30982,40494 +52093,20019,30981,40636 +55585,20020,30980,40569 +51707,20021,30979,40994 +58147,20022,30978,40287 +58985,20023,30977,40001 +57405,20024,30976,40896 +57166,20025,30975,40774 +51045,20026,30974,40831 +56532,20027,30973,40335 +51375,20028,30972,40689 +58213,20029,30971,40372 +50128,20030,30970,40744 +51829,20031,30969,40736 +56546,20032,30968,40655 +57023,20033,30967,40218 +53808,20034,30966,40393 +53959,20035,30965,40260 +50497,20036,30964,40234 +56047,20037,30963,40823 +59841,20038,30962,40809 +56805,20039,30961,40177 +50235,20040,30960,40016 +59546,20041,30959,40940 +57795,20042,30958,40498 +57165,20043,30957,40516 +56783,20044,30956,40328 +51669,20045,30955,40981 +52646,20046,30954,40488 +53678,20047,30953,40743 +58209,20048,30952,40699 +51546,20049,30951,40775 +51550,20050,30950,40434 +57753,20051,30949,40843 +56019,20052,30948,40196 +51859,20053,30947,40513 +55791,20054,30946,40741 +59682,20055,30945,40364 +54508,20056,30944,40782 +55005,20057,30943,40661 +51233,20058,30942,40366 +59967,20059,30941,40690 +59428,20060,30940,40154 +57447,20061,30939,40165 +55453,20062,30938,40462 +56376,20063,30937,40940 +52197,20064,30936,40808 +54496,20065,30935,40072 +58909,20066,30934,40165 +50245,20067,30933,40484 +54427,20068,30932,40602 +57483,20069,30931,40588 +58207,20070,30930,40585 +52883,20071,30929,40199 +56740,20072,30928,40046 +58334,20073,30927,40595 +59923,20074,30926,40637 +56031,20075,30925,40564 +54033,20076,30924,40514 +56526,20077,30923,40712 +58504,20078,30922,40597 +58440,20079,30921,40362 +57203,20080,30920,40656 +55348,20081,30919,40673 +55186,20082,30918,40606 +56112,20083,30917,40508 +52686,20084,30916,40505 +52922,20085,30915,40148 +55862,20086,30914,40752 +55340,20087,30913,40022 +57672,20088,30912,40516 +51182,20089,30911,40947 +56060,20090,30910,40133 +54447,20091,30909,40054 +53210,20092,30908,40997 +55982,20093,30907,40042 +55324,20094,30906,40017 +53346,20095,30905,40381 +50157,20096,30904,40384 +57850,20097,30903,40365 +50545,20098,30902,40305 +58463,20099,30901,40510 +59342,20100,30900,40781 +51749,20101,30899,40925 +55752,20102,30898,40246 +52288,20103,30897,40300 +59531,20104,30896,40875 +50516,20105,30895,40393 +51921,20106,30894,40937 +58596,20107,30893,40837 +50243,20108,30892,40439 +55452,20109,30891,40623 +54044,20110,30890,40830 +57354,20111,30889,40218 +53466,20112,30888,40507 +52455,20113,30887,40754 +56861,20114,30886,40859 +59044,20115,30885,40566 +50546,20116,30884,40634 +57455,20117,30883,40242 +58969,20118,30882,40143 +52917,20119,30881,40621 +51649,20120,30880,40288 +54129,20121,30879,40561 +59622,20122,30878,40421 +55603,20123,30877,40308 +53105,20124,30876,40019 +59900,20125,30875,40290 +57214,20126,30874,40224 +59605,20127,30873,40437 +59867,20128,30872,40294 +52399,20129,30871,40666 +57388,20130,30870,40663 +52405,20131,30869,40705 +50091,20132,30868,40731 +55389,20133,30867,40017 +50844,20134,30866,40288 +52014,20135,30865,40101 +51663,20136,30864,40814 +57212,20137,30863,40111 +50735,20138,30862,40413 +51598,20139,30861,40792 +51271,20140,30860,40662 +53217,20141,30859,40025 +52324,20142,30858,40636 +58197,20143,30857,40561 +58262,20144,30856,40389 +51477,20145,30855,40539 +54352,20146,30854,40072 +55956,20147,30853,40946 +55887,20148,30852,40389 +58067,20149,30851,40068 +56375,20150,30850,40619 +51215,20151,30849,40417 +58840,20152,30848,40394 +54215,20153,30847,40887 +57327,20154,30846,40926 +59339,20155,30845,40636 +51882,20156,30844,40284 +58255,20157,30843,40022 +55700,20158,30842,40924 +55583,20159,30841,40730 +59870,20160,30840,40899 +57358,20161,30839,40615 +52670,20162,30838,40148 +55063,20163,30837,40734 +56673,20164,30836,40571 +51604,20165,30835,40881 +55324,20166,30834,40774 +54252,20167,30833,40493 +55696,20168,30832,40448 +55286,20169,30831,40909 +51916,20170,30830,40898 +57980,20171,30829,40372 +53420,20172,30828,40992 +58508,20173,30827,40127 +55215,20174,30826,40678 +52776,20175,30825,40829 +59943,20176,30824,40085 +57533,20177,30823,40067 +57002,20178,30822,40159 +51200,20179,30821,40400 +58933,20180,30820,40162 +51060,20181,30819,40210 +53423,20182,30818,40020 +59913,20183,30817,40164 +53499,20184,30816,40747 +51790,20185,30815,40789 +53560,20186,30814,40743 +53319,20187,30813,40357 +58611,20188,30812,40135 +54457,20189,30811,40190 +56380,20190,30810,40765 +52050,20191,30809,40541 +54278,20192,30808,40103 +57030,20193,30807,40931 +57751,20194,30806,40723 +52437,20195,30805,40965 +53119,20196,30804,40182 +57592,20197,30803,40844 +57030,20198,30802,40113 +58185,20199,30801,40794 +54302,20200,30800,40552 +59906,20201,30799,40986 +58152,20202,30798,40608 +52078,20203,30797,40178 +56594,20204,30796,40541 +56173,20205,30795,40328 +51838,20206,30794,40717 +55507,20207,30793,40990 +53165,20208,30792,40053 +59839,20209,30791,40371 +52986,20210,30790,40493 +50632,20211,30789,40376 +52772,20212,30788,40330 +56531,20213,30787,40323 +58339,20214,30786,40489 +55874,20215,30785,40035 +53212,20216,30784,40019 +54263,20217,30783,40546 +56735,20218,30782,40033 +56663,20219,30781,40136 +52686,20220,30780,40773 +53145,20221,30779,40105 +50584,20222,30778,40066 +55085,20223,30777,40253 +50147,20224,30776,40138 +59257,20225,30775,40407 +59431,20226,30774,40754 +50959,20227,30773,40381 +59303,20228,30772,40531 +56331,20229,30771,40588 +51355,20230,30770,40968 +51751,20231,30769,40020 +59897,20232,30768,40927 +52481,20233,30767,40855 +54371,20234,30766,40086 +52069,20235,30765,40250 +53641,20236,30764,40820 +54148,20237,30763,40373 +59663,20238,30762,40049 +55606,20239,30761,40565 +59017,20240,30760,40834 +59259,20241,30759,40507 +51138,20242,30758,40389 +50845,20243,30757,40377 +59677,20244,30756,40397 +53841,20245,30755,40808 +58418,20246,30754,40203 +53069,20247,30753,40049 +53978,20248,30752,40569 +51379,20249,30751,40758 +59734,20250,30750,40540 +55147,20251,30749,40932 +54153,20252,30748,40093 +57039,20253,30747,40872 +56519,20254,30746,40484 +57376,20255,30745,40531 +55765,20256,30744,40891 +55719,20257,30743,40923 +59935,20258,30742,40474 +59477,20259,30741,40111 +51640,20260,30740,40451 +52219,20261,30739,40038 +55596,20262,30738,40748 +53366,20263,30737,40173 +57890,20264,30736,40661 +50578,20265,30735,40171 +58093,20266,30734,40765 +56031,20267,30733,40299 +50738,20268,30732,40974 +59409,20269,30731,40710 +53827,20270,30730,40153 +56545,20271,30729,40138 +54170,20272,30728,40671 +56769,20273,30727,40907 +52737,20274,30726,40645 +53901,20275,30725,40955 +53614,20276,30724,40107 +58941,20277,30723,40985 +57005,20278,30722,40009 +51639,20279,30721,40868 +57157,20280,30720,40174 +57761,20281,30719,40811 +53948,20282,30718,40135 +52724,20283,30717,40034 +57670,20284,30716,40849 +55644,20285,30715,40082 +54041,20286,30714,40699 +58539,20287,30713,40590 +57148,20288,30712,40162 +58558,20289,30711,40486 +50510,20290,30710,40866 +58504,20291,30709,40218 +58482,20292,30708,40326 +56442,20293,30707,40181 +58680,20294,30706,40453 +52804,20295,30705,40139 +50023,20296,30704,40729 +50389,20297,30703,40480 +50823,20298,30702,40677 +55277,20299,30701,40134 +59499,20300,30700,40810 +53892,20301,30699,40578 +51003,20302,30698,40902 +58308,20303,30697,40964 +56479,20304,30696,40386 +58241,20305,30695,40882 +51512,20306,30694,40254 +51097,20307,30693,40896 +52041,20308,30692,40467 +53559,20309,30691,40941 +51506,20310,30690,40628 +57761,20311,30689,40285 +52733,20312,30688,40370 +56369,20313,30687,40598 +52481,20314,30686,40107 +56656,20315,30685,40186 +57364,20316,30684,40198 +51214,20317,30683,40129 +50334,20318,30682,40902 +53775,20319,30681,40255 +57208,20320,30680,40761 +54271,20321,30679,40313 +51475,20322,30678,40539 +54966,20323,30677,40703 +53589,20324,30676,40508 +56199,20325,30675,40591 +56399,20326,30674,40282 +50162,20327,30673,40990 +53098,20328,30672,40732 +50233,20329,30671,40571 +50351,20330,30670,40837 +56832,20331,30669,40954 +51893,20332,30668,40041 +56862,20333,30667,40842 +56885,20334,30666,40847 +55968,20335,30665,40196 +59610,20336,30664,40819 +55676,20337,30663,40208 +58197,20338,30662,40775 +53170,20339,30661,40142 +50237,20340,30660,40333 +51519,20341,30659,40533 +54898,20342,30658,40876 +51835,20343,30657,40315 +58082,20344,30656,40412 +50163,20345,30655,40466 +50613,20346,30654,40879 +58161,20347,30653,40795 +57203,20348,30652,40399 +51047,20349,30651,40074 +59206,20350,30650,40606 +56954,20351,30649,40758 +59482,20352,30648,40693 +51339,20353,30647,40395 +59408,20354,30646,40845 +51393,20355,30645,40710 +58754,20356,30644,40476 +52018,20357,30643,40068 +50257,20358,30642,40956 +53153,20359,30641,40471 +55898,20360,30640,40726 +54032,20361,30639,40703 +57495,20362,30638,40782 +50343,20363,30637,40249 +57825,20364,30636,40899 +56301,20365,30635,40846 +58243,20366,30634,40845 +53635,20367,30633,40426 +50458,20368,30632,40891 +57456,20369,30631,40454 +54121,20370,30630,40865 +52231,20371,30629,40341 +53977,20372,30628,40370 +50693,20373,30627,40112 +59214,20374,30626,40984 +54758,20375,30625,40799 +56708,20376,30624,40149 +50087,20377,30623,40053 +52584,20378,30622,40884 +59366,20379,30621,40942 +54035,20380,30620,40585 +56213,20381,30619,40088 +58593,20382,30618,40066 +58270,20383,30617,40211 +58304,20384,30616,40737 +56752,20385,30615,40053 +53604,20386,30614,40983 +52488,20387,30613,40222 +50983,20388,30612,40726 +58683,20389,30611,40830 +50878,20390,30610,40611 +57887,20391,30609,40822 +59735,20392,30608,40726 +53802,20393,30607,40834 +51165,20394,30606,40479 +59682,20395,30605,40080 +51870,20396,30604,40551 +58515,20397,30603,40181 +51284,20398,30602,40464 +50399,20399,30601,40381 +51008,20400,30600,40858 +59519,20401,30599,40980 +58533,20402,30598,40123 +50152,20403,30597,40062 +53936,20404,30596,40050 +53033,20405,30595,40648 +58869,20406,30594,40649 +58753,20407,30593,40265 +51540,20408,30592,40396 +57613,20409,30591,40520 +56587,20410,30590,40642 +53071,20411,30589,40651 +52485,20412,30588,40231 +54730,20413,30587,40137 +58976,20414,30586,40451 +50090,20415,30585,40285 +52476,20416,30584,40747 +55472,20417,30583,40975 +50495,20418,30582,40130 +50731,20419,30581,40632 +57766,20420,30580,40403 +58018,20421,30579,40834 +53270,20422,30578,40422 +56110,20423,30577,40035 +54497,20424,30576,40477 +55893,20425,30575,40964 +56931,20426,30574,40745 +58977,20427,30573,40346 +58092,20428,30572,40190 +54991,20429,30571,40607 +59176,20430,30570,40543 +53394,20431,30569,40238 +57578,20432,30568,40904 +55672,20433,30567,40850 +56711,20434,30566,40503 +59621,20435,30565,40753 +58287,20436,30564,40085 +51867,20437,30563,40626 +55030,20438,30562,40878 +57355,20439,30561,40816 +54544,20440,30560,40987 +55493,20441,30559,40514 +57964,20442,30558,40568 +50588,20443,30557,40777 +59815,20444,30556,40511 +59413,20445,30555,40301 +57169,20446,30554,40905 +53725,20447,30553,40156 +56317,20448,30552,40404 +50666,20449,30551,40056 +51937,20450,30550,40477 +53834,20451,30549,40556 +53374,20452,30548,40715 +56232,20453,30547,40099 +59225,20454,30546,40846 +56045,20455,30545,40501 +50072,20456,30544,40314 +55314,20457,30543,40198 +59320,20458,30542,40572 +54148,20459,30541,40237 +52251,20460,30540,40327 +50177,20461,30539,40406 +53183,20462,30538,40371 +56382,20463,30537,40252 +50041,20464,30536,40164 +53291,20465,30535,40951 +58177,20466,30534,40922 +59758,20467,30533,40485 +52583,20468,30532,40306 +51052,20469,30531,40353 +54419,20470,30530,40808 +52534,20471,30529,40709 +59146,20472,30528,40727 +52128,20473,30527,40164 +55085,20474,30526,40527 +51437,20475,30525,40809 +51707,20476,30524,40122 +51926,20477,30523,40293 +52102,20478,30522,40483 +56169,20479,30521,40417 +53395,20480,30520,40459 +59454,20481,30519,40801 +56043,20482,30518,40889 +51221,20483,30517,40041 +50543,20484,30516,40502 +51227,20485,30515,40087 +55352,20486,30514,40658 +53212,20487,30513,40148 +51516,20488,30512,40518 +50146,20489,30511,40016 +56796,20490,30510,40367 +51707,20491,30509,40377 +55739,20492,30508,40651 +50169,20493,30507,40120 +57418,20494,30506,40476 +51938,20495,30505,40840 +59118,20496,30504,40254 +58168,20497,30503,40140 +54866,20498,30502,40263 +58995,20499,30501,40795 +57832,20500,30500,40978 +58682,20501,30499,40027 +51851,20502,30498,40135 +57441,20503,30497,40471 +52609,20504,30496,40515 +55901,20505,30495,40630 +58012,20506,30494,40815 +53138,20507,30493,40578 +57183,20508,30492,40936 +52461,20509,30491,40297 +53134,20510,30490,40042 +55037,20511,30489,40788 +55758,20512,30488,40489 +52268,20513,30487,40450 +54459,20514,30486,40358 +57900,20515,30485,40504 +55769,20516,30484,40659 +57181,20517,30483,40311 +51890,20518,30482,40723 +54043,20519,30481,40618 +58653,20520,30480,40705 +51332,20521,30479,40698 +55888,20522,30478,40867 +54822,20523,30477,40112 +55020,20524,30476,40498 +52311,20525,30475,40678 +50855,20526,30474,40513 +50094,20527,30473,40034 +55655,20528,30472,40712 +58383,20529,30471,40776 +52922,20530,30470,40804 +57109,20531,30469,40195 +58547,20532,30468,40740 +56183,20533,30467,40864 +58159,20534,30466,40755 +53597,20535,30465,40359 +54741,20536,30464,40525 +58667,20537,30463,40511 +55259,20538,30462,40535 +57196,20539,30461,40533 +57973,20540,30460,40640 +50202,20541,30459,40201 +58473,20542,30458,40350 +57130,20543,30457,40853 +54894,20544,30456,40078 +55829,20545,30455,40442 +50563,20546,30454,40540 +51824,20547,30453,40705 +51996,20548,30452,40882 +58269,20549,30451,40842 +53382,20550,30450,40857 +54874,20551,30449,40165 +52124,20552,30448,40890 +54327,20553,30447,40475 +56098,20554,30446,40496 +57590,20555,30445,40111 +55631,20556,30444,40236 +52059,20557,30443,40311 +55799,20558,30442,40995 +56819,20559,30441,40145 +54342,20560,30440,40344 +58272,20561,30439,40044 +56345,20562,30438,40634 +54386,20563,30437,40484 +58055,20564,30436,40801 +51138,20565,30435,40649 +59965,20566,30434,40963 +51688,20567,30433,40837 +53046,20568,30432,40853 +59212,20569,30431,40688 +57929,20570,30430,40704 +52473,20571,30429,40922 +55260,20572,30428,40458 +55646,20573,30427,40372 +59095,20574,30426,40150 +58846,20575,30425,40003 +52787,20576,30424,40041 +59863,20577,30423,40722 +57618,20578,30422,40682 +58639,20579,30421,40211 +57496,20580,30420,40085 +50475,20581,30419,40737 +57558,20582,30418,40715 +53738,20583,30417,40661 +58455,20584,30416,40874 +58013,20585,30415,40187 +53156,20586,30414,40453 +55626,20587,30413,40897 +50610,20588,30412,40616 +50758,20589,30411,40964 +50779,20590,30410,40706 +50831,20591,30409,40638 +55626,20592,30408,40958 +54124,20593,30407,40776 +54256,20594,30406,40616 +56428,20595,30405,40551 +56611,20596,30404,40113 +51851,20597,30403,40382 +56726,20598,30402,40327 +59763,20599,30401,40673 +55956,20600,30400,40420 +57615,20601,30399,40793 +54646,20602,30398,40210 +52187,20603,30397,40704 +58164,20604,30396,40080 +50183,20605,30395,40123 +52504,20606,30394,40451 +52922,20607,30393,40999 +55646,20608,30392,40787 +53667,20609,30391,40137 +55143,20610,30390,40040 +50059,20611,30389,40606 +56733,20612,30388,40498 +54439,20613,30387,40076 +54177,20614,30386,40242 +50233,20615,30385,40731 +54288,20616,30384,40721 +58165,20617,30383,40556 +56692,20618,30382,40546 +59457,20619,30381,40508 +50919,20620,30380,40222 +54326,20621,30379,40572 +55298,20622,30378,40437 +55796,20623,30377,40617 +58547,20624,30376,40724 +51729,20625,30375,40427 +55421,20626,30374,40031 +58786,20627,30373,40100 +54889,20628,30372,40923 +51058,20629,30371,40359 +51387,20630,30370,40656 +58559,20631,30369,40186 +57103,20632,30368,40546 +53236,20633,30367,40225 +57522,20634,30366,40388 +51809,20635,30365,40744 +51373,20636,30364,40144 +54839,20637,30363,40789 +54828,20638,30362,40708 +53375,20639,30361,40328 +59486,20640,30360,40716 +56410,20641,30359,40808 +57956,20642,30358,40279 +50307,20643,30357,40076 +54716,20644,30356,40913 +59089,20645,30355,40210 +51143,20646,30354,40030 +56441,20647,30353,40575 +57862,20648,30352,40910 +53600,20649,30351,40308 +53428,20650,30350,40809 +55997,20651,30349,40609 +50285,20652,30348,40351 +52861,20653,30347,40001 +57388,20654,30346,40100 +57072,20655,30345,40929 +58129,20656,30344,40775 +58497,20657,30343,40838 +53698,20658,30342,40718 +55348,20659,30341,40570 +52024,20660,30340,40592 +58663,20661,30339,40291 +56538,20662,30338,40454 +53274,20663,30337,40520 +56728,20664,30336,40679 +58203,20665,30335,40505 +56206,20666,30334,40454 +55995,20667,30333,40898 +52744,20668,30332,40346 +50732,20669,30331,40539 +55588,20670,30330,40698 +56764,20671,30329,40351 +51090,20672,30328,40347 +58347,20673,30327,40407 +56249,20674,30326,40359 +54551,20675,30325,40731 +59683,20676,30324,40076 +54425,20677,30323,40276 +52473,20678,30322,40534 +59560,20679,30321,40521 +55881,20680,30320,40458 +59708,20681,30319,40627 +54915,20682,30318,40504 +52813,20683,30317,40335 +54611,20684,30316,40691 +50202,20685,30315,40256 +52889,20686,30314,40473 +56677,20687,30313,40479 +50037,20688,30312,40218 +51883,20689,30311,40384 +58973,20690,30310,40079 +53042,20691,30309,40506 +51873,20692,30308,40560 +50923,20693,30307,40802 +55957,20694,30306,40657 +56262,20695,30305,40068 +55885,20696,30304,40090 +57221,20697,30303,40056 +53784,20698,30302,40906 +55609,20699,30301,40549 +50867,20700,30300,40455 +57752,20701,30299,40517 +56078,20702,30298,40413 +50848,20703,30297,40484 +50012,20704,30296,40657 +57414,20705,30295,40997 +58212,20706,30294,40872 +54471,20707,30293,40779 +59284,20708,30292,40280 +52512,20709,30291,40266 +52581,20710,30290,40371 +55464,20711,30289,40784 +51417,20712,30288,40132 +54538,20713,30287,40867 +57953,20714,30286,40864 +53313,20715,30285,40463 +50539,20716,30284,40322 +59949,20717,30283,40436 +59289,20718,30282,40890 +59970,20719,30281,40098 +55197,20720,30280,40387 +50623,20721,30279,40858 +56192,20722,30278,40799 +52860,20723,30277,40187 +56530,20724,30276,40634 +52300,20725,30275,40246 +53531,20726,30274,40264 +58738,20727,30273,40510 +52512,20728,30272,40836 +54640,20729,30271,40847 +53602,20730,30270,40534 +54715,20731,30269,40354 +50032,20732,30268,40887 +52378,20733,30267,40234 +55964,20734,30266,40572 +59437,20735,30265,40110 +50411,20736,30264,40973 +52267,20737,30263,40491 +54646,20738,30262,40937 +55683,20739,30261,40325 +56846,20740,30260,40704 +57492,20741,30259,40771 +53372,20742,30258,40652 +54104,20743,30257,40788 +52598,20744,30256,40453 +55099,20745,30255,40353 +53214,20746,30254,40680 +51898,20747,30253,40841 +55733,20748,30252,40219 +58614,20749,30251,40523 +51420,20750,30250,40519 +50679,20751,30249,40443 +57227,20752,30248,40675 +50397,20753,30247,40148 +58122,20754,30246,40793 +59218,20755,30245,40230 +50764,20756,30244,40951 +54588,20757,30243,40853 +59324,20758,30242,40308 +51646,20759,30241,40878 +51920,20760,30240,40868 +51630,20761,30239,40534 +53338,20762,30238,40242 +50241,20763,30237,40600 +55022,20764,30236,40546 +50882,20765,30235,40483 +59837,20766,30234,40584 +58274,20767,30233,40054 +52175,20768,30232,40784 +57994,20769,30231,40369 +58000,20770,30230,40123 +57964,20771,30229,40305 +57617,20772,30228,40474 +53815,20773,30227,40231 +55759,20774,30226,40754 +55832,20775,30225,40159 +57745,20776,30224,40733 +58910,20777,30223,40392 +55722,20778,30222,40457 +56374,20779,30221,40084 +51967,20780,30220,40727 +54405,20781,30219,40213 +50771,20782,30218,40122 +52116,20783,30217,40634 +54285,20784,30216,40137 +54181,20785,30215,40589 +53499,20786,30214,40283 +57268,20787,30213,40635 +52768,20788,30212,40918 +51529,20789,30211,40079 +55736,20790,30210,40196 +57434,20791,30209,40955 +53741,20792,30208,40579 +59534,20793,30207,40332 +50002,20794,30206,40239 +58092,20795,30205,40240 +59660,20796,30204,40279 +54385,20797,30203,40847 +52929,20798,30202,40880 +53600,20799,30201,40555 +59992,20800,30200,40570 +50035,20801,30199,40198 +51504,20802,30198,40925 +59904,20803,30197,40223 +52269,20804,30196,40415 +57256,20805,30195,40744 +54925,20806,30194,40829 +56745,20807,30193,40807 +50472,20808,30192,40547 +59298,20809,30191,40838 +54358,20810,30190,40826 +55878,20811,30189,40777 +50890,20812,30188,40997 +57610,20813,30187,40132 +58412,20814,30186,40552 +54025,20815,30185,40678 +55621,20816,30184,40734 +56088,20817,30183,40526 +57971,20818,30182,40214 +54083,20819,30181,40673 +57708,20820,30180,40408 +56117,20821,30179,40397 +56336,20822,30178,40617 +54503,20823,30177,40222 +53431,20824,30176,40385 +55216,20825,30175,40986 +53129,20826,30174,40029 +51930,20827,30173,40370 +56268,20828,30172,40486 +51173,20829,30171,40959 +56792,20830,30170,40518 +52565,20831,30169,40215 +59943,20832,30168,40322 +55367,20833,30167,40291 +59096,20834,30166,40400 +52721,20835,30165,40854 +58610,20836,30164,40462 +59430,20837,30163,40188 +54614,20838,30162,40452 +54121,20839,30161,40396 +52061,20840,30160,40656 +58905,20841,30159,40276 +51456,20842,30158,40636 +58763,20843,30157,40287 +56231,20844,30156,40526 +58502,20845,30155,40182 +53433,20846,30154,40996 +54679,20847,30153,40640 +52546,20848,30152,40945 +59892,20849,30151,40783 +59474,20850,30150,40329 +51438,20851,30149,40353 +54898,20852,30148,40877 +57039,20853,30147,40591 +51138,20854,30146,40651 +59859,20855,30145,40838 +59150,20856,30144,40037 +55428,20857,30143,40815 +53359,20858,30142,40836 +52877,20859,30141,40733 +50493,20860,30140,40753 +59936,20861,30139,40667 +50354,20862,30138,40519 +56322,20863,30137,40959 +54986,20864,30136,40609 +58244,20865,30135,40695 +56375,20866,30134,40468 +58621,20867,30133,40511 +54209,20868,30132,40416 +59699,20869,30131,40563 +56922,20870,30130,40608 +59945,20871,30129,40719 +52031,20872,30128,40948 +57618,20873,30127,40121 +52250,20874,30126,40487 +54100,20875,30125,40960 +50436,20876,30124,40122 +56839,20877,30123,40939 +50393,20878,30122,40052 +53196,20879,30121,40480 +58564,20880,30120,40412 +51995,20881,30119,40751 +51945,20882,30118,40645 +51524,20883,30117,40835 +53041,20884,30116,40732 +53207,20885,30115,40541 +55376,20886,30114,40905 +54576,20887,30113,40596 +51442,20888,30112,40144 +51146,20889,30111,40861 +58404,20890,30110,40011 +57412,20891,30109,40674 +58944,20892,30108,40390 +51200,20893,30107,40818 +52960,20894,30106,40006 +51320,20895,30105,40646 +59603,20896,30104,40678 +55916,20897,30103,40619 +50589,20898,30102,40128 +58198,20899,30101,40217 +58040,20900,30100,40533 +50687,20901,30099,40295 +57465,20902,30098,40161 +58170,20903,30097,40928 +55038,20904,30096,40534 +57901,20905,30095,40918 +59939,20906,30094,40883 +51393,20907,30093,40641 +54115,20908,30092,40024 +52415,20909,30091,40180 +59579,20910,30090,40033 +57114,20911,30089,40157 +58523,20912,30088,40669 +56235,20913,30087,40335 +58870,20914,30086,40001 +59799,20915,30085,40070 +58409,20916,30084,40630 +53918,20917,30083,40990 +50248,20918,30082,40100 +56380,20919,30081,40192 +56532,20920,30080,40601 +57410,20921,30079,40401 +56153,20922,30078,40931 +53487,20923,30077,40577 +53139,20924,30076,40133 +50503,20925,30075,40069 +54544,20926,30074,40121 +52454,20927,30073,40962 +54529,20928,30072,40826 +56190,20929,30071,40007 +50586,20930,30070,40237 +51563,20931,30069,40853 +54937,20932,30068,40268 +53768,20933,30067,40686 +57939,20934,30066,40366 +50059,20935,30065,40030 +56922,20936,30064,40167 +52795,20937,30063,40675 +52490,20938,30062,40407 +58498,20939,30061,40053 +56387,20940,30060,40881 +54621,20941,30059,40745 +59937,20942,30058,40226 +55584,20943,30057,40240 +51511,20944,30056,40796 +54214,20945,30055,40271 +55179,20946,30054,40119 +56038,20947,30053,40987 +58266,20948,30052,40907 +53314,20949,30051,40746 +58108,20950,30050,40675 +58697,20951,30049,40649 +58642,20952,30048,40937 +59484,20953,30047,40926 +52460,20954,30046,40043 +57422,20955,30045,40585 +58967,20956,30044,40511 +52596,20957,30043,40324 +54020,20958,30042,40633 +55244,20959,30041,40203 +57683,20960,30040,40437 +57673,20961,30039,40434 +50510,20962,30038,40898 +53916,20963,30037,40451 +54594,20964,30036,40174 +55471,20965,30035,40400 +56760,20966,30034,40408 +59628,20967,30033,40002 +50723,20968,30032,40214 +50234,20969,30031,40223 +55761,20970,30030,40347 +58567,20971,30029,40842 +55204,20972,30028,40156 +54817,20973,30027,40242 +50203,20974,30026,40072 +56062,20975,30025,40832 +58185,20976,30024,40146 +50987,20977,30023,40486 +52615,20978,30022,40268 +57249,20979,30021,40065 +55333,20980,30020,40866 +56020,20981,30019,40091 +53147,20982,30018,40904 +54246,20983,30017,40064 +57006,20984,30016,40920 +59113,20985,30015,40882 +56079,20986,30014,40476 +55489,20987,30013,40163 +55165,20988,30012,40068 +50087,20989,30011,40774 +53162,20990,30010,40925 +53514,20991,30009,40891 +58843,20992,30008,40583 +57407,20993,30007,40861 +54281,20994,30006,40008 +50266,20995,30005,40162 +58661,20996,30004,40226 +59381,20997,30003,40798 +57913,20998,30002,40254 +57165,20999,30001,40460 +52665,21000,30000,40548 +51116,21001,31000,40195 +54952,21002,30999,40641 +53440,21003,30998,40424 +55878,21004,30997,40579 +56779,21005,30996,40086 +53655,21006,30995,40603 +54740,21007,30994,40766 +58191,21008,30993,40463 +52618,21009,30992,40597 +52506,21010,30991,40155 +55145,21011,30990,40585 +55864,21012,30989,40275 +57077,21013,30988,40039 +54757,21014,30987,40616 +52259,21015,30986,40908 +53655,21016,30985,40725 +54263,21017,30984,40413 +57328,21018,30983,40261 +51816,21019,30982,40102 +54596,21020,30981,40964 +52176,21021,30980,40572 +56820,21022,30979,40886 +50688,21023,30978,40240 +52520,21024,30977,40183 +53744,21025,30976,40296 +50172,21026,30975,40231 +57411,21027,30974,40787 +57921,21028,30973,40601 +53417,21029,30972,40184 +58004,21030,30971,40554 +51902,21031,30970,40243 +57292,21032,30969,40697 +52735,21033,30968,40094 +57661,21034,30967,40079 +55117,21035,30966,40977 +55929,21036,30965,40667 +54539,21037,30964,40381 +51078,21038,30963,40738 +56002,21039,30962,40242 +55675,21040,30961,40378 +51939,21041,30960,40907 +53908,21042,30959,40762 +54396,21043,30958,40139 +56757,21044,30957,40128 +54804,21045,30956,40870 +58282,21046,30955,40902 +54720,21047,30954,40190 +52125,21048,30953,40073 +52616,21049,30952,40289 +59441,21050,30951,40176 +55316,21051,30950,40147 +50908,21052,30949,40614 +57823,21053,30948,40933 +51329,21054,30947,40723 +51998,21055,30946,40434 +52571,21056,30945,40669 +50394,21057,30944,40482 +50757,21058,30943,40311 +50488,21059,30942,40861 +56742,21060,30941,40771 +53562,21061,30940,40317 +53291,21062,30939,40369 +56543,21063,30938,40616 +55277,21064,30937,40556 +59493,21065,30936,40801 +57169,21066,30935,40965 +53679,21067,30934,40930 +59086,21068,30933,40119 +53713,21069,30932,40081 +50985,21070,30931,40902 +57384,21071,30930,40956 +52172,21072,30929,40468 +59687,21073,30928,40505 +50901,21074,30927,40466 +59228,21075,30926,40998 +59098,21076,30925,40423 +50800,21077,30924,40385 +59259,21078,30923,40656 +59998,21079,30922,40694 +57200,21080,30921,40868 +52315,21081,30920,40812 +54465,21082,30919,40731 +56707,21083,30918,40178 +57988,21084,30917,40114 +52661,21085,30916,40043 +59249,21086,30915,40270 +57604,21087,30914,40626 +52306,21088,30913,40435 +54782,21089,30912,40332 +52966,21090,30911,40927 +52186,21091,30910,40361 +59253,21092,30909,40103 +59322,21093,30908,40894 +54909,21094,30907,40254 +53520,21095,30906,40027 +50378,21096,30905,40366 +52749,21097,30904,40228 +58261,21098,30903,40964 +58820,21099,30902,40606 +59251,21100,30901,40749 +55758,21101,30900,40743 +50750,21102,30899,40494 +58150,21103,30898,40210 +57586,21104,30897,40461 +53028,21105,30896,40255 +56205,21106,30895,40242 +56327,21107,30894,40043 +50745,21108,30893,40697 +52747,21109,30892,40496 +55046,21110,30891,40638 +58203,21111,30890,40259 +57200,21112,30889,40861 +55392,21113,30888,40278 +52784,21114,30887,40894 +51863,21115,30886,40066 +55743,21116,30885,40114 +54928,21117,30884,40627 +53252,21118,30883,40380 +52979,21119,30882,40200 +55518,21120,30881,40022 +58381,21121,30880,40789 +56206,21122,30879,40831 +54760,21123,30878,40967 +53852,21124,30877,40486 +59272,21125,30876,40531 +57722,21126,30875,40806 +56754,21127,30874,40427 +55429,21128,30873,40654 +50647,21129,30872,40534 +51383,21130,30871,40228 +55006,21131,30870,40827 +58090,21132,30869,40349 +50176,21133,30868,40874 +54071,21134,30867,40331 +56893,21135,30866,40463 +56669,21136,30865,40228 +57580,21137,30864,40420 +52061,21138,30863,40715 +55839,21139,30862,40769 +55345,21140,30861,40869 +53525,21141,30860,40603 +51837,21142,30859,40370 +55704,21143,30858,40846 +58253,21144,30857,40061 +53991,21145,30856,40712 +51790,21146,30855,40554 +55119,21147,30854,40980 +50426,21148,30853,40708 +56914,21149,30852,40392 +52683,21150,30851,40656 +53849,21151,30850,40075 +54768,21152,30849,40289 +52421,21153,30848,40086 +53293,21154,30847,40176 +58369,21155,30846,40534 +53916,21156,30845,40456 +55636,21157,30844,40307 +57378,21158,30843,40220 +57971,21159,30842,40857 +50173,21160,30841,40278 +54259,21161,30840,40664 +59353,21162,30839,40956 +53884,21163,30838,40674 +55410,21164,30837,40217 +52361,21165,30836,40800 +57571,21166,30835,40997 +57467,21167,30834,40425 +59117,21168,30833,40466 +50462,21169,30832,40665 +56611,21170,30831,40892 +50691,21171,30830,40338 +52146,21172,30829,40116 +52188,21173,30828,40529 +53518,21174,30827,40658 +55014,21175,30826,40639 +52056,21176,30825,40980 +58320,21177,30824,40738 +52636,21178,30823,40415 +51739,21179,30822,40416 +52246,21180,30821,40136 +52714,21181,30820,40712 +51972,21182,30819,40128 +58408,21183,30818,40204 +56935,21184,30817,40770 +51816,21185,30816,40135 +51347,21186,30815,40530 +53975,21187,30814,40647 +56838,21188,30813,40644 +59775,21189,30812,40391 +57333,21190,30811,40014 +55701,21191,30810,40644 +57314,21192,30809,40891 +53826,21193,30808,40442 +57930,21194,30807,40461 +52206,21195,30806,40738 +56683,21196,30805,40478 +56808,21197,30804,40538 +58322,21198,30803,40404 +52066,21199,30802,40969 +55170,21200,30801,40806 +53321,21201,30800,40965 +53905,21202,30799,40927 +50355,21203,30798,40347 +50492,21204,30797,40485 +58561,21205,30796,40202 +51451,21206,30795,40150 +54772,21207,30794,40989 +51967,21208,30793,40865 +51996,21209,30792,40955 +54376,21210,30791,40636 +50347,21211,30790,40621 +51172,21212,30789,40855 +56903,21213,30788,40947 +59025,21214,30787,40044 +56783,21215,30786,40403 +56979,21216,30785,40482 +59045,21217,30784,40311 +59952,21218,30783,40325 +52554,21219,30782,40858 +53849,21220,30781,40675 +59527,21221,30780,40055 +53140,21222,30779,40517 +50711,21223,30778,40869 +50292,21224,30777,40928 +53074,21225,30776,40875 +54346,21226,30775,40607 +53364,21227,30774,40236 +59845,21228,30773,40095 +52189,21229,30772,40143 +56740,21230,30771,40967 +58849,21231,30770,40167 +56588,21232,30769,40377 +53439,21233,30768,40137 +56566,21234,30767,40137 +50111,21235,30766,40823 +57808,21236,30765,40186 +56037,21237,30764,40824 +54211,21238,30763,40615 +51458,21239,30762,40993 +58948,21240,30761,40013 +54521,21241,30760,40228 +56196,21242,30759,40850 +56271,21243,30758,40212 +52706,21244,30757,40705 +55067,21245,30756,40610 +52753,21246,30755,40734 +52366,21247,30754,40671 +51668,21248,30753,40704 +50844,21249,30752,40911 +51173,21250,30751,40696 +54408,21251,30750,40654 +53589,21252,30749,40493 +56526,21253,30748,40066 +53181,21254,30747,40961 +55881,21255,30746,40628 +54803,21256,30745,40131 +57285,21257,30744,40780 +50521,21258,30743,40289 +51598,21259,30742,40088 +54640,21260,30741,40418 +59096,21261,30740,40160 +55930,21262,30739,40990 +59672,21263,30738,40258 +59484,21264,30737,40739 +56815,21265,30736,40165 +59506,21266,30735,40541 +51223,21267,30734,40700 +59564,21268,30733,40488 +52454,21269,30732,40129 +56486,21270,30731,40149 +53904,21271,30730,40259 +52182,21272,30729,40639 +58457,21273,30728,40829 +55134,21274,30727,40385 +59447,21275,30726,40068 +50930,21276,30725,40862 +54294,21277,30724,40853 +52339,21278,30723,40972 +54869,21279,30722,40905 +54218,21280,30721,40197 +50269,21281,30720,40871 +59536,21282,30719,40516 +56562,21283,30718,40692 +56458,21284,30717,40785 +55362,21285,30716,40937 +56546,21286,30715,40137 +53467,21287,30714,40672 +52048,21288,30713,40005 +54841,21289,30712,40612 +52599,21290,30711,40348 +59005,21291,30710,40669 +59356,21292,30709,40608 +55993,21293,30708,40333 +57346,21294,30707,40074 +59543,21295,30706,40922 +55361,21296,30705,40971 +52042,21297,30704,40848 +56181,21298,30703,40049 +57436,21299,30702,40746 +51794,21300,30701,40138 +50262,21301,30700,40917 +59700,21302,30699,40687 +51422,21303,30698,40306 +57781,21304,30697,40256 +56426,21305,30696,40069 +54728,21306,30695,40696 +51348,21307,30694,40718 +57043,21308,30693,40181 +58230,21309,30692,40164 +52009,21310,30691,40206 +51716,21311,30690,40225 +51733,21312,30689,40921 +56968,21313,30688,40638 +55635,21314,30687,40000 +56601,21315,30686,40531 +50952,21316,30685,40431 +54485,21317,30684,40083 +59234,21318,30683,40077 +51389,21319,30682,40906 +58425,21320,30681,40285 +54416,21321,30680,40860 +51397,21322,30679,40984 +57103,21323,30678,40956 +50233,21324,30677,40016 +57968,21325,30676,40341 +51022,21326,30675,40323 +53343,21327,30674,40777 +52122,21328,30673,40674 +56030,21329,30672,40475 +50479,21330,30671,40525 +54268,21331,30670,40579 +56528,21332,30669,40726 +51924,21333,30668,40606 +52734,21334,30667,40094 +54604,21335,30666,40510 +50289,21336,30665,40776 +53758,21337,30664,40157 +50913,21338,30663,40472 +59300,21339,30662,40522 +51525,21340,30661,40214 +52108,21341,30660,40270 +51298,21342,30659,40565 +58331,21343,30658,40326 +52485,21344,30657,40075 +52014,21345,30656,40773 +59821,21346,30655,40861 +58235,21347,30654,40636 +56191,21348,30653,40457 +58134,21349,30652,40305 +56556,21350,30651,40887 +56784,21351,30650,40498 +50608,21352,30649,40156 +59289,21353,30648,40108 +50113,21354,30647,40084 +55542,21355,30646,40452 +56376,21356,30645,40243 +51678,21357,30644,40337 +56700,21358,30643,40521 +52638,21359,30642,40709 +55993,21360,30641,40696 +57948,21361,30640,40182 +53040,21362,30639,40403 +53689,21363,30638,40941 +55192,21364,30637,40572 +53664,21365,30636,40225 +51666,21366,30635,40682 +52571,21367,30634,40441 +59562,21368,30633,40358 +54612,21369,30632,40949 +51545,21370,30631,40240 +52537,21371,30630,40415 +52616,21372,30629,40195 +56921,21373,30628,40420 +56111,21374,30627,40497 +51355,21375,30626,40337 +52475,21376,30625,40996 +53645,21377,30624,40403 +56685,21378,30623,40907 +53322,21379,30622,40343 +58191,21380,30621,40949 +56357,21381,30620,40771 +58466,21382,30619,40133 +51410,21383,30618,40551 +59764,21384,30617,40897 +54468,21385,30616,40843 +50253,21386,30615,40873 +53729,21387,30614,40511 +50040,21388,30613,40585 +56865,21389,30612,40097 +51294,21390,30611,40867 +56933,21391,30610,40014 +54349,21392,30609,40900 +56773,21393,30608,40096 +50376,21394,30607,40025 +51586,21395,30606,40304 +55865,21396,30605,40094 +58234,21397,30604,40041 +50434,21398,30603,40642 +59241,21399,30602,40809 +57744,21400,30601,40635 +57260,21401,30600,40148 +57776,21402,30599,40241 +56450,21403,30598,40382 +57596,21404,30597,40114 +52619,21405,30596,40813 +50814,21406,30595,40306 +54402,21407,30594,40233 +52773,21408,30593,40964 +52983,21409,30592,40129 +52341,21410,30591,40849 +53845,21411,30590,40740 +57049,21412,30589,40891 +56882,21413,30588,40616 +53780,21414,30587,40615 +57029,21415,30586,40338 +54805,21416,30585,40982 +52833,21417,30584,40810 +53864,21418,30583,40006 +51360,21419,30582,40730 +53368,21420,30581,40209 +57723,21421,30580,40084 +50083,21422,30579,40682 +57717,21423,30578,40093 +53111,21424,30577,40015 +51512,21425,30576,40930 +52072,21426,30575,40383 +56967,21427,30574,40029 +53091,21428,30573,40690 +54946,21429,30572,40188 +50636,21430,30571,40687 +58760,21431,30570,40982 +54324,21432,30569,40494 +51223,21433,30568,40363 +55399,21434,30567,40619 +56815,21435,30566,40319 +59441,21436,30565,40235 +54116,21437,30564,40538 +52064,21438,30563,40319 +58514,21439,30562,40167 +55077,21440,30561,40978 +57947,21441,30560,40119 +52612,21442,30559,40136 +53868,21443,30558,40993 +55851,21444,30557,40205 +56957,21445,30556,40457 +55440,21446,30555,40230 +56279,21447,30554,40498 +52083,21448,30553,40080 +57729,21449,30552,40233 +57634,21450,30551,40100 +50931,21451,30550,40568 +56858,21452,30549,40188 +59755,21453,30548,40187 +51403,21454,30547,40613 +56125,21455,30546,40818 +50453,21456,30545,40632 +52469,21457,30544,40300 +52671,21458,30543,40878 +54904,21459,30542,40676 +55078,21460,30541,40936 +50616,21461,30540,40059 +56722,21462,30539,40545 +53591,21463,30538,40874 +57636,21464,30537,40072 +52483,21465,30536,40241 +50748,21466,30535,40413 +56816,21467,30534,40273 +56280,21468,30533,40351 +59011,21469,30532,40051 +55430,21470,30531,40136 +51626,21471,30530,40875 +51818,21472,30529,40743 +54441,21473,30528,40540 +53899,21474,30527,40639 +56991,21475,30526,40521 +52391,21476,30525,40752 +58935,21477,30524,40517 +54807,21478,30523,40562 +51642,21479,30522,40152 +54110,21480,30521,40858 +58226,21481,30520,40287 +54251,21482,30519,40003 +53738,21483,30518,40391 +55213,21484,30517,40146 +57553,21485,30516,40901 +58726,21486,30515,40517 +57869,21487,30514,40109 +50616,21488,30513,40528 +53291,21489,30512,40141 +57052,21490,30511,40694 +52149,21491,30510,40748 +52626,21492,30509,40817 +56957,21493,30508,40117 +50323,21494,30507,40887 +53526,21495,30506,40330 +56338,21496,30505,40657 +59746,21497,30504,40407 +51169,21498,30503,40928 +50389,21499,30502,40949 +58111,21500,30501,40822 +58120,21501,30500,40175 +52799,21502,30499,40439 +51658,21503,30498,40420 +50836,21504,30497,40562 +52097,21505,30496,40313 +57784,21506,30495,40959 +54718,21507,30494,40842 +52732,21508,30493,40559 +55694,21509,30492,40613 +51450,21510,30491,40219 +56381,21511,30490,40220 +50134,21512,30489,40690 +58950,21513,30488,40669 +54675,21514,30487,40034 +50565,21515,30486,40023 +51281,21516,30485,40818 +54429,21517,30484,40483 +56356,21518,30483,40545 +50021,21519,30482,40069 +53905,21520,30481,40191 +51229,21521,30480,40093 +56849,21522,30479,40975 +51774,21523,30478,40239 +57208,21524,30477,40221 +51455,21525,30476,40107 +54559,21526,30475,40946 +57493,21527,30474,40977 +50845,21528,30473,40320 +51474,21529,30472,40605 +58148,21530,30471,40548 +51886,21531,30470,40306 +55256,21532,30469,40952 +59619,21533,30468,40351 +52715,21534,30467,40410 +58754,21535,30466,40019 +56371,21536,30465,40204 +53635,21537,30464,40942 +51837,21538,30463,40936 +53849,21539,30462,40053 +55562,21540,30461,40696 +56164,21541,30460,40753 +51959,21542,30459,40360 +57088,21543,30458,40301 +59387,21544,30457,40929 +53515,21545,30456,40018 +50378,21546,30455,40306 +53156,21547,30454,40978 +58199,21548,30453,40820 +57423,21549,30452,40365 +50502,21550,30451,40387 +53173,21551,30450,40682 +50558,21552,30449,40612 +51128,21553,30448,40558 +58589,21554,30447,40672 +53444,21555,30446,40378 +56310,21556,30445,40756 +59296,21557,30444,40692 +55606,21558,30443,40265 +59796,21559,30442,40541 +53925,21560,30441,40886 +52085,21561,30440,40626 +56903,21562,30439,40928 +52188,21563,30438,40001 +50546,21564,30437,40500 +54100,21565,30436,40330 +55962,21566,30435,40905 +53842,21567,30434,40071 +54615,21568,30433,40325 +51487,21569,30432,40274 +50632,21570,30431,40074 +56673,21571,30430,40730 +53937,21572,30429,40564 +59048,21573,30428,40353 +55216,21574,30427,40801 +50100,21575,30426,40284 +58078,21576,30425,40262 +57123,21577,30424,40480 +54736,21578,30423,40971 +55784,21579,30422,40413 +56093,21580,30421,40386 +51463,21581,30420,40242 +50442,21582,30419,40993 +56397,21583,30418,40942 +58929,21584,30417,40640 +54685,21585,30416,40198 +53697,21586,30415,40305 +58933,21587,30414,40767 +58750,21588,30413,40421 +57007,21589,30412,40194 +52473,21590,30411,40197 +50099,21591,30410,40687 +53962,21592,30409,40035 +56346,21593,30408,40223 +51337,21594,30407,40397 +54781,21595,30406,40458 +58781,21596,30405,40994 +53244,21597,30404,40377 +52188,21598,30403,40109 +58106,21599,30402,40458 +54769,21600,30401,40044 +56278,21601,30400,40806 +57435,21602,30399,40636 +53828,21603,30398,40816 +56049,21604,30397,40306 +58282,21605,30396,40604 +53972,21606,30395,40256 +53159,21607,30394,40049 +53517,21608,30393,40986 +54525,21609,30392,40540 +59798,21610,30391,40364 +52191,21611,30390,40011 +59701,21612,30389,40306 +53494,21613,30388,40795 +56018,21614,30387,40995 +59470,21615,30386,40551 +59289,21616,30385,40651 +59917,21617,30384,40821 +55755,21618,30383,40284 +55987,21619,30382,40950 +55487,21620,30381,40248 +58908,21621,30380,40698 +51334,21622,30379,40718 +52435,21623,30378,40590 +57372,21624,30377,40502 +56449,21625,30376,40860 +54506,21626,30375,40506 +58163,21627,30374,40724 +54265,21628,30373,40012 +55753,21629,30372,40900 +55553,21630,30371,40286 +57963,21631,30370,40337 +55471,21632,30369,40658 +58918,21633,30368,40489 +57045,21634,30367,40542 +56324,21635,30366,40295 +57851,21636,30365,40731 +58586,21637,30364,40570 +59107,21638,30363,40187 +51770,21639,30362,40491 +59290,21640,30361,40948 +52553,21641,30360,40769 +59499,21642,30359,40541 +55339,21643,30358,40290 +55949,21644,30357,40548 +55754,21645,30356,40416 +52381,21646,30355,40146 +55062,21647,30354,40285 +53014,21648,30353,40668 +54118,21649,30352,40357 +51388,21650,30351,40079 +51196,21651,30350,40423 +59465,21652,30349,40798 +56231,21653,30348,40031 +55247,21654,30347,40211 +51474,21655,30346,40059 +52747,21656,30345,40008 +53642,21657,30344,40800 +52699,21658,30343,40369 +57389,21659,30342,40832 +55734,21660,30341,40960 +56093,21661,30340,40178 +53177,21662,30339,40499 +58115,21663,30338,40383 +54035,21664,30337,40038 +59969,21665,30336,40932 +52950,21666,30335,40937 +53872,21667,30334,40721 +55645,21668,30333,40031 +51800,21669,30332,40028 +53981,21670,30331,40058 +50926,21671,30330,40755 +58500,21672,30329,40645 +56391,21673,30328,40589 +51902,21674,30327,40488 +52523,21675,30326,40363 +54343,21676,30325,40970 +52549,21677,30324,40400 +52955,21678,30323,40262 +51847,21679,30322,40578 +55384,21680,30321,40916 +58682,21681,30320,40908 +57589,21682,30319,40538 +56498,21683,30318,40625 +58252,21684,30317,40271 +54448,21685,30316,40631 +57602,21686,30315,40053 +55250,21687,30314,40638 +58744,21688,30313,40633 +58069,21689,30312,40683 +56778,21690,30311,40679 +55595,21691,30310,40126 +53956,21692,30309,40238 +52247,21693,30308,40116 +51669,21694,30307,40894 +52004,21695,30306,40698 +51051,21696,30305,40705 +56261,21697,30304,40551 +51054,21698,30303,40965 +50488,21699,30302,40948 +59593,21700,30301,40933 +55204,21701,30300,40442 +56050,21702,30299,40310 +55986,21703,30298,40080 +55227,21704,30297,40693 +58392,21705,30296,40320 +50593,21706,30295,40827 +54239,21707,30294,40837 +58130,21708,30293,40698 +57238,21709,30292,40092 +59660,21710,30291,40950 +56751,21711,30290,40939 +52128,21712,30289,40115 +54824,21713,30288,40018 +52533,21714,30287,40422 +58468,21715,30286,40181 +56648,21716,30285,40939 +57864,21717,30284,40995 +57313,21718,30283,40571 +55954,21719,30282,40494 +53697,21720,30281,40216 +59522,21721,30280,40495 +55384,21722,30279,40527 +52781,21723,30278,40389 +56596,21724,30277,40199 +54390,21725,30276,40442 +57395,21726,30275,40236 +50333,21727,30274,40762 +51449,21728,30273,40923 +56676,21729,30272,40593 +55949,21730,30271,40458 +54652,21731,30270,40192 +52718,21732,30269,40006 +50623,21733,30268,40220 +59267,21734,30267,40247 +55286,21735,30266,40323 +58783,21736,30265,40692 +55226,21737,30264,40299 +50499,21738,30263,40615 +56535,21739,30262,40281 +50158,21740,30261,40892 +59885,21741,30260,40715 +50400,21742,30259,40971 +55296,21743,30258,40131 +55804,21744,30257,40152 +51168,21745,30256,40384 +55675,21746,30255,40947 +53939,21747,30254,40362 +52909,21748,30253,40617 +55117,21749,30252,40138 +59499,21750,30251,40806 +59890,21751,30250,40756 +53448,21752,30249,40909 +59922,21753,30248,40258 +54454,21754,30247,40999 +57395,21755,30246,40406 +54932,21756,30245,40075 +58125,21757,30244,40043 +52133,21758,30243,40727 +59694,21759,30242,40105 +58220,21760,30241,40540 +55997,21761,30240,40651 +55523,21762,30239,40183 +54972,21763,30238,40239 +58939,21764,30237,40521 +54439,21765,30236,40921 +59406,21766,30235,40429 +56490,21767,30234,40460 +52400,21768,30233,40873 +57710,21769,30232,40686 +55700,21770,30231,40763 +52643,21771,30230,40951 +53163,21772,30229,40785 +56074,21773,30228,40286 +57463,21774,30227,40381 +58377,21775,30226,40352 +50526,21776,30225,40611 +54002,21777,30224,40646 +59449,21778,30223,40497 +51933,21779,30222,40449 +59532,21780,30221,40682 +52897,21781,30220,40453 +50736,21782,30219,40942 +54690,21783,30218,40815 +51964,21784,30217,40698 +50484,21785,30216,40533 +51299,21786,30215,40055 +55053,21787,30214,40912 +56902,21788,30213,40226 +58617,21789,30212,40584 +55978,21790,30211,40719 +51975,21791,30210,40901 +53412,21792,30209,40091 +59809,21793,30208,40029 +56353,21794,30207,40173 +53929,21795,30206,40374 +55666,21796,30205,40695 +54062,21797,30204,40690 +58293,21798,30203,40735 +58318,21799,30202,40338 +55663,21800,30201,40900 +56949,21801,30200,40705 +51669,21802,30199,40064 +52564,21803,30198,40542 +56505,21804,30197,40265 +53677,21805,30196,40565 +59537,21806,30195,40531 +55370,21807,30194,40347 +51108,21808,30193,40862 +58446,21809,30192,40739 +53886,21810,30191,40231 +59347,21811,30190,40482 +55891,21812,30189,40069 +55026,21813,30188,40107 +58736,21814,30187,40947 +50146,21815,30186,40248 +59101,21816,30185,40885 +56967,21817,30184,40879 +50542,21818,30183,40368 +51948,21819,30182,40572 +51993,21820,30181,40075 +59307,21821,30180,40720 +51298,21822,30179,40644 +58456,21823,30178,40470 +58273,21824,30177,40392 +55582,21825,30176,40318 +55541,21826,30175,40683 +54417,21827,30174,40776 +59187,21828,30173,40968 +53411,21829,30172,40878 +52710,21830,30171,40286 +56834,21831,30170,40118 +57722,21832,30169,40527 +56926,21833,30168,40035 +57476,21834,30167,40493 +53816,21835,30166,40391 +51929,21836,30165,40907 +50662,21837,30164,40495 +52879,21838,30163,40686 +52740,21839,30162,40307 +58672,21840,30161,40815 +55124,21841,30160,40752 +55674,21842,30159,40493 +51062,21843,30158,40388 +52612,21844,30157,40707 +51650,21845,30156,40670 +54956,21846,30155,40124 +59954,21847,30154,40535 +52107,21848,30153,40734 +59485,21849,30152,40233 +58137,21850,30151,40666 +52686,21851,30150,40922 +52461,21852,30149,40943 +50579,21853,30148,40893 +55581,21854,30147,40909 +55633,21855,30146,40165 +59716,21856,30145,40357 +56693,21857,30144,40943 +52529,21858,30143,40994 +50854,21859,30142,40859 +50844,21860,30141,40123 +52966,21861,30140,40118 +58691,21862,30139,40273 +50886,21863,30138,40680 +55203,21864,30137,40976 +56121,21865,30136,40821 +59042,21866,30135,40595 +59201,21867,30134,40641 +57529,21868,30133,40568 +50166,21869,30132,40389 +58800,21870,30131,40437 +50725,21871,30130,40505 +57969,21872,30129,40486 +53157,21873,30128,40045 +59070,21874,30127,40077 +52852,21875,30126,40152 +53326,21876,30125,40396 +51088,21877,30124,40628 +52450,21878,30123,40281 +56258,21879,30122,40916 +50742,21880,30121,40727 +50517,21881,30120,40306 +53715,21882,30119,40397 +51877,21883,30118,40409 +57346,21884,30117,40565 +55698,21885,30116,40012 +56267,21886,30115,40707 +51955,21887,30114,40226 +50395,21888,30113,40999 +52631,21889,30112,40615 +55460,21890,30111,40306 +55654,21891,30110,40600 +50606,21892,30109,40393 +57079,21893,30108,40954 +50363,21894,30107,40113 +51979,21895,30106,40703 +54537,21896,30105,40831 +54630,21897,30104,40942 +57760,21898,30103,40130 +54782,21899,30102,40326 +56283,21900,30101,40944 +58235,21901,30100,40135 +58419,21902,30099,40554 +54719,21903,30098,40484 +58455,21904,30097,40580 +57711,21905,30096,40745 +59480,21906,30095,40509 +51567,21907,30094,40230 +58161,21908,30093,40063 +52604,21909,30092,40301 +58420,21910,30091,40108 +50387,21911,30090,40526 +58718,21912,30089,40133 +51135,21913,30088,40267 +52781,21914,30087,40952 +53792,21915,30086,40458 +50920,21916,30085,40582 +53190,21917,30084,40432 +56364,21918,30083,40029 +52764,21919,30082,40252 +57944,21920,30081,40249 +55650,21921,30080,40999 +57518,21922,30079,40362 +52163,21923,30078,40302 +58714,21924,30077,40402 +55846,21925,30076,40849 +53358,21926,30075,40805 +57887,21927,30074,40492 +53452,21928,30073,40133 +57605,21929,30072,40847 +51789,21930,30071,40170 +55951,21931,30070,40355 +59134,21932,30069,40098 +58023,21933,30068,40852 +51034,21934,30067,40922 +50128,21935,30066,40350 +50738,21936,30065,40281 +57524,21937,30064,40989 +54442,21938,30063,40493 +57974,21939,30062,40893 +55437,21940,30061,40173 +57383,21941,30060,40370 +58480,21942,30059,40514 +53812,21943,30058,40781 +54292,21944,30057,40747 +51660,21945,30056,40076 +52645,21946,30055,40804 +57534,21947,30054,40149 +59471,21948,30053,40345 +52721,21949,30052,40751 +54753,21950,30051,40300 +56158,21951,30050,40940 +53226,21952,30049,40721 +54696,21953,30048,40343 +54175,21954,30047,40411 +50252,21955,30046,40150 +57422,21956,30045,40501 +57891,21957,30044,40996 +50077,21958,30043,40799 +58948,21959,30042,40934 +59724,21960,30041,40146 +59606,21961,30040,40943 +54745,21962,30039,40218 +52516,21963,30038,40779 +59810,21964,30037,40735 +57465,21965,30036,40684 +59876,21966,30035,40816 +58282,21967,30034,40189 +50290,21968,30033,40605 +58867,21969,30032,40480 +51730,21970,30031,40782 +53353,21971,30030,40006 +56978,21972,30029,40454 +55823,21973,30028,40483 +57384,21974,30027,40838 +58004,21975,30026,40690 +56230,21976,30025,40519 +53354,21977,30024,40397 +58332,21978,30023,40848 +54066,21979,30022,40993 +57928,21980,30021,40880 +56594,21981,30020,40425 +59032,21982,30019,40624 +56104,21983,30018,40266 +57744,21984,30017,40296 +57528,21985,30016,40318 +56887,21986,30015,40412 +56481,21987,30014,40448 +51772,21988,30013,40723 +57710,21989,30012,40738 +59382,21990,30011,40932 +58905,21991,30010,40502 +52601,21992,30009,40982 +54458,21993,30008,40664 +59764,21994,30007,40946 +55773,21995,30006,40004 +59735,21996,30005,40959 +53537,21997,30004,40929 +57713,21998,30003,40418 +57708,21999,30002,40649 +57608,22000,30001,40367 +51244,22001,30000,40724 +57570,22002,31000,40624 +50520,22003,30999,40304 +52576,22004,30998,40777 +53989,22005,30997,40791 +51467,22006,30996,40358 +58037,22007,30995,40709 +57174,22008,30994,40930 +59146,22009,30993,40941 +55747,22010,30992,40477 +57657,22011,30991,40143 +50225,22012,30990,40512 +54745,22013,30989,40231 +57651,22014,30988,40832 +59178,22015,30987,40749 +50076,22016,30986,40181 +53634,22017,30985,40125 +50279,22018,30984,40174 +58818,22019,30983,40939 +54915,22020,30982,40459 +58392,22021,30981,40261 +52747,22022,30980,40831 +56670,22023,30979,40332 +51619,22024,30978,40840 +57775,22025,30977,40327 +58126,22026,30976,40380 +52714,22027,30975,40766 +57501,22028,30974,40017 +59055,22029,30973,40593 +52546,22030,30972,40856 +59030,22031,30971,40019 +50098,22032,30970,40655 +54943,22033,30969,40350 +57513,22034,30968,40571 +56708,22035,30967,40052 +50776,22036,30966,40767 +52730,22037,30965,40735 +51193,22038,30964,40323 +59798,22039,30963,40934 +50483,22040,30962,40451 +55261,22041,30961,40372 +55753,22042,30960,40690 +52036,22043,30959,40750 +55996,22044,30958,40364 +55238,22045,30957,40161 +51873,22046,30956,40965 +59508,22047,30955,40926 +56045,22048,30954,40553 +53718,22049,30953,40916 +57661,22050,30952,40329 +51328,22051,30951,40392 +58003,22052,30950,40831 +51728,22053,30949,40890 +55898,22054,30948,40966 +50755,22055,30947,40399 +52554,22056,30946,40808 +54999,22057,30945,40327 +52439,22058,30944,40805 +59387,22059,30943,40587 +58180,22060,30942,40238 +54979,22061,30941,40109 +54213,22062,30940,40611 +57256,22063,30939,40683 +59474,22064,30938,40439 +55852,22065,30937,40769 +56471,22066,30936,40750 +55595,22067,30935,40386 +53272,22068,30934,40207 +51357,22069,30933,40571 +58130,22070,30932,40940 +50824,22071,30931,40724 +58125,22072,30930,40627 +57410,22073,30929,40011 +52813,22074,30928,40937 +50019,22075,30927,40183 +51816,22076,30926,40746 +57561,22077,30925,40711 +55138,22078,30924,40495 +54630,22079,30923,40621 +55092,22080,30922,40148 +57140,22081,30921,40962 +50987,22082,30920,40405 +58009,22083,30919,40222 +57340,22084,30918,40836 +59109,22085,30917,40908 +53957,22086,30916,40522 +54744,22087,30915,40128 +53471,22088,30914,40576 +54801,22089,30913,40574 +59792,22090,30912,40488 +54225,22091,30911,40561 +50156,22092,30910,40301 +52813,22093,30909,40012 +53676,22094,30908,40371 +57554,22095,30907,40432 +52759,22096,30906,40453 +55779,22097,30905,40779 +50476,22098,30904,40145 +54719,22099,30903,40497 +51170,22100,30902,40714 +55886,22101,30901,40106 +55670,22102,30900,40282 +52985,22103,30899,40480 +53940,22104,30898,40122 +51545,22105,30897,40674 +59953,22106,30896,40567 +58775,22107,30895,40378 +56069,22108,30894,40235 +53059,22109,30893,40488 +57798,22110,30892,40517 +51312,22111,30891,40001 +56863,22112,30890,40485 +54989,22113,30889,40256 +59007,22114,30888,40809 +58367,22115,30887,40662 +58798,22116,30886,40309 +53465,22117,30885,40617 +53963,22118,30884,40338 +53550,22119,30883,40743 +57088,22120,30882,40406 +52589,22121,30881,40509 +51351,22122,30880,40347 +53226,22123,30879,40640 +52614,22124,30878,40591 +50494,22125,30877,40831 +50501,22126,30876,40560 +51125,22127,30875,40395 +57857,22128,30874,40521 +54501,22129,30873,40044 +54889,22130,30872,40102 +53790,22131,30871,40506 +54853,22132,30870,40376 +54541,22133,30869,40517 +56070,22134,30868,40805 +54202,22135,30867,40681 +52408,22136,30866,40975 +56338,22137,30865,40553 +53812,22138,30864,40687 +53983,22139,30863,40470 +59315,22140,30862,40542 +59106,22141,30861,40493 +51005,22142,30860,40968 +50531,22143,30859,40675 +58463,22144,30858,40469 +58527,22145,30857,40317 +54587,22146,30856,40893 +56721,22147,30855,40264 +54090,22148,30854,40832 +58331,22149,30853,40441 +58316,22150,30852,40303 +57875,22151,30851,40643 +54063,22152,30850,40786 +56683,22153,30849,40963 +51806,22154,30848,40607 +51464,22155,30847,40305 +52305,22156,30846,40460 +58372,22157,30845,40645 +55858,22158,30844,40425 +58335,22159,30843,40172 +53680,22160,30842,40549 +53664,22161,30841,40774 +58924,22162,30840,40611 +55818,22163,30839,40468 +52065,22164,30838,40952 +57818,22165,30837,40259 +57456,22166,30836,40316 +56604,22167,30835,40896 +56441,22168,30834,40827 +57645,22169,30833,40119 +54135,22170,30832,40487 +55035,22171,30831,40620 +53682,22172,30830,40652 +56904,22173,30829,40197 +59624,22174,30828,40935 +50526,22175,30827,40866 +59221,22176,30826,40900 +51260,22177,30825,40394 +57390,22178,30824,40058 +52302,22179,30823,40483 +58766,22180,30822,40869 +55260,22181,30821,40118 +52648,22182,30820,40009 +50537,22183,30819,40340 +51771,22184,30818,40413 +51755,22185,30817,40049 +51731,22186,30816,40947 +50090,22187,30815,40964 +55692,22188,30814,40883 +52465,22189,30813,40392 +57234,22190,30812,40335 +57234,22191,30811,40882 +52004,22192,30810,40438 +59846,22193,30809,40126 +58390,22194,30808,40512 +57250,22195,30807,40073 +55958,22196,30806,40987 +58517,22197,30805,40005 +52694,22198,30804,40728 +56414,22199,30803,40589 +54328,22200,30802,40941 +59162,22201,30801,40237 +58760,22202,30800,40976 +53850,22203,30799,40932 +57763,22204,30798,40388 +51940,22205,30797,40889 +56997,22206,30796,40587 +57248,22207,30795,40799 +51648,22208,30794,40249 +57443,22209,30793,40319 +52072,22210,30792,40232 +53096,22211,30791,40712 +51260,22212,30790,40861 +50122,22213,30789,40910 +54735,22214,30788,40783 +57342,22215,30787,40956 +51172,22216,30786,40719 +57773,22217,30785,40255 +59800,22218,30784,40920 +59664,22219,30783,40448 +54713,22220,30782,40661 +50372,22221,30781,40949 +55957,22222,30780,40153 +56749,22223,30779,40182 +51309,22224,30778,40319 +56630,22225,30777,40015 +57448,22226,30776,40198 +52678,22227,30775,40470 +57700,22228,30774,40481 +59038,22229,30773,40731 +52807,22230,30772,40553 +51231,22231,30771,40711 +51235,22232,30770,40959 +54121,22233,30769,40242 +56824,22234,30768,40729 +50015,22235,30767,40637 +57828,22236,30766,40912 +57254,22237,30765,40985 +57926,22238,30764,40476 +56539,22239,30763,40586 +50608,22240,30762,40589 +55028,22241,30761,40771 +56442,22242,30760,40263 +56942,22243,30759,40391 +52706,22244,30758,40176 +52342,22245,30757,40033 +58786,22246,30756,40818 +58756,22247,30755,40921 +57418,22248,30754,40440 +57970,22249,30753,40396 +56844,22250,30752,40926 +51690,22251,30751,40942 +54391,22252,30750,40953 +53645,22253,30749,40327 +51035,22254,30748,40544 +57024,22255,30747,40191 +59515,22256,30746,40046 +56656,22257,30745,40335 +57761,22258,30744,40581 +53158,22259,30743,40854 +52699,22260,30742,40825 +58774,22261,30741,40124 +50371,22262,30740,40774 +50801,22263,30739,40279 +52444,22264,30738,40446 +57771,22265,30737,40175 +51928,22266,30736,40851 +55063,22267,30735,40248 +55495,22268,30734,40109 +55726,22269,30733,40252 +57961,22270,30732,40289 +58158,22271,30731,40434 +56229,22272,30730,40543 +52351,22273,30729,40255 +50530,22274,30728,40462 +53425,22275,30727,40567 +54162,22276,30726,40382 +54913,22277,30725,40048 +51583,22278,30724,40617 +54490,22279,30723,40468 +59485,22280,30722,40559 +53256,22281,30721,40945 +52719,22282,30720,40916 +53768,22283,30719,40302 +52310,22284,30718,40544 +58236,22285,30717,40868 +51204,22286,30716,40580 +58907,22287,30715,40630 +55999,22288,30714,40140 +57412,22289,30713,40999 +59377,22290,30712,40733 +54626,22291,30711,40703 +55980,22292,30710,40059 +52283,22293,30709,40961 +57466,22294,30708,40167 +58819,22295,30707,40788 +53026,22296,30706,40477 +54542,22297,30705,40796 +52567,22298,30704,40902 +58499,22299,30703,40620 +56170,22300,30702,40382 +52460,22301,30701,40187 +57264,22302,30700,40163 +58025,22303,30699,40824 +53951,22304,30698,40096 +50196,22305,30697,40355 +58465,22306,30696,40934 +58687,22307,30695,40017 +53659,22308,30694,40430 +58969,22309,30693,40995 +52248,22310,30692,40005 +53344,22311,30691,40748 +58014,22312,30690,40404 +51073,22313,30689,40805 +55842,22314,30688,40139 +59307,22315,30687,40159 +55223,22316,30686,40314 +55985,22317,30685,40316 +50593,22318,30684,40628 +57998,22319,30683,40867 +56152,22320,30682,40872 +58754,22321,30681,40934 +55224,22322,30680,40677 +56155,22323,30679,40945 +52933,22324,30678,40929 +50271,22325,30677,40226 +56300,22326,30676,40350 +50117,22327,30675,40023 +51141,22328,30674,40706 +53300,22329,30673,40528 +50773,22330,30672,40977 +57555,22331,30671,40170 +51247,22332,30670,40041 +57952,22333,30669,40469 +51722,22334,30668,40426 +58540,22335,30667,40779 +53726,22336,30666,40072 +59363,22337,30665,40366 +53832,22338,30664,40534 +59145,22339,30663,40500 +56189,22340,30662,40289 +57520,22341,30661,40425 +55611,22342,30660,40454 +55031,22343,30659,40386 +56763,22344,30658,40417 +55276,22345,30657,40761 +59043,22346,30656,40315 +51793,22347,30655,40066 +57640,22348,30654,40566 +53244,22349,30653,40441 +58944,22350,30652,40321 +51369,22351,30651,40933 +55221,22352,30650,40971 +58635,22353,30649,40941 +52054,22354,30648,40093 +57487,22355,30647,40030 +55576,22356,30646,40905 +54177,22357,30645,40606 +54521,22358,30644,40329 +59704,22359,30643,40240 +54949,22360,30642,40309 +50796,22361,30641,40300 +55313,22362,30640,40757 +59624,22363,30639,40818 +56613,22364,30638,40735 +57706,22365,30637,40923 +55927,22366,30636,40733 +50888,22367,30635,40869 +54722,22368,30634,40062 +59149,22369,30633,40193 +53366,22370,30632,40727 +59888,22371,30631,40946 +56233,22372,30630,40006 +54549,22373,30629,40011 +58394,22374,30628,40859 +56429,22375,30627,40589 +59574,22376,30626,40420 +54105,22377,30625,40781 +54580,22378,30624,40555 +55388,22379,30623,40071 +58507,22380,30622,40381 +52302,22381,30621,40977 +53699,22382,30620,40026 +50732,22383,30619,40397 +51048,22384,30618,40293 +53389,22385,30617,40276 +55003,22386,30616,40695 +55472,22387,30615,40500 +59716,22388,30614,40532 +51681,22389,30613,40958 +50370,22390,30612,40969 +55418,22391,30611,40206 +54082,22392,30610,40703 +58742,22393,30609,40536 +56622,22394,30608,40225 +58305,22395,30607,40435 +52076,22396,30606,40263 +59115,22397,30605,40925 +51527,22398,30604,40877 +56235,22399,30603,40115 +57164,22400,30602,40027 +53904,22401,30601,40043 +52379,22402,30600,40721 +52099,22403,30599,40528 +57677,22404,30598,40630 +53272,22405,30597,40641 +50756,22406,30596,40045 +56995,22407,30595,40175 +52702,22408,30594,40861 +56360,22409,30593,40048 +57347,22410,30592,40364 +57371,22411,30591,40797 +52430,22412,30590,40767 +53717,22413,30589,40484 +52857,22414,30588,40288 +56392,22415,30587,40963 +52432,22416,30586,40941 +55290,22417,30585,40570 +53880,22418,30584,40161 +55181,22419,30583,40651 +54792,22420,30582,40865 +56767,22421,30581,40865 +50629,22422,30580,40717 +51501,22423,30579,40802 +52028,22424,30578,40712 +53682,22425,30577,40539 +52761,22426,30576,40134 +57662,22427,30575,40206 +58052,22428,30574,40530 +55601,22429,30573,40002 +55675,22430,30572,40801 +56215,22431,30571,40656 +52506,22432,30570,40102 +55230,22433,30569,40205 +54743,22434,30568,40443 +54098,22435,30567,40441 +56410,22436,30566,40281 +50713,22437,30565,40314 +53353,22438,30564,40772 +57786,22439,30563,40445 +59955,22440,30562,40317 +53081,22441,30561,40627 +59826,22442,30560,40493 +57853,22443,30559,40732 +59123,22444,30558,40595 +53219,22445,30557,40707 +52530,22446,30556,40179 +56827,22447,30555,40350 +51934,22448,30554,40468 +57360,22449,30553,40944 +56843,22450,30552,40523 +53702,22451,30551,40284 +52871,22452,30550,40641 +59755,22453,30549,40928 +50436,22454,30548,40950 +53071,22455,30547,40996 +55780,22456,30546,40888 +52240,22457,30545,40126 +50771,22458,30544,40548 +54686,22459,30543,40899 +53166,22460,30542,40887 +50734,22461,30541,40123 +55793,22462,30540,40994 +56890,22463,30539,40882 +55342,22464,30538,40080 +51301,22465,30537,40271 +54730,22466,30536,40614 +52477,22467,30535,40331 +54769,22468,30534,40006 +54137,22469,30533,40063 +50714,22470,30532,40007 +51393,22471,30531,40394 +54149,22472,30530,40148 +51900,22473,30529,40374 +59824,22474,30528,40655 +50404,22475,30527,40134 +56457,22476,30526,40466 +53031,22477,30525,40902 +57166,22478,30524,40154 +53527,22479,30523,40831 +56880,22480,30522,40225 +59105,22481,30521,40861 +56758,22482,30520,40038 +52139,22483,30519,40775 +58542,22484,30518,40651 +51894,22485,30517,40795 +51166,22486,30516,40171 +58818,22487,30515,40507 +56392,22488,30514,40022 +54577,22489,30513,40592 +50684,22490,30512,40186 +50787,22491,30511,40105 +57352,22492,30510,40800 +57841,22493,30509,40008 +57019,22494,30508,40568 +51878,22495,30507,40329 +53511,22496,30506,40689 +57111,22497,30505,40328 +57876,22498,30504,40137 +50372,22499,30503,40062 +57713,22500,30502,40622 +53798,22501,30501,40264 +50117,22502,30500,40759 +52792,22503,30499,40812 +53124,22504,30498,40585 +55010,22505,30497,40184 +58189,22506,30496,40202 +58992,22507,30495,40305 +54432,22508,30494,40820 +52481,22509,30493,40781 +56093,22510,30492,40638 +57803,22511,30491,40285 +54935,22512,30490,40277 +50444,22513,30489,40955 +54808,22514,30488,40690 +53932,22515,30487,40060 +51502,22516,30486,40273 +58158,22517,30485,40681 +55715,22518,30484,40181 +56357,22519,30483,40664 +50458,22520,30482,40291 +52403,22521,30481,40002 +58821,22522,30480,40033 +53373,22523,30479,40689 +55748,22524,30478,40882 +53242,22525,30477,40000 +57032,22526,30476,40474 +50970,22527,30475,40591 +54533,22528,30474,40489 +58451,22529,30473,40473 +54645,22530,30472,40349 +56775,22531,30471,40571 +50986,22532,30470,40744 +51202,22533,30469,40084 +54091,22534,30468,40875 +57455,22535,30467,40612 +56672,22536,30466,40158 +53577,22537,30465,40618 +57433,22538,30464,40421 +51375,22539,30463,40861 +56408,22540,30462,40736 +51153,22541,30461,40015 +52863,22542,30460,40055 +56631,22543,30459,40505 +50580,22544,30458,40336 +51025,22545,30457,40351 +55025,22546,30456,40295 +57737,22547,30455,40882 +50039,22548,30454,40776 +56373,22549,30453,40635 +55507,22550,30452,40156 +53096,22551,30451,40946 +52489,22552,30450,40830 +50616,22553,30449,40796 +59037,22554,30448,40969 +54570,22555,30447,40850 +51856,22556,30446,40928 +56745,22557,30445,40148 +55319,22558,30444,40873 +53190,22559,30443,40025 +52136,22560,30442,40087 +56682,22561,30441,40361 +59470,22562,30440,40530 +51222,22563,30439,40746 +55468,22564,30438,40861 +50971,22565,30437,40732 +56525,22566,30436,40756 +57670,22567,30435,40057 +51673,22568,30434,40952 +54835,22569,30433,40731 +52212,22570,30432,40745 +55170,22571,30431,40188 +55841,22572,30430,40815 +55783,22573,30429,40948 +54564,22574,30428,40828 +52107,22575,30427,40779 +55205,22576,30426,40497 +54224,22577,30425,40140 +54321,22578,30424,40476 +55810,22579,30423,40897 +51914,22580,30422,40331 +50889,22581,30421,40361 +58414,22582,30420,40583 +57067,22583,30419,40907 +57269,22584,30418,40816 +53487,22585,30417,40845 +58660,22586,30416,40553 +51931,22587,30415,40341 +55966,22588,30414,40768 +56702,22589,30413,40659 +51594,22590,30412,40357 +53594,22591,30411,40850 +54512,22592,30410,40859 +52650,22593,30409,40306 +57181,22594,30408,40144 +53042,22595,30407,40867 +54327,22596,30406,40781 +55395,22597,30405,40559 +53338,22598,30404,40866 +57885,22599,30403,40020 +55312,22600,30402,40922 +59135,22601,30401,40172 +51535,22602,30400,40405 +57530,22603,30399,40284 +58396,22604,30398,40096 +54419,22605,30397,40222 +57453,22606,30396,40350 +50056,22607,30395,40074 +59068,22608,30394,40649 +53690,22609,30393,40816 +57896,22610,30392,40185 +51416,22611,30391,40451 +54134,22612,30390,40784 +51772,22613,30389,40770 +53124,22614,30388,40167 +59615,22615,30387,40296 +58654,22616,30386,40513 +58119,22617,30385,40182 +58986,22618,30384,40666 +55329,22619,30383,40114 +59197,22620,30382,40235 +58682,22621,30381,40751 +51472,22622,30380,40605 +51799,22623,30379,40728 +57134,22624,30378,40935 +56116,22625,30377,40409 +51988,22626,30376,40062 +51513,22627,30375,40309 +59323,22628,30374,40287 +53657,22629,30373,40302 +57714,22630,30372,40380 +53796,22631,30371,40332 +52979,22632,30370,40617 +50749,22633,30369,40133 +58360,22634,30368,40579 +50325,22635,30367,40285 +55911,22636,30366,40820 +56902,22637,30365,40770 +56329,22638,30364,40397 +54012,22639,30363,40391 +51320,22640,30362,40736 +59165,22641,30361,40459 +57446,22642,30360,40672 +58090,22643,30359,40501 +54714,22644,30358,40895 +52061,22645,30357,40687 +55238,22646,30356,40052 +57106,22647,30355,40812 +56452,22648,30354,40176 +58818,22649,30353,40046 +52911,22650,30352,40931 +55835,22651,30351,40712 +54685,22652,30350,40088 +53291,22653,30349,40925 +59418,22654,30348,40785 +50603,22655,30347,40332 +52016,22656,30346,40792 +55017,22657,30345,40265 +50322,22658,30344,40572 +57885,22659,30343,40457 +54248,22660,30342,40300 +53613,22661,30341,40953 +53541,22662,30340,40227 +55868,22663,30339,40514 +57908,22664,30338,40968 +58509,22665,30337,40029 +53633,22666,30336,40512 +58949,22667,30335,40896 +55876,22668,30334,40931 +59902,22669,30333,40627 +58343,22670,30332,40976 +55656,22671,30331,40474 +55673,22672,30330,40989 +54859,22673,30329,40174 +54748,22674,30328,40655 +56167,22675,30327,40578 +59816,22676,30326,40186 +55132,22677,30325,40167 +55218,22678,30324,40437 +52742,22679,30323,40341 +51511,22680,30322,40222 +52367,22681,30321,40622 +58195,22682,30320,40182 +51736,22683,30319,40632 +58863,22684,30318,40856 +54787,22685,30317,40056 +56246,22686,30316,40867 +56344,22687,30315,40053 +50472,22688,30314,40425 +57655,22689,30313,40080 +54343,22690,30312,40947 +55469,22691,30311,40582 +59407,22692,30310,40820 +54607,22693,30309,40119 +52339,22694,30308,40095 +52947,22695,30307,40302 +54418,22696,30306,40485 +59375,22697,30305,40277 +54057,22698,30304,40847 +52025,22699,30303,40325 +58978,22700,30302,40492 +57469,22701,30301,40279 +55961,22702,30300,40623 +57917,22703,30299,40690 +54959,22704,30298,40017 +53442,22705,30297,40033 +55336,22706,30296,40934 +56577,22707,30295,40528 +55439,22708,30294,40751 +58377,22709,30293,40971 +53610,22710,30292,40331 +59145,22711,30291,40883 +57256,22712,30290,40066 +50575,22713,30289,40966 +56918,22714,30288,40000 +57354,22715,30287,40298 +55409,22716,30286,40643 +58017,22717,30285,40782 +56597,22718,30284,40713 +54748,22719,30283,40444 +53252,22720,30282,40112 +55680,22721,30281,40959 +52019,22722,30280,40163 +58073,22723,30279,40229 +55118,22724,30278,40558 +53903,22725,30277,40833 +57708,22726,30276,40055 +53963,22727,30275,40608 +58557,22728,30274,40385 +57251,22729,30273,40037 +57007,22730,30272,40566 +58385,22731,30271,40299 +53104,22732,30270,40184 +50594,22733,30269,40055 +57182,22734,30268,40964 +58042,22735,30267,40808 +57675,22736,30266,40859 +57188,22737,30265,40636 +53916,22738,30264,40390 +55543,22739,30263,40648 +53680,22740,30262,40934 +57797,22741,30261,40819 +54461,22742,30260,40694 +52941,22743,30259,40032 +55653,22744,30258,40061 +53728,22745,30257,40326 +56921,22746,30256,40012 +56416,22747,30255,40357 +51060,22748,30254,40384 +52501,22749,30253,40415 +57320,22750,30252,40220 +54057,22751,30251,40457 +51606,22752,30250,40646 +50675,22753,30249,40685 +51638,22754,30248,40292 +51921,22755,30247,40973 +55191,22756,30246,40003 +55790,22757,30245,40326 +54080,22758,30244,40452 +50659,22759,30243,40111 +58581,22760,30242,40099 +52842,22761,30241,40276 +51077,22762,30240,40493 +54957,22763,30239,40179 +57312,22764,30238,40486 +57693,22765,30237,40010 +53030,22766,30236,40237 +59007,22767,30235,40515 +51659,22768,30234,40308 +54608,22769,30233,40638 +52567,22770,30232,40303 +51145,22771,30231,40257 +58009,22772,30230,40968 +56206,22773,30229,40742 +51419,22774,30228,40309 +58225,22775,30227,40009 +55040,22776,30226,40807 +52260,22777,30225,40077 +53082,22778,30224,40952 +57163,22779,30223,40610 +50441,22780,30222,40832 +50255,22781,30221,40868 +59598,22782,30220,40067 +59054,22783,30219,40003 +59117,22784,30218,40394 +51792,22785,30217,40179 +53585,22786,30216,40509 +56725,22787,30215,40984 +54137,22788,30214,40874 +59834,22789,30213,40719 +50160,22790,30212,40941 +51115,22791,30211,40451 +50122,22792,30210,40924 +58066,22793,30209,40635 +52811,22794,30208,40422 +58269,22795,30207,40981 +53058,22796,30206,40943 +51534,22797,30205,40433 +56898,22798,30204,40386 +55228,22799,30203,40260 +55169,22800,30202,40732 +58006,22801,30201,40136 +51624,22802,30200,40289 +55256,22803,30199,40300 +56891,22804,30198,40117 +51542,22805,30197,40997 +59332,22806,30196,40217 +59317,22807,30195,40273 +57096,22808,30194,40671 +51081,22809,30193,40331 +55995,22810,30192,40188 +57545,22811,30191,40944 +58287,22812,30190,40690 +52639,22813,30189,40733 +52679,22814,30188,40551 +52363,22815,30187,40667 +51881,22816,30186,40701 +53223,22817,30185,40920 +59506,22818,30184,40495 +54965,22819,30183,40547 +56116,22820,30182,40124 +56405,22821,30181,40268 +59627,22822,30180,40963 +56067,22823,30179,40702 +55789,22824,30178,40468 +51261,22825,30177,40610 +53535,22826,30176,40023 +56050,22827,30175,40832 +53636,22828,30174,40283 +50597,22829,30173,40556 +58320,22830,30172,40061 +59441,22831,30171,40355 +52379,22832,30170,40866 +52887,22833,30169,40961 +58770,22834,30168,40443 +51922,22835,30167,40505 +58999,22836,30166,40845 +57708,22837,30165,40056 +56760,22838,30164,40889 +53353,22839,30163,40134 +51901,22840,30162,40870 +55777,22841,30161,40698 +53307,22842,30160,40153 +50395,22843,30159,40440 +58805,22844,30158,40775 +58117,22845,30157,40330 +55123,22846,30156,40399 +56656,22847,30155,40497 +53114,22848,30154,40311 +56360,22849,30153,40526 +54027,22850,30152,40025 +58434,22851,30151,40809 +54792,22852,30150,40809 +53918,22853,30149,40580 +57216,22854,30148,40846 +51547,22855,30147,40862 +54860,22856,30146,40418 +56122,22857,30145,40704 +57106,22858,30144,40968 +58666,22859,30143,40821 +53591,22860,30142,40858 +56882,22861,30141,40586 +58738,22862,30140,40171 +53886,22863,30139,40528 +52635,22864,30138,40223 +51793,22865,30137,40594 +58082,22866,30136,40101 +51129,22867,30135,40103 +52300,22868,30134,40135 +55647,22869,30133,40638 +57511,22870,30132,40598 +53917,22871,30131,40481 +52143,22872,30130,40164 +57003,22873,30129,40656 +55626,22874,30128,40799 +55858,22875,30127,40370 +58781,22876,30126,40919 +55521,22877,30125,40666 +54946,22878,30124,40429 +56830,22879,30123,40892 +57857,22880,30122,40703 +52740,22881,30121,40530 +52090,22882,30120,40604 +50154,22883,30119,40880 +52341,22884,30118,40561 +58069,22885,30117,40632 +53953,22886,30116,40805 +57972,22887,30115,40435 +55657,22888,30114,40759 +55209,22889,30113,40621 +53973,22890,30112,40202 +55255,22891,30111,40812 +56332,22892,30110,40531 +53686,22893,30109,40652 +51686,22894,30108,40479 +51715,22895,30107,40313 +55072,22896,30106,40355 +50133,22897,30105,40339 +56489,22898,30104,40513 +59003,22899,30103,40759 +54745,22900,30102,40131 +53313,22901,30101,40232 +52274,22902,30100,40880 +55458,22903,30099,40873 +55534,22904,30098,40464 +53911,22905,30097,40901 +50632,22906,30096,40502 +57437,22907,30095,40885 +59702,22908,30094,40305 +53636,22909,30093,40958 +59860,22910,30092,40294 +59571,22911,30091,40813 +58460,22912,30090,40398 +54377,22913,30089,40663 +53441,22914,30088,40064 +53695,22915,30087,40345 +57484,22916,30086,40747 +51850,22917,30085,40920 +53293,22918,30084,40985 +52716,22919,30083,40230 +51523,22920,30082,40771 +54234,22921,30081,40059 +59798,22922,30080,40589 +58872,22923,30079,40228 +59009,22924,30078,40238 +56991,22925,30077,40842 +50254,22926,30076,40863 +57297,22927,30075,40729 +55098,22928,30074,40381 +50900,22929,30073,40651 +51815,22930,30072,40661 +53402,22931,30071,40873 +59648,22932,30070,40283 +53026,22933,30069,40949 +59271,22934,30068,40854 +56038,22935,30067,40551 +52602,22936,30066,40003 +53077,22937,30065,40138 +55269,22938,30064,40989 +50843,22939,30063,40842 +51745,22940,30062,40958 +54397,22941,30061,40765 +54777,22942,30060,40861 +55473,22943,30059,40899 +58413,22944,30058,40004 +58537,22945,30057,40339 +50847,22946,30056,40132 +54208,22947,30055,40843 +52667,22948,30054,40655 +59181,22949,30053,40243 +58180,22950,30052,40874 +58325,22951,30051,40815 +56906,22952,30050,40421 +57389,22953,30049,40664 +54999,22954,30048,40121 +58908,22955,30047,40693 +54664,22956,30046,40868 +51423,22957,30045,40083 +58281,22958,30044,40140 +57559,22959,30043,40134 +58137,22960,30042,40134 +58669,22961,30041,40547 +51053,22962,30040,40873 +58645,22963,30039,40684 +54672,22964,30038,40860 +58800,22965,30037,40110 +53128,22966,30036,40273 +55339,22967,30035,40243 +59988,22968,30034,40765 +57397,22969,30033,40655 +59921,22970,30032,40828 +53630,22971,30031,40313 +54076,22972,30030,40494 +59835,22973,30029,40336 +52930,22974,30028,40184 +59479,22975,30027,40503 +56003,22976,30026,40400 +56243,22977,30025,40111 +53700,22978,30024,40857 +51325,22979,30023,40159 +50276,22980,30022,40182 +50526,22981,30021,40330 +59830,22982,30020,40111 +59613,22983,30019,40902 +50574,22984,30018,40838 +51698,22985,30017,40300 +56135,22986,30016,40573 +59013,22987,30015,40993 +52576,22988,30014,40181 +55349,22989,30013,40064 +51399,22990,30012,40565 +59652,22991,30011,40433 +56989,22992,30010,40213 +57087,22993,30009,40810 +55770,22994,30008,40470 +52924,22995,30007,40697 +59849,22996,30006,40633 +56348,22997,30005,40091 +50052,22998,30004,40720 +53824,22999,30003,40996 +54650,23000,30002,40885 +56840,23001,30001,40939 +55133,23002,30000,40421 +50453,23003,31000,40233 +57960,23004,30999,40136 +55216,23005,30998,40623 +55197,23006,30997,40351 +56708,23007,30996,40985 +52669,23008,30995,40019 +58871,23009,30994,40746 +53473,23010,30993,40702 +56614,23011,30992,40221 +50693,23012,30991,40896 +56462,23013,30990,40909 +52148,23014,30989,40193 +54646,23015,30988,40458 +52575,23016,30987,40525 +59577,23017,30986,40592 +52678,23018,30985,40649 +57683,23019,30984,40182 +54937,23020,30983,40217 +54065,23021,30982,40824 +57352,23022,30981,40067 +58586,23023,30980,40114 +54695,23024,30979,40195 +53756,23025,30978,40761 +53021,23026,30977,40788 +53919,23027,30976,40903 +55692,23028,30975,40744 +57767,23029,30974,40027 +53115,23030,30973,40133 +51621,23031,30972,40571 +55342,23032,30971,40852 +52812,23033,30970,40319 +50311,23034,30969,40014 +57233,23035,30968,40739 +56182,23036,30967,40589 +57803,23037,30966,40689 +52108,23038,30965,40644 +53786,23039,30964,40512 +59437,23040,30963,40796 +57541,23041,30962,40093 +52788,23042,30961,40388 +51003,23043,30960,40716 +52224,23044,30959,40197 +57819,23045,30958,40339 +51388,23046,30957,40751 +56367,23047,30956,40787 +54813,23048,30955,40659 +58659,23049,30954,40604 +59284,23050,30953,40815 +54356,23051,30952,40724 +59027,23052,30951,40799 +58483,23053,30950,40908 +52508,23054,30949,40222 +51304,23055,30948,40624 +50069,23056,30947,40272 +59540,23057,30946,40696 +59880,23058,30945,40467 +53566,23059,30944,40847 +59383,23060,30943,40322 +51471,23061,30942,40431 +51965,23062,30941,40469 +55866,23063,30940,40095 +51343,23064,30939,40729 +53443,23065,30938,40275 +50513,23066,30937,40279 +53648,23067,30936,40990 +51493,23068,30935,40988 +55468,23069,30934,40015 +52286,23070,30933,40957 +51896,23071,30932,40589 +52498,23072,30931,40276 +59773,23073,30930,40335 +56350,23074,30929,40219 +59469,23075,30928,40973 +59092,23076,30927,40556 +52023,23077,30926,40621 +57808,23078,30925,40674 +53512,23079,30924,40059 +51592,23080,30923,40888 +55231,23081,30922,40264 +56273,23082,30921,40500 +51833,23083,30920,40781 +52062,23084,30919,40008 +58379,23085,30918,40132 +51172,23086,30917,40365 +51550,23087,30916,40827 +52393,23088,30915,40340 +54325,23089,30914,40887 +56170,23090,30913,40890 +52666,23091,30912,40561 +50124,23092,30911,40238 +58710,23093,30910,40479 +58986,23094,30909,40115 +58703,23095,30908,40873 +58461,23096,30907,40589 +55179,23097,30906,40086 +57786,23098,30905,40042 +54659,23099,30904,40387 +59749,23100,30903,40190 +57284,23101,30902,40024 +52627,23102,30901,40618 +50879,23103,30900,40735 +58765,23104,30899,40739 +55167,23105,30898,40330 +54544,23106,30897,40394 +57578,23107,30896,40695 +50481,23108,30895,40502 +51409,23109,30894,40146 +59039,23110,30893,40026 +56898,23111,30892,40448 +51073,23112,30891,40043 +55885,23113,30890,40515 +59134,23114,30889,40579 +50547,23115,30888,40463 +58843,23116,30887,40563 +59257,23117,30886,40911 +50398,23118,30885,40801 +53069,23119,30884,40021 +50530,23120,30883,40293 +52752,23121,30882,40789 +59876,23122,30881,40889 +52065,23123,30880,40156 +59977,23124,30879,40429 +59915,23125,30878,40394 +55426,23126,30877,40021 +55508,23127,30876,40977 +50536,23128,30875,40504 +54486,23129,30874,40673 +50722,23130,30873,40732 +58347,23131,30872,40810 +58421,23132,30871,40603 +57601,23133,30870,40453 +51275,23134,30869,40396 +51405,23135,30868,40023 +55036,23136,30867,40536 +58476,23137,30866,40851 +56185,23138,30865,40866 +52596,23139,30864,40667 +53064,23140,30863,40626 +56792,23141,30862,40587 +58969,23142,30861,40174 +50267,23143,30860,40362 +58582,23144,30859,40117 +50076,23145,30858,40326 +53529,23146,30857,40282 +55504,23147,30856,40354 +52072,23148,30855,40769 +53774,23149,30854,40446 +50188,23150,30853,40977 +52643,23151,30852,40100 +51328,23152,30851,40462 +54502,23153,30850,40514 +59940,23154,30849,40178 +55445,23155,30848,40345 +50912,23156,30847,40239 +53854,23157,30846,40561 +51142,23158,30845,40227 +58362,23159,30844,40822 +57264,23160,30843,40505 +51267,23161,30842,40180 +53977,23162,30841,40352 +54791,23163,30840,40770 +57784,23164,30839,40594 +52932,23165,30838,40574 +54214,23166,30837,40955 +55363,23167,30836,40397 +50913,23168,30835,40932 +53458,23169,30834,40237 +53001,23170,30833,40475 +56313,23171,30832,40017 +51863,23172,30831,40857 +58559,23173,30830,40824 +59294,23174,30829,40703 +51108,23175,30828,40298 +56249,23176,30827,40502 +56302,23177,30826,40200 +57572,23178,30825,40554 +56978,23179,30824,40943 +52647,23180,30823,40074 +55832,23181,30822,40337 +50941,23182,30821,40222 +57826,23183,30820,40456 +59619,23184,30819,40669 +54549,23185,30818,40271 +55259,23186,30817,40171 +55029,23187,30816,40040 +59360,23188,30815,40211 +54991,23189,30814,40843 +59844,23190,30813,40239 +52447,23191,30812,40937 +55637,23192,30811,40809 +57794,23193,30810,40470 +56943,23194,30809,40988 +52086,23195,30808,40012 +59483,23196,30807,40500 +52446,23197,30806,40274 +51828,23198,30805,40815 +54450,23199,30804,40385 +54250,23200,30803,40374 +56835,23201,30802,40862 +52448,23202,30801,40924 +50683,23203,30800,40040 +51904,23204,30799,40938 +55699,23205,30798,40896 +50222,23206,30797,40253 +57918,23207,30796,40888 +58137,23208,30795,40085 +52835,23209,30794,40418 +54062,23210,30793,40202 +58328,23211,30792,40910 +50983,23212,30791,40949 +54777,23213,30790,40831 +54657,23214,30789,40744 +59096,23215,30788,40322 +57499,23216,30787,40139 +55279,23217,30786,40308 +52010,23218,30785,40188 +57137,23219,30784,40160 +57785,23220,30783,40610 +56222,23221,30782,40409 +53374,23222,30781,40422 +51349,23223,30780,40418 +50536,23224,30779,40783 +54900,23225,30778,40000 +50500,23226,30777,40009 +57866,23227,30776,40952 +59551,23228,30775,40617 +57614,23229,30774,40402 +53670,23230,30773,40039 +58729,23231,30772,40426 +59545,23232,30771,40864 +51261,23233,30770,40015 +53070,23234,30769,40798 +58953,23235,30768,40401 +59009,23236,30767,40471 +56837,23237,30766,40516 +56553,23238,30765,40959 +51896,23239,30764,40340 +58054,23240,30763,40075 +59369,23241,30762,40131 +51879,23242,30761,40963 +50274,23243,30760,40734 +54536,23244,30759,40755 +54960,23245,30758,40321 +50568,23246,30757,40598 +54823,23247,30756,40138 +53448,23248,30755,40088 +58563,23249,30754,40529 +59055,23250,30753,40158 +57833,23251,30752,40705 +52827,23252,30751,40036 +59819,23253,30750,40635 +59715,23254,30749,40099 +50683,23255,30748,40760 +55287,23256,30747,40812 +58135,23257,30746,40841 +54809,23258,30745,40702 +59970,23259,30744,40453 +55157,23260,30743,40864 +58996,23261,30742,40134 +57786,23262,30741,40779 +56103,23263,30740,40576 +59805,23264,30739,40527 +53810,23265,30738,40439 +53603,23266,30737,40065 +50291,23267,30736,40372 +51516,23268,30735,40214 +52037,23269,30734,40843 +54799,23270,30733,40878 +55090,23271,30732,40197 +51920,23272,30731,40511 +58641,23273,30730,40317 +59103,23274,30729,40885 +56080,23275,30728,40160 +50010,23276,30727,40611 +54461,23277,30726,40470 +58978,23278,30725,40161 +53486,23279,30724,40424 +53435,23280,30723,40803 +56049,23281,30722,40909 +53452,23282,30721,40641 +58541,23283,30720,40093 +51527,23284,30719,40768 +58471,23285,30718,40752 +58147,23286,30717,40820 +50753,23287,30716,40604 +59492,23288,30715,40088 +52140,23289,30714,40970 +53292,23290,30713,40700 +58847,23291,30712,40628 +56731,23292,30711,40826 +57712,23293,30710,40789 +56370,23294,30709,40677 +57294,23295,30708,40661 +57574,23296,30707,40390 +50769,23297,30706,40847 +56639,23298,30705,40860 +51802,23299,30704,40504 +54656,23300,30703,40063 +55652,23301,30702,40174 +50145,23302,30701,40433 +55804,23303,30700,40419 +59287,23304,30699,40970 +57196,23305,30698,40749 +50822,23306,30697,40919 +53058,23307,30696,40036 +58237,23308,30695,40031 +55536,23309,30694,40071 +57903,23310,30693,40809 +54925,23311,30692,40971 +51858,23312,30691,40412 +53065,23313,30690,40289 +53088,23314,30689,40061 +55277,23315,30688,40290 +58459,23316,30687,40911 +55216,23317,30686,40465 +57198,23318,30685,40042 +56471,23319,30684,40334 +57758,23320,30683,40186 +57812,23321,30682,40467 +56847,23322,30681,40387 +50863,23323,30680,40548 +51011,23324,30679,40774 +55938,23325,30678,40912 +50557,23326,30677,40691 +52541,23327,30676,40686 +56868,23328,30675,40659 +51595,23329,30674,40118 +51315,23330,30673,40520 +54156,23331,30672,40454 +55981,23332,30671,40827 +56305,23333,30670,40837 +50797,23334,30669,40834 +50326,23335,30668,40912 +52940,23336,30667,40252 +51529,23337,30666,40078 +59484,23338,30665,40426 +59577,23339,30664,40545 +55377,23340,30663,40260 +51513,23341,30662,40516 +51440,23342,30661,40085 +58980,23343,30660,40891 +58943,23344,30659,40733 +54379,23345,30658,40020 +54011,23346,30657,40553 +57034,23347,30656,40737 +58377,23348,30655,40560 +59960,23349,30654,40646 +58100,23350,30653,40412 +51837,23351,30652,40997 +56645,23352,30651,40499 +58366,23353,30650,40979 +56001,23354,30649,40498 +52659,23355,30648,40278 +53228,23356,30647,40533 +54666,23357,30646,40726 +54251,23358,30645,40621 +51109,23359,30644,40934 +55079,23360,30643,40318 +54590,23361,30642,40398 +51501,23362,30641,40540 +53546,23363,30640,40773 +58739,23364,30639,40618 +50619,23365,30638,40112 +52309,23366,30637,40286 +52864,23367,30636,40017 +54941,23368,30635,40148 +57031,23369,30634,40086 +53585,23370,30633,40238 +54739,23371,30632,40168 +56919,23372,30631,40205 +50953,23373,30630,40660 +55395,23374,30629,40446 +54915,23375,30628,40282 +52688,23376,30627,40268 +55335,23377,30626,40823 +56781,23378,30625,40669 +59538,23379,30624,40713 +56927,23380,30623,40772 +53118,23381,30622,40310 +59973,23382,30621,40731 +56275,23383,30620,40378 +55225,23384,30619,40227 +55626,23385,30618,40507 +51410,23386,30617,40114 +57100,23387,30616,40298 +54678,23388,30615,40439 +53320,23389,30614,40041 +57100,23390,30613,40300 +51700,23391,30612,40195 +50383,23392,30611,40353 +59035,23393,30610,40228 +50319,23394,30609,40785 +56437,23395,30608,40911 +53714,23396,30607,40859 +59620,23397,30606,40894 +54568,23398,30605,40536 +53690,23399,30604,40337 +51708,23400,30603,40475 +53256,23401,30602,40534 +55382,23402,30601,40746 +56274,23403,30600,40201 +58941,23404,30599,40776 +58126,23405,30598,40528 +57610,23406,30597,40548 +50939,23407,30596,40094 +54439,23408,30595,40529 +53086,23409,30594,40610 +55495,23410,30593,40347 +51815,23411,30592,40915 +59711,23412,30591,40555 +53826,23413,30590,40434 +53218,23414,30589,40063 +59050,23415,30588,40444 +55610,23416,30587,40393 +59800,23417,30586,40578 +50674,23418,30585,40970 +59449,23419,30584,40007 +53089,23420,30583,40267 +55693,23421,30582,40822 +53792,23422,30581,40216 +54603,23423,30580,40334 +51821,23424,30579,40346 +50931,23425,30578,40307 +53800,23426,30577,40567 +52396,23427,30576,40825 +59018,23428,30575,40503 +52395,23429,30574,40143 +55238,23430,30573,40310 +56309,23431,30572,40046 +55528,23432,30571,40849 +51035,23433,30570,40133 +59514,23434,30569,40735 +50276,23435,30568,40131 +54757,23436,30567,40101 +55354,23437,30566,40112 +50819,23438,30565,40926 +59098,23439,30564,40383 +59827,23440,30563,40565 +56846,23441,30562,40332 +58791,23442,30561,40249 +55416,23443,30560,40758 +52120,23444,30559,40012 +53652,23445,30558,40921 +51113,23446,30557,40463 +58368,23447,30556,40652 +56280,23448,30555,40902 +58408,23449,30554,40562 +51473,23450,30553,40683 +59737,23451,30552,40846 +52013,23452,30551,40130 +51384,23453,30550,40872 +54264,23454,30549,40657 +58523,23455,30548,40406 +54879,23456,30547,40345 +55060,23457,30546,40201 +53576,23458,30545,40029 +50670,23459,30544,40870 +59980,23460,30543,40862 +52560,23461,30542,40077 +53167,23462,30541,40328 +54719,23463,30540,40481 +57809,23464,30539,40949 +58625,23465,30538,40084 +55244,23466,30537,40700 +53627,23467,30536,40982 +51645,23468,30535,40646 +51659,23469,30534,40379 +55616,23470,30533,40052 +56626,23471,30532,40599 +58053,23472,30531,40104 +52713,23473,30530,40406 +58815,23474,30529,40503 +55508,23475,30528,40187 +50090,23476,30527,40216 +53924,23477,30526,40781 +51388,23478,30525,40676 +57623,23479,30524,40105 +58084,23480,30523,40434 +55178,23481,30522,40776 +51151,23482,30521,40533 +55230,23483,30520,40455 +59370,23484,30519,40116 +56264,23485,30518,40685 +52114,23486,30517,40566 +50899,23487,30516,40932 +59751,23488,30515,40879 +58912,23489,30514,40279 +52367,23490,30513,40164 +59437,23491,30512,40468 +57238,23492,30511,40055 +56452,23493,30510,40733 +58115,23494,30509,40279 +55114,23495,30508,40985 +51479,23496,30507,40176 +50648,23497,30506,40467 +51502,23498,30505,40098 +53670,23499,30504,40276 +51207,23500,30503,40944 +57875,23501,30502,40361 +58912,23502,30501,40896 +56306,23503,30500,40299 +51947,23504,30499,40850 +50334,23505,30498,40551 +54045,23506,30497,40814 +54637,23507,30496,40042 +50949,23508,30495,40767 +53971,23509,30494,40675 +56938,23510,30493,40926 +54430,23511,30492,40093 +54796,23512,30491,40676 +58094,23513,30490,40463 +55325,23514,30489,40215 +56503,23515,30488,40265 +52313,23516,30487,40416 +53039,23517,30486,40301 +53936,23518,30485,40567 +52915,23519,30484,40360 +52388,23520,30483,40052 +51158,23521,30482,40956 +57549,23522,30481,40851 +55017,23523,30480,40283 +51162,23524,30479,40555 +53173,23525,30478,40050 +53283,23526,30477,40299 +57669,23527,30476,40375 +59706,23528,30475,40273 +59713,23529,30474,40601 +57295,23530,30473,40841 +57989,23531,30472,40139 +58738,23532,30471,40550 +56177,23533,30470,40340 +55892,23534,30469,40744 +55049,23535,30468,40438 +50838,23536,30467,40210 +54957,23537,30466,40688 +54675,23538,30465,40726 +57523,23539,30464,40339 +53290,23540,30463,40192 +58383,23541,30462,40222 +54627,23542,30461,40196 +54228,23543,30460,40422 +54594,23544,30459,40692 +54581,23545,30458,40533 +51049,23546,30457,40506 +59845,23547,30456,40709 +50296,23548,30455,40847 +56236,23549,30454,40529 +51312,23550,30453,40238 +54346,23551,30452,40697 +54582,23552,30451,40327 +52806,23553,30450,40689 +55763,23554,30449,40515 +57536,23555,30448,40316 +52583,23556,30447,40865 +52853,23557,30446,40194 +54157,23558,30445,40420 +51008,23559,30444,40203 +50122,23560,30443,40329 +57181,23561,30442,40559 +53983,23562,30441,40480 +51321,23563,30440,40388 +59054,23564,30439,40590 +53365,23565,30438,40994 +56650,23566,30437,40996 +59738,23567,30436,40086 +55143,23568,30435,40769 +59574,23569,30434,40193 +54432,23570,30433,40671 +57460,23571,30432,40277 +53159,23572,30431,40092 +55322,23573,30430,40715 +56887,23574,30429,40199 +56556,23575,30428,40724 +58789,23576,30427,40388 +56909,23577,30426,40714 +51845,23578,30425,40726 +53398,23579,30424,40114 +54473,23580,30423,40040 +54591,23581,30422,40729 +59268,23582,30421,40008 +57691,23583,30420,40856 +55901,23584,30419,40505 +53856,23585,30418,40453 +51951,23586,30417,40284 +55619,23587,30416,40247 +54573,23588,30415,40946 +54866,23589,30414,40166 +50979,23590,30413,40633 +54875,23591,30412,40396 +52663,23592,30411,40112 +56603,23593,30410,40812 +58463,23594,30409,40768 +56208,23595,30408,40222 +54988,23596,30407,40241 +59519,23597,30406,40228 +58211,23598,30405,40110 +57618,23599,30404,40892 +58348,23600,30403,40726 +55145,23601,30402,40433 +56964,23602,30401,40944 +50241,23603,30400,40936 +50349,23604,30399,40250 +59250,23605,30398,40957 +57878,23606,30397,40422 +53171,23607,30396,40024 +58773,23608,30395,40642 +51912,23609,30394,40960 +50800,23610,30393,40282 +59499,23611,30392,40793 +57179,23612,30391,40900 +50569,23613,30390,40213 +52795,23614,30389,40616 +57539,23615,30388,40869 +59241,23616,30387,40682 +58164,23617,30386,40618 +53907,23618,30385,40173 +51987,23619,30384,40764 +57708,23620,30383,40310 +59678,23621,30382,40717 +51300,23622,30381,40458 +53718,23623,30380,40811 +56434,23624,30379,40893 +50778,23625,30378,40161 +59965,23626,30377,40368 +59980,23627,30376,40482 +57738,23628,30375,40758 +52160,23629,30374,40737 +51104,23630,30373,40915 +50322,23631,30372,40743 +51671,23632,30371,40010 +58214,23633,30370,40089 +54895,23634,30369,40633 +53323,23635,30368,40702 +54653,23636,30367,40955 +55529,23637,30366,40450 +58672,23638,30365,40922 +59802,23639,30364,40922 +59282,23640,30363,40598 +52677,23641,30362,40989 +59306,23642,30361,40367 +56293,23643,30360,40466 +54910,23644,30359,40563 +54568,23645,30358,40148 +57125,23646,30357,40180 +56531,23647,30356,40831 +57291,23648,30355,40641 +52739,23649,30354,40485 +54077,23650,30353,40663 +51854,23651,30352,40970 +53668,23652,30351,40028 +57128,23653,30350,40016 +52383,23654,30349,40777 +56594,23655,30348,40232 +57609,23656,30347,40721 +56204,23657,30346,40558 +54122,23658,30345,40594 +56283,23659,30344,40111 +57194,23660,30343,40478 +53078,23661,30342,40306 +51439,23662,30341,40038 +52442,23663,30340,40992 +54087,23664,30339,40836 +55662,23665,30338,40865 +54385,23666,30337,40772 +59681,23667,30336,40653 +57494,23668,30335,40399 +56862,23669,30334,40051 +54294,23670,30333,40307 +56097,23671,30332,40873 +57164,23672,30331,40034 +51972,23673,30330,40761 +51043,23674,30329,40620 +52835,23675,30328,40524 +50578,23676,30327,40972 +57214,23677,30326,40783 +53378,23678,30325,40717 +52908,23679,30324,40222 +57201,23680,30323,40751 +50779,23681,30322,40753 +59583,23682,30321,40114 +55766,23683,30320,40354 +54086,23684,30319,40189 +59152,23685,30318,40391 +59238,23686,30317,40332 +52573,23687,30316,40154 +52718,23688,30315,40012 +51008,23689,30314,40210 +57127,23690,30313,40939 +59295,23691,30312,40646 +56810,23692,30311,40969 +58915,23693,30310,40958 +58370,23694,30309,40093 +58315,23695,30308,40294 +57996,23696,30307,40238 +50495,23697,30306,40688 +58715,23698,30305,40383 +53394,23699,30304,40645 +54600,23700,30303,40061 +58769,23701,30302,40696 +56262,23702,30301,40296 +59193,23703,30300,40198 +52819,23704,30299,40763 +52117,23705,30298,40733 +50651,23706,30297,40650 +57940,23707,30296,40576 +57367,23708,30295,40480 +57145,23709,30294,40285 +58771,23710,30293,40562 +51932,23711,30292,40564 +52525,23712,30291,40124 +54686,23713,30290,40820 +54904,23714,30289,40221 +58874,23715,30288,40499 +50560,23716,30287,40249 +52598,23717,30286,40225 +59785,23718,30285,40387 +53417,23719,30284,40906 +58240,23720,30283,40645 +52982,23721,30282,40526 +52435,23722,30281,40646 +58967,23723,30280,40095 +59404,23724,30279,40910 +57925,23725,30278,40375 +53400,23726,30277,40577 +56883,23727,30276,40659 +53782,23728,30275,40613 +55723,23729,30274,40895 +52907,23730,30273,40866 +57088,23731,30272,40287 +54051,23732,30271,40582 +56915,23733,30270,40520 +58626,23734,30269,40826 +54545,23735,30268,40057 +57144,23736,30267,40132 +56584,23737,30266,40025 +56018,23738,30265,40169 +50762,23739,30264,40534 +59165,23740,30263,40487 +52427,23741,30262,40679 +59622,23742,30261,40244 +57973,23743,30260,40151 +50525,23744,30259,40039 +59979,23745,30258,40830 +51016,23746,30257,40497 +50186,23747,30256,40046 +55332,23748,30255,40551 +53771,23749,30254,40175 +50118,23750,30253,40647 +53508,23751,30252,40015 +53951,23752,30251,40029 +54879,23753,30250,40210 +56750,23754,30249,40113 +58819,23755,30248,40953 +53855,23756,30247,40070 +56030,23757,30246,40514 +50609,23758,30245,40537 +54900,23759,30244,40757 +59062,23760,30243,40620 +53729,23761,30242,40902 +57251,23762,30241,40166 +57578,23763,30240,40899 +54295,23764,30239,40433 +58994,23765,30238,40467 +53273,23766,30237,40192 +54968,23767,30236,40113 +59385,23768,30235,40411 +53454,23769,30234,40796 +59593,23770,30233,40745 +50516,23771,30232,40797 +54485,23772,30231,40568 +55571,23773,30230,40861 +54205,23774,30229,40731 +56806,23775,30228,40056 +51475,23776,30227,40929 +55538,23777,30226,40753 +51664,23778,30225,40606 +53670,23779,30224,40930 +51233,23780,30223,40800 +54013,23781,30222,40593 +51502,23782,30221,40144 +53408,23783,30220,40746 +54347,23784,30219,40131 +58729,23785,30218,40509 +50440,23786,30217,40876 +53011,23787,30216,40021 +51779,23788,30215,40656 +57293,23789,30214,40914 +55085,23790,30213,40694 +53613,23791,30212,40556 +50602,23792,30211,40953 +53857,23793,30210,40620 +57394,23794,30209,40035 +56896,23795,30208,40144 +55908,23796,30207,40208 +59295,23797,30206,40235 +59675,23798,30205,40275 +50592,23799,30204,40335 +56728,23800,30203,40297 +57077,23801,30202,40480 +52494,23802,30201,40408 +59827,23803,30200,40646 +52237,23804,30199,40292 +51361,23805,30198,40470 +52166,23806,30197,40942 +58703,23807,30196,40574 +50494,23808,30195,40329 +56643,23809,30194,40539 +51614,23810,30193,40019 +57438,23811,30192,40649 +59718,23812,30191,40924 +58781,23813,30190,40510 +52866,23814,30189,40686 +55260,23815,30188,40995 +50164,23816,30187,40312 +52966,23817,30186,40192 +56161,23818,30185,40961 +59607,23819,30184,40779 +50648,23820,30183,40174 +54370,23821,30182,40189 +59437,23822,30181,40176 +56494,23823,30180,40753 +57156,23824,30179,40765 +58075,23825,30178,40898 +50632,23826,30177,40617 +59763,23827,30176,40335 +55083,23828,30175,40408 +56059,23829,30174,40590 +51896,23830,30173,40211 +57832,23831,30172,40594 +58564,23832,30171,40189 +57007,23833,30170,40090 +54947,23834,30169,40233 +58981,23835,30168,40360 +53015,23836,30167,40114 +53701,23837,30166,40619 +55555,23838,30165,40358 +52432,23839,30164,40402 +56782,23840,30163,40984 +51630,23841,30162,40492 +59347,23842,30161,40529 +53970,23843,30160,40841 +50757,23844,30159,40202 +50460,23845,30158,40942 +58800,23846,30157,40512 +51816,23847,30156,40705 +51627,23848,30155,40828 +50452,23849,30154,40434 +59337,23850,30153,40270 +52176,23851,30152,40082 +50398,23852,30151,40245 +57293,23853,30150,40339 +52287,23854,30149,40926 +57751,23855,30148,40876 +59554,23856,30147,40511 +51327,23857,30146,40815 +58645,23858,30145,40295 +51025,23859,30144,40536 +58026,23860,30143,40028 +54213,23861,30142,40660 +53808,23862,30141,40736 +58465,23863,30140,40588 +58845,23864,30139,40568 +52299,23865,30138,40580 +58567,23866,30137,40818 +57451,23867,30136,40789 +56690,23868,30135,40483 +57023,23869,30134,40699 +59123,23870,30133,40059 +55705,23871,30132,40315 +52819,23872,30131,40974 +50275,23873,30130,40549 +54304,23874,30129,40375 +56659,23875,30128,40322 +56334,23876,30127,40010 +53849,23877,30126,40051 +55642,23878,30125,40566 +52725,23879,30124,40829 +54494,23880,30123,40894 +51893,23881,30122,40452 +54016,23882,30121,40819 +52172,23883,30120,40123 +55670,23884,30119,40592 +51151,23885,30118,40894 +56612,23886,30117,40913 +53640,23887,30116,40892 +51718,23888,30115,40304 +52670,23889,30114,40948 +51145,23890,30113,40749 +55772,23891,30112,40282 +54515,23892,30111,40106 +54557,23893,30110,40022 +53459,23894,30109,40089 +58665,23895,30108,40610 +55699,23896,30107,40338 +56856,23897,30106,40974 +54970,23898,30105,40284 +57270,23899,30104,40586 +57278,23900,30103,40447 +51312,23901,30102,40231 +54118,23902,30101,40268 +56410,23903,30100,40058 +54478,23904,30099,40346 +56866,23905,30098,40414 +59636,23906,30097,40286 +50783,23907,30096,40845 +59455,23908,30095,40182 +58916,23909,30094,40267 +56703,23910,30093,40386 +52673,23911,30092,40679 +57839,23912,30091,40311 +55688,23913,30090,40622 +57879,23914,30089,40601 +54125,23915,30088,40134 +57886,23916,30087,40789 +59398,23917,30086,40684 +57229,23918,30085,40600 +55634,23919,30084,40194 +53519,23920,30083,40528 +55558,23921,30082,40785 +53140,23922,30081,40629 +56834,23923,30080,40918 +57765,23924,30079,40426 +51971,23925,30078,40756 +59169,23926,30077,40126 +59777,23927,30076,40951 +51142,23928,30075,40490 +52856,23929,30074,40656 +55292,23930,30073,40287 +50837,23931,30072,40018 +52363,23932,30071,40989 +57222,23933,30070,40439 +53117,23934,30069,40754 +54884,23935,30068,40015 +54749,23936,30067,40717 +55948,23937,30066,40775 +51279,23938,30065,40022 +57416,23939,30064,40010 +57593,23940,30063,40812 +59997,23941,30062,40926 +51119,23942,30061,40898 +52206,23943,30060,40358 +50157,23944,30059,40351 +50461,23945,30058,40343 +55453,23946,30057,40992 +58081,23947,30056,40634 +58376,23948,30055,40012 +50660,23949,30054,40813 +51081,23950,30053,40092 +54371,23951,30052,40030 +59965,23952,30051,40718 +59049,23953,30050,40869 +58519,23954,30049,40429 +54021,23955,30048,40788 +51568,23956,30047,40014 +51831,23957,30046,40118 +52891,23958,30045,40104 +54714,23959,30044,40841 +52518,23960,30043,40273 +59675,23961,30042,40513 +59805,23962,30041,40242 +51655,23963,30040,40610 +57081,23964,30039,40518 +58339,23965,30038,40386 +51990,23966,30037,40604 +50613,23967,30036,40810 +52034,23968,30035,40782 +59792,23969,30034,40207 +54289,23970,30033,40350 +57165,23971,30032,40384 +58109,23972,30031,40556 +59428,23973,30030,40574 +58202,23974,30029,40966 +54042,23975,30028,40883 +50728,23976,30027,40613 +50388,23977,30026,40224 +55761,23978,30025,40495 +54730,23979,30024,40608 +53219,23980,30023,40271 +56567,23981,30022,40554 +51016,23982,30021,40781 +58301,23983,30020,40255 +57648,23984,30019,40411 +55317,23985,30018,40097 +57376,23986,30017,40693 +53316,23987,30016,40803 +52932,23988,30015,40948 +57337,23989,30014,40419 +50960,23990,30013,40615 +56898,23991,30012,40728 +52148,23992,30011,40862 +59135,23993,30010,40106 +56429,23994,30009,40757 +56670,23995,30008,40189 +58072,23996,30007,40210 +59877,23997,30006,40673 +55618,23998,30005,40803 +55391,23999,30004,40210 +59340,24000,30003,40687 +56909,24001,30002,40510 +54682,24002,30001,40471 +56718,24003,30000,40056 +53513,24004,31000,40560 +54921,24005,30999,40121 +59872,24006,30998,40888 +59367,24007,30997,40197 +53904,24008,30996,40386 +57662,24009,30995,40529 +51013,24010,30994,40864 +54263,24011,30993,40223 +56303,24012,30992,40436 +54033,24013,30991,40195 +56954,24014,30990,40555 +56751,24015,30989,40646 +50344,24016,30988,40734 +53628,24017,30987,40924 +55073,24018,30986,40718 +54415,24019,30985,40348 +56449,24020,30984,40332 +56809,24021,30983,40467 +51984,24022,30982,40491 +53899,24023,30981,40998 +54238,24024,30980,40171 +53557,24025,30979,40802 +56765,24026,30978,40442 +56937,24027,30977,40353 +59289,24028,30976,40136 +51950,24029,30975,40044 +50866,24030,30974,40479 +52785,24031,30973,40847 +54394,24032,30972,40709 +54181,24033,30971,40254 +51242,24034,30970,40944 +55355,24035,30969,40226 +56831,24036,30968,40869 +57725,24037,30967,40975 +53186,24038,30966,40701 +58676,24039,30965,40765 +56885,24040,30964,40917 +56937,24041,30963,40425 +54312,24042,30962,40480 +59672,24043,30961,40888 +56940,24044,30960,40483 +53969,24045,30959,40520 +57023,24046,30958,40029 +58505,24047,30957,40530 +57286,24048,30956,40080 +55085,24049,30955,40191 +55849,24050,30954,40576 +57158,24051,30953,40782 +52407,24052,30952,40583 +50136,24053,30951,40328 +58474,24054,30950,40675 +55492,24055,30949,40064 +54598,24056,30948,40101 +52830,24057,30947,40898 +52779,24058,30946,40751 +50025,24059,30945,40279 +51419,24060,30944,40137 +58205,24061,30943,40906 +53989,24062,30942,40007 +51227,24063,30941,40946 +50670,24064,30940,40219 +59767,24065,30939,40525 +54593,24066,30938,40458 +56964,24067,30937,40877 +54222,24068,30936,40302 +51822,24069,30935,40025 +50126,24070,30934,40456 +57185,24071,30933,40059 +57591,24072,30932,40711 +56919,24073,30931,40721 +53690,24074,30930,40897 +51902,24075,30929,40091 +55690,24076,30928,40757 +55383,24077,30927,40608 +52311,24078,30926,40987 +55883,24079,30925,40164 +55048,24080,30924,40041 +58424,24081,30923,40914 +54648,24082,30922,40347 +59945,24083,30921,40818 +57575,24084,30920,40037 +58836,24085,30919,40936 +50209,24086,30918,40192 +59117,24087,30917,40737 +57483,24088,30916,40607 +56040,24089,30915,40634 +53721,24090,30914,40324 +58860,24091,30913,40134 +58573,24092,30912,40956 +53618,24093,30911,40172 +57323,24094,30910,40084 +57197,24095,30909,40979 +58375,24096,30908,40071 +51651,24097,30907,40299 +50832,24098,30906,40285 +50138,24099,30905,40250 +53926,24100,30904,40273 +58510,24101,30903,40943 +59126,24102,30902,40103 +52910,24103,30901,40030 +57910,24104,30900,40976 +55686,24105,30899,40881 +57180,24106,30898,40747 +51447,24107,30897,40983 +50969,24108,30896,40794 +53219,24109,30895,40659 +53475,24110,30894,40918 +52309,24111,30893,40596 +59536,24112,30892,40736 +53885,24113,30891,40820 +59854,24114,30890,40558 +55289,24115,30889,40496 +55951,24116,30888,40302 +57855,24117,30887,40387 +59442,24118,30886,40545 +58822,24119,30885,40967 +59837,24120,30884,40287 +51317,24121,30883,40305 +55574,24122,30882,40363 +52307,24123,30881,40648 +58593,24124,30880,40050 +50494,24125,30879,40545 +54867,24126,30878,40654 +59191,24127,30877,40754 +50950,24128,30876,40145 +53322,24129,30875,40665 +58773,24130,30874,40704 +50251,24131,30873,40280 +57063,24132,30872,40839 +55532,24133,30871,40288 +56680,24134,30870,40235 +51195,24135,30869,40071 +57043,24136,30868,40983 +50456,24137,30867,40232 +55020,24138,30866,40454 +53445,24139,30865,40693 +54937,24140,30864,40001 +54278,24141,30863,40267 +59073,24142,30862,40742 +52807,24143,30861,40569 +53341,24144,30860,40334 +56237,24145,30859,40022 +58699,24146,30858,40705 +56404,24147,30857,40791 +58673,24148,30856,40633 +55688,24149,30855,40322 +55278,24150,30854,40567 +59840,24151,30853,40795 +55500,24152,30852,40973 +59284,24153,30851,40232 +52498,24154,30850,40433 +51247,24155,30849,40050 +50742,24156,30848,40899 +51599,24157,30847,40243 +52560,24158,30846,40100 +50841,24159,30845,40710 +54233,24160,30844,40571 +55898,24161,30843,40423 +50002,24162,30842,40100 +54089,24163,30841,40008 +58401,24164,30840,40055 +57128,24165,30839,40693 +56230,24166,30838,40451 +57320,24167,30837,40310 +59276,24168,30836,40453 +58380,24169,30835,40566 +51020,24170,30834,40265 +52854,24171,30833,40788 +55579,24172,30832,40603 +54990,24173,30831,40357 +52243,24174,30830,40579 +53393,24175,30829,40452 +50367,24176,30828,40203 +51414,24177,30827,40136 +52767,24178,30826,40814 +55532,24179,30825,40304 +58476,24180,30824,40630 +58943,24181,30823,40981 +56117,24182,30822,40234 +55705,24183,30821,40276 +55736,24184,30820,40690 +53781,24185,30819,40511 +54461,24186,30818,40025 +59215,24187,30817,40119 +58652,24188,30816,40990 +59879,24189,30815,40455 +54863,24190,30814,40815 +59540,24191,30813,40368 +54786,24192,30812,40027 +52933,24193,30811,40189 +59702,24194,30810,40561 +58210,24195,30809,40434 +52629,24196,30808,40546 +52290,24197,30807,40198 +56063,24198,30806,40328 +56502,24199,30805,40098 +51859,24200,30804,40386 +58130,24201,30803,40765 +59418,24202,30802,40493 +56908,24203,30801,40061 +52526,24204,30800,40552 +50109,24205,30799,40996 +57208,24206,30798,40188 +58804,24207,30797,40429 +59606,24208,30796,40198 +54074,24209,30795,40313 +54282,24210,30794,40371 +59520,24211,30793,40859 +51296,24212,30792,40623 +55108,24213,30791,40988 +50312,24214,30790,40449 +53715,24215,30789,40843 +55265,24216,30788,40526 +57144,24217,30787,40749 +56855,24218,30786,40177 +55714,24219,30785,40292 +59843,24220,30784,40548 +59764,24221,30783,40136 +54033,24222,30782,40102 +59494,24223,30781,40855 +57231,24224,30780,40257 +57065,24225,30779,40354 +58529,24226,30778,40686 +58232,24227,30777,40453 +54241,24228,30776,40280 +55690,24229,30775,40442 +53667,24230,30774,40905 +54675,24231,30773,40132 +58247,24232,30772,40509 +51578,24233,30771,40923 +52536,24234,30770,40425 +52118,24235,30769,40464 +56497,24236,30768,40999 +52305,24237,30767,40150 +53183,24238,30766,40618 +58303,24239,30765,40491 +58882,24240,30764,40104 +52407,24241,30763,40298 +53437,24242,30762,40824 +51856,24243,30761,40255 +57149,24244,30760,40889 +54471,24245,30759,40358 +59622,24246,30758,40629 +58460,24247,30757,40576 +51912,24248,30756,40713 +56397,24249,30755,40995 +57249,24250,30754,40914 +52330,24251,30753,40244 +52380,24252,30752,40397 +57768,24253,30751,40748 +58535,24254,30750,40570 +58529,24255,30749,40940 +54402,24256,30748,40734 +56648,24257,30747,40774 +52563,24258,30746,40124 +57130,24259,30745,40890 +56455,24260,30744,40368 +56816,24261,30743,40290 +55459,24262,30742,40776 +53025,24263,30741,40411 +58744,24264,30740,40455 +54501,24265,30739,40208 +55813,24266,30738,40982 +53012,24267,30737,40124 +50470,24268,30736,40385 +59980,24269,30735,40668 +53658,24270,30734,40820 +53345,24271,30733,40511 +51267,24272,30732,40632 +50223,24273,30731,40875 +53799,24274,30730,40694 +50076,24275,30729,40045 +58147,24276,30728,40039 +52825,24277,30727,40515 +54398,24278,30726,40309 +50870,24279,30725,40570 +54459,24280,30724,40266 +54005,24281,30723,40408 +52233,24282,30722,40939 +54214,24283,30721,40117 +53381,24284,30720,40920 +55618,24285,30719,40523 +56959,24286,30718,40267 +57556,24287,30717,40567 +50154,24288,30716,40106 +54225,24289,30715,40851 +52412,24290,30714,40907 +57288,24291,30713,40905 +51157,24292,30712,40667 +54613,24293,30711,40494 +52013,24294,30710,40858 +51535,24295,30709,40592 +53686,24296,30708,40623 +56433,24297,30707,40701 +51873,24298,30706,40508 +50966,24299,30705,40754 +52828,24300,30704,40918 +53149,24301,30703,40869 +54825,24302,30702,40123 +50748,24303,30701,40464 +56186,24304,30700,40447 +54529,24305,30699,40859 +53223,24306,30698,40837 +58676,24307,30697,40108 +52018,24308,30696,40183 +51560,24309,30695,40181 +50626,24310,30694,40907 +54512,24311,30693,40034 +55884,24312,30692,40706 +50350,24313,30691,40141 +50593,24314,30690,40005 +53430,24315,30689,40976 +52096,24316,30688,40342 +56322,24317,30687,40630 +58139,24318,30686,40248 +56367,24319,30685,40471 +53095,24320,30684,40332 +54036,24321,30683,40151 +52285,24322,30682,40698 +52386,24323,30681,40553 +55997,24324,30680,40696 +53847,24325,30679,40437 +55155,24326,30678,40202 +50749,24327,30677,40011 +59553,24328,30676,40774 +58608,24329,30675,40834 +56444,24330,30674,40954 +53004,24331,30673,40082 +57651,24332,30672,40653 +50372,24333,30671,40346 +53034,24334,30670,40318 +59343,24335,30669,40863 +56709,24336,30668,40637 +55789,24337,30667,40666 +59327,24338,30666,40677 +54696,24339,30665,40661 +53835,24340,30664,40842 +56790,24341,30663,40098 +55169,24342,30662,40204 +55514,24343,30661,40591 +57626,24344,30660,40112 +51850,24345,30659,40354 +53735,24346,30658,40432 +55099,24347,30657,40516 +50235,24348,30656,40510 +55480,24349,30655,40069 +54186,24350,30654,40834 +57762,24351,30653,40245 +59465,24352,30652,40253 +54209,24353,30651,40906 +59972,24354,30650,40362 +54921,24355,30649,40019 +55214,24356,30648,40120 +54280,24357,30647,40736 +54883,24358,30646,40046 +53499,24359,30645,40971 +57626,24360,30644,40884 +57520,24361,30643,40759 +50598,24362,30642,40441 +58807,24363,30641,40251 +50508,24364,30640,40502 +57409,24365,30639,40435 +55054,24366,30638,40367 +59562,24367,30637,40212 +55190,24368,30636,40561 +52740,24369,30635,40018 +50334,24370,30634,40813 +56104,24371,30633,40304 +56764,24372,30632,40463 +53969,24373,30631,40970 +53692,24374,30630,40587 +50692,24375,30629,40850 +58293,24376,30628,40317 +50663,24377,30627,40918 +54333,24378,30626,40539 +56083,24379,30625,40987 +59576,24380,30624,40057 +58228,24381,30623,40552 +50668,24382,30622,40649 +50573,24383,30621,40073 +56800,24384,30620,40661 +56904,24385,30619,40757 +55987,24386,30618,40090 +57211,24387,30617,40351 +53144,24388,30616,40547 +56151,24389,30615,40694 +50175,24390,30614,40983 +59433,24391,30613,40241 +58271,24392,30612,40800 +56451,24393,30611,40499 +54848,24394,30610,40969 +56741,24395,30609,40670 +57861,24396,30608,40971 +55029,24397,30607,40487 +57350,24398,30606,40252 +56510,24399,30605,40670 +52379,24400,30604,40852 +59060,24401,30603,40257 +53317,24402,30602,40965 +59205,24403,30601,40444 +57383,24404,30600,40687 +55195,24405,30599,40439 +59489,24406,30598,40294 +56591,24407,30597,40827 +53277,24408,30596,40545 +56391,24409,30595,40146 +55874,24410,30594,40103 +53904,24411,30593,40482 +54118,24412,30592,40711 +50615,24413,30591,40278 +58641,24414,30590,40460 +57376,24415,30589,40970 +53228,24416,30588,40579 +55978,24417,30587,40536 +59832,36673,30586,40739 +53450,24419,30585,40460 +58636,24420,30584,40720 +50227,24421,30583,40488 +57734,24422,30582,40956 +58568,24423,30581,40461 +51426,24424,30580,40923 +53560,24425,30579,40903 +51448,24426,30578,40153 +58104,24427,30577,40827 +59280,24428,30576,40154 +55838,24429,30575,40759 +50864,24430,30574,40917 +51241,24431,30573,40278 +58534,24432,30572,40678 +55422,24433,30571,40359 +53218,24434,30570,40999 +50606,24435,30569,40930 +54731,24436,30568,40634 +54707,24437,30567,40654 +56065,24438,30566,40941 +58489,24439,30565,40393 +58114,24440,30564,40019 +51385,24441,30563,40133 +54886,24442,30562,40667 +53600,24443,30561,40988 +55861,24444,30560,40223 +50127,24445,30559,40344 +58537,24446,30558,40988 +54876,24447,30557,40992 +59310,24448,30556,40920 +54485,24449,30555,40779 +55557,24450,30554,40781 +52533,24451,30553,40146 +54024,24452,30552,40904 +59710,24453,30551,40446 +50024,24454,30550,40246 +52102,24455,30549,40166 +58114,24456,30548,40092 +57119,24457,30547,40322 +53840,24458,30546,40466 +57806,24459,30545,40777 +56779,24460,30544,40891 +52974,24461,30543,40675 +53070,24462,30542,40891 +57549,24463,30541,40388 +50710,24464,30540,40678 +57987,24465,30539,40782 +51974,24466,30538,40913 +55634,24467,30537,40353 +59208,24468,30536,40511 +58953,24469,30535,40138 +55901,24470,30534,40194 +53971,24471,30533,40173 +52628,24472,30532,40132 +50493,24473,30531,40256 +53257,24474,30530,40304 +52117,24475,30529,40790 +58789,24476,30528,40858 +55246,24477,30527,40637 +50372,24478,30526,40976 +55199,24479,30525,40061 +57268,24480,30524,40236 +50395,24481,30523,40333 +55257,24482,30522,40223 +57339,24483,30521,40219 +51373,24484,30520,40251 +50216,24485,30519,40999 +50437,24486,30518,40885 +59685,24487,30517,40429 +57343,24488,30516,40093 +56248,24489,30515,40685 +52663,24490,30514,40035 +55849,24491,30513,40137 +59800,24492,30512,40000 +56995,24493,30511,40482 +56335,24494,30510,40398 +58712,24495,30509,40527 +51100,24496,30508,40405 +53218,24497,30507,40052 +53954,24498,30506,40227 +50243,24499,30505,40099 +57918,24500,30504,40967 +50269,24501,30503,40713 +53908,24502,30502,40107 +58350,24503,30501,40815 +58820,24504,30500,40283 +51844,24505,30499,40931 +52284,24506,30498,40270 +56990,24507,30497,40403 +59175,24508,30496,40848 +58739,24509,30495,40422 +57571,24510,30494,40769 +54459,24511,30493,40231 +51136,24512,30492,40550 +51451,24513,30491,40046 +53748,24514,30490,40978 +53982,24515,30489,40581 +53276,24516,30488,40248 +57151,24517,30487,40900 +50317,24518,30486,40280 +51108,24519,30485,40889 +58505,24520,30484,40955 +56212,24521,30483,40999 +54316,24522,30482,40821 +54296,24523,30481,40578 +55430,24524,30480,40543 +52751,24525,30479,40581 +59091,24526,30478,40861 +55164,24527,30477,40600 +55334,24528,30476,40970 +59962,24529,30475,40681 +52308,24530,30474,40094 +53008,24531,30473,40765 +54573,24532,30472,40522 +57824,24533,30471,40948 +56261,24534,30470,40032 +51817,24535,30469,40766 +55888,24536,30468,40465 +53004,24537,30467,40806 +58573,24538,30466,40236 +50667,24539,30465,40505 +52329,24540,30464,40056 +54445,24541,30463,40059 +50884,24542,30462,40503 +53167,24543,30461,40102 +54033,24544,30460,40935 +51765,24545,30459,40552 +50246,24546,30458,40605 +55613,24547,30457,40288 +57268,24548,30456,40728 +55764,24549,30455,40236 +58784,24550,30454,40344 +59042,24551,30453,40739 +57392,24552,30452,40401 +57329,24553,30451,40954 +52321,24554,30450,40592 +59755,24555,30449,40109 +55205,24556,30448,40888 +59857,24557,30447,40819 +59674,24558,30446,40841 +55768,24559,30445,40870 +52517,24560,30444,40423 +53389,24561,30443,40990 +53534,24562,30442,40970 +51690,24563,30441,40210 +55717,24564,30440,40447 +54064,24565,30439,40914 +57442,24566,30438,40082 +57636,24567,30437,40667 +57242,24568,30436,40630 +52646,24569,30435,40880 +54510,24570,30434,40659 +52908,24571,30433,40689 +57437,24572,30432,40203 +59694,24573,30431,40523 +56745,24574,30430,40025 +52971,24575,30429,40564 +52023,24576,30428,40166 +52153,24577,30427,40129 +51216,24578,30426,40617 +53497,24579,30425,40814 +53861,24580,30424,40082 +54808,24581,30423,40880 +57935,24582,30422,40996 +57969,24583,30421,40171 +55828,24584,30420,40613 +56561,24585,30419,40540 +50534,24586,30418,40163 +57587,24587,30417,40394 +54453,24588,30416,40860 +51385,24589,30415,40293 +53781,24590,30414,40658 +50956,24591,30413,40746 +57242,24592,30412,40865 +57946,24593,30411,40195 +57407,24594,30410,40551 +58815,24595,30409,40328 +52454,24596,30408,40671 +53839,24597,30407,40508 +55482,24598,30406,40209 +50175,24599,30405,40654 +50993,24600,30404,40745 +58531,24601,30403,40169 +58685,24602,30402,40059 +59634,24603,30401,40115 +57889,24604,30400,40408 +57558,24605,30399,40135 +57473,24606,30398,40800 +57951,24607,30397,40967 +56866,24608,30396,40180 +58551,24609,30395,40313 +57520,24610,30394,40286 +55344,24611,30393,40276 +58319,24612,30392,40392 +51114,24613,30391,40032 +58009,24614,30390,40469 +56032,24615,30389,40128 +59509,24616,30388,40448 +57426,24617,30387,40237 +54441,24618,30386,40311 +52558,24619,30385,40800 +56326,24620,30384,40915 +54407,24621,30383,40763 +52962,24622,30382,40151 +59480,24623,30381,40884 +58739,24624,30380,40659 +51362,24625,30379,40647 +54311,24626,30378,40860 +50064,24627,30377,40975 +50257,24628,30376,40241 +54428,24629,30375,40273 +52590,24630,30374,40196 +58570,24631,30373,40574 +57845,24632,30372,40043 +50994,24633,30371,40467 +50892,24634,30370,40691 +58907,24635,30369,40598 +57127,24636,30368,40648 +59203,24637,30367,40958 +57932,24638,30366,40243 +57771,24639,30365,40159 +53458,24640,30364,40145 +59583,24641,30363,40881 +54504,24642,30362,40531 +54563,24643,30361,40421 +52274,24644,30360,40575 +56969,24645,30359,40732 +53597,24646,30358,40635 +59440,24647,30357,40099 +54052,24648,30356,40793 +52470,24649,30355,40758 +56203,24650,30354,40075 +58525,24651,30353,40360 +53913,24652,30352,40820 +58620,24653,30351,40628 +58371,24654,30350,40593 +56076,24655,30349,40796 +50946,24656,30348,40715 +53891,24657,30347,40507 +54294,24658,30346,40009 +53438,24659,30345,40985 +57109,24660,30344,40646 +51078,24661,30343,40955 +59516,24662,30342,40508 +50229,24663,30341,40819 +54358,24664,30340,40956 +51811,24665,30339,40067 +55322,24666,30338,40708 +53497,24667,30337,40386 +51614,24668,30336,40011 +58918,24669,30335,40817 +59322,24670,30334,40324 +58911,24671,30333,40429 +58056,24672,30332,40148 +56801,24673,30331,40393 +51911,24674,30330,40793 +57715,24675,30329,40783 +59086,24676,30328,40586 +56519,24677,30327,40635 +56989,24678,30326,40781 +55199,24679,30325,40171 +52767,24680,30324,40601 +56764,24681,30323,40703 +56013,24682,30322,40609 +53617,24683,30321,40825 +51500,24684,30320,40656 +52358,24685,30319,40521 +53782,24686,30318,40455 +59097,24687,30317,40480 +50902,24688,30316,40873 +55086,24689,30315,40159 +57981,24690,30314,40928 +54999,24691,30313,40796 +56081,24692,30312,40102 +51567,24693,30311,40791 +58005,24694,30310,40161 +50785,24695,30309,40311 +57124,24696,30308,40019 +53158,24697,30307,40708 +50087,24698,30306,40413 +54090,24699,30305,40313 +52150,24700,30304,40680 +54640,24701,30303,40408 +52123,24702,30302,40608 +54236,24703,30301,40657 +50242,24704,30300,40798 +58670,24705,30299,40241 +52141,24706,30298,40800 +55583,24707,30297,40195 +56467,24708,30296,40087 +58483,24709,30295,40053 +57960,24710,30294,40468 +57343,24711,30293,40762 +58184,24712,30292,40015 +54084,24713,30291,40479 +53421,24714,30290,40950 +55385,24715,30289,40860 +55809,24716,30288,40023 +53991,24717,30287,40810 +50349,24718,30286,40963 +55533,24719,30285,40507 +55103,24720,30284,40670 +54868,24721,30283,40298 +51098,24722,30282,40535 +58925,24723,30281,40000 +51527,24724,30280,40048 +50855,24725,30279,40600 +52394,24726,30278,40098 +51308,24727,30277,40856 +56095,24728,30276,40153 +55595,24729,30275,40764 +50355,24730,30274,40191 +52736,24731,30273,40801 +50560,24732,30272,40424 +55743,24733,30271,40082 +54544,24734,30270,40042 +56048,24735,30269,40490 +51218,24736,30268,40974 +55333,24737,30267,40072 +54697,24738,30266,40375 +54215,24739,30265,40368 +52722,24740,30264,40582 +53565,24741,30263,40499 +57182,24742,30262,40536 +54190,24743,30261,40549 +58942,24744,30260,40637 +53998,24745,30259,40839 +53229,24746,30258,40997 +50517,24747,30257,40921 +54487,24748,30256,40456 +50573,24749,30255,40662 +58615,24750,30254,40570 +57642,24751,30253,40875 +55133,24752,30252,40890 +57524,24753,30251,40581 +56271,24754,30250,40886 +56831,24755,30249,40262 +53606,24756,30248,40725 +52876,24757,30247,40244 +54826,24758,30246,40480 +53736,24759,30245,40310 +53288,24760,30244,40686 +50610,24761,30243,40124 +52527,24762,30242,40586 +57066,24763,30241,40898 +59994,24764,30240,40699 +53509,24765,30239,40008 +53639,24766,30238,40520 +54653,24767,30237,40673 +59350,24768,30236,40662 +58885,24769,30235,40366 +56270,24770,30234,40863 +56059,24771,30233,40927 +56601,24772,30232,40104 +55350,24773,30231,40901 +55952,24774,30230,40968 +58286,24775,30229,40919 +52193,24776,30228,40120 +57162,24777,30227,40623 +50524,24778,30226,40804 +58165,24779,30225,40679 +51053,24780,30224,40220 +56602,24781,30223,40078 +56036,24782,30222,40751 +50735,24783,30221,40161 +58673,24784,30220,40213 +59198,24785,30219,40184 +53962,24786,30218,40286 +51533,24787,30217,40222 +58063,24788,30216,40677 +59727,24789,30215,40188 +52324,24790,30214,40643 +57076,24791,30213,40171 +57933,24792,30212,40753 +51371,24793,30211,40155 +57305,24794,30210,40405 +55432,24795,30209,40109 +57093,24796,30208,40960 +57089,24797,30207,40610 +56402,24798,30206,40139 +57010,24799,30205,40046 +56640,24800,30204,40579 +52800,24801,30203,40629 +57001,24802,30202,40872 +54587,24803,30201,40168 +59018,24804,30200,40629 +57644,24805,30199,40379 +56012,24806,30198,40189 +52654,24807,30197,40774 +52321,24808,30196,40915 +53289,24809,30195,40062 +58394,24810,30194,40083 +52425,24811,30193,40319 +56981,24812,30192,40251 +53549,24813,30191,40369 +53524,24814,30190,40000 +52571,24815,30189,40261 +50473,24816,30188,40534 +59122,24817,30187,40626 +59741,24818,30186,40311 +53607,24819,30185,40295 +57984,24820,30184,40503 +50817,24821,30183,40143 +51946,24822,30182,40858 +50192,24823,30181,40445 +57008,24824,30180,40147 +53447,24825,30179,40050 +55699,24826,30178,40329 +54842,24827,30177,40490 +52354,24828,30176,40648 +50387,24829,30175,40255 +59999,24830,30174,40298 +55231,24831,30173,40640 +56095,24832,30172,40728 +52133,24833,30171,40491 +58747,24834,30170,40873 +53607,24835,30169,40618 +55668,24836,30168,40829 +55441,24837,30167,40932 +53811,24838,30166,40102 +53502,24839,30165,40915 +51518,24840,30164,40796 +51913,24841,30163,40757 +51959,24842,30162,40332 +50193,24843,30161,40137 +57519,24844,30160,40660 +52198,24845,30159,40776 +58439,24846,30158,40037 +50144,24847,30157,40118 +53431,24848,30156,40789 +56224,24849,30155,40859 +51511,24850,30154,40281 +56974,24851,30153,40107 +50938,24852,30152,40356 +51984,24853,30151,40038 +56971,24854,30150,40414 +58892,24855,30149,40772 +57616,24856,30148,40299 +52788,24857,30147,40321 +53915,24858,30146,40838 +54273,24859,30145,40769 +55872,24860,30144,40618 +53499,24861,30143,40632 +50224,24862,30142,40718 +57876,24863,30141,40560 +57315,24864,30140,40659 +57476,24865,30139,40784 +50469,24866,30138,40715 +52895,24867,30137,40622 +58679,24868,30136,40071 +56787,24869,30135,40633 +57558,24870,30134,40804 +55598,24871,30133,40861 +51273,24872,30132,40668 +59484,24873,30131,40803 +53443,24874,30130,40389 +53581,24875,30129,40068 +53833,24876,30128,40560 +55893,24877,30127,40123 +50254,24878,30126,40751 +57374,24879,30125,40476 +57737,24880,30124,40156 +54888,24881,30123,40861 +54952,24882,30122,40219 +59984,24883,30121,40759 +57022,24884,30120,40699 +58238,24885,30119,40712 +58472,24886,30118,40254 +59592,24887,30117,40585 +52989,24888,30116,40954 +52868,24889,30115,40671 +57539,24890,30114,40939 +53483,24891,30113,40505 +52238,24892,30112,40951 +55881,24893,30111,40500 +50724,24894,30110,40182 +50401,24895,30109,40958 +52044,24896,30108,40380 +52526,24897,30107,40413 +56421,24898,30106,40453 +52852,24899,30105,40963 +52003,24900,30104,40996 +58276,24901,30103,40897 +52484,24902,30102,40503 +52206,24903,30101,40109 +59232,24904,30100,40626 +53713,24905,30099,40889 +50735,24906,30098,40910 +58782,24907,30097,40001 +53364,24908,30096,40502 +57403,24909,30095,40201 +53479,24910,30094,40758 +50883,24911,30093,40545 +56481,24912,30092,40993 +53386,24913,30091,40950 +58112,24914,30090,40797 +53774,24915,30089,40741 +56059,24916,30088,40981 +54826,24917,30087,40839 +50495,24918,30086,40587 +53764,24919,30085,40884 +51287,24920,30084,40863 +57190,24921,30083,40317 +58250,24922,30082,40329 +59098,24923,30081,40794 +59998,24924,30080,40911 +53262,24925,30079,40541 +56923,24926,30078,40267 +50983,24927,30077,40681 +56987,24928,30076,40213 +53377,24929,30075,40250 +57965,24930,30074,40688 +51956,24931,30073,40738 +58536,24932,30072,40987 +52387,24933,30071,40557 +53245,24934,30070,40054 +58638,24935,30069,40538 +57109,24936,30068,40231 +59784,24937,30067,40007 +59689,24938,30066,40344 +55715,24939,30065,40648 +56497,24940,30064,40367 +53046,24941,30063,40307 +58804,24942,30062,40338 +56816,24943,30061,40275 +59326,24944,30060,40572 +57815,24945,30059,40854 +57728,24946,30058,40417 +54233,24947,30057,40725 +51936,24948,30056,40978 +58964,24949,30055,40849 +55345,24950,30054,40997 +50593,24951,30053,40684 +51534,24952,30052,40100 +50954,24953,30051,40627 +56176,24954,30050,40240 +53356,24955,30049,40958 +55535,24956,30048,40633 +50872,24957,30047,40688 +51669,24958,30046,40909 +59956,24959,30045,40778 +54830,24960,30044,40572 +53455,24961,30043,40591 +59932,24962,30042,40164 +58785,24963,30041,40803 +59095,24964,30040,40573 +51152,24965,30039,40493 +51953,24966,30038,40114 +55903,24967,30037,40086 +56663,24968,30036,40154 +55585,24969,30035,40964 +55459,24970,30034,40819 +57771,24971,30033,40864 +57790,24972,30032,40571 +55032,24973,30031,40744 +58788,24974,30030,40058 +59382,24975,30029,40442 +50880,24976,30028,40495 +58701,24977,30027,40855 +53750,24978,30026,40733 +58528,24979,30025,40055 +52575,24980,30024,40937 +56380,24981,30023,40790 +59647,24982,30022,40467 +50541,24983,30021,40914 +51538,24984,30020,40167 +56336,24985,30019,40672 +55733,24986,30018,40127 +56611,24987,30017,40251 +59890,24988,30016,40854 +50297,24989,30015,40512 +55443,24990,30014,40364 +55706,24991,30013,40264 +56183,24992,30012,40833 +53686,24993,30011,40171 +56962,24994,30010,40984 +52106,24995,30009,40117 +55006,24996,30008,40074 +58027,24997,30007,40288 +54288,24998,30006,40387 +53248,24999,30005,40030 +53894,25000,30004,40925 +50684,25001,30003,40329 +56620,25002,30002,40054 +57880,25003,30001,40050 +56365,25004,30000,40945 +57407,25005,31000,40946 +56231,25006,30999,40591 +57603,25007,30998,40751 +59847,25008,30997,40295 +50414,25009,30996,40670 +56675,25010,30995,40209 +53491,25011,30994,40906 +57031,25012,30993,40043 +52162,25013,30992,40263 +51447,25014,30991,40782 +50778,25015,30990,40686 +52004,25016,30989,40192 +51384,25017,30988,40397 +55210,25018,30987,40342 +58846,25019,30986,40841 +56229,25020,30985,40718 +50880,25021,30984,40259 +55715,25022,30983,40247 +50519,25023,30982,40564 +52421,25024,30981,40757 +57368,25025,30980,40742 +55343,25026,30979,40797 +59311,25027,30978,40313 +56207,25028,30977,40881 +51620,25029,30976,40743 +55578,25030,30975,40008 +54576,25031,30974,40437 +54146,25032,30973,40285 +57033,25033,30972,40710 +54676,25034,30971,40130 +58185,25035,30970,40053 +54365,25036,30969,40418 +52925,25037,30968,40742 +58045,25038,30967,40104 +50281,25039,30966,40850 +56387,25040,30965,40983 +59593,25041,30964,40838 +51064,25042,30963,40414 +58434,25043,30962,40303 +58104,25044,30961,40439 +54534,25045,30960,40508 +58107,25046,30959,40725 +59623,25047,30958,40423 +58979,25048,30957,40864 +59827,25049,30956,40585 +50781,25050,30955,40295 +57517,25051,30954,40049 +52137,25052,30953,40792 +56636,25053,30952,40169 +50743,25054,30951,40374 +55469,25055,30950,40694 +51207,25056,30949,40176 +52292,25057,30948,40322 +57523,25058,30947,40666 +57392,25059,30946,40919 +58361,25060,30945,40227 +50204,25061,30944,40945 +54271,25062,30943,40674 +53761,25063,30942,40321 +55419,25064,30941,40637 +50585,25065,30940,40226 +51771,25066,30939,40759 +59822,25067,30938,40986 +55518,25068,30937,40253 +54465,25069,30936,40607 +57334,25070,30935,40662 +53623,25071,30934,40203 +59573,25072,30933,40117 +55438,25073,30932,40365 +55636,25074,30931,40156 +59005,25075,30930,40509 +56803,25076,30929,40519 +58473,25077,30928,40868 +51578,25078,30927,40841 +56500,25079,30926,40902 +57086,25080,30925,40743 +57327,25081,30924,40205 +52512,25082,30923,40352 +59136,25083,30922,40091 +52559,25084,30921,40997 +54895,25085,30920,40291 +53453,25086,30919,40571 +59035,25087,30918,40173 +57519,25088,30917,40833 +54602,25089,30916,40237 +58478,25090,30915,40544 +59549,25091,30914,40158 +51835,25092,30913,40935 +51857,25093,30912,40312 +56192,25094,30911,40088 +57346,25095,30910,40618 +58001,25096,30909,40755 +55706,25097,30908,40374 +57553,25098,30907,40284 +56184,25099,30906,40361 +59072,25100,30905,40371 +56427,25101,30904,40563 +52610,25102,30903,40441 +54381,25103,30902,40929 +57387,25104,30901,40986 +57261,25105,30900,40932 +50503,25106,30899,40955 +50068,25107,30898,40573 +58534,25108,30897,40416 +56713,25109,30896,40056 +58116,25110,30895,40922 +51857,25111,30894,40202 +50151,25112,30893,40780 +53934,25113,30892,40313 +52897,25114,30891,40121 +58936,25115,30890,40791 +58374,25116,30889,40740 +57737,25117,30888,40321 +52599,25118,30887,40332 +58401,25119,30886,40146 +52877,25120,30885,40305 +59098,25121,30884,40551 +52049,25122,30883,40319 +52582,25123,30882,40887 +55239,25124,30881,40422 +57157,25125,30880,40481 +55243,25126,30879,40027 +56275,25127,30878,40826 +55956,25128,30877,40407 +57678,25129,30876,40857 +59526,25130,30875,40482 +50869,25131,30874,40321 +55588,25132,30873,40708 +55275,25133,30872,40843 +56289,25134,30871,40840 +56603,25135,30870,40556 +59655,25136,30869,40693 +55654,25137,30868,40778 +51665,25138,30867,40538 +53144,25139,30866,40375 +58451,25140,30865,40181 +56136,25141,30864,40384 +50793,25142,30863,40944 +58942,25143,30862,40981 +52605,25144,30861,40400 +55807,25145,30860,40460 +56450,25146,30859,40180 +56979,25147,30858,40908 +51294,25148,30857,40374 +56104,25149,30856,40299 +56580,25150,30855,40161 +57071,25151,30854,40764 +59951,25152,30853,40664 +53156,25153,30852,40289 +50075,25154,30851,40054 +53436,25155,30850,40273 +51628,25156,30849,40272 +53847,25157,30848,40887 +50434,25158,30847,40203 +53124,25159,30846,40735 +51285,25160,30845,40363 +55284,25161,30844,40684 +53626,25162,30843,40033 +51014,25163,30842,40011 +53640,25164,30841,40008 +51810,25165,30840,40214 +56676,25166,30839,40044 +59297,25167,30838,40278 +58104,25168,30837,40863 +52809,25169,30836,40024 +52898,25170,30835,40657 +50167,25171,30834,40514 +58648,25172,30833,40740 +59653,25173,30832,40907 +55626,25174,30831,40266 +52843,25175,30830,40188 +54640,25176,30829,40843 +51377,25177,30828,40775 +51010,25178,30827,40526 +53299,25179,30826,40618 +57783,25180,30825,40859 +56717,25181,30824,40160 +55476,25182,30823,40819 +59878,25183,30822,40373 +50918,25184,30821,40869 +57913,25185,30820,40331 +55963,25186,30819,40214 +55709,25187,30818,40261 +51163,25188,30817,40652 +58647,25189,30816,40120 +54756,25190,30815,40855 +59302,25191,30814,40657 +54530,25192,30813,40365 +59724,25193,30812,40823 +55454,25194,30811,40496 +51532,25195,30810,40630 +51085,25196,30809,40470 +57182,25197,30808,40629 +52746,25198,30807,40196 +51360,25199,30806,40933 +54638,25200,30805,40015 +53623,25201,30804,40382 +54778,25202,30803,40002 +50995,25203,30802,40479 +59799,25204,30801,40893 +58064,25205,30800,40778 +59557,25206,30799,40504 +51256,25207,30798,40874 +59088,25208,30797,40124 +57478,25209,30796,40249 +50097,25210,30795,40546 +54886,25211,30794,40371 +52129,25212,30793,40690 +50713,25213,30792,40369 +54936,25214,30791,40018 +55124,25215,30790,40178 +55651,25216,30789,40665 +59415,25217,30788,40460 +52003,25218,30787,40431 +54379,25219,30786,40779 +51842,25220,30785,40883 +52805,25221,30784,40028 +56737,25222,30783,40144 +53159,25223,30782,40393 +54413,25224,30781,40317 +59846,25225,30780,40530 +54432,25226,30779,40608 +53910,25227,30778,40275 +58996,25228,30777,40494 +59697,25229,30776,40023 +52546,25230,30775,40137 +54710,25231,30774,40497 +55113,25232,30773,40335 +52430,25233,30772,40355 +52858,25234,30771,40483 +51691,25235,30770,40006 +52879,25236,30769,40458 +59177,25237,30768,40972 +56524,25238,30767,40556 +54534,25239,30766,40781 +58398,25240,30765,40908 +51102,25241,30764,40292 +50511,25242,30763,40174 +59950,25243,30762,40245 +51372,25244,30761,40740 +51434,25245,30760,40997 +56382,25246,30759,40902 +56827,25247,30758,40558 +55540,25248,30757,40388 +53520,25249,30756,40494 +52050,25250,30755,40960 +57781,25251,30754,40563 +53043,25252,30753,40861 +59377,25253,30752,40205 +50201,25254,30751,40214 +52665,25255,30750,40407 +54725,25256,30749,40196 +57474,25257,30748,40067 +59698,25258,30747,40728 +53220,25259,30746,40578 +57452,25260,30745,40025 +56297,25261,30744,40677 +56158,25262,30743,40403 +53749,25263,30742,40428 +53081,25264,30741,40165 +56880,25265,30740,40776 +54992,25266,30739,40028 +59263,25267,30738,40070 +54512,25268,30737,40137 +59728,25269,30736,40762 +53613,25270,30735,40939 +50980,25271,30734,40213 +50632,25272,30733,40531 +51815,25273,30732,40189 +57453,25274,30731,40443 +59434,25275,30730,40872 +51016,25276,30729,40009 +50434,25277,30728,40421 +54487,25278,30727,40214 +50569,25279,30726,40199 +55403,25280,30725,40741 +56979,25281,30724,40446 +59720,25282,30723,40106 +56859,25283,30722,40004 +59964,25284,30721,40505 +56955,25285,30720,40313 +50476,25286,30719,40760 +51691,25287,30718,40139 +51322,25288,30717,40354 +55408,25289,30716,40213 +53251,25290,30715,40369 +51446,25291,30714,40555 +56837,25292,30713,40063 +57544,25293,30712,40951 +54973,25294,30711,40193 +50316,25295,30710,40027 +59854,25296,30709,40065 +52716,25297,30708,40420 +52158,25298,30707,40694 +59071,25299,30706,40776 +52282,25300,30705,40730 +52678,25301,30704,40212 +58138,25302,30703,40704 +56833,25303,30702,40219 +55440,25304,30701,40104 +51698,25305,30700,40135 +53945,25306,30699,40120 +59450,25307,30698,40677 +59078,25308,30697,40640 +57904,25309,30696,40225 +53796,25310,30695,40010 +55680,25311,30694,40693 +56295,25312,30693,40429 +51456,25313,30692,40487 +50197,25314,30691,40317 +58973,25315,30690,40446 +53455,25316,30689,40064 +55124,25317,30688,40696 +55851,25318,30687,40271 +50860,25319,30686,40652 +52604,25320,30685,40199 +51745,25321,30684,40614 +58611,25322,30683,40467 +58076,25323,30682,40237 +52623,25324,30681,40424 +57277,25325,30680,40765 +56479,25326,30679,40788 +54971,25327,30678,40969 +58313,25328,30677,40724 +52306,25329,30676,40833 +53955,25330,30675,40985 +55979,25331,30674,40875 +55550,25332,30673,40590 +51769,25333,30672,40937 +59138,25334,30671,40185 +58927,25335,30670,40927 +51060,25336,30669,40715 +57824,25337,30668,40216 +53189,25338,30667,40134 +55566,25339,30666,40324 +53620,25340,30665,40498 +50500,25341,30664,40888 +50724,25342,30663,40300 +52911,25343,30662,40986 +56536,25344,30661,40459 +56439,25345,30660,40630 +56602,25346,30659,40432 +55323,25347,30658,40802 +54523,25348,30657,40737 +50010,25349,30656,40179 +50196,25350,30655,40066 +50254,25351,30654,40418 +58331,25352,30653,40378 +54291,25353,30652,40599 +52146,25354,30651,40325 +54438,25355,30650,40288 +52138,25356,30649,40947 +53064,25357,30648,40566 +52661,25358,30647,40044 +50130,25359,30646,40244 +57496,25360,30645,40542 +53954,25361,30644,40004 +56783,25362,30643,40029 +57107,25363,30642,40072 +51642,25364,30641,40005 +52539,25365,30640,40666 +54517,25366,30639,40791 +58253,25367,30638,40201 +57526,25368,30637,40006 +51183,25369,30636,40968 +54399,25370,30635,40981 +52471,25371,30634,40781 +57684,25372,30633,40062 +55486,25373,30632,40699 +51062,25374,30631,40521 +53030,25375,30630,40252 +57294,25376,30629,40600 +54136,25377,30628,40462 +59029,25378,30627,40900 +52934,25379,30626,40432 +54096,25380,30625,40749 +58863,25381,30624,40962 +59897,25382,30623,40714 +52897,25383,30622,40087 +52872,25384,30621,40691 +51304,25385,30620,40824 +57201,25386,30619,40472 +53284,25387,30618,40757 +54006,25388,30617,40857 +53097,25389,30616,40634 +50253,25390,30615,40040 +56817,25391,30614,40397 +53645,25392,30613,40422 +54956,25393,30612,40488 +58338,25394,30611,40185 +56695,25395,30610,40479 +53088,25396,30609,40423 +59642,25397,30608,40935 +57075,25398,30607,40641 +50796,25399,30606,40560 +51845,25400,30605,40543 +56529,25401,30604,40785 +59689,25402,30603,40972 +55491,25403,30602,40535 +56885,25404,30601,40718 +58494,25405,30600,40969 +52044,25406,30599,40420 +58085,25407,30598,40579 +57193,25408,30597,40748 +55155,25409,30596,40469 +53688,25410,30595,40552 +51196,25411,30594,40880 +53950,25412,30593,40444 +55538,25413,30592,40780 +50057,25414,30591,40599 +50227,25415,30590,40849 +56657,25416,30589,40340 +51247,25417,30588,40552 +56302,25418,30587,40076 +55895,25419,30586,40628 +59316,25420,30585,40961 +56705,25421,30584,40411 +55433,25422,30583,40289 +55032,25423,30582,40651 +54855,25424,30581,40717 +52736,25425,30580,40787 +54908,25426,30579,40341 +54328,25427,30578,40335 +51038,25428,30577,40363 +56856,25429,30576,40711 +59821,25430,30575,40768 +57514,25431,30574,40901 +57617,25432,30573,40870 +52181,25433,30572,40345 +57138,25434,30571,40932 +52212,25435,30570,40946 +56983,25436,30569,40287 +58549,25437,30568,40235 +53430,25438,30567,40699 +58173,25439,30566,40856 +53369,25440,30565,40022 +50632,25441,30564,40124 +54706,25442,30563,40589 +51087,25443,30562,40577 +57349,25444,30561,40646 +54195,25445,30560,40682 +51492,25446,30559,40456 +52005,25447,30558,40384 +50440,25448,30557,40715 +57240,25449,30556,40127 +50762,25450,30555,40328 +58078,25451,30554,40637 +53826,25452,30553,40188 +51182,25453,30552,40791 +59543,25454,30551,40967 +55975,25455,30550,40727 +52997,25456,30549,40011 +58783,25457,30548,40645 +55933,25458,30547,40347 +58789,25459,30546,40993 +50678,25460,30545,40817 +59876,25461,30544,40971 +51121,25462,30543,40636 +58760,25463,30542,40943 +55562,25464,30541,40821 +54395,25465,30540,40608 +54090,25466,30539,40100 +55688,25467,30538,40528 +57898,25468,30537,40796 +53185,25469,30536,40777 +57746,25470,30535,40367 +52764,25471,30534,40035 +57903,25472,30533,40959 +53384,25473,30532,40098 +58610,25474,30531,40347 +54477,25475,30530,40755 +58149,25476,30529,40522 +51202,25477,30528,40716 +50522,25478,30527,40822 +53480,25479,30526,40941 +50332,25480,30525,40176 +58643,25481,30524,40783 +54710,25482,30523,40981 +58968,25483,30522,40759 +59202,25484,30521,40794 +55074,25485,30520,40926 +54793,25486,30519,40649 +58831,25487,30518,40736 +50201,25488,30517,40183 +56200,25489,30516,40728 +50294,25490,30515,40777 +58237,25491,30514,40812 +57415,25492,30513,40987 +50030,25493,30512,40498 +59953,25494,30511,40516 +58791,25495,30510,40887 +51441,25496,30509,40273 +52643,25497,30508,40255 +52050,25498,30507,40821 +55185,25499,30506,40471 +54046,25500,30505,40714 +50708,25501,30504,40162 +51441,25502,30503,40863 +53764,25503,30502,40195 +57993,25504,30501,40318 +59154,25505,30500,40872 +59850,25506,30499,40289 +54232,25507,30498,40032 +55151,25508,30497,40064 +55119,25509,30496,40881 +58731,25510,30495,40041 +57242,25511,30494,40920 +53885,25512,30493,40260 +59088,25513,30492,40582 +51921,25514,30491,40258 +58983,25515,30490,40443 +55154,25516,30489,40890 +56828,25517,30488,40345 +58030,25518,30487,40607 +55631,25519,30486,40528 +55299,25520,30485,40906 +54522,25521,30484,40265 +50933,25522,30483,40599 +55762,25523,30482,40322 +53169,25524,30481,40854 +50663,25525,30480,40933 +57467,25526,30479,40833 +57542,25527,30478,40221 +50164,25528,30477,40645 +59453,25529,30476,40910 +56264,25530,30475,40863 +55806,25531,30474,40863 +57347,25532,30473,40364 +52541,25533,30472,40479 +58708,25534,30471,40636 +53251,25535,30470,40633 +58681,25536,30469,40917 +51349,25537,30468,40070 +50746,25538,30467,40952 +51695,25539,30466,40790 +51954,25540,30465,40185 +50426,25541,30464,40586 +56343,25542,30463,40888 +56685,25543,30462,40721 +59659,25544,30461,40687 +54479,25545,30460,40052 +56267,25546,30459,40216 +54906,25547,30458,40920 +59796,25548,30457,40125 +54363,25549,30456,40520 +56502,25550,30455,40779 +58102,25551,30454,40053 +52129,25552,30453,40403 +56391,25553,30452,40971 +52972,25554,30451,40414 +56915,25555,30450,40584 +54388,25556,30449,40453 +51725,25557,30448,40804 +54065,25558,30447,40011 +52372,25559,30446,40904 +57301,25560,30445,40231 +59274,25561,30444,40516 +57981,25562,30443,40577 +54575,25563,30442,40873 +50330,25564,30441,40280 +59196,25565,30440,40408 +59865,25566,30439,40390 +51067,25567,30438,40749 +53086,25568,30437,40497 +57763,25569,30436,40947 +56944,25570,30435,40927 +56850,25571,30434,40533 +54205,25572,30433,40373 +51219,25573,30432,40183 +54750,25574,30431,40756 +52384,25575,30430,40799 +52422,25576,30429,40393 +58257,25577,30428,40307 +56724,25578,30427,40479 +58721,25579,30426,40727 +52663,25580,30425,40330 +58385,25581,30424,40515 +54401,25582,30423,40587 +53414,25583,30422,40535 +51460,25584,30421,40011 +58654,25585,30420,40860 +54618,25586,30419,40942 +58848,25587,30418,40889 +56513,25588,30417,40502 +52577,25589,30416,40934 +51842,25590,30415,40993 +52483,25591,30414,40761 +57842,25592,30413,40520 +51080,25593,30412,40218 +54914,25594,30411,40508 +52020,25595,30410,40605 +59201,25596,30409,40439 +58913,25597,30408,40388 +56194,25598,30407,40836 +53435,25599,30406,40606 +53304,25600,30405,40093 +58075,25601,30404,40552 +56493,25602,30403,40111 +54802,25603,30402,40151 +55746,25604,30401,40908 +54875,25605,30400,40839 +55361,25606,30399,40396 +52915,25607,30398,40394 +58190,25608,30397,40417 +51220,25609,30396,40552 +58700,25610,30395,40478 +53708,25611,30394,40376 +50540,25612,30393,40674 +55533,25613,30392,40489 +57615,25614,30391,40975 +59198,25615,30390,40423 +57469,25616,30389,40706 +59103,25617,30388,40285 +58990,25618,30387,40087 +53322,25619,30386,40235 +57462,25620,30385,40962 +51108,25621,30384,40468 +53486,25622,30383,40619 +52610,25623,30382,40079 +50349,25624,30381,40599 +59065,25625,30380,40024 +54374,25626,30379,40616 +54542,25627,30378,40459 +59594,25628,30377,40505 +53692,25629,30376,40052 +59198,25630,30375,40471 +56963,25631,30374,40405 +57879,25632,30373,40479 +50509,25633,30372,40333 +50770,25634,30371,40976 +55997,25635,30370,40201 +53088,25636,30369,40341 +52977,25637,30368,40250 +55710,25638,30367,40338 +50230,25639,30366,40764 +56659,25640,30365,40999 +55914,25641,30364,40334 +57219,25642,30363,40606 +53212,25643,30362,40754 +53249,25644,30361,40245 +58928,25645,30360,40058 +53985,25646,30359,40521 +52062,25647,30358,40677 +57834,25648,30357,40303 +56698,25649,30356,40341 +50507,25650,30355,40600 +54959,25651,30354,40902 +52981,25652,30353,40792 +54709,25653,30352,40398 +57493,25654,30351,40323 +51025,25655,30350,40179 +54837,25656,30349,40701 +56123,25657,30348,40157 +59208,25658,30347,40356 +50523,25659,30346,40698 +58756,25660,30345,40765 +58813,25661,30344,40271 +58077,25662,30343,40799 +51796,25663,30342,40458 +51819,25664,30341,40895 +54810,25665,30340,40473 +59021,25666,30339,40937 +50884,25667,30338,40838 +51623,25668,30337,40945 +55988,25669,30336,40154 +51079,25670,30335,40099 +50537,25671,30334,40674 +50774,25672,30333,40645 +58274,25673,30332,40867 +57369,25674,30331,40742 +53967,25675,30330,40030 +59415,25676,30329,40971 +51384,25677,30328,40680 +56229,25678,30327,40582 +59847,25679,30326,40432 +54749,25680,30325,40403 +50944,25681,30324,40613 +59342,25682,30323,40377 +50545,25683,30322,40116 +52892,25684,30321,40921 +51220,25685,30320,40651 +56056,25686,30319,40919 +50465,25687,30318,40597 +52394,25688,30317,40842 +53664,25689,30316,40842 +56410,25690,30315,40193 +59117,25691,30314,40746 +50415,25692,30313,40315 +53396,25693,30312,40767 +57295,25694,30311,40579 +56492,25695,30310,40836 +59541,25696,30309,40087 +58960,25697,30308,40437 +51936,25698,30307,40803 +58312,25699,30306,40324 +51927,25700,30305,40311 +58710,25701,30304,40341 +57835,25702,30303,40730 +56908,25703,30302,40871 +59221,25704,30301,40857 +51948,25705,30300,40456 +59311,25706,30299,40767 +59527,25707,30298,40467 +56783,25708,30297,40379 +54134,25709,30296,40480 +55789,25710,30295,40481 +55607,25711,30294,40985 +54133,25712,30293,40118 +58527,25713,30292,40813 +50584,25714,30291,40484 +50990,25715,30290,40379 +56381,25716,30289,40349 +58081,25717,30288,40908 +51285,25718,30287,40591 +56192,25719,30286,40364 +50300,25720,30285,40725 +52327,25721,30284,40943 +51227,25722,30283,40446 +53586,25723,30282,40581 +56907,25724,30281,40877 +56338,25725,30280,40681 +51284,25726,30279,40932 +56652,25727,30278,40580 +53059,25728,30277,40493 +58449,25729,30276,40016 +52602,25730,30275,40614 +58360,25731,30274,40596 +59553,25732,30273,40624 +57590,25733,30272,40756 +51466,25734,30271,40957 +56576,25735,30270,40745 +50530,25736,30269,40211 +56360,25737,30268,40708 +53252,25738,30267,40673 +52579,25739,30266,40506 +52631,25740,30265,40045 +53627,25741,30264,40877 +55816,25742,30263,40344 +50752,25743,30262,40224 +54818,25744,30261,40839 +58169,25745,30260,40460 +51465,25746,30259,40087 +55160,25747,30258,40371 +55607,25748,30257,40827 +55100,25749,30256,40512 +51278,25750,30255,40749 +53216,25751,30254,40425 +50764,25752,30253,40319 +58208,25753,30252,40755 +53948,25754,30251,40924 +59212,25755,30250,40441 +57752,25756,30249,40689 +56805,25757,30248,40664 +54652,25758,30247,40409 +56213,25759,30246,40761 +51223,25760,30245,40521 +57515,25761,30244,40403 +50139,25762,30243,40673 +58915,25763,30242,40029 +56803,25764,30241,40787 +59893,25765,30240,40686 +50804,25766,30239,40140 +57124,25767,30238,40865 +58204,25768,30237,40324 +52854,25769,30236,40664 +58983,25770,30235,40956 +51139,25771,30234,40107 +53089,25772,30233,40418 +53014,25773,30232,40525 +52246,25774,30231,40348 +59088,25775,30230,40732 +59588,25776,30229,40383 +50844,25777,30228,40475 +57746,25778,30227,40898 +56366,25779,30226,40757 +54570,25780,30225,40436 +58133,25781,30224,40056 +52625,25782,30223,40183 +52655,25783,30222,40444 +50568,25784,30221,40583 +50812,25785,30220,40231 +58539,25786,30219,40651 +58458,25787,30218,40158 +59014,25788,30217,40855 +52943,25789,30216,40562 +55192,25790,30215,40979 +55062,25791,30214,40572 +52559,25792,30213,40156 +53072,25793,30212,40766 +59651,25794,30211,40509 +57627,25795,30210,40640 +51647,25796,30209,40522 +59185,25797,30208,40388 +54233,25798,30207,40600 +55607,25799,30206,40934 +54067,25800,30205,40452 +56342,25801,30204,40355 +53626,25802,30203,40735 +56343,25803,30202,40710 +59020,25804,30201,40906 +58070,25805,30200,40057 +58615,25806,30199,40276 +53545,25807,30198,40342 +55244,25808,30197,40453 +57402,25809,30196,40145 +55474,25810,30195,40286 +54368,25811,30194,40609 +59958,25812,30193,40200 +54620,25813,30192,40524 +52896,25814,30191,40565 +50655,25815,30190,40932 +52578,25816,30189,40870 +54745,25817,30188,40002 +54905,25818,30187,40026 +52460,25819,30186,40341 +52758,25820,30185,40120 +50543,25821,30184,40087 +54966,25822,30183,40458 +50398,25823,30182,40269 +51741,25824,30181,40702 +54943,25825,30180,40144 +54978,25826,30179,40970 +55712,25827,30178,40789 +54020,25828,30177,40667 +52683,25829,30176,40749 +59386,25830,30175,40449 +51163,25831,30174,40793 +58743,25832,30173,40227 +57865,25833,30172,40999 +52044,25834,30171,40138 +52223,25835,30170,40290 +51752,25836,30169,40469 +57677,25837,30168,40968 +59899,25838,30167,40513 +54746,25839,30166,40581 +55464,25840,30165,40794 +53314,25841,30164,40951 +56488,25842,30163,40947 +50046,25843,30162,40631 +51019,25844,30161,40726 +58146,25845,30160,40291 +58618,25846,30159,40208 +50223,25847,30158,40050 +58968,25848,30157,40772 +59497,25849,30156,40965 +55703,25850,30155,40730 +55314,25851,30154,40174 +50118,25852,30153,40092 +59925,25853,30152,40984 +56904,25854,30151,40781 +52527,25855,30150,40971 +53312,25856,30149,40030 +51608,25857,30148,40850 +57768,25858,30147,40879 +59024,25859,30146,40331 +59265,25860,30145,40750 +57620,25861,30144,40330 +52933,25862,30143,40039 +54063,25863,30142,40090 +55880,25864,30141,40784 +51709,25865,30140,40322 +52765,25866,30139,40839 +57211,25867,30138,40551 +55253,25868,30137,40530 +50746,25869,30136,40771 +53618,25870,30135,40611 +57795,25871,30134,40586 +53642,25872,30133,40182 +50820,25873,30132,40597 +59302,25874,30131,40081 +57464,25875,30130,40870 +50346,25876,30129,40111 +54853,25877,30128,40502 +54991,25878,30127,40256 +54799,25879,30126,40150 +51852,25880,30125,40401 +55658,25881,30124,40184 +51364,25882,30123,40595 +51981,25883,30122,40129 +54344,25884,30121,40323 +52785,25885,30120,40813 +52301,25886,30119,40613 +54392,25887,30118,40191 +56328,25888,30117,40093 +54155,25889,30116,40892 +51110,25890,30115,40492 +53692,25891,30114,40259 +52616,25892,30113,40820 +55002,25893,30112,40315 +58588,25894,30111,40969 +57443,25895,30110,40976 +50935,25896,30109,40027 +50612,25897,30108,40044 +53870,25898,30107,40964 +56555,25899,30106,40862 +54627,25900,30105,40042 +54878,25901,30104,40762 +57388,25902,30103,40753 +55380,25903,30102,40373 +59328,25904,30101,40456 +57392,25905,30100,40307 +54539,25906,30099,40295 +58479,25907,30098,40006 +51921,25908,30097,40290 +58071,25909,30096,40949 +55695,25910,30095,40860 +50847,25911,30094,40751 +54685,25912,30093,40412 +56526,25913,30092,40762 +53199,25914,30091,40092 +58859,25915,30090,40533 +52043,25916,30089,40580 +58195,25917,30088,40702 +54645,25918,30087,40682 +59194,25919,30086,40160 +55445,25920,30085,40883 +54664,25921,30084,40493 +56779,25922,30083,40979 +58069,25923,30082,40732 +56345,25924,30081,40189 +53215,25925,30080,40023 +54942,25926,30079,40711 +51831,25927,30078,40140 +51682,25928,30077,40230 +56589,25929,30076,40974 +54381,25930,30075,40809 +56592,25931,30074,40567 +56467,25932,30073,40684 +59575,25933,30072,40348 +53610,25934,30071,40260 +54493,25935,30070,40037 +57484,25936,30069,40633 +50519,25937,30068,40792 +51287,25938,30067,40957 +56625,25939,30066,40945 +51026,25940,30065,40824 +59255,25941,30064,40159 +55371,25942,30063,40845 +56080,25943,30062,40557 +57419,25944,30061,40405 +52500,25945,30060,40052 +58490,25946,30059,40790 +57166,25947,30058,40218 +51695,25948,30057,40695 +56684,25949,30056,40546 +56240,25950,30055,40323 +50803,25951,30054,40424 +54552,25952,30053,40639 +59280,25953,30052,40342 +58934,25954,30051,40514 +50185,25955,30050,40135 +56882,25956,30049,40032 +56306,25957,30048,40687 +59882,25958,30047,40147 +50460,25959,30046,40382 +57883,25960,30045,40470 +57015,25961,30044,40368 +57388,25962,30043,40223 +53576,25963,30042,40042 +56467,25964,30041,40937 +51318,25965,30040,40586 +58843,25966,30039,40171 +53247,25967,30038,40387 +58509,25968,30037,40761 +51639,25969,30036,40372 +58011,25970,30035,40221 +54496,25971,30034,40628 +53164,25972,30033,40129 +56197,25973,30032,40213 +56657,25974,30031,40819 +52928,25975,30030,40610 +54326,25976,30029,40181 +51804,25977,30028,40166 +50820,25978,30027,40201 +55332,25979,30026,40210 +56724,25980,30025,40550 +55354,25981,30024,40290 +53854,25982,30023,40881 +56852,25983,30022,40396 +56975,25984,30021,40522 +59361,25985,30020,40398 +50361,25986,30019,40121 +52474,25987,30018,40340 +57444,25988,30017,40366 +51299,25989,30016,40083 +57554,25990,30015,40955 +56560,25991,30014,40469 +58209,25992,30013,40414 +53637,25993,30012,40497 +50553,25994,30011,40494 +50597,25995,30010,40238 +57013,25996,30009,40217 +54956,25997,30008,40740 +51262,25998,30007,40223 +58472,25999,30006,40431 +52963,26000,30005,40615 +50050,26001,30004,40360 +58021,26002,30003,40549 +53915,26003,30002,40402 +50383,26004,30001,40972 +50385,26005,30000,40598 +50851,26006,31000,40901 +54001,26007,30999,40236 +59087,26008,30998,40260 +59414,26009,30997,40007 +50638,26010,30996,40764 +58799,26011,30995,40195 +55834,26012,30994,40615 +56495,26013,30993,40653 +56223,26014,30992,40243 +51918,26015,30991,40487 +55532,26016,30990,40348 +58141,26017,30989,40502 +58931,26018,30988,40298 +52807,26019,30987,40234 +57920,26020,30986,40823 +56418,26021,30985,40834 +50006,26022,30984,40679 +57797,26023,30983,40890 +51732,26024,30982,40516 +51412,26025,30981,40778 +53766,26026,30980,40557 +55526,26027,30979,40620 +52968,26028,30978,40475 +54248,26029,30977,40289 +57269,26030,30976,40312 +54362,26031,30975,40368 +54366,26032,30974,40972 +52311,26033,30973,40356 +53975,26034,30972,40325 +57026,26035,30971,40353 +50139,26036,30970,40050 +59739,26037,30969,40203 +57711,26038,30968,40364 +52913,26039,30967,40915 +58084,26040,30966,40610 +58658,26041,30965,40143 +51062,26042,30964,40631 +58702,26043,30963,40037 +50610,26044,30962,40946 +50874,26045,30961,40588 +52468,26046,30960,40250 +54192,26047,30959,40127 +59022,26048,30958,40788 +57347,26049,30957,40358 +51204,26050,30956,40731 +54688,26051,30955,40106 +58372,26052,30954,40746 +57520,26053,30953,40277 +53268,26054,30952,40352 +52554,26055,30951,40236 +52084,26056,30950,40033 +54757,26057,30949,40979 +51474,26058,30948,40413 +57051,26059,30947,40715 +58380,26060,30946,40344 +57785,26061,30945,40314 +54415,26062,30944,40645 +58244,26063,30943,40719 +57502,26064,30942,40128 +52437,26065,30941,40568 +51519,26066,30940,40094 +58293,26067,30939,40498 +54384,26068,30938,40195 +51444,26069,30937,40404 +56999,26070,30936,40592 +52386,26071,30935,40057 +55559,26072,30934,40750 +52912,26073,30933,40536 +52029,26074,30932,40308 +59841,26075,30931,40073 +53082,26076,30930,40312 +56411,26077,30929,40775 +53180,26078,30928,40406 +56842,26079,30927,40012 +51396,26080,30926,40523 +52035,26081,30925,40429 +55996,26082,30924,40396 +57413,26083,30923,40404 +59810,26084,30922,40792 +53547,26085,30921,40532 +56237,26086,30920,40918 +55374,26087,30919,40372 +54417,26088,30918,40108 +58216,26089,30917,40059 +55805,26090,30916,40510 +59860,26091,30915,40340 +50449,26092,30914,40079 +56769,26093,30913,40382 +52540,26094,30912,40271 +50101,26095,30911,40787 +59396,26096,30910,40106 +54078,26097,30909,40579 +52911,26098,30908,40696 +58228,26099,30907,40060 +50254,26100,30906,40366 +52858,26101,30905,40824 +56458,26102,30904,40784 +54195,26103,30903,40444 +52246,26104,30902,40249 +55377,26105,30901,40472 +56164,26106,30900,40777 +50376,26107,30899,40207 +54340,26108,30898,40009 +54114,26109,30897,40253 +50662,26110,30896,40982 +57451,26111,30895,40664 +53728,26112,30894,40080 +52685,26113,30893,40988 +59932,26114,30892,40102 +56198,26115,30891,40647 +51401,26116,30890,40256 +55733,26117,30889,40190 +59522,26118,30888,40145 +50483,26119,30887,40050 +51387,26120,30886,40847 +54526,26121,30885,40611 +52487,26122,30884,40575 +50737,26123,30883,40679 +54407,26124,30882,40770 +58287,26125,30881,40702 +55821,26126,30880,40222 +52063,26127,30879,40853 +57678,26128,30878,40890 +50769,26129,30877,40678 +56134,26130,30876,40091 +55455,26131,30875,40960 +55446,26132,30874,40260 +57935,26133,30873,40248 +58824,26134,30872,40797 +52740,26135,30871,40836 +50595,26136,30870,40002 +58004,26137,30869,40472 +57450,26138,30868,40910 +55140,26139,30867,40623 +55678,26140,30866,40813 +58575,26141,30865,40207 +57380,26142,30864,40275 +57558,26143,30863,40545 +51554,26144,30862,40348 +58209,26145,30861,40187 +51890,26146,30860,40113 +58755,26147,30859,40252 +54825,26148,30858,40443 +54876,26149,30857,40212 +55201,26150,30856,40872 +52697,26151,30855,40901 +55586,26152,30854,40575 +59814,26153,30853,40170 +51328,26154,30852,40937 +52739,26155,30851,40571 +59310,26156,30850,40158 +59380,26157,30849,40538 +54784,26158,30848,40049 +51506,26159,30847,40221 +51502,26160,30846,40866 +57103,26161,30845,40672 +53044,26162,30844,40558 +55911,26163,30843,40382 +53558,26164,30842,40308 +51841,26165,30841,40556 +54337,26166,30840,40726 +56821,26167,30839,40834 +59821,26168,30838,40610 +54984,26169,30837,40695 +57039,26170,30836,40364 +55395,26171,30835,40056 +50794,26172,30834,40619 +54914,26173,30833,40900 +58837,26174,30832,40405 +56616,26175,30831,40447 +54072,26176,30830,40647 +59871,26177,30829,40281 +52144,26178,30828,40812 +54541,26179,30827,40026 +52370,26180,30826,40873 +51426,26181,30825,40197 +58444,26182,30824,40691 +54526,26183,30823,40230 +59111,26184,30822,40854 +58079,26185,30821,40129 +58425,26186,30820,40180 +55000,26187,30819,40121 +51094,26188,30818,40678 +59438,26189,30817,40889 +50183,26190,30816,40609 +55068,26191,30815,40290 +59027,26192,30814,40224 +58102,26193,30813,40282 +55721,26194,30812,40105 +54842,26195,30811,40141 +56704,26196,30810,40463 +51906,26197,30809,40219 +56870,26198,30808,40164 +50438,26199,30807,40062 +59172,26200,30806,40073 +55263,26201,30805,40726 +59282,26202,30804,40219 +53031,26203,30803,40386 +51591,26204,30802,40515 +58267,26205,30801,40453 +59257,26206,30800,40747 +58770,26207,30799,40027 +51555,26208,30798,40416 +57879,26209,30797,40527 +53221,26210,30796,40208 +50322,26211,30795,40763 +54996,26212,30794,40473 +51878,26213,30793,40402 +58146,26214,30792,40372 +59859,26215,30791,40477 +58760,26216,30790,40452 +53627,26217,30789,40336 +52112,26218,30788,40823 +55090,26219,30787,40216 +56544,26220,30786,40392 +59742,26221,30785,40084 +57776,26222,30784,40662 +54526,26223,30783,40021 +56509,26224,30782,40524 +52215,26225,30781,40076 +54678,26226,30780,40734 +56074,26227,30779,40318 +50787,26228,30778,40725 +53121,26229,30777,40302 +50965,26230,30776,40663 +53688,26231,30775,40855 +57640,26232,30774,40398 +53256,26233,30773,40804 +58422,26234,30772,40051 +59438,26235,30771,40031 +59365,26236,30770,40063 +52555,26237,30769,40250 +52768,26238,30768,40742 +51477,26239,30767,40773 +59076,26240,30766,40760 +55370,26241,30765,40988 +50864,26242,30764,40773 +59492,26243,30763,40612 +51312,26244,30762,40204 +56088,26245,30761,40131 +59427,26246,30760,40121 +53833,26247,30759,40537 +53783,26248,30758,40585 +56425,26249,30757,40014 +56999,26250,30756,40323 +56048,26251,30755,40257 +58171,26252,30754,40612 +56741,26253,30753,40171 +52141,26254,30752,40183 +55337,26255,30751,40126 +53964,26256,30750,40335 +53459,26257,30749,40149 +58793,26258,30748,40131 +51238,26259,30747,40505 +51823,26260,30746,40749 +57262,26261,30745,40484 +59792,26262,30744,40166 +55385,26263,30743,40566 +58106,26264,30742,40474 +58723,26265,30741,40138 +58200,26266,30740,40747 +50586,26267,30739,40357 +59732,26268,30738,40725 +50032,26269,30737,40074 +56315,26270,30736,40613 +57615,26271,30735,40716 +53849,26272,30734,40662 +50471,26273,30733,40497 +59427,26274,30732,40362 +56754,26275,30731,40912 +59220,26276,30730,40946 +59144,26277,30729,40631 +50687,26278,30728,40778 +52798,26279,30727,40347 +52899,26280,30726,40364 +54602,26281,30725,40300 +51740,26282,30724,40223 +55154,26283,30723,40500 +50006,26284,30722,40260 +59762,26285,30721,40797 +50573,26286,30720,40844 +50683,26287,30719,40876 +57024,26288,30718,40209 +54345,26289,30717,40830 +52644,26290,30716,40352 +50861,26291,30715,40613 +53044,26292,30714,40904 +51161,26293,30713,40886 +59413,26294,30712,40946 +51195,26295,30711,40779 +57928,26296,30710,40444 +55664,26297,30709,40552 +53209,26298,30708,40644 +54074,26299,30707,40604 +53877,26300,30706,40029 +57292,26301,30705,40566 +57128,26302,30704,40057 +54178,26303,30703,40113 +59028,26304,30702,40356 +59277,26305,30701,40286 +52765,26306,30700,40640 +53724,26307,30699,40565 +58610,26308,30698,40074 +57798,26309,30697,40959 +54278,26310,30696,40497 +50612,26311,30695,40786 +52924,26312,30694,40270 +50684,26313,30693,40634 +55841,26314,30692,40516 +58200,26315,30691,40257 +54307,26316,30690,40061 +50708,26317,30689,40131 +56016,26318,30688,40743 +59142,26319,30687,40656 +55241,26320,30686,40554 +57145,26321,30685,40830 +59205,26322,30684,40694 +55425,26323,30683,40539 +57506,26324,30682,40645 +50355,26325,30681,40972 +59510,26326,30680,40858 +56317,26327,30679,40789 +55860,26328,30678,40461 +54832,26329,30677,40326 +53849,26330,30676,40629 +50622,26331,30675,40181 +56118,26332,30674,40880 +52046,26333,30673,40422 +53001,26334,30672,40674 +52557,26335,30671,40796 +50164,26336,30670,40303 +57982,26337,30669,40178 +54287,26338,30668,40823 +50034,26339,30667,40099 +50232,26340,30666,40637 +53219,26341,30665,40810 +57145,26342,30664,40979 +52186,26343,30663,40327 +54914,26344,30662,40014 +55920,26345,30661,40119 +52773,26346,30660,40434 +56434,26347,30659,40823 +51873,26348,30658,40330 +51709,26349,30657,40452 +50902,26350,30656,40814 +55961,26351,30655,40593 +54952,26352,30654,40081 +58643,26353,30653,40774 +52526,26354,30652,40253 +55570,26355,30651,40610 +58905,26356,30650,40510 +55530,26357,30649,40845 +54066,26358,30648,40160 +50847,26359,30647,40997 +53516,26360,30646,40237 +52689,26361,30645,40779 +50441,26362,30644,40047 +54710,26363,30643,40000 +50633,26364,30642,40486 +52838,26365,30641,40617 +50636,26366,30640,40831 +50816,26367,30639,40324 +51641,26368,30638,40210 +52265,26369,30637,40398 +52375,26370,30636,40926 +50756,26371,30635,40987 +53864,26372,30634,40403 +59245,26373,30633,40393 +55206,26374,30632,40171 +58896,26375,30631,40170 +54613,26376,30630,40189 +53751,26377,30629,40740 +50489,26378,30628,40984 +57248,26379,30627,40798 +56928,26380,30626,40689 +50284,26381,30625,40305 +50143,26382,30624,40625 +52548,26383,30623,40049 +53867,26384,30622,40854 +53223,26385,30621,40286 +54142,26386,30620,40565 +50382,26387,30619,40723 +51418,26388,30618,40552 +51648,26389,30617,40626 +53785,26390,30616,40585 +56993,26391,30615,40858 +55058,26392,30614,40563 +53045,26393,30613,40471 +54600,26394,30612,40329 +54243,26395,30611,40301 +58140,26396,30610,40551 +57652,26397,30609,40192 +53155,26398,30608,40681 +57691,26399,30607,40458 +53203,26400,30606,40715 +54766,26401,30605,40882 +53079,26402,30604,40925 +57443,26403,30603,40061 +55361,26404,30602,40507 +56966,26405,30601,40492 +51231,26406,30600,40967 +52198,26407,30599,40418 +58534,26408,30598,40011 +57840,26409,30597,40248 +53659,26410,30596,40751 +52002,26411,30595,40487 +50209,26412,30594,40083 +57058,26413,30593,40266 +58556,26414,30592,40026 +54167,26415,30591,40661 +53060,26416,30590,40619 +54853,26417,30589,40637 +58517,26418,30588,40749 +58486,26419,30587,40446 +55987,26420,30586,40870 +51620,26421,30585,40627 +50491,26422,30584,40640 +53555,26423,30583,40750 +51301,26424,30582,40800 +52299,26425,30581,40372 +58694,26426,30580,40725 +57603,26427,30579,40515 +54449,26428,30578,40618 +51673,26429,30577,40650 +59453,26430,30576,40199 +58446,26431,30575,40486 +57266,26432,30574,40578 +54542,26433,30573,40909 +51949,26434,30572,40998 +52909,26435,30571,40713 +52051,26436,30570,40085 +51149,26437,30569,40923 +52802,26438,30568,40840 +50732,26439,30567,40928 +59059,26440,30566,40791 +51834,26441,30565,40557 +57772,26442,30564,40423 +50297,26443,30563,40450 +53778,26444,30562,40567 +59917,26445,30561,40566 +56619,26446,30560,40406 +59362,26447,30559,40368 +50674,26448,30558,40854 +55645,26449,30557,40252 +51155,26450,30556,40213 +57339,26451,30555,40554 +58342,26452,30554,40566 +50901,26453,30553,40847 +51368,26454,30552,40147 +54965,26455,30551,40798 +50405,26456,30550,40516 +50195,26457,30549,40175 +51875,26458,30548,40753 +57848,26459,30547,40858 +58023,26460,30546,40551 +58787,26461,30545,40217 +57994,26462,30544,40915 +54345,26463,30543,40519 +53622,26464,30542,40313 +56359,26465,30541,40648 +53147,26466,30540,40391 +52212,26467,30539,40838 +59855,26468,30538,40987 +55698,26469,30537,40309 +58497,26470,30536,40373 +51299,26471,30535,40828 +53166,26472,30534,40154 +53815,26473,30533,40448 +55901,26474,30532,40415 +58803,26475,30531,40023 +54181,26476,30530,40902 +54494,26477,30529,40038 +59726,26478,30528,40880 +56774,26479,30527,40623 +57492,26480,30526,40151 +54256,26481,30525,40939 +58696,26482,30524,40679 +50603,26483,30523,40848 +59810,26484,30522,40096 +51237,26485,30521,40383 +54241,26486,30520,40418 +51240,26487,30519,40981 +59218,26488,30518,40742 +55133,26489,30517,40003 +59471,26490,30516,40109 +53344,26491,30515,40132 +56702,26492,30514,40000 +55635,26493,30513,40706 +53403,26494,30512,40178 +50333,26495,30511,40406 +56816,26496,30510,40726 +57387,26497,30509,40202 +57568,26498,30508,40544 +52902,26499,30507,40861 +50499,26500,30506,40987 +50149,26501,30505,40418 +58491,26502,30504,40007 +56841,26503,30503,40021 +52998,26504,30502,40684 +54230,26505,30501,40740 +59212,26506,30500,40111 +59122,26507,30499,40693 +58136,26508,30498,40112 +53798,26509,30497,40265 +50228,26510,30496,40662 +52737,26511,30495,40541 +53420,26512,30494,40632 +58028,26513,30493,40569 +57909,26514,30492,40465 +55624,26515,30491,40864 +58103,26516,30490,40766 +57892,26517,30489,40986 +57284,26518,30488,40039 +59658,26519,30487,40313 +58493,26520,30486,40199 +53913,26521,30485,40246 +50842,26522,30484,40298 +52029,26523,30483,40375 +50742,26524,30482,40291 +50346,26525,30481,40312 +52206,26526,30480,40775 +52680,26527,30479,40738 +57134,26528,30478,40489 +59256,26529,30477,40036 +50124,26530,30476,40491 +55125,26531,30475,40853 +54928,26532,30474,40917 +52358,26533,30473,40468 +58912,26534,30472,40397 +55600,26535,30471,40644 +52763,26536,30470,40316 +51224,26537,30469,40223 +55563,26538,30468,40481 +53845,26539,30467,40501 +50221,26540,30466,40956 +54164,26541,30465,40001 +50397,26542,30464,40129 +52629,26543,30463,40696 +53930,26544,30462,40142 +55923,26545,30461,40431 +59368,26546,30460,40875 +50865,26547,30459,40569 +56309,26548,30458,40486 +51568,26549,30457,40410 +55187,26550,30456,40743 +58429,26551,30455,40474 +53348,26552,30454,40671 +56167,26553,30453,40329 +55188,26554,30452,40360 +52926,26555,30451,40547 +58656,26556,30450,40536 +56647,26557,30449,40353 +51124,26558,30448,40608 +57548,26559,30447,40996 +56162,26560,30446,40803 +52928,26561,30445,40902 +58879,26562,30444,40334 +55456,26563,30443,40623 +59639,26564,30442,40763 +53173,26565,30441,40576 +58865,26566,30440,40689 +54566,26567,30439,40744 +55725,26568,30438,40163 +54043,26569,30437,40057 +52649,26570,30436,40675 +51772,26571,30435,40534 +54979,26572,30434,40963 +51175,26573,30433,40491 +59945,26574,30432,40024 +58529,26575,30431,40681 +58364,26576,30430,40964 +53428,26577,30429,40085 +50163,26578,30428,40662 +53318,26579,30427,40491 +59964,26580,30426,40152 +50298,26581,30425,40492 +58925,26582,30424,40733 +50192,26583,30423,40641 +55721,26584,30422,40109 +50519,26585,30421,40195 +58398,26586,30420,40622 +52227,26587,30419,40713 +50186,26588,30418,40296 +50778,26589,30417,40125 +51934,26590,30416,40246 +58696,26591,30415,40788 +51483,26592,30414,40844 +51634,26593,30413,40327 +54025,26594,30412,40345 +59767,26595,30411,40122 +57447,26596,30410,40018 +51891,26597,30409,40249 +55660,26598,30408,40048 +56813,26599,30407,40802 +51036,26600,30406,40728 +53840,26601,30405,40723 +57606,26602,30404,40174 +53911,26603,30403,40505 +50890,26604,30402,40077 +59329,26605,30401,40018 +57976,26606,30400,40988 +56853,26607,30399,40440 +51859,26608,30398,40072 +57311,26609,30397,40890 +51157,26610,30396,40754 +51415,26611,30395,40000 +53404,26612,30394,40933 +56707,26613,30393,40459 +58210,26614,30392,40079 +52915,26615,30391,40766 +58538,26616,30390,40481 +58954,26617,30389,40133 +52566,26618,30388,40013 +52988,26619,30387,40137 +54918,26620,30386,40099 +56483,26621,30385,40885 +57115,26622,30384,40672 +53276,26623,30383,40649 +59465,26624,30382,40195 +51214,26625,30381,40424 +54378,26626,30380,40861 +57946,26627,30379,40064 +58224,26628,30378,40501 +50862,26629,30377,40357 +50019,26630,30376,40117 +56772,26631,30375,40402 +59848,26632,30374,40500 +50664,26633,30373,40645 +54690,26634,30372,40025 +54166,26635,30371,40478 +56194,26636,30370,40865 +55185,26637,30369,40452 +57866,26638,30368,40293 +55137,26639,30367,40052 +51824,26640,30366,40667 +57764,26641,30365,40095 +55166,26642,30364,40375 +51557,26643,30363,40902 +58661,26644,30362,40469 +59017,26645,30361,40404 +54034,26646,30360,40566 +52518,26647,30359,40993 +58105,26648,30358,40701 +59390,26649,30357,40439 +51022,26650,30356,40637 +56682,26651,30355,40755 +50723,26652,30354,40097 +53746,26653,30353,40225 +52762,26654,30352,40007 +54072,26655,30351,40276 +50844,26656,30350,40121 +52180,26657,30349,40257 +53587,26658,30348,40794 +59530,26659,30347,40039 +50674,26660,30346,40234 +53720,26661,30345,40797 +56772,26662,30344,40014 +51147,26663,30343,40759 +57617,26664,30342,40455 +54321,26665,30341,40079 +54813,26666,30340,40293 +50810,26667,30339,40804 +50091,26668,30338,40343 +51560,26669,30337,40970 +50096,26670,30336,40490 +55141,26671,30335,40133 +54385,26672,30334,40668 +58627,26673,30333,40723 +59694,26674,30332,40596 +54606,26675,30331,40198 +50808,26676,30330,40280 +57438,26677,30329,40714 +50237,26678,30328,40865 +58297,26679,30327,40465 +52805,26680,30326,40647 +57285,26681,30325,40472 +56021,26682,30324,40205 +51067,26683,30323,40334 +55952,26684,30322,40001 +52903,26685,30321,40121 +54301,26686,30320,40194 +54412,26687,30319,40796 +52628,26688,30318,40286 +56340,26689,30317,40769 +57506,26690,30316,40815 +55653,26691,30315,40663 +51245,26692,30314,40546 +55456,26693,30313,40240 +54593,26694,30312,40260 +55202,26695,30311,40626 +56504,26696,30310,40768 +52253,26697,30309,40800 +55992,26698,30308,40233 +51697,26699,30307,40196 +59446,26700,30306,40305 +58036,26701,30305,40027 +58952,26702,30304,40436 +54161,26703,30303,40149 +56344,26704,30302,40068 +51356,26705,30301,40247 +52341,26706,30300,40745 +52484,26707,30299,40207 +51508,26708,30298,40845 +56049,26709,30297,40259 +55043,26710,30296,40905 +53724,26711,30295,40159 +59198,26712,30294,40919 +50030,26713,30293,40737 +58299,26714,30292,40382 +58977,26715,30291,40418 +57007,26716,30290,40859 +50610,26717,30289,40596 +58515,26718,30288,40787 +58584,26719,30287,40418 +55506,26720,30286,40385 +56223,26721,30285,40625 +52361,26722,30284,40693 +50157,26723,30283,40577 +55841,26724,30282,40612 +51525,26725,30281,40671 +54873,26726,30280,40662 +56314,26727,30279,40403 +52331,26728,30278,40440 +51275,26729,30277,40760 +55649,26730,30276,40270 +50269,26731,30275,40021 +50993,26732,30274,40021 +57798,26733,30273,40008 +53540,26734,30272,40946 +59013,26735,30271,40338 +59796,26736,30270,40195 +54368,26737,30269,40651 +59955,26738,30268,40080 +51893,26739,30267,40146 +57945,26740,30266,40188 +54658,26741,30265,40400 +53637,26742,30264,40926 +57344,26743,30263,40922 +54308,26744,30262,40391 +56729,26745,30261,40170 +52944,26746,30260,40559 +52602,26747,30259,40833 +52351,26748,30258,40929 +53076,26749,30257,40891 +59197,26750,30256,40807 +52221,26751,30255,40286 +57572,26752,30254,40803 +55283,26753,30253,40368 +51927,26754,30252,40540 +59713,26755,30251,40765 +52446,26756,30250,40489 +52458,26757,30249,40962 +51516,26758,30248,40765 +59377,26759,30247,40753 +53276,26760,30246,40183 +59163,26761,30245,40417 +57354,26762,30244,40588 +59885,26763,30243,40904 +50686,26764,30242,40043 +56319,26765,30241,40264 +59010,26766,30240,40405 +57410,26767,30239,40556 +55909,26768,30238,40296 +50589,26769,30237,40926 +57625,26770,30236,40311 +55443,26771,30235,40782 +54550,26772,30234,40023 +55217,26773,30233,40417 +57873,26774,30232,40559 +55395,26775,30231,40131 +59896,26776,30230,40781 +59014,26777,30229,40690 +51716,26778,30228,40617 +54104,26779,30227,40281 +58257,26780,30226,40217 +56556,26781,30225,40541 +59241,26782,30224,40121 +53593,26783,30223,40952 +56268,26784,30222,40660 +52802,26785,30221,40383 +57644,26786,30220,40731 +56752,26787,30219,40026 +50069,26788,30218,40481 +55724,26789,30217,40936 +58810,26790,30216,40801 +53129,26791,30215,40189 +52298,26792,30214,40924 +59037,26793,30213,40857 +53186,26794,30212,40987 +51648,26795,30211,40253 +54076,26796,30210,40085 +55550,26797,30209,40644 +50340,26798,30208,40301 +56471,26799,30207,40620 +54075,26800,30206,40276 +58629,26801,30205,40961 +59653,26802,30204,40510 +54493,26803,30203,40484 +50109,26804,30202,40323 +59150,26805,30201,40221 +55145,26806,30200,40525 +57239,26807,30199,40554 +57512,26808,30198,40329 +51701,26809,30197,40666 +59799,26810,30196,40116 +57130,26811,30195,40378 +50995,26812,30194,40883 +52409,26813,30193,40187 +59880,26814,30192,40655 +58526,26815,30191,40703 +56632,26816,30190,40347 +52267,26817,30189,40230 +56680,26818,30188,40979 +57772,26819,30187,40065 +50484,26820,30186,40347 +58524,26821,30185,40066 +57635,26822,30184,40425 +58193,26823,30183,40030 +57653,26824,30182,40224 +51010,26825,30181,40896 +57705,26826,30180,40946 +55976,26827,30179,40276 +52074,26828,30178,40345 +52546,26829,30177,40116 +57145,26830,30176,40194 +50387,26831,30175,40026 +58455,26832,30174,40806 +53095,26833,30173,40155 +55913,26834,30172,40406 +59395,26835,30171,40996 +55902,26836,30170,40243 +58297,26837,30169,40020 +50860,26838,30168,40480 +59803,26839,30167,40182 +56358,26840,30166,40900 +59895,26841,30165,40585 +52650,26842,30164,40991 +51952,26843,30163,40541 +58054,26844,30162,40257 +53069,26845,30161,40773 +51899,26846,30160,40057 +58107,26847,30159,40211 +58714,26848,30158,40105 +57150,26849,30157,40780 +52923,26850,30156,40428 +55380,26851,30155,40250 +57117,26852,30154,40792 +57834,26853,30153,40360 +52455,26854,30152,40086 +57113,26855,30151,40349 +59853,26856,30150,40842 +53800,26857,30149,40736 +58495,26858,30148,40361 +50485,26859,30147,40092 +53163,26860,30146,40511 +50893,26861,30145,40656 +54818,26862,30144,40891 +59944,26863,30143,40822 +57063,26864,30142,40535 +52995,26865,30141,40597 +50868,26866,30140,40463 +58629,26867,30139,40774 +50039,26868,30138,40397 +54067,26869,30137,40856 +53722,26870,30136,40183 +51183,26871,30135,40864 +54752,26872,30134,40942 +57946,26873,30133,40456 +55515,26874,30132,40923 +54346,26875,30131,40026 +57563,26876,30130,40760 +55271,26877,30129,40066 +56689,26878,30128,40745 +51776,26879,30127,40686 +52241,26880,30126,40325 +50299,26881,30125,40730 +57814,26882,30124,40197 +50185,26883,30123,40172 +50495,26884,30122,40847 +56775,26885,30121,40993 +57463,26886,30120,40583 +50577,26887,30119,40402 +58594,26888,30118,40331 +51857,26889,30117,40934 +50196,26890,30116,40786 +57845,26891,30115,40165 +59084,26892,30114,40264 +57631,26893,30113,40399 +54685,26894,30112,40536 +51061,26895,30111,40799 +57437,26896,30110,40023 +57529,26897,30109,40391 +53638,26898,30108,40464 +59107,26899,30107,40121 +50137,26900,30106,40474 +53850,26901,30105,40087 +54499,26902,30104,40874 +54211,26903,30103,40423 +52520,26904,30102,40190 +50144,26905,30101,40543 +58460,26906,30100,40096 +57017,26907,30099,40401 +59569,26908,30098,40051 +55959,26909,30097,40203 +51050,26910,30096,40973 +58621,26911,30095,40397 +53021,26912,30094,40656 +57762,26913,30093,40208 +52215,26914,30092,40950 +58313,26915,30091,40120 +58010,26916,30090,40593 +54722,26917,30089,40909 +59986,26918,30088,40077 +53737,26919,30087,40212 +58709,26920,30086,40243 +58795,26921,30085,40133 +51336,26922,30084,40930 +56441,26923,30083,40945 +56174,26924,30082,40804 +50022,26925,30081,40113 +55211,26926,30080,40554 +58842,26927,30079,40134 +59431,26928,30078,40477 +56313,26929,30077,40712 +58847,26930,30076,40603 +53486,26931,30075,40813 +57717,26932,30074,40585 +54704,26933,30073,40809 +53127,26934,30072,40619 +59991,26935,30071,40708 +56989,26936,30070,40917 +53256,26937,30069,40293 +56764,26938,30068,40853 +50299,26939,30067,40113 +55399,26940,30066,40824 +50174,26941,30065,40327 +51958,26942,30064,40117 +53234,26943,30063,40603 +54031,26944,30062,40482 +55539,26945,30061,40813 +56368,26946,30060,40025 +59717,26947,30059,40277 +50254,26948,30058,40958 +50090,26949,30057,40334 +57511,26950,30056,40248 +53441,26951,30055,40068 +58100,26952,30054,40081 +53640,26953,30053,40963 +57483,26954,30052,40732 +57346,26955,30051,40173 +53825,26956,30050,40826 +58899,26957,30049,40472 +53981,26958,30048,40321 +50648,26959,30047,40866 +58935,26960,30046,40514 +53347,26961,30045,40017 +53919,26962,30044,40941 +56756,26963,30043,40356 +59866,26964,30042,40051 +57940,26965,30041,40055 +51190,26966,30040,40856 +51531,26967,30039,40183 +59903,26968,30038,40571 +58225,26969,30037,40659 +57771,26970,30036,40875 +53650,26971,30035,40378 +54415,26972,30034,40184 +56890,26973,30033,40551 +58597,26974,30032,40570 +52479,26975,30031,40598 +50933,26976,30030,40202 +55230,26977,30029,40050 +58048,26978,30028,40116 +58334,26979,30027,40020 +57195,26980,30026,40669 +51201,26981,30025,40194 +52920,26982,30024,40999 +51785,26983,30023,40282 +58225,26984,30022,40334 +53255,26985,30021,40945 +53550,26986,30020,40790 +57614,26987,30019,40004 +53046,26988,30018,40579 +59958,26989,30017,40994 +59777,26990,30016,40285 +59261,26991,30015,40012 +57084,26992,30014,40070 +55416,26993,30013,40810 +56342,26994,30012,40681 +51863,26995,30011,40724 +50999,26996,30010,40224 +51926,26997,30009,40497 +55313,26998,30008,40922 +51807,26999,30007,40967 +59838,27000,30006,40679 +56301,27001,30005,40680 +54057,27002,30004,40305 +55340,27003,30003,40630 +59785,27004,30002,40106 +54140,27005,30001,40827 +55303,27006,30000,40196 +54933,27007,31000,40167 +50400,27008,30999,40185 +59780,27009,30998,40134 +53526,27010,30997,40231 +50451,27011,30996,40181 +58098,27012,30995,40175 +50070,27013,30994,40865 +59684,27014,30993,40739 +50578,27015,30992,40861 +58315,27016,30991,40362 +59592,27017,30990,40758 +51471,27018,30989,40201 +51919,27019,30988,40076 +53099,27020,30987,40311 +55280,27021,30986,40847 +50041,27022,30985,40053 +58731,27023,30984,40403 +57686,27024,30983,40280 +50582,27025,30982,40138 +51844,27026,30981,40500 +55286,27027,30980,40853 +52702,27028,30979,40151 +57558,27029,30978,40823 +57814,27030,30977,40016 +59220,27031,30976,40029 +54587,27032,30975,40074 +54315,27033,30974,40150 +53862,27034,30973,40625 +51307,27035,30972,40579 +51523,27036,30971,40095 +53157,27037,30970,40378 +51772,27038,30969,40347 +53122,27039,30968,40405 +57457,27040,30967,40871 +58372,27041,30966,40418 +56612,27042,30965,40204 +59396,27043,30964,40279 +54113,27044,30963,40772 +59689,27045,30962,40013 +56219,27046,30961,40148 +58602,27047,30960,40797 +56866,27048,30959,40252 +53003,27049,30958,40427 +57040,27050,30957,40764 +52132,27051,30956,40918 +51890,27052,30955,40149 +57392,27053,30954,40264 +54772,27054,30953,40394 +53824,27055,30952,40497 +55429,27056,30951,40977 +50303,27057,30950,40186 +58890,27058,30949,40297 +59073,27059,30948,40152 +56366,27060,30947,40929 +55588,27061,30946,40856 +50167,27062,30945,40603 +59241,27063,30944,40217 +58916,27064,30943,40619 +59116,27065,30942,40314 +56082,27066,30941,40024 +54782,27067,30940,40841 +55038,27068,30939,40822 +51540,27069,30938,40805 +58773,27070,30937,40198 +53032,27071,30936,40105 +54679,27072,30935,40603 +50221,27073,30934,40558 +56841,27074,30933,40521 +55729,27075,30932,40259 +59082,27076,30931,40699 +59515,27077,30930,40156 +55614,27078,30929,40801 +53315,27079,30928,40564 +52150,27080,30927,40125 +56721,27081,30926,40768 +56704,27082,30925,40456 +53485,27083,30924,40089 +51722,27084,30923,40134 +54374,27085,30922,40925 +51218,27086,30921,40851 +54046,27087,30920,40627 +58777,27088,30919,40632 +53266,27089,30918,40482 +54215,27090,30917,40294 +57304,27091,30916,40925 +53912,27092,30915,40134 +52161,27093,30914,40756 +50883,27094,30913,40962 +59933,27095,30912,40330 +54315,27096,30911,40964 +55486,27097,30910,40255 +50766,27098,30909,40217 +57909,27099,30908,40417 +55994,27100,30907,40553 +54761,27101,30906,40636 +52880,27102,30905,40589 +55334,27103,30904,40643 +56897,27104,30903,40909 +58593,27105,30902,40761 +53990,27106,30901,40310 +52810,27107,30900,40489 +56652,27108,30899,40797 +52810,27109,30898,40094 +57211,27110,30897,40299 +58988,27111,30896,40816 +53767,27112,30895,40460 +51176,27113,30894,40340 +56223,27114,30893,40405 +58810,27115,30892,40462 +50563,27116,30891,40810 +55745,27117,30890,40438 +50547,27118,30889,40217 +54100,27119,30888,40588 +58243,27120,30887,40790 +51215,27121,30886,40777 +57258,27122,30885,40364 +57243,27123,30884,40651 +53194,27124,30883,40997 +56075,27125,30882,40373 +57146,27126,30881,40654 +55426,27127,30880,40105 +52222,27128,30879,40682 +58755,27129,30878,40579 +56744,27130,30877,40690 +56848,27131,30876,40603 +56088,27132,30875,40365 +53860,27133,30874,40550 +53071,27134,30873,40538 +54012,27135,30872,40186 +56689,27136,30871,40047 +51951,27137,30870,40596 +55385,27138,30869,40292 +56111,27139,30868,40080 +50198,27140,30867,40073 +57608,27141,30866,40300 +56403,27142,30865,40065 +58469,27143,30864,40178 +53093,27144,30863,40746 +56530,27145,30862,40072 +58349,27146,30861,40778 +52747,27147,30860,40189 +59629,27148,30859,40784 +53988,27149,30858,40898 +51656,27150,30857,40619 +50546,27151,30856,40522 +51921,27152,30855,40779 +58262,27153,30854,40431 +53877,27154,30853,40554 +56682,27155,30852,40531 +57845,27156,30851,40367 +50740,27157,30850,40969 +58172,27158,30849,40247 +54071,27159,30848,40630 +50063,27160,30847,40320 +59129,27161,30846,40270 +54898,27162,30845,40339 +56032,27163,30844,40887 +54327,27164,30843,40645 +54181,27165,30842,40164 +50929,27166,30841,40547 +51306,27167,30840,40575 +53607,27168,30839,40919 +52375,27169,30838,40599 +54947,27170,30837,40051 +50608,27171,30836,40417 +55418,27172,30835,40481 +51283,27173,30834,40054 +54391,27174,30833,40412 +52206,27175,30832,40769 +51248,27176,30831,40519 +54349,27177,30830,40443 +56954,27178,30829,40400 +59697,27179,30828,40805 +52825,27180,30827,40609 +51308,27181,30826,40953 +50479,27182,30825,40171 +54088,27183,30824,40214 +50181,27184,30823,40614 +55703,27185,30822,40710 +54487,27186,30821,40050 +56917,27187,30820,40349 +56266,27188,30819,40115 +58666,27189,30818,40992 +51369,27190,30817,40309 +59277,27191,30816,40856 +54541,27192,30815,40596 +55186,27193,30814,40450 +58555,27194,30813,40493 +57923,27195,30812,40388 +53687,27196,30811,40535 +59484,27197,30810,40077 +52710,27198,30809,40944 +55328,27199,30808,40186 +50673,27200,30807,40093 +51370,27201,30806,40313 +55029,27202,30805,40402 +50974,27203,30804,40836 +56535,27204,30803,40714 +50637,27205,30802,40123 +57910,27206,30801,40052 +57239,27207,30800,40350 +50425,27208,30799,40778 +59259,27209,30798,40174 +52887,27210,30797,40759 +56202,27211,30796,40431 +59797,27212,30795,40700 +51098,27213,30794,40133 +53865,27214,30793,40639 +52646,27215,30792,40511 +56670,27216,30791,40352 +55043,27217,30790,40988 +56769,27218,30789,40409 +59213,27219,30788,40488 +59639,27220,30787,40514 +55247,27221,30786,40979 +52113,27222,30785,40311 +52194,27223,30784,40023 +58552,27224,30783,40326 +52733,27225,30782,40157 +53043,27226,30781,40368 +53562,27227,30780,40930 +50568,27228,30779,40604 +51562,27229,30778,40131 +54078,27230,30777,40722 +57774,27231,30776,40338 +53552,27232,30775,40139 +56454,27233,30774,40371 +50926,27234,30773,40434 +50791,27235,30772,40088 +56254,27236,30771,40519 +50997,27237,30770,40076 +55408,27238,30769,40392 +56289,27239,30768,40840 +50030,27240,30767,40668 +59611,27241,30766,40641 +52626,27242,30765,40390 +50728,27243,30764,40586 +56258,27244,30763,40746 +59358,27245,30762,40787 +59767,27246,30761,40159 +57229,27247,30760,40846 +59292,27248,30759,40649 +55576,27249,30758,40337 +53873,27250,30757,40354 +51361,27251,30756,40917 +50990,27252,30755,40468 +56018,27253,30754,40554 +52549,27254,30753,40741 +50727,27255,30752,40109 +59008,27256,30751,40456 +57418,27257,30750,40231 +57914,27258,30749,40380 +54150,27259,30748,40603 +56922,27260,30747,40771 +59821,27261,30746,40331 +57641,27262,30745,40753 +57013,27263,30744,40152 +56981,27264,30743,40223 +56909,27265,30742,40412 +50894,27266,30741,40515 +55517,27267,30740,40197 +52845,27268,30739,40846 +58123,27269,30738,40673 +59541,27270,30737,40577 +54922,27271,30736,40585 +50785,27272,30735,40717 +59197,27273,30734,40091 +54205,27274,30733,40470 +59626,27275,30732,40328 +53457,27276,30731,40507 +52441,27277,30730,40134 +53880,27278,30729,40788 +54123,27279,30728,40075 +51279,27280,30727,40400 +50056,27281,30726,40799 +51656,27282,30725,40938 +54208,27283,30724,40788 +56782,27284,30723,40768 +56723,27285,30722,40101 +54131,27286,30721,40592 +59453,27287,30720,40720 +50166,27288,30719,40799 +52713,27289,30718,40921 +50208,27290,30717,40016 +58006,27291,30716,40709 +57885,27292,30715,40797 +55431,27293,30714,40584 +54919,27294,30713,40396 +59379,27295,30712,40907 +55886,27296,30711,40625 +59485,27297,30710,40285 +53429,27298,30709,40804 +58927,27299,30708,40693 +50038,27300,30707,40503 +59135,27301,30706,40465 +55045,27302,30705,40847 +50580,27303,30704,40638 +58097,27304,30703,40876 +59745,27305,30702,40477 +58503,27306,30701,40966 +59679,27307,30700,40182 +52081,27308,30699,40342 +53946,27309,30698,40836 +53420,27310,30697,40686 +58002,27311,30696,40229 +51287,27312,30695,40422 +50449,27313,30694,40844 +52359,27314,30693,40052 +58156,27315,30692,40540 +53207,27316,30691,40151 +54291,27317,30690,40995 +52845,27318,30689,40536 +55042,27319,30688,40072 +58680,27320,30687,40310 +58810,27321,30686,40699 +50261,27322,30685,40621 +58442,27323,30684,40856 +55729,27324,30683,40385 +52726,27325,30682,40736 +56649,27326,30681,40837 +52330,27327,30680,40836 +58109,27328,30679,40754 +59624,27329,30678,40438 +59923,27330,30677,40270 +56957,27331,30676,40046 +55111,27332,30675,40379 +52594,27333,30674,40661 +55888,27334,30673,40865 +57101,27335,30672,40970 +55278,27336,30671,40346 +59864,27337,30670,40903 +51584,27338,30669,40463 +53193,27339,30668,40111 +57202,27340,30667,40244 +57937,27341,30666,40222 +52883,27342,30665,40196 +54177,27343,30664,40773 +59812,27344,30663,40562 +50965,27345,30662,40768 +52716,27346,30661,40878 +52452,27347,30660,40326 +59737,27348,30659,40025 +54128,27349,30658,40340 +54386,27350,30657,40941 +50712,27351,30656,40063 +58760,27352,30655,40475 +56077,27353,30654,40876 +53146,27354,30653,40146 +58082,27355,30652,40325 +54727,27356,30651,40553 +58828,27357,30650,40539 +56573,27358,30649,40625 +56617,27359,30648,40363 +50049,27360,30647,40186 +52637,27361,30646,40406 +52008,27362,30645,40601 +55159,27363,30644,40672 +59666,27364,30643,40210 +57602,27365,30642,40197 +54022,27366,30641,40496 +57335,27367,30640,40163 +56856,27368,30639,40198 +56656,27369,30638,40280 +51464,27370,30637,40433 +57768,27371,30636,40321 +54004,27372,30635,40132 +57662,27373,30634,40875 +53293,27374,30633,40207 +56231,27375,30632,40642 +56647,27376,30631,40965 +51043,27377,30630,40332 +58521,27378,30629,40809 +53512,27379,30628,40289 +57109,27380,30627,40461 +50219,27381,30626,40786 +59442,27382,30625,40982 +53470,27383,30624,40658 +56340,27384,30623,40983 +54019,27385,30622,40005 +52653,27386,30621,40408 +53022,27387,30620,40684 +55165,27388,30619,40146 +55928,27389,30618,40226 +51685,27390,30617,40786 +50320,27391,30616,40959 +52154,27392,30615,40968 +52156,27393,30614,40566 +52388,27394,30613,40932 +55181,27395,30612,40844 +54950,27396,30611,40148 +55712,27397,30610,40368 +57416,27398,30609,40307 +51249,27399,30608,40146 +56447,27400,30607,40265 +50139,27401,30606,40249 +50383,27402,30605,40883 +55914,27403,30604,40052 +53607,27404,30603,40711 +52353,27405,30602,40140 +57898,27406,30601,40703 +58214,27407,30600,40213 +55470,27408,30599,40655 +58315,27409,30598,40088 +53741,27410,30597,40084 +55097,27411,30596,40814 +56345,27412,30595,40932 +56005,27413,30594,40139 +53405,27414,30593,40372 +56740,27415,30592,40556 +57822,27416,30591,40185 +58315,27417,30590,40726 +51856,27418,30589,40070 +52622,27419,30588,40741 +52741,27420,30587,40095 +59082,27421,30586,40237 +53376,27422,30585,40296 +51087,27423,30584,40265 +52744,27424,30583,40670 +52197,27425,30582,40558 +50360,27426,30581,40527 +50399,27427,30580,40922 +50803,27428,30579,40832 +55501,27429,30578,40247 +54276,27430,30577,40875 +50491,27431,30576,40422 +59060,27432,30575,40235 +52087,27433,30574,40009 +51637,27434,30573,40214 +57600,27435,30572,40866 +58859,27436,30571,40293 +55066,27437,30570,40537 +58779,27438,30569,40595 +58686,27439,30568,40574 +54891,27440,30567,40864 +56253,27441,30566,40027 +55016,27442,30565,40585 +54805,27443,30564,40389 +50455,27444,30563,40885 +53597,27445,30562,40839 +55235,27446,30561,40998 +55786,27447,30560,40043 +59717,27448,30559,40826 +50660,27449,30558,40822 +52562,27450,30557,40022 +52787,27451,30556,40519 +56158,27452,30555,40158 +54915,27453,30554,40564 +51262,27454,30553,40195 +56454,27455,30552,40824 +58027,27456,30551,40505 +56616,27457,30550,40805 +50818,27458,30549,40148 +59758,27459,30548,40146 +51993,27460,30547,40191 +58056,27461,30546,40025 +52908,27462,30545,40112 +52790,27463,30544,40624 +51733,27464,30543,40771 +58630,27465,30542,40121 +55434,27466,30541,40225 +58043,27467,30540,40544 +53745,27468,30539,40533 +58601,27469,30538,40441 +58830,27470,30537,40508 +59325,27471,30536,40372 +50397,27472,30535,40902 +57066,27473,30534,40846 +51658,27474,30533,40237 +59726,27475,30532,40213 +59741,27476,30531,40657 +57427,27477,30530,40567 +54532,27478,30529,40477 +55809,27479,30528,40480 +50153,27480,30527,40794 +53168,27481,30526,40062 +58515,27482,30525,40125 +50283,27483,30524,40146 +52936,27484,30523,40184 +56641,27485,30522,40822 +52511,27486,30521,40946 +52502,27487,30520,40621 +51395,27488,30519,40731 +53814,27489,30518,40764 +57956,27490,30517,40145 +59689,27491,30516,40227 +56152,27492,30515,40448 +55265,27493,30514,40255 +55055,27494,30513,40745 +53744,27495,30512,40863 +51316,27496,30511,40490 +59159,27497,30510,40753 +58495,27498,30509,40910 +54777,27499,30508,40321 +54647,27500,30507,40024 +57871,27501,30506,40269 +53845,27502,30505,40489 +57972,27503,30504,40744 +58035,27504,30503,40020 +53872,27505,30502,40713 +50212,27506,30501,40043 +52994,27507,30500,40943 +51677,27508,30499,40520 +57047,27509,30498,40891 +57633,27510,30497,40673 +54599,27511,30496,40042 +53050,27512,30495,40728 +54494,27513,30494,40726 +55859,27514,30493,40534 +57848,27515,30492,40304 +52483,27516,30491,40148 +54598,27517,30490,40012 +51139,27518,30489,40190 +53293,27519,30488,40048 +57969,27520,30487,40132 +51661,27521,30486,40730 +59741,27522,30485,40062 +59775,27523,30484,40078 +55584,27524,30483,40636 +58888,27525,30482,40073 +58397,27526,30481,40119 +54938,27527,30480,40812 +52336,27528,30479,40496 +55210,27529,30478,40360 +51731,27530,30477,40338 +53628,27531,30476,40603 +56991,27532,30475,40206 +50346,27533,30474,40741 +50911,27534,30473,40396 +59060,27535,30472,40562 +51839,27536,30471,40576 +53665,27537,30470,40763 +51684,27538,30469,40248 +51139,27539,30468,40883 +56278,27540,30467,40825 +58953,27541,30466,40883 +55560,27542,30465,40073 +57054,27543,30464,40266 +53209,27544,30463,40133 +53358,27545,30462,40213 +53570,27546,30461,40559 +59385,27547,30460,40287 +51839,27548,30459,40235 +53088,27549,30458,40653 +59163,27550,30457,40110 +58525,27551,30456,40265 +59363,27552,30455,40588 +52271,27553,30454,40096 +56141,27554,30453,40093 +57442,27555,30452,40522 +51618,27556,30451,40427 +57021,27557,30450,40910 +50902,27558,30449,40202 +52965,27559,30448,40231 +50249,27560,30447,40476 +55791,27561,30446,40463 +56133,27562,30445,40112 +54899,27563,30444,40615 +50215,27564,30443,40486 +56604,27565,30442,40480 +57723,27566,30441,40706 +54955,27567,30440,40721 +57569,27568,30439,40947 +53068,27569,30438,40933 +51580,27570,30437,40959 +53408,27571,30436,40848 +56856,27572,30435,40117 +52153,27573,30434,40406 +50187,27574,30433,40782 +56004,27575,30432,40376 +53252,27576,30431,40216 +56497,27577,30430,40156 +54800,27578,30429,40513 +54190,27579,30428,40575 +57868,27580,30427,40996 +55441,27581,30426,40890 +57717,27582,30425,40067 +50324,27583,30424,40879 +56411,27584,30423,40738 +52267,27585,30422,40742 +52724,27586,30421,40668 +50849,27587,30420,40200 +52701,27588,30419,40580 +52288,27589,30418,40599 +56906,27590,30417,40209 +59360,27591,30416,40576 +51135,27592,30415,40231 +50790,27593,30414,40150 +57815,27594,30413,40886 +51166,27595,30412,40652 +55297,27596,30411,40273 +56244,27597,30410,40807 +58219,27598,30409,40974 +50795,27599,30408,40510 +56423,27600,30407,40469 +59472,27601,30406,40687 +58954,27602,30405,40374 +52825,27603,30404,40423 +56275,27604,30403,40155 +58167,27605,30402,40205 +59417,27606,30401,40071 +50315,27607,30400,40707 +55133,27608,30399,40530 +53061,27609,30398,40090 +50078,27610,30397,40051 +57623,27611,30396,40073 +52123,27612,30395,40313 +52680,27613,30394,40691 +59091,27614,30393,40437 +54484,27615,30392,40706 +51160,27616,30391,40431 +58561,27617,30390,40819 +59762,27618,30389,40035 +59052,27619,30388,40864 +51520,27620,30387,40192 +50130,27621,30386,40147 +55994,27622,30385,40733 +51451,27623,30384,40998 +56770,27624,30383,40480 +58128,27625,30382,40268 +58424,27626,30381,40349 +53405,27627,30380,40659 +53308,27628,30379,40327 +57554,27629,30378,40921 +58303,27630,30377,40054 +55891,27631,30376,40888 +55202,27632,30375,40053 +59567,27633,30374,40432 +50032,27634,30373,40630 +51806,27635,30372,40815 +50472,27636,30371,40557 +50180,27637,30370,40015 +50578,27638,30369,40198 +58482,27639,30368,40748 +52418,27640,30367,40931 +55339,27641,30366,40152 +53178,27642,30365,40190 +58916,27643,30364,40317 +50266,27644,30363,40671 +51349,27645,30362,40423 +53315,27646,30361,40475 +50028,27647,30360,40459 +54250,27648,30359,40210 +59505,27649,30358,40856 +54008,27650,30357,40619 +56723,27651,30356,40289 +58573,27652,30355,40670 +54225,27653,30354,40131 +51844,27654,30353,40301 +54118,27655,30352,40369 +58850,27656,30351,40568 +51691,27657,30350,40514 +57416,27658,30349,40108 +58848,27659,30348,40844 +59353,27660,30347,40263 +50662,27661,30346,40759 +50597,27662,30345,40194 +57683,27663,30344,40920 +53603,27664,30343,40827 +52296,27665,30342,40200 +50973,27666,30341,40214 +57743,27667,30340,40881 +58293,27668,30339,40640 +53102,27669,30338,40125 +52966,27670,30337,40480 +52201,27671,30336,40090 +51861,27672,30335,40395 +54036,27673,30334,40926 +53446,27674,30333,40122 +50965,27675,30332,40315 +52411,27676,30331,40009 +55768,27677,30330,40991 +54727,27678,30329,40334 +54972,27679,30328,40978 +58609,27680,30327,40124 +56955,27681,30326,40181 +53268,27682,30325,40828 +55191,27683,30324,40508 +53811,27684,30323,40863 +56607,27685,30322,40943 +59290,27686,30321,40922 +55169,27687,30320,40275 +59535,27688,30319,40207 +50313,27689,30318,40799 +55240,27690,30317,40252 +51640,27691,30316,40430 +56598,27692,30315,40674 +51728,27693,30314,40353 +56462,27694,30313,40979 +53083,27695,30312,40174 +57145,27696,30311,40817 +50972,27697,30310,40705 +52369,27698,30309,40928 +55981,27699,30308,40397 +55084,27700,30307,40839 +53607,27701,30306,40366 +55765,27702,30305,40592 +50848,27703,30304,40054 +52101,27704,30303,40857 +50815,27705,30302,40555 +58897,27706,30301,40758 +50907,27707,30300,40746 +58013,27708,30299,40109 +51329,27709,30298,40178 +51326,27710,30297,40990 +50420,27711,30296,40855 +53245,27712,30295,40965 +55727,27713,30294,40793 +57304,27714,30293,40885 +59926,27715,30292,40544 +54738,27716,30291,40747 +54091,27717,30290,40895 +54987,27718,30289,40172 +58924,27719,30288,40098 +56554,27720,30287,40484 +54825,27721,30286,40461 +59190,27722,30285,40468 +58867,27723,30284,40266 +53796,27724,30283,40567 +56160,27725,30282,40862 +53515,27726,30281,40353 +57899,27727,30280,40145 +53587,27728,30279,40349 +51705,27729,30278,40249 +50188,27730,30277,40177 +55334,27731,30276,40074 +54347,27732,30275,40480 +52014,27733,30274,40500 +56879,27734,30273,40812 +55928,27735,30272,40760 +53282,27736,30271,40149 +59052,27737,30270,40824 +56715,27738,30269,40779 +58900,27739,30268,40626 +59792,27740,30267,40324 +52225,27741,30266,40257 +52216,27742,30265,40842 +52741,27743,30264,40785 +52415,27744,30263,40028 +55597,27745,30262,40965 +52338,27746,30261,40519 +56114,27747,30260,40470 +53530,27748,30259,40841 +55493,27749,30258,40810 +54407,27750,30257,40914 +53415,27751,30256,40190 +52865,27752,30255,40952 +50619,27753,30254,40801 +50307,27754,30253,40965 +59395,27755,30252,40879 +52084,27756,30251,40255 +56391,27757,30250,40167 +53114,27758,30249,40036 +54596,27759,30248,40666 +57555,27760,30247,40023 +50992,27761,30246,40792 +57502,27762,30245,40060 +58300,27763,30244,40897 +56676,27764,30243,40259 +56851,27765,30242,40324 +57269,27766,30241,40492 +59263,27767,30240,40168 +56764,27768,30239,40312 +53611,27769,30238,40444 +56420,27770,30237,40888 +52418,27771,30236,40573 +58692,27772,30235,40797 +51974,27773,30234,40916 +55141,27774,30233,40763 +50301,27775,30232,40721 +52997,27776,30231,40586 +52582,27777,30230,40584 +54724,27778,30229,40210 +54313,27779,30228,40966 +53308,27780,30227,40314 +59069,27781,30226,40544 +56222,27782,30225,40509 +55795,27783,30224,40488 +53590,27784,30223,40811 +57471,27785,30222,40126 +50112,27786,30221,40823 +59015,27787,30220,40375 +53380,27788,30219,40674 +50563,27789,30218,40668 +55117,27790,30217,40259 +58948,27791,30216,40561 +52552,27792,30215,40944 +55970,27793,30214,40448 +52792,27794,30213,40534 +58526,27795,30212,40665 +59718,27796,30211,40610 +55862,27797,30210,40593 +59845,27798,30209,40490 +51031,27799,30208,40789 +52916,27800,30207,40762 +54364,27801,30206,40905 +50300,27802,30205,40742 +50500,27803,30204,40105 +51385,27804,30203,40657 +53922,27805,30202,40282 +59398,27806,30201,40576 +55710,27807,30200,40638 +57377,27808,30199,40583 +59113,27809,30198,40283 +59981,27810,30197,40461 +54205,27811,30196,40551 +57078,27812,30195,40630 +59795,27813,30194,40346 +57472,27814,30193,40117 +50414,27815,30192,40504 +52904,27816,30191,40300 +50277,27817,30190,40866 +54732,27818,30189,40146 +56510,27819,30188,40959 +59014,27820,30187,40391 +58486,27821,30186,40052 +53539,27822,30185,40879 +55037,27823,30184,40933 +55522,27824,30183,40752 +56526,27825,30182,40422 +51608,27826,30181,40626 +59068,27827,30180,40452 +50689,27828,30179,40995 +55095,27829,30178,40001 +51857,27830,30177,40748 +59774,27831,30176,40143 +55352,27832,30175,40075 +54143,27833,30174,40692 +58403,27834,30173,40029 +57978,27835,30172,40326 +54351,27836,30171,40712 +59939,27837,30170,40732 +57897,27838,30169,40282 +58022,27839,30168,40921 +54401,27840,30167,40410 +59845,27841,30166,40958 +55581,27842,30165,40521 +55725,27843,30164,40674 +58538,27844,30163,40828 +57559,27845,30162,40664 +55181,27846,30161,40969 +57002,27847,30160,40118 +53735,27848,30159,40580 +57053,27849,30158,40325 +50759,27850,30157,40125 +50634,27851,30156,40962 +50889,27852,30155,40455 +59439,27853,30154,40568 +57724,27854,30153,40527 +55614,27855,30152,40183 +59746,27856,30151,40087 +57380,27857,30150,40877 +56704,27858,30149,40478 +59926,27859,30148,40727 +54517,27860,30147,40694 +55383,27861,30146,40221 +54792,27862,30145,40610 +59558,27863,30144,40647 +59610,27864,30143,40682 +56788,27865,30142,40504 +51738,27866,30141,40980 +51556,27867,30140,40054 +53207,27868,30139,40929 +58155,27869,30138,40442 +55552,27870,30137,40601 +52215,27871,30136,40362 +59495,27872,30135,40595 +55548,27873,30134,40720 +50869,27874,30133,40070 +54633,27875,30132,40359 +53783,27876,30131,40885 +55450,27877,30130,40274 +53349,27878,30129,40610 +56918,27879,30128,40337 +52835,27880,30127,40890 +51496,27881,30126,40336 +51201,27882,30125,40776 +58939,27883,30124,40942 +50045,27884,30123,40225 +58062,27885,30122,40023 +56184,27886,30121,40492 +57975,27887,30120,40638 +55814,27888,30119,40500 +58371,27889,30118,40507 +56111,27890,30117,40027 +51772,27891,30116,40941 +59122,27892,30115,40684 +52308,27893,30114,40716 +51290,27894,30113,40581 +56270,27895,30112,40949 +50152,27896,30111,40072 +56924,27897,30110,40403 +58143,27898,30109,40868 +54098,27899,30108,40374 +54015,27900,30107,40845 +55369,27901,30106,40259 +59514,27902,30105,40484 +59568,27903,30104,40256 +50274,27904,30103,40996 +51549,27905,30102,40242 +55315,27906,30101,40283 +53586,27907,30100,40877 +56637,27908,30099,40280 +53418,27909,30098,40615 +53689,27910,30097,40583 +51266,27911,30096,40673 +57708,27912,30095,40551 +51860,27913,30094,40939 +54106,27914,30093,40477 +52927,27915,30092,40123 +56946,27916,30091,40694 +52227,27917,30090,40882 +51352,27918,30089,40750 +55208,27919,30088,40987 +51760,27920,30087,40688 +51070,27921,30086,40521 +52261,27922,30085,40232 +59774,27923,30084,40468 +53497,27924,30083,40245 +57216,27925,30082,40951 +58631,27926,30081,40701 +55782,27927,30080,40233 +54516,27928,30079,40068 +59829,27929,30078,40557 +57316,27930,30077,40341 +50644,27931,30076,40897 +52681,27932,30075,40571 +51069,27933,30074,40840 +55734,27934,30073,40724 +52609,27935,30072,40580 +52946,27936,30071,40067 +51688,27937,30070,40180 +59320,27938,30069,40528 +52358,27939,30068,40573 +57596,27940,30067,40830 +56505,27941,30066,40392 +50791,27942,30065,40554 +50862,27943,30064,40376 +58099,27944,30063,40707 +52643,27945,30062,40750 +53858,27946,30061,40873 +53175,27947,30060,40739 +55512,27948,30059,40254 +53454,27949,30058,40681 +58890,27950,30057,40372 +54833,27951,30056,40326 +53150,27952,30055,40874 +55474,27953,30054,40990 +54722,27954,30053,40575 +57389,27955,30052,40012 +55752,27956,30051,40017 +51833,27957,30050,40381 +59359,27958,30049,40593 +57486,27959,30048,40434 +52957,27960,30047,40503 +55745,27961,30046,40112 +58504,27962,30045,40094 +51819,27963,30044,40837 +52548,27964,30043,40436 +51672,27965,30042,40048 +57382,27966,30041,40049 +57322,27967,30040,40670 +56104,27968,30039,40825 +56702,27969,30038,40101 +57941,27970,30037,40311 +55206,27971,30036,40598 +58276,27972,30035,40431 +57622,27973,30034,40380 +51041,27974,30033,40520 +52522,27975,30032,40980 +51094,27976,30031,40797 +58932,27977,30030,40816 +50810,27978,30029,40895 +51844,27979,30028,40579 +51584,27980,30027,40025 +59311,27981,30026,40707 +55216,27982,30025,40791 +58226,27983,30024,40230 +51394,27984,30023,40627 +51152,27985,30022,40115 +51958,27986,30021,40109 +55655,27987,30020,40143 +53025,27988,30019,40023 +57329,27989,30018,40544 +52002,27990,30017,40018 +59686,27991,30016,40073 +53603,27992,30015,40025 +52511,27993,30014,40506 +52763,27994,30013,40088 +58021,27995,30012,40499 +50208,27996,30011,40408 +51896,27997,30010,40861 +54169,27998,30009,40258 +56268,27999,30008,40869 +59890,28000,30007,40885 +54589,28001,30006,40326 +54457,28002,30005,40198 +55619,28003,30004,40321 +59477,28004,30003,40307 +51248,28005,30002,40612 +55014,28006,30001,40300 +59911,28007,30000,40309 +56199,28008,31000,40070 +51671,28009,30999,40625 +53456,28010,30998,40541 +55028,28011,30997,40222 +56888,28012,30996,40262 +55655,28013,30995,40945 +57688,28014,30994,40510 +56491,28015,30993,40276 +54715,28016,30992,40066 +50233,28017,30991,40640 +54129,28018,30990,40493 +56926,28019,30989,40755 +57699,28020,30988,40959 +51703,28021,30987,40405 +53521,28022,30986,40632 +55903,28023,30985,40941 +52982,28024,30984,40537 +50751,28025,30983,40875 +50717,28026,30982,40394 +51012,28027,30981,40370 +58573,28028,30980,40966 +55295,28029,30979,40884 +54352,28030,30978,40976 +52613,28031,30977,40033 +50673,28032,30976,40768 +57175,28033,30975,40438 +54036,28034,30974,40125 +57388,28035,30973,40886 +52863,28036,30972,40337 +57097,28037,30971,40656 +56454,28038,30970,40084 +50707,28039,30969,40612 +50501,28040,30968,40933 +54780,28041,30967,40619 +58950,28042,30966,40716 +57097,28043,30965,40698 +55810,28044,30964,40805 +54500,28045,30963,40114 +56660,28046,30962,40306 +59949,28047,30961,40824 +56521,28048,30960,40745 +56843,28049,30959,40996 +58436,28050,30958,40212 +55985,28051,30957,40136 +51838,28052,30956,40747 +58907,28053,30955,40799 +58202,28054,30954,40770 +59383,28055,30953,40111 +57463,28056,30952,40184 +53745,28057,30951,40140 +55694,28058,30950,40478 +57223,28059,30949,40539 +52619,28060,30948,40591 +52859,28061,30947,40552 +55881,28062,30946,40130 +54135,28063,30945,40596 +59334,28064,30944,40945 +55002,28065,30943,40838 +50070,28066,30942,40670 +55649,28067,30941,40797 +50851,28068,30940,40185 +59281,28069,30939,40567 +52849,28070,30938,40040 +51168,28071,30937,40737 +54624,28072,30936,40052 +52243,28073,30935,40724 +55338,28074,30934,40435 +58514,28075,30933,40896 +51997,28076,30932,40255 +50792,28077,30931,40904 +54787,28078,30930,40579 +57591,28079,30929,40529 +56316,28080,30928,40141 +50040,28081,30927,40544 +57389,28082,30926,40733 +53839,28083,30925,40311 +55234,28084,30924,40288 +52525,28085,30923,40484 +54639,28086,30922,40737 +55696,28087,30921,40743 +55732,28088,30920,40429 +57269,28089,30919,40525 +59663,28090,30918,40273 +59278,28091,30917,40669 +55227,28092,30916,40923 +54558,28093,30915,40463 +57525,28094,30914,40177 +50016,28095,30913,40708 +53168,28096,30912,40377 +53016,28097,30911,40190 +51423,28098,30910,40711 +54369,28099,30909,40244 +54703,28100,30908,40340 +58150,28101,30907,40402 +57991,28102,30906,40937 +54172,28103,30905,40979 +52424,28104,30904,40704 +55164,28105,30903,40508 +58366,28106,30902,40299 +51055,28107,30901,40759 +56009,28108,30900,40356 +58450,28109,30899,40536 +57253,28110,30898,40800 +55688,28111,30897,40896 +59892,28112,30896,40665 +56831,28113,30895,40891 +50574,28114,30894,40902 +59722,28115,30893,40872 +55311,28116,30892,40497 +57662,28117,30891,40405 +54687,28118,30890,40061 +57305,28119,30889,40972 +59231,28120,30888,40641 +54812,28121,30887,40990 +54542,28122,30886,40350 +55721,28123,30885,40834 +51099,28124,30884,40073 +58823,28125,30883,40585 +51845,28126,30882,40293 +59378,28127,30881,40074 +55998,28128,30880,40088 +58096,28129,30879,40797 +52479,28130,30878,40584 +51919,28131,30877,40926 +53413,28132,30876,40122 +57641,28133,30875,40344 +51673,28134,30874,40327 +57369,28135,30873,40548 +59709,28136,30872,40820 +59864,28137,30871,40781 +50129,28138,30870,40764 +51104,28139,30869,40864 +52934,28140,30868,40644 +56258,28141,30867,40365 +55610,28142,30866,40154 +58130,28143,30865,40908 +50306,28144,30864,40267 +53408,28145,30863,40311 +55558,28146,30862,40976 +54818,28147,30861,40906 +53349,28148,30860,40580 +59148,28149,30859,40041 +54026,28150,30858,40309 +57042,28151,30857,40247 +52806,28152,30856,40164 +56532,28153,30855,40406 +53613,28154,30854,40107 +54360,28155,30853,40607 +53485,28156,30852,40202 +54022,28157,30851,40943 +57192,28158,30850,40589 +58956,28159,30849,40565 +56498,28160,30848,40470 +53042,28161,30847,40468 +57622,28162,30846,40922 +53080,28163,30845,40545 +51860,28164,30844,40251 +58939,28165,30843,40635 +54069,28166,30842,40346 +52230,28167,30841,40881 +58463,28168,30840,40862 +51221,28169,30839,40508 +50403,28170,30838,40493 +59397,28171,30837,40035 +53620,28172,30836,40598 +57496,28173,30835,40373 +57122,28174,30834,40921 +57796,28175,30833,40871 +57060,28176,30832,40732 +54459,28177,30831,40121 +58773,28178,30830,40146 +55269,28179,30829,40543 +58917,28180,30828,40890 +54313,28181,30827,40377 +55648,28182,30826,40410 +50859,28183,30825,40279 +56155,28184,30824,40429 +58191,28185,30823,40573 +51002,28186,30822,40352 +56523,28187,30821,40247 +59103,28188,30820,40005 +55307,28189,30819,40937 +55214,28190,30818,40074 +51694,28191,30817,40638 +51884,28192,30816,40386 +57694,28193,30815,40883 +59461,28194,30814,40277 +53741,28195,30813,40046 +56108,28196,30812,40974 +53291,28197,30811,40632 +54557,28198,30810,40721 +51187,28199,30809,40885 +56446,28200,30808,40575 +52597,28201,30807,40356 +50773,28202,30806,40103 +50735,28203,30805,40503 +53171,28204,30804,40171 +56836,28205,30803,40593 +55838,28206,30802,40420 +57774,28207,30801,40046 +54444,28208,30800,40651 +51632,28209,30799,40100 +56491,28210,30798,40093 +55844,28211,30797,40812 +57917,28212,30796,40386 +51252,28213,30795,40133 +54129,28214,30794,40107 +57716,28215,30793,40021 +57117,28216,30792,40389 +51804,28217,30791,40220 +51271,28218,30790,40142 +58579,28219,30789,40792 +56563,28220,30788,40875 +59670,28221,30787,40447 +52919,28222,30786,40988 +51657,28223,30785,40660 +51706,28224,30784,40004 +50148,28225,30783,40761 +52426,28226,30782,40192 +50143,28227,30781,40053 +55965,28228,30780,40572 +56552,28229,30779,40570 +59680,28230,30778,40340 +53105,28231,30777,40181 +54187,28232,30776,40102 +59239,28233,30775,40779 +53189,28234,30774,40338 +50012,28235,30773,40349 +58595,28236,30772,40522 +58022,28237,30771,40080 +54700,28238,30770,40684 +54561,28239,30769,40084 +51593,28240,30768,40593 +50207,28241,30767,40334 +58344,28242,30766,40985 +58416,28243,30765,40667 +58847,28244,30764,40309 +56124,28245,30763,40556 +51757,28246,30762,40049 +54973,28247,30761,40329 +57644,28248,30760,40212 +51930,28249,30759,40491 +58019,28250,30758,40829 +57070,28251,30757,40771 +50408,28252,30756,40156 +58264,28253,30755,40792 +50115,28254,30754,40290 +53499,28255,30753,40968 +56077,28256,30752,40021 +57941,28257,30751,40519 +50935,28258,30750,40596 +53628,28259,30749,40869 +54935,28260,30748,40492 +50180,28261,30747,40327 +50141,28262,30746,40549 +55886,28263,30745,40468 +52757,28264,30744,40316 +53547,28265,30743,40330 +59573,28266,30742,40397 +54702,28267,30741,40780 +51829,28268,30740,40204 +55423,28269,30739,40507 +58446,28270,30738,40521 +57451,28271,30737,40887 +55355,28272,30736,40014 +52089,28273,30735,40639 +53772,28274,30734,40853 +57448,28275,30733,40020 +56314,28276,30732,40819 +55011,28277,30731,40535 +52869,28278,30730,40068 +54695,28279,30729,40170 +57160,28280,30728,40889 +54507,28281,30727,40530 +59758,28282,30726,40021 +50302,28283,30725,40887 +59598,28284,30724,40831 +59631,28285,30723,40549 +54242,28286,30722,40580 +57445,28287,30721,40906 +58582,28288,30720,40669 +52847,28289,30719,40668 +53051,28290,30718,40345 +50774,28291,30717,40742 +51899,28292,30716,40791 +52190,28293,30715,40471 +55190,28294,30714,40130 +51883,28295,30713,40536 +55291,28296,30712,40648 +59489,28297,30711,40928 +56787,28298,30710,40825 +52707,28299,30709,40454 +51912,28300,30708,40185 +55293,28301,30707,40665 +52003,28302,30706,40418 +57214,28303,30705,40103 +52178,28304,30704,40433 +59708,28305,30703,40409 +59256,28306,30702,40530 +53003,28307,30701,40527 +51822,28308,30700,40491 +51273,28309,30699,40509 +50855,28310,30698,40091 +54512,28311,30697,40409 +54002,28312,30696,40757 +55775,28313,30695,40328 +59528,28314,30694,40101 +51650,28315,30693,40141 +58789,28316,30692,40253 +56557,28317,30691,40037 +59636,28318,30690,40004 +59640,28319,30689,40057 +56323,28320,30688,40820 +54836,28321,30687,40425 +54118,28322,30686,40550 +58076,28323,30685,40450 +56407,28324,30684,40148 +51734,28325,30683,40212 +54139,28326,30682,40723 +54217,28327,30681,40562 +52943,28328,30680,40244 +56041,28329,30679,40046 +58881,28330,30678,40069 +56669,28331,30677,40224 +59835,28332,30676,40208 +51858,28333,30675,40179 +54395,28334,30674,40023 +50952,28335,30673,40525 +59150,28336,30672,40635 +54490,28337,30671,40201 +56458,28338,30670,40384 +52651,28339,30669,40211 +51819,28340,30668,40134 +51932,28341,30667,40999 +57029,28342,30666,40951 +54810,28343,30665,40894 +51416,28344,30664,40928 +59412,28345,30663,40598 +54354,28346,30662,40421 +54730,28347,30661,40692 +57694,28348,30660,40006 +55713,28349,30659,40369 +58650,28350,30658,40936 +51651,28351,30657,40279 +59126,28352,30656,40761 +58691,28353,30655,40806 +56712,28354,30654,40596 +59438,28355,30653,40975 +59485,28356,30652,40613 +55533,28357,30651,40499 +57978,28358,30650,40097 +58471,28359,30649,40953 +55520,28360,30648,40077 +57891,28361,30647,40100 +52126,28362,30646,40250 +56347,28363,30645,40349 +56192,28364,30644,40234 +55933,28365,30643,40185 +50726,28366,30642,40930 +59771,28367,30641,40401 +52303,28368,30640,40907 +52578,28369,30639,40954 +50468,28370,30638,40134 +57111,28371,30637,40073 +53953,28372,30636,40108 +55917,28373,30635,40861 +57694,28374,30634,40823 +57764,28375,30633,40768 +51772,28376,30632,40281 +52699,28377,30631,40387 +52090,28378,30630,40351 +55830,28379,30629,40158 +55127,28380,30628,40161 +58090,28381,30627,40057 +55570,28382,30626,40529 +59941,28383,30625,40233 +54238,28384,30624,40885 +54252,28385,30623,40002 +53393,28386,30622,40827 +55388,28387,30621,40917 +59931,28388,30620,40368 +54273,28389,30619,40215 +54612,28390,30618,40332 +55429,28391,30617,40054 +51966,28392,30616,40878 +55296,28393,30615,40161 +51786,28394,30614,40784 +56509,28395,30613,40299 +51494,28396,30612,40382 +56350,28397,30611,40275 +50612,28398,30610,40329 +55590,28399,30609,40067 +51238,28400,30608,40474 +55124,28401,30607,40506 +58821,28402,30606,40821 +52223,28403,30605,40128 +50592,28404,30604,40964 +52269,28405,30603,40582 +59297,28406,30602,40156 +59998,28407,30601,40272 +55324,28408,30600,40776 +57237,28409,30599,40480 +59186,28410,30598,40881 +57254,28411,30597,40352 +52898,28412,30596,40967 +51418,28413,30595,40828 +51326,28414,30594,40870 +52608,28415,30593,40657 +51819,28416,30592,40175 +50399,28417,30591,40950 +59426,28418,30590,40962 +55094,28419,30589,40110 +54115,28420,30588,40485 +57220,28421,30587,40446 +59466,28422,30586,40620 +58243,28423,30585,40521 +59178,28424,30584,40365 +56606,28425,30583,40174 +54389,28426,30582,40030 +53972,28427,30581,40250 +50109,28428,30580,40846 +58645,28429,30579,40592 +52933,28430,30578,40212 +55097,28431,30577,40674 +55601,28432,30576,40968 +58544,28433,30575,40690 +54268,28434,30574,40036 +59124,28435,30573,40953 +55961,28436,30572,40647 +51146,28437,30571,40307 +51921,28438,30570,40286 +53448,28439,30569,40638 +50714,28440,30568,40919 +54224,28441,30567,40541 +51928,28442,30566,40851 +55226,28443,30565,40357 +55325,28444,30564,40871 +54177,28445,30563,40875 +57341,28446,30562,40592 +58915,28447,30561,40423 +55117,28448,30560,40480 +59820,28449,30559,40234 +55465,28450,30558,40793 +53756,28451,30557,40735 +56804,28452,30556,40517 +50436,28453,30555,40849 +54426,28454,30554,40216 +51457,28455,30553,40961 +51602,28456,30552,40699 +59951,28457,30551,40786 +58207,28458,30550,40445 +52718,28459,30549,40668 +54294,28460,30548,40599 +51954,28461,30547,40952 +52441,28462,30546,40669 +51092,28463,30545,40350 +55186,28464,30544,40516 +56630,28465,30543,40569 +55627,28466,30542,40772 +51684,28467,30541,40492 +55130,28468,30540,40900 +50214,28469,30539,40308 +52603,28470,30538,40133 +58898,28471,30537,40769 +53797,28472,30536,40244 +57950,28473,30535,40929 +57918,28474,30534,40791 +57763,28475,30533,40787 +57658,28476,30532,40442 +57133,28477,30531,40085 +54895,28478,30530,40966 +56911,28479,30529,40627 +51428,28480,30528,40528 +52931,28481,30527,40829 +50344,28482,30526,40074 +59151,28483,30525,40179 +58318,28484,30524,40536 +58627,28485,30523,40343 +57574,28486,30522,40120 +54591,28487,30521,40023 +57287,28488,30520,40303 +59346,28489,30519,40502 +56409,28490,30518,40700 +57229,28491,30517,40615 +55359,28492,30516,40252 +57637,28493,30515,40173 +51745,28494,30514,40145 +50151,28495,30513,40809 +58232,28496,30512,40855 +53574,28497,30511,40408 +56018,28498,30510,40477 +53921,28499,30509,40128 +55685,28500,30508,40348 +59232,28501,30507,40592 +52416,28502,30506,40456 +52316,28503,30505,40201 +52669,28504,30504,40663 +51950,28505,30503,40077 +53731,28506,30502,40906 +58047,28507,30501,40331 +50120,28508,30500,40272 +57423,28509,30499,40707 +53508,28510,30498,40986 +52898,28511,30497,40180 +59504,28512,30496,40262 +50004,28513,30495,40479 +50989,28514,30494,40203 +56381,28515,30493,40024 +56242,28516,30492,40085 +57072,28517,30491,40705 +53821,28518,30490,40910 +56637,28519,30489,40915 +52954,28520,30488,40026 +52791,28521,30487,40282 +57473,28522,30486,40365 +58607,28523,30485,40219 +53178,28524,30484,40875 +51647,28525,30483,40957 +57980,28526,30482,40275 +53907,28527,30481,40921 +56994,28528,30480,40889 +52369,28529,30479,40791 +51887,28530,30478,40726 +50201,28531,30477,40022 +52185,28532,30476,40079 +55560,28533,30475,40200 +53504,28534,30474,40671 +53863,28535,30473,40664 +51026,28536,30472,40018 +56080,28537,30471,40481 +58087,28538,30470,40159 +56832,28539,30469,40900 +52743,28540,30468,40608 +54488,28541,30467,40629 +55644,28542,30466,40929 +57357,28543,30465,40963 +56930,28544,30464,40795 +55968,28545,30463,40618 +59738,28546,30462,40828 +59768,28547,30461,40263 +56158,28548,30460,40805 +50699,28549,30459,40143 +59295,28550,30458,40128 +56876,28551,30457,40964 +55514,28552,30456,40195 +52910,28553,30455,40165 +59353,28554,30454,40085 +55142,28555,30453,40753 +52821,28556,30452,40028 +56862,28557,30451,40400 +52025,28558,30450,40313 +54886,28559,30449,40558 +53282,28560,30448,40273 +50597,28561,30447,40709 +52131,28562,30446,40456 +53534,28563,30445,40950 +59654,28564,30444,40788 +57870,28565,30443,40819 +59740,28566,30442,40875 +55105,28567,30441,40268 +58661,28568,30440,40651 +50036,28569,30439,40548 +53226,28570,30438,40020 +56693,28571,30437,40991 +52999,28572,30436,40195 +58806,28573,30435,40050 +57047,28574,30434,40030 +59761,28575,30433,40999 +52056,28576,30432,40511 +52470,28577,30431,40620 +50670,28578,30430,40711 +51311,28579,30429,40583 +56131,28580,30428,40912 +56900,28581,30427,40304 +59212,28582,30426,40406 +53898,28583,30425,40019 +58023,28584,30424,40603 +59575,28585,30423,40456 +53472,28586,30422,40911 +52961,28587,30421,40681 +57650,28588,30420,40713 +54452,28589,30419,40111 +56058,28590,30418,40436 +57858,28591,30417,40345 +55848,28592,30416,40856 +57956,28593,30415,40507 +53535,28594,30414,40107 +51247,28595,30413,40815 +58924,28596,30412,40004 +55234,28597,30411,40482 +59235,28598,30410,40836 +53500,28599,30409,40373 +52052,28600,30408,40138 +54954,28601,30407,40359 +53549,28602,30406,40722 +58142,28603,30405,40659 +59753,28604,30404,40321 +56955,28605,30403,40587 +55030,28606,30402,40399 +50909,28607,30401,40489 +58612,28608,30400,40545 +56389,28609,30399,40142 +51449,28610,30398,40201 +57106,28611,30397,40401 +56562,28612,30396,40181 +58315,28613,30395,40029 +56788,28614,30394,40682 +53785,28615,30393,40183 +50321,28616,30392,40682 +53314,28617,30391,40763 +57061,28618,30390,40593 +56656,28619,30389,40858 +55072,28620,30388,40623 +55328,28621,30387,40778 +50126,28622,30386,40003 +59254,28623,30385,40562 +58690,28624,30384,40381 +51981,28625,30383,40496 +59826,28626,30382,40086 +58748,28627,30381,40722 +59243,28628,30380,40351 +53604,28629,30379,40837 +54116,28630,30378,40898 +54135,28631,30377,40533 +52225,28632,30376,40336 +56867,28633,30375,40801 +50574,28634,30374,40248 +54763,28635,30373,40706 +52715,28636,30372,40241 +52038,28637,30371,40880 +59687,28638,30370,40980 +53216,28639,30369,40345 +56757,28640,30368,40417 +51023,28641,30367,40255 +54188,28642,30366,40525 +59393,28643,30365,40213 +54602,28644,30364,40773 +54641,28645,30363,40238 +53880,28646,30362,40321 +51768,28647,30361,40929 +55864,28648,30360,40128 +52464,28649,30359,40357 +56282,28650,30358,40675 +52579,28651,30357,40701 +58751,28652,30356,40281 +54274,28653,30355,40873 +55989,28654,30354,40791 +50337,28655,30353,40185 +52033,28656,30352,40401 +58336,28657,30351,40429 +50827,28658,30350,40034 +55141,28659,30349,40902 +51795,28660,30348,40892 +56725,28661,30347,40075 +52977,28662,30346,40500 +59681,28663,30345,40065 +57978,28664,30344,40285 +58365,28665,30343,40507 +57055,28666,30342,40999 +59260,28667,30341,40769 +57279,28668,30340,40996 +58807,28669,30339,40760 +51308,28670,30338,40599 +50284,28671,30337,40510 +57755,28672,30336,40225 +56291,28673,30335,40312 +51813,28674,30334,40897 +50332,28675,30333,40914 +56779,28676,30332,40279 +59124,28677,30331,40802 +54422,28678,30330,40390 +55879,28679,30329,40177 +50540,28680,30328,40732 +53807,28681,30327,40503 +59439,28682,30326,40031 +52234,28683,30325,40970 +55247,28684,30324,40997 +58634,28685,30323,40987 +55520,28686,30322,40320 +58453,28687,30321,40909 +56102,28688,30320,40916 +52013,28689,30319,40530 +55100,28690,30318,40406 +53402,28691,30317,40724 +53189,28692,30316,40628 +52547,28693,30315,40085 +59769,28694,30314,40499 +53964,28695,30313,40716 +56513,28696,30312,40432 +56586,28697,30311,40645 +50110,28698,30310,40311 +52305,28699,30309,40451 +52148,28700,30308,40361 +50510,28701,30307,40092 +57060,28702,30306,40382 +59009,28703,30305,40913 +54022,28704,30304,40911 +50929,28705,30303,40496 +55349,28706,30302,40518 +57636,28707,30301,40977 +51589,28708,30300,40020 +58550,28709,30299,40609 +59600,28710,30298,40839 +58678,28711,30297,40470 +53213,28712,30296,40238 +59793,28713,30295,40824 +59218,28714,30294,40771 +54694,28715,30293,40056 +53456,28716,30292,40996 +57912,28717,30291,40712 +54605,28718,30290,40909 +52018,28719,30289,40367 +54864,28720,30288,40405 +54852,28721,30287,40847 +59972,28722,30286,40675 +55116,28723,30285,40332 +58095,28724,30284,40902 +57856,28725,30283,40091 +59021,28726,30282,40214 +56440,28727,30281,40276 +52133,28728,30280,40714 +59400,28729,30279,40198 +58109,28730,30278,40647 +50411,28731,30277,40526 +57881,28732,30276,40193 +50299,28733,30275,40115 +50223,28734,30274,40097 +58269,28735,30273,40369 +51974,28736,30272,40932 +50874,28737,30271,40273 +54813,28738,30270,40515 +53815,28739,30269,40833 +53944,28740,30268,40676 +53318,28741,30267,40021 +53108,28742,30266,40541 +53541,28743,30265,40177 +57180,28744,30264,40760 +56405,28745,30263,40809 +53140,28746,30262,40311 +50869,28747,30261,40296 +54963,28748,30260,40445 +59692,28749,30259,40618 +54190,28750,30258,40239 +57238,28751,30257,40270 +53390,28752,30256,40885 +51270,28753,30255,40811 +55187,28754,30254,40033 +56937,28755,30253,40533 +54563,28756,30252,40187 +58267,28757,30251,40444 +54667,28758,30250,40334 +50291,28759,30249,40010 +53158,28760,30248,40843 +52521,28761,30247,40527 +54683,28762,30246,40944 +51064,28763,30245,40891 +54464,28764,30244,40796 +59903,28765,30243,40407 +52221,28766,30242,40233 +51921,28767,30241,40656 +56732,28768,30240,40295 +51388,28769,30239,40760 +51020,28770,30238,40929 +59047,28771,30237,40283 +52292,28772,30236,40350 +54788,28773,30235,40644 +59092,28774,30234,40175 +59157,28775,30233,40602 +52536,28776,30232,40048 +52202,28777,30231,40170 +52214,28778,30230,40996 +54105,28779,30229,40730 +54358,28780,30228,40457 +52951,28781,30227,40078 +50593,28782,30226,40877 +56690,28783,30225,40803 +53426,28784,30224,40228 +59489,28785,30223,40062 +55578,28786,30222,40415 +50803,28787,30221,40376 +58480,28788,30220,40611 +59268,28789,30219,40977 +54388,28790,30218,40619 +56974,28791,30217,40341 +57988,28792,30216,40730 +56572,28793,30215,40471 +52840,28794,30214,40273 +54314,28795,30213,40305 +53432,28796,30212,40201 +50152,28797,30211,40693 +57454,28798,30210,40918 +55661,28799,30209,40179 +51254,28800,30208,40809 +55513,28801,30207,40952 +54658,28802,30206,40608 +50482,28803,30205,40759 +51241,28804,30204,40787 +54352,28805,30203,40615 +57343,28806,30202,40862 +51284,28807,30201,40008 +51344,28808,30200,40678 +55315,28809,30199,40058 +58614,28810,30198,40506 +52624,28811,30197,40237 +54123,28812,30196,40240 +57559,28813,30195,40839 +52024,28814,30194,40368 +51511,28815,30193,40053 +59867,28816,30192,40689 +50855,28817,30191,40481 +57479,28818,30190,40326 +50457,28819,30189,40044 +52469,28820,30188,40565 +53451,28821,30187,40025 +57561,28822,30186,40796 +57898,28823,30185,40566 +52896,28824,30184,40840 +59665,28825,30183,40087 +56340,28826,30182,40715 +55136,28827,30181,40401 +53746,28828,30180,40953 +55128,28829,30179,40104 +56211,28830,30178,40936 +53730,28831,30177,40397 +55574,28832,30176,40185 +54367,28833,30175,40319 +50863,28834,30174,40479 +55994,28835,30173,40148 +57800,28836,30172,40851 +53546,28837,30171,40013 +57653,28838,30170,40689 +50836,28839,30169,40148 +58998,28840,30168,40315 +56061,28841,30167,40546 +59814,28842,30166,40545 +52892,28843,30165,40177 +50417,28844,30164,40625 +55774,28845,30163,40075 +51538,28846,30162,40176 +53683,28847,30161,40062 +50857,28848,30160,40997 +56534,28849,30159,40596 +55932,28850,30158,40150 +51595,28851,30157,40019 +59477,28852,30156,40706 +58784,28853,30155,40309 +53177,28854,30154,40090 +59846,28855,30153,40661 +52616,28856,30152,40380 +59945,28857,30151,40279 +56448,28858,30150,40494 +53194,28859,30149,40418 +53852,28860,30148,40268 +59918,28861,30147,40694 +54842,28862,30146,40950 +50175,28863,30145,40140 +58698,28864,30144,40520 +59184,28865,30143,40502 +58227,28866,30142,40327 +50718,28867,30141,40939 +52175,28868,30140,40565 +59538,28869,30139,40911 +55895,28870,30138,40170 +55699,28871,30137,40165 +56745,28872,30136,40311 +50361,28873,30135,40426 +50789,28874,30134,40368 +52940,28875,30133,40648 +59784,28876,30132,40453 +54507,28877,30131,40371 +55503,28878,30130,40004 +59928,28879,30129,40539 +52445,28880,30128,40463 +51360,28881,30127,40679 +59271,28882,30126,40390 +50217,28883,30125,40090 +51725,28884,30124,40089 +54148,28885,30123,40373 +59619,28886,30122,40829 +57665,28887,30121,40465 +56318,28888,30120,40648 +59042,28889,30119,40007 +59722,28890,30118,40025 +55272,28891,30117,40630 +52087,28892,30116,40641 +52937,28893,30115,40223 +50629,28894,30114,40160 +54804,28895,30113,40912 +58724,28896,30112,40926 +51675,28897,30111,40444 +57086,28898,30110,40775 +54510,28899,30109,40868 +52192,28900,30108,40474 +55177,28901,30107,40500 +56547,28902,30106,40886 +52403,28903,30105,40356 +56633,28904,30104,40794 +52295,28905,30103,40865 +57267,28906,30102,40055 +52960,28907,30101,40352 +55824,28908,30100,40811 +56750,28909,30099,40366 +58255,28910,30098,40621 +57701,28911,30097,40687 +56853,28912,30096,40489 +58708,28913,30095,40681 +59098,28914,30094,40455 +58243,28915,30093,40108 +52350,28916,30092,40108 +52949,28917,30091,40992 +55353,28918,30090,40556 +58685,28919,30089,40019 +54608,28920,30088,40929 +59149,28921,30087,40686 +56596,28922,30086,40933 +54026,28923,30085,40546 +51508,28924,30084,40185 +59163,28925,30083,40620 +59186,28926,30082,40296 +53441,28927,30081,40451 +51155,28928,30080,40835 +56944,28929,30079,40498 +55760,28930,30078,40297 +59370,28931,30077,40886 +54970,28932,30076,40562 +52653,28933,30075,40837 +51546,28934,30074,40832 +57059,28935,30073,40137 +58567,28936,30072,40147 +58520,28937,30071,40032 +56112,28938,30070,40215 +55993,28939,30069,40921 +57721,28940,30068,40653 +51207,28941,30067,40797 +59682,28942,30066,40539 +54554,28943,30065,40440 +56259,28944,30064,40256 +57106,28945,30063,40563 +54804,28946,30062,40832 +53689,28947,30061,40759 +52664,28948,30060,40928 +51429,28949,30059,40199 +53226,28950,30058,40519 +55465,28951,30057,40922 +55440,28952,30056,40082 +59243,28953,30055,40388 +56396,28954,30054,40218 +57776,28955,30053,40225 +51170,28956,30052,40355 +55220,28957,30051,40765 +51971,28958,30050,40148 +59350,28959,30049,40139 +55303,28960,30048,40046 +58383,28961,30047,40847 +53370,28962,30046,40018 +57779,28963,30045,40986 +56813,28964,30044,40676 +56320,28965,30043,40682 +50045,28966,30042,40526 +58851,28967,30041,40979 +59905,28968,30040,40458 +57115,28969,30039,40518 +55804,28970,30038,40728 +55749,28971,30037,40669 +53331,28972,30036,40856 +53654,28973,30035,40320 +53593,28974,30034,40829 +56775,28975,30033,40167 +59237,28976,30032,40359 +52346,28977,30031,40348 +59957,28978,30030,40938 +50811,28979,30029,40139 +54668,28980,30028,40016 +54098,28981,30027,40106 +59335,28982,30026,40552 +51093,28983,30025,40551 +52941,28984,30024,40849 +53979,28985,30023,40955 +58692,28986,30022,40743 +56491,28987,30021,40297 +52785,28988,30020,40168 +52546,28989,30019,40186 +55639,28990,30018,40388 +56259,28991,30017,40392 +52673,28992,30016,40263 +59704,28993,30015,40029 +58842,28994,30014,40557 +55591,28995,30013,40695 +54953,28996,30012,40976 +58177,28997,30011,40418 +52731,28998,30010,40881 +54564,28999,30009,40315 +59624,29000,30008,40049 +56527,29001,30007,40141 +53240,29002,30006,40514 +58182,29003,30005,40842 +54942,29004,30004,40023 +58395,29005,30003,40894 +57938,29006,30002,40220 +56108,29007,30001,40979 +55421,29008,30000,40964 +53213,29009,31000,40925 +52301,29010,30999,40173 +52106,29011,30998,40418 +50953,29012,30997,40802 +56574,29013,30996,40344 +54558,29014,30995,40677 +50114,29015,30994,40778 +54327,29016,30993,40374 +57149,29017,30992,40720 +55547,29018,30991,40989 +52457,29019,30990,40451 +57472,29020,30989,40104 +54310,29021,30988,40074 +53134,29022,30987,40873 +56072,29023,30986,40603 +54239,29024,30985,40319 +58012,29025,30984,40881 +57314,29026,30983,40408 +52200,29027,30982,40671 +53726,29028,30981,40944 +50624,29029,30980,40478 +59764,29030,30979,40736 +52132,29031,30978,40889 +53517,29032,30977,40982 +54486,29033,30976,40650 +58738,29034,30975,40972 +52074,29035,30974,40384 +53243,29036,30973,40712 +51447,29037,30972,40856 +58655,29038,30971,40680 +55626,29039,30970,40309 +51066,29040,30969,40375 +58121,29041,30968,40334 +59133,29042,30967,40648 +50277,29043,30966,40170 +59166,29044,30965,40326 +56488,29045,30964,40938 +50784,29046,30963,40278 +56590,29047,30962,40771 +50430,29048,30961,40995 +56049,29049,30960,40806 +51985,29050,30959,40603 +53628,29051,30958,40582 +50594,29052,30957,40442 +58641,29053,30956,40046 +56632,29054,30955,40043 +59254,29055,30954,40292 +59714,29056,30953,40534 +54009,29057,30952,40246 +52849,29058,30951,40787 +55253,29059,30950,40719 +53549,29060,30949,40186 +52013,29061,30948,40974 +53272,29062,30947,40660 +56052,29063,30946,40780 +54639,29064,30945,40009 +54175,29065,30944,40600 +50076,29066,30943,40167 +55139,29067,30942,40720 +58553,29068,30941,40355 +57464,29069,30940,40942 +59007,29070,30939,40504 +51919,29071,30938,40101 +50940,29072,30937,40561 +52672,29073,30936,40334 +58307,29074,30935,40956 +58411,29075,30934,40979 +58205,29076,30933,40734 +54496,29077,30932,40807 +56030,29078,30931,40773 +54971,29079,30930,40649 +54435,29080,30929,40813 +56759,29081,30928,40963 +50070,29082,30927,40090 +53283,29083,30926,40211 +52084,29084,30925,40399 +51825,29085,30924,40389 +55990,29086,30923,40698 +52475,29087,30922,40634 +52187,29088,30921,40116 +53249,29089,30920,40682 +58423,29090,30919,40608 +58989,29091,30918,40626 +59044,29092,30917,40030 +50280,29093,30916,40649 +54407,29094,30915,40309 +56405,29095,30914,40693 +53982,29096,30913,40723 +52267,29097,30912,40173 +54853,29098,30911,40978 +52784,29099,30910,40154 +58503,29100,30909,40378 +54752,29101,30908,40887 +51602,29102,30907,40612 +51853,29103,30906,40506 +57603,29104,30905,40354 +57168,29105,30904,40518 +58145,29106,30903,40833 +50126,29107,30902,40190 +53557,29108,30901,40032 +53367,29109,30900,40000 +51543,29110,30899,40008 +58215,29111,30898,40940 +53412,29112,30897,40839 +53983,29113,30896,40448 +50251,29114,30895,40130 +50734,29115,30894,40641 +58647,29116,30893,40527 +54312,29117,30892,40000 +51622,29118,30891,40221 +51769,29119,30890,40438 +50025,29120,30889,40936 +55459,29121,30888,40806 +53172,29122,30887,40548 +53490,29123,30886,40590 +54309,29124,30885,40566 +53969,29125,30884,40800 +53073,29126,30883,40642 +51494,29127,30882,40155 +50042,29128,30881,40916 +55976,29129,30880,40337 +54461,29130,30879,40982 +52385,29131,30878,40957 +58263,29132,30877,40579 +59422,29133,30876,40460 +54968,29134,30875,40518 +50227,29135,30874,40549 +59583,29136,30873,40338 +54235,29137,30872,40517 +58373,29138,30871,40102 +51565,29139,30870,40331 +54503,29140,30869,40172 +59867,29141,30868,40245 +53338,29142,30867,40759 +58596,29143,30866,40765 +56995,29144,30865,40919 +53561,29145,30864,40988 +58206,29146,30863,40443 +57277,29147,30862,40666 +54972,29148,30861,40433 +58437,29149,30860,40047 +54778,29150,30859,40532 +57407,29151,30858,40792 +56988,29152,30857,40219 +52079,29153,30856,40369 +51496,29154,30855,40746 +59427,29155,30854,40523 +58271,29156,30853,40943 +50392,29157,30852,40939 +54102,29158,30851,40516 +55991,29159,30850,40167 +52131,29160,30849,40964 +55623,29161,30848,40797 +50980,29162,30847,40315 +52118,29163,30846,40410 +50040,29164,30845,40430 +52226,29165,30844,40460 +55633,29166,30843,40444 +55649,29167,30842,40405 +59777,29168,30841,40688 +57216,29169,30840,40772 +57393,29170,30839,40700 +57017,29171,30838,40746 +52097,29172,30837,40635 +54861,29173,30836,40653 +51129,29174,30835,40195 +55889,29175,30834,40580 +53438,29176,30833,40110 +54134,29177,30832,40832 +53425,29178,30831,40636 +59664,29179,30830,40603 +52209,29180,30829,40710 +56248,29181,30828,40489 +56833,29182,30827,40433 +59821,29183,30826,40215 +50547,29184,30825,40436 +53893,29185,30824,40772 +55780,29186,30823,40800 +53601,29187,30822,40426 +50017,29188,30821,40244 +51182,29189,30820,40537 +58807,29190,30819,40778 +59048,29191,30818,40337 +51897,29192,30817,40250 +59049,29193,30816,40561 +51210,29194,30815,40376 +51519,29195,30814,40713 +54314,29196,30813,40988 +51836,29197,30812,40056 +54637,29198,30811,40118 +55431,29199,30810,40835 +59095,29200,30809,40476 +51375,29201,30808,40323 +56804,29202,30807,40962 +51792,29203,30806,40842 +58196,29204,30805,40629 +54190,29205,30804,40929 +50739,29206,30803,40068 +52702,29207,30802,40777 +53767,29208,30801,40731 +58772,29209,30800,40188 +50578,29210,30799,40541 +51527,29211,30798,40959 +57496,29212,30797,40717 +50001,29213,30796,40863 +53146,29214,30795,40137 +55363,29215,30794,40484 +55585,29216,30793,40468 +53909,29217,30792,40430 +53670,29218,30791,40879 +56458,29219,30790,40859 +52333,29220,30789,40067 +50514,29221,30788,40571 +58387,29222,30787,40573 +53321,29223,30786,40112 +51980,29224,30785,40782 +56813,29225,30784,40533 +57151,29226,30783,40334 +52140,29227,30782,40089 +51038,29228,30781,40957 +50796,29229,30780,40664 +58732,29230,30779,40070 +53285,29231,30778,40287 +59395,29232,30777,40632 +52361,29233,30776,40106 +56846,29234,30775,40417 +56019,29235,30774,40251 +57153,29236,30773,40850 +56941,29237,30772,40713 +50265,29238,30771,40185 +59899,29239,30770,40603 +56957,29240,30769,40967 +52117,29241,30768,40447 +59107,29242,30767,40887 +50435,29243,30766,40860 +58720,29244,30765,40391 +58976,29245,30764,40032 +50535,29246,30763,40447 +56753,29247,30762,40959 +54531,29248,30761,40379 +54111,29249,30760,40001 +54384,29250,30759,40606 +53103,29251,30758,40326 +57907,29252,30757,40813 +54243,29253,30756,40440 +54601,29254,30755,40317 +51258,29255,30754,40869 +56653,29256,30753,40850 +52082,29257,30752,40200 +59155,29258,30751,40485 +57230,29259,30750,40931 +57282,29260,30749,40832 +57794,29261,30748,40867 +53311,29262,30747,40945 +56043,29263,30746,40208 +51652,29264,30745,40586 +59228,29265,30744,40160 +57343,29266,30743,40489 +53939,29267,30742,40847 +57478,29268,30741,40209 +57338,29269,30740,40372 +59849,29270,30739,40779 +51049,29271,30738,40587 +58608,29272,30737,40042 +58296,29273,30736,40506 +53587,29274,30735,40810 +52082,29275,30734,40779 +52217,29276,30733,40556 +57334,29277,30732,40389 +53895,29278,30731,40641 +56199,29279,30730,40231 +50186,29280,30729,40344 +52051,29281,30728,40626 +58752,29282,30727,40694 +51697,29283,30726,40386 +51041,29284,30725,40801 +59955,29285,30724,40689 +55003,29286,30723,40233 +59595,29287,30722,40784 +52299,29288,30721,40996 +51306,29289,30720,40291 +54583,29290,30719,40340 +50564,29291,30718,40783 +51207,29292,30717,40142 +57327,29293,30716,40714 +52597,29294,30715,40578 +53177,29295,30714,40975 +54362,29296,30713,40538 +56489,29297,30712,40805 +56727,29298,30711,40577 +54926,29299,30710,40723 +52661,29300,30709,40770 +55653,29301,30708,40947 +51428,29302,30707,40266 +56966,29303,30706,40928 +53360,29304,30705,40939 +50829,29305,30704,40461 +58786,29306,30703,40110 +55526,29307,30702,40443 +57603,29308,30701,40555 +59105,29309,30700,40134 +51851,29310,30699,40696 +52134,29311,30698,40981 +55799,29312,30697,40308 +52946,29313,30696,40692 +58296,29314,30695,40895 +59935,29315,30694,40512 +53928,29316,30693,40728 +50625,29317,30692,40694 +58136,29318,30691,40098 +54765,29319,30690,40448 +57173,29320,30689,40260 +52276,29321,30688,40397 +55482,29322,30687,40868 +51597,29323,30686,40956 +53294,29324,30685,40951 +53793,29325,30684,40813 +55341,29326,30683,40535 +55344,29327,30682,40324 +50837,29328,30681,40689 +56257,29329,30680,40730 +54807,29330,30679,40882 +50966,29331,30678,40802 +51949,29332,30677,40895 +51918,29333,30676,40637 +57627,29334,30675,40621 +57396,29335,30674,40155 +56334,29336,30673,40571 +53316,29337,30672,40047 +56449,29338,30671,40770 +51902,29339,30670,40085 +54462,29340,30669,40389 +59635,29341,30668,40002 +54257,29342,30667,40539 +59564,29343,30666,40096 +52536,29344,30665,40439 +51739,29345,30664,40837 +51559,29346,30663,40568 +57977,29347,30662,40375 +51945,29348,30661,40498 +51086,29349,30660,40614 +51536,29350,30659,40304 +54622,29351,30658,40806 +56413,29352,30657,40683 +53921,29353,30656,40511 +52715,29354,30655,40644 +51531,29355,30654,40578 +54838,29356,30653,40442 +57450,29357,30652,40155 +54137,29358,30651,40953 +54783,29359,30650,40510 +51189,29360,30649,40383 +52115,29361,30648,40287 +57261,29362,30647,40604 +59498,29363,30646,40986 +52046,29364,30645,40109 +50549,29365,30644,40163 +52381,29366,30643,40429 +50081,29367,30642,40396 +51016,29368,30641,40857 +55629,29369,30640,40865 +50286,29370,30639,40798 +51482,29371,30638,40232 +58186,29372,30637,40466 +56987,29373,30636,40666 +59674,29374,30635,40443 +55115,29375,30634,40649 +58559,29376,30633,40904 +56205,29377,30632,40238 +55005,29378,30631,40458 +53103,29379,30630,40472 +54450,29380,30629,40726 +53512,29381,30628,40850 +53220,29382,30627,40722 +57440,29383,30626,40705 +54434,29384,30625,40961 +50655,29385,30624,40712 +59116,29386,30623,40269 +50285,29387,30622,40203 +59247,29388,30621,40896 +53161,29389,30620,40333 +55640,29390,30619,40319 +56629,29391,30618,40566 +58746,29392,30617,40756 +59438,29393,30616,40700 +53883,29394,30615,40350 +56362,29395,30614,40772 +56072,29396,30613,40079 +59402,29397,30612,40429 +54361,29398,30611,40730 +58863,29399,30610,40690 +55232,29400,30609,40366 +54665,29401,30608,40106 +59178,29402,30607,40980 +57866,29403,30606,40726 +53896,29404,30605,40969 +50617,29405,30604,40398 +55639,29406,30603,40456 +53666,29407,30602,40248 +54667,29408,30601,40504 +58010,29409,30600,40150 +53067,29410,30599,40380 +59057,29411,30598,40642 +59205,29412,30597,40285 +59232,29413,30596,40577 +56098,29414,30595,40001 +55586,29415,30594,40250 +52836,29416,30593,40829 +52239,29417,30592,40178 +53548,29418,30591,40511 +51683,29419,30590,40269 +57769,29420,30589,40281 +58990,29421,30588,40946 +50762,29422,30587,40482 +50196,29423,30586,40875 +50213,29424,30585,40055 +51092,29425,30584,40240 +56656,29426,30583,40457 +50470,29427,30582,40751 +57084,29428,30581,40187 +51758,29429,30580,40410 +57665,29430,30579,40835 +50925,29431,30578,40550 +58964,29432,30577,40330 +57766,29433,30576,40379 +59398,29434,30575,40778 +53214,29435,30574,40036 +53158,29436,30573,40787 +51901,29437,30572,40829 +56071,29438,30571,40025 +54273,29439,30570,40540 +58028,29440,30569,40566 +51281,29441,30568,40958 +52623,29442,30567,40824 +54287,29443,30566,40519 +58641,29444,30565,40574 +55223,29445,30564,40972 +54939,29446,30563,40252 +50804,29447,30562,40177 +58148,29448,30561,40545 +56306,29449,30560,40858 +51419,29450,30559,40025 +52254,29451,30558,40184 +55316,29452,30557,40220 +53129,29453,30556,40587 +51312,29454,30555,40794 +58459,29455,30554,40366 +57556,29456,30553,40225 +58629,29457,30552,40668 +50764,29458,30551,40220 +50335,29459,30550,40636 +53448,29460,30549,40146 +52607,29461,30548,40939 +56116,29462,30547,40409 +52123,29463,30546,40799 +51334,29464,30545,40813 +58950,29465,30544,40428 +59633,29466,30543,40264 +50614,29467,30542,40461 +50678,29468,30541,40295 +50983,29469,30540,40496 +50666,29470,30539,40199 +54168,29471,30538,40334 +56818,29472,30537,40219 +56434,29473,30536,40005 +50282,29474,30535,40163 +59465,29475,30534,40516 +55158,29476,30533,40706 +55035,29477,30532,40571 +50720,29478,30531,40764 +51478,29479,30530,40493 +53312,29480,30529,40146 +59094,29481,30528,40203 +55034,29482,30527,40380 +59996,29483,30526,40022 +59904,29484,30525,40113 +53498,29485,30524,40368 +51064,29486,30523,40814 +54810,29487,30522,40559 +51753,29488,30521,40585 +53455,29489,30520,40119 +54495,29490,30519,40744 +52451,29491,30518,40587 +51358,29492,30517,40051 +52463,29493,30516,40472 +57538,29494,30515,40755 +53353,29495,30514,40198 +56597,29496,30513,40438 +54152,29497,30512,40484 +52330,29498,30511,40904 +56547,29499,30510,40559 +52839,29500,30509,40870 +55479,29501,30508,40182 +55072,29502,30507,40074 +50967,29503,30506,40277 +58477,29504,30505,40295 +52334,29505,30504,40357 +54221,29506,30503,40496 +52144,29507,30502,40164 +55572,29508,30501,40841 +57934,29509,30500,40430 +57648,29510,30499,40273 +55272,29511,30498,40919 +58329,29512,30497,40355 +54397,29513,30496,40659 +53223,29514,30495,40767 +52302,29515,30494,40421 +57470,29516,30493,40114 +53665,29517,30492,40248 +53284,29518,30491,40519 +54370,29519,30490,40229 +54739,29520,30489,40000 +50803,29521,30488,40130 +50185,29522,30487,40645 +51411,29523,30486,40115 +50268,29524,30485,40407 +52765,29525,30484,40640 +55420,29526,30483,40130 +57703,29527,30482,40219 +56465,29528,30481,40085 +58331,29529,30480,40996 +59603,29530,30479,40303 +50611,29531,30478,40931 +51625,29532,30477,40848 +59149,29533,30476,40825 +53865,29534,30475,40225 +59438,29535,30474,40155 +51709,29536,30473,40185 +59235,29537,30472,40099 +51399,29538,30471,40917 +51506,29539,30470,40509 +52827,29540,30469,40250 +51647,29541,30468,40196 +58395,29542,30467,40202 +50923,29543,30466,40350 +56144,29544,30465,40713 +50582,29545,30464,40275 +54467,29546,30463,40924 +53845,29547,30462,40405 +57724,29548,30461,40181 +55215,29549,30460,40164 +54562,29550,30459,40124 +52561,29551,30458,40633 +54033,29552,30457,40029 +50834,29553,30456,40293 +58778,29554,30455,40426 +59168,29555,30454,40533 +57236,29556,30453,40118 +52329,29557,30452,40956 +54064,29558,30451,40446 +54054,29559,30450,40085 +50762,29560,30449,40203 +53489,29561,30448,40323 +53691,29562,30447,40824 +57928,29563,30446,40720 +54988,29564,30445,40044 +55130,29565,30444,40494 +56197,29566,30443,40869 +50942,29567,30442,40389 +59267,29568,30441,40922 +59123,29569,30440,40154 +58520,29570,30439,40530 +54849,29571,30438,40384 +50379,29572,30437,40830 +51566,29573,30436,40797 +55649,29574,30435,40000 +59053,29575,30434,40532 +52404,29576,30433,40367 +58657,29577,30432,40378 +52815,29578,30431,40536 +55376,29579,30430,40167 +51740,29580,30429,40235 +54546,29581,30428,40995 +54164,29582,30427,40878 +56361,29583,30426,40995 +52870,29584,30425,40274 +55370,29585,30424,40863 +56115,29586,30423,40008 +52505,29587,30422,40441 +59589,29588,30421,40631 +54707,29589,30420,40131 +50192,29590,30419,40406 +50644,29591,30418,40485 +54273,29592,30417,40272 +56650,29593,30416,40531 +53747,29594,30415,40801 +50689,29595,30414,40975 +57184,29596,30413,40115 +50076,29597,30412,40720 +59652,29598,30411,40285 +50261,29599,30410,40222 +52589,29600,30409,40801 +51420,29601,30408,40528 +53775,29602,30407,40961 +50508,29603,30406,40580 +55733,29604,30405,40285 +50731,29605,30404,40099 +53762,29606,30403,40611 +53904,29607,30402,40638 +58709,29608,30401,40211 +59358,29609,30400,40649 +53770,29610,30399,40990 +52495,29611,30398,40355 +50445,29612,30397,40627 +58012,29613,30396,40927 +56041,29614,30395,40709 +50232,29615,30394,40610 +52991,29616,30393,40405 +59885,29617,30392,40889 +53906,29618,30391,40575 +59534,29619,30390,40182 +55679,29620,30389,40755 +59979,29621,30388,40902 +55450,29622,30387,40147 +59555,29623,30386,40619 +50980,29624,30385,40588 +56052,29625,30384,40553 +50825,29626,30383,40387 +53326,29627,30382,40271 +52725,29628,30381,40437 +59221,29629,30380,40293 +55959,29630,30379,40690 +55925,29631,30378,40684 +59245,29632,30377,40399 +52320,29633,30376,40949 +53279,29634,30375,40127 +59811,29635,30374,40994 +51240,29636,30373,40518 +54503,29637,30372,40651 +53886,29638,30371,40986 +55154,29639,30370,40479 +54067,29640,30369,40718 +57502,29641,30368,40328 +58388,29642,30367,40188 +57218,29643,30366,40032 +54974,29644,30365,40934 +50540,29645,30364,40069 +58113,29646,30363,40489 +54608,29647,30362,40511 +53901,29648,30361,40870 +52058,29649,30360,40178 +51497,29650,30359,40334 +54399,29651,30358,40325 +51138,29652,30357,40978 +51234,29653,30356,40285 +55248,29654,30355,40732 +55746,29655,30354,40550 +50981,29656,30353,40310 +55552,29657,30352,40576 +54734,29658,30351,40893 +57647,29659,30350,40954 +55836,29660,30349,40937 +58692,29661,30348,40821 +54780,29662,30347,40244 +50621,29663,30346,40543 +53858,29664,30345,40556 +54206,29665,30344,40171 +54629,29666,30343,40343 +51830,29667,30342,40922 +58515,29668,30341,40642 +55072,29669,30340,40528 +57445,29670,30339,40326 +53237,29671,30338,40197 +50910,29672,30337,40447 +50895,29673,30336,40054 +58285,29674,30335,40826 +59513,29675,30334,40143 +50641,29676,30333,40139 +50706,29677,30332,40760 +55292,29678,30331,40857 +59056,29679,30330,40633 +50192,29680,30329,40566 +53825,29681,30328,40883 +50423,29682,30327,40134 +53836,29683,30326,40885 +58751,29684,30325,40811 +52774,29685,30324,40520 +59441,29686,30323,40786 +56065,29687,30322,40431 +54658,29688,30321,40663 +57103,29689,30320,40374 +59907,29690,30319,40104 +59828,29691,30318,40525 +51635,29692,30317,40912 +51449,29693,30316,40305 +58549,29694,30315,40986 +51581,29695,30314,40217 +51020,29696,30313,40328 +56806,29697,30312,40552 +56930,29698,30311,40151 +52565,29699,30310,40675 +50120,29700,30309,40137 +53368,29701,30308,40008 +54040,29702,30307,40526 +56632,29703,30306,40353 +56614,29704,30305,40047 +53811,29705,30304,40308 +59669,29706,30303,40098 +54212,29707,30302,40648 +55462,29708,30301,40251 +55774,29709,30300,40006 +59642,29710,30299,40309 +55416,29711,30298,40009 +58969,29712,30297,40661 +55282,29713,30296,40364 +56236,29714,30295,40398 +52757,29715,30294,40631 +52884,29716,30293,40231 +59241,29717,30292,40093 +53933,29718,30291,40053 +52816,29719,30290,40510 +53309,29720,30289,40862 +51567,29721,30288,40459 +53127,29722,30287,40148 +51965,29723,30286,40419 +51068,29724,30285,40625 +56020,29725,30284,40217 +52673,29726,30283,40781 +59173,29727,30282,40536 +52635,29728,30281,40146 +57496,29729,30280,40300 +54423,29730,30279,40304 +59760,29731,30278,40462 +53094,29732,30277,40146 +55517,29733,30276,40124 +55797,29734,30275,40835 +51707,29735,30274,40506 +59451,29736,30273,40294 +54072,29737,30272,40425 +58412,29738,30271,40434 +52611,29739,30270,40458 +57707,29740,30269,40774 +58592,29741,30268,40608 +59692,29742,30267,40846 +56312,29743,30266,40575 +52647,29744,30265,40794 +50445,29745,30264,40356 +59352,29746,30263,40271 +55339,29747,30262,40835 +57539,29748,30261,40901 +53881,29749,30260,40327 +54948,29750,30259,40853 +59183,29751,30258,40402 +59605,29752,30257,40196 +59378,29753,30256,40193 +57577,29754,30255,40392 +56299,29755,30254,40266 +59446,29756,30253,40005 +59669,29757,30252,40605 +58416,29758,30251,40725 +51813,29759,30250,40020 +53471,29760,30249,40538 +54276,29761,30248,40880 +57378,29762,30247,40129 +52024,29763,30246,40178 +59757,29764,30245,40701 +52801,29765,30244,40875 +53454,29766,30243,40125 +54543,29767,30242,40305 +50990,29768,30241,40619 +54704,29769,30240,40454 +51315,29770,30239,40626 +58503,29771,30238,40694 +51793,29772,30237,40387 +59864,29773,30236,40133 +57952,29774,30235,40940 +51056,29775,30234,40370 +53609,29776,30233,40318 +52978,29777,30232,40772 +56939,29778,30231,40377 +56076,29779,30230,40048 +59898,29780,30229,40382 +58552,29781,30228,40460 +52455,29782,30227,40169 +50030,29783,30226,40811 +50986,29784,30225,40313 +58583,29785,30224,40622 +57931,29786,30223,40381 +54940,29787,30222,40787 +52129,29788,30221,40308 +58957,29789,30220,40292 +51410,29790,30219,40505 +56381,29791,30218,40990 +55865,29792,30217,40170 +56955,29793,30216,40020 +53909,29794,30215,40627 +55468,29795,30214,40000 +54830,29796,30213,40196 +59939,29797,30212,40006 +55234,29798,30211,40779 +54482,29799,30210,40413 +53054,29800,30209,40623 +59194,29801,30208,40459 +56648,29802,30207,40915 +50655,29803,30206,40908 +55769,29804,30205,40299 +50519,29805,30204,40510 +54760,29806,30203,40359 +55985,29807,30202,40523 +57073,29808,30201,40729 +58242,29809,30200,40580 +55589,29810,30199,40139 +59994,29811,30198,40679 +59259,29812,30197,40586 +57461,29813,30196,40061 +50852,29814,30195,40633 +59150,29815,30194,40331 +55596,29816,30193,40236 +55566,29817,30192,40954 +57036,29818,30191,40202 +52274,29819,30190,40533 +50429,29820,30189,40453 +52026,29821,30188,40807 +58119,29822,30187,40098 +51310,29823,30186,40958 +57911,29824,30185,40031 +53835,29825,30184,40408 +53631,29826,30183,40366 +56539,29827,30182,40408 +58055,29828,30181,40245 +56995,29829,30180,40693 +50289,29830,30179,40790 +52246,29831,30178,40312 +50058,29832,30177,40370 +54966,29833,30176,40383 +57245,29834,30175,40117 +59722,29835,30174,40459 +52673,29836,30173,40046 +59451,29837,30172,40826 +57619,29838,30171,40198 +52185,29839,30170,40442 +52974,29840,30169,40082 +52731,29841,30168,40131 +52198,29842,30167,40366 +54580,29843,30166,40648 +57813,29844,30165,40512 +55344,29845,30164,40346 +59629,29846,30163,40791 +52829,29847,30162,40336 +59260,29848,30161,40534 +53975,29849,30160,40574 +56477,29850,30159,40008 +57452,29851,30158,40953 +57354,29852,30157,40753 +50046,29853,30156,40517 +59823,29854,30155,40599 +51526,29855,30154,40507 +58235,29856,30153,40308 +56486,29857,30152,40763 +59408,29858,30151,40401 +54951,29859,30150,40361 +56793,29860,30149,40760 +58417,29861,30148,40087 +56571,29862,30147,40766 +52601,29863,30146,40399 +53204,29864,30145,40483 +56820,29865,30144,40347 +54624,29866,30143,40295 +52554,29867,30142,40155 +57147,29868,30141,40371 +57718,29869,30140,40746 +58625,29870,30139,40586 +54010,29871,30138,40750 +57008,29872,30137,40546 +57951,29873,30136,40866 +54943,29874,30135,40690 +53578,29875,30134,40490 +56936,29876,30133,40713 +59385,29877,30132,40410 +54928,29878,30131,40792 +53389,29879,30130,40258 +54184,29880,30129,40046 +59970,29881,30128,40746 +56028,29882,30127,40207 +54970,29883,30126,40070 +50616,29884,30125,40128 +57672,29885,30124,40215 +57259,29886,30123,40041 +51607,29887,30122,40862 +56003,29888,30121,40151 +57307,29889,30120,40061 +50136,29890,30119,40997 +54687,29891,30118,40388 +51413,29892,30117,40454 +55005,29893,30116,40885 +56096,29894,30115,40554 +50653,29895,30114,40437 +57467,29896,30113,40619 +55877,29897,30112,40631 +53091,29898,30111,40363 +59166,29899,30110,40918 +59430,29900,30109,40907 +57159,29901,30108,40190 +59282,29902,30107,40002 +57683,29903,30106,40416 +57992,29904,30105,40048 +59789,29905,30104,40225 +51391,29906,30103,40030 +59932,29907,30102,40725 +52500,29908,30101,40373 +55569,29909,30100,40669 +53919,29910,30099,40303 +55517,29911,30098,40011 +50466,29912,30097,40933 +59328,29913,30096,40341 +54154,29914,30095,40158 +53452,29915,30094,40966 +57624,29916,30093,40657 +53608,29917,30092,40597 +59129,29918,30091,40048 +50656,29919,30090,40351 +58337,29920,30089,40609 +58010,29921,30088,40784 +57959,29922,30087,40721 +53347,29923,30086,40585 +56874,29924,30085,40439 +52072,29925,30084,40750 +53825,29926,30083,40075 +56337,29927,30082,40952 +54783,29928,30081,40385 +53895,29929,30080,40738 +53797,29930,30079,40222 +50630,29931,30078,40834 +52978,29932,30077,40470 +55470,29933,30076,40926 +55286,29934,30075,40287 +52579,29935,30074,40919 +50724,29936,30073,40597 +57861,29937,30072,40063 +59413,29938,30071,40915 +56810,29939,30070,40843 +51097,29940,30069,40187 +59718,29941,30068,40917 +56297,29942,30067,40962 +58925,29943,30066,40784 +56616,29944,30065,40635 +52751,29945,30064,40184 +53880,29946,30063,40078 +50882,29947,30062,40222 +55720,29948,30061,40621 +59246,29949,30060,40614 +55867,29950,30059,40531 +50929,29951,30058,40741 +58628,29952,30057,40577 +57123,29953,30056,40314 +55581,29954,30055,40695 +57683,29955,30054,40583 +51832,29956,30053,40851 +58640,29957,30052,40300 +58268,29958,30051,40472 +52533,29959,30050,40616 +56513,29960,30049,40526 +54988,29961,30048,40909 +56070,29962,30047,40306 +54227,29963,30046,40351 +59343,29964,30045,40915 +58539,29965,30044,40017 +53037,29966,30043,40248 +58012,29967,30042,40445 +50582,29968,30041,40457 +57655,29969,30040,40797 +52659,29970,30039,40712 +55076,29971,30038,40898 +58120,29972,30037,40972 +51082,29973,30036,40344 +51422,29974,30035,40466 +58269,29975,30034,40188 +52892,29976,30033,40279 +55617,29977,30032,40547 +50517,29978,30031,40375 +53324,29979,30030,40345 +56170,29980,30029,40875 +56458,29981,30028,40019 +55376,29982,30027,40523 +58186,29983,30026,40529 +56588,29984,30025,40960 +57590,29985,30024,40307 +52603,29986,30023,40156 +50176,29987,30022,40727 +58399,29988,30021,40569 +51079,29989,30020,40404 +53139,29990,30019,40418 +54089,29991,30018,40831 +57631,29992,30017,40186 +54466,29993,30016,40415 +55191,29994,30015,40727 +56803,29995,30014,40215 +50317,29996,30013,40723 +56398,29997,30012,40239 +54488,29998,30011,40495 +55390,29999,30010,40223 +52796,30000,30009,40939 +54403,30001,30008,40994 +52344,30002,30007,40774 +52490,30003,30006,40675 +53103,30004,30005,40663 +52492,30005,30004,40718 +50702,30006,30003,40558 +58573,30007,30002,40685 +53645,30008,30001,40634 +56996,30009,30000,40669 +51249,30010,31000,40376 +58331,30011,30999,40381 +59997,30012,30998,40420 +59004,30013,30997,40411 +50504,30014,30996,40696 +51195,30015,30995,40155 +52042,30016,30994,40446 +59747,30017,30993,40324 +55472,30018,30992,40187 +58280,30019,30991,40217 +54831,30020,30990,40722 +56828,30021,30989,40705 +50725,30022,30988,40737 +57757,30023,30987,40867 +53594,30024,30986,40156 +50491,30025,30985,40193 +55542,30026,30984,40805 +58103,30027,30983,40368 +53693,30028,30982,40213 +53735,30029,30981,40818 +59125,30030,30980,40162 +50471,30031,30979,40960 +58872,30032,30978,40164 +59753,30033,30977,40991 +57253,30034,30976,40197 +57597,30035,30975,40645 +51392,30036,30974,40805 +55771,30037,30973,40880 +59258,30038,30972,40879 +59677,30039,30971,40556 +54235,30040,30970,40284 +56634,30041,30969,40375 +51851,30042,30968,40082 +52781,30043,30967,40107 +58257,30044,30966,40304 +52148,30045,30965,40143 +54723,30046,30964,40609 +54853,30047,30963,40410 +57740,30048,30962,40138 +56154,30049,30961,40669 +58475,30050,30960,40450 +57293,30051,30959,40348 +56296,30052,30958,40637 +53503,30053,30957,40977 +56177,30054,30956,40645 +59393,30055,30955,40388 +50947,30056,30954,40669 +51222,30057,30953,40259 +54677,30058,30952,40283 +55952,30059,30951,40178 +59117,30060,30950,40954 +56727,30061,30949,40552 +55110,30062,30948,40977 +58296,30063,30947,40294 +54857,30064,30946,40268 +53818,30065,30945,40363 +57352,30066,30944,40140 +52508,30067,30943,40065 +54954,30068,30942,40726 +55481,30069,30941,40446 +55664,30070,30940,40189 +52542,30071,30939,40344 +59798,30072,30938,40644 +52146,30073,30937,40825 +59046,30074,30936,40772 +57172,30075,30935,40474 +59702,30076,30934,40254 +58595,30077,30933,40895 +54129,30078,30932,40223 +53270,30079,30931,40887 +53091,30080,30930,40101 +56396,30081,30929,40846 +54574,30082,30928,40849 +58717,30083,30927,40592 +59258,30084,30926,40707 +57152,30085,30925,40932 +58249,30086,30924,40084 +56662,30087,30923,40011 +57897,30088,30922,40173 +52755,30089,30921,40572 +52882,30090,30920,40034 +51405,30091,30919,40166 +54735,30092,30918,40970 +56316,30093,30917,40081 +54969,30094,30916,40053 +58082,30095,30915,40697 +56063,30096,30914,40986 +54612,30097,30913,40256 +55618,30098,30912,40060 +58614,30099,30911,40110 +56813,30100,30910,40441 +51686,30101,30909,40480 +56258,30102,30908,40335 +53758,30103,30907,40162 +51279,30104,30906,40835 +52412,30105,30905,40954 +56335,30106,30904,40583 +56223,30107,30903,40027 +59228,30108,30902,40167 +56280,30109,30901,40754 +53187,30110,30900,40153 +55664,30111,30899,40097 +57040,30112,30898,40575 +51032,30113,30897,40870 +55384,30114,30896,40634 +55898,30115,30895,40663 +59606,30116,30894,40276 +54127,30117,30893,40356 +57165,30118,30892,40497 +56170,30119,30891,40648 +53916,30120,30890,40483 +57154,30121,30889,40925 +55423,30122,30888,40857 +58462,30123,30887,40292 +50274,30124,30886,40804 +53224,30125,30885,40894 +51264,30126,30884,40590 +54563,30127,30883,40170 +58922,30128,30882,40095 +50985,30129,30881,40140 +50772,30130,30880,40557 +52141,30131,30879,40797 +51801,30132,30878,40767 +59984,30133,30877,40669 +56702,30134,30876,40006 +55439,30135,30875,40258 +50484,30136,30874,40057 +57417,30137,30873,40995 +53591,30138,30872,40643 +57694,30139,30871,40821 +57364,30140,30870,40211 +52482,30141,30869,40969 +53959,30142,30868,40768 +57617,30143,30867,40561 +51730,30144,30866,40103 +50925,30145,30865,40957 +53961,30146,30864,40226 +52323,30147,30863,40415 +57914,30148,30862,40327 +50220,30149,30861,40079 +53531,30150,30860,40794 +52591,30151,30859,40651 +59436,30152,30858,40960 +54100,30153,30857,40686 +53931,30154,30856,40897 +57395,30155,30855,40915 +52806,30156,30854,40017 +53050,30157,30853,40359 +53162,30158,30852,40379 +52013,30159,30851,40961 +50234,30160,30850,40170 +56584,30161,30849,40023 +59036,30162,30848,40782 +57088,30163,30847,40590 +50110,30164,30846,40047 +53400,30165,30845,40525 +56358,30166,30844,40226 +58848,30167,30843,40439 +51591,30168,30842,40285 +55351,30169,30841,40851 +55662,30170,30840,40823 +50225,30171,30839,40666 +57836,30172,30838,40193 +50739,30173,30837,40500 +50031,30174,30836,40324 +55147,30175,30835,40991 +51801,30176,30834,40406 +56669,30177,30833,40309 +58369,30178,30832,40324 +56376,30179,30831,40384 +53048,30180,30830,40141 +59768,30181,30829,40293 +56276,30182,30828,40728 +53972,30183,30827,40867 +50921,30184,30826,40315 +56151,30185,30825,40102 +59526,30186,30824,40674 +57228,30187,30823,40964 +55307,30188,30822,40368 +58514,30189,30821,40964 +57576,30190,30820,40389 +59167,30191,30819,40382 +54496,30192,30818,40092 +55553,30193,30817,40514 +53292,30194,30816,40056 +58959,30195,30815,40441 +59868,30196,30814,40683 +50591,30197,30813,40386 +56137,30198,30812,40522 +51521,30199,30811,40170 +52614,30200,30810,40935 +59687,30201,30809,40387 +55541,30202,30808,40644 +54920,30203,30807,40863 +57942,30204,30806,40730 +56778,30205,30805,40946 +55801,30206,30804,40068 +56845,30207,30803,40962 +52580,30208,30802,40035 +51495,30209,30801,40268 +52641,30210,30800,40734 +57818,30211,30799,40163 +58303,30212,30798,40917 +54849,30213,30797,40295 +54201,30214,30796,40507 +57145,30215,30795,40776 +56035,30216,30794,40669 +55869,30217,30793,40630 +59680,30218,30792,40379 +56297,30219,30791,40367 +56945,30220,30790,40786 +53680,30221,30789,40468 +53912,30222,30788,40796 +58713,30223,30787,40704 +58618,30224,30786,40741 +51028,30225,30785,40669 +59363,30226,30784,40154 +50475,30227,30783,40685 +58868,30228,30782,40736 +55907,30229,30781,40082 +52935,30230,30780,40654 +50962,30231,30779,40466 +50499,30232,30778,40625 +59050,30233,30777,40627 +52091,30234,30776,40850 +52307,30235,30775,40687 +50640,30236,30774,40901 +59015,30237,30773,40684 +56695,30238,30772,40017 +54359,30239,30771,40867 +53910,30240,30770,40535 +57115,30241,30769,40986 +58519,30242,30768,40297 +58007,30243,30767,40872 +56831,30244,30766,40848 +59865,30245,30765,40789 +57624,30246,30764,40746 +51342,30247,30763,40908 +58650,30248,30762,40182 +51956,30249,30761,40654 +54105,30250,30760,40325 +52906,30251,30759,40987 +56168,30252,30758,40079 +58964,30253,30757,40319 +57979,30254,30756,40039 +54043,30255,30755,40855 +50138,30256,30754,40268 +59009,30257,30753,40935 +53345,30258,30752,40453 +53474,30259,30751,40554 +52612,30260,30750,40641 +50374,30261,30749,40525 +54720,30262,30748,40960 +52643,30263,30747,40928 +58061,30264,30746,40009 +51519,30265,30745,40922 +58688,30266,30744,40952 +57507,30267,30743,40184 +54044,30268,30742,40835 +59963,30269,30741,40153 +56632,30270,30740,40882 +55417,30271,30739,40409 +57452,30272,30738,40218 +52106,30273,30737,40056 +54597,30274,30736,40364 +50912,30275,30735,40303 +56904,30276,30734,40566 +59727,30277,30733,40638 +53523,30278,30732,40333 +56243,30279,30731,40149 +56783,30280,30730,40989 +51854,30281,30729,40397 +54258,30282,30728,40064 +55952,30283,30727,40585 +54704,30284,30726,40079 +54350,30285,30725,40983 +50322,30286,30724,40975 +53269,30287,30723,40085 +53759,30288,30722,40970 +55033,30289,30721,40305 +59718,30290,30720,40985 +58214,30291,30719,40138 +59630,30292,30718,40628 +55335,30293,30717,40092 +55845,30294,30716,40846 +57284,30295,30715,40348 +57252,30296,30714,40775 +56326,30297,30713,40273 +55476,30298,30712,40167 +51718,30299,30711,40531 +55337,30300,30710,40188 +56788,30301,30709,40227 +58300,30302,30708,40969 +56132,30303,30707,40141 +55047,30304,30706,40739 +56738,30305,30705,40702 +57178,30306,30704,40080 +57862,30307,30703,40919 +50922,30308,30702,40798 +50850,30309,30701,40699 +52649,30310,30700,40430 +54713,30311,30699,40507 +56721,30312,30698,40307 +52410,30313,30697,40763 +52937,30314,30696,40419 +51865,30315,30695,40985 +58698,30316,30694,40585 +51759,30317,30693,40825 +51947,30318,30692,40515 +55096,30319,30691,40888 +52329,30320,30690,40495 +53514,30321,30689,40307 +50499,30322,30688,40165 +54389,30323,30687,40475 +55937,30324,30686,40017 +52550,30325,30685,40791 +50436,30326,30684,40017 +56213,30327,30683,40918 +57928,30328,30682,40549 +57279,30329,30681,40376 +52535,30330,30680,40135 +57454,30331,30679,40719 +54791,30332,30678,40312 +59011,30333,30677,40671 +58803,30334,30676,40571 +55846,30335,30675,40375 +54200,30336,30674,40755 +56021,30337,30673,40476 +51237,30338,30672,40797 +54968,30339,30671,40417 +54390,30340,30670,40937 +53061,30341,30669,40156 +53786,30342,30668,40451 +56318,30343,30667,40319 +53599,30344,30666,40488 +58888,30345,30665,40370 +51024,30346,30664,40079 +58007,30347,30663,40154 +51013,30348,30662,40813 +52789,30349,30661,40328 +58136,30350,30660,40253 +51010,30351,30659,40496 +56024,30352,30658,40370 +52598,30353,30657,40220 +58822,30354,30656,40914 +53201,30355,30655,40341 +58525,30356,30654,40306 +52371,30357,30653,40470 +55759,30358,30652,40144 +58583,30359,30651,40477 +56586,30360,30650,40817 +54394,30361,30649,40710 +57609,30362,30648,40791 +58202,30363,30647,40677 +51510,30364,30646,40501 +57241,30365,30645,40992 +56222,30366,30644,40459 +50321,30367,30643,40247 +51901,30368,30642,40729 +58113,30369,30641,40441 +54872,30370,30640,40122 +58758,30371,30639,40660 +51210,30372,30638,40519 +59573,30373,30637,40472 +54454,30374,30636,40188 +50004,30375,30635,40001 +50187,30376,30634,40059 +50168,30377,30633,40024 +56198,30378,30632,40747 +54137,30379,30631,40845 +55952,30380,30630,40036 +58322,30381,30629,40442 +52344,30382,30628,40218 +58389,30383,30627,40574 +50684,30384,30626,40852 +58971,30385,30625,40189 +54385,30386,30624,40264 +59257,30387,30623,40521 +50706,30388,30622,40389 +52014,30389,30621,40104 +58372,30390,30620,40916 +59497,30391,30619,40025 +56008,30392,30618,40899 +54679,30393,30617,40171 +57450,30394,30616,40151 +53594,30395,30615,40189 +51975,30396,30614,40694 +58229,30397,30613,40476 +52619,30398,30612,40391 +55699,30399,30611,40452 +55592,30400,30610,40006 +55544,30401,30609,40285 +56675,30402,30608,40808 +50831,30403,30607,40065 +59080,30404,30606,40615 +59779,30405,30605,40144 +54285,30406,30604,40322 +58618,30407,30603,40489 +53748,30408,30602,40493 +50394,30409,30601,40469 +50554,30410,30600,40912 +51279,30411,30599,40257 +59741,30412,30598,40798 +59029,30413,30597,40328 +59131,30414,30596,40741 +55456,30415,30595,40586 +57877,30416,30594,40220 +52651,30417,30593,40374 +57090,30418,30592,40710 +59869,30419,30591,40415 +51072,30420,30590,40530 +50151,30421,30589,40589 +56613,30422,30588,40180 +55402,30423,30587,40907 +52180,30424,30586,40164 +54646,30425,30585,40281 +54667,30426,30584,40713 +51838,30427,30583,40078 +54904,30428,30582,40833 +52599,30429,30581,40395 +54188,30430,30580,40072 +53518,30431,30579,40894 +53272,30432,30578,40498 +56393,30433,30577,40978 +54708,30434,30576,40086 +59910,30435,30575,40952 +55662,30436,30574,40842 +57535,30437,30573,40644 +53904,30438,30572,40013 +56927,30439,30571,40646 +53002,30440,30570,40477 +55183,30441,30569,40394 +51150,30442,30568,40934 +51369,30443,30567,40743 +55307,30444,30566,40323 +56798,30445,30565,40481 +51649,30446,30564,40676 +56211,30447,30563,40372 +57764,30448,30562,40804 +55509,30449,30561,40534 +55259,30450,30560,40533 +53373,30451,30559,40078 +57959,30452,30558,40002 +58767,30453,30557,40799 +58577,30454,30556,40169 +55804,30455,30555,40555 +56700,30456,30554,40764 +57384,30457,30553,40934 +59946,30458,30552,40763 +54006,30459,30551,40713 +54331,30460,30550,40447 +56319,30461,30549,40990 +59727,30462,30548,40253 +56497,30463,30547,40431 +54525,30464,30546,40581 +59092,30465,30545,40758 +54764,30466,30544,40974 +55608,30467,30543,40512 +52158,30468,30542,40927 +53882,30469,30541,40235 +57421,30470,30540,40349 +53509,30471,30539,40640 +51406,30472,30538,40916 +58741,30473,30537,40351 +50386,30474,30536,40172 +50647,30475,30535,40999 +57162,30476,30534,40018 +58829,30477,30533,40350 +56395,30478,30532,40087 +56270,30479,30531,40227 +50983,30480,30530,40801 +50585,30481,30529,40301 +55563,30482,30528,40084 +56601,30483,30527,40119 +58344,30484,30526,40933 +59572,30485,30525,40844 +58184,30486,30524,40875 +58718,30487,30523,40681 +54578,30488,30522,40266 +52428,30489,30521,40899 +53433,30490,30520,40253 +53698,30491,30519,40365 +59934,30492,30518,40191 +53901,30493,30517,40141 +58966,30494,30516,40751 +56188,30495,30515,40452 +59751,30496,30514,40902 +59081,30497,30513,40265 +59404,30498,30512,40429 +53126,30499,30511,40986 +58599,30500,30510,40488 +59859,30501,30509,40038 +58550,30502,30508,40593 +56939,30503,30507,40529 +54990,30504,30506,40562 +55422,30505,30505,40940 +56484,30506,30504,40955 +58426,30507,30503,40352 +52731,30508,30502,40948 +51826,30509,30501,40991 +57111,30510,30500,40303 +53265,30511,30499,40768 +56992,30512,30498,40782 +54199,30513,30497,40941 +52114,30514,30496,40228 +50434,30515,30495,40858 +51425,30516,30494,40067 +51336,30517,30493,40068 +54986,30518,30492,40985 +50561,30519,30491,40308 +54821,30520,30490,40383 +54657,30521,30489,40279 +52423,30522,30488,40937 +55859,30523,30487,40131 +50995,30524,30486,40899 +56161,30525,30485,40528 +52864,30526,30484,40781 +57071,30527,30483,40160 +53830,30528,30482,40157 +52728,30529,30481,40412 +52498,30530,30480,40486 +59793,30531,30479,40045 +58297,30532,30478,40530 +54697,30533,30477,40188 +57626,30534,30476,40625 +53026,30535,30475,40750 +53819,30536,30474,40950 +54201,30537,30473,40848 +52997,30538,30472,40586 +51360,30539,30471,40667 +52572,30540,30470,40216 +51566,30541,30469,40803 +50422,30542,30468,40828 +54508,30543,30467,40482 +54126,30544,30466,40329 +51680,30545,30465,40500 +57408,30546,30464,40101 +57334,30547,30463,40638 +53940,30548,30462,40195 +50826,30549,30461,40080 +57592,30550,30460,40548 +55187,30551,30459,40437 +50053,30552,30458,40371 +54105,30553,30457,40243 +55508,30554,30456,40820 +50151,30555,30455,40523 +52201,30556,30454,40944 +54427,30557,30453,40126 +51053,30558,30452,40856 +51435,30559,30451,40561 +58122,30560,30450,40780 +54866,30561,30449,40983 +58336,30562,30448,40639 +55223,30563,30447,40610 +53205,30564,30446,40648 +56814,30565,30445,40910 +57784,30566,30444,40311 +53896,30567,30443,40946 +55302,30568,30442,40505 +58406,30569,30441,40620 +58406,30570,30440,40435 +57691,30571,30439,40567 +59887,30572,30438,40615 +54319,30573,30437,40011 +53321,30574,30436,40166 +58271,30575,30435,40658 +58816,30576,30434,40066 +54946,30577,30433,40042 +52293,30578,30432,40782 +54135,30579,30431,40572 +52736,30580,30430,40333 +55610,30581,30429,40864 +58816,30582,30428,40324 +50197,30583,30427,40195 +56226,30584,30426,40229 +50323,30585,30425,40310 +57504,30586,30424,40017 +52416,30587,30423,40620 +59424,30588,30422,40473 +54588,30589,30421,40488 +51134,30590,30420,40480 +53406,30591,30419,40976 +56900,30592,30418,40128 +54533,30593,30417,40978 +57045,30594,30416,40448 +53338,30595,30415,40297 +53705,30596,30414,40344 +57473,30597,30413,40852 +52866,30598,30412,40057 +50575,30599,30411,40219 +53822,30600,30410,40243 +57429,30601,30409,40167 +56501,30602,30408,40115 +53338,30603,30407,40461 +54450,30604,30406,40481 +51895,30605,30405,40927 +56159,30606,30404,40204 +56923,30607,30403,40927 +52073,30608,30402,40482 +58175,30609,30401,40329 +54146,30610,30400,40528 +50452,30611,30399,40732 +57445,30612,30398,40683 +56824,30613,30397,40748 +51876,30614,30396,40976 +54152,30615,30395,40087 +53117,30616,30394,40574 +58607,30617,30393,40201 +54475,30618,30392,40022 +58109,30619,30391,40671 +53705,30620,30390,40292 +53123,30621,30389,40173 +58065,30622,30388,40629 +54842,30623,30387,40508 +59282,30624,30386,40004 +57043,30625,30385,40036 +51873,30626,30384,40403 +58809,30627,30383,40705 +51334,30628,30382,40866 +59954,30629,30381,40741 +51767,30630,30380,40063 +57541,30631,30379,40426 +57635,30632,30378,40515 +55574,30633,30377,40898 +59572,30634,30376,40757 +50669,30635,30375,40533 +54759,30636,30374,40813 +51236,30637,30373,40958 +57368,30638,30372,40975 +57327,30639,30371,40611 +52278,30640,30370,40425 +54501,30641,30369,40111 +52309,30642,30368,40267 +52477,30643,30367,40957 +50291,30644,30366,40978 +55556,30645,30365,40635 +58306,30646,30364,40953 +57403,30647,30363,40913 +58564,30648,30362,40773 +57949,30649,30361,40708 +55077,30650,30360,40612 +58286,30651,30359,40124 +51554,30652,30358,40921 +57567,30653,30357,40798 +56103,30654,30356,40678 +51997,30655,30355,40670 +54790,30656,30354,40774 +56139,30657,30353,40717 +50084,30658,30352,40045 +51844,30659,30351,40859 +59453,30660,30350,40487 +51394,30661,30349,40842 +50872,30662,30348,40354 +53484,30663,30347,40078 +56805,30664,30346,40130 +51945,30665,30345,40628 +53442,30666,30344,40359 +56420,30667,30343,40406 +59325,30668,30342,40420 +51288,30669,30341,40641 +54628,30670,30340,40158 +53914,30671,30339,40379 +58088,30672,30338,40399 +50806,30673,30337,40748 +58096,30674,30336,40654 +56738,30675,30335,40224 +56938,30676,30334,40925 +59327,30677,30333,40094 +57740,30678,30332,40799 +53837,30679,30331,40192 +51737,30680,30330,40588 +55438,30681,30329,40015 +56463,30682,30328,40018 +50275,30683,30327,40514 +58060,30684,30326,40609 +59778,30685,30325,40291 +56369,30686,30324,40891 +51481,30687,30323,40790 +53455,30688,30322,40655 +56940,30689,30321,40343 +58414,30690,30320,40313 +57403,30691,30319,40799 +57789,30692,30318,40975 +56479,30693,30317,40082 +57523,30694,30316,40610 +52275,30695,30315,40992 +59092,30696,30314,40215 +51119,30697,30313,40423 +54239,30698,30312,40825 +59583,30699,30311,40201 +58756,30700,30310,40397 +58066,30701,30309,40879 +57763,30702,30308,40610 +55502,30703,30307,40538 +51167,30704,30306,40939 +55297,30705,30305,40737 +55698,30706,30304,40098 +50307,30707,30303,40684 +51770,30708,30302,40130 +52055,30709,30301,40172 +54001,30710,30300,40913 +58128,30711,30299,40909 +58250,30712,30298,40128 +56976,30713,30297,40337 +52039,30714,30296,40817 +53724,30715,30295,40562 +59016,30716,30294,40260 +51867,30717,30293,40467 +58846,30718,30292,40342 +57805,30719,30291,40755 +50493,30720,30290,40606 +58041,30721,30289,40392 +52143,30722,30288,40893 +53566,30723,30287,40308 +58582,30724,30286,40754 +52059,30725,30285,40094 +57930,30726,30284,40207 +57306,30727,30283,40072 +52416,30728,30282,40571 +57558,30729,30281,40624 +57019,30730,30280,40613 +55614,30731,30279,40726 +51580,30732,30278,40801 +52402,30733,30277,40041 +55381,30734,30276,40451 +53834,30735,30275,40454 +55500,30736,30274,40141 +50470,30737,30273,40278 +53067,30738,30272,40638 +50032,30739,30271,40858 +56916,30740,30270,40954 +52366,30741,30269,40958 +51297,30742,30268,40632 +51059,30743,30267,40519 +56201,30744,30266,40732 +56213,30745,30265,40178 +53663,30746,30264,40281 +58505,30747,30263,40531 +50309,30748,30262,40274 +53050,30749,30261,40407 +59886,30750,30260,40109 +51161,30751,30259,40542 +53648,30752,30258,40548 +59103,30753,30257,40984 +51432,30754,30256,40626 +56221,30755,30255,40683 +53768,30756,30254,40031 +54420,30757,30253,40054 +56923,30758,30252,40688 +56993,30759,30251,40837 +58105,30760,30250,40062 +55408,30761,30249,40634 +59894,30762,30248,40825 +54385,30763,30247,40060 +50037,30764,30246,40768 +59544,30765,30245,40191 +56891,30766,30244,40064 +53038,30767,30243,40368 +51950,30768,30242,40343 +58870,30769,30241,40794 +51947,30770,30240,40443 +52682,30771,30239,40794 +59350,30772,30238,40916 +56322,30773,30237,40811 +54844,30774,30236,40867 +53190,30775,30235,40407 +54869,30776,30234,40982 +53436,30777,30233,40684 +51222,30778,30232,40273 +56235,30779,30231,40558 +58354,30780,30230,40946 +59296,30781,30229,40966 +57920,30782,30228,40784 +56797,30783,30227,40191 +52392,30784,30226,40785 +50191,30785,30225,40992 +57752,30786,30224,40447 +58313,30787,30223,40227 +56723,30788,30222,40247 +50316,30789,30221,40658 +53224,30790,30220,40926 +50120,30791,30219,40624 +54240,30792,30218,40383 +50140,30793,30217,40355 +53537,30794,30216,40333 +57161,30795,30215,40516 +56784,30796,30214,40786 +56965,30797,30213,40544 +51779,30798,30212,40362 +58235,30799,30211,40295 +51156,30800,30210,40991 +52463,30801,30209,40326 +52338,30802,30208,40217 +51535,30803,30207,40083 +50802,30804,30206,40129 +52021,30805,30205,40917 +56994,30806,30204,40715 +57418,30807,30203,40773 +58926,30808,30202,40166 +59029,30809,30201,40180 +52188,30810,30200,40298 +59056,30811,30199,40835 +58481,30812,30198,40244 +51051,30813,30197,40569 +56311,30814,30196,40496 +50026,30815,30195,40805 +52630,30816,30194,40580 +52953,30817,30193,40048 +50158,30818,30192,40317 +54592,30819,30191,40197 +51143,30820,30190,40433 +58770,30821,30189,40137 +52784,30822,30188,40064 +59391,30823,30187,40993 +58836,30824,30186,40335 +51114,30825,30185,40852 +55242,30826,30184,40514 +52596,30827,30183,40454 +51563,30828,30182,40510 +54839,30829,30181,40581 +58991,30830,30180,40960 +57759,30831,30179,40012 +50864,30832,30178,40797 +55634,30833,30177,40170 +55296,30834,30176,40927 +50113,30835,30175,40902 +51271,30836,30174,40881 +59686,30837,30173,40577 +58868,30838,30172,40216 +50813,30839,30171,40320 +57204,30840,30170,40774 +55136,30841,30169,40301 +50193,30842,30168,40811 +51226,30843,30167,40409 +57185,30844,30166,40218 +51069,30845,30165,40840 +52768,30846,30164,40125 +55662,30847,30163,40353 +58536,30848,30162,40166 +50014,30849,30161,40592 +55308,30850,30160,40820 +54452,30851,30159,40473 +55556,30852,30158,40318 +50278,30853,30157,40595 +53171,30854,30156,40911 +57783,30855,30155,40103 +53252,30856,30154,40118 +54106,30857,30153,40620 +59443,30858,30152,40784 +52020,30859,30151,40361 +56088,30860,30150,40452 +51088,30861,30149,40030 +53438,30862,30148,40859 +50764,30863,30147,40487 +59697,30864,30146,40027 +58144,30865,30145,40797 +57462,30866,30144,40574 +59647,30867,30143,40555 +53460,30868,30142,40779 +58901,30869,30141,40186 +56416,30870,30140,40081 +56305,30871,30139,40561 +51432,30872,30138,40419 +53645,30873,30137,40701 +50997,30874,30136,40389 +57832,30875,30135,40545 +55171,30876,30134,40354 +53956,30877,30133,40738 +51324,30878,30132,40375 +53915,30879,30131,40842 +56384,30880,30130,40199 +57036,30881,30129,40831 +59329,30882,30128,40139 +58500,30883,30127,40382 +54971,30884,30126,40973 +59496,30885,30125,40665 +54145,30886,30124,40946 +56623,30887,30123,40947 +50850,30888,30122,40019 +52988,30889,30121,40772 +55355,30890,30120,40454 +59016,30891,30119,40198 +54422,30892,30118,40270 +58270,30893,30117,40746 +50847,30894,30116,40555 +58560,30895,30115,40039 +50903,30896,30114,40582 +56424,30897,30113,40968 +54610,30898,30112,40798 +52872,30899,30111,40929 +56236,30900,30110,40624 +56067,30901,30109,40566 +57528,30902,30108,40447 +59044,30903,30107,40032 +54936,30904,30106,40280 +58732,30905,30105,40357 +52888,30906,30104,40624 +58202,30907,30103,40051 +56709,30908,30102,40220 +51234,30909,30101,40496 +58044,30910,30100,40645 +51648,30911,30099,40649 +52796,30912,30098,40830 +57589,30913,30097,40837 +55885,30914,30096,40723 +54160,30915,30095,40493 +51674,30916,30094,40392 +50857,30917,30093,40019 +54810,30918,30092,40003 +59174,30919,30091,40900 +50333,30920,30090,40647 +59488,30921,30089,40724 +59314,30922,30088,40501 +59232,30923,30087,40652 +54149,30924,30086,40737 +53155,30925,30085,40338 +51508,30926,30084,40543 +55933,30927,30083,40837 +56067,30928,30082,40361 +56473,30929,30081,40882 +50838,30930,30080,40582 +56030,30931,30079,40921 +52764,30932,30078,40376 +51566,30933,30077,40006 +56267,30934,30076,40257 +50856,30935,30075,40420 +55094,30936,30074,40379 +54909,30937,30073,40756 +52587,30938,30072,40059 +57392,30939,30071,40758 +57336,30940,30070,40185 +54598,30941,30069,40986 +52110,30942,30068,40631 +51852,30943,30067,40814 +56622,30944,30066,40396 +59736,30945,30065,40572 +54464,30946,30064,40083 +52184,30947,30063,40614 +53299,30948,30062,40309 +55783,30949,30061,40385 +52367,30950,30060,40039 +54190,30951,30059,40723 +59877,30952,30058,40737 +53991,30953,30057,40315 +50600,30954,30056,40597 +57324,30955,30055,40604 +54933,30956,30054,40696 +58142,30957,30053,40997 +51533,30958,30052,40848 +58770,30959,30051,40992 +55267,30960,30050,40922 +55093,30961,30049,40653 +53937,30962,30048,40575 +53537,30963,30047,40066 +55797,30964,30046,40442 +59047,30965,30045,40961 +55449,30966,30044,40953 +52892,30967,30043,40606 +59264,30968,30042,40901 +53153,30969,30041,40427 +59356,30970,30040,40967 +50474,30971,30039,40731 +58685,30972,30038,40641 +54560,30973,30037,40943 +59716,30974,30036,40487 +58625,30975,30035,40248 +56437,30976,30034,40960 +56373,30977,30033,40450 +57563,30978,30032,40989 +51372,30979,30031,40056 +54501,30980,30030,40956 +52835,30981,30029,40346 +56494,30982,30028,40297 +52262,30983,30027,40344 +56891,30984,30026,40450 +50767,30985,30025,40266 +55597,30986,30024,40701 +54812,30987,30023,40262 +57046,30988,30022,40017 +53599,30989,30021,40116 +51128,30990,30020,40462 +59903,30991,30019,40233 +51673,30992,30018,40018 +51083,30993,30017,40150 +58163,30994,30016,40672 +51807,30995,30015,40789 +55751,30996,30014,40175 +59007,30997,30013,40488 +59058,30998,30012,40324 +56496,30999,30011,40374 +55416,31000,30010,40413 +53478,31001,30009,40546 +51789,31002,30008,40756 +55848,31003,30007,40569 +58819,31004,30006,40604 +59184,31005,30005,40640 +55213,31006,30004,40778 +54814,31007,30003,40448 +58705,31008,30002,40179 +52700,31009,30001,40303 +51612,31010,30000,40734 +51501,31011,31000,40516 +57792,31012,30999,40950 +54046,31013,30998,40535 +51817,31014,30997,40303 +56606,31015,30996,40738 +55725,31016,30995,40578 +56010,31017,30994,40120 +56385,31018,30993,40510 +55329,31019,30992,40449 +56216,31020,30991,40965 +50166,31021,30990,40943 +56742,31022,30989,40288 +54100,31023,30988,40712 +56227,31024,30987,40328 +55468,31025,30986,40192 +52380,31026,30985,40514 +53049,31027,30984,40802 +56051,31028,30983,40742 +54357,31029,30982,40010 +58406,31030,30981,40029 +54036,31031,30980,40163 +54477,31032,30979,40188 +51134,31033,30978,40696 +50093,31034,30977,40569 +57707,31035,30976,40385 +53482,31036,30975,40649 +54550,31037,30974,40396 +53993,31038,30973,40531 +56932,31039,30972,40989 +55219,31040,30971,40077 +52030,31041,30970,40012 +55173,31042,30969,40217 +50681,31043,30968,40810 +52452,31044,30967,40387 +52295,31045,30966,40439 +58574,31046,30965,40498 +53942,31047,30964,40426 +51964,31048,30963,40792 +51239,31049,30962,40286 +50244,31050,30961,40984 +52409,31051,30960,40214 +56683,31052,30959,40987 +59268,31053,30958,40965 +59400,31054,30957,40815 +53841,31055,30956,40020 +58659,31056,30955,40869 +52758,31057,30954,40153 +56412,31058,30953,40189 +50912,31059,30952,40640 +57496,31060,30951,40392 +57721,31061,30950,40169 +52853,31062,30949,40674 +50649,31063,30948,40365 +58191,31064,30947,40714 +56408,31065,30946,40894 +54700,31066,30945,40575 +51169,31067,30944,40691 +54609,31068,30943,40744 +54371,31069,30942,40725 +52760,31070,30941,40008 +52865,31071,30940,40008 +56857,31072,30939,40269 +56025,31073,30938,40049 +50741,31074,30937,40028 +53762,31075,30936,40633 +57185,31076,30935,40738 +56766,31077,30934,40643 +54207,31078,30933,40713 +58991,31079,30932,40584 +53849,31080,30931,40437 +51398,31081,30930,40340 +50199,31082,30929,40970 +56566,31083,30928,40644 +53408,31084,30927,40012 +50887,31085,30926,40095 +53132,31086,30925,40883 +58839,31087,30924,40006 +59400,31088,30923,40665 +55706,31089,30922,40849 +52899,31090,30921,40960 +57858,31091,30920,40184 +50965,31092,30919,40445 +56939,31093,30918,40930 +54016,31094,30917,40339 +58781,31095,30916,40198 +52350,31096,30915,40782 +53588,31097,30914,40340 +56730,31098,30913,40037 +52924,31099,30912,40846 +59755,31100,30911,40715 +55925,31101,30910,40368 +58826,31102,30909,40634 +54022,31103,30908,40465 +56372,31104,30907,40676 +53150,31105,30906,40525 +52875,31106,30905,40295 +59750,31107,30904,40713 +51800,31108,30903,40236 +52147,31109,30902,40699 +53147,31110,30901,40325 +54343,31111,30900,40715 +50147,31112,30899,40657 +58199,31113,30898,40705 +50808,31114,30897,40445 +54903,31115,30896,40652 +57766,31116,30895,40600 +58609,31117,30894,40228 +59732,31118,30893,40771 +58228,31119,30892,40022 +59714,31120,30891,40867 +50153,31121,30890,40514 +53586,31122,30889,40444 +52641,31123,30888,40257 +52668,31124,30887,40492 +57835,31125,30886,40448 +52901,31126,30885,40714 +58930,31127,30884,40172 +51067,31128,30883,40473 +53410,31129,30882,40801 +58423,31130,30881,40724 +59131,31131,30880,40123 +53365,31132,30879,40840 +55150,31133,30878,40864 +51263,31134,30877,40600 +54868,31135,30876,40912 +51269,31136,30875,40569 +52622,31137,30874,40618 +53721,31138,30873,40660 +53799,31139,30872,40100 +56151,31140,30871,40185 +55910,31141,30870,40486 +51986,31142,30869,40261 +58672,31143,30868,40940 +53402,31144,30867,40547 +50042,31145,30866,40782 +59593,31146,30865,40128 +53660,31147,30864,40910 +52524,31148,30863,40822 +56512,31149,30862,40606 +54415,31150,30861,40255 +58266,31151,30860,40267 +54497,31152,30859,40252 +57138,31153,30858,40145 +53943,31154,30857,40457 +55036,31155,30856,40141 +53132,31156,30855,40454 +52489,31157,30854,40753 +50534,31158,30853,40621 +54246,31159,30852,40199 +51828,31160,30851,40234 +52082,31161,30850,40838 +51779,31162,30849,40564 +58702,31163,30848,40626 +52496,31164,30847,40903 +57100,31165,30846,40163 +53784,31166,30845,40203 +57834,31167,30844,40228 +58411,31168,30843,40405 +50088,31169,30842,40141 +55662,31170,30841,40344 +56452,31171,30840,40248 +58240,31172,30839,40816 +53799,31173,30838,40965 +52037,31174,30837,40275 +51129,31175,30836,40434 +55038,31176,30835,40628 +55423,31177,30834,40987 +57481,31178,30833,40084 +52357,31179,30832,40513 +50308,31180,30831,40943 +55094,31181,30830,40194 +50637,31182,30829,40761 +51752,31183,30828,40806 +54229,31184,30827,40275 +54981,31185,30826,40073 +50340,31186,30825,40478 +55955,31187,30824,40937 +54406,31188,30823,40363 +59237,31189,30822,40086 +51378,31190,30821,40684 +52155,31191,30820,40129 +57003,31192,30819,40522 +56501,31193,30818,40826 +54463,31194,30817,40876 +54917,31195,30816,40826 +57213,31196,30815,40857 +59217,31197,30814,40369 +55955,31198,30813,40035 +53735,31199,30812,40157 +58726,31200,30811,40104 +53404,31201,30810,40097 +57723,31202,30809,40846 +53805,31203,30808,40965 +55922,31204,30807,40594 +51767,31205,30806,40063 +59026,31206,30805,40125 +56785,31207,30804,40598 +52319,31208,30803,40355 +59143,31209,30802,40463 +55576,31210,30801,40217 +54514,31211,30800,40390 +57565,31212,30799,40010 +59986,31213,30798,40171 +59342,31214,30797,40351 +58493,31215,30796,40494 +55951,31216,30795,40985 +58626,31217,30794,40480 +52840,31218,30793,40860 +56710,31219,30792,40560 +58040,31220,30791,40594 +59120,31221,30790,40414 +53081,31222,30789,40736 +58080,31223,30788,40727 +53422,31224,30787,40409 +55913,31225,30786,40302 +52969,31226,30785,40093 +53232,31227,30784,40772 +52714,31228,30783,40454 +57260,31229,30782,40075 +57906,31230,30781,40439 +57565,31231,30780,40221 +59990,31232,30779,40002 +57434,31233,30778,40067 +50990,31234,30777,40884 +52226,31235,30776,40141 +53996,31236,30775,40078 +55044,31237,30774,40606 +53834,31238,30773,40675 +57450,31239,30772,40024 +58925,31240,30771,40177 +58480,31241,30770,40707 +58374,31242,30769,40158 +53619,31243,30768,40141 +59447,31244,30767,40473 +59700,31245,30766,40535 +51955,31246,30765,40297 +59259,31247,30764,40060 +57981,31248,30763,40254 +55433,31249,30762,40087 +58786,31250,30761,40818 +52838,31251,30760,40272 +54115,31252,30759,40660 +55000,31253,30758,40994 +58075,31254,30757,40305 +51589,31255,30756,40044 +51247,31256,30755,40159 +52608,31257,30754,40754 +54003,31258,30753,40927 +57423,31259,30752,40687 +59673,31260,30751,40030 +56749,31261,30750,40441 +55124,31262,30749,40640 +58027,31263,30748,40537 +56059,31264,30747,40306 +50706,31265,30746,40646 +55897,31266,30745,40971 +56692,31267,30744,40805 +58688,31268,30743,40109 +50960,31269,30742,40263 +57662,31270,30741,40310 +51636,31271,30740,40431 +59960,31272,30739,40814 +56636,31273,30738,40694 +56004,31274,30737,40012 +55672,31275,30736,40325 +56547,31276,30735,40297 +59820,31277,30734,40119 +58746,31278,30733,40249 +57122,31279,30732,40264 +59073,31280,30731,40569 +55402,31281,30730,40797 +52836,31282,30729,40281 +55185,31283,30728,40201 +59288,31284,30727,40840 +58895,31285,30726,40306 +58792,31286,30725,40494 +51002,31287,30724,40270 +59837,31288,30723,40899 +59992,31289,30722,40789 +51228,31290,30721,40265 +56514,31291,30720,40004 +51833,31292,30719,40312 +59781,31293,30718,40835 +55929,31294,30717,40206 +52450,31295,30716,40396 +55125,31296,30715,40520 +52036,31297,30714,40656 +53114,31298,30713,40834 +53681,31299,30712,40336 +57502,31300,30711,40199 +50778,31301,30710,40421 +50941,31302,30709,40798 +57197,31303,30708,40516 +50833,31304,30707,40193 +55322,31305,30706,40625 +58320,31306,30705,40291 +54274,31307,30704,40015 +59711,31308,30703,40653 +51627,31309,30702,40562 +56356,31310,30701,40676 +58768,31311,30700,40857 +52122,31312,30699,40739 +56901,31313,30698,40315 +55070,31314,30697,40537 +59081,31315,30696,40357 +55750,31316,30695,40631 +50212,31317,30694,40493 +57440,31318,30693,40944 +59599,31319,30692,40574 +58440,31320,30691,40077 +51459,31321,30690,40568 +56708,31322,30689,40108 +54506,31323,30688,40195 +58170,31324,30687,40436 +55586,31325,30686,40256 +57153,31326,30685,40112 +59904,31327,30684,40012 +54420,31328,30683,40486 +51713,31329,30682,40050 +58067,31330,30681,40810 +54987,31331,30680,40100 +54580,31332,30679,40187 +54338,31333,30678,40894 +53031,31334,30677,40826 +54886,31335,30676,40711 +56791,31336,30675,40907 +56378,31337,30674,40636 +59915,31338,30673,40778 +52159,31339,30672,40723 +55901,31340,30671,40555 +54463,31341,30670,40609 +58930,31342,30669,40165 +58486,31343,30668,40456 +55272,31344,30667,40156 +51547,31345,30666,40265 +53790,31346,30665,40961 +56428,31347,30664,40018 +52044,31348,30663,40905 +51255,31349,30662,40068 +52100,31350,30661,40647 +53813,31351,30660,40731 +58480,31352,30659,40662 +53808,31353,30658,40978 +59483,31354,30657,40288 +51014,31355,30656,40923 +52316,31356,30655,40116 +50118,31357,30654,40097 +57084,31358,30653,40031 +57942,31359,30652,40330 +55705,31360,30651,40569 +54535,31361,30650,40955 +55539,31362,30649,40035 +54193,31363,30648,40370 +51443,31364,30647,40458 +52776,31365,30646,40026 +56604,31366,30645,40507 +52000,31367,30644,40207 +58089,31368,30643,40563 +54300,31369,30642,40015 +57798,31370,30641,40233 +50945,31371,30640,40016 +54827,31372,30639,40075 +50778,31373,30638,40907 +51923,31374,30637,40738 +51301,31375,30636,40381 +55563,31376,30635,40731 +56218,31377,30634,40278 +51813,31378,30633,40954 +56700,31379,30632,40520 +59260,31380,30631,40349 +52696,31381,30630,40638 +59266,31382,30629,40618 +58554,31383,30628,40190 +54182,31384,30627,40662 +51711,31385,30626,40357 +53297,31386,30625,40636 +50934,31387,30624,40053 +59247,31388,30623,40238 +59247,31389,30622,40925 +56618,31390,30621,40514 +52133,31391,30620,40085 +59090,31392,30619,40532 +58232,31393,30618,40805 +57770,31394,30617,40124 +57842,31395,30616,40201 +55116,31396,30615,40828 +51340,31397,30614,40883 +56460,31398,30613,40329 +55865,31399,30612,40485 +50537,31400,30611,40235 +51568,31401,30610,40736 +58224,31402,30609,40138 +56247,31403,30608,40975 +55691,31404,30607,40223 +51130,31405,30606,40425 +56007,31406,30605,40916 +53371,31407,30604,40759 +54563,31408,30603,40577 +50708,31409,30602,40587 +52852,31410,30601,40972 +54376,31411,30600,40176 +54613,31412,30599,40524 +52791,31413,30598,40732 +58124,31414,30597,40946 +56288,31415,30596,40583 +57624,31416,30595,40613 +52017,31417,30594,40430 +57942,31418,30593,40880 +53257,31419,30592,40681 +53827,31420,30591,40970 +57471,31421,30590,40589 +56732,31422,30589,40218 +50028,31423,30588,40598 +56705,31424,30587,40893 +53731,31425,30586,40501 +59944,31426,30585,40486 +58208,31427,30584,40226 +53389,31428,30583,40528 +58526,31429,30582,40110 +52903,31430,30581,40779 +54723,31431,30580,40920 +50598,31432,30579,40464 +59350,31433,30578,40506 +58089,31434,30577,40571 +52897,31435,30576,40391 +59292,31436,30575,40860 +56593,31437,30574,40779 +57294,31438,30573,40922 +53306,31439,30572,40839 +52080,31440,30571,40821 +53320,31441,30570,40343 +58810,31442,30569,40102 +51888,31443,30568,40586 +58519,31444,30567,40997 +59141,31445,30566,40238 +53025,31446,30565,40047 +55126,31447,30564,40853 +53896,31448,30563,40514 +59908,31449,30562,40512 +59755,31450,30561,40230 +51746,31451,30560,40262 +58377,31452,30559,40313 +51173,31453,30558,40473 +56865,31454,30557,40391 +57931,31455,30556,40661 +51045,31456,30555,40029 +58231,31457,30554,40669 +55645,31458,30553,40824 +59930,31459,30552,40301 +51128,31460,30551,40919 +58831,31461,30550,40774 +58861,31462,30549,40234 +58573,31463,30548,40489 +58704,31464,30547,40301 +59119,31465,30546,40875 +50753,31466,30545,40429 +54591,31467,30544,40585 +53886,31468,30543,40061 +54638,31469,30542,40825 +50232,31470,30541,40269 +56145,31471,30540,40508 +58083,31472,30539,40168 +54934,31473,30538,40332 +51510,31474,30537,40569 +50644,31475,30536,40029 +53651,31476,30535,40578 +57024,31477,30534,40219 +52417,31478,30533,40664 +55132,31479,30532,40649 +57972,31480,30531,40494 +55162,31481,30530,40025 +53838,31482,30529,40796 +55438,31483,30528,40413 +55743,31484,30527,40139 +53617,31485,30526,40016 +56104,31486,30525,40848 +55874,31487,30524,40745 +55054,31488,30523,40955 +58118,31489,30522,40757 +58633,31490,30521,40923 +52849,31491,30520,40473 +58300,31492,30519,40001 +54653,31493,30518,40225 +56847,31494,30517,40349 +50935,31495,30516,40088 +57944,31496,30515,40832 +57065,31497,30514,40996 +53848,31498,30513,40127 +53633,31499,30512,40189 +54529,31500,30511,40368 +52417,31501,30510,40106 +54245,31502,30509,40381 +53792,31503,30508,40191 +52826,31504,30507,40778 +50078,31505,30506,40519 +57354,31506,30505,40428 +58500,31507,30504,40955 +53831,31508,30503,40456 +53930,31509,30502,40180 +57612,31510,30501,40470 +51890,31511,30500,40978 +58046,31512,30499,40976 +52833,31513,30498,40465 +51793,31514,30497,40762 +55742,31515,30496,40325 +50583,31516,30495,40032 +53683,31517,30494,40851 +55155,31518,30493,40470 +50673,31519,30492,40475 +53116,31520,30491,40248 +53856,31521,30490,40757 +57421,31522,30489,40679 +56691,31523,30488,40159 +52569,31524,30487,40005 +50874,31525,30486,40872 +59660,31526,30485,40477 +54225,31527,30484,40524 +53788,31528,30483,40690 +50246,31529,30482,40621 +53278,31530,30481,40754 +54296,31531,30480,40434 +53461,31532,30479,40862 +59066,31533,30478,40326 +52102,31534,30477,40057 +50823,31535,30476,40192 +59655,31536,30475,40762 +52688,31537,30474,40891 +52629,31538,30473,40304 +55313,31539,30472,40489 +50325,31540,30471,40082 +54177,31541,30470,40889 +56242,31542,30469,40888 +50984,31543,30468,40721 +55173,31544,30467,40465 +53099,31545,30466,40810 +59411,31546,30465,40169 +56066,31547,30464,40039 +58720,31548,30463,40927 +52683,31549,30462,40793 +52993,31550,30461,40649 +56376,31551,30460,40955 +58495,31552,30459,40116 +52963,31553,30458,40076 +55223,31554,30457,40764 +52209,31555,30456,40526 +51039,31556,30455,40675 +57636,31557,30454,40226 +54707,31558,30453,40882 +53339,31559,30452,40958 +57309,31560,30451,40706 +52821,31561,30450,40381 +55555,31562,30449,40077 +52498,31563,30448,40113 +56811,31564,30447,40950 +55274,31565,30446,40327 +50137,31566,30445,40978 +53094,31567,30444,40062 +56953,31568,30443,40481 +59132,31569,30442,40062 +53639,31570,30441,40557 +56825,31571,30440,40809 +57147,31572,30439,40126 +53511,31573,30438,40985 +58387,31574,30437,40703 +50686,31575,30436,40462 +55593,31576,30435,40833 +57415,31577,30434,40890 +54468,31578,30433,40017 +58843,31579,30432,40331 +57546,31580,30431,40296 +51274,31581,30430,40563 +54306,31582,30429,40072 +52791,31583,30428,40064 +55207,31584,30427,40030 +57552,31585,30426,40435 +53657,31586,30425,40073 +50396,31587,30424,40311 +56430,31588,30423,40981 +53101,31589,30422,40736 +51942,31590,30421,40923 +59205,31591,30420,40422 +55788,31592,30419,40649 +59429,31593,30418,40908 +54568,31594,30417,40393 +50049,31595,30416,40745 +50321,31596,30415,40201 +59295,31597,30414,40267 +53040,31598,30413,40583 +52670,31599,30412,40178 +57360,31600,30411,40919 +52147,31601,30410,40512 +51137,31602,30409,40138 +55694,31603,30408,40883 +58235,31604,30407,40420 +57307,31605,30406,40925 +56320,31606,30405,40283 +57317,31607,30404,40177 +55034,31608,30403,40687 +57477,31609,30402,40441 +54356,31610,30401,40226 +55224,31611,30400,40104 +53557,31612,30399,40557 +56334,31613,30398,40545 +56086,31614,30397,40588 +50463,31615,30396,40018 +55397,31616,30395,40975 +53720,31617,30394,40025 +56274,31618,30393,40918 +59907,31619,30392,40266 +51591,31620,30391,40385 +51700,31621,30390,40474 +52708,31622,30389,40561 +51488,31623,30388,40027 +52344,31624,30387,40054 +50553,31625,30386,40052 +53852,31626,30385,40302 +58036,31627,30384,40955 +53417,31628,30383,40423 +57403,31629,30382,40242 +52250,31630,30381,40105 +50013,31631,30380,40172 +52364,31632,30379,40451 +52851,31633,30378,40506 +56737,31634,30377,40344 +50719,31635,30376,40551 +54580,31636,30375,40566 +57933,31637,30374,40004 +58807,31638,30373,40491 +59755,31639,30372,40944 +54617,31640,30371,40780 +52261,31641,30370,40544 +59347,31642,30369,40803 +52041,31643,30368,40215 +51873,31644,30367,40372 +56873,31645,30366,40330 +56078,31646,30365,40868 +53726,31647,30364,40083 +52215,31648,30363,40663 +50905,31649,30362,40415 +51378,31650,30361,40356 +59990,31651,30360,40502 +56552,31652,30359,40919 +59658,31653,30358,40031 +56797,31654,30357,40364 +55723,31655,30356,40718 +57425,31656,30355,40731 +58654,31657,30354,40003 +57070,31658,30353,40972 +55594,31659,30352,40519 +55810,31660,30351,40559 +54428,31661,30350,40885 +50679,31662,30349,40976 +54389,31663,30348,40387 +54285,31664,30347,40102 +57454,31665,30346,40908 +51065,31666,30345,40439 +58876,31667,30344,40796 +56870,31668,30343,40930 +54781,31669,30342,40887 +54570,31670,30341,40848 +55682,31671,30340,40702 +56036,31672,30339,40847 +51511,31673,30338,40791 +58401,31674,30337,40741 +58861,31675,30336,40984 +57358,31676,30335,40053 +50025,31677,30334,40655 +52008,31678,30333,40745 +52102,31679,30332,40657 +58079,31680,30331,40549 +58517,31681,30330,40645 +53737,31682,30329,40499 +58789,31683,30328,40764 +57571,31684,30327,40337 +59533,31685,30326,40032 +50417,31686,30325,40019 +56085,31687,30324,40950 +52967,31688,30323,40413 +52533,31689,30322,40449 +50224,31690,30321,40498 +50533,31691,30320,40860 +58795,31692,30319,40650 +56980,31693,30318,40804 +51175,31694,30317,40035 +51525,31695,30316,40192 +56339,31696,30315,40783 +52979,31697,30314,40222 +51047,31698,30313,40286 +56373,31699,30312,40707 +52561,31700,30311,40080 +55212,31701,30310,40806 +50168,31702,30309,40617 +52505,31703,30308,40185 +51181,31704,30307,40657 +56491,31705,30306,40013 +56959,31706,30305,40007 +53943,31707,30304,40138 +53261,31708,30303,40169 +52432,31709,30302,40120 +59158,31710,30301,40995 +54230,31711,30300,40573 +54780,31712,30299,40170 +58059,31713,30298,40954 +52871,31714,30297,40315 +58096,31715,30296,40948 +57894,31716,30295,40004 +52158,31717,30294,40261 +55889,31718,30293,40335 +57056,31719,30292,40268 +53002,31720,30291,40559 +54478,31721,30290,40879 +51249,31722,30289,40344 +50869,31723,30288,40036 +51926,31724,30287,40608 +51218,31725,30286,40823 +50362,31726,30285,40355 +52189,31727,30284,40906 +59150,31728,30283,40671 +52962,31729,30282,40639 +56237,31730,30281,40446 +56970,31731,30280,40219 +55878,31732,30279,40721 +51000,31733,30278,40208 +50689,31734,30277,40031 +55424,31735,30276,40210 +54546,31736,30275,40154 +53410,31737,30274,40275 +52811,31738,30273,40154 +54052,31739,30272,40910 +51452,31740,30271,40880 +51709,31741,30270,40004 +58710,31742,30269,40257 +56494,31743,30268,40542 +57214,31744,30267,40797 +57931,31745,30266,40943 +56589,31746,30265,40227 +59831,31747,30264,40549 +59443,31748,30263,40939 +55710,31749,30262,40701 +58731,31750,30261,40223 +52475,31751,30260,40568 +55994,31752,30259,40415 +55498,31753,30258,40149 +54049,31754,30257,40880 +59976,31755,30256,40996 +55187,31756,30255,40184 +57894,31757,30254,40021 +56096,31758,30253,40032 +51677,31759,30252,40531 +58991,31760,30251,40382 +59595,31761,30250,40904 +51578,31762,30249,40926 +59451,31763,30248,40957 +58467,31764,30247,40245 +53811,31765,30246,40134 +54997,31766,30245,40314 +50999,31767,30244,40385 +53733,31768,30243,40089 +55051,31769,30242,40313 +53831,31770,30241,40949 +56837,31771,30240,40099 +51005,31772,30239,40074 +56001,31773,30238,40052 +55258,31774,30237,40348 +54318,31775,30236,40389 +59909,31776,30235,40839 +59141,31777,30234,40292 +51913,31778,30233,40924 +56266,31779,30232,40008 +56345,31780,30231,40468 +58523,31781,30230,40376 +58369,31782,30229,40172 +58214,31783,30228,40329 +57271,31784,30227,40230 +58760,31785,30226,40427 +58977,31786,30225,40880 +59951,31787,30224,40990 +53840,31788,30223,40738 +52896,31789,30222,40318 +51369,31790,30221,40481 +51973,31791,30220,40312 +58821,31792,30219,40412 +57598,31793,30218,40720 +54606,31794,30217,40271 +54120,31795,30216,40689 +51226,31796,30215,40732 +56172,31797,30214,40336 +53652,31798,30213,40026 +59870,31799,30212,40917 +57333,31800,30211,40455 +57909,31801,30210,40462 +59314,31802,30209,40162 +59642,31803,30208,40994 +51199,31804,30207,40822 +55386,31805,30206,40871 +52513,31806,30205,40188 +57078,31807,30204,40265 +53393,31808,30203,40320 +51114,31809,30202,40984 +53277,31810,30201,40189 +57386,31811,30200,40980 +55736,31812,30199,40088 +58231,31813,30198,40976 +53266,31814,30197,40054 +55761,31815,30196,40224 +55890,31816,30195,40019 +53127,31817,30194,40768 +55983,31818,30193,40296 +53995,31819,30192,40170 +56078,31820,30191,40032 +55873,31821,30190,40340 +59942,31822,30189,40055 +54949,31823,30188,40892 +53887,31824,30187,40191 +59947,31825,30186,40664 +50041,31826,30185,40617 +54802,31827,30184,40102 +54073,31828,30183,40141 +58770,31829,30182,40237 +58686,31830,30181,40318 +52965,31831,30180,40799 +55490,31832,30179,40716 +52002,31833,30178,40275 +56828,31834,30177,40551 +52884,31835,30176,40259 +51922,31836,30175,40636 +58793,31837,30174,40839 +57099,31838,30173,40752 +52166,31839,30172,40411 +57139,31840,30171,40159 +50040,31841,30170,40556 +57976,31842,30169,40647 +59285,31843,30168,40506 +51233,31844,30167,40062 +55457,31845,30166,40515 +54398,31846,30165,40068 +58477,31847,30164,40765 +57946,31848,30163,40783 +50185,31849,30162,40941 +56925,31850,30161,40345 +53482,31851,30160,40056 +58750,31852,30159,40408 +56247,31853,30158,40356 +58422,31854,30157,40514 +52701,31855,30156,40045 +54463,31856,30155,40706 +52755,31857,30154,40304 +57052,31858,30153,40419 +54456,31859,30152,40789 +51362,31860,30151,40136 +54199,31861,30150,40526 +50644,31862,30149,40990 +53341,31863,30148,40902 +50428,31864,30147,40583 +51585,31865,30146,40216 +57141,31866,30145,40588 +58802,31867,30144,40789 +51206,31868,30143,40862 +55343,31869,30142,40377 +59737,31870,30141,40473 +54431,31871,30140,40955 +55049,31872,30139,40829 +52864,31873,30138,40439 +57945,31874,30137,40602 +58893,31875,30136,40514 +52850,31876,30135,40695 +50185,31877,30134,40785 +54101,31878,30133,40543 +57944,31879,30132,40735 +58094,31880,30131,40153 +57709,31881,30130,40641 +59593,31882,30129,40635 +54878,31883,30128,40263 +54126,31884,30127,40410 +50964,31885,30126,40849 +54664,31886,30125,40169 +57038,31887,30124,40651 +55156,31888,30123,40427 +50933,31889,30122,40287 +56485,31890,30121,40574 +51705,31891,30120,40438 +50772,31892,30119,40343 +51483,31893,30118,40530 +52884,31894,30117,40627 +58804,31895,30116,40467 +52484,31896,30115,40721 +50434,31897,30114,40452 +50189,31898,30113,40978 +59363,31899,30112,40313 +56507,31900,30111,40050 +56730,31901,30110,40984 +58153,31902,30109,40014 +58415,31903,30108,40329 +51045,31904,30107,40049 +53939,31905,30106,40794 +53394,31906,30105,40309 +50417,31907,30104,40404 +55948,31908,30103,40107 +58223,31909,30102,40196 +54887,31910,30101,40183 +58404,31911,30100,40774 +50912,31912,30099,40139 +54052,31913,30098,40621 +58197,31914,30097,40781 +56742,31915,30096,40552 +57456,31916,30095,40256 +54086,31917,30094,40457 +55198,31918,30093,40828 +52583,31919,30092,40319 +59470,31920,30091,40939 +51248,31921,30090,40286 +57254,31922,30089,40082 +54631,31923,30088,40640 +54191,31924,30087,40399 +57996,31925,30086,40394 +56800,31926,30085,40941 +50044,31927,30084,40485 +57048,31928,30083,40586 +54390,31929,30082,40432 +59125,31930,30081,40441 +55081,31931,30080,40423 +53249,31932,30079,40472 +58636,31933,30078,40330 +52796,31934,30077,40792 +53272,31935,30076,40356 +58261,31936,30075,40380 +59760,31937,30074,40677 +54642,31938,30073,40753 +51073,31939,30072,40079 +59328,31940,30071,40329 +53988,31941,30070,40338 +51060,31942,30069,40099 +51280,31943,30068,40468 +59775,31944,30067,40538 +53436,31945,30066,40840 +53808,31946,30065,40176 +59410,31947,30064,40730 +50963,31948,30063,40160 +58255,31949,30062,40773 +50983,31950,30061,40357 +59031,31951,30060,40177 +59054,31952,30059,40514 +59814,31953,30058,40964 +55389,31954,30057,40934 +55473,31955,30056,40668 +51139,31956,30055,40043 +53115,31957,30054,40926 +58887,31958,30053,40916 +58724,31959,30052,40422 +54186,31960,30051,40417 +52107,31961,30050,40203 +56219,31962,30049,40464 +57443,31963,30048,40406 +51449,31964,30047,40082 +52100,31965,30046,40871 +57923,31966,30045,40631 +53177,31967,30044,40844 +55515,31968,30043,40094 +59335,31969,30042,40287 +53930,31970,30041,40389 +52061,31971,30040,40059 +52349,31972,30039,40962 +58662,31973,30038,40115 +57596,31974,30037,40292 +51435,31975,30036,40863 +59099,31976,30035,40977 +56630,31977,30034,40364 +58426,31978,30033,40204 +51122,31979,30032,40822 +57815,31980,30031,40394 +59630,31981,30030,40172 +51251,31982,30029,40962 +58784,31983,30028,40209 +51970,31984,30027,40263 +54262,31985,30026,40746 +55900,31986,30025,40603 +53543,31987,30024,40753 +57825,31988,30023,40041 +51017,31989,30022,40653 +59545,31990,30021,40327 +54731,31991,30020,40252 +54696,31992,30019,40198 +59426,31993,30018,40998 +53329,31994,30017,40912 +52258,31995,30016,40103 +53378,31996,30015,40789 +54050,31997,30014,40368 +51837,31998,30013,40162 +54066,31999,30012,40738 +51974,32000,30011,40071 +55336,32001,30010,40017 +57192,32002,30009,40282 +54229,32003,30008,40689 +56611,32004,30007,40389 +53047,32005,30006,40968 +57104,32006,30005,40449 +53527,32007,30004,40496 +54101,32008,30003,40326 +52659,32009,30002,40799 +50899,32010,30001,40704 +58582,32011,30000,40092 +52412,32012,31000,40735 +56707,32013,30999,40671 +53667,32014,30998,40819 +59137,32015,30997,40094 +55532,32016,30996,40666 +59408,32017,30995,40552 +50002,32018,30994,40512 +58106,32019,30993,40632 +52391,32020,30992,40042 +57092,32021,30991,40440 +51974,32022,30990,40879 +52451,32023,30989,40471 +56964,32024,30988,40827 +56412,32025,30987,40897 +58677,32026,30986,40305 +56612,32027,30985,40857 +50251,32028,30984,40660 +51446,32029,30983,40021 +50745,32030,30982,40546 +52227,32031,30981,40350 +54502,32032,30980,40422 +56163,32033,30979,40227 +58638,32034,30978,40840 +53705,32035,30977,40665 +50434,32036,30976,40963 +58485,32037,30975,40641 +58766,32038,30974,40307 +59140,32039,30973,40862 +57691,32040,30972,40673 +50354,32041,30971,40609 +50107,32042,30970,40957 +57615,32043,30969,40147 +51714,32044,30968,40343 +57086,32045,30967,40286 +55525,32046,30966,40130 +53626,32047,30965,40200 +57338,32048,30964,40181 +53012,32049,30963,40446 +50559,32050,30962,40886 +52168,32051,30961,40057 +58502,32052,30960,40037 +54334,32053,30959,40367 +51038,32054,30958,40027 +57948,32055,30957,40608 +59437,32056,30956,40542 +59080,32057,30955,40827 +59145,32058,30954,40546 +51338,32059,30953,40197 +59830,32060,30952,40605 +59040,32061,30951,40110 +59881,32062,30950,40454 +51916,32063,30949,40928 +50508,32064,30948,40451 +58104,32065,30947,40468 +57994,32066,30946,40423 +50202,32067,30945,40827 +58714,32068,30944,40044 +53298,32069,30943,40229 +54424,32070,30942,40514 +58608,32071,30941,40730 +57342,32072,30940,40276 +52834,32073,30939,40323 +54467,32074,30938,40267 +52843,32075,30937,40436 +50058,32076,30936,40089 +56224,32077,30935,40472 +53035,32078,30934,40084 +55100,32079,30933,40009 +55342,32080,30932,40070 +58803,32081,30931,40251 +59379,32082,30930,40861 +50835,32083,30929,40219 +57007,32084,30928,40979 +52518,32085,30927,40281 +52097,32086,30926,40052 +59892,32087,30925,40759 +58355,32088,30924,40623 +58262,32089,30923,40701 +53468,32090,30922,40676 +53445,32091,30921,40075 +57634,32092,30920,40105 +52641,32093,30919,40770 +50125,32094,30918,40264 +50365,32095,30917,40359 +51702,32096,30916,40696 +58280,32097,30915,40325 +52318,32098,30914,40142 +54471,32099,30913,40806 +56395,32100,30912,40655 +51885,32101,30911,40013 +50157,32102,30910,40277 +54572,32103,30909,40843 +50287,32104,30908,40885 +57237,32105,30907,40133 +56937,32106,30906,40529 +53820,32107,30905,40470 +53122,32108,30904,40558 +50615,32109,30903,40606 +58803,32110,30902,40932 +51589,32111,30901,40279 +50711,32112,30900,40189 +51227,32113,30899,40319 +50830,32114,30898,40100 +53273,32115,30897,40623 +53105,32116,30896,40884 +59116,32117,30895,40391 +58048,32118,30894,40410 +56684,32119,30893,40219 +58406,32120,30892,40296 +53030,32121,30891,40055 +59870,32122,30890,40886 +55812,32123,30889,40906 +58255,32124,30888,40839 +57751,32125,30887,40346 +52707,32126,30886,40805 +59927,32127,30885,40620 +51477,32128,30884,40522 +54033,32129,30883,40573 +56009,32130,30882,40109 +56671,32131,30881,40346 +52981,32132,30880,40757 +50278,32133,30879,40793 +59725,32134,30878,40701 +52793,32135,30877,40243 +58557,32136,30876,40044 +51834,32137,30875,40574 +54591,32138,30874,40880 +54641,32139,30873,40850 +57404,32140,30872,40254 +50133,32141,30871,40136 +57535,32142,30870,40472 +55799,32143,30869,40186 +57013,32144,30868,40811 +55838,32145,30867,40563 +56369,32146,30866,40732 +50188,32147,30865,40444 +53484,32148,30864,40863 +56656,32149,30863,40048 +57273,32150,30862,40868 +58261,32151,30861,40493 +53223,32152,30860,40951 +55160,32153,30859,40488 +59327,32154,30858,40985 +55094,32155,30857,40987 +53805,32156,30856,40064 +54660,32157,30855,40933 +57660,32158,30854,40496 +53960,32159,30853,40654 +52250,32160,30852,40940 +59589,32161,30851,40197 +59851,32162,30850,40653 +56468,32163,30849,40129 +59593,32164,30848,40374 +53421,32165,30847,40784 +56088,32166,30846,40498 +58469,32167,30845,40199 +57768,32168,30844,40778 +57714,32169,30843,40247 +53556,32170,30842,40551 +55545,32171,30841,40312 +57767,32172,30840,40368 +54920,32173,30839,40405 +54398,32174,30838,40353 +54560,32175,30837,40483 +51256,32176,30836,40008 +57626,32177,30835,40919 +53626,32178,30834,40141 +50315,32179,30833,40580 +58016,32180,30832,40997 +56402,32181,30831,40165 +52510,32182,30830,40443 +59630,32183,30829,40213 +55972,32184,30828,40580 +52492,32185,30827,40240 +53264,32186,30826,40293 +59597,32187,30825,40470 +55165,32188,30824,40179 +59847,32189,30823,40780 +53993,32190,30822,40911 +51746,32191,30821,40998 +59252,32192,30820,40668 +59027,32193,30819,40261 +50148,32194,30818,40446 +55109,32195,30817,40209 +58005,32196,30816,40985 +58898,32197,30815,40539 +53966,32198,30814,40667 +57122,32199,30813,40122 +57632,32200,30812,40415 +55835,32201,30811,40672 +50407,32202,30810,40935 +53542,32203,30809,40336 +58739,32204,30808,40221 +54962,32205,30807,40278 +59840,32206,30806,40742 +50146,32207,30805,40754 +50304,32208,30804,40820 +56881,32209,30803,40387 +50059,32210,30802,40726 +55126,32211,30801,40716 +59661,32212,30800,40006 +59298,32213,30799,40174 +50622,32214,30798,40654 +57206,32215,30797,40210 +56271,32216,30796,40768 +54274,32217,30795,40513 +52159,32218,30794,40281 +59000,32219,30793,40898 +52381,32220,30792,40338 +57359,32221,30791,40487 +53608,32222,30790,40683 +55252,32223,30789,40780 +56051,32224,30788,40475 +51114,32225,30787,40564 +55940,32226,30786,40784 +50050,32227,30785,40370 +55067,32228,30784,40831 +58742,32229,30783,40314 +50480,32230,30782,40217 +53551,32231,30781,40554 +56213,32232,30780,40859 +52294,32233,30779,40592 +59882,32234,30778,40968 +55704,32235,30777,40201 +50240,32236,30776,40501 +54210,32237,30775,40674 +58837,32238,30774,40984 +56140,32239,30773,40343 +58334,32240,30772,40758 +52994,32241,30771,40670 +52915,32242,30770,40928 +55389,32243,30769,40079 +57043,32244,30768,40833 +57825,32245,30767,40266 +58697,32246,30766,40695 +51471,32247,30765,40613 +51654,32248,30764,40299 +50939,32249,30763,40457 +56014,32250,30762,40294 +54056,32251,30761,40656 +52207,32252,30760,40018 +53934,32253,30759,40637 +53307,32254,30758,40899 +55870,32255,30757,40815 +52871,32256,30756,40776 +58700,32257,30755,40635 +59963,32258,30754,40706 +56971,32259,30753,40094 +53434,32260,30752,40240 +55927,32261,30751,40108 +53996,32262,30750,40427 +50892,32263,30749,40608 +52263,32264,30748,40181 +56388,32265,30747,40192 +52557,32266,30746,40313 +57965,32267,30745,40531 +50702,32268,30744,40879 +50216,32269,30743,40482 +51181,32270,30742,40559 +51390,32271,30741,40841 +57776,32272,30740,40743 +56605,32273,30739,40801 +57410,32274,30738,40754 +56752,32275,30737,40507 +59827,32276,30736,40255 +57005,32277,30735,40474 +55647,32278,30734,40803 +53240,32279,30733,40797 +59963,32280,30732,40028 +53973,32281,30731,40377 +51131,32282,30730,40364 +58139,32283,30729,40623 +52081,32284,30728,40222 +51252,32285,30727,40471 +57697,32286,30726,40288 +53008,32287,30725,40896 +51232,32288,30724,40796 +57129,32289,30723,40154 +50394,32290,30722,40989 +51761,32291,30721,40674 +53346,32292,30720,40995 +57063,32293,30719,40266 +57540,32294,30718,40394 +57881,32295,30717,40491 +50358,32296,30716,40365 +59459,32297,30715,40631 +57214,32298,30714,40331 +56726,32299,30713,40879 +51917,32300,30712,40076 +59140,32301,30711,40566 +52553,32302,30710,40266 +53240,32303,30709,40785 +57656,32304,30708,40894 +55362,32305,30707,40251 +53112,32306,30706,40981 +57184,32307,30705,40728 +52171,32308,30704,40879 +53496,32309,30703,40494 +57424,32310,30702,40557 +51794,32311,30701,40956 +58989,32312,30700,40612 +53874,32313,30699,40840 +57000,32314,30698,40050 +51474,32315,30697,40912 +55029,32316,30696,40572 +50991,32317,30695,40396 +59498,32318,30694,40329 +52650,32319,30693,40302 +52206,32320,30692,40639 +59103,32321,30691,40824 +59983,32322,30690,40440 +59762,32323,30689,40073 +54243,32324,30688,40488 +57061,32325,30687,40339 +54055,32326,30686,40414 +52310,32327,30685,40708 +55059,32328,30684,40429 +53845,32329,30683,40198 +51166,32330,30682,40382 +50292,32331,30681,40333 +52094,32332,30680,40595 +54503,32333,30679,40093 +58391,32334,30678,40898 +55066,32335,30677,40430 +57301,32336,30676,40532 +51410,32337,30675,40677 +52997,32338,30674,40801 +52619,32339,30673,40320 +59933,32340,30672,40930 +51121,32341,30671,40237 +54092,32342,30670,40475 +51211,32343,30669,40815 +54332,32344,30668,40555 +54545,32345,30667,40111 +53012,32346,30666,40137 +59918,32347,30665,40347 +55466,32348,30664,40333 +59040,32349,30663,40781 +53334,32350,30662,40616 +57772,32351,30661,40211 +58417,32352,30660,40568 +54927,32353,30659,40678 +50572,32354,30658,40180 +55936,32355,30657,40209 +58365,32356,30656,40321 +57297,32357,30655,40456 +52452,32358,30654,40111 +54708,32359,30653,40818 +57869,32360,30652,40043 +55433,32361,30651,40501 +50798,32362,30650,40617 +51349,32363,30649,40685 +57119,32364,30648,40077 +55775,32365,30647,40832 +55977,32366,30646,40006 +54037,32367,30645,40809 +59207,32368,30644,40144 +55323,32369,30643,40855 +58009,32370,30642,40309 +55283,32371,30641,40801 +56888,32372,30640,40480 +56376,32373,30639,40128 +52276,32374,30638,40133 +58436,32375,30637,40201 +58984,32376,30636,40520 +51314,32377,30635,40029 +50815,32378,30634,40000 +53838,32379,30633,40855 +56736,32380,30632,40928 +59544,32381,30631,40290 +52325,32382,30630,40898 +54135,32383,30629,40492 +59530,32384,30628,40368 +51898,32385,30627,40419 +59456,32386,30626,40593 +55929,32387,30625,40579 +54193,32388,30624,40276 +52107,32389,30623,40769 +51997,32390,30622,40883 +51857,32391,30621,40110 +50515,32392,30620,40071 +56191,32393,30619,40203 +59244,32394,30618,40812 +55771,32395,30617,40862 +51794,32396,30616,40746 +52606,32397,30615,40303 +54590,32398,30614,40751 +56007,32399,30613,40089 +54574,32400,30612,40972 +57311,32401,30611,40360 +50645,32402,30610,40922 +56567,32403,30609,40067 +52812,32404,30608,40000 +57549,32405,30607,40126 +59462,32406,30606,40301 +57790,32407,30605,40464 +58546,32408,30604,40036 +57973,32409,30603,40323 +56505,32410,30602,40073 +59537,32411,30601,40997 +56983,32412,30600,40894 +54581,32413,30599,40962 +52887,32414,30598,40514 +53465,32415,30597,40540 +57831,32416,30596,40391 +53662,32417,30595,40496 +53019,32418,30594,40190 +55359,32419,30593,40838 +53629,32420,30592,40041 +55123,32421,30591,40293 +54770,32422,30590,40621 +53119,32423,30589,40888 +59143,32424,30588,40074 +58551,32425,30587,40449 +52282,32426,30586,40281 +55029,32427,30585,40217 +51973,32428,30584,40641 +56178,32429,30583,40433 +52118,32430,30582,40437 +55922,32431,30581,40160 +53402,32432,30580,40389 +59325,32433,30579,40569 +55927,32434,30578,40632 +55415,32435,30577,40959 +50585,32436,30576,40475 +58400,32437,30575,40960 +54756,32438,30574,40465 +52743,32439,30573,40868 +54392,32440,30572,40798 +51210,32441,30571,40313 +53859,32442,30570,40385 +56313,32443,30569,40125 +58512,32444,30568,40166 +50041,32445,30567,40206 +54909,32446,30566,40958 +57428,32447,30565,40593 +58378,32448,30564,40740 +54141,32449,30563,40381 +50333,32450,30562,40092 +54465,32451,30561,40779 +56451,32452,30560,40713 +53001,32453,30559,40829 +59041,32454,30558,40971 +53068,32455,30557,40616 +59416,32456,30556,40076 +59762,32457,30555,40607 +53367,32458,30554,40934 +54115,32459,30553,40837 +54922,32460,30552,40299 +50669,32461,30551,40703 +58929,32462,30550,40240 +51829,32463,30549,40995 +57387,32464,30548,40670 +56196,32465,30547,40921 +59521,32466,30546,40710 +52083,32467,30545,40981 +57039,32468,30544,40073 +54642,32469,30543,40918 +52173,32470,30542,40849 +53073,32471,30541,40607 +53420,32472,30540,40200 +53122,32473,30539,40399 +55643,32474,30538,40915 +57941,32475,30537,40974 +50889,32476,30536,40266 +53475,32477,30535,40462 +58373,32478,30534,40134 +55335,32479,30533,40387 +57218,32480,30532,40848 +58710,32481,30531,40705 +59558,32482,30530,40418 +50159,32483,30529,40146 +50129,32484,30528,40692 +51822,32485,30527,40328 +52747,32486,30526,40822 +52346,32487,30525,40677 +52534,32488,30524,40077 +54446,32489,30523,40684 +56755,32490,30522,40316 +52133,32491,30521,40659 +59632,32492,30520,40343 +53726,32493,30519,40568 +58063,32494,30518,40567 +53455,32495,30517,40293 +52658,32496,30516,40893 +55926,32497,30515,40633 +58642,32498,30514,40381 +51051,32499,30513,40229 +51886,32500,30512,40433 +56609,32501,30511,40551 +56865,32502,30510,40822 +52107,32503,30509,40246 +54924,32504,30508,40287 +52875,32505,30507,40532 +54083,32506,30506,40893 +50614,32507,30505,40113 +53076,32508,30504,40351 +56387,32509,30503,40369 +55361,32510,30502,40812 +59938,32511,30501,40956 +53359,32512,30500,40426 +59001,32513,30499,40773 +53367,32514,30498,40129 +58858,32515,30497,40490 +50697,32516,30496,40010 +55344,32517,30495,40287 +53153,32518,30494,40102 +54008,32519,30493,40399 +59458,32520,30492,40756 +54429,32521,30491,40841 +50718,32522,30490,40842 +54747,32523,30489,40547 +51703,32524,30488,40750 +54213,32525,30487,40077 +54576,32526,30486,40962 +58994,32527,30485,40844 +59085,32528,30484,40883 +51826,32529,30483,40601 +54826,32530,30482,40700 +53903,32531,30481,40694 +59447,32532,30480,40868 +54863,32533,30479,40700 +53888,32534,30478,40328 +56645,32535,30477,40036 +56634,32536,30476,40694 +53751,32537,30475,40288 +59529,32538,30474,40735 +55306,32539,30473,40653 +53759,32540,30472,40584 +54729,32541,30471,40312 +51200,32542,30470,40342 +50613,32543,30469,40858 +53409,32544,30468,40979 +50502,32545,30467,40577 +58926,32546,30466,40353 +55760,32547,30465,40404 +59802,32548,30464,40050 +58641,32549,30463,40994 +56737,32550,30462,40194 +57014,32551,30461,40640 +53210,32552,30460,40865 +55821,32553,30459,40573 +57080,32554,30458,40009 +50246,32555,30457,40692 +59136,32556,30456,40672 +57346,32557,30455,40230 +57556,32558,30454,40642 +57262,32559,30453,40049 +51198,32560,30452,40239 +52745,32561,30451,40528 +53833,32562,30450,40756 +56768,32563,30449,40312 +59400,32564,30448,40825 +55626,32565,30447,40669 +56250,32566,30446,40526 +52383,32567,30445,40415 +50709,32568,30444,40011 +58517,32569,30443,40164 +59919,32570,30442,40122 +57538,32571,30441,40227 +52604,32572,30440,40059 +57605,32573,30439,40650 +52882,32574,30438,40884 +53680,32575,30437,40045 +54424,32576,30436,40171 +54590,32577,30435,40668 +59741,32578,30434,40402 +54098,32579,30433,40255 +51044,32580,30432,40701 +55472,32581,30431,40745 +53389,32582,30430,40098 +58052,32583,30429,40334 +50463,32584,30428,40646 +50672,32585,30427,40161 +57074,32586,30426,40456 +50164,32587,30425,40815 +59033,32588,30424,40708 +52374,32589,30423,40954 +56700,32590,30422,40167 +59009,32591,30421,40171 +57428,32592,30420,40450 +56089,32593,30419,40007 +58479,32594,30418,40725 +52316,32595,30417,40149 +50339,32596,30416,40561 +53620,32597,30415,40721 +55503,32598,30414,40345 +57418,32599,30413,40552 +55245,32600,30412,40782 +53700,32601,30411,40712 +54916,32602,30410,40398 +56159,32603,30409,40523 +52410,32604,30408,40937 +58648,32605,30407,40441 +50151,32606,30406,40063 +57411,32607,30405,40678 +53076,32608,30404,40217 +57951,32609,30403,40463 +56514,32610,30402,40867 +56241,32611,30401,40540 +59800,32612,30400,40306 +51037,32613,30399,40859 +53524,32614,30398,40376 +51443,32615,30397,40497 +58370,32616,30396,40801 +55877,32617,30395,40029 +54586,32618,30394,40352 +50823,32619,30393,40627 +54276,32620,30392,40667 +59535,32621,30391,40050 +53447,32622,30390,40209 +50092,32623,30389,40971 +55679,32624,30388,40860 +54467,32625,30387,40822 +56716,32626,30386,40838 +50789,32627,30385,40914 +55991,32628,30384,40724 +55676,32629,30383,40137 +52432,32630,30382,40297 +54084,32631,30381,40270 +51154,32632,30380,40817 +54902,32633,30379,40828 +59080,32634,30378,40587 +56688,32635,30377,40676 +54889,32636,30376,40961 +54784,32637,30375,40250 +53039,32638,30374,40015 +50527,32639,30373,40461 +56678,32640,30372,40078 +50090,32641,30371,40233 +50815,32642,30370,40572 +56524,32643,30369,40555 +55844,32644,30368,40586 +56584,32645,30367,40480 +59638,32646,30366,40538 +57249,32647,30365,40010 +58786,32648,30364,40738 +53004,32649,30363,40905 +52898,32650,30362,40929 +51181,32651,30361,40321 +59343,32652,30360,40365 +59567,32653,30359,40989 +50324,32654,30358,40695 +55424,32655,30357,40785 +58863,32656,30356,40084 +59592,32657,30355,40204 +50752,32658,30354,40376 +52058,32659,30353,40626 +56004,32660,30352,40257 +55394,32661,30351,40828 +55947,32662,30350,40613 +50639,32663,30349,40522 +58197,32664,30348,40409 +53018,32665,30347,40247 +55003,32666,30346,40912 +59220,32667,30345,40743 +51002,32668,30344,40652 +51199,32669,30343,40352 +51130,32670,30342,40108 +51731,32671,30341,40873 +52412,32672,30340,40969 +57280,32673,30339,40587 +55059,32674,30338,40382 +54179,32675,30337,40811 +55946,32676,30336,40413 +57633,32677,30335,40713 +53363,32678,30334,40112 +57600,32679,30333,40793 +59759,32680,30332,40018 +58085,32681,30331,40116 +52457,32682,30330,40395 +54440,32683,30329,40561 +52460,32684,30328,40153 +51540,32685,30327,40389 +55669,32686,30326,40810 +50315,32687,30325,40332 +52292,32688,30324,40323 +58039,32689,30323,40666 +52492,32690,30322,40347 +56586,32691,30321,40059 +51290,32692,30320,40217 +56823,32693,30319,40627 +57362,32694,30318,40070 +53977,32695,30317,40140 +51924,32696,30316,40017 +54897,32697,30315,40770 +52894,32698,30314,40230 +56301,32699,30313,40268 +58555,32700,30312,40057 +50980,32701,30311,40657 +56569,32702,30310,40629 +55566,32703,30309,40851 +55592,32704,30308,40844 +59184,32705,30307,40933 +59758,32706,30306,40033 +59877,32707,30305,40589 +54664,32708,30304,40962 +55816,32709,30303,40598 +51547,32710,30302,40859 +56623,32711,30301,40358 +53337,32712,30300,40417 +51505,32713,30299,40222 +54031,32714,30298,40997 +52183,32715,30297,40683 +57706,32716,30296,40544 +53376,32717,30295,40223 +57497,32718,30294,40849 +51791,32719,30293,40973 +51982,32720,30292,40192 +56032,32721,30291,40616 +58127,32722,30290,40710 +56616,32723,30289,40766 +50281,32724,30288,40331 +54457,32725,30287,40318 +51108,32726,30286,40060 +56788,32727,30285,40315 +56945,32728,30284,40303 +52329,32729,30283,40524 +56479,32730,30282,40188 +55354,32731,30281,40170 +58013,32732,30280,40474 +56495,32733,30279,40733 +51498,32734,30278,40218 +57298,32735,30277,40731 +58825,32736,30276,40908 +50042,32737,30275,40838 +55329,32738,30274,40525 +57653,32739,30273,40825 +59712,32740,30272,40610 +57165,32741,30271,40423 +53375,32742,30270,40011 +50350,32743,30269,40568 +58880,32744,30268,40255 +58670,32745,30267,40784 +50068,32746,30266,40055 +52394,32747,30265,40862 +57225,32748,30264,40618 +51378,32749,30263,40534 +50992,32750,30262,40805 +58923,32751,30261,40339 +51981,32752,30260,40860 +53379,32753,30259,40589 +58920,32754,30258,40642 +52593,32755,30257,40114 +57857,32756,30256,40105 +56985,32757,30255,40157 +59888,32758,30254,40294 +58447,32759,30253,40400 +55690,32760,30252,40452 +54532,32761,30251,40366 +51584,32762,30250,40075 +52972,32763,30249,40898 +51921,32764,30248,40612 +57216,32765,30247,40325 +51951,32766,30246,40085 +54238,32767,30245,40400 +54927,32768,30244,40340 +53470,32769,30243,40671 +53050,32770,30242,40313 +51504,32771,30241,40838 +52689,32772,30240,40852 +55777,32773,30239,40819 +57325,32774,30238,40072 +53069,32775,30237,40663 +59988,32776,30236,40283 +53486,32777,30235,40578 +59672,32778,30234,40851 +51778,32779,30233,40602 +55161,32780,30232,40174 +56218,32781,30231,40168 +51499,32782,30230,40693 +50559,32783,30229,40175 +59090,32784,30228,40815 +58320,32785,30227,40466 +53161,32786,30226,40062 +52534,32787,30225,40128 +50723,32788,30224,40904 +52760,32789,30223,40078 +57225,32790,30222,40237 +54938,32791,30221,40802 +59857,32792,30220,40335 +51664,32793,30219,40728 +58447,32794,30218,40450 +54577,32795,30217,40731 +50646,32796,30216,40850 +52919,32797,30215,40841 +50759,32798,30214,40724 +57986,32799,30213,40123 +56970,32800,30212,40738 +57356,32801,30211,40672 +56810,32802,30210,40286 +58199,32803,30209,40453 +56267,32804,30208,40897 +51091,32805,30207,40715 +55527,32806,30206,40713 +51756,32807,30205,40437 +50453,32808,30204,40837 +56383,32809,30203,40428 +52731,32810,30202,40182 +51005,32811,30201,40024 +53450,32812,30200,40501 +57129,32813,30199,40198 +54648,32814,30198,40667 +53835,32815,30197,40625 +58364,32816,30196,40008 +56807,32817,30195,40342 +55121,32818,30194,40187 +55687,32819,30193,40704 +55453,32820,30192,40779 +50773,32821,30191,40636 +52668,32822,30190,40744 +56037,32823,30189,40906 +57349,32824,30188,40593 +59135,32825,30187,40321 +59422,32826,30186,40635 +54186,32827,30185,40462 +58219,32828,30184,40330 +55092,32829,30183,40993 +56914,32830,30182,40143 +54750,32831,30181,40924 +51130,32832,30180,40494 +54948,32833,30179,40584 +57650,32834,30178,40427 +59355,32835,30177,40437 +51342,32836,30176,40593 +55266,32837,30175,40382 +54427,32838,30174,40862 +53307,32839,30173,40544 +58548,32840,30172,40199 +51379,32841,30171,40301 +55773,32842,30170,40083 +54397,32843,30169,40064 +58525,32844,30168,40870 +56877,32845,30167,40303 +59417,32846,30166,40517 +53727,32847,30165,40712 +55066,32848,30164,40560 +51064,32849,30163,40274 +56945,32850,30162,40289 +54661,32851,30161,40273 +57457,32852,30160,40480 +51600,32853,30159,40789 +54282,32854,30158,40672 +55297,32855,30157,40848 +52838,32856,30156,40626 +52944,32857,30155,40034 +51228,32858,30154,40995 +52248,32859,30153,40931 +54498,32860,30152,40221 +56551,32861,30151,40756 +50304,32862,30150,40111 +54003,32863,30149,40826 +53152,32864,30148,40890 +51575,32865,30147,40144 +53809,32866,30146,40321 +59706,32867,30145,40560 +51450,32868,30144,40139 +53232,32869,30143,40381 +50027,32870,30142,40481 +59034,32871,30141,40800 +52096,32872,30140,40270 +55929,32873,30139,40965 +56975,32874,30138,40552 +56864,32875,30137,40402 +52576,32876,30136,40722 +50487,32877,30135,40308 +56428,32878,30134,40203 +52444,32879,30133,40101 +53886,32880,30132,40079 +51636,32881,30131,40102 +52263,32882,30130,40607 +50911,32883,30129,40140 +54494,32884,30128,40751 +56553,32885,30127,40610 +52035,32886,30126,40285 +51756,32887,30125,40907 +55588,32888,30124,40961 +55811,32889,30123,40403 +59065,32890,30122,40373 +52634,32891,30121,40177 +59050,32892,30120,40698 +54673,32893,30119,40003 +51009,32894,30118,40964 +53327,32895,30117,40414 +53018,32896,30116,40228 +52147,32897,30115,40239 +58855,32898,30114,40344 +58182,32899,30113,40795 +58095,32900,30112,40360 +52700,32901,30111,40784 +58486,32902,30110,40656 +58186,32903,30109,40262 +50808,32904,30108,40413 +53457,32905,30107,40966 +58431,32906,30106,40798 +54600,32907,30105,40133 +50197,32908,30104,40929 +50280,32909,30103,40332 +51891,32910,30102,40590 +50800,32911,30101,40696 +57175,32912,30100,40836 +51289,32913,30099,40649 +57076,32914,30098,40342 +50452,32915,30097,40729 +51108,32916,30096,40826 +56800,32917,30095,40658 +53048,32918,30094,40038 +50807,32919,30093,40516 +51840,32920,30092,40311 +50696,32921,30091,40867 +50693,32922,30090,40543 +55135,32923,30089,40393 +54324,32924,30088,40138 +54592,32925,30087,40469 +51398,32926,30086,40621 +52548,32927,30085,40895 +59594,32928,30084,40404 +51466,32929,30083,40222 +58020,32930,30082,40175 +54478,32931,30081,40617 +54286,32932,30080,40480 +53335,32933,30079,40126 +58716,32934,30078,40371 +52505,32935,30077,40514 +52366,32936,30076,40002 +54091,32937,30075,40750 +55695,32938,30074,40740 +50196,32939,30073,40170 +58763,32940,30072,40266 +52767,32941,30071,40208 +55021,32942,30070,40150 +57677,32943,30069,40336 +55989,32944,30068,40856 +50777,32945,30067,40204 +58841,32946,30066,40094 +56710,32947,30065,40335 +53971,32948,30064,40591 +51637,32949,30063,40103 +53160,32950,30062,40868 +55027,32951,30061,40067 +58104,32952,30060,40467 +57807,32953,30059,40939 +56833,32954,30058,40410 +54153,32955,30057,40955 +55006,32956,30056,40461 +51558,32957,30055,40267 +51709,32958,30054,40219 +56752,32959,30053,40542 +52526,32960,30052,40979 +57195,32961,30051,40485 +54632,32962,30050,40983 +58306,32963,30049,40968 +54390,32964,30048,40162 +54943,32965,30047,40624 +51166,32966,30046,40371 +54281,32967,30045,40755 +56577,32968,30044,40142 +59960,32969,30043,40709 +58222,32970,30042,40075 +59620,32971,30041,40440 +51490,32972,30040,40094 +58219,32973,30039,40160 +50154,32974,30038,40170 +57682,32975,30037,40758 +52041,32976,30036,40026 +57267,32977,30035,40542 +50116,32978,30034,40622 +51572,32979,30033,40607 +59899,32980,30032,40558 +58488,32981,30031,40326 +56706,32982,30030,40094 +56863,32983,30029,40447 +51726,32984,30028,40534 +54537,32985,30027,40578 +58955,32986,30026,40349 +51255,32987,30025,40606 +52889,32988,30024,40906 +53250,32989,30023,40381 +58568,32990,30022,40358 +56709,32991,30021,40227 +53304,32992,30020,40161 +55637,32993,30019,40763 +53683,32994,30018,40815 +57666,32995,30017,40728 +55846,32996,30016,40927 +59413,32997,30015,40597 +56698,32998,30014,40344 +50841,32999,30013,40323 +51393,33000,30012,40880 +56806,33001,30011,40301 +57084,33002,30010,40715 +57400,33003,30009,40704 +54106,33004,30008,40412 +54798,33005,30007,40396 +52346,33006,30006,40635 +52431,33007,30005,40873 +51377,33008,30004,40011 +54631,33009,30003,40992 +52183,33010,30002,40167 +52894,33011,30001,40120 +57612,33012,30000,40856 +53002,33013,31000,40170 +52616,33014,30999,40293 +57643,33015,30998,40729 +58704,33016,30997,40944 +59700,33017,30996,40425 +51509,33018,30995,40577 +55690,33019,30994,40963 +58182,33020,30993,40202 +56660,33021,30992,40002 +55093,33022,30991,40501 +54786,33023,30990,40037 +58983,33024,30989,40349 +51946,33025,30988,40833 +54549,33026,30987,40088 +52750,33027,30986,40922 +51792,33028,30985,40662 +53434,33029,30984,40807 +52738,33030,30983,40426 +50905,33031,30982,40599 +50783,33032,30981,40209 +56519,33033,30980,40851 +50889,33034,30979,40619 +59072,33035,30978,40690 +57027,33036,30977,40253 +54535,33037,30976,40555 +50365,33038,30975,40961 +53684,33039,30974,40610 +59103,33040,30973,40483 +54645,33041,30972,40282 +56865,33042,30971,40328 +55493,33043,30970,40979 +53926,33044,30969,40373 +50873,33045,30968,40657 +53305,33046,30967,40561 +51143,33047,30966,40473 +52432,33048,30965,40273 +58946,33049,30964,40408 +52349,33050,30963,40966 +56880,33051,30962,40817 +57956,33052,30961,40164 +50348,33053,30960,40499 +53942,33054,30959,40753 +56119,33055,30958,40637 +53179,33056,30957,40056 +55018,33057,30956,40527 +51919,33058,30955,40914 +56038,33059,30954,40598 +52707,33060,30953,40049 +54012,33061,30952,40699 +52084,33062,30951,40504 +51721,33063,30950,40362 +54329,33064,30949,40513 +59753,33065,30948,40858 +58022,33066,30947,40356 +52653,33067,30946,40437 +57501,33068,30945,40321 +52935,33069,30944,40125 +56004,33070,30943,40291 +53745,33071,30942,40905 +52177,33072,30941,40857 +54509,33073,30940,40371 +58322,33074,30939,40322 +55879,33075,30938,40272 +59098,33076,30937,40277 +53415,33077,30936,40931 +59894,33078,30935,40322 +51715,33079,30934,40646 +54285,33080,30933,40023 +54465,33081,30932,40854 +52325,33082,30931,40883 +59594,33083,30930,40761 +51987,33084,30929,40689 +58682,33085,30928,40927 +56538,33086,30927,40730 +53652,33087,30926,40354 +58917,33088,30925,40922 +53171,33089,30924,40716 +53983,33090,30923,40821 +57899,33091,30922,40916 +58159,33092,30921,40117 +54909,33093,30920,40628 +51826,33094,30919,40547 +57241,33095,30918,40273 +55984,33096,30917,40575 +55694,33097,30916,40264 +54385,33098,30915,40870 +57501,33099,30914,40442 +52664,33100,30913,40264 +58540,33101,30912,40180 +53357,33102,30911,40170 +53126,33103,30910,40125 +56777,33104,30909,40406 +57167,33105,30908,40476 +59402,33106,30907,40277 +55206,33107,30906,40494 +50375,33108,30905,40631 +59315,33109,30904,40585 +57389,33110,30903,40767 +53327,33111,30902,40345 +56887,33112,30901,40325 +53043,33113,30900,40220 +50236,33114,30899,40241 +55433,33115,30898,40131 +56675,33116,30897,40473 +58623,33117,30896,40879 +50641,33118,30895,40215 +53962,33119,30894,40126 +56035,33120,30893,40050 +59926,33121,30892,40505 +59655,33122,30891,40144 +59579,33123,30890,40499 +53924,33124,30889,40389 +55740,33125,30888,40624 +56683,33126,30887,40378 +57082,33127,30886,40591 +54677,33128,30885,40316 +58261,33129,30884,40878 +57467,33130,30883,40808 +51266,33131,30882,40640 +53509,33132,30881,40321 +51655,33133,30880,40502 +54554,33134,30879,40605 +54531,33135,30878,40887 +54806,33136,30877,40114 +56060,33137,30876,40189 +53498,33138,30875,40256 +59344,33139,30874,40182 +57276,33140,30873,40035 +53917,33141,30872,40531 +59967,33142,30871,40728 +54924,33143,30870,40945 +55582,33144,30869,40129 +55015,33145,30868,40673 +56002,33146,30867,40159 +59820,33147,30866,40102 +59060,33148,30865,40939 +51193,33149,30864,40411 +51403,33150,30863,40857 +50343,33151,30862,40646 +53974,33152,30861,40257 +51508,33153,30860,40277 +54934,33154,30859,40923 +54152,33155,30858,40404 +58259,33156,30857,40959 +53881,33157,30856,40327 +56095,33158,30855,40182 +57466,33159,30854,40594 +56647,33160,30853,40568 +52286,33161,30852,40643 +58613,33162,30851,40115 +52330,33163,30850,40376 +57059,33164,30849,40588 +52089,33165,30848,40851 +59914,33166,30847,40918 +50585,33167,30846,40951 +59432,33168,30845,40020 +51858,33169,30844,40509 +50832,33170,30843,40900 +53655,33171,30842,40752 +50619,33172,30841,40883 +55509,33173,30840,40209 +57037,33174,30839,40759 +51288,33175,30838,40647 +50819,33176,30837,40492 +50365,33177,30836,40702 +52984,33178,30835,40134 +57202,33179,30834,40699 +59862,33180,30833,40784 +51034,33181,30832,40474 +59817,33182,30831,40943 +57757,33183,30830,40901 +54655,33184,30829,40583 +59851,33185,30828,40825 +53836,33186,30827,40879 +57681,33187,30826,40294 +57194,33188,30825,40163 +55396,33189,30824,40051 +53038,33190,30823,40158 +57419,33191,30822,40763 +55990,33192,30821,40690 +54249,33193,30820,40120 +53502,33194,30819,40238 +52231,33195,30818,40746 +51217,33196,30817,40378 +56049,33197,30816,40620 +58205,33198,30815,40682 +52343,33199,30814,40916 +58831,33200,30813,40901 +55395,33201,30812,40845 +59438,33202,30811,40161 +55834,33203,30810,40771 +55971,33204,30809,40004 +54539,33205,30808,40522 +59398,33206,30807,40361 +51173,33207,30806,40098 +54148,33208,30805,40598 +56806,33209,30804,40523 +57436,33210,30803,40230 +51629,33211,30802,40122 +57433,33212,30801,40320 +58753,33213,30800,40965 +51129,33214,30799,40978 +55978,33215,30798,40433 +50733,33216,30797,40715 +54765,33217,30796,40517 +59289,33218,30795,40076 +57526,33219,30794,40826 +59931,33220,30793,40730 +58766,33221,30792,40530 +55640,33222,30791,40500 +54235,33223,30790,40977 +55298,33224,30789,40467 +53926,33225,30788,40229 +54358,33226,30787,40842 +50872,33227,30786,40262 +55121,33228,30785,40771 +58414,33229,30784,40921 +55923,33230,30783,40996 +51548,33231,30782,40183 +54492,33232,30781,40620 +57038,33233,30780,40277 +59618,33234,30779,40414 +55209,33235,30778,40215 +54501,33236,30777,40513 +54560,33237,30776,40334 +56313,33238,30775,40361 +51746,33239,30774,40820 +53379,33240,30773,40510 +51344,33241,30772,40160 +59951,33242,30771,40422 +52828,33243,30770,40578 +54510,33244,30769,40842 +52302,33245,30768,40628 +58637,33246,30767,40634 +58128,33247,30766,40346 +55712,33248,30765,40270 +52281,33249,30764,40896 +57645,33250,30763,40722 +56151,33251,30762,40407 +58661,33252,30761,40732 +56693,33253,30760,40052 +58766,33254,30759,40869 +59740,33255,30758,40333 +58843,33256,30757,40602 +53302,33257,30756,40553 +52253,33258,30755,40895 +52525,33259,30754,40907 +59458,33260,30753,40743 +56050,33261,30752,40417 +50316,33262,30751,40298 +58266,33263,30750,40287 +55837,33264,30749,40211 +57923,33265,30748,40028 +53102,33266,30747,40132 +51060,33267,30746,40214 +58255,33268,30745,40976 +53138,33269,30744,40767 +50664,33270,30743,40901 +52191,33271,30742,40595 +55806,33272,30741,40373 +57484,33273,30740,40732 +56738,33274,30739,40263 +56848,33275,30738,40492 +52099,33276,30737,40615 +52097,33277,30736,40686 +52164,33278,30735,40094 +51998,33279,30734,40866 +52264,33280,30733,40447 +53231,33281,30732,40435 +52345,33282,30731,40360 +58548,33283,30730,40463 +57543,33284,30729,40561 +55307,33285,30728,40442 +54622,33286,30727,40204 +55693,33287,30726,40759 +55041,33288,30725,40440 +52743,33289,30724,40725 +52083,33290,30723,40500 +56519,33291,30722,40329 +58644,33292,30721,40837 +54604,33293,30720,40534 +54952,33294,30719,40868 +57664,33295,30718,40981 +54003,33296,30717,40287 +56562,33297,30716,40794 +50273,33298,30715,40114 +59147,33299,30714,40590 +59186,33300,30713,40618 +57459,33301,30712,40627 +55138,33302,30711,40934 +54572,33303,30710,40127 +51543,33304,30709,40986 +50379,33305,30708,40359 +55588,33306,30707,40105 +53015,33307,30706,40103 +59002,33308,30705,40950 +53274,33309,30704,40868 +50029,33310,30703,40887 +57700,33311,30702,40695 +58629,33312,30701,40079 +53423,33313,30700,40902 +50251,33314,30699,40143 +51518,33315,30698,40200 +53539,33316,30697,40944 +55086,33317,30696,40068 +52650,33318,30695,40071 +52814,33319,30694,40598 +59700,33320,30693,40877 +51739,33321,30692,40792 +55752,33322,30691,40514 +55060,33323,30690,40073 +59320,33324,30689,40174 +59053,33325,30688,40165 +54568,33326,30687,40363 +52174,33327,30686,40633 +54639,33328,30685,40603 +50011,33329,30684,40209 +58315,33330,30683,40633 +52799,33331,30682,40616 +56255,33332,30681,40542 +55169,33333,30680,40530 +55560,33334,30679,40211 +56425,33335,30678,40257 +55869,33336,30677,40830 +52204,33337,30676,40219 +56276,33338,30675,40531 +55458,33339,30674,40500 +53874,33340,30673,40720 +57097,33341,30672,40157 +52058,33342,30671,40109 +57170,33343,30670,40161 +53351,33344,30669,40870 +58506,33345,30668,40584 +52549,33346,30667,40902 +59267,33347,30666,40162 +55321,33348,30665,40154 +56352,33349,30664,40297 +53712,33350,30663,40591 +57072,33351,30662,40515 +54773,33352,30661,40720 +54193,33353,30660,40019 +52620,33354,30659,40552 +58454,33355,30658,40891 +57052,33356,30657,40001 +53267,33357,30656,40712 +50698,33358,30655,40191 +57397,33359,30654,40946 +53504,33360,30653,40989 +50542,33361,30652,40583 +53100,33362,30651,40193 +56670,33363,30650,40491 +58981,33364,30649,40237 +58158,33365,30648,40749 +53496,33366,30647,40781 +58038,33367,30646,40385 +57088,33368,30645,40873 +54671,33369,30644,40678 +53764,33370,30643,40814 +50130,33371,30642,40507 +59275,33372,30641,40613 +58814,33373,30640,40403 +53370,33374,30639,40319 +56345,33375,30638,40345 +57150,33376,30637,40267 +56094,33377,30636,40242 +50197,33378,30635,40246 +53573,33379,30634,40174 +55927,33380,30633,40606 +53904,33381,30632,40922 +57218,33382,30631,40619 +57825,33383,30630,40198 +54371,33384,30629,40666 +59097,33385,30628,40246 +54512,33386,30627,40080 +59339,33387,30626,40911 +50306,33388,30625,40175 +51439,33389,30624,40615 +52816,33390,30623,40576 +56083,33391,30622,40777 +57446,33392,30621,40733 +59580,33393,30620,40844 +54564,33394,30619,40201 +57898,33395,30618,40568 +50019,33396,30617,40383 +57113,33397,30616,40972 +59523,33398,30615,40508 +51460,33399,30614,40566 +50704,33400,30613,40714 +59748,33401,30612,40528 +51363,33402,30611,40465 +53558,33403,30610,40723 +59205,33404,30609,40468 +51706,33405,30608,40891 +52862,33406,30607,40294 +56487,33407,30606,40807 +53947,33408,30605,40711 +59628,33409,30604,40155 +57597,33410,30603,40103 +54850,33411,30602,40660 +50798,33412,30601,40373 +50686,33413,30600,40551 +51727,33414,30599,40900 +58642,33415,30598,40086 +58045,33416,30597,40891 +59539,33417,30596,40808 +59747,33418,30595,40943 +57845,33419,30594,40012 +51672,33420,30593,40776 +56770,33421,30592,40562 +57672,33422,30591,40757 +54922,33423,30590,40734 +50881,33424,30589,40348 +59715,33425,30588,40218 +59476,33426,30587,40146 +59794,33427,30586,40358 +53243,33428,30585,40235 +53346,33429,30584,40215 +57658,33430,30583,40503 +50417,33431,30582,40169 +59102,33432,30581,40162 +58587,33433,30580,40594 +51170,33434,30579,40222 +50749,33435,30578,40645 +54032,33436,30577,40062 +59467,33437,30576,40024 +58820,33438,30575,40857 +58190,33439,30574,40186 +52796,33440,30573,40201 +52325,33441,30572,40788 +57036,33442,30571,40584 +55084,33443,30570,40115 +51311,33444,30569,40126 +52362,33445,30568,40855 +56599,33446,30567,40370 +53620,33447,30566,40548 +58629,33448,30565,40794 +57903,33449,30564,40666 +50916,33450,30563,40232 +54947,33451,30562,40875 +50960,33452,30561,40227 +51067,33453,30560,40496 +50372,33454,30559,40231 +50344,33455,30558,40816 +54129,33456,30557,40178 +51413,33457,30556,40519 +55930,33458,30555,40500 +51174,33459,30554,40230 +55436,33460,30553,40498 +55305,33461,30552,40405 +55036,33462,30551,40359 +54799,33463,30550,40682 +57544,33464,30549,40664 +54068,33465,30548,40436 +57295,33466,30547,40418 +54009,33467,30546,40937 +54444,33468,30545,40267 +50323,33469,30544,40472 +50045,33470,30543,40697 +58173,33471,30542,40995 +53443,33472,30541,40723 +50152,33473,30540,40477 +59714,33474,30539,40170 +52482,33475,30538,40548 +50984,33476,30537,40419 +53748,33477,30536,40027 +51723,33478,30535,40132 +53670,33479,30534,40191 +54634,33480,30533,40120 +53869,33481,30532,40204 +54389,33482,30531,40745 +58501,33483,30530,40179 +54601,33484,30529,40033 +51609,33485,30528,40706 +59187,33486,30527,40717 +50783,33487,30526,40432 +58886,33488,30525,40935 +55089,33489,30524,40123 +50648,33490,30523,40774 +51062,33491,30522,40536 +55254,33492,30521,40940 +57631,33493,30520,40174 +52632,33494,30519,40812 +56989,33495,30518,40248 +51088,33496,30517,40357 +51551,33497,30516,40837 +52587,33498,30515,40448 +51721,33499,30514,40262 +56314,33500,30513,40602 +52993,33501,30512,40435 +53418,33502,30511,40966 +54163,33503,30510,40562 +56431,33504,30509,40114 +50309,33505,30508,40917 +57424,33506,30507,40396 +55284,33507,30506,40591 +58139,33508,30505,40394 +52509,33509,30504,40019 +52745,33510,30503,40291 +51016,33511,30502,40456 +51676,33512,30501,40228 +52510,33513,30500,40237 +55317,33514,30499,40618 +56667,33515,30498,40477 +55971,33516,30497,40369 +51630,33517,30496,40655 +59398,33518,30495,40280 +50654,33519,30494,40677 +59329,33520,30493,40778 +55047,33521,30492,40735 +59885,33522,30491,40137 +53362,33523,30490,40596 +50394,33524,30489,40736 +53954,33525,30488,40620 +52304,33526,30487,40445 +59931,33527,30486,40708 +53348,33528,30485,40913 +55949,33529,30484,40334 +53687,33530,30483,40718 +58990,33531,30482,40141 +58360,33532,30481,40276 +53573,33533,30480,40458 +51306,33534,30479,40143 +56226,33535,30478,40534 +53184,33536,30477,40433 +59676,33537,30476,40917 +51748,33538,30475,40399 +57426,33539,30474,40299 +52983,33540,30473,40411 +50115,33541,30472,40062 +59922,33542,30471,40398 +53658,33543,30470,40103 +53996,33544,30469,40391 +53984,33545,30468,40878 +53556,33546,30467,40621 +54821,33547,30466,40921 +57566,33548,30465,40349 +57241,33549,30464,40840 +50747,33550,30463,40472 +57141,33551,30462,40473 +56704,33552,30461,40491 +55143,33553,30460,40123 +56665,33554,30459,40348 +57034,33555,30458,40537 +58374,33556,30457,40319 +50612,33557,30456,40917 +50147,33558,30455,40882 +58937,33559,30454,40845 +54294,33560,30453,40467 +59708,33561,30452,40879 +58754,33562,30451,40468 +53654,33563,30450,40309 +50600,33564,30449,40672 +55087,33565,30448,40917 +56365,33566,30447,40941 +51705,33567,30446,40648 +56182,33568,30445,40110 +55117,33569,30444,40117 +55807,33570,30443,40539 +52285,33571,30442,40441 +59388,33572,30441,40711 +55480,33573,30440,40381 +51527,33574,30439,40166 +58044,33575,30438,40387 +57704,33576,30437,40129 +57109,33577,30436,40774 +58611,33578,30435,40360 +55268,33579,30434,40606 +56794,33580,30433,40434 +55147,33581,30432,40557 +52291,33582,30431,40684 +59652,33583,30430,40905 +50373,33584,30429,40220 +55489,33585,30428,40766 +59868,33586,30427,40960 +54479,33587,30426,40863 +50940,33588,30425,40432 +53028,33589,30424,40849 +59954,33590,30423,40317 +55223,33591,30422,40365 +51781,33592,30421,40348 +57246,33593,30420,40487 +51515,33594,30419,40723 +56994,33595,30418,40287 +59241,33596,30417,40047 +50784,33597,30416,40420 +57251,33598,30415,40400 +53785,33599,30414,40816 +52625,33600,30413,40969 +52808,33601,30412,40916 +52450,33602,30411,40768 +52867,33603,30410,40528 +50154,33604,30409,40326 +53275,33605,30408,40999 +50871,33606,30407,40683 +59006,33607,30406,40965 +56833,33608,30405,40737 +55468,33609,30404,40502 +51024,33610,30403,40939 +56102,33611,30402,40829 +51736,33612,30401,40883 +50450,33613,30400,40173 +57087,33614,30399,40597 +58427,33615,30398,40008 +52463,33616,30397,40227 +58182,33617,30396,40473 +55174,33618,30395,40965 +51647,33619,30394,40416 +57610,33620,30393,40564 +53953,33621,30392,40361 +58395,33622,30391,40468 +54949,33623,30390,40961 +51169,33624,30389,40476 +53810,33625,30388,40783 +53524,33626,30387,40171 +54275,33627,30386,40323 +52491,33628,30385,40601 +51862,33629,30384,40710 +52412,33630,30383,40023 +54608,33631,30382,40365 +51841,33632,30381,40620 +59422,33633,30380,40371 +56060,33634,30379,40077 +59270,33635,30378,40929 +59665,33636,30377,40975 +58444,33637,30376,40165 +52482,33638,30375,40356 +50608,33639,30374,40597 +54760,33640,30373,40560 +57269,33641,30372,40870 +53741,33642,30371,40103 +53565,33643,30370,40549 +52406,33644,30369,40334 +54431,33645,30368,40777 +56973,33646,30367,40226 +54875,33647,30366,40868 +56142,33648,30365,40160 +52996,33649,30364,40796 +54087,33650,30363,40874 +57308,33651,30362,40762 +55554,33652,30361,40235 +58973,33653,30360,40853 +55711,33654,30359,40399 +51875,33655,30358,40364 +52202,33656,30357,40914 +59848,33657,30356,40119 +59212,33658,30355,40292 +55383,33659,30354,40488 +57278,33660,30353,40701 +57058,33661,30352,40188 +50328,33662,30351,40883 +59311,33663,30350,40248 +59959,33664,30349,40645 +52461,33665,30348,40593 +51629,33666,30347,40042 +57861,33667,30346,40372 +51922,33668,30345,40283 +55403,33669,30344,40687 +52712,33670,30343,40602 +50611,33671,30342,40170 +53020,33672,30341,40174 +52464,33673,30340,40597 +57080,33674,30339,40420 +59079,33675,30338,40528 +55638,33676,30337,40315 +59587,33677,30336,40273 +59215,33678,30335,40788 +52946,33679,30334,40581 +55746,33680,30333,40284 +58589,33681,30332,40822 +53056,33682,30331,40248 +50516,33683,30330,40685 +59427,33684,30329,40084 +56568,33685,30328,40557 +53663,33686,30327,40248 +54578,33687,30326,40044 +56929,33688,30325,40391 +59936,33689,30324,40646 +58084,33690,30323,40117 +52736,33691,30322,40039 +54050,33692,30321,40076 +58677,33693,30320,40805 +54311,33694,30319,40451 +50023,33695,30318,40456 +54546,33696,30317,40820 +57735,33697,30316,40415 +56629,33698,30315,40096 +52447,33699,30314,40528 +53131,33700,30313,40314 +58968,33701,30312,40940 +57737,33702,30311,40557 +54085,33703,30310,40989 +57261,33704,30309,40594 +57949,33705,30308,40388 +58275,33706,30307,40786 +51670,33707,30306,40963 +59927,33708,30305,40828 +56525,33709,30304,40500 +59332,33710,30303,40219 +54002,33711,30302,40836 +53227,33712,30301,40567 +58255,33713,30300,40120 +56207,33714,30299,40895 +57113,33715,30298,40106 +51309,33716,30297,40096 +50848,33717,30296,40416 +53450,33718,30295,40861 +54577,33719,30294,40673 +51108,33720,30293,40083 +52618,33721,30292,40261 +57946,33722,30291,40478 +52797,33723,30290,40392 +59911,33724,30289,40214 +52110,33725,30288,40650 +52682,33726,30287,40712 +52663,33727,30286,40462 +56513,33728,30285,40186 +51515,33729,30284,40781 +52724,33730,30283,40247 +50694,33731,30282,40454 +57102,33732,30281,40963 +57139,33733,30280,40621 +56933,33734,30279,40756 +51464,33735,30278,40917 +52347,33736,30277,40581 +51100,33737,30276,40731 +59213,33738,30275,40248 +54937,33739,30274,40049 +56728,33740,30273,40318 +56236,33741,30272,40859 +55100,33742,30271,40974 +51770,33743,30270,40041 +56457,33744,30269,40737 +51068,33745,30268,40946 +57110,33746,30267,40870 +57130,33747,30266,40689 +58720,33748,30265,40919 +54390,33749,30264,40175 +59135,33750,30263,40998 +50783,33751,30262,40308 +59365,33752,30261,40661 +59271,33753,30260,40443 +59871,33754,30259,40945 +52158,33755,30258,40010 +56190,33756,30257,40730 +59101,33757,30256,40259 +55391,33758,30255,40578 +52766,33759,30254,40754 +51174,33760,30253,40975 +54424,33761,30252,40826 +53114,33762,30251,40471 +58057,33763,30250,40886 +58713,33764,30249,40615 +51149,33765,30248,40577 +58108,33766,30247,40504 +57627,33767,30246,40139 +53910,33768,30245,40078 +54094,33769,30244,40905 +50502,33770,30243,40630 +52240,33771,30242,40840 +57131,33772,30241,40628 +56114,33773,30240,40957 +57559,33774,30239,40262 +51865,33775,30238,40844 +53852,33776,30237,40601 +53107,33777,30236,40531 +50628,33778,30235,40206 +59592,33779,30234,40585 +59085,33780,30233,40448 +52795,33781,30232,40193 +55632,33782,30231,40204 +50398,33783,30230,40837 +54770,33784,30229,40141 +53061,33785,30228,40193 +58660,33786,30227,40244 +53587,33787,30226,40854 +58805,33788,30225,40945 +53682,33789,30224,40543 +52376,33790,30223,40472 +52222,33791,30222,40747 +57376,33792,30221,40970 +56240,33793,30220,40335 +57959,33794,30219,40311 +51433,33795,30218,40559 +59246,33796,30217,40357 +56420,33797,30216,40793 +56351,33798,30215,40840 +53662,33799,30214,40239 +58798,33800,30213,40286 +54673,33801,30212,40255 +56446,33802,30211,40182 +54556,33803,30210,40040 +55792,33804,30209,40604 +50398,33805,30208,40003 +57653,33806,30207,40723 +55745,33807,30206,40972 +55445,33808,30205,40816 +51364,33809,30204,40947 +50153,33810,30203,40142 +59857,33811,30202,40275 +53218,33812,30201,40436 +51101,33813,30200,40303 +51116,33814,30199,40183 +54237,33815,30198,40116 +53117,33816,30197,40517 +56934,33817,30196,40231 +59624,33818,30195,40079 +53933,33819,30194,40035 +56718,33820,30193,40074 +54557,33821,30192,40167 +55652,33822,30191,40219 +51510,33823,30190,40850 +57679,33824,30189,40260 +56195,33825,30188,40812 +54364,33826,30187,40152 +51268,33827,30186,40386 +56268,33828,30185,40462 +51738,33829,30184,40989 +57436,33830,30183,40733 +54001,33831,30182,40672 +54803,33832,30181,40925 +55943,33833,30180,40316 +52821,33834,30179,40317 +51131,33835,30178,40235 +58613,33836,30177,40815 +58017,33837,30176,40333 +59191,33838,30175,40244 +59346,33839,30174,40873 +52035,33840,30173,40493 +53967,33841,30172,40924 +57637,33842,30171,40271 +54358,33843,30170,40023 +57025,33844,30169,40490 +54766,33845,30168,40152 +50483,33846,30167,40438 +53101,33847,30166,40352 +51621,33848,30165,40075 +59801,33849,30164,40404 +58171,33850,30163,40620 +56586,33851,30162,40554 +52360,33852,30161,40278 +50974,33853,30160,40650 +55843,33854,30159,40915 +50967,33855,30158,40902 +56611,33856,30157,40309 +56895,33857,30156,40112 +50919,33858,30155,40881 +52571,33859,30154,40247 +51731,33860,30153,40538 +50142,33861,30152,40132 +54853,33862,30151,40759 +58244,33863,30150,40375 +52118,33864,30149,40594 +58015,33865,30148,40562 +59084,33866,30147,40558 +59166,33867,30146,40902 +50267,33868,30145,40044 +51209,33869,30144,40626 +50827,33870,30143,40354 +59802,33871,30142,40901 +56197,33872,30141,40441 +58741,33873,30140,40348 +52648,33874,30139,40241 +52600,33875,30138,40708 +57752,33876,30137,40211 +56957,33877,30136,40942 +50534,33878,30135,40178 +54924,33879,30134,40474 +53130,33880,30133,40503 +52701,33881,30132,40529 +51116,33882,30131,40192 +55676,33883,30130,40075 +50963,33884,30129,40381 +56933,33885,30128,40921 +52453,33886,30127,40471 +54847,33887,30126,40713 +57133,33888,30125,40700 +51861,33889,30124,40524 +59514,33890,30123,40043 +51423,33891,30122,40285 +51796,33892,30121,40720 +57215,33893,30120,40920 +58681,33894,30119,40285 +54712,33895,30118,40820 +55702,33896,30117,40046 +54217,33897,30116,40166 +50673,33898,30115,40335 +58998,33899,30114,40828 +57347,33900,30113,40476 +50599,33901,30112,40203 +55443,33902,30111,40861 +57674,33903,30110,40662 +58797,33904,30109,40187 +57012,33905,30108,40739 +55986,33906,30107,40187 +56421,33907,30106,40699 +53865,33908,30105,40719 +55002,33909,30104,40830 +55251,33910,30103,40131 +58379,33911,30102,40281 +50300,33912,30101,40795 +51412,33913,30100,40565 +50798,33914,30099,40654 +57649,33915,30098,40725 +55519,33916,30097,40094 +53475,33917,30096,40948 +52218,33918,30095,40423 +58063,33919,30094,40672 +58011,33920,30093,40978 +50326,33921,30092,40631 +58996,33922,30091,40030 +50639,33923,30090,40228 +56749,33924,30089,40649 +54752,33925,30088,40406 +54440,33926,30087,40568 +58555,33927,30086,40686 +58562,33928,30085,40777 +56325,33929,30084,40467 +56694,33930,30083,40105 +59250,33931,30082,40643 +54059,33932,30081,40311 +51180,33933,30080,40880 +50302,33934,30079,40236 +59139,33935,30078,40380 +50874,33936,30077,40805 +53054,33937,30076,40691 +52451,33938,30075,40502 +51935,33939,30074,40452 +59475,33940,30073,40557 +58565,33941,30072,40203 +58220,33942,30071,40920 +52795,33943,30070,40582 +58924,33944,30069,40412 +59838,33945,30068,40578 +55502,33946,30067,40204 +58235,33947,30066,40217 +57932,33948,30065,40914 +56471,33949,30064,40058 +51202,33950,30063,40653 +57480,33951,30062,40118 +59407,33952,30061,40807 +54832,33953,30060,40682 +53269,33954,30059,40001 +54459,33955,30058,40918 +59951,33956,30057,40005 +58974,33957,30056,40904 +52850,33958,30055,40816 +57135,33959,30054,40502 +50540,33960,30053,40178 +59891,33961,30052,40255 +54041,33962,30051,40387 +56546,33963,30050,40004 +53557,33964,30049,40236 +54615,33965,30048,40680 +50956,33966,30047,40263 +56387,33967,30046,40128 +54684,33968,30045,40460 +57954,33969,30044,40457 +51692,33970,30043,40794 +50613,33971,30042,40670 +59686,33972,30041,40510 +52510,33973,30040,40011 +59727,33974,30039,40114 +53579,33975,30038,40577 +56632,33976,30037,40781 +57145,33977,30036,40493 +58109,33978,30035,40931 +57609,33979,30034,40711 +56747,33980,30033,40113 +54384,33981,30032,40748 +54030,33982,30031,40367 +57769,33983,30030,40065 +58423,33984,30029,40450 +50565,33985,30028,40109 +57725,33986,30027,40309 +51443,33987,30026,40337 +52283,33988,30025,40787 +50618,33989,30024,40606 +50503,33990,30023,40052 +54546,33991,30022,40083 +55171,33992,30021,40250 +54947,33993,30020,40466 +57852,33994,30019,40294 +52486,33995,30018,40958 +52752,33996,30017,40108 +52455,33997,30016,40812 +54173,33998,30015,40656 +52588,33999,30014,40602 +51060,34000,30013,40011 +59935,34001,30012,40576 +59148,34002,30011,40534 +54935,34003,30010,40026 +54962,34004,30009,40513 +52309,34005,30008,40751 +58302,34006,30007,40369 +56666,34007,30006,40577 +54402,34008,30005,40516 +54870,34009,30004,40481 +51995,34010,30003,40802 +59179,34011,30002,40758 +55530,34012,30001,40866 +55184,34013,30000,40290 +55100,34014,31000,40886 +54530,34015,30999,40505 +51925,34016,30998,40052 +53828,34017,30997,40183 +53756,34018,30996,40241 +57335,34019,30995,40077 +59264,34020,30994,40084 +54036,34021,30993,40248 +51448,34022,30992,40357 +57878,34023,30991,40294 +53943,34024,30990,40576 +51270,34025,30989,40485 +50974,34026,30988,40802 +57886,34027,30987,40410 +57228,34028,30986,40247 +51214,34029,30985,40259 +55425,34030,30984,40525 +52221,34031,30983,40642 +54976,34032,30982,40320 +56407,34033,30981,40038 +56018,34034,30980,40083 +50357,34035,30979,40439 +56536,34036,30978,40056 +57787,34037,30977,40334 +58696,34038,30976,40300 +54826,34039,30975,40103 +57080,34040,30974,40554 +50342,34041,30973,40236 +50553,34042,30972,40626 +50225,34043,30971,40695 +58779,34044,30970,40422 +57686,34045,30969,40899 +50590,34046,30968,40209 +57378,34047,30967,40912 +51208,34048,30966,40532 +56845,34049,30965,40009 +51475,34050,30964,40214 +57079,34051,30963,40491 +57326,34052,30962,40232 +55453,34053,30961,40853 +56979,34054,30960,40314 +58970,34055,30959,40183 +54985,34056,30958,40861 +59146,34057,30957,40472 +58128,34058,30956,40750 +53466,34059,30955,40200 +56121,34060,30954,40052 +53755,34061,30953,40342 +50936,34062,30952,40822 +51510,34063,30951,40071 +55682,34064,30950,40844 +55161,34065,30949,40916 +51088,34066,30948,40272 +50896,34067,30947,40382 +53542,34068,30946,40968 +59534,34069,30945,40649 +58893,34070,30944,40508 +54874,34071,30943,40426 +59420,34072,30942,40446 +58311,34073,30941,40942 +58566,34074,30940,40683 +58860,34075,30939,40409 +53068,34076,30938,40940 +53938,34077,30937,40168 +57715,34078,30936,40329 +55836,34079,30935,40707 +53936,34080,30934,40803 +58064,34081,30933,40595 +59696,34082,30932,40748 +53155,34083,30931,40331 +53701,34084,30930,40998 +57540,34085,30929,40982 +54458,34086,30928,40668 +58030,34087,30927,40045 +52791,34088,30926,40785 +59169,34089,30925,40195 +54496,34090,30924,40291 +53082,34091,30923,40391 +50616,34092,30922,40011 +52543,34093,30921,40317 +59699,34094,30920,40341 +58823,34095,30919,40394 +52200,34096,30918,40070 +53782,34097,30917,40473 +56165,34098,30916,40902 +51158,34099,30915,40631 +52830,34100,30914,40244 +55296,34101,30913,40087 +56269,34102,30912,40624 +59450,34103,30911,40899 +53021,34104,30910,40313 +52683,34105,30909,40273 +59906,34106,30908,40804 +56490,34107,30907,40965 +56543,34108,30906,40005 +53333,34109,30905,40168 +55035,34110,30904,40565 +50589,34111,30903,40301 +55102,34112,30902,40489 +52430,34113,30901,40484 +56837,34114,30900,40834 +54828,34115,30899,40725 +55333,34116,30898,40678 +59496,34117,30897,40890 +58924,34118,30896,40947 +58035,34119,30895,40793 +50498,34120,30894,40715 +53882,34121,30893,40365 +59823,34122,30892,40361 +50831,34123,30891,40640 +50647,34124,30890,40902 +57448,34125,30889,40223 +58288,34126,30888,40271 +54096,34127,30887,40218 +53524,34128,30886,40519 +57132,34129,30885,40670 +52434,34130,30884,40445 +50104,34131,30883,40633 +54398,34132,30882,40706 +51856,34133,30881,40154 +59129,34134,30880,40161 +54171,34135,30879,40730 +55947,34136,30878,40779 +59841,34137,30877,40523 +54381,34138,30876,40126 +59309,34139,30875,40083 +50131,34140,30874,40529 +51277,34141,30873,40708 +53542,34142,30872,40055 +57558,34143,30871,40324 +52672,34144,30870,40261 +51621,34145,30869,40245 +50960,34146,30868,40385 +54656,34147,30867,40640 +56126,34148,30866,40346 +52507,34149,30865,40306 +53737,34150,30864,40998 +57463,34151,30863,40899 +58731,34152,30862,40980 +53989,34153,30861,40462 +59774,34154,30860,40007 +52456,34155,30859,40898 +52519,34156,30858,40323 +54343,34157,30857,40253 +50113,34158,30856,40087 +55650,34159,30855,40016 +51349,34160,30854,40711 +54940,34161,30853,40635 +55013,34162,30852,40420 +53959,34163,30851,40253 +59384,34164,30850,40594 +53246,34165,30849,40999 +55631,34166,30848,40623 +58523,34167,30847,40614 +51494,34168,30846,40875 +53145,34169,30845,40252 +53607,34170,30844,40992 +59875,34171,30843,40994 +59672,34172,30842,40735 +50667,34173,30841,40852 +59604,34174,30840,40260 +57336,34175,30839,40193 +59431,34176,30838,40088 +54390,34177,30837,40277 +56963,34178,30836,40721 +54161,34179,30835,40797 +59440,34180,30834,40824 +52588,34181,30833,40822 +57665,34182,30832,40734 +54763,34183,30831,40826 +50641,34184,30830,40812 +57234,34185,30829,40488 +53611,34186,30828,40982 +56980,34187,30827,40903 +53785,34188,30826,40554 +56621,34189,30825,40774 +58405,34190,30824,40923 +56027,34191,30823,40779 +58443,34192,30822,40749 +55703,34193,30821,40751 +57487,34194,30820,40572 +59090,34195,30819,40555 +55435,34196,30818,40174 +58106,34197,30817,40913 +59857,34198,30816,40993 +55788,34199,30815,40800 +59631,34200,30814,40970 +51731,34201,30813,40781 +52384,34202,30812,40939 +55838,34203,30811,40099 +54494,34204,30810,40000 +56848,34205,30809,40408 +58822,34206,30808,40695 +53777,34207,30807,40227 +55860,34208,30806,40689 +54978,34209,30805,40773 +58445,34210,30804,40249 +51214,34211,30803,40787 +53516,34212,30802,40816 +53275,34213,30801,40085 +50052,34214,30800,40491 +50080,34215,30799,40263 +50692,34216,30798,40146 +59137,34217,30797,40905 +55624,34218,30796,40949 +54533,34219,30795,40164 +58092,34220,30794,40141 +52905,34221,30793,40284 +51883,34222,30792,40284 +56861,34223,30791,40253 +55094,34224,30790,40410 +58796,34225,30789,40659 +56401,34226,30788,40773 +53097,34227,30787,40074 +57463,34228,30786,40084 +59716,34229,30785,40734 +54317,34230,30784,40320 +54812,34231,30783,40656 +54884,34232,30782,40791 +52239,34233,30781,40302 +56392,34234,30780,40775 +50637,34235,30779,40998 +54070,34236,30778,40900 +51851,34237,30777,40215 +54442,34238,30776,40142 +53507,34239,30775,40035 +55686,34240,30774,40722 +50680,34241,30773,40109 +51310,34242,30772,40482 +52935,34243,30771,40571 +50384,34244,30770,40300 +53945,34245,30769,40368 +59730,34246,30768,40004 +56133,34247,30767,40969 +55172,34248,30766,40983 +51938,34249,30765,40385 +57332,34250,30764,40197 +56970,34251,30763,40876 +53776,34252,30762,40162 +51211,34253,30761,40788 +54981,34254,30760,40249 +53015,34255,30759,40411 +59175,34256,30758,40141 +56555,34257,30757,40462 +56794,34258,30756,40726 +55868,34259,30755,40723 +51196,34260,30754,40476 +59645,34261,30753,40111 +53381,34262,30752,40323 +53517,34263,30751,40333 +52311,34264,30750,40532 +54974,34265,30749,40014 +51744,34266,30748,40979 +57696,34267,30747,40914 +56526,34268,30746,40930 +57532,34269,30745,40921 +55746,34270,30744,40905 +50797,34271,30743,40049 +55997,34272,30742,40648 +55736,34273,30741,40572 +52871,34274,30740,40132 +53148,34275,30739,40181 +54878,34276,30738,40177 +57972,34277,30737,40638 +54715,34278,30736,40594 +58122,34279,30735,40833 +50097,34280,30734,40714 +56214,34281,30733,40762 +59791,34282,30732,40022 +54003,34283,30731,40725 +51349,34284,30730,40585 +56722,34285,30729,40345 +58035,34286,30728,40651 +54681,34287,30727,40280 +59948,34288,30726,40087 +57267,34289,30725,40202 +53929,34290,30724,40936 +52491,34291,30723,40941 +55754,34292,30722,40487 +58787,34293,30721,40443 +56664,34294,30720,40804 +57086,34295,30719,40328 +58966,34296,30718,40046 +53678,34297,30717,40007 +55446,34298,30716,40312 +51063,34299,30715,40312 +58072,34300,30714,40083 +54339,34301,30713,40983 +58284,34302,30712,40674 +53487,34303,30711,40140 +54617,34304,30710,40398 +51666,34305,30709,40579 +50918,34306,30708,40302 +57101,34307,30707,40632 +56309,34308,30706,40850 +54638,34309,30705,40953 +52944,34310,30704,40852 +59135,34311,30703,40303 +58955,34312,30702,40012 +50699,34313,30701,40705 +54921,34314,30700,40023 +59169,34315,30699,40031 +58507,34316,30698,40123 +56833,34317,30697,40913 +52979,34318,30696,40866 +58755,34319,30695,40418 +53606,34320,30694,40616 +50023,34321,30693,40644 +56064,34322,30692,40642 +51542,34323,30691,40425 +55378,34324,30690,40253 +51896,34325,30689,40259 +52390,34326,30688,40480 +54239,34327,30687,40673 +57235,34328,30686,40728 +52705,34329,30685,40510 +52188,34330,30684,40094 +53315,34331,30683,40087 +51570,34332,30682,40686 +57216,34333,30681,40617 +51386,34334,30680,40423 +58745,34335,30679,40037 +57450,34336,30678,40522 +58390,34337,30677,40986 +50060,34338,30676,40169 +51562,34339,30675,40397 +54709,34340,30674,40749 +54645,34341,30673,40294 +58383,34342,30672,40467 +56468,34343,30671,40562 +52434,34344,30670,40037 +59379,34345,30669,40153 +52338,34346,30668,40849 +59666,34347,30667,40684 +53090,34348,30666,40056 +58037,34349,30665,40477 +59958,34350,30664,40461 +54645,34351,30663,40026 +52422,34352,30662,40055 +59524,34353,30661,40879 +52590,34354,30660,40317 +58062,34355,30659,40751 +53826,34356,30658,40910 +54906,34357,30657,40799 +58143,34358,30656,40522 +55360,34359,30655,40151 +59885,34360,30654,40584 +54965,34361,30653,40365 +52977,34362,30652,40636 +56130,34363,30651,40360 +54958,34364,30650,40156 +57955,34365,30649,40791 +51035,34366,30648,40160 +54459,34367,30647,40004 +59568,34368,30646,40268 +55444,34369,30645,40664 +57210,34370,30644,40292 +53252,34371,30643,40603 +57982,34372,30642,40971 +51019,34373,30641,40552 +54410,34374,30640,40383 +53321,34375,30639,40731 +59879,34376,30638,40036 +56781,34377,30637,40048 +56155,34378,30636,40723 +56855,34379,30635,40097 +54379,34380,30634,40615 +55503,34381,30633,40908 +56605,34382,30632,40757 +51935,34383,30631,40607 +51291,34384,30630,40453 +58171,34385,30629,40873 +51331,34386,30628,40073 +53665,34387,30627,40982 +50636,34388,30626,40969 +57771,34389,30625,40398 +58756,34390,30624,40560 +53298,34391,30623,40482 +55220,34392,30622,40638 +59980,34393,30621,40692 +51045,34394,30620,40643 +50966,34395,30619,40251 +51643,34396,30618,40309 +50220,34397,30617,40776 +57439,34398,30616,40414 +59525,34399,30615,40136 +57083,34400,30614,40862 +59517,34401,30613,40750 +56095,34402,30612,40360 +54410,34403,30611,40979 +53616,34404,30610,40395 +58335,34405,30609,40829 +59984,34406,30608,40391 +51534,34407,30607,40625 +58009,34408,30606,40082 +50536,34409,30605,40111 +52690,34410,30604,40719 +53329,34411,30603,40737 +53412,34412,30602,40225 +50847,34413,30601,40727 +51878,34414,30600,40705 +56257,34415,30599,40490 +58709,34416,30598,40490 +52701,34417,30597,40410 +52160,34418,30596,40277 +54865,34419,30595,40767 +57343,34420,30594,40662 +54426,34421,30593,40305 +53347,34422,30592,40394 +51555,34423,30591,40716 +53960,34424,30590,40835 +56357,34425,30589,40883 +58664,34426,30588,40170 +57805,34427,30587,40679 +53577,34428,30586,40048 +50076,34429,30585,40429 +54326,34430,30584,40745 +57064,34431,30583,40922 +58172,34432,30582,40510 +51135,34433,30581,40099 +53627,34434,30580,40549 +56571,34435,30579,40173 +54012,34436,30578,40438 +58145,34437,30577,40541 +53905,34438,30576,40876 +57812,34439,30575,40486 +50551,34440,30574,40607 +59319,34441,30573,40997 +50041,34442,30572,40106 +53471,34443,30571,40786 +51519,34444,30570,40174 +58118,34445,30569,40437 +59059,34446,30568,40570 +51484,34447,30567,40075 +53252,34448,30566,40413 +56328,34449,30565,40956 +51523,34450,30564,40546 +51485,34451,30563,40121 +55563,34452,30562,40383 +54743,34453,30561,40887 +57870,34454,30560,40482 +59621,34455,30559,40123 +52570,34456,30558,40559 +52608,34457,30557,40857 +53930,34458,30556,40850 +57657,34459,30555,40781 +59704,34460,30554,40094 +56482,34461,30553,40269 +51857,34462,30552,40353 +51122,34463,30551,40953 +51361,34464,30550,40508 +52140,34465,30549,40896 +59886,34466,30548,40922 +54441,34467,30547,40224 +59072,34468,30546,40348 +54497,34469,30545,40962 +59165,34470,30544,40822 +51929,34471,30543,40799 +57971,34472,30542,40554 +52759,34473,30541,40187 +56671,34474,30540,40103 +53169,34475,30539,40197 +57866,34476,30538,40917 +52451,34477,30537,40647 +57763,34478,30536,40392 +52831,34479,30535,40769 +50024,34480,30534,40423 +55326,34481,30533,40820 +51534,34482,30532,40832 +59509,34483,30531,40646 +52336,34484,30530,40201 +52675,34485,30529,40977 +58435,34486,30528,40869 +54742,34487,30527,40823 +59256,34488,30526,40714 +55102,34489,30525,40415 +50347,34490,30524,40379 +58537,34491,30523,40181 +59097,34492,30522,40143 +56349,34493,30521,40233 +55038,34494,30520,40821 +51589,34495,30519,40014 +58380,34496,30518,40313 +51490,34497,30517,40341 +56312,34498,30516,40968 +54195,34499,30515,40709 +57006,34500,30514,40540 +57664,34501,30513,40785 +53620,34502,30512,40492 +53839,34503,30511,40559 +57036,34504,30510,40092 +57561,34505,30509,40729 +52803,34506,30508,40692 +52327,34507,30507,40945 +55351,34508,30506,40279 +54230,34509,30505,40805 +54166,34510,30504,40082 +51817,34511,30503,40469 +52609,34512,30502,40079 +58398,34513,30501,40669 +53615,34514,30500,40830 +52137,34515,30499,40891 +55438,34516,30498,40839 +56380,34517,30497,40903 +52980,34518,30496,40454 +54616,34519,30495,40562 +54532,34520,30494,40123 +55165,34521,30493,40428 +51788,34522,30492,40213 +53437,34523,30491,40174 +54874,34524,30490,40178 +53215,34525,30489,40224 +50351,34526,30488,40253 +52848,34527,30487,40377 +56972,34528,30486,40581 +58211,34529,30485,40489 +52921,34530,30484,40286 +56345,34531,30483,40092 +56037,34532,30482,40551 +56892,34533,30481,40205 +54279,34534,30480,40503 +50053,34535,30479,40372 +52370,34536,30478,40588 +57357,34537,30477,40246 +50840,34538,30476,40657 +56273,34539,30475,40551 +51733,34540,30474,40340 +56862,34541,30473,40031 +54844,34542,30472,40361 +57548,34543,30471,40318 +58640,34544,30470,40270 +55208,34545,30469,40285 +52120,34546,30468,40005 +56345,34547,30467,40699 +56901,34548,30466,40359 +56435,34549,30465,40952 +52768,34550,30464,40387 +59098,34551,30463,40746 +59036,34552,30462,40787 +59806,34553,30461,40313 +55659,34554,30460,40231 +56373,34555,30459,40881 +50925,34556,30458,40400 +50471,34557,30457,40692 +54099,34558,30456,40787 +54979,34559,30455,40897 +51921,34560,30454,40063 +54430,34561,30453,40301 +50209,34562,30452,40893 +51403,34563,30451,40636 +52436,34564,30450,40364 +50422,34565,30449,40892 +57092,34566,30448,40030 +58107,34567,30447,40375 +54198,34568,30446,40147 +58884,34569,30445,40155 +51275,34570,30444,40768 +53743,34571,30443,40751 +53701,34572,30442,40291 +51822,34573,30441,40620 +52470,34574,30440,40197 +56199,34575,30439,40661 +51683,34576,30438,40036 +54748,34577,30437,40365 +51560,34578,30436,40524 +59413,34579,30435,40740 +50150,34580,30434,40258 +57657,34581,30433,40933 +58583,34582,30432,40917 +51068,34583,30431,40751 +55922,34584,30430,40993 +57938,34585,30429,40398 +57930,34586,30428,40905 +59346,34587,30427,40605 +58593,34588,30426,40416 +59157,34589,30425,40059 +59913,34590,30424,40901 +53294,34591,30423,40599 +50635,34592,30422,40712 +51092,34593,30421,40472 +56305,34594,30420,40677 +58218,34595,30419,40934 +56765,34596,30418,40132 +51951,34597,30417,40303 +59421,34598,30416,40467 +57345,34599,30415,40575 +54422,34600,30414,40169 +59069,34601,30413,40551 +55885,34602,30412,40687 +52001,34603,30411,40248 +53477,34604,30410,40317 +58243,34605,30409,40164 +51474,34606,30408,40045 +58714,34607,30407,40330 +55932,34608,30406,40416 +58394,34609,30405,40812 +54879,34610,30404,40348 +55421,34611,30403,40326 +59935,34612,30402,40631 +51021,34613,30401,40870 +58649,34614,30400,40323 +54558,34615,30399,40194 +55093,34616,30398,40510 +59272,34617,30397,40922 +50824,34618,30396,40548 +58450,34619,30395,40459 +57925,34620,30394,40643 +59370,34621,30393,40773 +50819,34622,30392,40107 +51489,34623,30391,40946 +54106,34624,30390,40216 +55523,34625,30389,40196 +57047,34626,30388,40933 +59572,34627,30387,40697 +59263,34628,30386,40679 +59766,34629,30385,40893 +51649,34630,30384,40691 +51687,34631,30383,40997 +51731,34632,30382,40653 +53975,34633,30381,40307 +57230,34634,30380,40742 +51112,34635,30379,40211 +51062,34636,30378,40921 +53438,34637,30377,40473 +51921,34638,30376,40170 +56582,34639,30375,40068 +56266,34640,30374,40099 +51986,34641,30373,40355 +56029,34642,30372,40989 +53602,34643,30371,40779 +53058,34644,30370,40903 +58255,34645,30369,40274 +54759,34646,30368,40118 +52848,34647,30367,40947 +58229,34648,30366,40282 +53184,34649,30365,40526 +52373,34650,30364,40544 +55367,34651,30363,40307 +56187,34652,30362,40321 +58932,34653,30361,40323 +50320,34654,30360,40790 +51932,34655,30359,40491 +51614,34656,30358,40222 +56268,34657,30357,40518 +54149,34658,30356,40702 +52347,34659,30355,40406 +56027,34660,30354,40044 +55851,34661,30353,40135 +51471,34662,30352,40553 +57646,34663,30351,40792 +56670,34664,30350,40880 +53124,34665,30349,40023 +54607,34666,30348,40846 +58179,34667,30347,40551 +56313,34668,30346,40224 +57024,34669,30345,40569 +59700,34670,30344,40116 +58649,34671,30343,40348 +55709,34672,30342,40093 +56117,34673,30341,40258 +54659,34674,30340,40238 +52195,34675,30339,40169 +59182,34676,30338,40002 +56399,34677,30337,40426 +59311,34678,30336,40566 +55715,34679,30335,40993 +52146,34680,30334,40220 +55914,34681,30333,40074 +59585,34682,30332,40477 +51647,34683,30331,40396 +54578,34684,30330,40793 +53925,34685,30329,40941 +53585,34686,30328,40718 +52528,34687,30327,40674 +57160,34688,30326,40291 +53296,34689,30325,40689 +59674,34690,30324,40664 +59533,34691,30323,40629 +51631,34692,30322,40460 +54142,34693,30321,40261 +56393,34694,30320,40722 +51620,34695,30319,40562 +52214,34696,30318,40298 +53907,34697,30317,40298 +54430,34698,30316,40255 +59793,34699,30315,40894 +54764,34700,30314,40578 +59607,34701,30313,40788 +59514,34702,30312,40498 +56021,34703,30311,40618 +55429,34704,30310,40605 +53681,34705,30309,40816 +57807,34706,30308,40936 +55791,34707,30307,40104 +56211,34708,30306,40671 +51517,34709,30305,40821 +53267,34710,30304,40058 +58405,34711,30303,40973 +50237,34712,30302,40597 +59366,34713,30301,40725 +58876,34714,30300,40890 +55676,34715,30299,40887 +50331,34716,30298,40292 +55531,34717,30297,40906 +55764,34718,30296,40650 +52475,34719,30295,40759 +55991,34720,30294,40759 +50189,34721,30293,40523 +55206,34722,30292,40114 +57628,34723,30291,40846 +52669,34724,30290,40887 +58751,34725,30289,40806 +50783,34726,30288,40001 +59739,34727,30287,40640 +55259,34728,30286,40322 +51381,34729,30285,40621 +58013,34730,30284,40904 +58100,34731,30283,40973 +57073,34732,30282,40574 +52389,34733,30281,40547 +58659,34734,30280,40300 +57048,34735,30279,40293 +57666,34736,30278,40724 +57400,34737,30277,40302 +50882,34738,30276,40987 +58312,34739,30275,40593 +52801,34740,30274,40175 +59673,34741,30273,40868 +58657,34742,30272,40459 +53416,34743,30271,40103 +52116,34744,30270,40604 +59188,34745,30269,40231 +52006,34746,30268,40535 +50541,34747,30267,40772 +56196,34748,30266,40098 +55096,34749,30265,40131 +59594,34750,30264,40436 +56367,34751,30263,40697 +54618,34752,30262,40401 +52533,34753,30261,40741 +54505,34754,30260,40333 +57767,34755,30259,40535 +51251,34756,30258,40588 +50398,34757,30257,40531 +59247,34758,30256,40940 +54273,34759,30255,40893 +54429,34760,30254,40456 +59912,34761,30253,40408 +51067,34762,30252,40939 +51419,34763,30251,40543 +50183,34764,30250,40893 +51321,34765,30249,40022 +50079,34766,30248,40788 +59460,34767,30247,40774 +55796,34768,30246,40937 +52841,34769,30245,40227 +59421,34770,30244,40246 +52173,34771,30243,40116 +50152,34772,30242,40378 +56931,34773,30241,40271 +56475,34774,30240,40953 +59531,34775,30239,40302 +51481,34776,30238,40218 +50932,34777,30237,40370 +54688,34778,30236,40310 +52002,34779,30235,40354 +58014,34780,30234,40850 +50091,34781,30233,40824 +51892,34782,30232,40441 +59067,34783,30231,40832 +56467,34784,30230,40178 +57335,34785,30229,40046 +56259,34786,30228,40977 +53054,34787,30227,40235 +59427,34788,30226,40604 +59164,34789,30225,40788 +58218,34790,30224,40324 +51656,34791,30223,40879 +57036,34792,30222,40806 +55741,34793,30221,40306 +59656,34794,30220,40093 +58486,34795,30219,40538 +57774,34796,30218,40838 +50291,34797,30217,40684 +50670,34798,30216,40736 +53528,34799,30215,40724 +56251,34800,30214,40990 +58708,34801,30213,40112 +57295,34802,30212,40954 +50382,34803,30211,40608 +57288,34804,30210,40623 +52156,34805,30209,40789 +55600,34806,30208,40915 +54478,34807,30207,40235 +50282,34808,30206,40991 +54423,34809,30205,40636 +59752,34810,30204,40325 +55355,34811,30203,40106 +57786,34812,30202,40421 +53700,34813,30201,40360 +53793,34814,30200,40716 +54335,34815,30199,40054 +58305,34816,30198,40777 +56883,34817,30197,40399 +56805,34818,30196,40677 +53410,34819,30195,40448 +55452,34820,30194,40911 +52743,34821,30193,40912 +53041,34822,30192,40377 +55183,34823,30191,40470 +57768,34824,30190,40130 +55861,34825,30189,40228 +53284,34826,30188,40472 +51846,34827,30187,40454 +55958,34828,30186,40306 +50755,34829,30185,40807 +51568,34830,30184,40112 +55204,34831,30183,40856 +58648,34832,30182,40816 +54393,34833,30181,40573 +51240,34834,30180,40318 +59292,34835,30179,40599 +59138,34836,30178,40287 +58018,34837,30177,40911 +56160,34838,30176,40938 +58497,34839,30175,40317 +57465,34840,30174,40682 +59035,34841,30173,40334 +52176,34842,30172,40428 +59817,34843,30171,40675 +57655,34844,30170,40514 +58963,34845,30169,40716 +55553,34846,30168,40762 +54235,34847,30167,40968 +51236,34848,30166,40127 +52697,34849,30165,40511 +59165,34850,30164,40962 +57425,34851,30163,40175 +51790,34852,30162,40956 +57377,34853,30161,40823 +55842,34854,30160,40010 +51334,34855,30159,40492 +51121,34856,30158,40181 +53343,34857,30157,40717 +59967,34858,30156,40572 +52025,34859,30155,40101 +50015,34860,30154,40793 +54041,34861,30153,40580 +52870,34862,30152,40430 +58280,34863,30151,40626 +52234,34864,30150,40578 +50200,34865,30149,40322 +56296,34866,30148,40251 +52517,34867,30147,40830 +50932,34868,30146,40297 +55495,34869,30145,40973 +54747,34870,30144,40821 +55172,34871,30143,40526 +53205,34872,30142,40580 +56242,34873,30141,40151 +53127,34874,30140,40989 +53562,34875,30139,40214 +56564,34876,30138,40714 +56536,34877,30137,40515 +50372,34878,30136,40710 +56879,34879,30135,40881 +58140,34880,30134,40764 +55801,34881,30133,40648 +59485,34882,30132,40623 +57148,34883,30131,40056 +57801,34884,30130,40995 +57929,34885,30129,40131 +54447,34886,30128,40447 +52414,34887,30127,40807 +55560,34888,30126,40174 +54394,34889,30125,40510 +59386,34890,30124,40937 +50048,34891,30123,40092 +53802,34892,30122,40594 +59157,34893,30121,40741 +54798,34894,30120,40063 +59348,34895,30119,40657 +54192,34896,30118,40474 +52257,34897,30117,40078 +59455,34898,30116,40537 +51051,34899,30115,40223 +59056,34900,30114,40046 +51290,34901,30113,40766 +51490,34902,30112,40829 +57767,34903,30111,40635 +54878,34904,30110,40661 +50363,34905,30109,40832 +55869,34906,30108,40645 +58992,34907,30107,40211 +50659,34908,30106,40797 +57956,34909,30105,40638 +50074,34910,30104,40966 +54955,34911,30103,40735 +59194,34912,30102,40575 +57908,34913,30101,40999 +54243,34914,30100,40813 +50948,34915,30099,40314 +55917,34916,30098,40806 +50639,34917,30097,40666 +50311,34918,30096,40170 +56453,34919,30095,40895 +56828,34920,30094,40062 +54568,34921,30093,40079 +59651,34922,30092,40190 +50732,34923,30091,40726 +57365,34924,30090,40342 +59624,34925,30089,40810 +54250,34926,30088,40318 +56377,34927,30087,40558 +51564,34928,30086,40600 +53621,34929,30085,40337 +59629,34930,30084,40447 +55228,34931,30083,40562 +55381,34932,30082,40382 +57803,34933,30081,40835 +52499,34934,30080,40154 +50939,34935,30079,40855 +52180,34936,30078,40380 +58342,34937,30077,40112 +53522,34938,30076,40567 +57833,34939,30075,40289 +57172,34940,30074,40362 +58869,34941,30073,40149 +55347,34942,30072,40971 +57056,34943,30071,40027 +51948,34944,30070,40993 +59864,34945,30069,40551 +52977,34946,30068,40644 +58232,34947,30067,40373 +57914,34948,30066,40899 +55027,34949,30065,40116 +57370,34950,30064,40249 +54508,34951,30063,40061 +58524,34952,30062,40828 +51288,34953,30061,40663 +51468,34954,30060,40332 +55132,34955,30059,40409 +52770,34956,30058,40213 +52160,34957,30057,40243 +57785,34958,30056,40921 +58197,34959,30055,40465 +57725,34960,30054,40941 +59122,34961,30053,40812 +53123,34962,30052,40326 +54906,34963,30051,40687 +57235,34964,30050,40512 +54138,34965,30049,40499 +56064,34966,30048,40587 +55246,34967,30047,40480 +56808,34968,30046,40602 +50563,34969,30045,40624 +58550,34970,30044,40081 +59047,34971,30043,40273 +56645,34972,30042,40674 +58589,34973,30041,40616 +55007,34974,30040,40212 +50732,34975,30039,40220 +55156,34976,30038,40801 +58311,34977,30037,40742 +51910,34978,30036,40403 +54136,34979,30035,40147 +51153,34980,30034,40002 +53877,34981,30033,40979 +54504,34982,30032,40764 +50500,34983,30031,40073 +58058,34984,30030,40530 +58235,34985,30029,40343 +53076,34986,30028,40834 +53904,34987,30027,40302 +57056,34988,30026,40806 +59935,34989,30025,40903 +52699,34990,30024,40969 +53962,34991,30023,40441 +58835,34992,30022,40993 +58426,34993,30021,40079 +51775,34994,30020,40382 +57844,34995,30019,40005 +50858,34996,30018,40061 +53431,34997,30017,40327 +55975,34998,30016,40625 +51634,34999,30015,40814 +51160,35000,30014,40679 +56914,35001,30013,40064 +58697,35002,30012,40756 +53993,35003,30011,40811 +53239,35004,30010,40709 +52442,35005,30009,40326 +52655,35006,30008,40914 +50241,35007,30007,40779 +58785,35008,30006,40969 +59600,35009,30005,40101 +55794,35010,30004,40627 +59715,35011,30003,40658 +59377,35012,30002,40804 +57909,35013,30001,40661 +51745,35014,30000,40372 +59388,35015,31000,40011 +59989,35016,30999,40061 +56991,35017,30998,40543 +57051,35018,30997,40169 +54280,35019,30996,40220 +59071,35020,30995,40418 +50372,35021,30994,40687 +55488,35022,30993,40245 +58102,35023,30992,40087 +58495,35024,30991,40284 +58924,35025,30990,40786 +53907,35026,30989,40854 +58874,35027,30988,40565 +51306,35028,30987,40445 +59203,35029,30986,40095 +55898,35030,30985,40259 +59526,35031,30984,40594 +52550,35032,30983,40202 +50372,35033,30982,40160 +52892,35034,30981,40799 +58863,35035,30980,40206 +53242,35036,30979,40522 +57742,35037,30978,40079 +53169,35038,30977,40525 +51422,35039,30976,40464 +56018,35040,30975,40574 +52739,35041,30974,40675 +52421,35042,30973,40491 +58460,35043,30972,40858 +59833,35044,30971,40961 +54884,35045,30970,40722 +56326,35046,30969,40545 +58020,35047,30968,40730 +59341,35048,30967,40840 +55013,35049,30966,40334 +56257,35050,30965,40137 +54308,35051,30964,40156 +53311,35052,30963,40801 +50095,35053,30962,40058 +58392,35054,30961,40990 +57963,35055,30960,40818 +50607,35056,30959,40581 +52504,35057,30958,40828 +50638,35058,30957,40519 +58348,35059,30956,40334 +52323,35060,30955,40159 +52748,35061,30954,40026 +55464,35062,30953,40850 +53130,35063,30952,40084 +55616,35064,30951,40796 +55831,35065,30950,40015 +53469,35066,30949,40019 +55321,35067,30948,40923 +50847,35068,30947,40586 +53368,35069,30946,40468 +51191,35070,30945,40876 +53027,35071,30944,40482 +52393,35072,30943,40355 +54320,35073,30942,40305 +58048,35074,30941,40116 +53712,35075,30940,40133 +53195,35076,30939,40961 +56912,35077,30938,40099 +53413,35078,30937,40315 +52300,35079,30936,40774 +52051,35080,30935,40337 +53694,35081,30934,40653 +57878,35082,30933,40049 +58948,35083,30932,40414 +51280,35084,30931,40258 +57392,35085,30930,40257 +51443,35086,30929,40396 +51528,35087,30928,40059 +51269,35088,30927,40828 +50270,35089,30926,40734 +57712,35090,30925,40792 +59482,35091,30924,40097 +50773,35092,30923,40980 +58612,35093,30922,40169 +51873,35094,30921,40502 +59598,35095,30920,40972 +52824,35096,30919,40748 +59037,35097,30918,40661 +58494,35098,30917,40400 +50168,35099,30916,40945 +56725,35100,30915,40108 +50264,35101,30914,40013 +54032,35102,30913,40904 +50720,35103,30912,40666 +55973,35104,30911,40030 +52343,35105,30910,40174 +52913,35106,30909,40078 +54304,35107,30908,40880 +55206,35108,30907,40603 +58683,35109,30906,40112 +51280,35110,30905,40577 +57156,35111,30904,40425 +50229,35112,30903,40529 +53560,35113,30902,40243 +53898,35114,30901,40346 +55192,35115,30900,40489 +54450,35116,30899,40174 +55335,35117,30898,40716 +55425,35118,30897,40198 +58638,35119,30896,40234 +56159,35120,30895,40827 +58302,35121,30894,40015 +58233,35122,30893,40706 +54037,35123,30892,40966 +58337,35124,30891,40723 +58265,35125,30890,40628 +55109,35126,30889,40703 +51618,35127,30888,40697 +58701,35128,30887,40443 +53717,35129,30886,40172 +52158,35130,30885,40237 +55098,35131,30884,40753 +50092,35132,30883,40305 +52847,35133,30882,40154 +56444,35134,30881,40521 +57525,35135,30880,40152 +57367,35136,30879,40151 +53784,35137,30878,40444 +50250,35138,30877,40536 +51101,35139,30876,40254 +58426,35140,30875,40800 +52131,35141,30874,40568 +59269,35142,30873,40475 +52828,35143,30872,40433 +59844,35144,30871,40311 +51461,35145,30870,40938 +54253,35146,30869,40604 +57281,35147,30868,40086 +52853,35148,30867,40748 +53236,35149,30866,40386 +57507,35150,30865,40941 +56891,35151,30864,40782 +52495,35152,30863,40048 +55273,35153,30862,40024 +58073,35154,30861,40429 +53371,35155,30860,40748 +53174,35156,30859,40621 +59293,35157,30858,40002 +54068,35158,30857,40932 +58342,35159,30856,40468 +54047,35160,30855,40297 +56798,35161,30854,40385 +55277,35162,30853,40187 +54545,35163,30852,40803 +52756,35164,30851,40657 +55915,35165,30850,40858 +52651,35166,30849,40974 +57762,35167,30848,40267 +55373,35168,30847,40664 +50372,35169,30846,40552 +59034,35170,30845,40219 +56213,35171,30844,40213 +52999,35172,30843,40527 +50010,35173,30842,40300 +53974,35174,30841,40179 +59364,35175,30840,40486 +56865,35176,30839,40180 +50292,35177,30838,40127 +59136,35178,30837,40270 +50941,35179,30836,40581 +50810,35180,30835,40237 +54424,35181,30834,40276 +54264,35182,30833,40856 +52928,35183,30832,40792 +52708,35184,30831,40899 +58957,35185,30830,40129 +57728,35186,30829,40232 +56766,35187,30828,40932 +58980,35188,30827,40906 +59007,35189,30826,40500 +57247,35190,30825,40717 +58859,35191,30824,40412 +56462,35192,30823,40125 +57370,35193,30822,40847 +53867,35194,30821,40225 +59963,35195,30820,40382 +50301,35196,30819,40539 +59646,35197,30818,40902 +56589,35198,30817,40544 +52968,35199,30816,40851 +59768,35200,30815,40279 +52441,35201,30814,40805 +50352,35202,30813,40487 +55018,35203,30812,40086 +55630,35204,30811,40337 +56031,35205,30810,40092 +52546,35206,30809,40327 +53789,35207,30808,40289 +51355,35208,30807,40359 +58005,35209,30806,40277 +56674,35210,30805,40257 +51246,35211,30804,40749 +50048,35212,30803,40513 +54929,35213,30802,40306 +50895,35214,30801,40952 +51918,35215,30800,40728 +55518,35216,30799,40550 +53916,35217,30798,40745 +53199,35218,30797,40020 +52541,35219,30796,40582 +59290,35220,30795,40713 +51807,35221,30794,40793 +53396,35222,30793,40179 +52239,35223,30792,40474 +56379,35224,30791,40608 +54665,35225,30790,40708 +57816,35226,30789,40872 +54090,35227,30788,40971 +57015,35228,30787,40304 +58326,35229,30786,40893 +58466,35230,30785,40206 +53189,35231,30784,40562 +53241,35232,30783,40156 +59241,35233,30782,40609 +53742,35234,30781,40731 +57195,35235,30780,40800 +52173,35236,30779,40302 +52147,35237,30778,40983 +54345,35238,30777,40095 +54661,35239,30776,40386 +53554,35240,30775,40362 +52808,35241,30774,40402 +52466,35242,30773,40092 +59619,35243,30772,40518 +50902,35244,30771,40943 +53089,35245,30770,40427 +53370,35246,30769,40605 +50659,35247,30768,40589 +56029,35248,30767,40422 +50772,35249,30766,40097 +57780,35250,30765,40585 +53608,35251,30764,40497 +59306,35252,30763,40491 +53805,35253,30762,40418 +56741,35254,30761,40206 +52836,35255,30760,40334 +53060,35256,30759,40017 +50601,35257,30758,40545 +58580,35258,30757,40032 +55165,35259,30756,40162 +56194,35260,30755,40496 +50821,35261,30754,40728 +53179,35262,30753,40433 +57307,35263,30752,40014 +50591,35264,30751,40864 +50146,35265,30750,40885 +55380,35266,30749,40560 +56920,35267,30748,40268 +52086,35268,30747,40941 +51332,35269,30746,40430 +51612,35270,30745,40412 +52830,35271,30744,40009 +58982,35272,30743,40402 +55758,35273,30742,40278 +50978,35274,30741,40688 +55404,35275,30740,40058 +55374,35276,30739,40312 +52759,35277,30738,40840 +52168,35278,30737,40879 +58897,35279,30736,40816 +53090,35280,30735,40198 +56535,35281,30734,40256 +53009,35282,30733,40550 +51359,35283,30732,40230 +52020,35284,30731,40079 +52826,35285,30730,40399 +50401,35286,30729,40414 +50265,35287,30728,40887 +59755,35288,30727,40321 +57835,35289,30726,40325 +58736,35290,30725,40984 +57604,35291,30724,40954 +58655,35292,30723,40458 +56538,35293,30722,40142 +59638,35294,30721,40865 +55337,35295,30720,40024 +58842,35296,30719,40715 +50310,35297,30718,40072 +56240,35298,30717,40542 +59377,35299,30716,40146 +55544,35300,30715,40343 +51283,35301,30714,40137 +56457,35302,30713,40550 +50519,35303,30712,40301 +52567,35304,30711,40618 +52373,35305,30710,40282 +53249,35306,30709,40373 +54569,35307,30708,40167 +59335,35308,30707,40875 +57443,35309,30706,40696 +52601,35310,30705,40349 +51543,35311,30704,40624 +58507,35312,30703,40188 +53940,35313,30702,40191 +58629,35314,30701,40508 +58450,35315,30700,40476 +57270,35316,30699,40591 +54852,35317,30698,40119 +59784,35318,30697,40610 +55709,35319,30696,40582 +53278,35320,30695,40088 +58592,35321,30694,40809 +55146,35322,30693,40753 +59807,35323,30692,40092 +55804,35324,30691,40263 +55957,35325,30690,40937 +59125,35326,30689,40933 +54223,35327,30688,40759 +57322,35328,30687,40420 +51940,35329,30686,40179 +54819,35330,30685,40044 +59126,35331,30684,40337 +57011,35332,30683,40971 +58081,35333,30682,40279 +58898,35334,30681,40813 +55792,35335,30680,40470 +52053,35336,30679,40656 +59759,35337,30678,40830 +54575,35338,30677,40834 +50394,35339,30676,40429 +51873,35340,30675,40921 +59925,35341,30674,40196 +54974,35342,30673,40191 +53573,35343,30672,40735 +52585,35344,30671,40457 +56299,35345,30670,40278 +57119,35346,30669,40490 +51809,35347,30668,40564 +51585,35348,30667,40960 +55853,35349,30666,40531 +50538,35350,30665,40227 +58195,35351,30664,40778 +58287,35352,30663,40653 +51830,35353,30662,40693 +53044,35354,30661,40627 +53951,35355,30660,40535 +50923,35356,30659,40550 +51126,35357,30658,40815 +53735,35358,30657,40118 +55485,35359,30656,40972 +56895,35360,30655,40844 +59069,35361,30654,40797 +54414,35362,30653,40859 +57495,35363,30652,40634 +55943,35364,30651,40850 +59004,35365,30650,40569 +50133,35366,30649,40304 +55225,35367,30648,40542 +55712,35368,30647,40885 +53690,35369,30646,40690 +58637,35370,30645,40920 +56832,35371,30644,40486 +56621,35372,30643,40482 +51869,35373,30642,40300 +57541,35374,30641,40478 +54075,35375,30640,40178 +58813,35376,30639,40260 +55020,35377,30638,40468 +50082,35378,30637,40465 +53597,35379,30636,40614 +59878,35380,30635,40765 +53700,35381,30634,40091 +56471,35382,30633,40256 +56360,35383,30632,40260 +51389,35384,30631,40201 +58495,35385,30630,40424 +51021,35386,30629,40941 +56562,35387,30628,40380 +57579,35388,30627,40633 +59773,35389,30626,40968 +51148,35390,30625,40340 +52019,35391,30624,40862 +59161,35392,30623,40779 +57823,35393,30622,40736 +57663,35394,30621,40978 +52773,35395,30620,40044 +56772,35396,30619,40012 +53430,35397,30618,40006 +56996,35398,30617,40496 +52898,35399,30616,40442 +52985,35400,30615,40696 +59320,35401,30614,40893 +57945,35402,30613,40054 +57241,35403,30612,40712 +52921,35404,30611,40478 +52443,35405,30610,40167 +50384,35406,30609,40498 +51209,35407,30608,40260 +51222,35408,30607,40862 +52632,35409,30606,40090 +50939,35410,30605,40801 +51444,35411,30604,40961 +51700,35412,30603,40836 +59112,35413,30602,40254 +56623,35414,30601,40858 +50205,35415,30600,40420 +50888,35416,30599,40516 +54970,35417,30598,40227 +57877,35418,30597,40184 +54602,35419,30596,40747 +54620,35420,30595,40157 +54923,35421,30594,40501 +55716,35422,30593,40446 +50274,35423,30592,40542 +51976,35424,30591,40984 +52203,35425,30590,40857 +50120,35426,30589,40874 +57662,35427,30588,40552 +57786,35428,30587,40040 +54766,35429,30586,40711 +50702,35430,30585,40412 +53132,35431,30584,40821 +53199,35432,30583,40890 +58328,35433,30582,40983 +50612,35434,30581,40678 +53223,35435,30580,40203 +58039,35436,30579,40252 +54336,35437,30578,40934 +59245,35438,30577,40875 +52544,35439,30576,40427 +56308,35440,30575,40391 +53069,35441,30574,40320 +55851,35442,30573,40233 +50424,35443,30572,40142 +51114,35444,30571,40309 +57515,35445,30570,40773 +52307,35446,30569,40473 +53746,35447,30568,40185 +56368,35448,30567,40181 +58391,35449,30566,40798 +51196,35450,30565,40603 +55157,35451,30564,40875 +53710,35452,30563,40685 +55422,35453,30562,40838 +58703,35454,30561,40021 +51576,35455,30560,40428 +54125,35456,30559,40380 +55234,35457,30558,40891 +52152,35458,30557,40915 +52116,35459,30556,40678 +58345,35460,30555,40103 +56820,35461,30554,40204 +56643,35462,30553,40077 +59413,35463,30552,40661 +51553,35464,30551,40802 +53210,35465,30550,40642 +57215,35466,30549,40077 +57065,35467,30548,40152 +57445,35468,30547,40244 +58794,35469,30546,40625 +53934,35470,30545,40304 +59134,35471,30544,40519 +55863,35472,30543,40070 +58285,35473,30542,40677 +57298,35474,30541,40450 +58632,35475,30540,40732 +51130,35476,30539,40714 +58157,35477,30538,40775 +57761,35478,30537,40900 +59528,35479,30536,40844 +58374,35480,30535,40805 +56390,35481,30534,40096 +51426,35482,30533,40079 +56997,35483,30532,40541 +56961,35484,30531,40582 +51848,35485,30530,40618 +59438,35486,30529,40752 +52487,35487,30528,40064 +50902,35488,30527,40503 +54674,35489,30526,40092 +54335,35490,30525,40116 +53558,35491,30524,40709 +50530,35492,30523,40025 +56616,35493,30522,40764 +56035,35494,30521,40578 +56255,35495,30520,40923 +58849,35496,30519,40921 +53550,35497,30518,40516 +55737,35498,30517,40302 +51455,35499,30516,40783 +57909,35500,30515,40999 +54283,35501,30514,40215 +51282,35502,30513,40314 +58629,35503,30512,40113 +58015,35504,30511,40012 +56710,35505,30510,40210 +52353,35506,30509,40180 +51923,35507,30508,40565 +55395,35508,30507,40489 +56028,35509,30506,40293 +51723,35510,30505,40940 +52158,35511,30504,40445 +54408,35512,30503,40452 +58823,35513,30502,40570 +58759,35514,30501,40668 +52089,35515,30500,40977 +54533,35516,30499,40075 +53448,35517,30498,40338 +52783,35518,30497,40416 +54301,35519,30496,40857 +52373,35520,30495,40040 +55181,35521,30494,40173 +51997,35522,30493,40678 +58836,35523,30492,40086 +53587,35524,30491,40677 +55291,35525,30490,40184 +50110,35526,30489,40581 +53592,35527,30488,40038 +54702,35528,30487,40839 +59429,35529,30486,40317 +56610,35530,30485,40519 +51865,35531,30484,40071 +51494,35532,30483,40309 +51586,35533,30482,40313 +59017,35534,30481,40712 +51988,35535,30480,40129 +50940,35536,30479,40272 +53578,35537,30478,40223 +56199,35538,30477,40710 +52267,35539,30476,40038 +53510,35540,30475,40010 +59161,35541,30474,40999 +58144,35542,30473,40648 +57347,35543,30472,40627 +50440,35544,30471,40985 +56635,35545,30470,40419 +50796,35546,30469,40889 +50737,35547,30468,40758 +53147,35548,30467,40554 +57629,35549,30466,40606 +51172,35550,30465,40365 +59820,35551,30464,40967 +50777,35552,30463,40760 +54898,35553,30462,40549 +57026,35554,30461,40616 +54382,35555,30460,40105 +59294,35556,30459,40044 +50027,35557,30458,40247 +58180,35558,30457,40971 +52226,35559,30456,40023 +57208,35560,30455,40876 +50333,35561,30454,40127 +59482,35562,30453,40456 +52679,35563,30452,40097 +50344,35564,30451,40102 +56991,35565,30450,40638 +52307,35566,30449,40875 +56651,35567,30448,40871 +52079,35568,30447,40115 +56616,35569,30446,40227 +54931,35570,30445,40153 +59712,35571,30444,40514 +51841,35572,30443,40822 +56837,35573,30442,40372 +52288,35574,30441,40450 +59161,35575,30440,40423 +57780,35576,30439,40676 +59872,35577,30438,40348 +59359,35578,30437,40095 +55869,35579,30436,40957 +59153,35580,30435,40564 +59673,35581,30434,40477 +51195,35582,30433,40742 +56435,35583,30432,40867 +53314,35584,30431,40702 +50257,35585,30430,40741 +50590,35586,30429,40419 +54580,35587,30428,40589 +55394,35588,30427,40733 +54074,35589,30426,40066 +50950,35590,30425,40495 +54636,35591,30424,40094 +54464,35592,30423,40783 +58632,35593,30422,40015 +52785,35594,30421,40235 +55993,35595,30420,40885 +58043,35596,30419,40057 +50978,35597,30418,40991 +52160,35598,30417,40778 +51434,35599,30416,40698 +54614,35600,30415,40893 +52656,35601,30414,40903 +55495,35602,30413,40676 +51616,35603,30412,40503 +57957,35604,30411,40189 +50590,35605,30410,40909 +58683,35606,30409,40567 +54399,35607,30408,40449 +52766,35608,30407,40671 +59320,35609,30406,40357 +51874,35610,30405,40990 +53646,35611,30404,40797 +58873,35612,30403,40936 +57692,35613,30402,40072 +57462,35614,30401,40148 +58370,35615,30400,40813 +55968,35616,30399,40155 +50874,35617,30398,40036 +57714,35618,30397,40559 +59159,35619,30396,40955 +54671,35620,30395,40458 +51318,35621,30394,40033 +59459,35622,30393,40575 +54950,35623,30392,40010 +50516,35624,30391,40376 +53956,35625,30390,40880 +53271,35626,30389,40278 +53087,35627,30388,40394 +59871,35628,30387,40727 +55115,35629,30386,40556 +56625,35630,30385,40703 +57873,35631,30384,40538 +52979,35632,30383,40485 +51635,35633,30382,40226 +55714,35634,30381,40000 +51980,35635,30380,40181 +51379,35636,30379,40559 +56950,35637,30378,40114 +57281,35638,30377,40314 +53558,35639,30376,40176 +50053,35640,30375,40176 +59985,35641,30374,40261 +59060,35642,30373,40821 +58626,35643,30372,40335 +55250,35644,30371,40600 +52276,35645,30370,40734 +54660,35646,30369,40215 +57945,35647,30368,40173 +57171,35648,30367,40559 +55229,35649,30366,40531 +57229,35650,30365,40323 +54325,35651,30364,40410 +52917,35652,30363,40128 +57313,35653,30362,40684 +56570,35654,30361,40828 +57937,35655,30360,40516 +55061,35656,30359,40713 +50259,35657,30358,40536 +59165,35658,30357,40729 +50586,35659,30356,40721 +59509,35660,30355,40511 +58922,35661,30354,40636 +51828,35662,30353,40088 +59648,35663,30352,40201 +56693,35664,30351,40060 +53135,35665,30350,40141 +57941,35666,30349,40861 +56965,35667,30348,40350 +59833,35668,30347,40587 +55676,35669,30346,40530 +57698,35670,30345,40345 +54332,35671,30344,40764 +58585,35672,30343,40103 +53613,35673,30342,40013 +54485,35674,30341,40021 +52555,35675,30340,40643 +51900,35676,30339,40481 +58818,35677,30338,40232 +51349,35678,30337,40262 +52345,35679,30336,40018 +58859,35680,30335,40305 +51851,35681,30334,40562 +59934,35682,30333,40096 +58336,35683,30332,40956 +55236,35684,30331,40514 +57434,35685,30330,40010 +50445,35686,30329,40301 +53499,35687,30328,40804 +54868,35688,30327,40360 +55668,35689,30326,40024 +55169,35690,30325,40429 +51864,35691,30324,40322 +53947,35692,30323,40418 +56704,35693,30322,40840 +57707,35694,30321,40413 +52103,35695,30320,40541 +53100,35696,30319,40282 +55861,35697,30318,40976 +57134,35698,30317,40922 +56041,35699,30316,40584 +50073,35700,30315,40017 +58912,35701,30314,40854 +58143,35702,30313,40124 +54274,35703,30312,40695 +54954,35704,30311,40678 +56699,35705,30310,40396 +51381,35706,30309,40630 +54055,35707,30308,40552 +50647,35708,30307,40550 +58855,35709,30306,40742 +51145,35710,30305,40290 +52240,35711,30304,40389 +53849,35712,30303,40282 +52354,35713,30302,40161 +55911,35714,30301,40070 +52566,35715,30300,40590 +50429,35716,30299,40806 +58785,35717,30298,40667 +56091,35718,30297,40867 +55734,35719,30296,40537 +56240,35720,30295,40989 +52311,35721,30294,40879 +58389,35722,30293,40914 +55979,35723,30292,40388 +51075,35724,30291,40808 +50827,35725,30290,40935 +52757,35726,30289,40287 +58087,35727,30288,40358 +52088,35728,30287,40598 +55062,35729,30286,40586 +55518,35730,30285,40064 +53930,35731,30284,40259 +57714,35732,30283,40995 +54898,35733,30282,40253 +59718,35734,30281,40653 +58953,35735,30280,40831 +57545,35736,30279,40898 +53067,35737,30278,40524 +54020,35738,30277,40999 +51128,35739,30276,40775 +59155,35740,30275,40597 +50689,35741,30274,40520 +50225,35742,30273,40514 +50256,35743,30272,40357 +50476,35744,30271,40977 +52564,35745,30270,40479 +54503,35746,30269,40700 +54441,35747,30268,40955 +58174,35748,30267,40748 +58422,35749,30266,40760 +59716,35750,30265,40342 +50064,35751,30264,40380 +52729,35752,30263,40417 +58812,35753,30262,40670 +56919,35754,30261,40511 +58194,35755,30260,40543 +59116,35756,30259,40976 +50381,35757,30258,40267 +56994,35758,30257,40446 +58351,35759,30256,40093 +58889,35760,30255,40625 +57473,35761,30254,40300 +52486,35762,30253,40231 +51687,35763,30252,40880 +59876,35764,30251,40062 +52466,35765,30250,40248 +53401,35766,30249,40106 +56431,35767,30248,40580 +56180,35768,30247,40734 +59118,35769,30246,40650 +57170,35770,30245,40152 +58077,35771,30244,40176 +52176,35772,30243,40990 +57970,35773,30242,40949 +53851,35774,30241,40831 +59655,35775,30240,40763 +55443,35776,30239,40664 +55616,35777,30238,40660 +54270,35778,30237,40539 +59384,35779,30236,40657 +56185,35780,30235,40733 +56137,35781,30234,40705 +53865,35782,30233,40293 +52363,35783,30232,40252 +54015,35784,30231,40484 +57476,35785,30230,40037 +51241,35786,30229,40165 +57901,35787,30228,40397 +52390,35788,30227,40483 +58037,35789,30226,40377 +57586,35790,30225,40665 +58270,35791,30224,40194 +52383,35792,30223,40906 +58805,35793,30222,40477 +52836,35794,30221,40078 +55056,35795,30220,40039 +56847,35796,30219,40949 +53056,35797,30218,40151 +58055,35798,30217,40795 +54422,35799,30216,40672 +50925,35800,30215,40760 +53634,35801,30214,40905 +54832,35802,30213,40963 +51590,35803,30212,40250 +50063,35804,30211,40690 +50249,35805,30210,40909 +59353,35806,30209,40825 +58279,35807,30208,40103 +56640,35808,30207,40972 +53958,35809,30206,40034 +53036,35810,30205,40923 +58275,35811,30204,40328 +57324,35812,30203,40753 +50859,35813,30202,40062 +58184,35814,30201,40985 +54262,35815,30200,40034 +51794,35816,30199,40918 +54013,35817,30198,40051 +54634,35818,30197,40412 +50156,35819,30196,40764 +52577,35820,30195,40448 +58771,35821,30194,40660 +54581,35822,30193,40233 +53718,35823,30192,40637 +53370,35824,30191,40826 +53092,35825,30190,40982 +59450,35826,30189,40406 +50085,35827,30188,40400 +56548,35828,30187,40446 +58797,35829,30186,40177 +50176,35830,30185,40577 +51181,35831,30184,40657 +58018,35832,30183,40417 +56745,35833,30182,40871 +55165,35834,30181,40630 +51379,35835,30180,40334 +58190,35836,30179,40529 +56214,35837,30178,40241 +52713,35838,30177,40167 +57167,35839,30176,40792 +57810,35840,30175,40848 +56038,35841,30174,40975 +52370,35842,30173,40571 +53930,35843,30172,40593 +58585,35844,30171,40376 +58906,35845,30170,40870 +53682,35846,30169,40473 +52209,35847,30168,40590 +52242,35848,30167,40574 +56553,35849,30166,40489 +52746,35850,30165,40379 +54479,35851,30164,40988 +57245,35852,30163,40408 +50311,35853,30162,40450 +55659,35854,30161,40446 +50550,35855,30160,40765 +51051,35856,30159,40841 +55774,35857,30158,40271 +55111,35858,30157,40038 +58711,35859,30156,40002 +54369,35860,30155,40962 +55399,35861,30154,40359 +54548,35862,30153,40932 +52724,35863,30152,40751 +57797,35864,30151,40880 +57905,35865,30150,40548 +58216,35866,30149,40793 +59845,35867,30148,40611 +57295,35868,30147,40995 +53241,35869,30146,40881 +59725,35870,30145,40282 +51855,35871,30144,40231 +56841,35872,30143,40706 +55664,35873,30142,40811 +53102,35874,30141,40156 +58622,35875,30140,40540 +55567,35876,30139,40465 +51272,35877,30138,40490 +59784,35878,30137,40614 +57436,35879,30136,40055 +52911,35880,30135,40292 +53542,35881,30134,40310 +52186,35882,30133,40531 +53623,35883,30132,40047 +58346,35884,30131,40547 +50977,35885,30130,40148 +54500,35886,30129,40847 +57710,35887,30128,40099 +54065,35888,30127,40918 +59329,35889,30126,40447 +58891,35890,30125,40559 +50788,35891,30124,40309 +55816,35892,30123,40632 +57600,35893,30122,40185 +50403,35894,30121,40659 +56363,35895,30120,40755 +58805,35896,30119,40142 +51148,35897,30118,40706 +54563,35898,30117,40670 +59130,35899,30116,40682 +51073,35900,30115,40095 +57986,35901,30114,40261 +51572,35902,30113,40441 +57287,35903,30112,40892 +50373,35904,30111,40858 +55924,35905,30110,40863 +54338,35906,30109,40021 +54141,35907,30108,40217 +54094,35908,30107,40037 +50996,35909,30106,40929 +55001,35910,30105,40336 +54007,35911,30104,40334 +51482,35912,30103,40258 +50934,35913,30102,40403 +52856,35914,30101,40788 +51490,35915,30100,40043 +57976,35916,30099,40617 +55601,35917,30098,40489 +51953,35918,30097,40549 +51247,35919,30096,40830 +53259,35920,30095,40946 +54542,35921,30094,40303 +54262,35922,30093,40889 +51502,35923,30092,40635 +58167,35924,30091,40049 +57399,35925,30090,40982 +56605,35926,30089,40375 +53395,35927,30088,40885 +56594,35928,30087,40059 +56777,35929,30086,40719 +51213,35930,30085,40210 +51668,35931,30084,40563 +54692,35932,30083,40557 +58578,35933,30082,40212 +53342,35934,30081,40494 +58232,35935,30080,40206 +55799,35936,30079,40794 +56723,35937,30078,40227 +53501,35938,30077,40983 +51145,35939,30076,40575 +56519,35940,30075,40451 +54974,35941,30074,40804 +54869,35942,30073,40822 +51554,35943,30072,40451 +57186,35944,30071,40974 +56504,35945,30070,40296 +52838,35946,30069,40965 +54674,35947,30068,40784 +57880,35948,30067,40697 +56952,35949,30066,40546 +56225,35950,30065,40759 +50183,35951,30064,40567 +55499,35952,30063,40293 +56198,35953,30062,40367 +51897,35954,30061,40435 +54275,35955,30060,40825 +51296,35956,30059,40437 +50508,35957,30058,40679 +53283,35958,30057,40680 +58106,35959,30056,40516 +55196,35960,30055,40606 +51144,35961,30054,40395 +58422,35962,30053,40952 +58113,35963,30052,40021 +55160,35964,30051,40871 +55271,35965,30050,40839 +58732,35966,30049,40782 +56016,35967,30048,40421 +50397,35968,30047,40184 +53227,35969,30046,40287 +58110,35970,30045,40170 +55633,35971,30044,40143 +59752,35972,30043,40740 +53158,35973,30042,40787 +51740,35974,30041,40665 +52446,35975,30040,40389 +56918,35976,30039,40152 +59676,35977,30038,40724 +57138,35978,30037,40607 +50310,35979,30036,40455 +56088,35980,30035,40291 +54420,35981,30034,40118 +55875,35982,30033,40407 +55063,35983,30032,40413 +52848,35984,30031,40094 +50631,35985,30030,40822 +55954,35986,30029,40438 +56357,35987,30028,40458 +58450,35988,30027,40315 +50879,35989,30026,40475 +54243,35990,30025,40645 +58642,35991,30024,40729 +54916,35992,30023,40048 +58281,35993,30022,40343 +52830,35994,30021,40294 +57011,35995,30020,40345 +59773,35996,30019,40715 +57171,35997,30018,40709 +57548,35998,30017,40404 +59825,35999,30016,40483 +50569,36000,30015,40932 +53470,36001,30014,40026 +54007,36002,30013,40645 +53636,36003,30012,40848 +51506,36004,30011,40735 +59484,36005,30010,40445 +50894,36006,30009,40465 +57161,36007,30008,40509 +56600,36008,30007,40217 +59554,36009,30006,40464 +51694,36010,30005,40489 +59438,36011,30004,40016 +51770,36012,30003,40561 +52679,36013,30002,40910 +57241,36014,30001,40306 +55648,36015,30000,40314 +55371,36016,31000,40934 +54195,36017,30999,40157 +51411,36018,30998,40818 +56259,36019,30997,40348 +54301,36020,30996,40852 +53568,36021,30995,40020 +58671,36022,30994,40287 +51481,36023,30993,40580 +52920,36024,30992,40720 +51628,36025,30991,40619 +50694,36026,30990,40285 +51849,36027,30989,40967 +52900,36028,30988,40473 +53765,36029,30987,40143 +56831,36030,30986,40302 +59849,36031,30985,40598 +50090,36032,30984,40711 +54026,36033,30983,40308 +50712,36034,30982,40129 +52356,36035,30981,40107 +52038,36036,30980,40462 +51008,36037,30979,40571 +57563,36038,30978,40213 +52469,36039,30977,40858 +55463,36040,30976,40017 +58330,36041,30975,40724 +51113,36042,30974,40796 +58570,36043,30973,40754 +51117,36044,30972,40944 +50432,36045,30971,40450 +56546,36046,30970,40259 +51281,36047,30969,40531 +56730,36048,30968,40660 +58985,36049,30967,40836 +52170,36050,30966,40118 +50349,36051,30965,40864 +51201,36052,30964,40240 +53792,36053,30963,40903 +54422,36054,30962,40638 +59537,36055,30961,40228 +50154,36056,30960,40024 +57361,36057,30959,40862 +55548,36058,30958,40076 +54307,36059,30957,40998 +58955,36060,30956,40434 +58060,36061,30955,40172 +50182,36062,30954,40349 +55818,36063,30953,40294 +53871,36064,30952,40833 +58497,36065,30951,40775 +56063,36066,30950,40093 +55728,36067,30949,40879 +56675,36068,30948,40439 +57955,36069,30947,40084 +59459,36070,30946,40422 +50385,36071,30945,40821 +53827,36072,30944,40800 +55733,36073,30943,40911 +53683,36074,30942,40744 +52042,36075,30941,40806 +52129,36076,30940,40571 +59951,36077,30939,40034 +59150,36078,30938,40688 +59466,36079,30937,40059 +52462,36080,30936,40945 +53129,36081,30935,40010 +59273,36082,30934,40995 +51987,36083,30933,40373 +55407,36084,30932,40686 +50669,36085,30931,40719 +59656,36086,30930,40801 +55753,36087,30929,40386 +50104,36088,30928,40085 +55241,36089,30927,40937 +53266,36090,30926,40772 +54081,36091,30925,40327 +53716,36092,30924,40534 +59002,36093,30923,40822 +54352,36094,30922,40208 +58323,36095,30921,40869 +59930,36096,30920,40609 +52306,36097,30919,40537 +53405,36098,30918,40954 +59145,36099,30917,40582 +53033,36100,30916,40658 +51971,36101,30915,40890 +51975,36102,30914,40515 +58173,36103,30913,40254 +57325,36104,30912,40397 +59665,36105,30911,40794 +52700,36106,30910,40172 +52702,36107,30909,40828 +54086,36108,30908,40056 +59412,36109,30907,40525 +58894,36110,30906,40969 +58059,36111,30905,40864 +52808,36112,30904,40813 +51043,36113,30903,40663 +55423,36114,30902,40336 +58181,36115,30901,40972 +52453,36116,30900,40207 +56345,36117,30899,40378 +54437,36118,30898,40329 +56673,36119,30897,40805 +56596,36120,30896,40226 +58355,36121,30895,40076 +54246,36122,30894,40413 +53012,36123,30893,40385 +56413,36124,30892,40789 +56431,36125,30891,40131 +55805,36126,30890,40056 +53764,36127,30889,40913 +58490,36128,30888,40104 +50302,36129,30887,40010 +53459,36130,30886,40696 +51437,36131,30885,40613 +59960,36132,30884,40656 +54354,36133,30883,40362 +54293,36134,30882,40301 +52777,36135,30881,40956 +57443,36136,30880,40784 +51536,36137,30879,40684 +50596,36138,30878,40457 +57974,36139,30877,40803 +53341,36140,30876,40272 +59791,36141,30875,40827 +54704,36142,30874,40783 +50260,36143,30873,40643 +52806,36144,30872,40135 +55543,36145,30871,40205 +58668,36146,30870,40814 +57844,36147,30869,40813 +56965,36148,30868,40794 +53314,36149,30867,40288 +57709,36150,30866,40621 +53273,36151,30865,40311 +58029,36152,30864,40389 +50254,36153,30863,40046 +50298,36154,30862,40406 +59434,36155,30861,40365 +59224,36156,30860,40694 +57081,36157,30859,40555 +51836,36158,30858,40508 +55614,36159,30857,40586 +56720,36160,30856,40910 +56083,36161,30855,40323 +56975,36162,30854,40942 +51421,36163,30853,40151 +54688,36164,30852,40257 +51535,36165,30851,40919 +54655,36166,30850,40484 +57109,36167,30849,40280 +53926,36168,30848,40739 +55201,36169,30847,40590 +57500,36170,30846,40815 +52243,36171,30845,40836 +55428,36172,30844,40194 +53488,36173,30843,40510 +58934,36174,30842,40730 +54037,36175,30841,40371 +51546,36176,30840,40336 +57221,36177,30839,40378 +52272,36178,30838,40941 +53790,36179,30837,40655 +50797,36180,30836,40088 +51722,36181,30835,40906 +52608,36182,30834,40774 +59058,36183,30833,40517 +53347,36184,30832,40190 +58412,36185,30831,40880 +52301,36186,30830,40632 +59669,36187,30829,40811 +50244,36188,30828,40945 +54201,36189,30827,40631 +54496,36190,30826,40517 +51183,36191,30825,40969 +54250,36192,30824,40834 +53186,36193,30823,40732 +55731,36194,30822,40349 +57114,36195,30821,40794 +54545,36196,30820,40988 +55130,36197,30819,40439 +57348,36198,30818,40903 +50082,36199,30817,40778 +50791,36200,30816,40516 +56692,36201,30815,40464 +58130,36202,30814,40797 +56627,36203,30813,40023 +53628,36204,30812,40439 +54936,36205,30811,40340 +53086,36206,30810,40450 +57055,36207,30809,40345 +58547,36208,30808,40656 +50142,36209,30807,40790 +59403,36210,30806,40036 +59301,36211,30805,40667 +58319,36212,30804,40313 +55808,36213,30803,40680 +50671,36214,30802,40396 +58250,36215,30801,40578 +51750,36216,30800,40822 +54940,36217,30799,40162 +57967,36218,30798,40994 +51363,36219,30797,40770 +52097,36220,30796,40016 +56192,36221,30795,40791 +50694,36222,30794,40475 +56600,36223,30793,40918 +54201,36224,30792,40093 +54476,36225,30791,40205 +58766,36226,30790,40853 +51395,36227,30789,40535 +54987,36228,30788,40186 +50195,36229,30787,40954 +52500,36230,30786,40279 +54590,36231,30785,40689 +58661,36232,30784,40091 +53225,36233,30783,40529 +58536,36234,30782,40420 +53192,36235,30781,40883 +50198,36236,30780,40767 +59157,36237,30779,40845 +58922,36238,30778,40118 +58048,36239,30777,40613 +52129,36240,30776,40326 +56688,36241,30775,40595 +54830,36242,30774,40220 +50056,36243,30773,40561 +57194,36244,30772,40476 +50324,36245,30771,40834 +58968,36246,30770,40982 +57474,36247,30769,40836 +56839,36248,30768,40629 +58222,36249,30767,40523 +55920,36250,30766,40349 +51398,36251,30765,40747 +50383,36252,30764,40345 +58044,36253,30763,40498 +56191,36254,30762,40934 +59866,36255,30761,40480 +51470,36256,30760,40527 +57855,36257,30759,40901 +52496,36258,30758,40237 +59400,36259,30757,40877 +54079,36260,30756,40883 +59802,36261,30755,40842 +59487,36262,30754,40572 +59371,36263,30753,40414 +57200,36264,30752,40553 +55696,36265,30751,40114 +50221,36266,30750,40427 +55601,36267,30749,40704 +51217,36268,30748,40369 +50553,36269,30747,40378 +55065,36270,30746,40039 +51690,36271,30745,40966 +55860,36272,30744,40771 +53325,36273,30743,40839 +52247,36274,30742,40149 +58871,36275,30741,40400 +54670,36276,30740,40834 +56919,36277,30739,40135 +53437,36278,30738,40613 +54827,36279,30737,40635 +57204,36280,30736,40427 +56402,36281,30735,40220 +59745,36282,30734,40697 +53757,36283,30733,40734 +52223,36284,30732,40388 +53695,36285,30731,40297 +53884,36286,30730,40293 +54004,36287,30729,40280 +58280,36288,30728,40967 +56541,36289,30727,40396 +56073,36290,30726,40206 +58713,36291,30725,40093 +57755,36292,30724,40902 +57823,36293,30723,40149 +53957,36294,30722,40957 +51640,36295,30721,40416 +50216,36296,30720,40926 +53977,36297,30719,40339 +53296,36298,30718,40707 +55150,36299,30717,40744 +57885,36300,30716,40086 +55171,36301,30715,40387 +59931,36302,30714,40260 +53547,36303,30713,40421 +52269,36304,30712,40959 +58084,36305,30711,40378 +52392,36306,30710,40774 +57698,36307,30709,40377 +59243,36308,30708,40915 +52375,36309,30707,40743 +59597,36310,30706,40152 +50676,36311,30705,40208 +59695,36312,30704,40663 +53545,36313,30703,40044 +54832,36314,30702,40469 +59256,36315,30701,40394 +51119,36316,30700,40338 +52808,36317,30699,40420 +58667,36318,30698,40528 +50181,36319,30697,40110 +58887,36320,30696,40278 +51189,36321,30695,40580 +57785,36322,30694,40480 +55878,36323,30693,40407 +58833,36324,30692,40108 +52626,36325,30691,40203 +55767,36326,30690,40955 +59700,36327,30689,40280 +53437,36328,30688,40441 +55829,36329,30687,40179 +58787,36330,30686,40620 +55951,36331,30685,40745 +55898,36332,30684,40165 +59427,36333,30683,40767 +55568,36334,30682,40398 +55013,36335,30681,40977 +52058,36336,30680,40609 +54501,36337,30679,40941 +56784,36338,30678,40368 +55001,36339,30677,40795 +56881,36340,30676,40454 +57765,36341,30675,40324 +55000,36342,30674,40768 +58557,36343,30673,40363 +58182,36344,30672,40266 +54001,36345,30671,40724 +55199,36346,30670,40250 +55239,36347,30669,40864 +50977,36348,30668,40995 +59543,36349,30667,40658 +57550,36350,30666,40873 +54447,36351,30665,40545 +54123,36352,30664,40899 +54695,36353,30663,40699 +50480,36354,30662,40042 +54767,36355,30661,40018 +59632,36356,30660,40380 +57092,36357,30659,40765 +58771,36358,30658,40581 +50241,36359,30657,40086 +53327,36360,30656,40428 +56722,36361,30655,40091 +52662,36362,30654,40589 +57380,36363,30653,40723 +53976,36364,30652,40712 +54201,36365,30651,40256 +50648,36366,30650,40781 +50087,36367,30649,40571 +57884,36368,30648,40185 +50112,36369,30647,40976 +58479,36370,30646,40106 +50524,36371,30645,40207 +53697,36372,30644,40892 +54866,36373,30643,40900 +55422,36374,30642,40605 +55094,36375,30641,40788 +52299,36376,30640,40811 +54988,36377,30639,40068 +59324,36378,30638,40296 +59835,36379,30637,40759 +50899,36380,30636,40015 +55756,36381,30635,40796 +59988,36382,30634,40606 +53617,36383,30633,40250 +59812,36384,30632,40711 +57907,36385,30631,40433 +58847,36386,30630,40653 +57620,36387,30629,40631 +59976,36388,30628,40391 +51428,36389,30627,40811 +56939,36390,30626,40060 +59118,36391,30625,40993 +56687,36392,30624,40108 +53282,36393,30623,40731 +59015,36394,30622,40311 +59198,36395,30621,40256 +56951,36396,30620,40916 +59029,36397,30619,40547 +58836,36398,30618,40336 +51186,36399,30617,40011 +59860,36400,30616,40577 +50325,36401,30615,40242 +54933,36402,30614,40805 +51787,36403,30613,40389 +55753,36404,30612,40188 +52541,36405,30611,40847 +51839,36406,30610,40479 +57183,36407,30609,40914 +53437,36408,30608,40363 +51833,36409,30607,40835 +57977,36410,30606,40318 +50770,36411,30605,40856 +58327,36412,30604,40253 +52407,36413,30603,40361 +57117,36414,30602,40911 +58300,36415,30601,40473 +56786,36416,30600,40106 +58137,36417,30599,40527 +53956,36418,30598,40032 +55238,36419,30597,40837 +59881,36420,30596,40997 +55009,36421,30595,40564 +58670,36422,30594,40336 +51292,36423,30593,40442 +56699,36424,30592,40372 +52228,36425,30591,40162 +51463,36426,30590,40465 +50411,36427,30589,40438 +58824,36428,30588,40332 +54375,36429,30587,40274 +59010,36430,30586,40616 +54100,36431,30585,40752 +57505,36432,30584,40559 +54148,36433,30583,40724 +51522,36434,30582,40441 +52439,36435,30581,40892 +52619,36436,30580,40903 +55926,36437,30579,40334 +51147,36438,30578,40373 +54680,36439,30577,40398 +56252,36440,30576,40114 +58728,36441,30575,40058 +53637,36442,30574,40941 +56862,36443,30573,40923 +52956,36444,30572,40837 +51881,36445,30571,40882 +57433,36446,30570,40605 +56142,36447,30569,40581 +58293,36448,30568,40619 +54810,36449,30567,40221 +51425,36450,30566,40788 +59843,36451,30565,40525 +52083,36452,30564,40949 +53725,36453,30563,40753 +52028,36454,30562,40368 +53561,36455,30561,40505 +58005,36456,30560,40689 +51992,36457,30559,40104 +57207,36458,30558,40804 +52573,36459,30557,40997 +54841,36460,30556,40278 +57648,36461,30555,40653 +57348,36462,30554,40268 +55630,36463,30553,40067 +56259,36464,30552,40355 +51774,36465,30551,40750 +53398,36466,30550,40061 +51519,36467,30549,40141 +50886,36468,30548,40021 +50989,36469,30547,40729 +55907,36470,30546,40719 +53058,36471,30545,40863 +51896,36472,30544,40639 +55801,36473,30543,40977 +56496,36474,30542,40900 +55949,36475,30541,40519 +57106,36476,30540,40393 +58512,36477,30539,40055 +54328,36478,30538,40648 +55736,36479,30537,40623 +57374,36480,30536,40531 +54388,36481,30535,40467 +57781,36482,30534,40833 +53453,36483,30533,40439 +52903,36484,30532,40056 +53639,36485,30531,40058 +58997,36486,30530,40173 +56199,36487,30529,40317 +58219,36488,30528,40062 +56190,36489,30527,40263 +55653,36490,30526,40688 +58579,36491,30525,40430 +52860,36492,30524,40642 +56350,36493,30523,40876 +56537,36494,30522,40773 +57665,36495,30521,40884 +57482,36496,30520,40870 +58481,36497,30519,40135 +50962,36498,30518,40778 +56338,36499,30517,40272 +51306,36500,30516,40557 +54594,36501,30515,40512 +58645,36502,30514,40662 +50619,36503,30513,40502 +52290,36504,30512,40123 +55340,36505,30511,40351 +50298,36506,30510,40028 +51857,36507,30509,40709 +55113,36508,30508,40527 +51790,36509,30507,40584 +52650,36510,30506,40512 +57099,36511,30505,40446 +56091,36512,30504,40730 +57849,36513,30503,40592 +50448,36514,30502,40134 +56211,36515,30501,40762 +56595,36516,30500,40070 +50160,36517,30499,40710 +50777,36518,30498,40887 +54804,36519,30497,40255 +57535,36520,30496,40761 +50710,36521,30495,40805 +57955,36522,30494,40941 +53324,36523,30493,40937 +53600,36524,30492,40410 +50515,36525,30491,40582 +57921,36526,30490,40091 +59339,36527,30489,40890 +58678,36528,30488,40128 +54863,36529,30487,40072 +50708,36530,30486,40152 +56274,36531,30485,40996 +50487,36532,30484,40672 +51829,36533,30483,40914 +58019,36534,30482,40106 +55685,36535,30481,40643 +54232,36536,30480,40733 +59745,36537,30479,40164 +54628,36538,30478,40037 +59561,36539,30477,40037 +55522,36540,30476,40991 +52354,36541,30475,40580 +52528,36542,30474,40516 +59286,36543,30473,40027 +55550,36544,30472,40727 +58248,36545,30471,40820 +52290,36546,30470,40548 +59285,36547,30469,40799 +57097,36548,30468,40726 +53526,36549,30467,40950 +57512,36550,30466,40981 +56594,36551,30465,40894 +54768,36552,30464,40155 +51712,36553,30463,40050 +51104,36554,30462,40266 +59738,36555,30461,40437 +53700,36556,30460,40988 +53086,36557,30459,40836 +59836,36558,30458,40981 +51998,36559,30457,40790 +56263,36560,30456,40977 +55383,36561,30455,40449 +59822,36562,30454,40006 +54766,36563,30453,40913 +54445,36564,30452,40341 +56950,36565,30451,40655 +50348,36566,30450,40915 +50223,36567,30449,40877 +59148,36568,30448,40078 +53224,36569,30447,40410 +50812,36570,30446,40510 +53973,36571,30445,40710 +55003,36572,30444,40290 +59724,36573,30443,40059 +56936,36574,30442,40964 +57161,36575,30441,40822 +56134,36576,30440,40402 +55553,36577,30439,40281 +59771,36578,30438,40210 +57731,36579,30437,40086 +52440,36580,30436,40401 +51562,36581,30435,40506 +58930,36582,30434,40856 +55712,36583,30433,40955 +53374,36584,30432,40923 +55485,36585,30431,40943 +55644,36586,30430,40687 +57613,36587,30429,40627 +51578,36588,30428,40856 +53231,36589,30427,40717 +56042,36590,30426,40772 +54121,36591,30425,40287 +57486,36592,30424,40760 +52185,36593,30423,40913 +55199,36594,30422,40749 +54934,36595,30421,40257 +50236,36596,30420,40294 +52534,36597,30419,40057 +54896,36598,30418,40136 +56969,36599,30417,40453 +55372,36600,30416,40998 +51570,36601,30415,40319 +55092,36602,30414,40624 +56933,36603,30413,40049 +56022,36604,30412,40608 +56476,36605,30411,40574 +59108,36606,30410,40010 +51779,36607,30409,40214 +51107,36608,30408,40141 +55092,36609,30407,40645 +52972,36610,30406,40433 +59805,36611,30405,40894 +56431,36612,30404,40975 +55229,36613,30403,40929 +58728,36614,30402,40231 +57822,36615,30401,40790 +53786,36616,30400,40354 +56379,36617,30399,40508 +54295,36618,30398,40678 +55107,36619,30397,40467 +53122,36620,30396,40479 +51382,36621,30395,40474 +50475,36622,30394,40504 +54460,36623,30393,40166 +57849,36624,30392,40790 +54533,36625,30391,40368 +59863,36626,30390,40900 +55163,36627,30389,40730 +54981,36628,30388,40912 +52243,36629,30387,40654 +53583,36630,30386,40266 +58531,36631,30385,40578 +56074,36632,30384,40548 +54733,36633,30383,40268 +59050,36634,30382,40315 +55113,36635,30381,40549 +52578,36636,30380,40057 +55090,36637,30379,40349 +58275,36638,30378,40963 +52631,36639,30377,40692 +55029,36640,30376,40806 +57857,36641,30375,40904 +55571,36642,30374,40273 +50707,36643,30373,40520 +58544,36644,30372,40423 +56845,36645,30371,40548 +57032,36646,30370,40211 +59948,36647,30369,40854 +53138,36648,30368,40088 +53084,36649,30367,40089 +58785,36650,30366,40717 +54813,36651,30365,40172 +59370,36652,30364,40777 +51539,36653,30363,40939 +56559,36654,30362,40872 +54199,36655,30361,40099 +50266,36656,30360,40138 +52683,36657,30359,40568 +57462,36658,30358,40996 +51131,36659,30357,40965 +50262,36660,30356,40646 +51807,36661,30355,40374 +57145,36662,30354,40352 +57277,36663,30353,40989 +53365,36664,30352,40673 +53019,36665,30351,40296 +52848,36666,30350,40118 +51538,36667,30349,40507 +51454,36668,30348,40668 +50302,36669,30347,40920 +56197,36670,30346,40986 +54306,36671,30345,40175 +56476,36672,30344,40997 +59832,36673,30343,40299 +59394,36674,30342,40953 +51830,36675,30341,40020 +52011,36676,30340,40097 +50988,36677,30339,40570 +52836,36678,30338,40148 +55946,36679,30337,40964 +52136,36680,30336,40236 +58383,36681,30335,40149 +59355,36682,30334,40468 +51676,36683,30333,40063 +55923,36684,30332,40749 +54486,36685,30331,40503 +53783,36686,30330,40549 +56506,36687,30329,40605 +57008,36688,30328,40749 +58204,36689,30327,40023 +53212,36690,30326,40589 +56872,36691,30325,40297 +55681,36692,30324,40678 +52665,36693,30323,40146 +53966,36694,30322,40843 +55319,36695,30321,40022 +58045,36696,30320,40957 +53243,36697,30319,40372 +51941,36698,30318,40162 +50718,36699,30317,40555 +51676,36700,30316,40465 +53184,36701,30315,40094 +51082,36702,30314,40925 +59749,36703,30313,40961 +50984,36704,30312,40500 +50474,36705,30311,40806 +58920,36706,30310,40962 +50101,36707,30309,40505 +53646,36708,30308,40143 +57369,36709,30307,40324 +52059,36710,30306,40937 +51816,36711,30305,40056 +54714,36712,30304,40303 +58068,36713,30303,40465 +54355,36714,30302,40348 +54526,36715,30301,40196 +59614,36716,30300,40884 +50160,36717,30299,40063 +53426,36718,30298,40599 +53222,36719,30297,40925 +57979,36720,30296,40646 +59670,36721,30295,40773 +52921,36722,30294,40270 +53088,36723,30293,40751 +56837,36724,30292,40976 +55713,36725,30291,40138 +51711,36726,30290,40403 +58930,36727,30289,40060 +51890,36728,30288,40527 +53101,36729,30287,40791 +53081,36730,30286,40887 +50239,36731,30285,40812 +52987,36732,30284,40338 +59913,36733,30283,40880 +52290,36734,30282,40125 +54161,36735,30281,40983 +55594,36736,30280,40825 +54805,36737,30279,40297 +54948,36738,30278,40892 +55279,36739,30277,40815 +50122,36740,30276,40303 +58964,36741,30275,40426 +53565,36742,30274,40707 +59351,36743,30273,40449 +54970,36744,30272,40481 +55355,36745,30271,40860 +53339,36746,30270,40525 +52997,36747,30269,40330 +50681,36748,30268,40662 +59039,36749,30267,40467 +54127,36750,30266,40621 +58937,36751,30265,40211 +50843,36752,30264,40519 +52923,36753,30263,40940 +59405,36754,30262,40904 +57333,36755,30261,40878 +55298,36756,30260,40030 +53127,36757,30259,40134 +53386,36758,30258,40287 +53996,36759,30257,40136 +51925,36760,30256,40520 +57393,36761,30255,40026 +50156,36762,30254,40564 +53124,36763,30253,40487 +59836,36764,30252,40285 +54023,36765,30251,40509 +51485,36766,30250,40793 +54532,36767,30249,40828 +56321,36768,30248,40372 +56427,36769,30247,40851 +57288,36770,30246,40118 +59366,36771,30245,40400 +54208,36772,30244,40217 +59421,36773,30243,40899 +58106,36774,30242,40530 +59621,36775,30241,40543 +52295,36776,30240,40393 +57028,36777,30239,40983 +54834,36778,30238,40014 +52768,36779,30237,40922 +54918,36780,30236,40674 +57157,36781,30235,40634 +54032,36782,30234,40455 +53157,36783,30233,40630 +57472,36784,30232,40157 +51417,36785,30231,40497 +56985,36786,30230,40179 +52390,36787,30229,40975 +55704,36788,30228,40014 +55691,36789,30227,40117 +57153,36790,30226,40392 +59559,36791,30225,40554 +55476,36792,30224,40328 +53271,36793,30223,40485 +59183,36794,30222,40729 +57597,36795,30221,40020 +52621,36796,30220,40114 +58764,36797,30219,40246 +51052,36798,30218,40986 +51856,36799,30217,40166 +59116,36800,30216,40150 +50490,36801,30215,40740 +50243,36802,30214,40409 +52073,36803,30213,40290 +58270,36804,30212,40647 +51253,36805,30211,40224 +57106,36806,30210,40045 +59396,36807,30209,40260 +51889,36808,30208,40512 +58735,36809,30207,40049 +54088,36810,30206,40264 +54303,36811,30205,40843 +50372,36812,30204,40009 +52145,36813,30203,40885 +50068,36814,30202,40983 +52553,36815,30201,40623 +58602,36816,30200,40811 +50066,36817,30199,40359 +58780,36818,30198,40902 +52739,36819,30197,40394 +51079,36820,30196,40520 +51038,36821,30195,40359 +52451,36822,30194,40750 +59554,36823,30193,40553 +54385,36824,30192,40774 +57344,36825,30191,40944 +51504,36826,30190,40288 +55866,36827,30189,40746 +52559,36828,30188,40810 +59415,36829,30187,40938 +56126,36830,30186,40448 +51540,36831,30185,40053 +53629,36832,30184,40815 +53124,36833,30183,40270 +59830,36834,30182,40485 +53816,36835,30181,40621 +53286,36836,30180,40942 +58586,36837,30179,40112 +52486,36838,30178,40997 +54563,36839,30177,40150 +54424,36840,30176,40837 +53901,36841,30175,40204 +58893,36842,30174,40315 +58978,36843,30173,40734 +54019,36844,30172,40955 +55475,36845,30171,40827 +50844,36846,30170,40763 +58597,36847,30169,40181 +53049,36848,30168,40855 +56469,36849,30167,40436 +50325,36850,30166,40730 +51116,36851,30165,40935 +54591,36852,30164,40789 +59150,36853,30163,40830 +53392,36854,30162,40048 +53709,36855,30161,40166 +51066,36856,30160,40187 +59098,36857,30159,40482 +50609,36858,30158,40823 +53819,36859,30157,40218 +52051,36860,30156,40757 +56520,36861,30155,40891 +50242,36862,30154,40770 +51904,36863,30153,40731 +50579,36864,30152,40271 +51640,36865,30151,40527 +57439,36866,30150,40801 +53139,36867,30149,40730 +52279,36868,30148,40209 +52718,36869,30147,40956 +51860,36870,30146,40273 +59314,36871,30145,40422 +57564,36872,30144,40025 +56252,36873,30143,40085 +50097,36874,30142,40206 +59641,36875,30141,40139 +51235,36876,30140,40743 +55739,36877,30139,40157 +56934,36878,30138,40363 +57049,36879,30137,40985 +53246,36880,30136,40618 +57522,36881,30135,40673 +54102,36882,30134,40750 +58689,36883,30133,40389 +59393,36884,30132,40909 +52429,36885,30131,40160 +53064,36886,30130,40654 +59224,36887,30129,40761 +51713,36888,30128,40510 +58071,36889,30127,40035 +58912,36890,30126,40766 +56224,36891,30125,40099 +56776,36892,30124,40987 +52735,36893,30123,40703 +53786,36894,30122,40057 +57364,36895,30121,40390 +50046,36896,30120,40069 +52134,36897,30119,40807 +57120,36898,30118,40821 +56811,36899,30117,40497 +53041,36900,30116,40134 +56687,36901,30115,40964 +54654,36902,30114,40675 +55041,36903,30113,40875 +58270,36904,30112,40652 +51502,36905,30111,40719 +57492,36906,30110,40426 +54917,36907,30109,40849 +53348,36908,30108,40837 +57305,36909,30107,40187 +59251,36910,30106,40713 +58357,36911,30105,40507 +52632,36912,30104,40875 +55177,36913,30103,40157 +52270,36914,30102,40627 +51555,36915,30101,40940 +56667,36916,30100,40280 +58425,36917,30099,40229 +56043,36918,30098,40018 +54435,36919,30097,40313 +51477,36920,30096,40088 +54502,36921,30095,40213 +56399,36922,30094,40238 +53658,36923,30093,40551 +55182,36924,30092,40819 +55180,36925,30091,40558 +54165,36926,30090,40317 +50640,36927,30089,40670 +57966,36928,30088,40593 +59759,36929,30087,40135 +58231,36930,30086,40499 +54606,36931,30085,40378 +51508,36932,30084,40086 +50767,36933,30083,40135 +50067,36934,30082,40128 +52160,36935,30081,40342 +52492,36936,30080,40517 +58050,36937,30079,40200 +52966,36938,30078,40327 +55236,36939,30077,40809 +58935,36940,30076,40503 +54477,36941,30075,40004 +59268,36942,30074,40362 +58025,36943,30073,40618 +50310,36944,30072,40851 +58523,36945,30071,40217 +59374,36946,30070,40657 +52736,36947,30069,40702 +52831,36948,30068,40933 +55380,36949,30067,40959 +53577,36950,30066,40458 +55022,36951,30065,40182 +57734,36952,30064,40361 +51030,36953,30063,40261 +50173,36954,30062,40447 +55879,36955,30061,40003 +58756,36956,30060,40694 +54112,36957,30059,40889 +58787,36958,30058,40893 +51284,36959,30057,40788 +50708,36960,30056,40988 +58961,36961,30055,40215 +59142,36962,30054,40905 +58526,36963,30053,40052 +53600,36964,30052,40360 +57101,36965,30051,40222 +51362,36966,30050,40931 +57312,36967,30049,40558 +54840,36968,30048,40677 +52248,36969,30047,40057 +59160,36970,30046,40508 +58024,36971,30045,40986 +53194,36972,30044,40563 +59272,36973,30043,40529 +53799,36974,30042,40665 +56133,36975,30041,40519 +59322,36976,30040,40538 +53126,36977,30039,40653 +50548,36978,30038,40439 +57802,36979,30037,40585 +54812,36980,30036,40228 +57725,36981,30035,40011 +52515,36982,30034,40390 +54905,36983,30033,40506 +56964,36984,30032,40120 +56121,36985,30031,40822 +53978,36986,30030,40945 +52473,36987,30029,40426 +59693,36988,30028,40931 +56153,36989,30027,40952 +51652,36990,30026,40330 +50657,36991,30025,40152 +52574,36992,30024,40462 +56526,36993,30023,40127 +52652,36994,30022,40239 +51161,36995,30021,40800 +57717,36996,30020,40213 +52425,36997,30019,40529 +52957,36998,30018,40434 +51471,36999,30017,40373 +50912,37000,30016,40628 +52816,37001,30015,40873 +54441,37002,30014,40410 +53792,37003,30013,40397 +57423,37004,30012,40849 +56456,37005,30011,40610 +52462,37006,30010,40860 +55882,37007,30009,40634 +50419,37008,30008,40519 +54124,37009,30007,40768 +55105,37010,30006,40814 +51392,37011,30005,40845 +51778,37012,30004,40943 +52500,37013,30003,40116 +54071,37014,30002,40704 +53461,37015,30001,40499 +56320,37016,30000,40678 +52990,37017,31000,40718 +52279,37018,30999,40259 +58863,37019,30998,40569 +50278,37020,30997,40035 +54793,37021,30996,40202 +58969,37022,30995,40683 +55925,37023,30994,40129 +50318,37024,30993,40743 +58228,37025,30992,40398 +52329,37026,30991,40991 +50385,37027,30990,40565 +55572,37028,30989,40525 +50883,37029,30988,40455 +55588,37030,30987,40869 +58975,37031,30986,40496 +52438,37032,30985,40809 +53338,37033,30984,40769 +59736,37034,30983,40112 +51259,37035,30982,40098 +52917,37036,30981,40435 +53151,37037,30980,40382 +57928,37038,30979,40372 +56695,37039,30978,40842 +51218,37040,30977,40171 +54555,37041,30976,40723 +56566,37042,30975,40654 +54658,37043,30974,40707 +50481,37044,30973,40139 +55737,37045,30972,40648 +50935,37046,30971,40694 +59057,37047,30970,40321 +50440,37048,30969,40706 +55798,37049,30968,40774 +56194,37050,30967,40918 +59721,37051,30966,40299 +56848,37052,30965,40333 +52735,37053,30964,40696 +59456,37054,30963,40913 +53218,37055,30962,40376 +55171,37056,30961,40150 +54517,37057,30960,40284 +54349,37058,30959,40767 +58597,37059,30958,40156 +52988,37060,30957,40655 +59515,37061,30956,40713 +56981,37062,30955,40805 +53807,37063,30954,40538 +52377,37064,30953,40317 +54854,37065,30952,40793 +58039,37066,30951,40863 +57979,37067,30950,40496 +53212,37068,30949,40255 +59340,37069,30948,40414 +58853,37070,30947,40128 +56475,37071,30946,40312 +54501,37072,30945,40309 +57573,37073,30944,40741 +51713,37074,30943,40566 +59024,37075,30942,40915 +50569,37076,30941,40139 +54349,37077,30940,40720 +52450,37078,30939,40376 +51740,37079,30938,40262 +57550,37080,30937,40469 +55807,37081,30936,40541 +54812,37082,30935,40961 +53159,37083,30934,40534 +50188,37084,30933,40459 +53275,37085,30932,40402 +51787,37086,30931,40668 +59799,37087,30930,40485 +54716,37088,30929,40636 +58992,37089,30928,40259 +55656,37090,30927,40575 +53829,37091,30926,40245 +54316,37092,30925,40396 +51954,37093,30924,40343 +55329,37094,30923,40146 +57742,37095,30922,40169 +50937,37096,30921,40879 +57477,37097,30920,40984 +56709,37098,30919,40943 +59168,37099,30918,40520 +56164,37100,30917,40109 +58351,37101,30916,40129 +54661,37102,30915,40977 +55592,37103,30914,40315 +58381,37104,30913,40158 +51193,37105,30912,40584 +55156,37106,30911,40327 +50986,37107,30910,40828 +57162,37108,30909,40157 +58926,37109,30908,40291 +52599,37110,30907,40599 +53192,37111,30906,40719 +59984,37112,30905,40895 +50347,37113,30904,40588 +59302,37114,30903,40845 +52313,37115,30902,40939 +55768,37116,30901,40810 +57181,37117,30900,40367 +53880,37118,30899,40147 +54452,37119,30898,40543 +53915,37120,30897,40680 +57797,37121,30896,40816 +56682,37122,30895,40184 +53522,37123,30894,40575 +50470,37124,30893,40835 +55734,37125,30892,40512 +58953,37126,30891,40412 +54814,37127,30890,40798 +58855,37128,30889,40096 +50213,37129,30888,40887 +55154,37130,30887,40423 +55560,37131,30886,40938 +56125,37132,30885,40574 +52840,37133,30884,40720 +59352,37134,30883,40831 +50013,37135,30882,40421 +56299,37136,30881,40878 +53143,37137,30880,40985 +50206,37138,30879,40704 +52160,37139,30878,40911 +54469,37140,30877,40802 +55566,37141,30876,40730 +56073,37142,30875,40771 +52052,37143,30874,40919 +59280,37144,30873,40279 +53496,37145,30872,40699 +54287,37146,30871,40313 +55007,37147,30870,40689 +56918,37148,30869,40453 +50485,37149,30868,40856 +55001,37150,30867,40767 +50665,37151,30866,40199 +54335,37152,30865,40747 +55332,37153,30864,40494 +52276,37154,30863,40690 +50154,37155,30862,40603 +57049,37156,30861,40245 +57817,37157,30860,40005 +52539,37158,30859,40970 +57631,37159,30858,40152 +51585,37160,30857,40888 +55352,37161,30856,40493 +58959,37162,30855,40208 +50420,37163,30854,40461 +57031,37164,30853,40066 +54391,37165,30852,40859 +56351,37166,30851,40017 +58058,37167,30850,40835 +57245,37168,30849,40708 +59328,37169,30848,40251 +51615,37170,30847,40306 +52259,37171,30846,40652 +51000,37172,30845,40241 +54140,37173,30844,40508 +52661,37174,30843,40795 +57585,37175,30842,40716 +54061,37176,30841,40534 +58632,37177,30840,40689 +57302,37178,30839,40239 +56218,37179,30838,40394 +53237,37180,30837,40570 +55891,37181,30836,40044 +59581,37182,30835,40440 +56006,37183,30834,40989 +51465,37184,30833,40117 +50877,37185,30832,40147 +58004,37186,30831,40476 +53198,37187,30830,40768 +58661,37188,30829,40122 +56426,37189,30828,40845 +54985,37190,30827,40732 +56367,37191,30826,40776 +51705,37192,30825,40614 +52813,37193,30824,40227 +59386,37194,30823,40562 +52869,37195,30822,40298 +57218,37196,30821,40984 +53084,37197,30820,40729 +59544,37198,30819,40840 +54416,37199,30818,40480 +57589,37200,30817,40025 +55906,37201,30816,40572 +51927,37202,30815,40989 +50145,37203,30814,40170 +54069,37204,30813,40171 +58295,37205,30812,40531 +57852,37206,30811,40088 +55885,37207,30810,40783 +56007,37208,30809,40420 +50122,37209,30808,40783 +51181,37210,30807,40669 +54152,37211,30806,40035 +50997,37212,30805,40722 +57799,37213,30804,40980 +51956,37214,30803,40525 +51723,37215,30802,40744 +55767,37216,30801,40109 +54369,37217,30800,40792 +50204,37218,30799,40775 +53871,37219,30798,40367 +53466,37220,30797,40433 +52041,37221,30796,40609 +52866,37222,30795,40212 +56911,37223,30794,40493 +54925,37224,30793,40291 +55412,37225,30792,40657 +54740,37226,30791,40732 +59417,37227,30790,40265 +55279,37228,30789,40601 +58920,37229,30788,40563 +52661,37230,30787,40347 +59661,37231,30786,40506 +54882,37232,30785,40197 +59582,37233,30784,40444 +58743,37234,30783,40176 +54860,37235,30782,40554 +53307,37236,30781,40160 +59201,37237,30780,40244 +58110,37238,30779,40930 +58073,37239,30778,40999 +51326,37240,30777,40560 +53102,37241,30776,40901 +50739,37242,30775,40787 +59003,37243,30774,40015 +55270,37244,30773,40532 +50130,37245,30772,40456 +57551,37246,30771,40231 +56649,37247,30770,40689 +51002,37248,30769,40444 +56606,37249,30768,40060 +54107,37250,30767,40803 +55260,37251,30766,40352 +56617,37252,30765,40003 +54710,37253,30764,40225 +59286,37254,30763,40560 +52624,37255,30762,40376 +56079,37256,30761,40591 +50573,37257,30760,40118 +59934,37258,30759,40246 +59122,37259,30758,40625 +50349,37260,30757,40973 +50505,37261,30756,40440 +50373,37262,30755,40235 +51506,37263,30754,40489 +53396,37264,30753,40279 +51509,37265,30752,40053 +50189,37266,30751,40796 +57683,37267,30750,40868 +56857,37268,30749,40439 +51018,37269,30748,40666 +54236,37270,30747,40304 +55622,37271,30746,40053 +57731,37272,30745,40907 +58756,37273,30744,40210 +56985,37274,30743,40842 +58146,37275,30742,40915 +50264,37276,30741,40769 +52227,37277,30740,40088 +59436,37278,30739,40981 +54974,37279,30738,40559 +54275,37280,30737,40994 +51446,37281,30736,40569 +58417,37282,30735,40031 +55253,37283,30734,40562 +50144,37284,30733,40528 +54977,37285,30732,40812 +52693,37286,30731,40520 +52416,37287,30730,40033 +50606,37288,30729,40881 +50936,37289,30728,40491 +55079,37290,30727,40714 +53295,37291,30726,40027 +51547,37292,30725,40707 +51953,37293,30724,40170 +51256,37294,30723,40032 +52496,37295,30722,40774 +51515,37296,30721,40344 +55750,37297,30720,40324 +52123,37298,30719,40721 +50389,37299,30718,40439 +54018,37300,30717,40369 +54576,37301,30716,40499 +51173,37302,30715,40427 +53075,37303,30714,40657 +58548,37304,30713,40229 +54156,37305,30712,40943 +51981,37306,30711,40522 +58605,37307,30710,40778 +53275,37308,30709,40504 +58505,37309,30708,40123 +59452,37310,30707,40752 +52924,37311,30706,40987 +55233,37312,30705,40854 +53240,37313,30704,40196 +52558,37314,30703,40964 +57545,37315,30702,40518 +53761,37316,30701,40079 +57610,37317,30700,40251 +59439,37318,30699,40165 +58929,37319,30698,40104 +56954,37320,30697,40346 +52485,37321,30696,40000 +59583,37322,30695,40646 +59776,37323,30694,40110 +51979,37324,30693,40756 +51503,37325,30692,40094 +53422,37326,30691,40121 +50374,37327,30690,40545 +55448,37328,30689,40535 +58656,37329,30688,40140 +50015,37330,30687,40582 +55493,37331,30686,40452 +51491,37332,30685,40870 +59268,37333,30684,40392 +52248,37334,30683,40115 +58847,37335,30682,40730 +58819,37336,30681,40045 +52070,37337,30680,40067 +54880,37338,30679,40466 +57596,37339,30678,40282 +51440,37340,30677,40427 +59830,37341,30676,40233 +51184,37342,30675,40264 +50114,37343,30674,40149 +54420,37344,30673,40440 +50852,37345,30672,40576 +54834,37346,30671,40474 +57339,37347,30670,40420 +52923,37348,30669,40353 +58002,37349,30668,40901 +59829,37350,30667,40615 +51138,37351,30666,40020 +58947,37352,30665,40313 +57924,37353,30664,40868 +50806,37354,30663,40435 +57173,37355,30662,40323 +57164,37356,30661,40952 +57539,37357,30660,40503 +53895,37358,30659,40159 +51252,37359,30658,40994 +52089,37360,30657,40445 +55509,37361,30656,40099 +55275,37362,30655,40684 +57264,37363,30654,40114 +55965,37364,30653,40245 +51255,37365,30652,40880 +59047,37366,30651,40487 +58828,37367,30650,40089 +52174,37368,30649,40995 +55331,37369,30648,40927 +58611,37370,30647,40467 +54111,37371,30646,40604 +55621,37372,30645,40119 +54041,37373,30644,40203 +54663,37374,30643,40140 +55344,37375,30642,40916 +52412,37376,30641,40274 +54218,37377,30640,40250 +53390,37378,30639,40104 +54168,37379,30638,40059 +57806,37380,30637,40942 +55831,37381,30636,40700 +56149,37382,30635,40950 +53411,37383,30634,40029 +54473,37384,30633,40735 +54742,37385,30632,40536 +51740,37386,30631,40240 +50014,37387,30630,40002 +52750,37388,30629,40326 +52685,37389,30628,40667 +56067,37390,30627,40274 +53562,37391,30626,40160 +59152,37392,30625,40882 +57124,37393,30624,40314 +56126,37394,30623,40938 +55559,37395,30622,40610 +58544,37396,30621,40495 +54471,37397,30620,40820 +52881,37398,30619,40104 +53593,37399,30618,40397 +50519,37400,30617,40601 +53058,37401,30616,40147 +56789,37402,30615,40397 +59526,37403,30614,40367 +59932,37404,30613,40199 +59154,37405,30612,40953 +59408,37406,30611,40165 +58838,37407,30610,40977 +55401,37408,30609,40898 +51946,37409,30608,40637 +50656,37410,30607,40990 +51185,37411,30606,40052 +52250,37412,30605,40813 +55179,37413,30604,40997 +50545,37414,30603,40457 +50884,37415,30602,40781 +56157,37416,30601,40100 +50410,37417,30600,40603 +54193,37418,30599,40958 +55756,37419,30598,40770 +54770,37420,30597,40767 +51645,37421,30596,40019 +55363,37422,30595,40953 +59400,37423,30594,40739 +53371,37424,30593,40365 +52910,37425,30592,40056 +51288,37426,30591,40417 +55962,37427,30590,40612 +50093,37428,30589,40315 +58774,37429,30588,40452 +59191,37430,30587,40253 +58294,37431,30586,40383 +56381,37432,30585,40101 +51314,37433,30584,40446 +56821,37434,30583,40047 +55474,37435,30582,40677 +57444,37436,30581,40769 +55714,37437,30580,40643 +56365,37438,30579,40435 +58100,37439,30578,40515 +53451,37440,30577,40249 +50644,37441,30576,40711 +59786,37442,30575,40174 +58055,37443,30574,40278 +54559,37444,30573,40702 +54477,37445,30572,40131 +53927,37446,30571,40960 +50341,37447,30570,40170 +59981,37448,30569,40383 +59567,37449,30568,40462 +56534,37450,30567,40172 +58109,37451,30566,40684 +57286,37452,30565,40922 +56179,37453,30564,40070 +56757,37454,30563,40661 +59486,37455,30562,40285 +54348,37456,30561,40183 +52001,37457,30560,40614 +55385,37458,30559,40001 +51786,37459,30558,40591 +57491,37460,30557,40234 +57363,37461,30556,40063 +59079,37462,30555,40151 +56292,37463,30554,40727 +59824,37464,30553,40095 +52101,37465,30552,40257 +54053,37466,30551,40770 +53569,37467,30550,40947 +52349,37468,30549,40086 +52759,37469,30548,40872 +56414,37470,30547,40733 +56442,37471,30546,40564 +56146,37472,30545,40694 +54344,37473,30544,40497 +59162,37474,30543,40806 +53816,37475,30542,40826 +56509,37476,30541,40123 +55740,37477,30540,40492 +50265,37478,30539,40949 +56470,37479,30538,40100 +54139,37480,30537,40137 +54695,37481,30536,40713 +57753,37482,30535,40947 +57635,37483,30534,40807 +55420,37484,30533,40328 +53824,37485,30532,40357 +52267,37486,30531,40070 +53501,37487,30530,40540 +50930,37488,30529,40008 +50846,37489,30528,40172 +53506,37490,30527,40105 +56038,37491,30526,40508 +52561,37492,30525,40140 +56750,37493,30524,40526 +52706,37494,30523,40814 +54513,37495,30522,40637 +51808,37496,30521,40153 +55834,37497,30520,40475 +53044,37498,30519,40549 +55109,37499,30518,40412 +57623,37500,30517,40485 +56466,37501,30516,40961 +50481,37502,30515,40748 +51609,37503,30514,40801 +53487,37504,30513,40930 +58359,37505,30512,40466 +51474,37506,30511,40638 +58902,37507,30510,40368 +53140,37508,30509,40282 +50938,37509,30508,40568 +59078,37510,30507,40134 +53624,37511,30506,40804 +50421,37512,30505,40266 +59585,37513,30504,40731 +56092,37514,30503,40715 +56076,37515,30502,40940 +58466,37516,30501,40377 +56578,37517,30500,40591 +58404,37518,30499,40739 +56867,37519,30498,40576 +55933,37520,30497,40719 +50758,37521,30496,40433 +55729,37522,30495,40858 +57949,37523,30494,40115 +53801,37524,30493,40888 +51415,37525,30492,40080 +51833,37526,30491,40081 +59727,37527,30490,40616 +57390,37528,30489,40032 +58513,37529,30488,40605 +50835,37530,30487,40465 +52621,37531,30486,40421 +53474,37532,30485,40519 +58884,37533,30484,40733 +55287,37534,30483,40735 +52479,37535,30482,40325 +50656,37536,30481,40084 +59584,37537,30480,40315 +54641,37538,30479,40888 +56176,37539,30478,40927 +58181,37540,30477,40803 +53863,37541,30476,40897 +57902,37542,30475,40699 +59434,37543,30474,40130 +59357,37544,30473,40585 +57374,37545,30472,40501 +55869,37546,30471,40428 +53242,37547,30470,40259 +56506,37548,30469,40436 +57803,37549,30468,40077 +53727,37550,30467,40820 +53858,37551,30466,40490 +58941,37552,30465,40957 +59080,37553,30464,40790 +52567,37554,30463,40652 +57713,37555,30462,40947 +55370,37556,30461,40007 +59246,37557,30460,40454 +50443,37558,30459,40961 +58556,37559,30458,40568 +57256,37560,30457,40063 +52379,37561,30456,40871 +53696,37562,30455,40534 +56793,37563,30454,40481 +53182,37564,30453,40467 +52044,37565,30452,40805 +50817,37566,30451,40559 +59518,37567,30450,40438 +50743,37568,30449,40549 +50418,37569,30448,40836 +55415,37570,30447,40826 +57478,37571,30446,40728 +53902,37572,30445,40287 +59265,37573,30444,40812 +51202,37574,30443,40574 +52859,37575,30442,40390 +55314,37576,30441,40887 +50300,37577,30440,40711 +54286,37578,30439,40325 +59516,37579,30438,40275 +59939,37580,30437,40882 +57194,37581,30436,40391 +58126,37582,30435,40267 +52552,37583,30434,40770 +57314,37584,30433,40361 +51268,37585,30432,40362 +58613,37586,30431,40902 +50241,37587,30430,40861 +54165,37588,30429,40721 +51667,37589,30428,40120 +58167,37590,30427,40829 +57338,37591,30426,40390 +50992,37592,30425,40836 +51254,37593,30424,40649 +59388,37594,30423,40107 +50793,37595,30422,40078 +57020,37596,30421,40243 +56634,37597,30420,40656 +59645,37598,30419,40772 +53301,37599,30418,40132 +51331,37600,30417,40317 +52655,37601,30416,40164 +52133,37602,30415,40948 +51080,37603,30414,40787 +57297,37604,30413,40150 +53849,37605,30412,40340 +54656,37606,30411,40372 +56925,37607,30410,40767 +59812,37608,30409,40507 +50508,37609,30408,40760 +59134,37610,30407,40374 +56450,37611,30406,40005 +54269,37612,30405,40450 +50447,37613,30404,40565 +50305,37614,30403,40414 +59767,37615,30402,40872 +52701,37616,30401,40653 +58474,37617,30400,40286 +56154,37618,30399,40609 +54429,37619,30398,40904 +58872,37620,30397,40645 +53607,37621,30396,40533 +54623,37622,30395,40598 +59368,37623,30394,40546 +57604,37624,30393,40872 +50323,37625,30392,40106 +58568,37626,30391,40833 +55373,37627,30390,40485 +53562,37628,30389,40724 +57118,37629,30388,40744 +55293,37630,30387,40885 +54900,37631,30386,40409 +52692,37632,30385,40116 +56870,37633,30384,40828 +56489,37634,30383,40447 +50870,37635,30382,40287 +58237,37636,30381,40952 +58992,37637,30380,40471 +50361,37638,30379,40088 +52239,37639,30378,40637 +53860,37640,30377,40622 +58927,37641,30376,40625 +51069,37642,30375,40697 +58269,37643,30374,40641 +59576,37644,30373,40389 +57002,37645,30372,40350 +59830,37646,30371,40661 +59598,37647,30370,40355 +51980,37648,30369,40454 +55098,37649,30368,40690 +53350,37650,30367,40348 +56982,37651,30366,40621 +57108,37652,30365,40580 +58152,37653,30364,40918 +55474,37654,30363,40796 +58470,37655,30362,40188 +59798,37656,30361,40026 +55059,37657,30360,40642 +57923,37658,30359,40528 +55013,37659,30358,40470 +57194,37660,30357,40897 +59400,37661,30356,40283 +54320,37662,30355,40627 +51771,37663,30354,40987 +53370,37664,30353,40033 +51783,37665,30352,40468 +54468,37666,30351,40907 +51168,37667,30350,40997 +51122,37668,30349,40524 +54501,37669,30348,40414 +53886,37670,30347,40152 +59665,37671,30346,40266 +53088,37672,30345,40696 +52356,37673,30344,40506 +53148,37674,30343,40939 +52523,37675,30342,40654 +52660,37676,30341,40579 +55995,37677,30340,40170 +59150,37678,30339,40178 +54766,37679,30338,40580 +52897,37680,30337,40383 +52660,37681,30336,40398 +56969,37682,30335,40416 +52554,37683,30334,40508 +58874,37684,30333,40973 +52936,37685,30332,40091 +53185,37686,30331,40855 +56180,37687,30330,40907 +55381,37688,30329,40035 +51061,37689,30328,40819 +56108,37690,30327,40015 +50258,37691,30326,40216 +59483,37692,30325,40304 +52360,37693,30324,40705 +57446,37694,30323,40629 +52666,37695,30322,40338 +56677,37696,30321,40532 +54531,37697,30320,40523 +50887,37698,30319,40247 +53143,37699,30318,40469 +54736,37700,30317,40011 +59511,37701,30316,40160 +58590,37702,30315,40061 +54851,37703,30314,40484 +52858,37704,30313,40544 +58762,37705,30312,40402 +58569,37706,30311,40527 +59774,37707,30310,40997 +56450,37708,30309,40027 +57714,37709,30308,40211 +52058,37710,30307,40106 +59685,37711,30306,40130 +55067,37712,30305,40158 +56472,37713,30304,40841 +55091,37714,30303,40885 +54811,37715,30302,40732 +57400,37716,30301,40945 +55670,37717,30300,40547 +57610,37718,30299,40310 +59027,37719,30298,40624 +55121,37720,30297,40803 +56569,37721,30296,40323 +57765,37722,30295,40471 +59330,37723,30294,40619 +53917,37724,30293,40658 +50990,37725,30292,40507 +56991,37726,30291,40325 +50753,37727,30290,40335 +57158,37728,30289,40086 +59144,37729,30288,40258 +50257,37730,30287,40300 +50505,37731,30286,40334 +58551,37732,30285,40580 +52536,37733,30284,40910 +52617,37734,30283,40502 +53542,37735,30282,40267 +50624,37736,30281,40663 +52547,37737,30280,40233 +57446,37738,30279,40803 +56068,37739,30278,40566 +54912,37740,30277,40350 +50432,37741,30276,40303 +59288,37742,30275,40504 +59988,37743,30274,40982 +50010,37744,30273,40459 +55927,37745,30272,40475 +57076,37746,30271,40274 +56631,37747,30270,40118 +52672,37748,30269,40576 +51410,37749,30268,40983 +58574,37750,30267,40377 +58353,37751,30266,40922 +56922,37752,30265,40361 +55071,37753,30264,40314 +55870,37754,30263,40439 +54183,37755,30262,40329 +55456,37756,30261,40822 +50571,37757,30260,40881 +55355,37758,30259,40344 +50353,37759,30258,40754 +54315,37760,30257,40535 +54056,37761,30256,40032 +54098,37762,30255,40466 +53288,37763,30254,40568 +59816,37764,30253,40288 +54311,37765,30252,40352 +56927,37766,30251,40508 +51576,37767,30250,40000 +59220,37768,30249,40709 +58014,37769,30248,40113 +56369,37770,30247,40216 +56207,37771,30246,40688 +50640,37772,30245,40444 +51795,37773,30244,40078 +57866,37774,30243,40962 +58364,37775,30242,40639 +53166,37776,30241,40919 +51103,37777,30240,40277 +59981,37778,30239,40432 +55696,37779,30238,40041 +53969,37780,30237,40753 +57212,37781,30236,40798 +55582,37782,30235,40274 +50368,37783,30234,40058 +52801,37784,30233,40038 +51399,37785,30232,40569 +57573,37786,30231,40353 +53808,37787,30230,40160 +51684,37788,30229,40005 +58110,37789,30228,40090 +56986,37790,30227,40945 +59176,37791,30226,40746 +57254,37792,30225,40135 +56049,37793,30224,40558 +59978,37794,30223,40632 +56179,37795,30222,40373 +54385,37796,30221,40207 +50484,37797,30220,40373 +59520,37798,30219,40814 +56619,37799,30218,40115 +59285,37800,30217,40465 +52812,37801,30216,40064 +57948,37802,30215,40877 +52638,37803,30214,40764 +56993,37804,30213,40900 +56669,37805,30212,40681 +54063,37806,30211,40369 +50363,37807,30210,40647 +56695,37808,30209,40802 +51234,37809,30208,40279 +56700,37810,30207,40439 +58277,37811,30206,40887 +53451,37812,30205,40637 +51220,37813,30204,40441 +56681,37814,30203,40558 +55086,37815,30202,40824 +57588,37816,30201,40537 +57105,37817,30200,40352 +56491,37818,30199,40666 +53997,37819,30198,40368 +52297,37820,30197,40750 +59158,37821,30196,40871 +51389,37822,30195,40286 +56888,37823,30194,40168 +58469,37824,30193,40333 +57829,37825,30192,40884 +50649,37826,30191,40191 +57770,37827,30190,40963 +53876,37828,30189,40576 +52640,37829,30188,40166 +57996,37830,30187,40430 +51742,37831,30186,40531 +58835,37832,30185,40036 +53227,37833,30184,40582 +51254,37834,30183,40979 +56897,37835,30182,40465 +52099,37836,30181,40039 +59405,37837,30180,40856 +56327,37838,30179,40468 +56659,37839,30178,40787 +56837,37840,30177,40116 +51375,37841,30176,40593 +55027,37842,30175,40902 +58534,37843,30174,40173 +51470,37844,30173,40331 +55499,37845,30172,40792 +51886,37846,30171,40336 +59965,37847,30170,40675 +59493,37848,30169,40043 +52029,37849,30168,40086 +52256,37850,30167,40965 +51534,37851,30166,40890 +59376,37852,30165,40419 +54725,37853,30164,40392 +50562,37854,30163,40976 +54576,37855,30162,40876 +52074,37856,30161,40514 +53667,37857,30160,40233 +53967,37858,30159,40191 +55309,37859,30158,40218 +59135,37860,30157,40052 +51049,37861,30156,40299 +52899,37862,30155,40873 +55328,37863,30154,40826 +54814,37864,30153,40341 +59452,37865,30152,40828 +55887,37866,30151,40122 +53032,37867,30150,40960 +51878,37868,30149,40909 +52563,37869,30148,40426 +56418,37870,30147,40332 +54323,37871,30146,40718 +53128,37872,30145,40524 +51750,37873,30144,40122 +53153,37874,30143,40390 +59539,37875,30142,40134 +55499,37876,30141,40173 +56943,37877,30140,40922 +59279,37878,30139,40126 +51612,37879,30138,40772 +57922,37880,30137,40716 +56908,37881,30136,40996 +56389,37882,30135,40216 +59427,37883,30134,40086 +51399,37884,30133,40650 +57210,37885,30132,40420 +52891,37886,30131,40174 +58784,37887,30130,40989 +53060,37888,30129,40781 +54331,37889,30128,40518 +54796,37890,30127,40823 +57532,37891,30126,40948 +53812,37892,30125,40274 +51985,37893,30124,40515 +51158,37894,30123,40922 +53779,37895,30122,40197 +51782,37896,30121,40541 +55408,37897,30120,40714 +57895,37898,30119,40257 +54515,37899,30118,40697 +59514,37900,30117,40141 +57359,37901,30116,40505 +57809,37902,30115,40505 +52667,37903,30114,40102 +51233,37904,30113,40578 +55303,37905,30112,40707 +53254,37906,30111,40254 +50748,37907,30110,40608 +56448,37908,30109,40632 +50994,37909,30108,40416 +57547,37910,30107,40889 +50299,37911,30106,40690 +54109,37912,30105,40620 +56764,37913,30104,40658 +56377,37914,30103,40643 +50220,37915,30102,40804 +57232,37916,30101,40907 +50901,37917,30100,40868 +53351,37918,30099,40721 +50104,37919,30098,40196 +57347,37920,30097,40231 +58205,37921,30096,40243 +59457,37922,30095,40751 +57592,37923,30094,40414 +53298,37924,30093,40755 +53238,37925,30092,40518 +59492,37926,30091,40615 +50535,37927,30090,40759 +53404,37928,30089,40596 +59478,37929,30088,40624 +52958,37930,30087,40545 +58547,37931,30086,40931 +53007,37932,30085,40128 +55153,37933,30084,40906 +54994,37934,30083,40298 +53643,37935,30082,40420 +50335,37936,30081,40160 +58866,37937,30080,40715 +54226,37938,30079,40831 +51794,37939,30078,40611 +58479,37940,30077,40319 +55314,37941,30076,40194 +59315,37942,30075,40664 +59850,37943,30074,40526 +51573,37944,30073,40098 +55343,37945,30072,40759 +56204,37946,30071,40919 +53866,37947,30070,40707 +55482,37948,30069,40991 +57975,37949,30068,40375 +55574,37950,30067,40952 +58088,37951,30066,40249 +51927,37952,30065,40968 +55209,37953,30064,40191 +58508,37954,30063,40425 +52303,37955,30062,40187 +58233,37956,30061,40215 +53258,37957,30060,40950 +54140,37958,30059,40585 +55066,37959,30058,40325 +54846,37960,30057,40273 +56157,37961,30056,40157 +55893,37962,30055,40418 +52086,37963,30054,40799 +59173,37964,30053,40645 +53370,37965,30052,40775 +57366,37966,30051,40352 +52211,37967,30050,40519 +53201,37968,30049,40532 +59831,37969,30048,40659 +58037,37970,30047,40553 +59891,37971,30046,40945 +59846,37972,30045,40112 +54385,37973,30044,40767 +59157,37974,30043,40180 +58569,37975,30042,40432 +59514,37976,30041,40174 +57620,37977,30040,40884 +58478,37978,30039,40860 +57451,37979,30038,40755 +51253,37980,30037,40590 +52574,37981,30036,40678 +52936,37982,30035,40708 +54369,37983,30034,40851 +54033,37984,30033,40439 +51632,37985,30032,40619 +57615,37986,30031,40931 +55955,37987,30030,40025 +57162,37988,30029,40589 +51196,37989,30028,40753 +53392,37990,30027,40831 +54669,37991,30026,40586 +54206,37992,30025,40829 +51319,37993,30024,40898 +56602,37994,30023,40315 +54334,37995,30022,40724 +51261,37996,30021,40965 +55976,37997,30020,40880 +59406,37998,30019,40570 +59508,37999,30018,40896 +59993,38000,30017,40902 +52791,38001,30016,40315 +54287,38002,30015,40155 +56401,38003,30014,40936 +54535,38004,30013,40451 +55006,38005,30012,40184 +59698,38006,30011,40613 +56361,38007,30010,40711 +51452,38008,30009,40809 +50523,38009,30008,40745 +57727,38010,30007,40386 +55841,38011,30006,40006 +51921,38012,30005,40911 +52283,38013,30004,40073 +58797,38014,30003,40085 +53041,38015,30002,40515 +53103,38016,30001,40093 +55872,38017,30000,40358 +53913,38018,31000,40837 +56786,38019,30999,40553 +53619,38020,30998,40598 +55164,38021,30997,40511 +52783,38022,30996,40578 +51633,38023,30995,40716 +50378,38024,30994,40192 +52035,38025,30993,40630 +50463,38026,30992,40869 +58233,38027,30991,40555 +56534,38028,30990,40896 +56765,38029,30989,40061 +59081,38030,30988,40393 +57740,38031,30987,40887 +59206,38032,30986,40767 +59792,38033,30985,40458 +57441,38034,30984,40078 +53355,38035,30983,40576 +58577,38036,30982,40722 +52713,38037,30981,40404 +53211,38038,30980,40370 +56536,38039,30979,40308 +56796,38040,30978,40715 +52804,38041,30977,40437 +59887,38042,30976,40096 +51339,38043,30975,40378 +53822,38044,30974,40875 +57679,38045,30973,40960 +50357,38046,30972,40803 +50202,38047,30971,40088 +58131,38048,30970,40426 +50507,38049,30969,40129 +56938,38050,30968,40057 +54510,38051,30967,40490 +53317,38052,30966,40282 +59514,38053,30965,40106 +52153,38054,30964,40226 +50500,38055,30963,40668 +57252,38056,30962,40169 +53665,38057,30961,40410 +59747,38058,30960,40815 +56537,38059,30959,40796 +59359,38060,30958,40069 +55303,38061,30957,40997 +51751,38062,30956,40613 +59645,38063,30955,40363 +53305,38064,30954,40887 +55156,38065,30953,40865 +53209,38066,30952,40794 +57249,38067,30951,40442 +56212,38068,30950,40883 +55459,38069,30949,40828 +55887,38070,30948,40732 +56648,38071,30947,40543 +58600,38072,30946,40492 +53935,38073,30945,40497 +57294,38074,30944,40055 +59801,38075,30943,40223 +57149,38076,30942,40570 +54681,38077,30941,40834 +57073,38078,30940,40133 +56970,38079,30939,40971 +56860,38080,30938,40813 +50800,38081,30937,40228 +54930,38082,30936,40381 +54022,38083,30935,40981 +54945,38084,30934,40632 +53975,38085,30933,40168 +52671,38086,30932,40030 +57064,38087,30931,40665 +55163,38088,30930,40105 +55154,38089,30929,40181 +59477,38090,30928,40410 +58781,38091,30927,40326 +59674,38092,30926,40917 +55560,38093,30925,40889 +52152,38094,30924,40526 +58038,38095,30923,40101 +57840,38096,30922,40694 +55794,38097,30921,40871 +57609,38098,30920,40382 +52803,38099,30919,40654 +54384,38100,30918,40030 +55498,38101,30917,40440 +52205,38102,30916,40995 +57528,38103,30915,40775 +55074,38104,30914,40675 +59325,38105,30913,40092 +50941,38106,30912,40190 +55771,38107,30911,40862 +59868,38108,30910,40155 +59577,38109,30909,40191 +59040,38110,30908,40203 +58147,38111,30907,40876 +55897,38112,30906,40438 +50351,38113,30905,40662 +54881,38114,30904,40113 +57450,38115,30903,40410 +50934,38116,30902,40009 +52881,38117,30901,40857 +54767,38118,30900,40231 +58268,38119,30899,40316 +56911,38120,30898,40559 +57940,38121,30897,40561 +52439,38122,30896,40758 +57413,38123,30895,40162 +55190,38124,30894,40263 +52863,38125,30893,40288 +52828,38126,30892,40811 +59799,38127,30891,40244 +52556,38128,30890,40667 +53258,38129,30889,40845 +58816,38130,30888,40683 +50465,38131,30887,40619 +51670,38132,30886,40740 +57599,38133,30885,40215 +51031,38134,30884,40454 +55000,38135,30883,40501 +53752,38136,30882,40937 +53868,38137,30881,40143 +51882,38138,30880,40254 +59473,38139,30879,40735 +59981,38140,30878,40551 +53199,38141,30877,40512 +59937,38142,30876,40695 +55300,38143,30875,40626 +55388,38144,30874,40655 +52376,38145,30873,40608 +54312,38146,30872,40318 +56986,38147,30871,40552 +52788,38148,30870,40652 +52361,38149,30869,40958 +55226,38150,30868,40148 +53152,38151,30867,40933 +51985,38152,30866,40844 +58489,38153,30865,40979 +54153,38154,30864,40402 +51058,38155,30863,40536 +56275,38156,30862,40292 +54348,38157,30861,40067 +52531,38158,30860,40620 +51712,38159,30859,40961 +52334,38160,30858,40751 +58588,38161,30857,40275 +53453,38162,30856,40344 +58347,38163,30855,40819 +50004,38164,30854,40213 +51811,38165,30853,40386 +59916,38166,30852,40613 +58040,38167,30851,40009 +58476,38168,30850,40605 +55342,38169,30849,40338 +53431,38170,30848,40398 +54715,38171,30847,40466 +55726,38172,30846,40925 +56827,38173,30845,40581 +54534,38174,30844,40615 +57117,38175,30843,40926 +59060,38176,30842,40678 +53531,38177,30841,40426 +51253,38178,30840,40500 +58759,38179,30839,40160 +51915,38180,30838,40867 +58688,38181,30837,40015 +51409,38182,30836,40302 +55396,38183,30835,40819 +59807,38184,30834,40584 +56319,38185,30833,40646 +57001,38186,30832,40535 +58818,38187,30831,40239 +59858,38188,30830,40668 +54911,38189,30829,40666 +58238,38190,30828,40170 +58161,38191,30827,40380 +54580,38192,30826,40905 +57128,38193,30825,40065 +51219,38194,30824,40262 +50610,38195,30823,40371 +51788,38196,30822,40793 +55381,38197,30821,40729 +51260,38198,30820,40642 +59608,38199,30819,40538 +57149,38200,30818,40856 +55186,38201,30817,40540 +54387,38202,30816,40608 +59466,38203,30815,40078 +52369,38204,30814,40038 +55485,38205,30813,40942 +53454,38206,30812,40875 +50798,38207,30811,40743 +58962,38208,30810,40068 +57016,38209,30809,40291 +53386,38210,30808,40210 +53839,38211,30807,40753 +58539,38212,30806,40115 +55525,38213,30805,40251 +58403,38214,30804,40573 +58792,38215,30803,40063 +59435,38216,30802,40610 +51064,38217,30801,40808 +59736,38218,30800,40060 +54551,38219,30799,40880 +54369,38220,30798,40863 +58665,38221,30797,40532 +56315,38222,30796,40821 +54202,38223,30795,40956 +54832,38224,30794,40402 +54255,38225,30793,40150 +59343,38226,30792,40637 +50276,38227,30791,40405 +50732,38228,30790,40935 +52757,38229,30789,40947 +53848,38230,30788,40219 +52040,38231,30787,40872 +56891,38232,30786,40298 +53719,38233,30785,40814 +57646,38234,30784,40801 +50172,38235,30783,40643 +57061,38236,30782,40074 +55670,38237,30781,40858 +55209,38238,30780,40540 +52344,38239,30779,40606 +53684,38240,30778,40768 +57279,38241,30777,40388 +57957,38242,30776,40201 +55700,38243,30775,40212 +57060,38244,30774,40567 +58568,38245,30773,40347 +54128,38246,30772,40792 +50796,38247,30771,40057 +50979,38248,30770,40459 +59619,38249,30769,40650 +57895,38250,30768,40627 +56511,38251,30767,40347 +53713,38252,30766,40452 +55768,38253,30765,40362 +59068,38254,30764,40733 +55083,38255,30763,40402 +51377,38256,30762,40849 +55663,38257,30761,40210 +50802,38258,30760,40644 +57683,38259,30759,40689 +53494,38260,30758,40495 +51091,38261,30757,40193 +51774,38262,30756,40353 +53353,38263,30755,40213 +52806,38264,30754,40930 +55455,38265,30753,40119 +57016,38266,30752,40796 +53219,38267,30751,40267 +57322,38268,30750,40400 +55876,38269,30749,40130 +55495,38270,30748,40282 +58825,38271,30747,40459 +59387,38272,30746,40243 +54945,38273,30745,40660 +50040,38274,30744,40321 +54933,38275,30743,40801 +52326,38276,30742,40125 +55561,38277,30741,40423 +54664,38278,30740,40136 +54289,38279,30739,40056 +57129,38280,30738,40442 +51376,38281,30737,40915 +51604,38282,30736,40569 +57100,38283,30735,40295 +53907,38284,30734,40435 +51118,38285,30733,40844 +56784,38286,30732,40417 +58437,38287,30731,40822 +50791,38288,30730,40016 +51274,38289,30729,40870 +52492,38290,30728,40020 +57821,38291,30727,40879 +59641,38292,30726,40579 +57599,38293,30725,40570 +50512,38294,30724,40107 +53513,38295,30723,40295 +51183,38296,30722,40369 +51674,38297,30721,40457 +54001,38298,30720,40119 +57422,38299,30719,40260 +55968,38300,30718,40169 +53449,38301,30717,40229 +55641,38302,30716,40101 +56035,38303,30715,40374 +52680,38304,30714,40100 +51581,38305,30713,40532 +50626,38306,30712,40081 +54881,38307,30711,40047 +53986,38308,30710,40205 +55464,38309,30709,40990 +51179,38310,30708,40541 +52006,38311,30707,40229 +59100,38312,30706,40561 +58959,38313,30705,40388 +59585,38314,30704,40065 +53517,38315,30703,40437 +50758,38316,30702,40245 +51241,38317,30701,40481 +51638,38318,30700,40330 +54679,38319,30699,40759 +56274,38320,30698,40972 +53694,38321,30697,40586 +57022,38322,30696,40557 +56020,38323,30695,40326 +54165,38324,30694,40056 +59593,38325,30693,40423 +55772,38326,30692,40242 +59866,38327,30691,40550 +51972,38328,30690,40926 +54726,38329,30689,40033 +51033,38330,30688,40611 +54605,38331,30687,40710 +57768,38332,30686,40069 +50579,38333,30685,40348 +52781,38334,30684,40900 +54340,38335,30683,40046 +54282,38336,30682,40052 +57266,38337,30681,40132 +59411,38338,30680,40730 +52650,38339,30679,40719 +59174,38340,30678,40424 +50293,38341,30677,40465 +57081,38342,30676,40270 +55658,38343,30675,40687 +57276,38344,30674,40509 +59873,38345,30673,40397 +57837,38346,30672,40897 +55554,38347,30671,40092 +54682,38348,30670,40538 +53867,38349,30669,40922 +58737,38350,30668,40487 +51024,38351,30667,40566 +55011,38352,30666,40448 +56653,38353,30665,40910 +53655,38354,30664,40510 +51703,38355,30663,40095 +54682,38356,30662,40833 +58129,38357,30661,40184 +54228,38358,30660,40117 +56171,38359,30659,40884 +51111,38360,30658,40250 +59732,38361,30657,40642 +59137,38362,30656,40007 +59328,38363,30655,40018 +58896,38364,30654,40283 +58388,38365,30653,40358 +51893,38366,30652,40087 +57214,38367,30651,40979 +54673,38368,30650,40011 +58130,38369,30649,40891 +58364,38370,30648,40348 +54799,38371,30647,40641 +55988,38372,30646,40958 +52465,38373,30645,40592 +50418,38374,30644,40748 +53951,38375,30643,40767 +51689,38376,30642,40657 +56356,38377,30641,40709 +59112,38378,30640,40138 +56315,38379,30639,40413 +56559,38380,30638,40786 +59347,38381,30637,40142 +52782,38382,30636,40289 +56418,38383,30635,40274 +56440,38384,30634,40146 +53526,38385,30633,40313 +57334,38386,30632,40920 +51303,38387,30631,40057 +54952,38388,30630,40188 +59048,38389,30629,40316 +55959,38390,30628,40565 +53372,38391,30627,40118 +58342,38392,30626,40693 +51653,38393,30625,40650 +52039,38394,30624,40364 +52231,38395,30623,40992 +59066,38396,30622,40476 +54747,38397,30621,40333 +56975,38398,30620,40032 +53504,38399,30619,40695 +55933,38400,30618,40281 +54796,38401,30617,40946 +59979,38402,30616,40390 +50177,38403,30615,40548 +58811,38404,30614,40463 +59402,38405,30613,40778 +54615,38406,30612,40062 +56228,38407,30611,40829 +57187,38408,30610,40339 +59674,38409,30609,40861 +50722,38410,30608,40091 +52776,38411,30607,40112 +53429,38412,30606,40540 +55697,38413,30605,40006 +58238,38414,30604,40311 +51964,38415,30603,40788 +59683,38416,30602,40275 +59353,38417,30601,40924 +55101,38418,30600,40138 +54786,38419,30599,40973 +52016,38420,30598,40922 +50204,38421,30597,40100 +59701,38422,30596,40154 +52349,38423,30595,40247 +57843,38424,30594,40718 +56919,38425,30593,40089 +56605,38426,30592,40874 +50642,38427,30591,40320 +55508,38428,30590,40927 +58424,38429,30589,40327 +50317,38430,30588,40725 +57786,38431,30587,40199 +59214,38432,30586,40717 +59984,38433,30585,40153 +51729,38434,30584,40608 +56494,38435,30583,40969 +51851,38436,30582,40906 +53522,38437,30581,40400 +59990,38438,30580,40621 +57849,38439,30579,40712 +57627,38440,30578,40196 +56385,38441,30577,40932 +52187,38442,30576,40093 +52793,38443,30575,40452 +57116,38444,30574,40849 +55493,38445,30573,40274 +59585,38446,30572,40899 +59438,38447,30571,40580 +55394,38448,30570,40986 +56598,38449,30569,40822 +53291,38450,30568,40733 +59449,38451,30567,40763 +51536,38452,30566,40874 +57039,38453,30565,40048 +57118,38454,30564,40347 +57454,38455,30563,40997 +59629,38456,30562,40390 +56924,38457,30561,40993 +58770,38458,30560,40000 +51042,38459,30559,40081 +54224,38460,30558,40285 +59548,38461,30557,40780 +57262,38462,30556,40470 +52572,38463,30555,40374 +57460,38464,30554,40855 +54191,38465,30553,40367 +58847,38466,30552,40828 +58631,38467,30551,40367 +52644,38468,30550,40200 +54200,38469,30549,40257 +53617,38470,30548,40073 +55534,38471,30547,40417 +52735,38472,30546,40403 +51755,38473,30545,40403 +52980,38474,30544,40039 +51135,38475,30543,40506 +58101,38476,30542,40992 +58144,38477,30541,40689 +50600,38478,30540,40835 +57193,38479,30539,40353 +58663,38480,30538,40728 +51822,38481,30537,40304 +59424,38482,30536,40897 +50973,38483,30535,40818 +56762,38484,30534,40541 +53520,38485,30533,40455 +57171,38486,30532,40538 +51903,38487,30531,40961 +53764,38488,30530,40069 +50531,38489,30529,40248 +54854,38490,30528,40231 +56901,38491,30527,40043 +57549,38492,30526,40638 +59221,38493,30525,40421 +55538,38494,30524,40020 +58727,38495,30523,40506 +55647,38496,30522,40192 +57815,38497,30521,40693 +55188,38498,30520,40280 +52445,38499,30519,40087 +53766,38500,30518,40968 +52284,38501,30517,40110 +55367,38502,30516,40841 +52804,38503,30515,40680 +59665,38504,30514,40481 +58663,38505,30513,40698 +50235,38506,30512,40954 +59257,38507,30511,40321 +57726,38508,30510,40426 +52256,38509,30509,40460 +56434,38510,30508,40111 +57787,38511,30507,40324 +59985,38512,30506,40269 +51375,38513,30505,40354 +54877,38514,30504,40653 +57276,38515,30503,40691 +52045,38516,30502,40715 +50351,38517,30501,40162 +58562,38518,30500,40732 +59489,38519,30499,40394 +56424,38520,30498,40666 +55740,38521,30497,40350 +52025,38522,30496,40742 +50269,38523,30495,40056 +59115,38524,30494,40329 +50053,38525,30493,40842 +51850,38526,30492,40143 +51257,38527,30491,40908 +58032,38528,30490,40784 +55962,38529,30489,40178 +54192,38530,30488,40612 +56783,38531,30487,40673 +57218,38532,30486,40763 +58350,38533,30485,40903 +55000,38534,30484,40926 +51737,38535,30483,40828 +51679,38536,30482,40997 +58373,38537,30481,40568 +55618,38538,30480,40638 +58566,38539,30479,40650 +56729,38540,30478,40399 +54327,38541,30477,40819 +57422,38542,30476,40368 +50181,38543,30475,40357 +56336,38544,30474,40520 +52603,38545,30473,40027 +55760,38546,30472,40610 +59512,38547,30471,40990 +57273,38548,30470,40035 +58684,38549,30469,40408 +57693,38550,30468,40763 +54626,38551,30467,40001 +56746,38552,30466,40462 +54967,38553,30465,40196 +53323,38554,30464,40510 +55081,38555,30463,40462 +51355,38556,30462,40559 +55706,38557,30461,40578 +54788,38558,30460,40526 +59796,38559,30459,40331 +55621,38560,30458,40407 +57798,38561,30457,40183 +59683,38562,30456,40994 +57229,38563,30455,40397 +52550,38564,30454,40840 +51870,38565,30453,40771 +53684,38566,30452,40264 +51055,38567,30451,40534 +59643,38568,30450,40609 +53973,38569,30449,40462 +55672,38570,30448,40523 +55672,38571,30447,40997 +59141,38572,30446,40662 +53747,38573,30445,40733 +59342,38574,30444,40246 +57432,38575,30443,40307 +52084,38576,30442,40330 +57712,38577,30441,40100 +50251,38578,30440,40936 +57744,38579,30439,40130 +55918,38580,30438,40398 +57447,38581,30437,40178 +58466,38582,30436,40743 +53060,38583,30435,40022 +52008,38584,30434,40945 +51236,38585,30433,40954 +50764,38586,30432,40911 +58681,38587,30431,40725 +55931,38588,30430,40432 +53254,38589,30429,40214 +56897,38590,30428,40578 +51622,38591,30427,40944 +54432,38592,30426,40684 +55069,38593,30425,40772 +56893,38594,30424,40704 +59943,38595,30423,40994 +59428,38596,30422,40257 +59404,38597,30421,40203 +51147,38598,30420,40238 +59701,38599,30419,40493 +57124,38600,30418,40178 +53784,38601,30417,40084 +57805,38602,30416,40088 +57470,38603,30415,40818 +50881,38604,30414,40264 +56966,38605,30413,40939 +59985,38606,30412,40296 +51651,38607,30411,40447 +50125,38608,30410,40538 +52336,38609,30409,40684 +53996,38610,30408,40934 +52004,38611,30407,40816 +51292,38612,30406,40684 +50641,38613,30405,40584 +50179,38614,30404,40560 +53734,38615,30403,40248 +56308,38616,30402,40098 +50692,38617,30401,40736 +50429,38618,30400,40712 +55197,38619,30399,40262 +53068,38620,30398,40971 +51848,38621,30397,40582 +50354,38622,30396,40803 +53025,38623,30395,40387 +51952,38624,30394,40960 +51390,38625,30393,40032 +57790,38626,30392,40006 +51821,38627,30391,40368 +52043,38628,30390,40172 +55592,38629,30389,40814 +57134,38630,30388,40329 +57691,38631,30387,40002 +50058,38632,30386,40051 +56748,38633,30385,40641 +57057,38634,30384,40837 +57272,38635,30383,40392 +55487,38636,30382,40436 +59855,38637,30381,40124 +52999,38638,30380,40807 +59750,38639,30379,40632 +58268,38640,30378,40889 +55690,38641,30377,40996 +54677,38642,30376,40253 +54260,38643,30375,40671 +52771,38644,30374,40692 +56488,38645,30373,40977 +55503,38646,30372,40693 +53207,38647,30371,40416 +53916,38648,30370,40362 +57909,38649,30369,40237 +56444,38650,30368,40682 +57941,38651,30367,40297 +53807,38652,30366,40401 +53248,38653,30365,40041 +56262,38654,30364,40016 +52388,38655,30363,40571 +54517,38656,30362,40714 +52585,38657,30361,40052 +50278,38658,30360,40565 +54271,38659,30359,40856 +55386,38660,30358,40473 +59523,38661,30357,40685 +55787,38662,30356,40504 +55168,38663,30355,40869 +56382,38664,30354,40642 +55779,38665,30353,40766 +52020,38666,30352,40300 +52663,38667,30351,40551 +59935,38668,30350,40916 +53566,38669,30349,40137 +59937,38670,30348,40891 +55761,38671,30347,40495 +53007,38672,30346,40967 +50014,38673,30345,40444 +51941,38674,30344,40468 +52241,38675,30343,40080 +57524,38676,30342,40639 +50206,38677,30341,40566 +51142,38678,30340,40647 +52874,38679,30339,40917 +56130,38680,30338,40800 +57529,38681,30337,40289 +50603,38682,30336,40221 +54609,38683,30335,40518 +57507,38684,30334,40929 +55022,38685,30333,40560 +58508,38686,30332,40066 +52431,38687,30331,40097 +50191,38688,30330,40907 +55102,38689,30329,40176 +58998,38690,30328,40253 +56141,38691,30327,40754 +57843,38692,30326,40201 +58492,38693,30325,40608 +52708,38694,30324,40172 +50487,38695,30323,40053 +57518,38696,30322,40888 +53083,38697,30321,40402 +54374,38698,30320,40178 +58857,38699,30319,40320 +53135,38700,30318,40597 +50611,38701,30317,40754 +50509,38702,30316,40835 +52996,38703,30315,40844 +53272,38704,30314,40931 +51740,38705,30313,40923 +52028,38706,30312,40692 +55929,38707,30311,40347 +58557,38708,30310,40972 +58625,38709,30309,40647 +50344,38710,30308,40885 +58028,38711,30307,40552 +59157,38712,30306,40589 +56798,38713,30305,40621 +52761,38714,30304,40088 +55154,38715,30303,40700 +58631,38716,30302,40556 +51954,38717,30301,40058 +52182,38718,30300,40057 +54179,38719,30299,40693 +58782,38720,30298,40163 +54525,38721,30297,40579 +58108,38722,30296,40925 +58376,38723,30295,40462 +51990,38724,30294,40940 +57954,38725,30293,40359 +57384,38726,30292,40621 +52845,38727,30291,40811 +59836,38728,30290,40308 +55462,38729,30289,40902 +59335,38730,30288,40418 +52975,38731,30287,40227 +59936,38732,30286,40738 +56191,38733,30285,40894 +53629,38734,30284,40664 +51711,38735,30283,40622 +57782,38736,30282,40926 +50869,38737,30281,40786 +59530,38738,30280,40813 +53213,38739,30279,40471 +52736,38740,30278,40396 +51139,38741,30277,40099 +55382,38742,30276,40792 +51374,38743,30275,40825 +54677,38744,30274,40952 +52678,38745,30273,40641 +57686,38746,30272,40156 +54214,38747,30271,40003 +50669,38748,30270,40090 +50253,38749,30269,40776 +51955,38750,30268,40652 +55614,38751,30267,40102 +54787,38752,30266,40049 +54871,38753,30265,40926 +59450,38754,30264,40462 +56062,38755,30263,40075 +52657,38756,30262,40233 +54407,38757,30261,40305 +52070,38758,30260,40330 +55971,38759,30259,40511 +50662,38760,30258,40687 +58627,38761,30257,40922 +56072,38762,30256,40586 +50042,38763,30255,40768 +54147,38764,30254,40841 +53264,38765,30253,40030 +55023,38766,30252,40313 +50387,38767,30251,40838 +51561,38768,30250,40344 +56663,38769,30249,40201 +51008,38770,30248,40926 +58206,38771,30247,40781 +59836,38772,30246,40807 +57907,38773,30245,40035 +54590,38774,30244,40080 +53920,38775,30243,40520 +54018,38776,30242,40475 +56208,38777,30241,40669 +50930,38778,30240,40072 +50815,38779,30239,40605 +55556,38780,30238,40666 +51597,38781,30237,40386 +52324,38782,30236,40772 +56529,38783,30235,40997 +55580,38784,30234,40326 +55274,38785,30233,40008 +57967,38786,30232,40424 +57617,38787,30231,40705 +57669,38788,30230,40745 +50810,38789,30229,40262 +57936,38790,30228,40940 +52458,38791,30227,40896 +58862,38792,30226,40904 +51618,38793,30225,40158 +51863,38794,30224,40115 +58265,38795,30223,40486 +57062,38796,30222,40162 +51240,38797,30221,40169 +55509,38798,30220,40776 +56158,38799,30219,40404 +50529,38800,30218,40704 +56148,38801,30217,40703 +51404,38802,30216,40272 +51419,38803,30215,40772 +51441,38804,30214,40140 +57217,38805,30213,40526 +53970,38806,30212,40572 +54899,38807,30211,40116 +53245,38808,30210,40972 +50492,38809,30209,40840 +52909,38810,30208,40134 +57212,38811,30207,40224 +51309,38812,30206,40349 +55524,38813,30205,40480 +54167,38814,30204,40072 +59005,38815,30203,40689 +54299,38816,30202,40810 +56648,38817,30201,40170 +52635,38818,30200,40858 +58656,38819,30199,40418 +59619,38820,30198,40036 +59404,38821,30197,40631 +58470,38822,30196,40795 +59264,38823,30195,40079 +59027,38824,30194,40145 +52947,38825,30193,40064 +52454,38826,30192,40156 +52268,38827,30191,40966 +56907,38828,30190,40295 +59221,38829,30189,40441 +53134,38830,30188,40986 +51570,38831,30187,40535 +57134,38832,30186,40447 +52571,38833,30185,40029 +53952,38834,30184,40915 +50852,38835,30183,40974 +57231,38836,30182,40188 +51869,38837,30181,40133 +51456,38838,30180,40493 +52598,38839,30179,40541 +54692,38840,30178,40923 +54187,38841,30177,40571 +58487,38842,30176,40715 +55821,38843,30175,40988 +55974,38844,30174,40827 +57184,38845,30173,40321 +50461,38846,30172,40465 +50433,38847,30171,40923 +56334,38848,30170,40740 +53712,38849,30169,40588 +51006,38850,30168,40781 +59355,38851,30167,40148 +52073,38852,30166,40121 +54491,38853,30165,40260 +55558,38854,30164,40974 +56711,38855,30163,40331 +52933,38856,30162,40199 +59542,38857,30161,40715 +58036,38858,30160,40350 +55603,38859,30159,40791 +58241,38860,30158,40789 +59225,38861,30157,40955 +55162,38862,30156,40498 +57645,38863,30155,40008 +55824,38864,30154,40988 +53835,38865,30153,40491 +53002,38866,30152,40318 +59401,38867,30151,40016 +50294,38868,30150,40919 +51064,38869,30149,40344 +57642,38870,30148,40074 +57048,38871,30147,40468 +59289,38872,30146,40057 +51307,38873,30145,40933 +54641,38874,30144,40378 +56242,38875,30143,40378 +57088,38876,30142,40075 +59667,38877,30141,40045 +57367,38878,30140,40775 +52172,38879,30139,40411 +57559,38880,30138,40173 +54418,38881,30137,40109 +50072,38882,30136,40217 +56498,38883,30135,40575 +53049,38884,30134,40609 +57896,38885,30133,40981 +56609,38886,30132,40126 +58382,38887,30131,40605 +59204,38888,30130,40909 +54716,38889,30129,40341 +56369,38890,30128,40153 +57694,38891,30127,40658 +55928,38892,30126,40159 +53955,38893,30125,40106 +59209,38894,30124,40950 +57057,38895,30123,40847 +57799,38896,30122,40280 +59142,38897,30121,40688 +54812,38898,30120,40906 +54122,38899,30119,40565 +56998,38900,30118,40116 +58608,38901,30117,40334 +51871,38902,30116,40317 +59035,38903,30115,40241 +58026,38904,30114,40126 +55597,38905,30113,40647 +58217,38906,30112,40121 +57659,38907,30111,40266 +59212,38908,30110,40342 +57228,38909,30109,40589 +50820,38910,30108,40729 +55344,38911,30107,40040 +52645,38912,30106,40820 +52046,38913,30105,40710 +57226,38914,30104,40149 +53605,38915,30103,40629 +59522,38916,30102,40379 +54516,38917,30101,40185 +57864,38918,30100,40210 +53829,38919,30099,40741 +50240,38920,30098,40233 +59875,38921,30097,40071 +52349,38922,30096,40484 +56285,38923,30095,40807 +57312,38924,30094,40083 +58195,38925,30093,40716 +51643,38926,30092,40510 +59021,38927,30091,40403 +58308,38928,30090,40099 +53835,38929,30089,40949 +54901,38930,30088,40998 +59111,38931,30087,40915 +52368,38932,30086,40228 +50279,38933,30085,40936 +50191,38934,30084,40715 +50958,38935,30083,40884 +58937,38936,30082,40257 +58514,38937,30081,40225 +52721,38938,30080,40368 +56744,38939,30079,40684 +59801,38940,30078,40283 +59435,38941,30077,40121 +51332,38942,30076,40848 +59420,38943,30075,40051 +54296,38944,30074,40914 +59972,38945,30073,40511 +52002,38946,30072,40681 +52916,38947,30071,40011 +55428,38948,30070,40768 +54189,38949,30069,40073 +52393,38950,30068,40859 +57596,38951,30067,40162 +56410,38952,30066,40515 +52429,38953,30065,40649 +50249,38954,30064,40120 +53504,38955,30063,40421 +57065,38956,30062,40178 +50297,38957,30061,40162 +54193,38958,30060,40523 +50641,38959,30059,40404 +58630,38960,30058,40780 +50571,38961,30057,40329 +58901,38962,30056,40955 +57537,38963,30055,40154 +59890,38964,30054,40182 +56556,38965,30053,40166 +55162,38966,30052,40311 +54018,38967,30051,40668 +52149,38968,30050,40851 +53657,38969,30049,40194 +56952,38970,30048,40288 +56474,38971,30047,40447 +58567,38972,30046,40363 +56225,38973,30045,40089 +54167,38974,30044,40852 +54433,38975,30043,40307 +56912,38976,30042,40983 +57476,38977,30041,40703 +55218,38978,30040,40223 +58288,38979,30039,40644 +58815,38980,30038,40496 +59893,38981,30037,40980 +54422,38982,30036,40705 +58211,38983,30035,40373 +51152,38984,30034,40197 +56617,38985,30033,40234 +52403,38986,30032,40629 +53784,38987,30031,40069 +51188,38988,30030,40139 +56214,38989,30029,40939 +50521,38990,30028,40421 +56334,38991,30027,40732 +52492,38992,30026,40924 +55044,38993,30025,40469 +59852,38994,30024,40937 +54454,38995,30023,40476 +53310,38996,30022,40651 +58158,38997,30021,40775 +50097,38998,30020,40183 +57253,38999,30019,40242 +57742,39000,30018,40812 +54690,39001,30017,40363 +58206,39002,30016,40657 +58559,39003,30015,40691 +54229,39004,30014,40278 +52924,39005,30013,40828 +52317,39006,30012,40780 +54093,39007,30011,40353 +52238,39008,30010,40130 +55390,39009,30009,40095 +57128,39010,30008,40765 +52648,39011,30007,40070 +57203,39012,30006,40139 +55083,39013,30005,40283 +59966,39014,30004,40859 +53627,39015,30003,40310 +56996,39016,30002,40029 +53239,39017,30001,40762 +54092,39018,30000,40882 +53508,39019,31000,40686 +50031,39020,30999,40927 +56456,39021,30998,40016 +59125,39022,30997,40604 +54642,39023,30996,40825 +56232,39024,30995,40715 +59927,39025,30994,40824 +58170,39026,30993,40575 +50664,39027,30992,40975 +53667,39028,30991,40099 +54255,39029,30990,40548 +57042,39030,30989,40323 +57496,39031,30988,40965 +56276,39032,30987,40267 +51597,39033,30986,40572 +54499,39034,30985,40763 +52201,39035,30984,40618 +55702,39036,30983,40123 +54430,39037,30982,40435 +55798,39038,30981,40225 +52529,39039,30980,40805 +54848,39040,30979,40340 +56435,39041,30978,40918 +56502,39042,30977,40595 +50827,39043,30976,40666 +52913,39044,30975,40935 +54655,39045,30974,40902 +59329,39046,30973,40362 +52034,39047,30972,40772 +52484,39048,30971,40075 +52311,39049,30970,40163 +59589,39050,30969,40112 +55347,39051,30968,40897 +54124,39052,30967,40734 +53841,39053,30966,40576 +53620,39054,30965,40471 +56783,39055,30964,40635 +50681,39056,30963,40096 +51477,39057,30962,40292 +53472,39058,30961,40150 +58294,39059,30960,40675 +52913,39060,30959,40629 +52527,39061,30958,40620 +55679,39062,30957,40309 +51996,39063,30956,40326 +53064,39064,30955,40681 +57722,39065,30954,40484 +55943,39066,30953,40277 +57527,39067,30952,40610 +57015,39068,30951,40587 +58405,39069,30950,40197 +59154,39070,30949,40218 +56526,39071,30948,40583 +52328,39072,30947,40876 +51874,39073,30946,40789 +54251,39074,30945,40107 +59787,39075,30944,40815 +59303,39076,30943,40327 +56817,39077,30942,40492 +55103,39078,30941,40486 +53594,39079,30940,40360 +53666,39080,30939,40160 +53673,39081,30938,40891 +51565,39082,30937,40006 +56087,39083,30936,40062 +52666,39084,30935,40399 +55791,39085,30934,40788 +52054,39086,30933,40423 +52451,39087,30932,40323 +58560,39088,30931,40916 +55293,39089,30930,40263 +50012,39090,30929,40197 +55536,39091,30928,40209 +51016,39092,30927,40338 +52844,39093,30926,40825 +56646,39094,30925,40995 +57487,39095,30924,40693 +55928,39096,30923,40286 +50553,39097,30922,40108 +56090,39098,30921,40447 +50633,39099,30920,40803 +57625,39100,30919,40406 +53987,39101,30918,40699 +52578,39102,30917,40400 +54083,39103,30916,40942 +55285,39104,30915,40523 +56250,39105,30914,40340 +51623,39106,30913,40571 +57863,39107,30912,40406 +54279,39108,30911,40641 +58578,39109,30910,40662 +57304,39110,30909,40118 +52257,39111,30908,40209 +54605,39112,30907,40524 +55117,39113,30906,40322 +57076,39114,30905,40533 +54543,39115,30904,40477 +57529,39116,30903,40147 +52148,39117,30902,40836 +51595,39118,30901,40531 +53024,39119,30900,40569 +59131,39120,30899,40630 +58399,39121,30898,40537 +53984,39122,30897,40102 +54054,39123,30896,40425 +58568,39124,30895,40153 +55511,39125,30894,40960 +58617,39126,30893,40717 +54643,39127,30892,40849 +59414,39128,30891,40129 +50586,39129,30890,40763 +58781,39130,30889,40443 +56143,39131,30888,40326 +55517,39132,30887,40731 +57751,39133,30886,40020 +53940,39134,30885,40323 +56591,39135,30884,40954 +56646,39136,30883,40049 +51405,39137,30882,40466 +58363,39138,30881,40883 +53983,39139,30880,40831 +54703,39140,30879,40158 +59440,39141,30878,40691 +53197,39142,30877,40539 +58377,39143,30876,40864 +57989,39144,30875,40911 +58468,39145,30874,40761 +54330,39146,30873,40861 +52155,39147,30872,40949 +58985,39148,30871,40882 +55647,39149,30870,40456 +51555,39150,30869,40252 +54597,39151,30868,40501 +50123,39152,30867,40568 +59531,39153,30866,40091 +56187,39154,30865,40230 +52840,39155,30864,40019 +56657,39156,30863,40308 +53121,39157,30862,40372 +52631,39158,30861,40812 +58023,39159,30860,40739 +54496,39160,30859,40330 +50286,39161,30858,40834 +56718,39162,30857,40311 +58665,39163,30856,40043 +54737,39164,30855,40947 +56001,39165,30854,40666 +56330,39166,30853,40498 +57460,39167,30852,40884 +50797,39168,30851,40622 +53034,39169,30850,40320 +55429,39170,30849,40164 +56035,39171,30848,40897 +53617,39172,30847,40918 +59661,39173,30846,40573 +53436,39174,30845,40868 +54113,39175,30844,40541 +58411,39176,30843,40400 +57644,39177,30842,40416 +52255,39178,30841,40765 +56380,39179,30840,40118 +58826,39180,30839,40395 +50608,39181,30838,40791 +58142,39182,30837,40274 +52066,39183,30836,40126 +56913,39184,30835,40159 +59393,39185,30834,40813 +57501,39186,30833,40408 +51910,39187,30832,40542 +52244,39188,30831,40944 +56968,39189,30830,40803 +51808,39190,30829,40288 +59643,39191,30828,40714 +51784,39192,30827,40955 +58419,39193,30826,40209 +53791,39194,30825,40259 +53399,39195,30824,40026 +50327,39196,30823,40621 +59857,39197,30822,40995 +56371,39198,30821,40878 +59762,39199,30820,40196 +55513,39200,30819,40913 +58289,39201,30818,40494 +54982,39202,30817,40566 +56500,39203,30816,40709 +50940,39204,30815,40960 +50231,39205,30814,40313 +59943,39206,30813,40779 +58809,39207,30812,40767 +52909,39208,30811,40855 +53047,39209,30810,40471 +52739,39210,30809,40022 +55808,39211,30808,40561 +55212,39212,30807,40542 +53479,39213,30806,40401 +56476,39214,30805,40164 +54935,39215,30804,40844 +57211,39216,30803,40382 +56417,39217,30802,40206 +55270,39218,30801,40114 +58928,39219,30800,40450 +57967,39220,30799,40936 +58030,39221,30798,40333 +54804,39222,30797,40224 +59807,39223,30796,40103 +56701,39224,30795,40386 +52603,39225,30794,40743 +51823,39226,30793,40089 +55898,39227,30792,40362 +59566,39228,30791,40202 +59367,39229,30790,40271 +51823,39230,30789,40023 +57495,39231,30788,40882 +51163,39232,30787,40466 +58755,39233,30786,40779 +59519,39234,30785,40512 +50752,39235,30784,40402 +55216,39236,30783,40660 +57552,39237,30782,40690 +52109,39238,30781,40765 +59874,39239,30780,40231 +59725,39240,30779,40046 +51316,39241,30778,40293 +58374,39242,30777,40175 +51736,39243,30776,40286 +59375,39244,30775,40869 +55109,39245,30774,40056 +53518,39246,30773,40227 +52276,39247,30772,40001 +51131,39248,30771,40459 +55195,39249,30770,40599 +54118,39250,30769,40245 +50263,39251,30768,40177 +53940,39252,30767,40442 +54258,39253,30766,40227 +57348,39254,30765,40213 +57092,39255,30764,40690 +55455,39256,30763,40431 +50053,39257,30762,40101 +58366,39258,30761,40590 +53552,39259,30760,40507 +53190,39260,30759,40034 +53124,39261,30758,40919 +50782,39262,30757,40052 +56948,39263,30756,40221 +54465,39264,30755,40091 +52574,39265,30754,40528 +58143,39266,30753,40627 +55465,39267,30752,40257 +51678,39268,30751,40092 +55239,39269,30750,40486 +57437,39270,30749,40629 +59034,39271,30748,40836 +50665,39272,30747,40267 +55187,39273,30746,40331 +52873,39274,30745,40626 +54165,39275,30744,40605 +53236,39276,30743,40662 +58520,39277,30742,40858 +54739,39278,30741,40438 +51306,39279,30740,40867 +50400,39280,30739,40182 +56768,39281,30738,40264 +53341,39282,30737,40080 +52010,39283,30736,40816 +58434,39284,30735,40958 +59732,39285,30734,40525 +57518,39286,30733,40639 +59112,39287,30732,40106 +56510,39288,30731,40172 +55601,39289,30730,40874 +54332,39290,30729,40453 +52587,39291,30728,40031 +52111,39292,30727,40636 +50550,39293,30726,40747 +50160,39294,30725,40454 +58841,39295,30724,40822 +54925,39296,30723,40753 +58308,39297,30722,40644 +51174,39298,30721,40039 +58733,39299,30720,40146 +53924,39300,30719,40238 +56028,39301,30718,40013 +56745,39302,30717,40977 +58690,39303,30716,40080 +55331,39304,30715,40878 +54260,39305,30714,40736 +54283,39306,30713,40516 +53430,39307,30712,40213 +54282,39308,30711,40809 +52194,39309,30710,40751 +59690,39310,30709,40478 +55927,39311,30708,40370 +52138,39312,30707,40736 +53470,39313,30706,40504 +58604,39314,30705,40516 +53816,39315,30704,40674 +50552,39316,30703,40870 +57428,39317,30702,40531 +51812,39318,30701,40349 +51629,39319,30700,40432 +57563,39320,30699,40182 +56031,39321,30698,40247 +50905,39322,30697,40300 +52314,39323,30696,40916 +50457,39324,30695,40545 +57935,39325,30694,40434 +55893,39326,30693,40748 +57863,39327,30692,40852 +57709,39328,30691,40391 +53475,39329,30690,40360 +59188,39330,30689,40299 +52062,39331,30688,40524 +50163,39332,30687,40178 +59999,39333,30686,40825 +52160,39334,30685,40233 +56347,39335,30684,40280 +51658,39336,30683,40456 +56551,39337,30682,40605 +57227,39338,30681,40888 +57083,39339,30680,40183 +50416,39340,30679,40568 +58721,39341,30678,40696 +59557,39342,30677,40675 +50781,39343,30676,40960 +57065,39344,30675,40841 +59159,39345,30674,40008 +59265,39346,30673,40912 +50915,39347,30672,40365 +58281,39348,30671,40800 +51138,39349,30670,40524 +57652,39350,30669,40296 +58433,39351,30668,40116 +59652,39352,30667,40672 +56271,39353,30666,40108 +58997,39354,30665,40308 +53949,39355,30664,40298 +50468,39356,30663,40361 +50654,39357,30662,40469 +59470,39358,30661,40119 +57581,39359,30660,40312 +51907,39360,30659,40387 +51997,39361,30658,40756 +58505,39362,30657,40752 +59611,39363,30656,40520 +54012,39364,30655,40130 +50064,39365,30654,40224 +59555,39366,30653,40150 +58196,39367,30652,40135 +54670,39368,30651,40209 +52028,39369,30650,40961 +56059,39370,30649,40500 +55108,39371,30648,40922 +57608,39372,30647,40001 +51671,39373,30646,40533 +51027,39374,30645,40084 +58907,39375,30644,40154 +53342,39376,30643,40809 +59530,39377,30642,40352 +51086,39378,30641,40798 +53290,39379,30640,40298 +57442,39380,30639,40692 +50878,39381,30638,40368 +50464,39382,30637,40736 +50390,39383,30636,40749 +56907,39384,30635,40768 +53794,39385,30634,40721 +58801,39386,30633,40772 +52100,39387,30632,40946 +51009,39388,30631,40115 +54674,39389,30630,40924 +52793,39390,30629,40367 +53563,39391,30628,40738 +50638,39392,30627,40798 +54561,39393,30626,40359 +52053,39394,30625,40982 +59300,39395,30624,40174 +59854,39396,30623,40099 +59312,39397,30622,40282 +52016,39398,30621,40512 +53613,39399,30620,40067 +51551,39400,30619,40953 +51524,39401,30618,40470 +50810,39402,30617,40104 +55105,39403,30616,40231 +56561,39404,30615,40516 +59715,39405,30614,40333 +59188,39406,30613,40794 +56673,39407,30612,40179 +59303,39408,30611,40159 +55111,39409,30610,40879 +59842,39410,30609,40595 +55885,39411,30608,40544 +55220,39412,30607,40747 +57577,39413,30606,40809 +53415,39414,30605,40156 +55387,39415,30604,40516 +58830,39416,30603,40479 +54742,39417,30602,40421 +54843,39418,30601,40957 +59055,39419,30600,40708 +53342,39420,30599,40552 +57901,39421,30598,40454 +51944,39422,30597,40899 +50113,39423,30596,40297 +58430,39424,30595,40359 +57071,39425,30594,40250 +59384,39426,30593,40708 +56586,39427,30592,40869 +56281,39428,30591,40456 +58317,39429,30590,40288 +50457,39430,30589,40063 +56918,39431,30588,40013 +50461,39432,30587,40943 +58317,39433,30586,40410 +55816,39434,30585,40094 +52850,39435,30584,40550 +51243,39436,30583,40890 +56261,39437,30582,40146 +53225,39438,30581,40181 +56911,39439,30580,40393 +59126,39440,30579,40443 +51518,39441,30578,40029 +54093,39442,30577,40802 +56077,39443,30576,40200 +50943,39444,30575,40325 +57601,39445,30574,40549 +54425,39446,30573,40893 +57312,39447,30572,40681 +51871,39448,30571,40564 +57453,39449,30570,40760 +50885,39450,30569,40319 +55390,39451,30568,40928 +55117,39452,30567,40615 +55263,39453,30566,40956 +59274,39454,30565,40916 +56159,39455,30564,40022 +50451,39456,30563,40591 +59063,39457,30562,40373 +56659,39458,30561,40650 +59147,39459,30560,40398 +51517,39460,30559,40111 +53369,39461,30558,40938 +50668,39462,30557,40978 +59103,39463,30556,40244 +51897,39464,30555,40787 +53465,39465,30554,40397 +57366,39466,30553,40356 +59303,39467,30552,40430 +57383,39468,30551,40923 +55405,39469,30550,40169 +59376,39470,30549,40796 +51077,39471,30548,40101 +53737,39472,30547,40095 +58863,39473,30546,40748 +55087,39474,30545,40833 +51928,39475,30544,40730 +55076,39476,30543,40650 +54680,39477,30542,40020 +53270,39478,30541,40474 +52421,39479,30540,40675 +59885,39480,30539,40264 +57702,39481,30538,40324 +54094,39482,30537,40753 +57842,39483,30536,40365 +55261,39484,30535,40201 +53766,39485,30534,40797 +57231,39486,30533,40578 +50165,39487,30532,40081 +53469,39488,30531,40278 +53977,39489,30530,40167 +57540,39490,30529,40362 +54376,39491,30528,40104 +55034,39492,30527,40209 +59251,39493,30526,40551 +58587,39494,30525,40729 +51416,39495,30524,40625 +53921,39496,30523,40047 +59207,39497,30522,40592 +50626,39498,30521,40986 +54881,39499,30520,40664 +50115,39500,30519,40582 +57852,39501,30518,40268 +51163,39502,30517,40688 +52451,39503,30516,40158 +54658,39504,30515,40481 +53834,39505,30514,40634 +59592,39506,30513,40137 +52432,39507,30512,40445 +54530,39508,30511,40889 +53549,39509,30510,40935 +55822,39510,30509,40932 +53787,39511,30508,40058 +56584,39512,30507,40699 +58512,39513,30506,40806 +55414,39514,30505,40828 +56329,39515,30504,40435 +54254,39516,30503,40174 +53875,39517,30502,40834 +58631,39518,30501,40012 +55955,39519,30500,40073 +53260,39520,30499,40395 +59526,39521,30498,40465 +52301,39522,30497,40562 +52242,39523,30496,40589 +53856,39524,30495,40837 +50235,39525,30494,40848 +53637,39526,30493,40382 +59857,39527,30492,40963 +52647,39528,30491,40673 +53415,39529,30490,40651 +50878,39530,30489,40321 +53695,39531,30488,40227 +59713,39532,30487,40948 +59632,39533,30486,40731 +59576,39534,30485,40872 +55529,39535,30484,40253 +56736,39536,30483,40409 +55392,39537,30482,40823 +51624,39538,30481,40753 +59475,39539,30480,40786 +58888,39540,30479,40386 +56400,39541,30478,40990 +55682,39542,30477,40803 +50304,39543,30476,40320 +59712,39544,30475,40420 +55469,39545,30474,40305 +54621,39546,30473,40911 +52709,39547,30472,40308 +59088,39548,30471,40237 +50039,39549,30470,40579 +57714,39550,30469,40306 +54042,39551,30468,40590 +59281,39552,30467,40359 +59660,39553,30466,40186 +53245,39554,30465,40738 +55416,39555,30464,40970 +54239,39556,30463,40188 +55505,39557,30462,40229 +58522,39558,30461,40871 +53291,39559,30460,40092 +55513,39560,30459,40489 +53881,39561,30458,40293 +54968,39562,30457,40937 +55056,39563,30456,40232 +54703,39564,30455,40717 +54443,39565,30454,40958 +58777,39566,30453,40422 +57400,39567,30452,40337 +56515,39568,30451,40825 +56911,39569,30450,40317 +54271,39570,30449,40010 +59779,39571,30448,40921 +55784,39572,30447,40919 +57409,39573,30446,40185 +54832,39574,30445,40670 +58502,39575,30444,40531 +59782,39576,30443,40284 +51053,39577,30442,40811 +57107,39578,30441,40931 +59621,39579,30440,40318 +51715,39580,30439,40239 +58480,39581,30438,40336 +58593,39582,30437,40342 +56568,39583,30436,40986 +52010,39584,30435,40946 +54061,39585,30434,40115 +55636,39586,30433,40716 +59498,39587,30432,40714 +50616,39588,30431,40798 +56565,39589,30430,40133 +52634,39590,30429,40180 +51524,39591,30428,40097 +57369,39592,30427,40344 +53645,39593,30426,40839 +59906,39594,30425,40338 +57782,39595,30424,40103 +56719,39596,30423,40728 +55003,39597,30422,40228 +51757,39598,30421,40463 +52606,39599,30420,40732 +58683,39600,30419,40486 +53705,39601,30418,40386 +59726,39602,30417,40259 +50575,39603,30416,40849 +52593,39604,30415,40805 +59248,39605,30414,40999 +52506,39606,30413,40046 +51483,39607,30412,40803 +59720,39608,30411,40586 +54478,39609,30410,40733 +55224,39610,30409,40920 +57417,39611,30408,40833 +54887,39612,30407,40460 +51312,39613,30406,40600 +53666,39614,30405,40662 +58575,39615,30404,40755 +55801,39616,30403,40603 +55576,39617,30402,40124 +51298,39618,30401,40077 +58615,39619,30400,40771 +53689,39620,30399,40882 +58135,39621,30398,40849 +59077,39622,30397,40206 +57134,39623,30396,40469 +54630,39624,30395,40526 +58051,39625,30394,40953 +59659,39626,30393,40891 +59872,39627,30392,40296 +57200,39628,30391,40350 +51810,39629,30390,40790 +54212,39630,30389,40094 +52701,39631,30388,40491 +57080,39632,30387,40675 +53341,39633,30386,40726 +57396,39634,30385,40990 +53367,39635,30384,40123 +58100,39636,30383,40823 +55790,39637,30382,40944 +54959,39638,30381,40978 +53505,39639,30380,40234 +59080,39640,30379,40999 +55153,39641,30378,40918 +51485,39642,30377,40357 +51185,39643,30376,40958 +53373,39644,30375,40035 +52502,39645,30374,40259 +54711,39646,30373,40075 +58414,39647,30372,40426 +58989,39648,30371,40139 +50589,39649,30370,40716 +57719,39650,30369,40560 +54642,39651,30368,40581 +51204,39652,30367,40345 +52792,39653,30366,40585 +53548,39654,30365,40941 +50776,39655,30364,40910 +54000,39656,30363,40683 +58252,39657,30362,40002 +56515,39658,30361,40748 +55454,39659,30360,40354 +57714,39660,30359,40663 +59023,39661,30358,40635 +54734,39662,30357,40609 +50228,39663,30356,40521 +59323,39664,30355,40566 +56747,39665,30354,40690 +50352,39666,30353,40144 +53195,39667,30352,40182 +52367,39668,30351,40307 +51257,39669,30350,40214 +57919,39670,30349,40219 +58039,39671,30348,40125 +52804,39672,30347,40587 +53399,39673,30346,40295 +58081,39674,30345,40187 +50445,39675,30344,40461 +56083,39676,30343,40477 +51106,39677,30342,40578 +59470,39678,30341,40404 +55429,39679,30340,40470 +51270,39680,30339,40673 +56524,39681,30338,40132 +50772,39682,30337,40299 +56504,39683,30336,40985 +50568,39684,30335,40050 +58278,39685,30334,40212 +58589,39686,30333,40625 +58482,39687,30332,40308 +56696,39688,30331,40822 +56438,39689,30330,40923 +53354,39690,30329,40438 +59120,39691,30328,40341 +58485,39692,30327,40538 +58690,39693,30326,40764 +54155,39694,30325,40480 +54563,39695,30324,40580 +57874,39696,30323,40704 +51299,39697,30322,40910 +50676,39698,30321,40060 +51515,39699,30320,40307 +53059,39700,30319,40242 +53939,39701,30318,40351 +59130,39702,30317,40545 +57693,39703,30316,40111 +55374,39704,30315,40622 +53022,39705,30314,40072 +58259,39706,30313,40338 +56109,39707,30312,40654 +51003,39708,30311,40273 +59060,39709,30310,40221 +56457,39710,30309,40562 +56660,39711,30308,40776 +58340,39712,30307,40446 +54853,39713,30306,40716 +57399,39714,30305,40399 +57578,39715,30304,40159 +57797,39716,30303,40894 +51139,39717,30302,40754 +58890,39718,30301,40697 +55148,39719,30300,40377 +53580,39720,30299,40351 +53875,39721,30298,40811 +50480,39722,30297,40721 +53751,39723,30296,40242 +55129,39724,30295,40592 +51163,39725,30294,40545 +54860,39726,30293,40765 +53258,39727,30292,40813 +59199,39728,30291,40440 +51045,39729,30290,40057 +56783,39730,30289,40552 +50936,39731,30288,40962 +54305,39732,30287,40427 +56218,39733,30286,40835 +59920,39734,30285,40860 +56931,39735,30284,40254 +51397,39736,30283,40015 +56568,39737,30282,40848 +56725,39738,30281,40561 +53890,39739,30280,40904 +52788,39740,30279,40880 +52588,39741,30278,40356 +55127,39742,30277,40828 +59995,39743,30276,40623 +51095,39744,30275,40242 +51368,39745,30274,40843 +58402,39746,30273,40707 +52233,39747,30272,40295 +51963,39748,30271,40957 +58686,39749,30270,40717 +53713,39750,30269,40533 +59062,39751,30268,40091 +52030,39752,30267,40848 +52546,39753,30266,40259 +55126,39754,30265,40061 +58433,39755,30264,40161 +52527,39756,30263,40976 +53851,39757,30262,40041 +59119,39758,30261,40717 +51466,39759,30260,40931 +53009,39760,30259,40695 +57025,39761,30258,40700 +59778,39762,30257,40381 +59920,39763,30256,40330 +58488,39764,30255,40447 +55520,39765,30254,40171 +54033,39766,30253,40635 +59225,39767,30252,40235 +56169,39768,30251,40014 +56068,39769,30250,40400 +51078,39770,30249,40073 +57546,39771,30248,40931 +50334,39772,30247,40498 +59931,39773,30246,40854 +52504,39774,30245,40748 +50938,39775,30244,40276 +50336,39776,30243,40316 +58309,39777,30242,40114 +52003,39778,30241,40152 +55987,39779,30240,40656 +55962,39780,30239,40806 +59863,39781,30238,40395 +59428,39782,30237,40111 +52753,39783,30236,40858 +52892,39784,30235,40030 +55827,39785,30234,40067 +52810,39786,30233,40249 +50000,39787,30232,40490 +55269,39788,30231,40027 +51696,39789,30230,40661 +53062,39790,30229,40211 +55105,39791,30228,40327 +52296,39792,30227,40868 +59320,39793,30226,40775 +57067,39794,30225,40922 +57461,39795,30224,40836 +54231,39796,30223,40366 +57108,39797,30222,40999 +55614,39798,30221,40782 +57952,39799,30220,40093 +57146,39800,30219,40756 +53762,39801,30218,40560 +59446,39802,30217,40977 +51415,39803,30216,40145 +53497,39804,30215,40238 +50111,39805,30214,40276 +55180,39806,30213,40231 +58402,39807,30212,40655 +51309,39808,30211,40109 +58221,39809,30210,40160 +57516,39810,30209,40398 +50234,39811,30208,40195 +59139,39812,30207,40658 +58094,39813,30206,40325 +58354,39814,30205,40621 +57451,39815,30204,40135 +57416,39816,30203,40652 +51142,39817,30202,40162 +50558,39818,30201,40702 +50883,39819,30200,40340 +57005,39820,30199,40121 +52220,39821,30198,40493 +58592,39822,30197,40525 +59408,39823,30196,40265 +58052,39824,30195,40425 +51897,39825,30194,40321 +56891,39826,30193,40696 +54198,39827,30192,40800 +59072,39828,30191,40167 +57798,39829,30190,40303 +59861,39830,30189,40438 +51718,39831,30188,40773 +52681,39832,30187,40897 +57378,39833,30186,40823 +56453,39834,30185,40378 +52776,39835,30184,40816 +50725,39836,30183,40317 +52490,39837,30182,40541 +54116,39838,30181,40928 +57889,39839,30180,40583 +58480,39840,30179,40940 +58847,39841,30178,40254 +58028,39842,30177,40708 +50573,39843,30176,40375 +50820,39844,30175,40321 +54915,39845,30174,40418 +51227,39846,30173,40071 +52118,39847,30172,40418 +54145,39848,30171,40648 +57867,39849,30170,40137 +54545,39850,30169,40963 +52474,39851,30168,40832 +53526,39852,30167,40145 +58765,39853,30166,40592 +51885,39854,30165,40348 +59320,39855,30164,40984 +52069,39856,30163,40276 +54723,39857,30162,40483 +58355,39858,30161,40862 +51619,39859,30160,40245 +56562,39860,30159,40923 +54103,39861,30158,40458 +51896,39862,30157,40139 +54381,39863,30156,40155 +51668,39864,30155,40285 +56324,39865,30154,40406 +53620,39866,30153,40276 +58909,39867,30152,40648 +55714,39868,30151,40567 +50875,39869,30150,40090 +58462,39870,30149,40261 +59113,39871,30148,40990 +59191,39872,30147,40546 +55162,39873,30146,40404 +59539,39874,30145,40371 +52412,39875,30144,40669 +55583,39876,30143,40826 +56406,39877,30142,40939 +56112,39878,30141,40263 +54320,39879,30140,40979 +54967,39880,30139,40499 +59922,39881,30138,40232 +52434,39882,30137,40769 +53045,39883,30136,40405 +59472,39884,30135,40532 +57365,39885,30134,40143 +59021,39886,30133,40095 +53512,39887,30132,40309 +51595,39888,30131,40893 +54904,39889,30130,40420 +56833,39890,30129,40686 +52300,39891,30128,40563 +59821,39892,30127,40170 +56005,39893,30126,40208 +55590,39894,30125,40189 +58548,39895,30124,40014 +54109,39896,30123,40951 +51497,39897,30122,40732 +56209,39898,30121,40855 +53990,39899,30120,40258 +55921,39900,30119,40635 +54081,39901,30118,40026 +58540,39902,30117,40862 +56409,39903,30116,40441 +51076,39904,30115,40599 +54208,39905,30114,40377 +58177,39906,30113,40090 +55719,39907,30112,40500 +56850,39908,30111,40142 +54183,39909,30110,40871 +55391,39910,30109,40618 +52843,39911,30108,40089 +57482,39912,30107,40612 +54684,39913,30106,40806 +53795,39914,30105,40136 +51044,39915,30104,40988 +58651,39916,30103,40257 +54515,39917,30102,40105 +53472,39918,30101,40919 +56608,39919,30100,40575 +54903,39920,30099,40221 +51559,39921,30098,40078 +54887,39922,30097,40445 +59985,39923,30096,40852 +56818,39924,30095,40787 +51521,39925,30094,40539 +51551,39926,30093,40771 +55531,39927,30092,40583 +57170,39928,30091,40480 +56943,39929,30090,40962 +52750,39930,30089,40554 +50675,39931,30088,40086 +53873,39932,30087,40026 +55518,39933,30086,40455 +55133,39934,30085,40733 +51825,39935,30084,40002 +53078,39936,30083,40771 +55424,39937,30082,40918 +50215,39938,30081,40235 +55150,39939,30080,40214 +50335,39940,30079,40037 +51767,39941,30078,40959 +55561,39942,30077,40283 +56742,39943,30076,40284 +58282,39944,30075,40804 +52807,39945,30074,40500 +55076,39946,30073,40191 +58487,39947,30072,40317 +56215,39948,30071,40697 +58567,39949,30070,40367 +58150,39950,30069,40316 +51376,39951,30068,40119 +57767,39952,30067,40260 +58784,39953,30066,40326 +54084,39954,30065,40782 +51650,39955,30064,40862 +56687,39956,30063,40551 +55820,39957,30062,40177 +57779,39958,30061,40270 +53506,39959,30060,40333 +54741,39960,30059,40823 +50552,39961,30058,40600 +55465,39962,30057,40533 +50708,39963,30056,40348 +51969,39964,30055,40531 +59090,39965,30054,40151 +53344,39966,30053,40720 +51009,39967,30052,40705 +56445,39968,30051,40485 +50826,39969,30050,40707 +55699,39970,30049,40755 +58385,39971,30048,40953 +58517,39972,30047,40966 +56453,39973,30046,40603 +59695,39974,30045,40832 +58961,39975,30044,40950 +50792,39976,30043,40099 +58965,39977,30042,40121 +57379,39978,30041,40439 +56078,39979,30040,40743 +56212,39980,30039,40452 +57569,39981,30038,40809 +52015,39982,30037,40309 +56424,39983,30036,40029 +56269,39984,30035,40745 +51411,39985,30034,40207 +50440,39986,30033,40727 +52112,39987,30032,40402 +59542,39988,30031,40301 +59493,39989,30030,40586 +58530,39990,30029,40373 +57401,39991,30028,40713 +59909,39992,30027,40029 +52130,39993,30026,40605 +59860,39994,30025,40569 +59146,39995,30024,40659 +57379,39996,30023,40687 +59787,39997,30022,40018 +51015,39998,30021,40983 +50825,39999,30020,40582 +51225,40000,30019,40637 +51759,40001,30018,40047 +52055,40002,30017,40261 +53617,40003,30016,40749 +50500,40004,30015,40353 +53040,40005,30014,40426 +59056,40006,30013,40602 +53437,40007,30012,40925 +50370,40008,30011,40256 +52549,40009,30010,40038 +51377,40010,30009,40176 +54778,40011,30008,40027 +53826,40012,30007,40025 +50594,40013,30006,40982 +52060,40014,30005,40123 +59272,40015,30004,40104 +58743,40016,30003,40021 +53441,40017,30002,40191 +50771,40018,30001,40873 +58857,40019,30000,40111 +50021,40020,31000,40910 +55852,40021,30999,40056 +53148,40022,30998,40865 +50640,40023,30997,40163 +50930,40024,30996,40586 +57679,40025,30995,40770 +56030,40026,30994,40694 +55027,40027,30993,40331 +52438,40028,30992,40494 +56826,40029,30991,40993 +57105,40030,30990,40299 +57065,40031,30989,40960 +55435,40032,30988,40341 +57245,40033,30987,40651 +50482,40034,30986,40407 +51468,40035,30985,40523 +50077,40036,30984,40064 +55642,40037,30983,40997 +51036,40038,30982,40408 +58776,40039,30981,40097 +57626,40040,30980,40228 +57527,40041,30979,40187 +50559,40042,30978,40761 +59097,40043,30977,40560 +53810,40044,30976,40825 +57400,40045,30975,40055 +55388,40046,30974,40653 +55873,40047,30973,40785 +57703,40048,30972,40192 +59272,40049,30971,40006 +53606,40050,30970,40339 +57535,40051,30969,40798 +54462,40052,30968,40218 +50081,40053,30967,40752 +50402,40054,30966,40850 +53336,40055,30965,40211 +55404,40056,30964,40789 +52942,40057,30963,40654 +59127,40058,30962,40212 +50129,40059,30961,40062 +51242,40060,30960,40583 +59712,40061,30959,40620 +58287,40062,30958,40220 +57538,40063,30957,40616 +53377,40064,30956,40410 +51622,40065,30955,40446 +57731,40066,30954,40849 +54308,40067,30953,40699 +54702,40068,30952,40857 +53234,40069,30951,40516 +58003,40070,30950,40755 +51779,40071,30949,40243 +50750,40072,30948,40863 +54971,40073,30947,40696 +58907,40074,30946,40971 +57789,40075,30945,40448 +56307,40076,30944,40020 +52533,40077,30943,40852 +51262,40078,30942,40204 +56449,40079,30941,40640 +52668,40080,30940,40705 +59370,40081,30939,40726 +56415,40082,30938,40358 +54961,40083,30937,40222 +57088,40084,30936,40936 +52004,40085,30935,40749 +56434,40086,30934,40423 +50319,40087,30933,40072 +54548,40088,30932,40151 +53151,40089,30931,40899 +57087,40090,30930,40570 +56867,40091,30929,40346 +51871,40092,30928,40763 +53195,40093,30927,40130 +59151,40094,30926,40034 +59714,40095,30925,40893 +52989,40096,30924,40639 +56600,40097,30923,40945 +57036,40098,30922,40405 +53640,40099,30921,40732 +54441,40100,30920,40924 +57881,40101,30919,40766 +50709,40102,30918,40546 +52815,40103,30917,40555 +57008,40104,30916,40296 +57441,40105,30915,40012 +57735,40106,30914,40797 +58021,40107,30913,40848 +58996,40108,30912,40361 +52216,40109,30911,40084 +52180,40110,30910,40896 +57658,40111,30909,40764 +53911,40112,30908,40145 +56965,40113,30907,40356 +56592,40114,30906,40065 +51022,40115,30905,40720 +59003,40116,30904,40761 +59765,40117,30903,40197 +56334,40118,30902,40721 +50215,40119,30901,40218 +53656,40120,30900,40887 +53811,40121,30899,40870 +58327,40122,30898,40496 +54409,40123,30897,40807 +53990,40124,30896,40122 +55981,40125,30895,40140 +51570,40126,30894,40748 +53883,40127,30893,40144 +53278,40128,30892,40106 +57893,40129,30891,40172 +59005,40130,30890,40880 +53000,40131,30889,40903 +50060,40132,30888,40283 +52925,40133,30887,40628 +56258,40134,30886,40951 +56699,40135,30885,40433 +55135,40136,30884,40424 +53337,40137,30883,40999 +55186,40138,30882,40568 +54241,40139,30881,40179 +54743,40140,30880,40865 +51216,40141,30879,40920 +55981,40142,30878,40816 +52138,40143,30877,40094 +57110,40144,30876,40935 +52843,40145,30875,40459 +52263,40146,30874,40614 +50680,40147,30873,40164 +55391,40148,30872,40693 +55364,40149,30871,40473 +53909,40150,30870,40063 +54479,40151,30869,40266 +58202,40152,30868,40262 +56856,40153,30867,40506 +58589,40154,30866,40400 +55571,40155,30865,40326 +53709,40156,30864,40747 +51285,40157,30863,40666 +51193,40158,30862,40338 +59916,40159,30861,40561 +51603,40160,30860,40572 +53692,40161,30859,40150 +52484,40162,30858,40765 +55412,40163,30857,40612 +51097,40164,30856,40723 +51279,40165,30855,40854 +51450,40166,30854,40231 +53543,40167,30853,40356 +57707,40168,30852,40766 +59459,40169,30851,40298 +59484,40170,30850,40276 +51473,40171,30849,40039 +53675,40172,30848,40516 +56975,40173,30847,40575 +55098,40174,30846,40253 +56147,40175,30845,40685 +57978,40176,30844,40660 +52923,40177,30843,40617 +57798,40178,30842,40786 +56879,40179,30841,40298 +59853,40180,30840,40675 +59218,40181,30839,40232 +57783,40182,30838,40531 +59111,40183,30837,40848 +54360,40184,30836,40492 +55967,40185,30835,40893 +50467,40186,30834,40328 +55697,40187,30833,40895 +55718,40188,30832,40839 +51827,40189,30831,40587 +59571,40190,30830,40206 +52117,40191,30829,40143 +51182,40192,30828,40020 +54061,40193,30827,40120 +59170,40194,30826,40826 +50812,40195,30825,40346 +52943,40196,30824,40495 +55440,40197,30823,40347 +57166,40198,30822,40013 +58627,40199,30821,40796 +57125,40200,30820,40819 +50832,40201,30819,40893 +54725,40202,30818,40816 +58709,40203,30817,40828 +59008,40204,30816,40361 +51940,40205,30815,40114 +59545,40206,30814,40783 +55396,40207,30813,40498 +53332,40208,30812,40184 +53925,40209,30811,40175 +54684,40210,30810,40640 +59777,40211,30809,40337 +50723,40212,30808,40148 +50221,40213,30807,40435 +57588,40214,30806,40282 +55519,40215,30805,40732 +54100,40216,30804,40672 +59961,40217,30803,40767 +56535,40218,30802,40544 +59619,40219,30801,40330 +51855,40220,30800,40365 +53975,40221,30799,40840 +53424,40222,30798,40838 +50646,40223,30797,40059 +59246,40224,30796,40523 +58408,40225,30795,40794 +51704,40226,30794,40328 +51681,40227,30793,40562 +55918,40228,30792,40965 +59358,40229,30791,40524 +59885,40230,30790,40471 +57903,40231,30789,40507 +58043,40232,30788,40447 +57791,40233,30787,40296 +56893,40234,30786,40253 +54030,40235,30785,40556 +50135,40236,30784,40097 +52224,40237,30783,40625 +55291,40238,30782,40213 +51805,40239,30781,40445 +56594,40240,30780,40850 +51017,40241,30779,40884 +50617,40242,30778,40590 +54191,40243,30777,40425 +58179,40244,30776,40399 +53079,40245,30775,40465 +58236,40246,30774,40607 +55943,40247,30773,40685 +53069,40248,30772,40803 +57221,40249,30771,40442 +59883,40250,30770,40610 +55882,40251,30769,40486 +51418,40252,30768,40462 +53745,40253,30767,40352 +55760,40254,30766,40794 +54543,40255,30765,40436 +59076,40256,30764,40961 +58589,40257,30763,40987 +53748,40258,30762,40806 +54993,40259,30761,40419 +53238,40260,30760,40182 +57579,40261,30759,40768 +50598,40262,30758,40662 +57803,40263,30757,40070 +51535,40264,30756,40593 +50335,40265,30755,40938 +55125,40266,30754,40122 +58874,40267,30753,40276 +51086,40268,30752,40747 +52705,40269,30751,40787 +51777,40270,30750,40256 +51167,40271,30749,40461 +59750,40272,30748,40187 +54360,40273,30747,40113 +59501,40274,30746,40877 +57946,40275,30745,40300 +57787,40276,30744,40053 +59247,40277,30743,40388 +58751,40278,30742,40416 +56959,40279,30741,40844 +52915,40280,30740,40485 +58211,40281,30739,40364 +51774,40282,30738,40187 +56468,40283,30737,40555 +55078,40284,30736,40986 +58178,40285,30735,40412 +58851,40286,30734,40955 +52144,40287,30733,40900 +54574,40288,30732,40709 +57261,40289,30731,40868 +56264,40290,30730,40757 +53326,40291,30729,40782 +53671,40292,30728,40361 +52582,40293,30727,40560 +51803,40294,30726,40761 +58919,40295,30725,40608 +51103,40296,30724,40370 +51634,40297,30723,40587 +54955,40298,30722,40577 +59579,40299,30721,40727 +55447,40300,30720,40256 +50216,40301,30719,40817 +55753,40302,30718,40648 +52664,40303,30717,40675 +55263,40304,30716,40819 +57632,40305,30715,40374 +58712,40306,30714,40532 +51136,40307,30713,40384 +56733,40308,30712,40950 +53381,40309,30711,40945 +57550,40310,30710,40469 +50376,40311,30709,40216 +53702,40312,30708,40229 +50787,40313,30707,40517 +51168,40314,30706,40950 +51091,40315,30705,40811 +57139,40316,30704,40256 +58568,40317,30703,40892 +53529,40318,30702,40217 +58762,40319,30701,40424 +55886,40320,30700,40536 +56454,40321,30699,40948 +58467,40322,30698,40293 +54982,40323,30697,40243 +56865,40324,30696,40975 +58447,40325,30695,40812 +57291,40326,30694,40753 +55876,40327,30693,40151 +54205,40328,30692,40130 +53255,40329,30691,40157 +58705,40330,30690,40215 +59824,40331,30689,40995 +51232,40332,30688,40752 +55878,40333,30687,40914 +53333,40334,30686,40180 +50122,40335,30685,40247 +52557,40336,30684,40345 +58291,40337,30683,40706 +52683,40338,30682,40260 +58067,40339,30681,40629 +53656,40340,30680,40289 +57865,40341,30679,40179 +55799,40342,30678,40992 +54096,40343,30677,40930 +58999,40344,30676,40276 +54533,40345,30675,40918 +54337,40346,30674,40153 +59558,40347,30673,40668 +56689,40348,30672,40841 +58261,40349,30671,40920 +50338,40350,30670,40027 +54331,40351,30669,40219 +50386,40352,30668,40762 +54106,40353,30667,40620 +50517,40354,30666,40301 +50571,40355,30665,40537 +52293,40356,30664,40416 +56374,40357,30663,40763 +55558,40358,30662,40846 +50000,40359,30661,40228 +57256,40360,30660,40432 +56847,40361,30659,40294 +53254,40362,30658,40295 +58457,40363,30657,40217 +53035,40364,30656,40314 +51994,40365,30655,40792 +55652,40366,30654,40516 +52403,40367,30653,40120 +54464,40368,30652,40486 +55088,40369,30651,40326 +51172,40370,30650,40340 +52930,40371,30649,40268 +53180,40372,30648,40207 +58379,40373,30647,40712 +56284,40374,30646,40831 +51065,40375,30645,40802 +52820,40376,30644,40026 +56953,40377,30643,40783 +54322,40378,30642,40069 +58829,40379,30641,40958 +56145,40380,30640,40957 +54056,40381,30639,40687 +59711,40382,30638,40499 +59269,40383,30637,40995 +50940,40384,30636,40682 +53512,40385,30635,40916 +55358,40386,30634,40574 +51308,40387,30633,40393 +50994,40388,30632,40147 +50172,40389,30631,40902 +59532,40390,30630,40391 +50205,40391,30629,40358 +57216,40392,30628,40645 +51192,40393,30627,40126 +55898,40394,30626,40495 +52006,40395,30625,40128 +57783,40396,30624,40711 +50675,40397,30623,40888 +52742,40398,30622,40938 +58373,40399,30621,40335 +52825,40400,30620,40785 +58390,40401,30619,40185 +50085,40402,30618,40278 +59917,40403,30617,40997 +58393,40404,30616,40335 +58492,40405,30615,40137 +59532,40406,30614,40490 +50194,40407,30613,40111 +52895,40408,30612,40734 +56927,40409,30611,40551 +55073,40410,30610,40145 +53560,40411,30609,40466 +54353,40412,30608,40131 +59473,40413,30607,40705 +58590,40414,30606,40118 +50295,40415,30605,40264 +54251,40416,30604,40905 +59920,40417,30603,40811 +53230,40418,30602,40551 +52825,40419,30601,40827 +59047,40420,30600,40009 +53599,40421,30599,40036 +52750,40422,30598,40421 +59242,40423,30597,40518 +52069,40424,30596,40624 +52067,40425,30595,40567 +53005,40426,30594,40655 +58919,40427,30593,40289 +56948,40428,30592,40342 +59859,40429,30591,40965 +57371,40430,30590,40332 +51823,40431,30589,40307 +52166,40432,30588,40227 +53175,40433,30587,40445 +56029,40434,30586,40879 +53428,40435,30585,40847 +57200,40436,30584,40147 +56922,40437,30583,40533 +58151,40438,30582,40762 +58074,40439,30581,40642 +59430,40440,30580,40768 +50024,40441,30579,40823 +50032,40442,30578,40206 +57687,40443,30577,40080 +54131,40444,30576,40892 +58800,40445,30575,40327 +56081,40446,30574,40038 +51761,40447,30573,40548 +57295,40448,30572,40894 +52626,40449,30571,40626 +54389,40450,30570,40514 +56242,40451,30569,40462 +53846,40452,30568,40081 +54033,40453,30567,40926 +57258,40454,30566,40743 +52759,40455,30565,40108 +58695,40456,30564,40658 +53825,40457,30563,40878 +52287,40458,30562,40905 +50124,40459,30561,40756 +54130,40460,30560,40152 +54697,40461,30559,40661 +17320,24209,30795,40000 +50017,40463,30557,40557 +54425,40464,30556,40764 +59282,40465,30555,40263 +51788,40466,30554,40730 +56360,40467,30553,40491 +54863,40468,30552,40856 +52199,40469,30551,40973 +53837,40470,30550,40399 +59843,40471,30549,40746 +53851,40472,30548,40186 +55539,40473,30547,40967 +58093,40474,30546,40380 +51386,40475,30545,40800 +53541,40476,30544,40791 +54069,40477,30543,40881 +54599,40478,30542,40963 +53299,40479,30541,40197 diff --git a/regression-test/suites/unique_with_mow_c_p0/test_schema_change_add_key_column.groovy b/regression-test/suites/unique_with_mow_c_p0/test_schema_change_add_key_column.groovy new file mode 100644 index 00000000000000..def763cd43c768 --- /dev/null +++ b/regression-test/suites/unique_with_mow_c_p0/test_schema_change_add_key_column.groovy @@ -0,0 +1,148 @@ +// 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. + +import org.awaitility.Awaitility +import static java.util.concurrent.TimeUnit.SECONDS + +suite("test_schema_change_add_key_column", "nonConcurrent") { + def tableName = "test_schema_change_add_key_column" + + def getAlterTableState = { + waitForSchemaChangeDone { + sql """ SHOW ALTER TABLE COLUMN WHERE tablename='${tableName}' ORDER BY createtime DESC LIMIT 1 """ + time 100 + } + return true + } + + def getTabletStatus = { rowsetNum, lastRowsetSegmentNum -> + def tablets = sql_return_maparray """ show tablets from ${tableName}; """ + logger.info("tablets: ${tablets}") + assertEquals(1, tablets.size()) + String compactionUrl = "" + for (Map tablet : tablets) { + compactionUrl = tablet["CompactionStatus"] + } + def (code, out, err) = curl("GET", compactionUrl) + logger.info("Show tablets status: code=" + code + ", out=" + out + ", err=" + err) + assertEquals(code, 0) + def tabletJson = parseJson(out.trim()) + assert tabletJson.rowsets instanceof List + assertTrue(tabletJson.rowsets.size() >= rowsetNum) + def rowset = tabletJson.rowsets.get(rowsetNum - 1) + logger.info("rowset: ${rowset}") + int start_index = rowset.indexOf("]") + int end_index = rowset.indexOf("DATA") + def segmentNumStr = rowset.substring(start_index + 1, end_index).trim() + logger.info("segmentNumStr: ${segmentNumStr}") + assertEquals(lastRowsetSegmentNum, Integer.parseInt(segmentNumStr)) + } + + // batch_size is 4164 in csv_reader.cpp + // _batch_size is 8192 in vtablet_writer.cpp + def backendId_to_params = get_be_param("doris_scanner_row_bytes") + onFinish { + GetDebugPoint().disableDebugPointForAllBEs("MemTable.need_flush") + set_original_be_param("doris_scanner_row_bytes", backendId_to_params) + } + GetDebugPoint().enableDebugPointForAllBEs("MemTable.need_flush") + set_be_param.call("doris_scanner_row_bytes", "1") + + for (int i = 0; i < 2; i++) { + tableName = "test_schema_change_add_key_column_" + i + sql """ DROP TABLE IF EXISTS ${tableName} """ + sql """ + CREATE TABLE IF NOT EXISTS ${tableName} ( + `k1` int(11) NULL, + `k2` int(11) NULL, + `v3` int(11) NULL, + `v4` int(11) NULL + ) unique KEY(`k1`, `k2`) + cluster by(`v3`, `v4`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 1 + PROPERTIES ( + """ + (i == 1 ? "\"function_column.sequence_col\"='v4', " : "") + + """ + "replication_num" = "1", + "disable_auto_compaction" = "true" + ); + """ + + streamLoad { + table "${tableName}" + set 'column_separator', ',' + file 'test_schema_change_add_key_column.csv' + time 10000 // limit inflight 10s + + check { result, exception, startTime, endTime -> + if (exception != null) { + throw exception + } + def json = parseJson(result) + assertEquals("success", json.Status.toLowerCase()) + assertEquals(8192, json.NumberTotalRows) + assertEquals(0, json.NumberFilteredRows) + } + } + // check generate 3 segments + sql """ select * from ${tableName} where `k1` = 12345; """ + getTabletStatus(2, 3) + + streamLoad { + table "${tableName}" + set 'column_separator', ',' + file 'test_schema_change_add_key_column1.csv' + time 10000 // limit inflight 10s + + check { result, exception, startTime, endTime -> + if (exception != null) { + throw exception + } + def json = parseJson(result) + assertEquals("success", json.Status.toLowerCase()) + assertEquals(20480, json.NumberTotalRows) + assertEquals(0, json.NumberFilteredRows) + } + } + // check generate 3 segments + sql """ select * from ${tableName} where `k1` = 12345; """ + getTabletStatus(3, 6) + + def rowCount1 = sql """ select count() from ${tableName}; """ + logger.info("rowCount1: ${rowCount1}") + + // do schema change + sql """ ALTER TABLE ${tableName} ADD COLUMN `k3` int(11) key """ + getAlterTableState() + // check generate 1 segments + getTabletStatus(2, 1) // [2-3] or [2-2] [3-3] + // getTabletStatus(3, 1) + + // check row count + def rowCount2 = sql """ select count() from ${tableName}; """ + logger.info("rowCount2: ${rowCount2}") + assertEquals(rowCount1[0][0], rowCount2[0][0]) + // check no duplicated key + def result = sql """ select `k1`, `k2`, count(*) a from ${tableName} group by `k1`, `k2` having a > 1; """ + logger.info("result: ${result}") + assertEquals(0, result.size()) + // check one row value + order_qt_select1 """ select * from ${tableName} where `k1` = 12345; """ + order_qt_select2 """ select * from ${tableName} where `k1` = 17320; """ + order_qt_select3 """ select * from ${tableName} where `k1` = 59832 and `k2` = 36673; """ + } +} From 483c56ea1476a94586d7ff719f0e27416f4d2700 Mon Sep 17 00:00:00 2001 From: wuwenchi Date: Thu, 12 Dec 2024 12:28:08 +0800 Subject: [PATCH 19/63] [fix](hive)Clear processed tasks (#45309) ### What problem does this PR solve? Problem Summary: Clear processed tasks, or it will be executed twice. --- .../doris/datasource/hive/HMSTransaction.java | 12 ++++++ .../doris/datasource/hive/HmsCommitTest.java | 40 ++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HMSTransaction.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HMSTransaction.java index 02c99a695c8b5e..9b88f7a8dea83b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HMSTransaction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/HMSTransaction.java @@ -534,6 +534,11 @@ public List getPartitions() { return partitions; } + public void clear() { + partitions.clear(); + createdPartitionValues.clear(); + } + public void addPartition(HivePartitionWithStatistics partition) { partitions.add(partition); } @@ -1143,6 +1148,7 @@ private void undoUpdateStatisticsTasks() { for (CompletableFuture undoUpdateFuture : undoUpdateFutures.build()) { MoreFutures.getFutureValue(undoUpdateFuture); } + updateStatisticsTasks.clear(); } private void undoAddPartitionsTask() { @@ -1157,6 +1163,7 @@ private void undoAddPartitionsTask() { LOG.warn("Failed to rollback: add_partition for partition values {}.{}", tableInfo, rollbackFailedPartitions); } + addPartitionsTask.clear(); } private void waitForAsyncFileSystemTaskSuppressThrowable() { @@ -1169,6 +1176,7 @@ private void waitForAsyncFileSystemTaskSuppressThrowable() { // ignore } } + asyncFileSystemTaskFutures.clear(); } public void prepareInsertExistingTable(SimpleTableInfo tableInfo, TableAndMore tableAndMore) { @@ -1319,6 +1327,7 @@ private void runDirectoryClearUpTasksForAbort() { for (DirectoryCleanUpTask cleanUpTask : directoryCleanUpTasksForAbort) { recursiveDeleteItems(cleanUpTask.getPath(), cleanUpTask.isDeleteEmptyDir(), false); } + directoryCleanUpTasksForAbort.clear(); } private void runRenameDirTasksForAbort() { @@ -1334,6 +1343,7 @@ private void runRenameDirTasksForAbort() { } } } + renameDirectoryTasksForAbort.clear(); } private void runClearPathsForFinish() { @@ -1486,6 +1496,7 @@ private void abortMultiUploads() { .build()); }, fileSystemExecutor)); } + uncompletedMpuPendingUploads.clear(); } public void doNothing() { @@ -1520,6 +1531,7 @@ public void rollback() { for (CompletableFuture future : asyncFileSystemTaskFutures) { MoreFutures.getFutureValue(future, RuntimeException.class); } + asyncFileSystemTaskFutures.clear(); } public void shutdownExecutorService() { diff --git a/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HmsCommitTest.java b/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HmsCommitTest.java index 0e79f8ee2b56cd..61b373706d9f75 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HmsCommitTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HmsCommitTest.java @@ -675,5 +675,43 @@ public void testRollbackNewPartitionForPartitionedTableWithNewAppendPartition() Partition pa = hmsClient.getPartition(dbName, tbWithPartition, Lists.newArrayList("a")); assertNumRows(3, pa); } -} + @Test + public void testCommitWithRollback() { + genQueryID(); + List pus = new ArrayList<>(); + try { + pus.add(createRandomAppend(null)); + pus.add(createRandomAppend(null)); + pus.add(createRandomAppend(null)); + } catch (Throwable t) { + Assert.fail(); + } + + mockDoOther(() -> { + Table table = hmsClient.getTable(dbName, tbWithoutPartition); + assertNumRows(3, table); + }); + + HMSTransaction hmsTransaction = new HMSTransaction(hmsOps, fileSystemProvider, fileSystemExecutor); + try { + hmsTransaction.setHivePartitionUpdates(pus); + HiveInsertCommandContext ctx = new HiveInsertCommandContext(); + String queryId = DebugUtil.printId(ConnectContext.get().queryId()); + ctx.setQueryId(queryId); + ctx.setWritePath(getWritePath()); + hmsTransaction.beginInsertTable(ctx); + hmsTransaction.finishInsertTable(new SimpleTableInfo(dbName, tbWithoutPartition)); + hmsTransaction.commit(); + Assert.fail(); + } catch (Throwable t) { + Assert.assertTrue(t.getMessage().contains("failed to do nothing")); + } + + try { + hmsTransaction.rollback(); + } catch (Throwable t) { + Assert.fail(); + } + } +} From 742e441dd70e494ea3f35a5779e7a21cd211850d Mon Sep 17 00:00:00 2001 From: wuwenchi Date: Thu, 12 Dec 2024 12:28:24 +0800 Subject: [PATCH 20/63] [fix](iceberg)Fill in the detailed error information (#45285) ### What problem does this PR solve? Problem Summary: When dropping a database, fill in the detailed error information. --- .../iceberg/IcebergMetadataOps.java | 3 ++- .../iceberg/CreateIcebergTableTest.java | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java index 970814b7acdc85..440a671afe58f1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java @@ -160,7 +160,8 @@ public void dropDb(DropDbStmt stmt) throws DdlException { return null; }); } catch (Exception e) { - throw new DdlException("Failed to drop database: " + stmt.getDbName() + " ,error message is: ", e); + throw new DdlException( + "Failed to drop database: " + stmt.getDbName() + ", error message is: " + e.getMessage(), e); } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/CreateIcebergTableTest.java b/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/CreateIcebergTableTest.java index 1c780d63c9cd8b..439f6f2aa7de21 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/CreateIcebergTableTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/CreateIcebergTableTest.java @@ -21,6 +21,8 @@ import org.apache.doris.analysis.CreateDbStmt; import org.apache.doris.analysis.CreateTableStmt; import org.apache.doris.analysis.DbName; +import org.apache.doris.analysis.DropDbStmt; +import org.apache.doris.common.DdlException; import org.apache.doris.common.UserException; import org.apache.doris.datasource.CatalogFactory; import org.apache.doris.nereids.parser.NereidsParser; @@ -201,4 +203,28 @@ public String getTableName() { String s = "test_tb_" + UUID.randomUUID(); return s.replaceAll("-", ""); } + + @Test + public void testDropDB() { + String dbName = "db_to_delete"; + CreateDbStmt createDBStmt = new CreateDbStmt(false, new DbName("iceberg", dbName), new HashMap<>()); + DropDbStmt dropDbStmt = new DropDbStmt(false, new DbName("iceberg", dbName), false); + DropDbStmt dropDbStmt2 = new DropDbStmt(false, new DbName("iceberg", "not_exists"), false); + try { + // create db success + ops.createDb(createDBStmt); + // drop db success + ops.dropDb(dropDbStmt); + } catch (Throwable t) { + Assert.fail(); + } + + try { + ops.dropDb(dropDbStmt2); + Assert.fail(); + } catch (Throwable t) { + Assert.assertTrue(t instanceof DdlException); + Assert.assertTrue(t.getMessage().contains("database doesn't exist")); + } + } } From 03407546ab53f98cb00f99990d8336aff4b342fe Mon Sep 17 00:00:00 2001 From: Calvin Kirs Date: Thu, 12 Dec 2024 12:50:49 +0800 Subject: [PATCH 21/63] [Fix](job-case)Fix status typo (#45326) ### What problem does this PR solve? Task cancellation status should be CANCELED --- regression-test/suites/job_p0/test_base_insert_job.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression-test/suites/job_p0/test_base_insert_job.groovy b/regression-test/suites/job_p0/test_base_insert_job.groovy index fc97e367483b86..2bdf96cd5bdc3f 100644 --- a/regression-test/suites/job_p0/test_base_insert_job.groovy +++ b/regression-test/suites/job_p0/test_base_insert_job.groovy @@ -116,7 +116,7 @@ suite("test_base_insert_job") { def taskStatus = sql """select status from tasks("type"="insert") where JobName ='${jobName}'""" for (int i = 0; i < taskStatus.size(); i++) { - assert taskStatus.get(i).get(0) =="CANCELLED" || taskStatus.get(i).get(0) =="FINISHED" + assert taskStatus.get(i).get(0) =="CANCELED" || taskStatus.get(i).get(0) =="FINISHED" } sql """ CREATE JOB ${jobMixedName} ON SCHEDULE every 1 second DO insert into ${tableName} (timestamp, type, user_id) values ('2023-03-18','1','12213'); From 069a33a2faca6dbfa58800698c1257a42a6e6c25 Mon Sep 17 00:00:00 2001 From: bobhan1 Date: Thu, 12 Dec 2024 14:52:56 +0800 Subject: [PATCH 22/63] [fix](regression) Fix some p0 case (#45333) ### What problem does this PR solve? fix `test_partial_update_2pc_schema_change` and `test_f_2pc_schema_change` case due to changes in https://github.com/apache/doris/pull/45211 --- .../test_partial_update_2pc_schema_change.groovy | 5 +++-- .../flexible/legacy/test_f_2pc_schema_change.groovy | 5 +++-- .../test_partial_update_2pc_schema_change.groovy | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_2pc_schema_change.groovy b/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_2pc_schema_change.groovy index e7205620ef319f..6b3c4572dab28b 100644 --- a/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_2pc_schema_change.groovy +++ b/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_2pc_schema_change.groovy @@ -38,11 +38,12 @@ suite("test_partial_update_2pc_schema_change", "p0") { String db = context.config.getDbNameByFile(context.file) sql "select 1;" // to create database - + def user = context.config.jdbcUser + def password = context.config.jdbcPassword for (def use_row_store : [false, true]) { logger.info("current params: use_row_store: ${use_row_store}") - connect( context.config.jdbcUser, context.config.jdbcPassword, context.config.jdbcUrl) { + connect( user, password, context.config.jdbcUrl) { sql "use ${db};" def tableName = "test_partial_update_2pc_schema_change" diff --git a/regression-test/suites/unique_with_mow_p0/flexible/legacy/test_f_2pc_schema_change.groovy b/regression-test/suites/unique_with_mow_p0/flexible/legacy/test_f_2pc_schema_change.groovy index 23a9dce1001eb0..776fad1da782c7 100644 --- a/regression-test/suites/unique_with_mow_p0/flexible/legacy/test_f_2pc_schema_change.groovy +++ b/regression-test/suites/unique_with_mow_p0/flexible/legacy/test_f_2pc_schema_change.groovy @@ -37,14 +37,15 @@ import org.apache.http.util.EntityUtils suite("test_f_2pc_schema_change", "p0") { String db = context.config.getDbNameByFile(context.file) sql "select 1;" // to create database - + def user = context.config.jdbcUser + def password = context.config.jdbcPassword if (isCloudMode()) { return } for (def use_row_store : [false, true]) { logger.info("current params: use_row_store: ${use_row_store}") - connect( context.config.jdbcUser, context.config.jdbcPassword, context.config.jdbcUrl) { + connect( user, password, context.config.jdbcUrl) { sql "use ${db};" def tableName = "test_f_2pc_schema_change" diff --git a/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_2pc_schema_change.groovy b/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_2pc_schema_change.groovy index 9b323dec19c7a8..d506d0ee766e58 100644 --- a/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_2pc_schema_change.groovy +++ b/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_2pc_schema_change.groovy @@ -38,11 +38,12 @@ suite("test_partial_update_2pc_schema_change", "p0") { String db = context.config.getDbNameByFile(context.file) sql "select 1;" // to create database - + def user = context.config.jdbcUser + def password = context.config.jdbcPassword for (def use_row_store : [false, true]) { logger.info("current params: use_row_store: ${use_row_store}") - connect( context.config.jdbcUser, context.config.jdbcPassword, context.config.jdbcUrl) { + connect( user, password, context.config.jdbcUrl) { sql "use ${db};" def tableName = "test_partial_update_2pc_schema_change" From a139679ce0bec52ca4175af2929df96528b24f65 Mon Sep 17 00:00:00 2001 From: Dongyang Li Date: Thu, 12 Dec 2024 15:05:17 +0800 Subject: [PATCH 23/63] [opt](ci) debug "Reach limit of connections" (#45173) --- regression-test/pipeline/cloud_p0/run.sh | 6 ++- .../pipeline/common/doris-utils.sh | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/regression-test/pipeline/cloud_p0/run.sh b/regression-test/pipeline/cloud_p0/run.sh index 43847f86980c2a..c1e2570047696b 100644 --- a/regression-test/pipeline/cloud_p0/run.sh +++ b/regression-test/pipeline/cloud_p0/run.sh @@ -13,7 +13,7 @@ fi EOF ############################# run.sh content ######################################## # shellcheck source=/dev/null -# check_tpcds_table_rows, restart_doris, set_session_variable, check_tpcds_result +# check_tpcds_table_rows, restart_doris, set_session_variable, check_tpcds_result, _monitor_connection source "${teamcity_build_checkoutDir}"/regression-test/pipeline/common/doris-utils.sh # shellcheck source=/dev/null # create_an_issue_comment @@ -47,6 +47,9 @@ export DORIS_HOME exit_flag=0 need_collect_log=false +# monitoring the log files in "${DORIS_HOME}"/regression-test/log/ for keyword 'Reach limit of connections' +_monitor_regression_log & + # shellcheck disable=SC2317 run() { set -e @@ -72,7 +75,6 @@ run() { export JAVA_HOME if "${teamcity_build_checkoutDir}"/run-regression-test.sh \ --teamcity \ - --clean \ --run \ --times "${repeat_times_from_trigger:-1}" \ -parallel 18 \ diff --git a/regression-test/pipeline/common/doris-utils.sh b/regression-test/pipeline/common/doris-utils.sh index 51bc0bece7af28..5f549db3c805f2 100644 --- a/regression-test/pipeline/common/doris-utils.sh +++ b/regression-test/pipeline/common/doris-utils.sh @@ -510,6 +510,43 @@ function set_doris_session_variables_from_file() { fi } +_monitor_regression_log() { + if ! command -v inotifywait >/dev/null; then + apt install inotify-tools -y + fi + + # Path to the log directory + local LOG_DIR="${DORIS_HOME}"/regression-test/log + + # keyword to search for in the log files + local KEYWORD="Reach limit of connections" + + local query_port + query_port=$(get_doris_conf_value "${DORIS_HOME}"/fe/conf/fe.conf query_port) + + echo "INFO: start monitoring the log files in ${LOG_DIR} for the keyword '${KEYWORD}'" + + local start_row=1 + # Monitor the log directory for new files and changes, only one file + # shellcheck disable=SC2034 + inotifywait -m -e modify "${LOG_DIR}" | while read -r directory events filename; do + total_rows=$(wc -l "${directory}${filename}" | awk '{print $1}') + if [[ ${start_row} -ge ${total_rows} ]]; then + start_row=${total_rows} + fi + # shellcheck disable=SC2250 + if sed -n "${start_row},\$p" "${directory}${filename}" | grep -a -q "${KEYWORD}"; then + matched=$(grep -a -n "${KEYWORD}" "${directory}${filename}") + start_row=$(echo "${matched}" | tail -n1 | cut -d: -f1) + echo "WARNING: find '${matched}' in ${directory}${filename}, run 'show processlist;' to check the connections" | tee -a "${DORIS_HOME}"/fe/log/monitor_regression_log.out + mysql -h127.0.0.1 -P"${query_port}" -uroot -e'show processlist;' | tee -a "${DORIS_HOME}"/fe/log/monitor_regression_log.out + fi + start_row=$((start_row + 1)) + # echo "start_row ${start_row}" | tee -a "${DORIS_HOME}"/fe/log/monitor_regression_log.out + done + +} + archive_doris_logs() { if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi local archive_name="$1" From 92015d941dd5e88fea1de7b08e2968374c4c4941 Mon Sep 17 00:00:00 2001 From: zhangstar333 Date: Thu, 12 Dec 2024 15:30:14 +0800 Subject: [PATCH 24/63] [bug](function) fix first/last value return error with ignore null (#44996) ### What problem does this PR solve? Problem Summary: needs another prs of FE: https://github.com/apache/doris/pull/45065 https://github.com/apache/doris/pull/45264 1. the first value even if have set value, should not return directly, need check it whether need arg_ignore_null, as maybe it's NULL 2. the last_value if need arg_ignore_null and not set value, should find in while loop, if find could return directly, not find check iff has any value before ### Release note fix first_value/last_value return error with ignore null param is true --- .../exec/analytic_source_operator.cpp | 14 +- .../aggregate_function_reader_first_last.h | 2 + .../aggregate_function_window.cpp | 2 + .../aggregate_function_window.h | 49 +++-- .../test_first_value_window.out | 100 +++++++++ .../test_first_value_window.groovy | 189 ++++++++++++++++++ 6 files changed, 328 insertions(+), 28 deletions(-) diff --git a/be/src/pipeline/exec/analytic_source_operator.cpp b/be/src/pipeline/exec/analytic_source_operator.cpp index 3a9156f45b6758..fe0ab0b148e55a 100644 --- a/be/src/pipeline/exec/analytic_source_operator.cpp +++ b/be/src/pipeline/exec/analytic_source_operator.cpp @@ -352,17 +352,17 @@ Status AnalyticLocalState::_get_next_for_rows(size_t current_block_rows) { int64_t range_start, range_end; if (!_parent->cast()._window.__isset.window_start && _parent->cast()._window.window_end.type == - TAnalyticWindowBoundaryType:: - CURRENT_ROW) { //[preceding, current_row],[current_row, following] + TAnalyticWindowBoundaryType::CURRENT_ROW) { + // [preceding, current_row], [current_row, following] rewrite it's same + // as could reuse the previous calculate result, so don't call _reset_agg_status function + // going on calculate, add up data, no need to reset state range_start = _shared_state->current_row_position; - range_end = _shared_state->current_row_position + - 1; //going on calculate,add up data, no need to reset state + range_end = _shared_state->current_row_position + 1; } else { _reset_agg_status(); range_end = _shared_state->current_row_position + _rows_end_offset + 1; - if (!_parent->cast() - ._window.__isset - .window_start) { //[preceding, offset] --unbound: [preceding, following] + //[preceding, offset] --unbound: [preceding, following] + if (!_parent->cast()._window.__isset.window_start) { range_start = _partition_by_start.pos; } else { range_start = _shared_state->current_row_position + _rows_start_offset; diff --git a/be/src/vec/aggregate_functions/aggregate_function_reader_first_last.h b/be/src/vec/aggregate_functions/aggregate_function_reader_first_last.h index 2657feb9380acd..8efea2dc6fc8e4 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_reader_first_last.h +++ b/be/src/vec/aggregate_functions/aggregate_function_reader_first_last.h @@ -142,6 +142,8 @@ struct ReaderFirstAndLastData { bool has_set_value() { return _has_value; } + bool is_null() { return _data_value.is_null(); } + protected: StoreType _data_value; bool _has_value = false; diff --git a/be/src/vec/aggregate_functions/aggregate_function_window.cpp b/be/src/vec/aggregate_functions/aggregate_function_window.cpp index fcb0072abe8d6f..9df45611f0fc95 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_window.cpp +++ b/be/src/vec/aggregate_functions/aggregate_function_window.cpp @@ -41,6 +41,8 @@ AggregateFunctionPtr create_function_lead_lag_first_last(const String& name, WhichDataType which(*type); bool arg_ignore_null_value = false; + // FE have rewrite case first_value(k1,false)--->first_value(k1) + // so size is 2, must will be arg_ignore_null_value if (argument_types.size() == 2) { DCHECK(name == "first_value" || name == "last_value") << "invalid function name: " << name; arg_ignore_null_value = true; diff --git a/be/src/vec/aggregate_functions/aggregate_function_window.h b/be/src/vec/aggregate_functions/aggregate_function_window.h index 0011ae3aba96b3..13fa8e74751df6 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_window.h +++ b/be/src/vec/aggregate_functions/aggregate_function_window.h @@ -455,31 +455,28 @@ struct WindowFunctionLagImpl : Data { static const char* name() { return "lag"; } }; -// TODO: first_value && last_value in some corner case will be core, -// if need to simply change it, should set them to always nullable insert into null value, and register in cpp maybe be change -// But it's may be another better way to handle it template struct WindowFunctionFirstImpl : Data { void add_range_single_place(int64_t partition_start, int64_t partition_end, int64_t frame_start, int64_t frame_end, const IColumn** columns) { - if (this->has_set_value()) { + // case 1: (has_set_value() = true && arg_ignore_null = false) + // case 2: (has_set_value() = true && arg_ignore_null = true && is_null() = false) + if ((this->has_set_value()) && + (!arg_ignore_null || (arg_ignore_null && !this->is_null()))) { return; } - if (frame_start <= frame_end && - frame_end <= partition_start) { //rewrite last_value when under partition - this->set_is_null(); //so no need more judge + DCHECK_LE(frame_start, frame_end); + if (frame_start >= partition_end || frame_end <= partition_start) { + this->set_is_null(); return; } frame_start = std::max(frame_start, partition_start); if constexpr (arg_ignore_null) { frame_end = std::min(frame_end, partition_end); - - auto& second_arg = assert_cast&>(*columns[1]); - auto ignore_null_value = second_arg.get_data()[0]; - - if (ignore_null_value && columns[0]->is_nullable()) { - auto& arg_nullable = assert_cast(*columns[0]); + if (columns[0]->is_nullable()) { + const auto& arg_nullable = assert_cast(*columns[0]); + // the valid range is: [frame_start, frame_end) while (frame_start < frame_end - 1 && arg_nullable.is_null_at(frame_start)) { frame_start++; } @@ -505,15 +502,25 @@ struct WindowFunctionLastImpl : Data { if constexpr (arg_ignore_null) { frame_start = std::max(frame_start, partition_start); - - auto& second_arg = assert_cast&>(*columns[1]); - auto ignore_null_value = second_arg.get_data()[0]; - - if (ignore_null_value && columns[0]->is_nullable()) { - auto& arg_nullable = assert_cast(*columns[0]); - while (frame_start < (frame_end - 1) && arg_nullable.is_null_at(frame_end - 1)) { - frame_end--; + if (columns[0]->is_nullable()) { + const auto& arg_nullable = assert_cast(*columns[0]); + // wants find a not null value in [frame_start, frame_end) + // iff has find: set_value and return directly + // iff not find: the while loop is finished + // case 1: iff has_set_value, means the previous window have value, could reuse it, so return directly + // case 2: iff not has_set_value, means there is none value, set it's to NULL + while (frame_start < frame_end) { + if (arg_nullable.is_null_at(frame_end - 1)) { + frame_end--; + } else { + this->set_value(columns, frame_end - 1); + return; + } } + if (!this->has_set_value()) { + this->set_is_null(); + } + return; } } diff --git a/regression-test/data/correctness_p0/test_first_value_window.out b/regression-test/data/correctness_p0/test_first_value_window.out index 9951ad95c60bf4..73dbcf3ed34eda 100644 --- a/regression-test/data/correctness_p0/test_first_value_window.out +++ b/regression-test/data/correctness_p0/test_first_value_window.out @@ -41,3 +41,103 @@ 11 23 04-23-13 \N 10 10 10 12 24 02-24-10-21 \N \N \N \N +-- !select_default4 -- +a 1 1 1 0 +a \N 1 \N 1 +a \N 1 \N 2 +a \N 1 \N 3 +b \N \N \N 4 +b 3 3 3 5 +b \N 3 \N 6 +b 2 2 2 7 + +-- !select_default5 -- +a \N \N \N 0 +a 1 1 \N 1 +a \N 1 \N 2 +a \N 1 \N 3 +b \N \N \N 4 +b 3 3 \N 5 +b \N 3 \N 6 +b 2 3 \N 7 + +-- !select_default_desc -- +a 2 3 +a \N 2 +a \N 1 +a 1 0 +b 2 7 +b \N 6 +b 3 5 +b \N 4 + +-- !select_default_asc -- +a 1 0 +a \N 1 +a \N 2 +a 2 3 +b \N 4 +b 3 5 +b \N 6 +b 2 7 + +-- !select_default_last_rewrite_first -- +a 1 1 0 +a \N 1 1 +a \N 1 2 +a 2 1 3 +b \N \N 4 +b 3 3 5 +b \N 3 6 +b 2 3 7 + +-- !select_default6 -- +a \N 2 \N 0 +a 1 2 1 1 +a 2 2 2 2 +a \N 2 2 3 +b \N 2 \N 4 +b 3 2 3 5 +b \N 2 3 6 +b 2 2 2 7 + +-- !select_default_last_rewrite_first2 -- +a 1 1 0 +a \N 1 1 +a \N 1 2 +a 2 2 3 +b \N \N 4 +b 3 3 5 +b \N 3 6 +b 2 2 7 + +-- !select_default7 -- +a 1 1 1 1 1 0 +a \N 1 1 1 1 1 +a \N 1 1 1 1 2 +a 2 2 2 2 1 3 +b \N \N \N \N \N 4 +b 3 3 3 3 3 5 +b \N 3 3 3 3 6 +b 2 2 2 2 3 7 + +-- !select_default8 -- +a 1 2 0 +a \N \N 1 +a \N \N 2 +a 2 \N 3 +b \N 2 4 +b 3 \N 5 +b \N \N 6 +b 2 \N 7 + +-- !select_default9 -- +a 1 2 0 +a \N \N 1 +a \N \N 2 +a 2 \N 3 +b \N 2 4 +b 3 \N 5 +b \N \N 6 +b 2 \N 7 + diff --git a/regression-test/suites/correctness_p0/test_first_value_window.groovy b/regression-test/suites/correctness_p0/test_first_value_window.groovy index 8d0a3097056d18..7c1582e0e61b60 100644 --- a/regression-test/suites/correctness_p0/test_first_value_window.groovy +++ b/regression-test/suites/correctness_p0/test_first_value_window.groovy @@ -159,4 +159,193 @@ suite("test_first_value_window") { ,first_value(`state`, 1) over(partition by `myday` order by `time_col` rows between 1 preceding and 1 following) v3 from ${tableName3} order by `id`, `myday`, `time_col`; """ + + qt_select_default4 """ + SELECT uid + ,amt + ,LAST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) amt1 + ,LAST_VALUE(amt, false) OVER(PARTITION BY uid ORDER BY time_s ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) amt2 + ,time_s + FROM ( + SELECT 'a' AS uid, 1 AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + ORDER BY uid, time_s + ; + """ + + qt_select_default5 """ + SELECT uid + ,amt + ,FIRST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) amt1 + ,FIRST_VALUE(amt, false) OVER(PARTITION BY uid ORDER BY time_s ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) amt2 + ,time_s + FROM ( + SELECT 'a' AS uid, NULL AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, 1 AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + ORDER BY uid, time_s + ; + """ + qt_select_default_desc """ + SELECT uid + ,amt + ,time_s + FROM ( + SELECT 'a' AS uid, 1 AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, 2 AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + order by uid,time_s desc; + """ + + qt_select_default_asc """ + SELECT uid + ,amt + ,time_s + FROM ( + SELECT 'a' AS uid, 1 AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, 2 AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + order by uid,time_s ASC; + """ + + // FIRST_VALUE: ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW + qt_select_default_last_rewrite_first """ + SELECT uid + ,amt + ,(LAST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)) amt3 + ,time_s + FROM ( + SELECT 'a' AS uid, 1 AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, 2 AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + ORDER BY uid, time_s; + """ + + qt_select_default6 """ + SELECT uid + ,amt + ,LAST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED following) amt1 + ,LAST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) amt2 + ,time_s + FROM ( + SELECT 'a' AS uid, null AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, 1 AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, 2 AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + ORDER BY uid, time_s + ; + """ + + //last value: ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW + qt_select_default_last_rewrite_first2 """ + SELECT uid + ,amt + ,(FIRST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)) amt3 + ,time_s + FROM ( + SELECT 'a' AS uid, 1 AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, 2 AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + ORDER BY uid, time_s; + """ + + qt_select_default7 """ + SELECT uid + ,amt + ,COALESCE(LAST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)) amt1 + ,COALESCE(LAST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s ASC ROWS BETWEEN 100 PRECEDING AND CURRENT ROW)) amt_not + ,COALESCE(FIRST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)) amt2 + ,COALESCE(LAST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s DESC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)) amt3 + ,time_s + FROM ( + SELECT 'a' AS uid, 1 AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, 2 AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + ORDER BY uid, time_s + ; + """ + + qt_select_default8 """ + SELECT uid + ,amt + ,(FIRST_VALUE(amt, true) OVER(PARTITION BY uid ORDER BY time_s ROWS between 3 following AND 6 FOLLOWING)) amt3 + ,time_s + FROM ( + SELECT 'a' AS uid, 1 AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, 2 AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + ORDER BY uid, time_s; + """ + + qt_select_default9 """ + SELECT uid + ,amt + ,(FIRST_VALUE(amt) OVER(PARTITION BY uid ORDER BY time_s ROWS between 3 following AND 6 FOLLOWING)) amt3 + ,time_s + FROM ( + SELECT 'a' AS uid, 1 AS amt, 0 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 1 AS time_s UNION ALL + SELECT 'a' AS uid, null AS amt, 2 AS time_s UNION ALL + SELECT 'a' AS uid, 2 AS amt, 3 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 4 AS time_s UNION ALL + SELECT 'b' AS uid, 3 AS amt, 5 AS time_s UNION ALL + SELECT 'b' AS uid, null AS amt, 6 AS time_s UNION ALL + SELECT 'b' AS uid, 2 AS amt, 7 AS time_s + ) t + ORDER BY uid, time_s; + """ } From 7e990d2812759ac84afdf555563bbc0450ac0531 Mon Sep 17 00:00:00 2001 From: zclllhhjj Date: Thu, 12 Dec 2024 15:48:05 +0800 Subject: [PATCH 25/63] [chore](test) Refactor fold constant test util in regression test (#45266) make an abstract in `Suite.groovy`. no need to print result in `.out` files. --- .../data/correctness/test_str_to_date.out | 45 ------------- .../math_functions/test_conv.out | 54 ---------------- .../nereids_syntax_p0/test_regexp_replace.out | 36 ----------- .../conditional_functions/test_json_parse.out | 63 ------------------- .../doris/regression/suite/Suite.groovy | 9 +++ .../correctness/test_str_to_date.groovy | 27 ++------ .../math_functions/test_conv.groovy | 28 ++------- .../test_regexp_replace.groovy | 24 ++----- .../test_json_parse.groovy | 30 +++------ .../string_functions/test_translate.groovy | 33 +++------- .../string_functions/test_trim_in.groovy | 36 ++++------- .../test_template_three_args.groovy | 20 ++---- .../test_template_two_args.groovy | 22 ++----- 13 files changed, 61 insertions(+), 366 deletions(-) diff --git a/regression-test/data/correctness/test_str_to_date.out b/regression-test/data/correctness/test_str_to_date.out index dfbb90e234b35c..f145ff9e4bedc8 100644 --- a/regression-test/data/correctness/test_str_to_date.out +++ b/regression-test/data/correctness/test_str_to_date.out @@ -53,48 +53,3 @@ 6 \N 7 \N --- !check_fe -- -2019-12-01 - --- !check_be -- -2019-12-01 - --- !check_no_fold -- -2019-12-01 - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - diff --git a/regression-test/data/nereids_p0/sql_functions/math_functions/test_conv.out b/regression-test/data/nereids_p0/sql_functions/math_functions/test_conv.out index db787d1daf1c1e..b10406e6456122 100644 --- a/regression-test/data/nereids_p0/sql_functions/math_functions/test_conv.out +++ b/regression-test/data/nereids_p0/sql_functions/math_functions/test_conv.out @@ -23,57 +23,3 @@ 10 2.789 11 3.14159 --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -1111 - --- !check_be -- -1111 - --- !check_no_fold -- -1111 - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -1111011 - --- !check_be -- -1111011 - --- !check_no_fold -- -1111011 - diff --git a/regression-test/data/nereids_syntax_p0/test_regexp_replace.out b/regression-test/data/nereids_syntax_p0/test_regexp_replace.out index f06114138f0dcc..578937e0ca1236 100644 --- a/regression-test/data/nereids_syntax_p0/test_regexp_replace.out +++ b/regression-test/data/nereids_syntax_p0/test_regexp_replace.out @@ -5,42 +5,6 @@ abcxyz -- !replace_chinese -- 汉123 --- !check_fe -- -abcxyz - --- !check_be -- -abcxyz - --- !check_no_fold -- -abcxyz - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - -- !replace_in_table_chinese -- 1 abc123 2 汉汉汉汉汉456 diff --git a/regression-test/data/query_p0/sql_functions/conditional_functions/test_json_parse.out b/regression-test/data/query_p0/sql_functions/conditional_functions/test_json_parse.out index 05b650de68a545..a40cd6937d1560 100644 --- a/regression-test/data/query_p0/sql_functions/conditional_functions/test_json_parse.out +++ b/regression-test/data/query_p0/sql_functions/conditional_functions/test_json_parse.out @@ -28,66 +28,3 @@ null 8 123 9 [1,2,3] --- !check_fe -- -{"key":"value"} - --- !check_be -- -{"key":"value"} - --- !check_no_fold -- -{"key":"value"} - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -\N - --- !check_be -- -\N - --- !check_no_fold -- -\N - --- !check_fe -- -null - --- !check_be -- -null - --- !check_no_fold -- -null - --- !check_fe -- -123 - --- !check_be -- -123 - --- !check_no_fold -- -123 - --- !check_fe -- -[1,2,3] - --- !check_be -- -[1,2,3] - --- !check_no_fold -- -[1,2,3] - diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy index d622084c24bd82..59722d72d952fe 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy @@ -2714,4 +2714,13 @@ class Suite implements GroovyInterceptable { scpFiles("root", be_ip, udf_file_path, udf_file_path, false) } } + + def check_fold_consistency = { test_sql -> + def re_fe = order_sql "select /*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" + def re_be = order_sql "select /*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" + def re_no_fold = order_sql "select /*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" + logger.info("check sql: ${test_sql}") + assertEquals(re_fe, re_be) + assertEquals(re_fe, re_no_fold) + } } diff --git a/regression-test/suites/correctness/test_str_to_date.groovy b/regression-test/suites/correctness/test_str_to_date.groovy index a45be14902ba56..75234b1f3b3afd 100644 --- a/regression-test/suites/correctness/test_str_to_date.groovy +++ b/regression-test/suites/correctness/test_str_to_date.groovy @@ -72,26 +72,9 @@ suite("test_str_to_date") { SELECT id, STR_TO_DATE(s1, s2) as result from test_str_to_date_db order by id; """ - def re_fe - def re_be - def re_no_fold - - def check_three_ways = { test_sql -> - re_fe = order_sql "select /*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" - re_be = order_sql "select /*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" - re_no_fold = order_sql "select /*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" - logger.info("check sql: ${test_sql}") - qt_check_fe "select /*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" - qt_check_be "select /*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" - qt_check_no_fold "select /*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" - assertEquals(re_fe, re_be) - assertEquals(re_fe, re_no_fold) - } - - check_three_ways "STR_TO_DATE('2019-12-01', 'yyyy-MM-dd')" - check_three_ways "STR_TO_DATE(null, 'yyyy-MM-dd')" - check_three_ways "STR_TO_DATE('2019-12-01', null)" - check_three_ways "STR_TO_DATE(null, null)" - check_three_ways "STR_TO_DATE('无效日期', 'yyyy-MM-dd')" + check_fold_consistency "STR_TO_DATE('2019-12-01', 'yyyy-MM-dd')" + check_fold_consistency "STR_TO_DATE(null, 'yyyy-MM-dd')" + check_fold_consistency "STR_TO_DATE('2019-12-01', null)" + check_fold_consistency "STR_TO_DATE(null, null)" + check_fold_consistency "STR_TO_DATE('无效日期', 'yyyy-MM-dd')" } - diff --git a/regression-test/suites/nereids_p0/sql_functions/math_functions/test_conv.groovy b/regression-test/suites/nereids_p0/sql_functions/math_functions/test_conv.groovy index 631df018fbd726..1fa0bdcfc03ff9 100644 --- a/regression-test/suites/nereids_p0/sql_functions/math_functions/test_conv.groovy +++ b/regression-test/suites/nereids_p0/sql_functions/math_functions/test_conv.groovy @@ -36,26 +36,10 @@ suite("test_conv") { qt_select6 """ select conv(float_2,10,2), float_2 from test_tb_with_null; """ - def re_fe - def re_be - def re_no_fold - - def check_three_ways = { test_sql -> - re_fe = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" - re_be = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" - re_no_fold = order_sql "select/*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" - logger.info("check on sql: ${test_sql}") - qt_check_fe "select/*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" - qt_check_be "select/*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" - qt_check_no_fold "select/*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" - assertEquals(re_fe, re_be) - assertEquals(re_fe, re_no_fold) - } - - check_three_ways "conv(null, null, null)" - check_three_ways "conv(15, 10, 2)" - check_three_ways "conv(null, 10, 2)" - check_three_ways "conv(15, null, 2)" - check_three_ways "conv(15, 10, null)" - check_three_ways "conv('123', 10, 2)" + check_fold_consistency "conv(null, null, null)" + check_fold_consistency "conv(15, 10, 2)" + check_fold_consistency "conv(null, 10, 2)" + check_fold_consistency "conv(15, null, 2)" + check_fold_consistency "conv(15, 10, null)" + check_fold_consistency "conv('123', 10, 2)" } \ No newline at end of file diff --git a/regression-test/suites/nereids_syntax_p0/test_regexp_replace.groovy b/regression-test/suites/nereids_syntax_p0/test_regexp_replace.groovy index 33c6c845491c22..ff94b640022d6d 100644 --- a/regression-test/suites/nereids_syntax_p0/test_regexp_replace.groovy +++ b/regression-test/suites/nereids_syntax_p0/test_regexp_replace.groovy @@ -20,26 +20,10 @@ suite("test_regexp_replace") { qt_replace_chinese "SELECT regexp_replace('这是一个测试字符串123', '\\\\p{Han}+', '汉');" - def re_fe - def re_be - def re_no_fold - - def check_three_ways = { test_sql -> - re_fe = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" - re_be = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" - re_no_fold = order_sql "select/*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" - logger.info("check on sql: ${test_sql}") - qt_check_fe "select/*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" - qt_check_be "select/*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" - qt_check_no_fold "select/*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" - assertEquals(re_fe, re_be) - assertEquals(re_fe, re_no_fold) - } - - check_three_ways "regexp_replace('abc123', '123', 'xyz')" - check_three_ways "regexp_replace(null, 'abc', 'def')" - check_three_ways "regexp_replace('abc123', null, 'xyz')" - check_three_ways "regexp_replace('abc123', '123', null)" + check_fold_consistency "regexp_replace('abc123', '123', 'xyz')" + check_fold_consistency "regexp_replace(null, 'abc', 'def')" + check_fold_consistency "regexp_replace('abc123', null, 'xyz')" + check_fold_consistency "regexp_replace('abc123', '123', null)" sql """DROP TABLE IF EXISTS `test_table_for_regexp`;""" sql """CREATE TABLE test_table_for_regexp (id INT, name VARCHAR(100)) PROPERTIES ("replication_num"="1");""" diff --git a/regression-test/suites/query_p0/sql_functions/conditional_functions/test_json_parse.groovy b/regression-test/suites/query_p0/sql_functions/conditional_functions/test_json_parse.groovy index 11674695037218..a51138774dbc4b 100644 --- a/regression-test/suites/query_p0/sql_functions/conditional_functions/test_json_parse.groovy +++ b/regression-test/suites/query_p0/sql_functions/conditional_functions/test_json_parse.groovy @@ -42,28 +42,12 @@ suite("test_json_parse") { qt_parse_from_table "SELECT id, json_parse_error_to_null(json_str) FROM test_json_parse_table ORDER BY id;" - def re_fe - def re_be - def re_no_fold - - def check_three_ways = { test_sql -> - re_fe = order_sql "SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql};" - re_be = order_sql "SELECT /*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql};" - re_no_fold = order_sql "SELECT /*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql};" - logger.info("check on sql: ${test_sql}") - qt_check_fe "SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql};" - qt_check_be "SELECT /*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql};" - qt_check_no_fold "SELECT /*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql};" - assertEquals(re_fe, re_be) - assertEquals(re_fe, re_no_fold) - } - - check_three_ways "json_parse_error_to_null('{\"key\": \"value\"}')" - check_three_ways "json_parse_error_to_null('Invalid JSON')" - check_three_ways "json_parse_error_to_null(NULL)" - check_three_ways "json_parse_error_to_null('')" - check_three_ways "json_parse_error_to_null('null')" - check_three_ways "json_parse_error_to_null('123')" - check_three_ways "json_parse_error_to_null('[1, 2, 3]')" + check_fold_consistency "json_parse_error_to_null('{\"key\": \"value\"}')" + check_fold_consistency "json_parse_error_to_null('Invalid JSON')" + check_fold_consistency "json_parse_error_to_null(NULL)" + check_fold_consistency "json_parse_error_to_null('')" + check_fold_consistency "json_parse_error_to_null('null')" + check_fold_consistency "json_parse_error_to_null('123')" + check_fold_consistency "json_parse_error_to_null('[1, 2, 3]')" } diff --git a/regression-test/suites/query_p0/sql_functions/string_functions/test_translate.groovy b/regression-test/suites/query_p0/sql_functions/string_functions/test_translate.groovy index e63f42ae5b4cf5..e6ba0ed44f390e 100644 --- a/regression-test/suites/query_p0/sql_functions/string_functions/test_translate.groovy +++ b/regression-test/suites/query_p0/sql_functions/string_functions/test_translate.groovy @@ -88,30 +88,15 @@ suite("test_translate") { order_qt_const3 "select translate(b, a, 'abc') from test_translate" /// folding - def re_fe - def re_be - def re_no_fold - def check_three_ways = { test_sql -> - sql "set enable_fold_constant_by_be=false;" - re_fe = order_sql "select ${test_sql}" - sql "set enable_fold_constant_by_be=true;" - re_be = order_sql "select ${test_sql}" - sql "set debug_skip_fold_constant=true;" - re_no_fold = order_sql "select ${test_sql}" - logger.info("check on sql \${test_sql}") - assertEquals(re_fe, re_be) - assertEquals(re_fe, re_no_fold) - } - - check_three_ways "translate('abcd', '', '');" - check_three_ways "translate('abcda', 'a', 'z');" - check_three_ways "translate('abcd', 'ac', 'z');" - check_three_ways "translate('abcd', 'aac', 'zq');" - check_three_ways "translate('abcd', 'aac', 'zqx');" - check_three_ways "translate('abcd', 'aac', '中文x');" - check_three_ways "translate('中文', '中', '文');" - check_three_ways "translate('中文', '中', 'a');" - check_three_ways "translate('\tt\tt\tt', '\t', 't');" + check_fold_consistency "translate('abcd', '', '');" + check_fold_consistency "translate('abcda', 'a', 'z');" + check_fold_consistency "translate('abcd', 'ac', 'z');" + check_fold_consistency "translate('abcd', 'aac', 'zq');" + check_fold_consistency "translate('abcd', 'aac', 'zqx');" + check_fold_consistency "translate('abcd', 'aac', '中文x');" + check_fold_consistency "translate('中文', '中', '文');" + check_fold_consistency "translate('中文', '中', 'a');" + check_fold_consistency "translate('\tt\tt\tt', '\t', 't');" order_qt_1 "select translate('abcd', '', '');" order_qt_2 "select translate('abcd', 'a', 'z')" diff --git a/regression-test/suites/query_p0/sql_functions/string_functions/test_trim_in.groovy b/regression-test/suites/query_p0/sql_functions/string_functions/test_trim_in.groovy index ae6790fb0693e1..bf04ebb454a982 100644 --- a/regression-test/suites/query_p0/sql_functions/string_functions/test_trim_in.groovy +++ b/regression-test/suites/query_p0/sql_functions/string_functions/test_trim_in.groovy @@ -82,30 +82,18 @@ suite("test_trim_in") { /// folding - def re_fe - def re_be - def re_no_fold - def check_three_ways = { test_sql -> - re_fe = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" - re_be = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" - re_no_fold = order_sql "select/*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" - logger.info("check on sql ${test_sql}") - assertEquals(re_fe, re_be) - assertEquals(re_fe, re_no_fold) - } - - check_three_ways "trim_in(' hello world ', ' ld')" - check_three_ways "ltrim_in(' hello world ', ' ld')" - check_three_ways "rtrim_in(' hello world ', ' ld')" - check_three_ways "trim_in(' hello world ', ' ehlowrd')" - check_three_ways "ltrim_in(' hello world ', ' ehlowrd')" - check_three_ways "rtrim_in(' hello world ', ' ehlowrd')" - check_three_ways "trim_in(' hello world ', '')" - check_three_ways "ltrim_in(' hello world ', '')" - check_three_ways "rtrim_in(' hello world ', '')" - check_three_ways "trim_in(' hello world ', ' ')" - check_three_ways "ltrim_in(' hello world ', ' ')" - check_three_ways "rtrim_in(' hello world ', ' ')" + check_fold_consistency "trim_in(' hello world ', ' ld')" + check_fold_consistency "ltrim_in(' hello world ', ' ld')" + check_fold_consistency "rtrim_in(' hello world ', ' ld')" + check_fold_consistency "trim_in(' hello world ', ' ehlowrd')" + check_fold_consistency "ltrim_in(' hello world ', ' ehlowrd')" + check_fold_consistency "rtrim_in(' hello world ', ' ehlowrd')" + check_fold_consistency "trim_in(' hello world ', '')" + check_fold_consistency "ltrim_in(' hello world ', '')" + check_fold_consistency "rtrim_in(' hello world ', '')" + check_fold_consistency "trim_in(' hello world ', ' ')" + check_fold_consistency "ltrim_in(' hello world ', ' ')" + check_fold_consistency "rtrim_in(' hello world ', ' ')" order_qt_1 "SELECT ltrim_in('');" order_qt_2 "SELECT ltrim_in(' ');" diff --git a/regression-test/suites/query_p0/sql_functions/test_template_three_args.groovy b/regression-test/suites/query_p0/sql_functions/test_template_three_args.groovy index 13de80a0393024..64bb970c3f0cd6 100644 --- a/regression-test/suites/query_p0/sql_functions/test_template_three_args.groovy +++ b/regression-test/suites/query_p0/sql_functions/test_template_three_args.groovy @@ -95,20 +95,8 @@ suite("test_template_three_args") { order_qt_const3 "select concat(b, a, 'abc') from arg1_three_args" /// folding - def re_fe - def re_be - def re_no_fold - def check_three_ways = { test_sql -> - re_fe = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" - re_be = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" - re_no_fold = order_sql "select/*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" - logger.info("check on sql \${test_sql}") - assertEquals(re_fe, re_be) - assertEquals(re_fe, re_no_fold) - } - - check_three_ways "concat('', '', '')" - check_three_ways "concat('\\t\\t', '\\t\\t', '\\t\\t')" - check_three_ways "concat('中文', '中文', '中文')" - check_three_ways "concat('abcde', 'abcde', 'abcde')" + check_fold_consistency "concat('', '', '')" + check_fold_consistency "concat('\\t\\t', '\\t\\t', '\\t\\t')" + check_fold_consistency "concat('中文', '中文', '中文')" + check_fold_consistency "concat('abcde', 'abcde', 'abcde')" } \ No newline at end of file diff --git a/regression-test/suites/query_p0/sql_functions/test_template_two_args.groovy b/regression-test/suites/query_p0/sql_functions/test_template_two_args.groovy index 9d7e2643eca1c4..0794c79e817a40 100644 --- a/regression-test/suites/query_p0/sql_functions/test_template_two_args.groovy +++ b/regression-test/suites/query_p0/sql_functions/test_template_two_args.groovy @@ -88,21 +88,9 @@ suite("test_template_two_args") { order_qt_const_partial_nullable_no_null "select atan2(1e100, nullable(1e-10))" /// folding - def re_fe - def re_be - def re_no_fold - def check_three_ways = { test_sql -> - re_fe = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=false)*/ ${test_sql}" - re_be = order_sql "select/*+SET_VAR(enable_fold_constant_by_be=true)*/ ${test_sql}" - re_no_fold = order_sql "select/*+SET_VAR(debug_skip_fold_constant=true)*/ ${test_sql}" - logger.info("check on sql ${test_sql}") - assertEquals(re_fe, re_be) - assertEquals(re_fe, re_no_fold) - } - - check_three_ways "atan2(-1, -2)" - check_three_ways "atan2(-1e100, 3.14)" - check_three_ways "atan2(0, 0)" - check_three_ways "atan2(1e100, 1e100)" - check_three_ways "atan2(-0.5, 0.5)" + check_fold_consistency "atan2(-1, -2)" + check_fold_consistency "atan2(-1e100, 3.14)" + check_fold_consistency "atan2(0, 0)" + check_fold_consistency "atan2(1e100, 1e100)" + check_fold_consistency "atan2(-0.5, 0.5)" } \ No newline at end of file From 7335ea8a2c0d2959c801d96282559235ca929364 Mon Sep 17 00:00:00 2001 From: Rijesh Kunhi Parambattu <147430310+rijeshkp@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:22:41 +0530 Subject: [PATCH 26/63] [Enhancement] (nereids)implement showQueryProfileCommand in nereids (#45271) Issue Number: close #42772 --- .../org/apache/doris/nereids/DorisParser.g4 | 2 +- .../nereids/parser/LogicalPlanBuilder.java | 8 +++ .../doris/nereids/trees/plans/PlanType.java | 3 +- .../commands/ShowQueryProfileCommand.java | 55 +++++++++++++++++++ .../trees/plans/visitor/CommandVisitor.java | 6 ++ .../show/test_show_commands_nereids.groovy | 1 + 6 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowQueryProfileCommand.java diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index a385e1e5ddb3bb..274a354b63bc03 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -272,6 +272,7 @@ supportedShowStatement | SHOW TABLE CREATION ((FROM | IN) database=multipartIdentifier)? (LIKE STRING_LITERAL)? #showTableCreation | SHOW TABLET STORAGE FORMAT VERBOSE? #showTabletStorageFormat + | SHOW QUERY PROFILE queryIdPath=STRING_LITERAL #showQueryProfile ; supportedLoadStatement @@ -359,7 +360,6 @@ unsupportedShowStatement (FROM |IN) tableName=multipartIdentifier ((FROM | IN) database=multipartIdentifier)? #showIndex | SHOW TRANSACTION ((FROM | IN) database=multipartIdentifier)? wildWhere? #showTransaction - | SHOW QUERY PROFILE queryIdPath=STRING_LITERAL #showQueryProfile | SHOW CACHE HOTSPOT tablePath=STRING_LITERAL #showCacheHotSpot | SHOW SYNC JOB ((FROM | IN) database=multipartIdentifier)? #showSyncJob | SHOW CATALOG RECYCLE BIN wildWhere? #showCatalogRecycleBin diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index 12ae62bac10930..56de50d620eb6d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -266,6 +266,7 @@ import org.apache.doris.nereids.DorisParser.ShowProcContext; import org.apache.doris.nereids.DorisParser.ShowProcedureStatusContext; import org.apache.doris.nereids.DorisParser.ShowProcessListContext; +import org.apache.doris.nereids.DorisParser.ShowQueryProfileContext; import org.apache.doris.nereids.DorisParser.ShowReplicaDistributionContext; import org.apache.doris.nereids.DorisParser.ShowRepositoriesContext; import org.apache.doris.nereids.DorisParser.ShowRolesContext; @@ -573,6 +574,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowProcCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcedureStatusCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcessListCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowQueryProfileCommand; import org.apache.doris.nereids.trees.plans.commands.ShowReplicaDistributionCommand; import org.apache.doris.nereids.trees.plans.commands.ShowRepositoriesCommand; import org.apache.doris.nereids.trees.plans.commands.ShowRolesCommand; @@ -5043,5 +5045,11 @@ public LogicalPlan visitAdminShowTabletStorageFormat(AdminShowTabletStorageForma public LogicalPlan visitShowTabletStorageFormat(ShowTabletStorageFormatContext ctx) { return new ShowTabletStorageFormatCommand(ctx.VERBOSE() != null); } + + @Override + public LogicalPlan visitShowQueryProfile(ShowQueryProfileContext ctx) { + String queryIdPath = stripQuotes(ctx.queryIdPath.getText()); + return new ShowQueryProfileCommand(queryIdPath); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java index 9bab39c946b45b..204d4b07111bec 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java @@ -253,5 +253,6 @@ public enum PlanType { CREATE_WORKLOAD_GROUP_COMMAND, CREATE_FILE_COMMAND, CREATE_ROUTINE_LOAD_COMMAND, - SHOW_TABLE_CREATION_COMMAND + SHOW_TABLE_CREATION_COMMAND, + SHOW_QUERY_PROFILE_COMMAND } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowQueryProfileCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowQueryProfileCommand.java new file mode 100644 index 00000000000000..1fe63619d0125e --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowQueryProfileCommand.java @@ -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. + +package org.apache.doris.nereids.trees.plans.commands; + +import org.apache.doris.catalog.Env; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.common.Config; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.ShowResultSet; +import org.apache.doris.qe.StmtExecutor; + +/** + * Represents the command for SHOW COLLATION + */ +public class ShowQueryProfileCommand extends ShowCommand { + String queryIdPath; + + public ShowQueryProfileCommand(String queryIdPath) { + super(PlanType.SHOW_QUERY_PROFILE_COMMAND); + this.queryIdPath = queryIdPath; + } + + @Override + public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) throws Exception { + String selfHost = Env.getCurrentEnv().getSelfNode().getHost(); + int httpPort = Config.http_port; + String terminalMsg = String.format( + "try visit http://%s:%d/QueryProfile, show query/load profile syntax is a deprecated feature", + selfHost, httpPort); + throw new AnalysisException(terminalMsg); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitShowQueryProfileCommand(this, context); + } + +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java index 085b510b095e00..e2ac1c863e2f5a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java @@ -111,6 +111,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowProcCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcedureStatusCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcessListCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowQueryProfileCommand; import org.apache.doris.nereids.trees.plans.commands.ShowReplicaDistributionCommand; import org.apache.doris.nereids.trees.plans.commands.ShowRepositoriesCommand; import org.apache.doris.nereids.trees.plans.commands.ShowRolesCommand; @@ -631,4 +632,9 @@ default R visitShowTabletStorageFormatCommand(ShowTabletStorageFormatCommand sho C context) { return visitCommand(showTabletStorageFormatCommand, context); } + + default R visitShowQueryProfileCommand(ShowQueryProfileCommand showQueryProfileCommand, + C context) { + return visitCommand(showQueryProfileCommand, context); + } } diff --git a/regression-test/suites/nereids_p0/show/test_show_commands_nereids.groovy b/regression-test/suites/nereids_p0/show/test_show_commands_nereids.groovy index ee243b42d3209a..92367db345a254 100644 --- a/regression-test/suites/nereids_p0/show/test_show_commands_nereids.groovy +++ b/regression-test/suites/nereids_p0/show/test_show_commands_nereids.groovy @@ -28,4 +28,5 @@ suite("test_show_commands_nereids") { checkNereidsExecute("""show triggers;""") checkNereidsExecute("""show events;""") checkNereidsExecute("""show load profile "/";""") + checkNereidsExecute("""show query profile "/";""") } From 13add3c17164c1a5f33dcfd34b4b11932a16ee67 Mon Sep 17 00:00:00 2001 From: Calvin Kirs Date: Thu, 12 Dec 2024 16:42:19 +0800 Subject: [PATCH 27/63] [fix](job)Fix millisecond offset issue in time window scheduling trigger time calculation (#45176) ### Abstract: In the current time window scheduling logic, the calculation of trigger times was not strictly aligned to the second level, which could lead to millisecond offsets. This offset caused issues such as consecutive trigger times at 14:56:59 and 14:57:00, disrupting the correctness of the scheduling. This PR optimizes the calculation of trigger times to ensure that time points are strictly aligned to the second level, preventing the accumulation of millisecond errors. ### Issue Description: Under a specified window (e.g., 14:50:00 to 14:59:00) and a fixed interval (e.g., every minute), the scheduler generated erroneous trigger times such as: ``` | 2024-12-04 14:56:59 | | 2024-12-04 14:57:00 | | 2024-12-04 14:57:59 | | 2024-12-04 14:58:00 | ``` #### Cause: The current firstTriggerTime and the loop calculation did not strictly align trigger times to the second level, resulting in erroneous trigger points due to floating-point or millisecond offset accumulation. The end condition for the time window was not aligned to the second level, which could lead to additional trigger times being included. ### Fix: Modification 1: Strictly align the trigger time to the second level. --- .../org/apache/doris/common/util/TimeUtils.java | 11 +++++++++++ .../doris/job/base/JobExecutionConfiguration.java | 2 +- .../org/apache/doris/job/base/TimerDefinition.java | 7 ++++++- .../apache/doris/job/scheduler/JobScheduler.java | 13 +++++++++---- .../job/base/JobExecutionConfigurationTest.java | 7 +++++++ 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java b/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java index e7066846c30919..d88971a6e72bde 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java @@ -257,6 +257,17 @@ public static long timeStringToLong(String timeStr) { return d.getTime(); } + /** + * Converts a millisecond timestamp to a second-level timestamp. + * + * @param timestamp The millisecond timestamp to be converted. + * @return The timestamp rounded to the nearest second (in milliseconds). + */ + public static long convertToSecondTimestamp(long timestamp) { + // Divide by 1000 to convert to seconds, then multiply by 1000 to return to milliseconds with no fractional part + return (timestamp / 1000) * 1000; + } + public static long timeStringToLong(String timeStr, TimeZone timeZone) { DateTimeFormatter dateFormatTimeZone = getDatetimeFormatWithTimeZone(); dateFormatTimeZone.withZone(timeZone.toZoneId()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/base/JobExecutionConfiguration.java b/fe/fe-core/src/main/java/org/apache/doris/job/base/JobExecutionConfiguration.java index 4c6ef4d2037f86..d564b1143122ec 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/base/JobExecutionConfiguration.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/base/JobExecutionConfiguration.java @@ -155,7 +155,7 @@ private Long queryDelayTimeSecond(Long currentTimeMs, Long startTimeMs) { return 0L; } - return (startTimeMs - currentTimeMs) / 1000; + return (startTimeMs * 1000 / 1000 - currentTimeMs) / 1000; } // Returns a list of delay times in seconds for executing the job within the specified window diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/base/TimerDefinition.java b/fe/fe-core/src/main/java/org/apache/doris/job/base/TimerDefinition.java index 9068a18f693e12..96181877b9a568 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/base/TimerDefinition.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/base/TimerDefinition.java @@ -17,6 +17,7 @@ package org.apache.doris.job.base; +import org.apache.doris.common.util.TimeUtils; import org.apache.doris.job.common.IntervalUnit; import com.google.gson.annotations.SerializedName; @@ -40,11 +41,15 @@ public class TimerDefinition { public void checkParams() { if (null == startTimeMs) { - startTimeMs = System.currentTimeMillis() + intervalUnit.getIntervalMs(interval); + long currentTimeMs = TimeUtils.convertToSecondTimestamp(System.currentTimeMillis()); + startTimeMs = currentTimeMs + intervalUnit.getIntervalMs(interval); } if (null != endTimeMs && endTimeMs < startTimeMs) { throw new IllegalArgumentException("endTimeMs must be greater than the start time"); } + if (null != endTimeMs) { + endTimeMs = TimeUtils.convertToSecondTimestamp(endTimeMs); + } if (null != intervalUnit) { if (null == interval) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/scheduler/JobScheduler.java b/fe/fe-core/src/main/java/org/apache/doris/job/scheduler/JobScheduler.java index 921f333791cb44..2bd6fc04dace53 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/scheduler/JobScheduler.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/scheduler/JobScheduler.java @@ -84,7 +84,8 @@ public void start() { taskDisruptorGroupManager = new TaskDisruptorGroupManager(); taskDisruptorGroupManager.init(); this.timerJobDisruptor = taskDisruptorGroupManager.getDispatchDisruptor(); - latestBatchSchedulerTimerTaskTimeMs = System.currentTimeMillis(); + long currentTimeMs = TimeUtils.convertToSecondTimestamp(System.currentTimeMillis()); + latestBatchSchedulerTimerTaskTimeMs = currentTimeMs; batchSchedulerTimerJob(); cycleSystemSchedulerTasks(); } @@ -94,7 +95,8 @@ public void start() { * Jobs will be re-registered after the task is completed */ private void cycleSystemSchedulerTasks() { - log.info("re-register system scheduler timer tasks" + TimeUtils.longToTimeString(System.currentTimeMillis())); + log.info("re-register system scheduler timer tasks, time is " + TimeUtils + .longToTimeStringWithms(System.currentTimeMillis())); timerTaskScheduler.newTimeout(timeout -> { batchSchedulerTimerJob(); cycleSystemSchedulerTasks(); @@ -144,7 +146,9 @@ public void close() throws IOException { private void cycleTimerJobScheduler(T job, long startTimeWindowMs) { - List delaySeconds = job.getJobConfig().getTriggerDelayTimes(System.currentTimeMillis(), + long currentTimeMs = TimeUtils.convertToSecondTimestamp(System.currentTimeMillis()); + startTimeWindowMs = TimeUtils.convertToSecondTimestamp(startTimeWindowMs); + List delaySeconds = job.getJobConfig().getTriggerDelayTimes(currentTimeMs, startTimeWindowMs, latestBatchSchedulerTimerTaskTimeMs); if (CollectionUtils.isEmpty(delaySeconds)) { log.info("skip job {} scheduler timer job, delay seconds is empty", job.getJobName()); @@ -190,7 +194,8 @@ private void executeTimerJobIdsWithinLastTenMinutesWindow() { long lastTimeWindowMs = latestBatchSchedulerTimerTaskTimeMs; if (latestBatchSchedulerTimerTaskTimeMs < System.currentTimeMillis()) { - this.latestBatchSchedulerTimerTaskTimeMs = System.currentTimeMillis(); + long currentTimeMs = TimeUtils.convertToSecondTimestamp(System.currentTimeMillis()); + this.latestBatchSchedulerTimerTaskTimeMs = currentTimeMs; } this.latestBatchSchedulerTimerTaskTimeMs += BATCH_SCHEDULER_INTERVAL_MILLI_SECONDS; log.info("execute timer job ids within last ten minutes window, last time window is {}", diff --git a/fe/fe-core/src/test/java/org/apache/doris/job/base/JobExecutionConfigurationTest.java b/fe/fe-core/src/test/java/org/apache/doris/job/base/JobExecutionConfigurationTest.java index cce0a93c01daf8..163b2494189d90 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/job/base/JobExecutionConfigurationTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/job/base/JobExecutionConfigurationTest.java @@ -75,7 +75,14 @@ public void testGetTriggerDelayTimesRecurring() { timerDefinition.setInterval(1L); Assertions.assertEquals(3, configuration.getTriggerDelayTimes(second * 5 + 10L, second * 3, second * 7).size()); Assertions.assertEquals(3, configuration.getTriggerDelayTimes(second * 5, second * 5, second * 7).size()); + timerDefinition.setStartTimeMs(1672531200000L); + timerDefinition.setIntervalUnit(IntervalUnit.MINUTE); + timerDefinition.setInterval(1L); + Assertions.assertArrayEquals(new Long[]{0L}, configuration.getTriggerDelayTimes(1672531800000L, 1672531200000L, 1672531800000L).toArray()); + + List expectDelayTimes = configuration.getTriggerDelayTimes(1672531200000L, 1672531200000L, 1672531850000L); + Assertions.assertArrayEquals(new Long[]{0L, 60L, 120L, 180L, 240L, 300L, 360L, 420L, 480L, 540L, 600L}, expectDelayTimes.toArray()); } @Test From 947100f9fa81154eae3122c4c8c867d79dfdfbb1 Mon Sep 17 00:00:00 2001 From: Calvin Kirs Date: Thu, 12 Dec 2024 16:43:18 +0800 Subject: [PATCH 28/63] [Chore](dependencies)Upgrade Fe dependencies (#44872) ### What problem does this PR solve? upgrade guava to 32.2.1-jre upgrade zookeeper to 3.9.3 upgrade azure to 1.2.29 exclusion ini4j and lucene --- fe/fe-core/pom.xml | 19 +++++++++++++++++++ fe/pom.xml | 30 +++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/fe/fe-core/pom.xml b/fe/fe-core/pom.xml index 70678c4262de33..1b40974d7e8b19 100644 --- a/fe/fe-core/pom.xml +++ b/fe/fe-core/pom.xml @@ -347,6 +347,7 @@ under the License. com.alibaba.otter canal.client 1.1.6 + provided ch.qos.logback @@ -410,6 +411,7 @@ under the License. com.huaweicloud hadoop-huaweicloud ${huaweiobs.version} + ${obs.dependency.scope} jackson-databind @@ -421,6 +423,7 @@ under the License. com.qcloud.cos hadoop-cos ${tencentcos.version} + ${cos.dependency.scope} org.json @@ -758,6 +761,20 @@ under the License. com.qcloud cos_api 5.6.211 + + + ch.qos.logback + logback-core + + + com.thoughtworks.xstream + xstream + + + org.bouncycastle + bcprov-jdk15on + + com.qcloud @@ -768,6 +785,7 @@ under the License. com.huaweicloud esdk-obs-java-bundle [3.21.11,) + ${obs.dependency.scope} com.baidubce @@ -791,6 +809,7 @@ under the License. gcs-connector hadoop3-2.2.21 shaded + ${gcs.dependency.scope} * diff --git a/fe/pom.xml b/fe/pom.xml index 0d2e3f70aa6e6a..c0f78b4423d0ba 100644 --- a/fe/pom.xml +++ b/fe/pom.xml @@ -222,13 +222,20 @@ under the License. be-java-extensions + 2.1.1 + 1.11.4 + 1.13.1 + 3.4.3 + 0.15.0 + compile + compile + compile ${fe.dir}/../thirdparty ${fe.dir}/../ 1.2-SNAPSHOT UTF-8 - 2.1.1 1.8 1.8 @@ -248,7 +255,7 @@ under the License. 1.10.0 1.7 2.10.1 - 32.1.2-jre + 33.2.1-jre 2.16.0 0.11-a-czt02-cdh 3.18.2-GA @@ -301,7 +308,6 @@ under the License. 1.2.0 2.3.0 0.8.13 - 3.4.3 hudi-spark3.4.x 3.1.3 2.3.9 @@ -314,16 +320,13 @@ under the License. you can find avro version info in iceberg mvn repository --> 1.4.3 0.49.0-public - 1.11.4 17.0.0 - - 0.15.0 2.7.4-11 3.0.0-8 2.6.2 - 1.13.1 + 3.2.2 1.27.1 2.12.10 @@ -346,7 +349,7 @@ under the License. 2.7.18 5.3.39 1.8.4 - 3.9.2 + 3.9.3 2.4 2.4.0 1.70 @@ -372,7 +375,7 @@ under the License. 2.1.1 9.4 202 - 1.2.27 + 1.2.29 12.22.0 5.3.0 3.15.0 @@ -1319,6 +1322,10 @@ under the License. org.apache.arrow arrow-vector + + org.ini4j + ini4j + @@ -1651,6 +1658,11 @@ under the License. concurrent ${airlift.concurrent.version} + + org.bouncycastle + bcprov-jdk15on + test + com.azure azure-sdk-bom From eab8d9f454f8da8668f75b7f5e790bea6c6d85b2 Mon Sep 17 00:00:00 2001 From: walter Date: Thu, 12 Dec 2024 17:22:40 +0800 Subject: [PATCH 29/63] [fix](backup) Fix read compressed backup job from old version (#45343) --- fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java b/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java index 1c897368624f11..de12670807f20e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java @@ -1126,7 +1126,7 @@ public void readFields(DataInput in) throws IOException { ByteArrayInputStream byteStream = new ByteArrayInputStream(text.getBytes()); try (GZIPInputStream gzipStream = new GZIPInputStream(byteStream)) { try (DataInputStream stream = new DataInputStream(gzipStream)) { - readOthers(in); + readOthers(stream); } } } else { From a288b825a8374ce548456b1496916e5349c59d77 Mon Sep 17 00:00:00 2001 From: walter Date: Thu, 12 Dec 2024 19:29:53 +0800 Subject: [PATCH 30/63] [chore](config) Enable batch download by default (#45324) --- be/src/common/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp index c3d00e23c98e5e..08f1ca7dd58c5c 100644 --- a/be/src/common/config.cpp +++ b/be/src/common/config.cpp @@ -251,7 +251,7 @@ DEFINE_mInt32(download_low_speed_limit_kbps, "50"); // download low speed time(seconds) DEFINE_mInt32(download_low_speed_time, "300"); // whether to download small files in batch -DEFINE_mBool(enable_batch_download, "false"); +DEFINE_mBool(enable_batch_download, "true"); DEFINE_String(sys_log_dir, ""); DEFINE_String(user_function_dir, "${DORIS_HOME}/lib/udf"); From 09619fc03da5d87053325dc2f4710a8eba3a5a59 Mon Sep 17 00:00:00 2001 From: walter Date: Thu, 12 Dec 2024 19:34:29 +0800 Subject: [PATCH 31/63] [fix](persist) Fix TableAddOrDropInvertedIndicesInfo.equals and remove useless logs (#45335) --- .../src/main/java/org/apache/doris/persist/EditLog.java | 4 ---- .../doris/persist/TableAddOrDropInvertedIndicesInfo.java | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java index 73a2c6338da5d7..65a161157c8967 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java @@ -2086,15 +2086,11 @@ public void logModifyTableAddOrDropColumns(TableAddOrDropColumnsInfo info) { public void logModifyTableAddOrDropInvertedIndices(TableAddOrDropInvertedIndicesInfo info) { long logId = logEdit(OperationType.OP_MODIFY_TABLE_ADD_OR_DROP_INVERTED_INDICES, info); - LOG.info("walter log modify table add or drop inverted indices, infos: {}, json: {}", - info, info.toJson(), new RuntimeException("test")); Env.getCurrentEnv().getBinlogManager().addModifyTableAddOrDropInvertedIndices(info, logId); } public void logIndexChangeJob(IndexChangeJob indexChangeJob) { long logId = logEdit(OperationType.OP_INVERTED_INDEX_JOB, indexChangeJob); - LOG.info("walter log inverted index job, infos: {}, json: {}", - indexChangeJob, indexChangeJob.toJson(), new RuntimeException("test")); Env.getCurrentEnv().getBinlogManager().addIndexChangeJob(indexChangeJob, logId); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/TableAddOrDropInvertedIndicesInfo.java b/fe/fe-core/src/main/java/org/apache/doris/persist/TableAddOrDropInvertedIndicesInfo.java index 39a90046d2419e..effe33ce624dd1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/persist/TableAddOrDropInvertedIndicesInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/persist/TableAddOrDropInvertedIndicesInfo.java @@ -120,7 +120,7 @@ public boolean equals(Object obj) { TableAddOrDropInvertedIndicesInfo info = (TableAddOrDropInvertedIndicesInfo) obj; - return (dbId == info.dbId && tableId == tableId + return (dbId == info.dbId && tableId == info.tableId && indexSchemaMap.equals(info.indexSchemaMap) && indexes.equals(info.indexes) && alterInvertedIndexes.equals(info.alterInvertedIndexes) From c0f4c89c97071e201e662130c5dcec7e4dac4d69 Mon Sep 17 00:00:00 2001 From: abmdocrt Date: Thu, 12 Dec 2024 22:51:26 +0800 Subject: [PATCH 32/63] [Enhancement](Test) Add test config to recycler (#44761) --- cloud/src/common/config.h | 4 +++ cloud/src/recycler/meta_checker.cpp | 36 ++++++++++++++++++++++--- cloud/src/recycler/recycler.cpp | 41 ++++++++++++++++++++--------- 3 files changed, 65 insertions(+), 16 deletions(-) diff --git a/cloud/src/common/config.h b/cloud/src/common/config.h index ac4403aeb24a3c..5befb0f8b2105e 100644 --- a/cloud/src/common/config.h +++ b/cloud/src/common/config.h @@ -87,6 +87,10 @@ CONF_mInt64(recycler_sleep_before_scheduling_seconds, "60"); // log a warning if a recycle task takes longer than this duration CONF_mInt64(recycle_task_threshold_seconds, "10800"); // 3h +// force recycler to recycle all useless object. +// **just for TEST** +CONF_Bool(force_immediate_recycle, "false"); + CONF_String(test_s3_ak, ""); CONF_String(test_s3_sk, ""); CONF_String(test_s3_endpoint, ""); diff --git a/cloud/src/recycler/meta_checker.cpp b/cloud/src/recycler/meta_checker.cpp index 522015555de825..f1223068d4be6e 100644 --- a/cloud/src/recycler/meta_checker.cpp +++ b/cloud/src/recycler/meta_checker.cpp @@ -25,6 +25,7 @@ #include #include +#include "common/logging.h" #include "common/util.h" #include "meta-service/keys.h" #include "meta-service/txn_kv.h" @@ -54,6 +55,7 @@ struct PartitionInfo { int64_t db_id; int64_t table_id; int64_t partition_id; + int64_t tablet_id; int64_t visible_version; }; @@ -173,6 +175,9 @@ bool MetaChecker::check_fdb_by_fe_meta(MYSQL* conn) { MYSQL_ROW row = mysql_fetch_row(result); TabletInfo tablet_info = {0}; tablet_info.tablet_id = atoll(row[0]); + VLOG_DEBUG << "get tablet info log" + << ", db name" << elem.first << ", table name" << table + << ",tablet id" << tablet_info.tablet_id; tablet_info.schema_version = atoll(row[4]); tablets.push_back(std::move(tablet_info)); } @@ -201,6 +206,13 @@ bool MetaChecker::check_fdb_by_fe_meta(MYSQL* conn) { partition_info.db_id = atoll(row[4]); partition_info.table_id = atoll(row[5]); partition_info.partition_id = atoll(row[6]); + partition_info.tablet_id = tablet_info.tablet_id; + VLOG_DEBUG << "get partition info log" + << ", db id" << partition_info.db_id << ", table id" + << partition_info.table_id << ", partition id" + << partition_info.partition_id << ", tablet id" + << partition_info.tablet_id; + partitions.insert({partition_info.partition_id, std::move(partition_info)}); } } @@ -217,9 +229,16 @@ bool MetaChecker::check_fdb_by_fe_meta(MYSQL* conn) { int num_row = mysql_num_rows(result); for (int i = 0; i < num_row; ++i) { MYSQL_ROW row = mysql_fetch_row(result); - int partition_id = atoll(row[0]); - int visible_version = atoll(row[2]); + int64_t partition_id = atoll(row[0]); + int64_t visible_version = atoll(row[2]); partitions[partition_id].visible_version = visible_version; + VLOG_DEBUG << "get partition version log" + << ", db name" << elem.first << ", table name" << table + << ", raw partition id" << row[0] << ", first partition id" + << partition_id << ", db id" << partitions[partition_id].db_id + << ", table id" << partitions[partition_id].table_id + << ", second partition id" << partitions[partition_id].partition_id + << ", tablet id" << partitions[partition_id].tablet_id; } } mysql_free_result(result); @@ -354,14 +373,23 @@ bool MetaChecker::check_fdb_by_fe_meta(MYSQL* conn) { int64_t db_id = elem.second.db_id; int64_t table_id = elem.second.table_id; int64_t partition_id = elem.second.partition_id; + int64_t tablet_id = elem.second.tablet_id; std::string ver_key = partition_version_key({instance_id_, db_id, table_id, partition_id}); std::string ver_val; err = txn->get(ver_key, &ver_val); if (err == TxnErrorCode::TXN_KEY_NOT_FOUND) { - LOG(WARNING) << "version key not found, partition id: " << partition_id; + LOG_WARNING("version key not found.") + .tag("db id", db_id) + .tag("table id", table_id) + .tag("partition id", partition_id) + .tag("tablet id", tablet_id); return false; } else if (err != TxnErrorCode::TXN_OK) { - LOG(WARNING) << "failed to get version: " << partition_id; + LOG_WARNING("failed to get version.") + .tag("db id", db_id) + .tag("table id", table_id) + .tag("partition id", partition_id) + .tag("tablet id", tablet_id); return false; } diff --git a/cloud/src/recycler/recycler.cpp b/cloud/src/recycler/recycler.cpp index f7000ea379225f..6877d7e433b253 100644 --- a/cloud/src/recycler/recycler.cpp +++ b/cloud/src/recycler/recycler.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -747,7 +748,10 @@ int InstanceRecycler::recycle_indexes() { .tag("num_recycled", num_recycled); }); - auto calc_expiration = [](const RecycleIndexPB& index) { + auto calc_expiration = [](const RecycleIndexPB& index) -> int64_t { + if (config::force_immediate_recycle) { + return 0; + } int64_t expiration = index.expiration() > 0 ? index.expiration() : index.creation_time(); int64_t retention_seconds = config::retention_seconds; if (index.state() == RecycleIndexPB::DROPPED) { @@ -942,7 +946,10 @@ int InstanceRecycler::recycle_partitions() { .tag("num_recycled", num_recycled); }); - auto calc_expiration = [](const RecyclePartitionPB& partition) { + auto calc_expiration = [](const RecyclePartitionPB& partition) -> int64_t { + if (config::force_immediate_recycle) { + return 0; + } int64_t expiration = partition.expiration() > 0 ? partition.expiration() : partition.creation_time(); int64_t retention_seconds = config::retention_seconds; @@ -1686,7 +1693,10 @@ int InstanceRecycler::recycle_rowsets() { return 0; }; - auto calc_expiration = [](const RecycleRowsetPB& rs) { + auto calc_expiration = [](const RecycleRowsetPB& rs) -> int64_t { + if (config::force_immediate_recycle) { + return 0; + } // RecycleRowsetPB created by compacted or dropped rowset has no expiration time, and will be recycled when exceed retention time int64_t expiration = rs.expiration() > 0 ? rs.expiration() : rs.creation_time(); int64_t retention_seconds = config::retention_seconds; @@ -1923,8 +1933,9 @@ int InstanceRecycler::recycle_tmp_rowsets() { // ATTN: `txn_expiration` should > 0, however we use `creation_time` + a large `retention_time` (> 1 day in production environment) // when `txn_expiration` <= 0 in some unexpected situation (usually when there are bugs). This is usually safe, coz loading // duration or timeout always < `retention_time` in practice. - int64_t expiration = - rowset.txn_expiration() > 0 ? rowset.txn_expiration() : rowset.creation_time(); + int64_t expiration = config::force_immediate_recycle ? 0 + : rowset.txn_expiration() > 0 ? rowset.txn_expiration() + : rowset.creation_time(); VLOG_DEBUG << "recycle tmp rowset scan, key=" << hex(k) << " num_scanned=" << num_scanned << " num_expired=" << num_expired << " expiration=" << expiration << " txn_expiration=" << rowset.txn_expiration() @@ -2106,7 +2117,7 @@ int InstanceRecycler::abort_timeout_txn() { LOG_WARNING("malformed txn_running_pb").tag("key", hex(k)); return -1; } - if (txn_running_pb.timeout_time() > current_time) { + if (!config::force_immediate_recycle && txn_running_pb.timeout_time() > current_time) { return 0; } ++num_timeout; @@ -2196,7 +2207,8 @@ int InstanceRecycler::recycle_expired_txn_label() { LOG_WARNING("malformed txn_running_pb").tag("key", hex(k)); return -1; } - if ((recycle_txn_pb.has_immediate() && recycle_txn_pb.immediate()) || + if ((config::force_immediate_recycle) || + (recycle_txn_pb.has_immediate() && recycle_txn_pb.immediate()) || (recycle_txn_pb.creation_time() + config::label_keep_max_second * 1000L <= current_time)) { LOG_INFO("found recycle txn").tag("key", hex(k)); @@ -2492,14 +2504,16 @@ int InstanceRecycler::recycle_copy_jobs() { int64_t current_time = duration_cast(system_clock::now().time_since_epoch()).count(); if (copy_job.finish_time_ms() > 0) { - if (current_time < - copy_job.finish_time_ms() + config::copy_job_max_retention_second * 1000) { + if (!config::force_immediate_recycle && + current_time < copy_job.finish_time_ms() + + config::copy_job_max_retention_second * 1000) { return 0; } } else { // For compatibility, copy job does not contain finish time before 2.2.2, use start time - if (current_time < - copy_job.start_time_ms() + config::copy_job_max_retention_second * 1000) { + if (!config::force_immediate_recycle && + current_time < copy_job.start_time_ms() + + config::copy_job_max_retention_second * 1000) { return 0; } } @@ -2508,7 +2522,7 @@ int InstanceRecycler::recycle_copy_jobs() { int64_t current_time = duration_cast(system_clock::now().time_since_epoch()).count(); // if copy job is timeout: delete all copy file kvs and copy job kv - if (current_time <= copy_job.timeout_time_ms()) { + if (!config::force_immediate_recycle && current_time <= copy_job.timeout_time_ms()) { return 0; } ++num_expired; @@ -2796,6 +2810,9 @@ int InstanceRecycler::recycle_expired_stage_objects() { int64_t expiration_time = duration_cast(system_clock::now().time_since_epoch()).count() - config::internal_stage_objects_expire_time_second; + if (config::force_immediate_recycle) { + expiration_time = INT64_MAX; + } ret1 = accessor->delete_all(expiration_time); if (ret1 != 0) { LOG(WARNING) << "failed to recycle expired stage objects, instance_id=" << instance_id_ From 735db65d23e4f1042e70bd3a841308ef74b53b70 Mon Sep 17 00:00:00 2001 From: Socrates Date: Fri, 13 Dec 2024 09:56:53 +0800 Subject: [PATCH 33/63] [regression](paimon) test Paimon's connectivity of cloud filesystems (#45268) ### What problem does this PR solve? Problem Summary: Add some cases to test Paimon's connectivity of oss, obs, cos and cosn --- .../paimon/paimon_base_filesystem.out | 29 +++++---- .../paimon/paimon_base_filesystem.groovy | 65 +++++++++++++++---- 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/regression-test/data/external_table_p0/paimon/paimon_base_filesystem.out b/regression-test/data/external_table_p0/paimon/paimon_base_filesystem.out index d24ebd07ef6b16..6ce16ab2a38a2d 100644 --- a/regression-test/data/external_table_p0/paimon/paimon_base_filesystem.out +++ b/regression-test/data/external_table_p0/paimon/paimon_base_filesystem.out @@ -1,17 +1,22 @@ -- This file is automatically generated. You should know what you did if you want to edit this --- !c1 -- -1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true 2023-08-10T14:35:38.768 -1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true 2023-08-10T15:58:54.364 +-- !oss -- +1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true aaaa 2023-08-13T09:32:38.530 --- !c2 -- -7 Hugo -8 Stop +-- !obs -- +1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true aaaa 2023-08-13T09:32:38.530 --- !c3 -- -1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true 2023-08-10T14:35:38.768 -1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true 2023-08-10T15:58:54.364 +-- !cos -- +1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true aaaa 2023-08-13T09:32:38.530 --- !c4 -- -7 Hugo -8 Stop +-- !cosn -- +1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true aaaa 2023-08-13T09:32:38.530 + +-- !oss -- +1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true aaaa 2023-08-13T09:32:38.530 + +-- !obs -- +1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true aaaa 2023-08-13T09:32:38.530 + +-- !cos -- +1 2 3 4 5 6 7 8 9.1 10.1 11.10 2020-02-02 13str 14varchar a true aaaa 2023-08-13T09:32:38.530 diff --git a/regression-test/suites/external_table_p0/paimon/paimon_base_filesystem.groovy b/regression-test/suites/external_table_p0/paimon/paimon_base_filesystem.groovy index 1e4561c406556f..6ac76336986288 100644 --- a/regression-test/suites/external_table_p0/paimon/paimon_base_filesystem.groovy +++ b/regression-test/suites/external_table_p0/paimon/paimon_base_filesystem.groovy @@ -17,29 +17,48 @@ suite("paimon_base_filesystem", "p0,external,doris,external_docker,external_docker_doris") { String enabled = context.config.otherConfigs.get("enablePaimonTest") - // if (enabled == null || !enabled.equalsIgnoreCase("true")) { - if (true) { - // temporary comment out, will add back when env is ready + + if (enabled == null || !enabled.equalsIgnoreCase("true")) { return } try { - String catalog_cos = "paimon_base_filesystem_paimon_cos" + String catalog_obs = "paimon_base_filesystem_paimon_obs" String catalog_oss = "paimon_base_filesystem_paimon_oss" + String catalog_cos = "paimon_base_filesystem_paimon_cos" + String catalog_cosn = "paimon_base_filesystem_paimon_cosn" String aliYunAk = context.config.otherConfigs.get("aliYunAk") String aliYunSk = context.config.otherConfigs.get("aliYunSk") + String hwYunAk = context.config.otherConfigs.get("hwYunAk") + String hwYunSk = context.config.otherConfigs.get("hwYunSk") String txYunAk = context.config.otherConfigs.get("txYunAk") String txYunSk = context.config.otherConfigs.get("txYunSk") - def cos = """select c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c18 from ${catalog_cos}.zd.all_table order by c18""" - def oss = """select * from ${catalog_oss}.paimonossdb1.test_tableoss order by a""" + def obs = """select * from ${catalog_obs}.db1.all_table limit 1;""" + def oss = """select * from ${catalog_oss}.db1.all_table limit 1;""" + def cos = """select * from ${catalog_cos}.db1.all_table limit 1;""" + def cosn = """select * from ${catalog_cosn}.db1.all_table limit 1;""" - sql """drop catalog if exists ${catalog_cos};""" + sql """drop catalog if exists ${catalog_obs};""" sql """drop catalog if exists ${catalog_oss};""" + sql """drop catalog if exists ${catalog_cos};""" + sql """drop catalog if exists ${catalog_cosn};""" + sql """ create catalog if not exists ${catalog_cos} properties ( "type" = "paimon", - "warehouse" = "cosn://doris-build-1308700295/regression/paimoncos", + "paimon.catalog.type"="filesystem", + "warehouse" = "s3://doris-build-1308700295/regression/paimon1", + "s3.access_key" = "${txYunAk}", + "s3.secret_key" = "${txYunSk}", + "s3.endpoint" = "cos.ap-beijing.myqcloud.com" + ); + """ + sql """ + create catalog if not exists ${catalog_cosn} properties ( + "type" = "paimon", + "paimon.catalog.type"="filesystem", + "warehouse" = "cosn://doris-build-1308700295/regression/paimon1", "cos.access_key" = "${txYunAk}", "cos.secret_key" = "${txYunSk}", "cos.endpoint" = "cos.ap-beijing.myqcloud.com" @@ -48,22 +67,40 @@ suite("paimon_base_filesystem", "p0,external,doris,external_docker,external_dock sql """ create catalog if not exists ${catalog_oss} properties ( "type" = "paimon", - "warehouse" = "oss://doris-regression-bj/regression/paimonoss", + "paimon.catalog.type"="filesystem", + "warehouse" = "oss://doris-regression-bj/regression/paimon1", "oss.access_key"="${aliYunAk}", "oss.secret_key"="${aliYunSk}", "oss.endpoint"="oss-cn-beijing.aliyuncs.com" ); """ - logger.info("catalog " + catalog_cos + " created") + sql """ + create catalog if not exists ${catalog_obs} properties ( + "type" = "paimon", + "paimon.catalog.type"="filesystem", + "warehouse" = "obs://doris-build/regression/paimon1", + "obs.access_key"="${hwYunAk}", + "obs.secret_key"="${hwYunSk}", + "obs.endpoint"="obs.cn-north-4.myhuaweicloud.com" + ); + """ + logger.info("catalog " + catalog_obs + " created") logger.info("catalog " + catalog_oss + " created") + logger.info("catalog " + catalog_cos + " created") + logger.info("catalog " + catalog_cosn + " created") sql """set force_jni_scanner=false""" - qt_c1 cos - qt_c2 oss + qt_oss oss + qt_obs obs + qt_cos cos + qt_cosn cosn sql """set force_jni_scanner=true""" - qt_c3 cos - qt_c4 oss + qt_oss oss + qt_obs obs + qt_cos cos + // java.lang.ClassNotFoundException: Class org.apache.hadoop.fs.CosFileSystem not found + // qt_cosn cosn } finally { sql """set force_jni_scanner=false""" From c7fefc367f992ee54ad08c8115d929f5ca4c9ba1 Mon Sep 17 00:00:00 2001 From: Socrates Date: Fri, 13 Dec 2024 09:57:41 +0800 Subject: [PATCH 34/63] [fix](hive) fix block decompressor bug (#45289) ### What problem does this PR solve? Problem Summary: In the block decompressor, when it is found that the input data is less than 4 bytes (the header size of the large block), should set more_input_bytes instead of reporting an error. --- be/src/exec/decompressor.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/be/src/exec/decompressor.cpp b/be/src/exec/decompressor.cpp index 9365bb00288db1..5da2e6acbb9bdf 100644 --- a/be/src/exec/decompressor.cpp +++ b/be/src/exec/decompressor.cpp @@ -492,15 +492,15 @@ Status Lz4BlockDecompressor::decompress(uint8_t* input, size_t input_len, size_t auto* output_ptr = output; while (input_len > 0) { - //if faild , fall back to large block begin - auto* large_block_input_ptr = input_ptr; - auto* large_block_output_ptr = output_ptr; - if (input_len < sizeof(uint32_t)) { - return Status::InvalidArgument(strings::Substitute( - "fail to do hadoop-lz4 decompress, input_len=$0", input_len)); + *more_input_bytes = sizeof(uint32_t) - input_len; + break; } + //if faild, fall back to large block begin + auto* large_block_input_ptr = input_ptr; + auto* large_block_output_ptr = output_ptr; + uint32_t remaining_decompressed_large_block_len = BigEndian::Load32(input_ptr); input_ptr += sizeof(uint32_t); @@ -609,15 +609,15 @@ Status SnappyBlockDecompressor::decompress(uint8_t* input, size_t input_len, auto* output_ptr = output; while (input_len > 0) { - //if faild , fall back to large block begin - auto* large_block_input_ptr = input_ptr; - auto* large_block_output_ptr = output_ptr; - if (input_len < sizeof(uint32_t)) { - return Status::InvalidArgument(strings::Substitute( - "fail to do hadoop-snappy decompress, input_len=$0", input_len)); + *more_input_bytes = sizeof(uint32_t) - input_len; + break; } + //if faild, fall back to large block begin + auto* large_block_input_ptr = input_ptr; + auto* large_block_output_ptr = output_ptr; + uint32_t remaining_decompressed_large_block_len = BigEndian::Load32(input_ptr); input_ptr += sizeof(uint32_t); From b9015f57fddd95c8b1ee57e303ce2dde0353fae7 Mon Sep 17 00:00:00 2001 From: wangbo Date: Fri, 13 Dec 2024 11:33:11 +0800 Subject: [PATCH 35/63] [Improment]add be avail cpu num metric (#45284) --- be/src/common/config.cpp | 2 +- be/src/common/config.h | 2 +- be/src/common/daemon.cpp | 2 + be/src/util/cgroup_util.cpp | 167 ++++++++++++++++++ be/src/util/cgroup_util.h | 22 +++ be/src/util/cpu_info.cpp | 55 +----- be/src/util/system_metrics.cpp | 13 ++ be/src/util/system_metrics.h | 2 + be/test/util/cgroup_util_test.cpp | 90 ++++++++++ .../util/test_data/cgroup_cpu_data/cpuset1 | 1 + .../util/test_data/cgroup_cpu_data/cpuset2 | 1 + .../util/test_data/cgroup_cpu_data/cpuset3 | 1 + .../cgroup_cpu_data/test11/child/cpu.max | 1 + .../test_data/cgroup_cpu_data/test11/cpu.max | 1 + .../cgroup_cpu_data/test12/child/cpu.max | 1 + .../test_data/cgroup_cpu_data/test12/cpu.max | 1 + .../cgroup_cpu_data/test13/child/cpu.max | 1 + .../test_data/cgroup_cpu_data/test13/cpu.max | 1 + .../cgroup_cpu_data/test14/child/cpu.max | 1 + .../test_data/cgroup_cpu_data/test14/cpu.max | 1 + .../test21/child/cpuset.cpus.effective | 1 + .../test21/cpuset.cpus.effective | 1 + .../test22/child/cpuset.cpus.effective | 0 .../test22/cpuset.cpus.effective | 1 + .../test31/child/cpu.cfs_period_us | 1 + .../test31/child/cpu.cfs_quota_us | 1 + .../cgroup_cpu_data/test31/cpu.cfs_period_us | 1 + .../cgroup_cpu_data/test31/cpu.cfs_quota_us | 1 + .../test32/child/cpu.cfs_period_us | 1 + .../test32/child/cpu.cfs_quota_us | 1 + .../cgroup_cpu_data/test32/cpu.cfs_period_us | 1 + .../cgroup_cpu_data/test32/cpu.cfs_quota_us | 1 + .../test33/child/cpu.cfs_period_us | 1 + .../test33/child/cpu.cfs_quota_us | 1 + .../cgroup_cpu_data/test33/cpu.cfs_period_us | 1 + .../cgroup_cpu_data/test33/cpu.cfs_quota_us | 1 + .../cgroup_cpu_data/test41/cpuset.cpus | 1 + 37 files changed, 327 insertions(+), 55 deletions(-) create mode 100644 be/test/util/test_data/cgroup_cpu_data/cpuset1 create mode 100644 be/test/util/test_data/cgroup_cpu_data/cpuset2 create mode 100644 be/test/util/test_data/cgroup_cpu_data/cpuset3 create mode 100644 be/test/util/test_data/cgroup_cpu_data/test11/child/cpu.max create mode 100644 be/test/util/test_data/cgroup_cpu_data/test11/cpu.max create mode 100644 be/test/util/test_data/cgroup_cpu_data/test12/child/cpu.max create mode 100644 be/test/util/test_data/cgroup_cpu_data/test12/cpu.max create mode 100644 be/test/util/test_data/cgroup_cpu_data/test13/child/cpu.max create mode 100644 be/test/util/test_data/cgroup_cpu_data/test13/cpu.max create mode 100644 be/test/util/test_data/cgroup_cpu_data/test14/child/cpu.max create mode 100644 be/test/util/test_data/cgroup_cpu_data/test14/cpu.max create mode 100644 be/test/util/test_data/cgroup_cpu_data/test21/child/cpuset.cpus.effective create mode 100644 be/test/util/test_data/cgroup_cpu_data/test21/cpuset.cpus.effective create mode 100644 be/test/util/test_data/cgroup_cpu_data/test22/child/cpuset.cpus.effective create mode 100644 be/test/util/test_data/cgroup_cpu_data/test22/cpuset.cpus.effective create mode 100644 be/test/util/test_data/cgroup_cpu_data/test31/child/cpu.cfs_period_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test31/child/cpu.cfs_quota_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test31/cpu.cfs_period_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test31/cpu.cfs_quota_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test32/child/cpu.cfs_period_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test32/child/cpu.cfs_quota_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test32/cpu.cfs_period_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test32/cpu.cfs_quota_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test33/child/cpu.cfs_period_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test33/child/cpu.cfs_quota_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test33/cpu.cfs_period_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test33/cpu.cfs_quota_us create mode 100644 be/test/util/test_data/cgroup_cpu_data/test41/cpuset.cpus diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp index 08f1ca7dd58c5c..b70f492a29dfda 100644 --- a/be/src/common/config.cpp +++ b/be/src/common/config.cpp @@ -1211,7 +1211,7 @@ DEFINE_Bool(exit_on_exception, "false"); DEFINE_Bool(enable_flush_file_cache_async, "true"); // cgroup -DEFINE_mString(doris_cgroup_cpu_path, ""); +DEFINE_String(doris_cgroup_cpu_path, ""); DEFINE_mBool(enable_be_proc_monitor, "false"); DEFINE_mInt32(be_proc_monitor_interval_ms, "10000"); diff --git a/be/src/common/config.h b/be/src/common/config.h index c0b2e19b49a6be..984024cab7c77f 100644 --- a/be/src/common/config.h +++ b/be/src/common/config.h @@ -1292,7 +1292,7 @@ DECLARE_mInt32(tablet_schema_cache_capacity); DECLARE_mBool(exit_on_exception); // cgroup -DECLARE_mString(doris_cgroup_cpu_path); +DECLARE_String(doris_cgroup_cpu_path); DECLARE_mBool(enable_be_proc_monitor); DECLARE_mInt32(be_proc_monitor_interval_ms); DECLARE_Int32(workload_group_metrics_interval_ms); diff --git a/be/src/common/daemon.cpp b/be/src/common/daemon.cpp index 73035ecf3957eb..12bf1749a5694d 100644 --- a/be/src/common/daemon.cpp +++ b/be/src/common/daemon.cpp @@ -437,6 +437,8 @@ void Daemon::calculate_metrics_thread() { // update lst map DorisMetrics::instance()->system_metrics()->get_network_traffic( &lst_net_send_bytes, &lst_net_receive_bytes); + + DorisMetrics::instance()->system_metrics()->update_be_avail_cpu_num(); } update_rowsets_and_segments_num_metrics(); } diff --git a/be/src/util/cgroup_util.cpp b/be/src/util/cgroup_util.cpp index 8f64fe699c6062..fc35be3dc35931 100644 --- a/be/src/util/cgroup_util.cpp +++ b/be/src/util/cgroup_util.cpp @@ -218,6 +218,10 @@ std::optional CGroupUtil::get_cgroupsv2_path(const std::string& sub Status CGroupUtil::read_int_line_from_cgroup_file(const std::filesystem::path& file_path, int64_t* val) { std::ifstream file_stream(file_path, std::ios::in); + if (!file_stream.is_open()) { + return Status::CgroupError("Error open {}", file_path.string()); + } + string line; getline(file_stream, line); if (file_stream.fail() || file_stream.bad()) { @@ -264,4 +268,167 @@ void CGroupUtil::read_int_metric_from_cgroup_file( } } +Status CGroupUtil::read_string_line_from_cgroup_file(const std::filesystem::path& file_path, + std::string* line_ptr) { + std::ifstream file_stream(file_path, std::ios::in); + if (!file_stream.is_open()) { + return Status::CgroupError("Error open {}", file_path.string()); + } + string line; + getline(file_stream, line); + if (file_stream.fail() || file_stream.bad()) { + return Status::CgroupError("Error reading {}: {}", file_path.string(), get_str_err_msg()); + } + *line_ptr = line; + return Status::OK(); +} + +Status CGroupUtil::parse_cpuset_line(std::string cpuset_line, int* cpu_count_ptr) { + if (cpuset_line.empty()) { + return Status::CgroupError("cpuset line is empty"); + } + std::vector ranges; + boost::split(ranges, cpuset_line, boost::is_any_of(",")); + int cpu_count = 0; + + for (const std::string& range : ranges) { + std::vector cpu_values; + boost::split(cpu_values, range, boost::is_any_of("-")); + + if (cpu_values.size() == 2) { + int start = std::stoi(cpu_values[0]); + int end = std::stoi(cpu_values[1]); + cpu_count += (end - start) + 1; + } else { + cpu_count++; + } + } + *cpu_count_ptr = cpu_count; + return Status::OK(); +} + +int CGroupUtil::get_cgroup_limited_cpu_number(int physical_cores) { + if (physical_cores <= 0) { + return physical_cores; + } + int ret = physical_cores; +#if defined(OS_LINUX) + // For cgroup v2 + // Child cgroup's cpu.max may bigger than parent group's cpu.max, + // so it should look up from current cgroup to top group. + // For cpuset, child cgroup's cpuset.cpus could not bigger thant parent's cpuset.cpus. + if (CGroupUtil::cgroupsv2_enable()) { + std::string cgroupv2_process_path = CGroupUtil::cgroupv2_of_process(); + if (cgroupv2_process_path.empty()) { + return ret; + } + std::filesystem::path current_cgroup_path = (default_cgroups_mount / cgroupv2_process_path); + ret = get_cgroup_v2_cpu_quota_number(current_cgroup_path, default_cgroups_mount, ret); + + current_cgroup_path = (default_cgroups_mount / cgroupv2_process_path); + ret = get_cgroup_v2_cpuset_number(current_cgroup_path, default_cgroups_mount, ret); + } else if (CGroupUtil::cgroupsv1_enable()) { + // cpu quota, should find first not empty config from current path to top. + // because if a process attach to current cgroup, its cpu quota may not be set. + std::string cpu_quota_path = ""; + Status cpu_quota_ret = CGroupUtil::find_abs_cgroupv1_path("cpu", &cpu_quota_path); + if (cpu_quota_ret.ok() && !cpu_quota_path.empty()) { + std::filesystem::path current_cgroup_path = cpu_quota_path; + ret = get_cgroup_v1_cpu_quota_number(current_cgroup_path, default_cgroups_mount, ret); + } + + //cpuset + // just lookup current process cgroup path is enough + // because if a process attach to current cgroup, its cpuset.cpus must be set. + std::string cpuset_path = ""; + Status cpuset_ret = CGroupUtil::find_abs_cgroupv1_path("cpuset", &cpuset_path); + if (cpuset_ret.ok() && !cpuset_path.empty()) { + std::filesystem::path current_path = cpuset_path; + ret = get_cgroup_v1_cpuset_number(current_path, ret); + } + } +#endif + return ret; +} + +int CGroupUtil::get_cgroup_v2_cpu_quota_number(std::filesystem::path& current_path, + const std::filesystem::path& default_cg_mout_path, + int cpu_num) { + int ret = cpu_num; + while (current_path != default_cg_mout_path.parent_path()) { + std::ifstream cpu_max_file(current_path / "cpu.max"); + if (cpu_max_file.is_open()) { + std::string cpu_limit_str; + double cpu_period; + cpu_max_file >> cpu_limit_str >> cpu_period; + if (cpu_limit_str != "max" && cpu_period != 0) { + double cpu_limit = std::stod(cpu_limit_str); + ret = std::min(static_cast(std::ceil(cpu_limit / cpu_period)), ret); + } + } + current_path = current_path.parent_path(); + } + return ret; +} + +int CGroupUtil::get_cgroup_v2_cpuset_number(std::filesystem::path& current_path, + const std::filesystem::path& default_cg_mout_path, + int cpu_num) { + int ret = cpu_num; + while (current_path != default_cg_mout_path.parent_path()) { + std::ifstream cpuset_cpus_file(current_path / "cpuset.cpus.effective"); + current_path = current_path.parent_path(); + if (cpuset_cpus_file.is_open()) { + std::string cpuset_line; + cpuset_cpus_file >> cpuset_line; + if (cpuset_line.empty()) { + continue; + } + int cpus_count = 0; + static_cast(CGroupUtil::parse_cpuset_line(cpuset_line, &cpus_count)); + ret = std::min(cpus_count, ret); + break; + } + } + return ret; +} + +int CGroupUtil::get_cgroup_v1_cpu_quota_number(std::filesystem::path& current_path, + const std::filesystem::path& default_cg_mout_path, + int cpu_num) { + int ret = cpu_num; + while (current_path != default_cg_mout_path.parent_path()) { + std::ifstream cpu_quota_file(current_path / "cpu.cfs_quota_us"); + std::ifstream cpu_period_file(current_path / "cpu.cfs_period_us"); + if (cpu_quota_file.is_open() && cpu_period_file.is_open()) { + double cpu_quota_value; + double cpu_period_value; + cpu_quota_file >> cpu_quota_value; + cpu_period_file >> cpu_period_value; + if (cpu_quota_value > 0 && cpu_period_value > 0) { + ret = std::min(ret, + static_cast(std::ceil(cpu_quota_value / cpu_period_value))); + break; + } + } + current_path = current_path.parent_path(); + } + return ret; +} + +int CGroupUtil::get_cgroup_v1_cpuset_number(std::filesystem::path& current_path, int cpu_num) { + int ret = cpu_num; + std::string cpuset_line = ""; + Status cpuset_ret = CGroupUtil::read_string_line_from_cgroup_file( + (current_path / "cpuset.cpus"), &cpuset_line); + if (cpuset_ret.ok() && !cpuset_line.empty()) { + int cpuset_count = 0; + static_cast(CGroupUtil::parse_cpuset_line(cpuset_line, &cpuset_count)); + if (cpuset_count > 0) { + ret = std::min(ret, cpuset_count); + } + } + return ret; +} + } // namespace doris diff --git a/be/src/util/cgroup_util.h b/be/src/util/cgroup_util.h index bc1417453f41f6..54fc9494599f15 100644 --- a/be/src/util/cgroup_util.h +++ b/be/src/util/cgroup_util.h @@ -104,5 +104,27 @@ class CGroupUtil { static void read_int_metric_from_cgroup_file( const std::filesystem::path& file_path, std::unordered_map& metrics_map); + + static Status read_string_line_from_cgroup_file(const std::filesystem::path& file_path, + std::string* line_ptr); + + // cpuset_line: 0-4,6,8-10 + static Status parse_cpuset_line(std::string cpuset_line, int* cpu_count_ptr); + + static int get_cgroup_limited_cpu_number(int physical_cores); + + static int get_cgroup_v2_cpu_quota_number(std::filesystem::path& current_path, + const std::filesystem::path& default_cg_mout_path, + int cpu_num); + + static int get_cgroup_v2_cpuset_number(std::filesystem::path& current_path, + const std::filesystem::path& default_cg_mout_path, + int cpu_num); + + static int get_cgroup_v1_cpu_quota_number(std::filesystem::path& current_path, + const std::filesystem::path& default_cg_mout_path, + int cpu_num); + + static int get_cgroup_v1_cpuset_number(std::filesystem::path& current_path, int cpu_num); }; } // namespace doris diff --git a/be/src/util/cpu_info.cpp b/be/src/util/cpu_info.cpp index 116dacb8da7ed4..b49985cdc06830 100644 --- a/be/src/util/cpu_info.cpp +++ b/be/src/util/cpu_info.cpp @@ -59,6 +59,7 @@ #include "gflags/gflags.h" #include "gutil/stringprintf.h" #include "gutil/strings/substitute.h" +#include "util/cgroup_util.h" #include "util/pretty_printer.h" using boost::algorithm::contains; @@ -109,58 +110,6 @@ static struct { {"popcnt", CpuInfo::POPCNT}, {"avx", CpuInfo::AVX}, {"avx2", CpuInfo::AVX2}, }; -int cgroup_bandwidth_quota(int physical_cores) { - namespace fs = std::filesystem; - fs::path cpu_max = "/sys/fs/cgroup/cpu.max"; - fs::path cfs_quota = "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"; - fs::path cfs_period = "/sys/fs/cgroup/cpu/cpu.cfs_period_us"; - - int64_t quota, period; - char byte_buffer[1000]; - int64_t read_bytes; - - if (fs::exists(cpu_max)) { - // cgroup v2 - // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html - std::ifstream file(cpu_max); - file.read(byte_buffer, 999); - read_bytes = file.gcount(); - byte_buffer[read_bytes] = '\0'; - if (sscanf(byte_buffer, "%" SCNd64 " %" SCNd64 "", "a, &period) != 2) { - return physical_cores; - } - } else if (fs::exists(cfs_quota) && fs::exists(cfs_period)) { - // cgroup v1 - // https://www.kernel.org/doc/html/latest/scheduler/sched-bwc.html#management - - // Read the quota, this indicates how many microseconds the CPU can be utilized by this cgroup per period - std::ifstream quota_file(cfs_quota); - quota_file.read(byte_buffer, 999); - read_bytes = quota_file.gcount(); - byte_buffer[read_bytes] = '\0'; - if (sscanf(byte_buffer, "%" SCNd64 "", "a) != 1) { - return physical_cores; - } - - // Read the time period, a cgroup can utilize the CPU up to quota microseconds every period - std::ifstream period_file(cfs_period); - period_file.read(byte_buffer, 999); - read_bytes = period_file.gcount(); - byte_buffer[read_bytes] = '\0'; - if (sscanf(byte_buffer, "%" SCNd64 "", &period) != 1) { - return physical_cores; - } - } else { - // No cgroup quota - return physical_cores; - } - if (quota > 0 && period > 0) { - return int64_t(ceil(double(quota) / double(period))); - } else { - return physical_cores; - } -} - // Helper function to parse for hardware flags. // values contains a list of space-separated flags. check to see if the flags we // care about are present. @@ -212,7 +161,7 @@ void CpuInfo::init() { } } - int num_cores = cgroup_bandwidth_quota(physical_num_cores); + int num_cores = CGroupUtil::get_cgroup_limited_cpu_number(physical_num_cores); if (max_mhz != 0) { cycles_per_ms_ = int64_t(max_mhz) * 1000; } else { diff --git a/be/src/util/system_metrics.cpp b/be/src/util/system_metrics.cpp index 973f461d8defe7..fc2cdcc9262b31 100644 --- a/be/src/util/system_metrics.cpp +++ b/be/src/util/system_metrics.cpp @@ -33,18 +33,23 @@ #include "gutil/strings/split.h" // for string split #include "gutil/strtoint.h" // for atoi64 +#include "util/cgroup_util.h" #include "util/mem_info.h" #include "util/perf_counters.h" namespace doris { +DEFINE_COUNTER_METRIC_PROTOTYPE_2ARG(avail_cpu_num, MetricUnit::NOUNIT); + DEFINE_COUNTER_METRIC_PROTOTYPE_2ARG(host_cpu_num, MetricUnit::NOUNIT); struct CpuNumberMetrics { CpuNumberMetrics(MetricEntity* ent) : entity(ent) { INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, host_cpu_num); + INT_ATOMIC_COUNTER_METRIC_REGISTER(entity, avail_cpu_num); } IntAtomicCounter* host_cpu_num {nullptr}; + IntAtomicCounter* avail_cpu_num {nullptr}; MetricEntity* entity = nullptr; }; @@ -1004,6 +1009,14 @@ void SystemMetrics::_update_proc_metrics() { fclose(fp); } +void SystemMetrics::update_be_avail_cpu_num() { + int64_t physical_cpu_num = _cpu_num_metrics->host_cpu_num->value(); + if (physical_cpu_num > 0) { + physical_cpu_num = CGroupUtil::get_cgroup_limited_cpu_number(physical_cpu_num); + _cpu_num_metrics->avail_cpu_num->set_value(physical_cpu_num); + } +} + void SystemMetrics::get_metrics_from_proc_vmstat() { #ifdef BE_TEST FILE* fp = fopen(k_ut_vmstat_path, "r"); diff --git a/be/src/util/system_metrics.h b/be/src/util/system_metrics.h index 29ce8c9c02b359..2c5446b81f4f71 100644 --- a/be/src/util/system_metrics.h +++ b/be/src/util/system_metrics.h @@ -66,6 +66,8 @@ class SystemMetrics { void update_max_network_receive_bytes_rate(int64_t max_receive_bytes_rate); void update_allocator_metrics(); + void update_be_avail_cpu_num(); + private: void _install_cpu_metrics(); // On Intel(R) Xeon(R) CPU E5-2450 0 @ 2.10GHz; diff --git a/be/test/util/cgroup_util_test.cpp b/be/test/util/cgroup_util_test.cpp index 92102120327840..4cc5c601b28ce1 100644 --- a/be/test/util/cgroup_util_test.cpp +++ b/be/test/util/cgroup_util_test.cpp @@ -87,4 +87,94 @@ TEST_F(CGroupUtilTest, memlimit) { } } +TEST_F(CGroupUtilTest, readcpu) { + std::string dir_path = GetCurrentRunningDir(); + + std::string cpuset_1_path(dir_path + "/util/test_data/cgroup_cpu_data/cpuset1"); + std::string cpuset_1_str = ""; + Status ret1 = CGroupUtil::read_string_line_from_cgroup_file(cpuset_1_path, &cpuset_1_str); + EXPECT_TRUE(ret1.ok()); + int cpu_count1 = 0; + static_cast(CGroupUtil::parse_cpuset_line(cpuset_1_str, &cpu_count1)); + EXPECT_TRUE(cpu_count1 == 3); + + std::string cpuset_2_path(dir_path + "/util/test_data/cgroup_cpu_data/cpuset2"); + std::string cpuset_2_str = ""; + Status ret2 = CGroupUtil::read_string_line_from_cgroup_file(cpuset_2_path, &cpuset_2_str); + EXPECT_TRUE(ret2.ok()); + int cpu_count2 = 0; + static_cast(CGroupUtil::parse_cpuset_line(cpuset_2_str, &cpu_count2)); + EXPECT_TRUE(cpu_count2 == 11); + + std::string cpuset_3_path(dir_path + "/util/test_data/cgroup_cpu_data/cpuset3"); + std::string cpuset_3_str = ""; + Status ret3 = CGroupUtil::read_string_line_from_cgroup_file(cpuset_3_path, &cpuset_3_str); + EXPECT_TRUE(ret3.ok()); + int cpu_count3 = 0; + static_cast(CGroupUtil::parse_cpuset_line(cpuset_3_str, &cpu_count3)); + EXPECT_TRUE(cpu_count3 == 10); + + int ret = CGroupUtil::get_cgroup_limited_cpu_number(16); + EXPECT_TRUE(ret > 0); + + // 1 read cgroup v2 quota + // 1.1 read default value + std::filesystem::path path11 = dir_path + "/util/test_data/cgroup_cpu_data/test11/child"; + std::filesystem::path default_path_11 = dir_path + "/util/test_data/cgroup_cpu_data/test11"; + int ret11 = CGroupUtil::get_cgroup_v2_cpu_quota_number(path11, default_path_11, 96); + EXPECT_TRUE(ret11 == 96); + + // 1.2 read from child to parent + std::filesystem::path path12 = dir_path + "/util/test_data/cgroup_cpu_data/test12/child"; + std::filesystem::path default_path_12 = dir_path + "/util/test_data/cgroup_cpu_data/test12"; + int ret12 = CGroupUtil::get_cgroup_v2_cpu_quota_number(path12, default_path_12, 96); + EXPECT_TRUE(ret12 == 2); + + // 1.3 read parent + std::filesystem::path path13 = dir_path + "/util/test_data/cgroup_cpu_data/test13/child"; + std::filesystem::path default_path_13 = dir_path + "/util/test_data/cgroup_cpu_data/test13"; + int ret13 = CGroupUtil::get_cgroup_v2_cpu_quota_number(path13, default_path_13, 96); + EXPECT_TRUE(ret13 == 2); + + // 1.4 read child + std::filesystem::path path14 = dir_path + "/util/test_data/cgroup_cpu_data/test14/child"; + std::filesystem::path default_path_14 = dir_path + "/util/test_data/cgroup_cpu_data/test14"; + int ret14 = CGroupUtil::get_cgroup_v2_cpu_quota_number(path14, default_path_14, 96); + EXPECT_TRUE(ret14 == 3); + + // 2 read cgroup v2 cpuset + // 2.1 read child + std::filesystem::path path21 = dir_path + "/util/test_data/cgroup_cpu_data/test21/child"; + std::filesystem::path default_path_21 = dir_path + "/util/test_data/cgroup_cpu_data/test21"; + int ret21 = CGroupUtil::get_cgroup_v2_cpuset_number(path21, default_path_21, 96); + EXPECT_TRUE(ret21 == 2); + // 2.2 read parent + std::filesystem::path path22 = dir_path + "/util/test_data/cgroup_cpu_data/test22/child"; + std::filesystem::path default_path_22 = dir_path + "/util/test_data/cgroup_cpu_data/test22"; + int ret22 = CGroupUtil::get_cgroup_v2_cpuset_number(path22, default_path_22, 96); + EXPECT_TRUE(ret22 == 7); + + // 3 read cgroup v1 quota + // 3.1 read child + std::filesystem::path path31 = dir_path + "/util/test_data/cgroup_cpu_data/test31/child"; + std::filesystem::path default_path_31 = dir_path + "/util/test_data/cgroup_cpu_data/test31"; + int ret31 = CGroupUtil::get_cgroup_v1_cpu_quota_number(path31, default_path_31, 96); + EXPECT_TRUE(ret31 == 5); + // 3.2 read parent + std::filesystem::path path32 = dir_path + "/util/test_data/cgroup_cpu_data/test32/child"; + std::filesystem::path default_path_32 = dir_path + "/util/test_data/cgroup_cpu_data/test32"; + int ret32 = CGroupUtil::get_cgroup_v1_cpu_quota_number(path32, default_path_32, 96); + EXPECT_TRUE(ret32 == 6); + // 3.3 read default + std::filesystem::path path33 = dir_path + "/util/test_data/cgroup_cpu_data/test33/child"; + std::filesystem::path default_path_33 = dir_path + "/util/test_data/cgroup_cpu_data/test33"; + int ret33 = CGroupUtil::get_cgroup_v1_cpu_quota_number(path33, default_path_33, 96); + EXPECT_TRUE(ret33 == 96); + + // 4 read cgroup v1 cpuset + std::filesystem::path path41 = dir_path + "/util/test_data/cgroup_cpu_data/test41"; + int ret41 = CGroupUtil::get_cgroup_v1_cpuset_number(path41, 96); + EXPECT_TRUE(ret41 == 3); +} + } // namespace doris diff --git a/be/test/util/test_data/cgroup_cpu_data/cpuset1 b/be/test/util/test_data/cgroup_cpu_data/cpuset1 new file mode 100644 index 00000000000000..f2fdae292d6460 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/cpuset1 @@ -0,0 +1 @@ +1,4,6 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/cpuset2 b/be/test/util/test_data/cgroup_cpu_data/cpuset2 new file mode 100644 index 00000000000000..9528de88c0a81c --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/cpuset2 @@ -0,0 +1 @@ +1-5,7-10,20-21 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/cpuset3 b/be/test/util/test_data/cgroup_cpu_data/cpuset3 new file mode 100644 index 00000000000000..02c93d74ecdcb9 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/cpuset3 @@ -0,0 +1 @@ +4,11-15,20,31-33 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test11/child/cpu.max b/be/test/util/test_data/cgroup_cpu_data/test11/child/cpu.max new file mode 100644 index 00000000000000..b22d43b0084fe5 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test11/child/cpu.max @@ -0,0 +1 @@ +max 100000 0 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test11/cpu.max b/be/test/util/test_data/cgroup_cpu_data/test11/cpu.max new file mode 100644 index 00000000000000..b22d43b0084fe5 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test11/cpu.max @@ -0,0 +1 @@ +max 100000 0 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test12/child/cpu.max b/be/test/util/test_data/cgroup_cpu_data/test12/child/cpu.max new file mode 100644 index 00000000000000..434d117ae1c9d9 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test12/child/cpu.max @@ -0,0 +1 @@ +300000 100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test12/cpu.max b/be/test/util/test_data/cgroup_cpu_data/test12/cpu.max new file mode 100644 index 00000000000000..20b625d5126f34 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test12/cpu.max @@ -0,0 +1 @@ +200000 100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test13/child/cpu.max b/be/test/util/test_data/cgroup_cpu_data/test13/child/cpu.max new file mode 100644 index 00000000000000..b22d43b0084fe5 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test13/child/cpu.max @@ -0,0 +1 @@ +max 100000 0 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test13/cpu.max b/be/test/util/test_data/cgroup_cpu_data/test13/cpu.max new file mode 100644 index 00000000000000..20b625d5126f34 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test13/cpu.max @@ -0,0 +1 @@ +200000 100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test14/child/cpu.max b/be/test/util/test_data/cgroup_cpu_data/test14/child/cpu.max new file mode 100644 index 00000000000000..434d117ae1c9d9 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test14/child/cpu.max @@ -0,0 +1 @@ +300000 100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test14/cpu.max b/be/test/util/test_data/cgroup_cpu_data/test14/cpu.max new file mode 100644 index 00000000000000..4199eb01a27554 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test14/cpu.max @@ -0,0 +1 @@ +400000 100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test21/child/cpuset.cpus.effective b/be/test/util/test_data/cgroup_cpu_data/test21/child/cpuset.cpus.effective new file mode 100644 index 00000000000000..fb00853f18d5c2 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test21/child/cpuset.cpus.effective @@ -0,0 +1 @@ +0-1 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test21/cpuset.cpus.effective b/be/test/util/test_data/cgroup_cpu_data/test21/cpuset.cpus.effective new file mode 100644 index 00000000000000..745f3eb7203929 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test21/cpuset.cpus.effective @@ -0,0 +1 @@ +0-6 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test22/child/cpuset.cpus.effective b/be/test/util/test_data/cgroup_cpu_data/test22/child/cpuset.cpus.effective new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/be/test/util/test_data/cgroup_cpu_data/test22/cpuset.cpus.effective b/be/test/util/test_data/cgroup_cpu_data/test22/cpuset.cpus.effective new file mode 100644 index 00000000000000..745f3eb7203929 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test22/cpuset.cpus.effective @@ -0,0 +1 @@ +0-6 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test31/child/cpu.cfs_period_us b/be/test/util/test_data/cgroup_cpu_data/test31/child/cpu.cfs_period_us new file mode 100644 index 00000000000000..483fb82b6dd2b5 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test31/child/cpu.cfs_period_us @@ -0,0 +1 @@ +100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test31/child/cpu.cfs_quota_us b/be/test/util/test_data/cgroup_cpu_data/test31/child/cpu.cfs_quota_us new file mode 100644 index 00000000000000..516a58aff39342 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test31/child/cpu.cfs_quota_us @@ -0,0 +1 @@ +500000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test31/cpu.cfs_period_us b/be/test/util/test_data/cgroup_cpu_data/test31/cpu.cfs_period_us new file mode 100644 index 00000000000000..483fb82b6dd2b5 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test31/cpu.cfs_period_us @@ -0,0 +1 @@ +100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test31/cpu.cfs_quota_us b/be/test/util/test_data/cgroup_cpu_data/test31/cpu.cfs_quota_us new file mode 100644 index 00000000000000..212f56fce5dd11 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test31/cpu.cfs_quota_us @@ -0,0 +1 @@ +600000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test32/child/cpu.cfs_period_us b/be/test/util/test_data/cgroup_cpu_data/test32/child/cpu.cfs_period_us new file mode 100644 index 00000000000000..483fb82b6dd2b5 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test32/child/cpu.cfs_period_us @@ -0,0 +1 @@ +100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test32/child/cpu.cfs_quota_us b/be/test/util/test_data/cgroup_cpu_data/test32/child/cpu.cfs_quota_us new file mode 100644 index 00000000000000..d7d17fcbef95ca --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test32/child/cpu.cfs_quota_us @@ -0,0 +1 @@ +-1 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test32/cpu.cfs_period_us b/be/test/util/test_data/cgroup_cpu_data/test32/cpu.cfs_period_us new file mode 100644 index 00000000000000..483fb82b6dd2b5 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test32/cpu.cfs_period_us @@ -0,0 +1 @@ +100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test32/cpu.cfs_quota_us b/be/test/util/test_data/cgroup_cpu_data/test32/cpu.cfs_quota_us new file mode 100644 index 00000000000000..212f56fce5dd11 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test32/cpu.cfs_quota_us @@ -0,0 +1 @@ +600000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test33/child/cpu.cfs_period_us b/be/test/util/test_data/cgroup_cpu_data/test33/child/cpu.cfs_period_us new file mode 100644 index 00000000000000..483fb82b6dd2b5 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test33/child/cpu.cfs_period_us @@ -0,0 +1 @@ +100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test33/child/cpu.cfs_quota_us b/be/test/util/test_data/cgroup_cpu_data/test33/child/cpu.cfs_quota_us new file mode 100644 index 00000000000000..d7d17fcbef95ca --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test33/child/cpu.cfs_quota_us @@ -0,0 +1 @@ +-1 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test33/cpu.cfs_period_us b/be/test/util/test_data/cgroup_cpu_data/test33/cpu.cfs_period_us new file mode 100644 index 00000000000000..483fb82b6dd2b5 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test33/cpu.cfs_period_us @@ -0,0 +1 @@ +100000 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test33/cpu.cfs_quota_us b/be/test/util/test_data/cgroup_cpu_data/test33/cpu.cfs_quota_us new file mode 100644 index 00000000000000..d7d17fcbef95ca --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test33/cpu.cfs_quota_us @@ -0,0 +1 @@ +-1 \ No newline at end of file diff --git a/be/test/util/test_data/cgroup_cpu_data/test41/cpuset.cpus b/be/test/util/test_data/cgroup_cpu_data/test41/cpuset.cpus new file mode 100644 index 00000000000000..b62d3ca93d6bd2 --- /dev/null +++ b/be/test/util/test_data/cgroup_cpu_data/test41/cpuset.cpus @@ -0,0 +1 @@ +1-3 \ No newline at end of file From c5a23076378291b3885328c6c2298197a9738b71 Mon Sep 17 00:00:00 2001 From: Xinyi Zou Date: Fri, 13 Dec 2024 11:33:36 +0800 Subject: [PATCH 36/63] [fix](memory) Disable Jemalloc Hook and loading libjvm at runtime (#45210) ### What problem does this PR solve? fix: ``` *** Aborted at 1733734087 (unix time) try "date -d @1733734087" if you are using GNU date *** *** Current BE git commitID: 43f06a5e26 *** *** SIGSEGV address not mapped to object (@0x0) received by PID 1671420 (TID 1671420 OR 0x7f4f35f74ac0) from PID 0; stack trace: *** 0# doris::signal::(anonymous namespace)::FailureSignalHandler(int, siginfo_t*, void*) at /home/zcp/repo_center/doris_release/doris/be/src/common/signal_handler.h:421 1# PosixSignals::chained_handler(int, siginfo*, void*) [clone .part.0] in /usr/local/jdk-17.0.2/lib/server/libjvm.so 2# JVM_handle_linux_signal in /usr/local/jdk-17.0.2/lib/server/libjvm.so 3# 0x00007F4F34340400 in /lib64/libc.so.6 4# je_arena_dalloc_promoted at ../src/arena.c:1277 5# je_free_default at ../src/jemalloc.c:3014 6# __pthread_create_2_1 in /lib64/libpthread.so.0 7# os::create_thread(Thread*, os::ThreadType, unsigned long) in /usr/local/jdk-17.0.2/lib/server/libjvm.so 8# JVM_StartThread in /usr/local/jdk-17.0.2/lib/server/libjvm.so 9# 0x00007F4F0A96C918 ``` --- be/src/http/default_path_handlers.cpp | 2 +- be/src/runtime/CMakeLists.txt | 4 +--- be/src/runtime/memory/heap_profiler.cpp | 8 ++++---- be/src/util/mem_info.cpp | 2 +- be/src/util/mem_info.h | 10 +++++----- be/src/vec/common/allocator.h | 2 +- build.sh | 14 -------------- cloud/src/common/CMakeLists.txt | 6 ------ thirdparty/build-thirdparty.sh | 4 +++- 9 files changed, 16 insertions(+), 36 deletions(-) diff --git a/be/src/http/default_path_handlers.cpp b/be/src/http/default_path_handlers.cpp index 04e1121cab63ba..b26ba67b54625c 100644 --- a/be/src/http/default_path_handlers.cpp +++ b/be/src/http/default_path_handlers.cpp @@ -146,7 +146,7 @@ void memory_info_handler(std::stringstream* output) { auto* _opaque = static_cast(opaque); _opaque->append(buf); }; - jemalloc_stats_print(write_cb, &tmp, "a"); + malloc_stats_print(write_cb, &tmp, "a"); boost::replace_all(tmp, "\n", "
"); (*output) << tmp; #else diff --git a/be/src/runtime/CMakeLists.txt b/be/src/runtime/CMakeLists.txt index a0b3b799a764cb..ab380f9711f1ac 100644 --- a/be/src/runtime/CMakeLists.txt +++ b/be/src/runtime/CMakeLists.txt @@ -25,9 +25,7 @@ set(EXECUTABLE_OUTPUT_PATH "${BUILD_DIR}/src/runtime") file(GLOB_RECURSE RUNTIME_FILES CONFIGURE_DEPENDS *.cpp *.cc) -if (NOT USE_JEMALLOC OR NOT USE_MEM_TRACKER) - list(REMOVE_ITEM RUNTIME_FILES ${CMAKE_CURRENT_SOURCE_DIR}/memory/jemalloc_hook.cpp) -endif() +list(REMOVE_ITEM RUNTIME_FILES ${CMAKE_CURRENT_SOURCE_DIR}/memory/jemalloc_hook.cpp) add_library(Runtime STATIC ${RUNTIME_FILES} diff --git a/be/src/runtime/memory/heap_profiler.cpp b/be/src/runtime/memory/heap_profiler.cpp index 01ed82f76ef6d1..0b0448ce0eaaf6 100644 --- a/be/src/runtime/memory/heap_profiler.cpp +++ b/be/src/runtime/memory/heap_profiler.cpp @@ -30,8 +30,8 @@ void HeapProfiler::set_prof_active(bool prof) { #ifdef USE_JEMALLOC std::lock_guard guard(_mutex); try { - int err = jemallctl("prof.active", nullptr, nullptr, &prof, 1); - err |= jemallctl("prof.thread_active_init", nullptr, nullptr, &prof, 1); + int err = mallctl("prof.active", nullptr, nullptr, &prof, 1); + err |= mallctl("prof.thread_active_init", nullptr, nullptr, &prof, 1); if (err) { LOG(WARNING) << "jemalloc heap profiling start failed, " << err; } else { @@ -48,7 +48,7 @@ bool HeapProfiler::get_prof_dump(const std::string& profile_file_name) { std::lock_guard guard(_mutex); const char* file_name_ptr = profile_file_name.c_str(); try { - int err = jemallctl("prof.dump", nullptr, nullptr, &file_name_ptr, sizeof(const char*)); + int err = mallctl("prof.dump", nullptr, nullptr, &file_name_ptr, sizeof(const char*)); if (err) { LOG(WARNING) << "dump heap profile failed, " << err; return false; @@ -93,7 +93,7 @@ bool HeapProfiler::check_heap_profiler() { #ifdef USE_JEMALLOC size_t value = 0; size_t sz = sizeof(value); - jemallctl("prof.active", &value, &sz, nullptr, 0); + mallctl("prof.active", &value, &sz, nullptr, 0); return value; #else return false; diff --git a/be/src/util/mem_info.cpp b/be/src/util/mem_info.cpp index fe9cf84b2aed54..97e529ac6c72e1 100644 --- a/be/src/util/mem_info.cpp +++ b/be/src/util/mem_info.cpp @@ -101,7 +101,7 @@ void MemInfo::refresh_allocator_mem() { // the current epoch number, which might be useful to log as a sanity check. uint64_t epoch = 0; size_t sz = sizeof(epoch); - jemallctl("epoch", &epoch, &sz, &epoch, sz); + mallctl("epoch", &epoch, &sz, &epoch, sz); // Number of extents of the given type in this arena in the bucket corresponding to page size index. // Large size class starts at 16384, the extents have three sizes before 16384: 4096, 8192, and 12288, so + 3 diff --git a/be/src/util/mem_info.h b/be/src/util/mem_info.h index 39ae9eb0b79cfb..0e14b64bd8f965 100644 --- a/be/src/util/mem_info.h +++ b/be/src/util/mem_info.h @@ -103,7 +103,7 @@ class MemInfo { #ifdef USE_JEMALLOC size_t value = 0; size_t sz = sizeof(value); - if (jemallctl(name.c_str(), &value, &sz, nullptr, 0) == 0) { + if (mallctl(name.c_str(), &value, &sz, nullptr, 0) == 0) { return value; } #endif @@ -114,7 +114,7 @@ class MemInfo { #ifdef USE_JEMALLOC unsigned value = 0; size_t sz = sizeof(value); - if (jemallctl(name.c_str(), &value, &sz, nullptr, 0) == 0) { + if (mallctl(name.c_str(), &value, &sz, nullptr, 0) == 0) { return value; } #endif @@ -146,8 +146,8 @@ class MemInfo { if (config::enable_je_purge_dirty_pages) { try { // Purge all unused dirty pages for arena , or for all arenas if equals MALLCTL_ARENAS_ALL. - int err = jemallctl(fmt::format("arena.{}.purge", MALLCTL_ARENAS_ALL).c_str(), - nullptr, nullptr, nullptr, 0); + int err = mallctl(fmt::format("arena.{}.purge", MALLCTL_ARENAS_ALL).c_str(), + nullptr, nullptr, nullptr, 0); if (err) { LOG(WARNING) << "Jemalloc purge all unused dirty pages failed"; } @@ -166,7 +166,7 @@ class MemInfo { #ifdef USE_JEMALLOC constexpr size_t TCACHE_LIMIT = (1ULL << 30); // 1G if (allocator_cache_mem() - je_dirty_pages_mem() > TCACHE_LIMIT) { - int err = jemallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0); + int err = mallctl("thread.tcache.flush", nullptr, nullptr, nullptr, 0); if (err) { LOG(WARNING) << "Jemalloc thread.tcache.flush failed"; } diff --git a/be/src/vec/common/allocator.h b/be/src/vec/common/allocator.h index b05128bc6933cc..a0ab9c8c0a8207 100644 --- a/be/src/vec/common/allocator.h +++ b/be/src/vec/common/allocator.h @@ -109,7 +109,7 @@ class DefaultMemoryAllocator { static void release_unused() { #if defined(USE_JEMALLOC) - jemallctl(fmt::format("arena.{}.purge", MALLCTL_ARENAS_ALL).c_str(), NULL, NULL, NULL, 0); + mallctl(fmt::format("arena.{}.purge", MALLCTL_ARENAS_ALL).c_str(), NULL, NULL, NULL, 0); #endif // defined(USE_JEMALLOC) } }; diff --git a/build.sh b/build.sh index da4e701f42146a..89a22842b7d100 100755 --- a/build.sh +++ b/build.sh @@ -377,20 +377,6 @@ if [[ "${BUILD_TYPE_LOWWER}" == "asan" ]]; then elif [[ -z "${USE_JEMALLOC}" ]]; then USE_JEMALLOC='ON' fi -if [[ -f "${TP_INCLUDE_DIR}/jemalloc/jemalloc_doris_with_prefix.h" ]]; then - # compatible with old thirdparty - rm -rf "${TP_INCLUDE_DIR}/jemalloc/jemalloc.h" - rm -rf "${TP_LIB_DIR}/libjemalloc_doris.a" - rm -rf "${TP_LIB_DIR}/libjemalloc_doris_pic.a" - rm -rf "${TP_INCLUDE_DIR}/rocksdb" - rm -rf "${TP_LIB_DIR}/librocksdb.a" - - mv "${TP_INCLUDE_DIR}/jemalloc/jemalloc_doris_with_prefix.h" "${TP_INCLUDE_DIR}/jemalloc/jemalloc.h" - mv "${TP_LIB_DIR}/libjemalloc_doris_with_prefix.a" "${TP_LIB_DIR}/libjemalloc_doris.a" - mv "${TP_LIB_DIR}/libjemalloc_doris_with_prefix_pic.a" "${TP_LIB_DIR}/libjemalloc_doris_pic.a" - mv "${TP_LIB_DIR}/librocksdb_jemalloc_with_prefix.a" "${TP_LIB_DIR}/librocksdb.a" - mv -f "${TP_INCLUDE_DIR}/rocksdb_jemalloc_with_prefix" "${TP_INCLUDE_DIR}/rocksdb" -fi if [[ -z "${USE_BTHREAD_SCANNER}" ]]; then USE_BTHREAD_SCANNER='OFF' fi diff --git a/cloud/src/common/CMakeLists.txt b/cloud/src/common/CMakeLists.txt index 429748909bebd9..008e8906044d51 100644 --- a/cloud/src/common/CMakeLists.txt +++ b/cloud/src/common/CMakeLists.txt @@ -15,12 +15,6 @@ set(COMMON_FILES network_util.cpp ) -if (USE_JEMALLOC) - set(COMMON_FILES ${COMMON_FILES} - jemalloc_hook.cpp - ) -endif() - add_library(Common STATIC ${COMMON_FILES} ) diff --git a/thirdparty/build-thirdparty.sh b/thirdparty/build-thirdparty.sh index f019f5f1e26bb2..a209977769c278 100755 --- a/thirdparty/build-thirdparty.sh +++ b/thirdparty/build-thirdparty.sh @@ -1529,8 +1529,10 @@ build_jemalloc_doris() { WITH_LG_PAGE='' fi + # CFLAGS="${cflags}" ../configure --prefix="${TP_INSTALL_DIR}" --with-install-suffix="_doris" "${WITH_LG_PAGE}" \ + # --with-jemalloc-prefix=je --enable-prof --disable-cxx --disable-libdl --disable-shared CFLAGS="${cflags}" ../configure --prefix="${TP_INSTALL_DIR}" --with-install-suffix="_doris" "${WITH_LG_PAGE}" \ - --with-jemalloc-prefix=je --enable-prof --disable-cxx --disable-libdl --disable-shared + --enable-prof --disable-libdl --disable-shared make -j "${PARALLEL}" make install From f85b40877c7ee20489d51fb287579f6ac92935f0 Mon Sep 17 00:00:00 2001 From: Xinyi Zou Date: Fri, 13 Dec 2024 11:43:01 +0800 Subject: [PATCH 37/63] [chore](arrow-flight-sql) Add Arrow Flight Sql demo for Java (#45306) ### What problem does this PR solve? # How to use: 1. mvn clean install -U 2. mvn package 3. java --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED -cp java-0.1.jar doris.arrowflight.demo.Main "sql" "fe_ip" "fe_arrow_flight_port" "fe_query_port" # What can this demo do: This is a java demo for doris arrow flight sql, you can use this to test various connection methods for sending queries to the doris arrow flight server, help you understand how to use arrow flight sql and test performance. You should install maven prior to run this demo. # Performance test Section 6.2 of https://github.com/apache/doris/issues/25514 is the performance test results of the Doris Arrow Flight SQL using java. # Output ``` WARNING: Unknown module: org.apache.arrow.memory.core specified to --add-opens ************************************* | FlightAdbcDriver | ************************************* FlightAdbcDriver > loadArrowBatch SLF4J(W): No SLF4J providers were found. SLF4J(W): Defaulting to no-operation (NOP) logger implementation SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details. > Schema > 1994-08-17, > batchCount: 25, rowCount: 100000 > cost: 1704 ms. FlightAdbcDriver > loadArrowBatchToString > Schema > 1992-01-02, > batchCount: 25, rowCount: 100000 > cost: 1692 ms. ************************************* | FlightJdbcDriver | ************************************* FlightJdbcDriver > loadArrowBatch > Schema > 1997-01-30, > batchCount: 98, rowCount: 100000 > cost: 1840 ms. FlightJdbcDriver > loadArrowBatchToString > Schema > 1992-01-02, > batchCount: 98, rowCount: 100000 > cost: 1712 ms. ************************************* | JdbcDriverManager | ************************************* JdbcDriverManager > jdbc:mysql > loadJdbcResult > rowCount: 100000, columnCount: 1 > cost: 11431 ms. JdbcDriverManager > jdbc:mysql > loadJdbcResultToString > 1992-01-02, > rowCount: 100000, columnCount: 1 resultSize: 100000 > cost: 5164 ms. JdbcDriverManager > jdbc:arrow-flight-sql > loadJdbcResultToString > rowCount: 100000, columnCount: 1 > cost: 1736 ms. JdbcDriverManager > jdbc:arrow-flight-sql > loadJdbcResultToString > 1997-01-29, > rowCount: 100000, columnCount: 1 resultSize: 100000 > cost: 2442 ms. ************************************* | FlightSqlClient | ************************************* FlightSqlClient > getFlightInfoFromDorisFe > Schema > 1994-08-15, > batchCount: 25, rowCount: 100000 FlightSqlClient > constructDummyFlightInfo, don't be afraid! expected to get error `INVALID_ARGUMENT: Malformed ticket` org.apache.arrow.flight.FlightRuntimeException: INVALID_ARGUMENT: Malformed ticket, size: 1 at org.apache.arrow.flight.CallStatus.toRuntimeException(CallStatus.java:121) at org.apache.arrow.flight.grpc.StatusUtils.fromGrpcRuntimeException(StatusUtils.java:161) at org.apache.arrow.flight.grpc.StatusUtils.fromThrowable(StatusUtils.java:182) at org.apache.arrow.flight.FlightStream$Observer.onError(FlightStream.java:489) at org.apache.arrow.flight.FlightClient$1.onError(FlightClient.java:371) at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:481) at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39) at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23) at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40) at org.apache.arrow.flight.grpc.ClientInterceptorAdapter$FlightClientCallListener.onClose(ClientInterceptorAdapter.java:118) at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:564) at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:72) at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:729) at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:710) at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:842) Process finished with exit code 0 ``` --- samples/arrow-flight-sql/java/README.md | 35 ++++ samples/arrow-flight-sql/java/pom.xml | 186 ++++++++++++++++++ .../arrowflight/demo/ArrowBatchReader.java | 110 +++++++++++ .../doris/arrowflight/demo/Configuration.java | 42 ++++ .../arrowflight/demo/FlightAdbcDriver.java | 90 +++++++++ .../arrowflight/demo/FlightJdbcDriver.java | 86 ++++++++ .../arrowflight/demo/FlightSqlClient.java | 144 ++++++++++++++ .../arrowflight/demo/JdbcDriverManager.java | 90 +++++++++ .../arrowflight/demo/JdbcResultSetReader.java | 63 ++++++ .../java/doris/arrowflight/demo/Main.java | 30 +++ .../arrowflight/demo/ConfigurationTest.java | 35 ++++ 11 files changed, 911 insertions(+) create mode 100644 samples/arrow-flight-sql/java/README.md create mode 100644 samples/arrow-flight-sql/java/pom.xml create mode 100644 samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/ArrowBatchReader.java create mode 100644 samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/Configuration.java create mode 100644 samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightAdbcDriver.java create mode 100644 samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightJdbcDriver.java create mode 100644 samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightSqlClient.java create mode 100644 samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/JdbcDriverManager.java create mode 100644 samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/JdbcResultSetReader.java create mode 100644 samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/Main.java create mode 100644 samples/arrow-flight-sql/java/src/test/java/doris/arrowflight/demo/ConfigurationTest.java diff --git a/samples/arrow-flight-sql/java/README.md b/samples/arrow-flight-sql/java/README.md new file mode 100644 index 00000000000000..1eb574e2ab6626 --- /dev/null +++ b/samples/arrow-flight-sql/java/README.md @@ -0,0 +1,35 @@ + + +# How to use: + + 1. mvn clean install -U + 2. mvn package + 3. java --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED -cp java-0.1.jar doris.arrowflight.demo.Main "sql" "fe_ip" "fe_arrow_flight_port" "fe_query_port" + +# What can this demo do: + + This is a java demo for doris arrow flight sql, you can use this to test various connection + methods for sending queries to the doris arrow flight server, help you understand how to use arrow flight sql + and test performance. You should install maven prior to run this demo. + +# Performance test + + Section 6.2 of https://github.com/apache/doris/issues/25514 is the performance test + results of the doris arrow flight sql using java. \ No newline at end of file diff --git a/samples/arrow-flight-sql/java/pom.xml b/samples/arrow-flight-sql/java/pom.xml new file mode 100644 index 00000000000000..d08e30d69aec0b --- /dev/null +++ b/samples/arrow-flight-sql/java/pom.xml @@ -0,0 +1,186 @@ + + + + 4.0.0 + + doris.arrowflight.demo + java + 0.1 + + + 17 + 17 + UTF-8 + + 18.1.0 + 0.15.0 + 2.17.1 + + + + + org.apache.arrow.adbc + adbc-driver-jdbc + ${adbc.version} + + + org.apache.arrow.adbc + adbc-driver-flight-sql + ${adbc.version} + + + mysql + mysql-connector-java + 8.0.33 + + + org.apache.arrow + arrow-memory-core + ${arrow.version} + + + org.apache.arrow + arrow-memory-netty + ${arrow.version} + + + org.apache.arrow + arrow-vector + ${arrow.version} + + + org.apache.arrow + arrow-vector + ${arrow.version} + + + org.apache.arrow + flight-core + ${arrow.version} + + + org.apache.arrow + flight-sql + ${arrow.version} + + + + org.apache.arrow.adbc + adbc-core + ${adbc.version} + + + org.apache.arrow.adbc + adbc-driver-manager + ${adbc.version} + + + org.apache.arrow.adbc + adbc-sql + ${adbc.version} + + + org.apache.arrow + flight-sql-jdbc-core + ${arrow.version} + + + junit + junit + 4.13.1 + test + + + org.junit.jupiter + junit-jupiter + RELEASE + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.4.1 + + + package + + shade + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/ArrowBatchReader.java b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/ArrowBatchReader.java new file mode 100644 index 00000000000000..2522187db6d1b4 --- /dev/null +++ b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/ArrowBatchReader.java @@ -0,0 +1,110 @@ +// 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. + +package doris.arrowflight.demo; + +import org.apache.arrow.vector.ValueVector; +import org.apache.arrow.vector.VectorSchemaRoot; +import org.apache.arrow.vector.ipc.ArrowReader; +import org.apache.arrow.vector.types.pojo.Field; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + + +/** + * Iterate over each batch in ArrowReader. + * ArrowReader is the iterator returned by ADBC Client when executing a query. + */ +public class ArrowBatchReader { + + @FunctionalInterface + public interface LoadArrowBatchFunc { + void load(ArrowReader reader) throws IOException; + } + + /** + * Print one row in VectorSchemaRoot, if the output format is incorrect, may need to modify + * the output method of different types of ValueVector. + */ + public static void printRow(VectorSchemaRoot root, int rowIndex) { + if (root == null || rowIndex < 0 || rowIndex >= root.getRowCount()) { + System.out.println("Invalid row index: " + rowIndex); + return; + } + + System.out.print("> "); + for (Field field : root.getSchema().getFields()) { + ValueVector vector = root.getVector(field.getName()); + if (vector != null) { + if (vector instanceof org.apache.arrow.vector.DateDayVector) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + int dayOffset = ((org.apache.arrow.vector.DateDayVector) vector).get(rowIndex); + LocalDate date = LocalDate.ofEpochDay(dayOffset); + System.out.print(date.format(formatter)); + } else if (vector instanceof org.apache.arrow.vector.BitVector) { + System.out.print(((org.apache.arrow.vector.BitVector) vector).get(rowIndex) == 1); + } else { + // other types field + System.out.print(vector.getObject(rowIndex).toString()); + } + System.out.print(", "); + } + } + System.out.println(); + } + + /** + * Iterate over each batch in ArrowReader with the least cost, only record the number of rows and batches, + * usually used to test performance. + */ + public static LoadArrowBatchFunc loadArrowBatch = reader -> { + int rowCount = 0; + int batchCount = 0; + while (reader.loadNextBatch()) { + VectorSchemaRoot root = reader.getVectorSchemaRoot(); + if (batchCount == 0) { + System.out.println("> " + root.getSchema().toString()); + printRow(root, 1); // only print first line + } + rowCount += root.getRowCount(); + batchCount += 1; + } + System.out.println("> batchCount: " + batchCount + ", rowCount: " + rowCount); + }; + + /** + * Iterate over each batch in ArrowReader and convert the batch to String, this will take more time. + */ + public static LoadArrowBatchFunc loadArrowBatchToString = reader -> { + int rowCount = 0; + List result = new ArrayList<>(); + while (reader.loadNextBatch()) { + VectorSchemaRoot root = reader.getVectorSchemaRoot(); + if (result.size() == 0) { + System.out.println("> " + root.getSchema().toString()); + printRow(root, 0); // only print first line + } + result.add(root.contentToTSVString()); + rowCount += root.getRowCount(); + } + System.out.println("> batchCount: " + result.size() + ", rowCount: " + rowCount); + }; +} diff --git a/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/Configuration.java b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/Configuration.java new file mode 100644 index 00000000000000..c40a46ca057f9b --- /dev/null +++ b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/Configuration.java @@ -0,0 +1,42 @@ +// 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. + +package doris.arrowflight.demo; + +public class Configuration { + public String sql = ""; // require + public String ip = "127.0.0.1"; // require + public String arrowFlightPort = "9090"; // require + public String mysqlPort = "9030"; + public int retryTimes = 2; // The first execution is cold run + public String user = "root"; + public String password = ""; + + Configuration(String[] args) { + for (int i = 0; i < args.length; i++) { + switch (i) { + case 0 -> sql = args[i]; + case 1 -> ip = args[i]; + case 2 -> arrowFlightPort = args[i]; + case 3 -> mysqlPort = args[i]; + case 4 -> retryTimes = Integer.parseInt(args[i]); + case 5 -> user = args[i]; + case 6 -> password = args[i]; + } + } + } +} diff --git a/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightAdbcDriver.java b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightAdbcDriver.java new file mode 100644 index 00000000000000..3c2202b2b07797 --- /dev/null +++ b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightAdbcDriver.java @@ -0,0 +1,90 @@ +// 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. + +package doris.arrowflight.demo; + +import doris.arrowflight.demo.ArrowBatchReader.LoadArrowBatchFunc; +import org.apache.arrow.adbc.core.AdbcConnection; +import org.apache.arrow.adbc.core.AdbcDatabase; +import org.apache.arrow.adbc.core.AdbcDriver; +import org.apache.arrow.adbc.core.AdbcStatement; +import org.apache.arrow.adbc.core.AdbcStatement.QueryResult; +import org.apache.arrow.adbc.driver.flightsql.FlightSqlDriver; +import org.apache.arrow.flight.Location; +import org.apache.arrow.memory.BufferAllocator; +import org.apache.arrow.memory.RootAllocator; +import org.apache.arrow.vector.ipc.ArrowReader; + +import java.util.HashMap; +import java.util.Map; + +/** + * Use the Arrow Flight ADBC driver to connect to the Doris Arrow Flight server and execute query. + */ +public class FlightAdbcDriver { + private static void connectAndExecute(Configuration configuration, LoadArrowBatchFunc loadArrowReader) { + final BufferAllocator allocator = new RootAllocator(); + FlightSqlDriver driver = new FlightSqlDriver(allocator); + Map parameters = new HashMap<>(); + AdbcDriver.PARAM_URI.set(parameters, + Location.forGrpcInsecure(configuration.ip, Integer.parseInt(configuration.arrowFlightPort)).getUri() + .toString()); + AdbcDriver.PARAM_USERNAME.set(parameters, configuration.user); + AdbcDriver.PARAM_PASSWORD.set(parameters, configuration.password); + + try { + AdbcDatabase adbcDatabase = driver.open(parameters); + AdbcConnection connection = adbcDatabase.connect(); + AdbcStatement stmt = connection.createStatement(); + long start = System.currentTimeMillis(); + stmt.setSqlQuery(configuration.sql); + + // executeQuery, two steps: + // 1. Execute Query and get returned FlightInfo; + // 2. Create FlightInfoReader to sequentially traverse each Endpoint; + QueryResult queryResult = stmt.executeQuery(); + ArrowReader reader = queryResult.getReader(); + loadArrowReader.load(reader); + System.out.printf("> cost: %d ms.\n\n", (System.currentTimeMillis() - start)); + + reader.close(); + queryResult.close(); + stmt.close(); + connection.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void run(Configuration configuration) { + System.out.println("*************************************"); + System.out.println("| FlightAdbcDriver |"); + System.out.println("*************************************"); + + System.out.println("FlightAdbcDriver > loadArrowBatch"); + connectAndExecute(configuration, ArrowBatchReader.loadArrowBatch); + System.out.println("FlightAdbcDriver > loadArrowBatchToString"); + connectAndExecute(configuration, ArrowBatchReader.loadArrowBatchToString); + } + + public static void main(String[] args) throws Exception { + Configuration configuration = new Configuration(args); + for (int i = 0; i < configuration.retryTimes; i++) { + run(configuration); + } + } +} diff --git a/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightJdbcDriver.java b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightJdbcDriver.java new file mode 100644 index 00000000000000..1560e5172d7384 --- /dev/null +++ b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightJdbcDriver.java @@ -0,0 +1,86 @@ +// 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. + +package doris.arrowflight.demo; + +import doris.arrowflight.demo.ArrowBatchReader.LoadArrowBatchFunc; +import org.apache.arrow.adbc.core.AdbcConnection; +import org.apache.arrow.adbc.core.AdbcDatabase; +import org.apache.arrow.adbc.core.AdbcDriver; +import org.apache.arrow.adbc.core.AdbcStatement; +import org.apache.arrow.adbc.driver.jdbc.JdbcDriver; +import org.apache.arrow.memory.BufferAllocator; +import org.apache.arrow.memory.RootAllocator; +import org.apache.arrow.vector.ipc.ArrowReader; + +import java.util.HashMap; +import java.util.Map; + +/** + * Use the Arrow Flight JDBC driver to connect to the Doris Arrow Flight server and execute query. + * Unlike the Java JDBC DriverManager, this is a JDBC Driver provided by Arrow Flight, which may contain + * some optimizations (although no performance advantage was observed). + */ +public class FlightJdbcDriver { + private static void connectAndExecute(Configuration configuration, LoadArrowBatchFunc loadArrowReader) { + String DB_URL = "jdbc:arrow-flight-sql://" + configuration.ip + ":" + configuration.arrowFlightPort + + "?useServerPrepStmts=false" + "&cachePrepStmts=true&useSSL=false&useEncryption=false"; + final Map parameters = new HashMap<>(); + AdbcDriver.PARAM_URI.set(parameters, DB_URL); + AdbcDriver.PARAM_USERNAME.set(parameters, configuration.user); + AdbcDriver.PARAM_PASSWORD.set(parameters, configuration.password); + + try { + BufferAllocator allocator = new RootAllocator(); + AdbcDatabase db = new JdbcDriver(allocator).open(parameters); + AdbcConnection connection = db.connect(); + AdbcStatement stmt = connection.createStatement(); + + long start = System.currentTimeMillis(); + stmt.setSqlQuery(configuration.sql); + AdbcStatement.QueryResult queryResult = stmt.executeQuery(); + ArrowReader reader = queryResult.getReader(); + loadArrowReader.load(reader); + System.out.printf("> cost: %d ms.\n\n", (System.currentTimeMillis() - start)); + + reader.close(); + queryResult.close(); + stmt.close(); + connection.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void run(Configuration configuration) { + System.out.println("*************************************"); + System.out.println("| FlightJdbcDriver |"); + System.out.println("*************************************"); + + System.out.println("FlightJdbcDriver > loadArrowBatch"); + connectAndExecute(configuration, ArrowBatchReader.loadArrowBatch); + System.out.println("FlightJdbcDriver > loadArrowBatchToString"); + connectAndExecute(configuration, ArrowBatchReader.loadArrowBatchToString); + } + + public static void main(String[] args) { + Configuration configuration = new Configuration(args); + for (int i = 0; i < configuration.retryTimes; i++) { + run(configuration); + } + } +} diff --git a/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightSqlClient.java b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightSqlClient.java new file mode 100644 index 00000000000000..3a01ea16370d4b --- /dev/null +++ b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/FlightSqlClient.java @@ -0,0 +1,144 @@ +// 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. + +package doris.arrowflight.demo; + +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import org.apache.arrow.flight.FlightClient; +import org.apache.arrow.flight.FlightInfo; +import org.apache.arrow.flight.FlightStream; +import org.apache.arrow.flight.Location; +import org.apache.arrow.flight.Ticket; +import org.apache.arrow.flight.auth2.BearerCredentialWriter; +import org.apache.arrow.flight.grpc.CredentialCallOption; +import org.apache.arrow.flight.sql.impl.FlightSql.TicketStatementQuery; +import org.apache.arrow.memory.BufferAllocator; +import org.apache.arrow.memory.RootAllocator; +import org.apache.arrow.vector.VectorSchemaRoot; + +import java.net.URI; +import java.net.URISyntaxException; + +/** + * Manually execute Arrow Flight SQL Rpc process, usually used for debug. + */ +public class FlightSqlClient { + public record FlightInfoResult(T first, T2 second, T3 third) { + } + + public record DummyFlightInfoResult(T first, T2 second) { + } + + /** + * Connect to FE Arrow Flight Server to obtain Bearertoken and execute Query to get Ticket. + */ + public static FlightInfoResult getFlightInfoFromDorisFe( + Configuration configuration) throws URISyntaxException { + BufferAllocator allocatorFE = new RootAllocator(Integer.MAX_VALUE); + final Location clientLocationFE = new Location( + new URI("grpc", null, configuration.ip, Integer.parseInt(configuration.arrowFlightPort), + null, null, null)); + FlightClient clientFE = FlightClient.builder(allocatorFE, clientLocationFE).build(); + org.apache.arrow.flight.sql.FlightSqlClient sqlClinetFE = new org.apache.arrow.flight.sql.FlightSqlClient( + clientFE); + + // Use username and password authentication to obtain a Bearertoken for subsequent access to the Doris Arrow Flight Server. + CredentialCallOption credentialCallOption = clientFE.authenticateBasicToken(configuration.user, + configuration.password).get(); + final org.apache.arrow.flight.sql.FlightSqlClient.PreparedStatement preparedStatement = sqlClinetFE.prepare( + configuration.sql, + credentialCallOption); + final FlightInfo info = preparedStatement.execute(credentialCallOption); + return new FlightInfoResult<>(info, credentialCallOption, preparedStatement); + } + + /** + * Use the correct Bearertoken and the correct Ticket, and the expected return result is normal. + */ + public static void getResultFromDorisBe(FlightInfo info, Ticket ticket, CredentialCallOption credentialCallOption) + throws Exception { + final Location locationBE = info.getEndpoints().get(0).getLocations().get(0); + // 连接 BE Arrow Flight Server + BufferAllocator allocatorBE = new RootAllocator(Integer.MAX_VALUE); + FlightClient clientBE = FlightClient.builder(allocatorBE, locationBE).build(); + org.apache.arrow.flight.sql.FlightSqlClient sqlClinetBE = new org.apache.arrow.flight.sql.FlightSqlClient( + clientBE); + + FlightStream stream = sqlClinetBE.getStream(ticket, credentialCallOption); + int rowCount = 0; + int batchCount = 0; + while (stream.next()) { + VectorSchemaRoot root = stream.getRoot(); + if (batchCount == 0) { + System.out.println("> " + root.getSchema().toString()); + ArrowBatchReader.printRow(root, 1); // only print first line + } + rowCount += root.getRowCount(); + batchCount += 1; + } + System.out.println("> batchCount: " + batchCount + ", rowCount: " + rowCount); + stream.close(); + } + + /** + * Construct a dummy Ticket and CredentialCallOption to simulate the BE Arrow Flight Server being hacked, + * to analyze data security. + * + * @return get error `INVALID_ARGUMENT: Malformed ticket` + */ + public static DummyFlightInfoResult constructDummyFlightInfo() { + String Bearertoken = "ojatddjr72k1ss20sqkatkhtd7"; + String queryId = "18c64b4e15094922-af5fea3da80fb89f"; + String query = "select * from clickbench.hits limit 10;"; + CredentialCallOption dummyCredentialCallOption = new CredentialCallOption( + new BearerCredentialWriter(Bearertoken)); + final ByteString handle = ByteString.copyFromUtf8(queryId + ":" + query); + TicketStatementQuery ticketStatement = TicketStatementQuery.newBuilder().setStatementHandle(handle).build(); + final Ticket dummyTicket = new Ticket(Any.pack(ticketStatement).toByteArray()); + return new DummyFlightInfoResult<>(dummyTicket, dummyCredentialCallOption); + } + + public static void run(Configuration configuration) { + System.out.println("*************************************"); + System.out.println("| FlightSqlClient |"); + System.out.println("*************************************"); + + try { + System.out.println("FlightSqlClient > getFlightInfoFromDorisFe"); + var flightInfo = getFlightInfoFromDorisFe(configuration); + getResultFromDorisBe(flightInfo.first(), flightInfo.first().getEndpoints().get(0).getTicket(), + flightInfo.second()); + System.out.println(); + + System.out.println( + "FlightSqlClient > constructDummyFlightInfo, don't be afraid! expected to get error `INVALID_ARGUMENT: Malformed ticket`"); + var dummyFlightInfo = constructDummyFlightInfo(); + getResultFromDorisBe(flightInfo.first(), dummyFlightInfo.first(), dummyFlightInfo.second()); + System.out.println(); + + flightInfo.third().close(flightInfo.second()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + Configuration configuration = new Configuration(args); + run(configuration); + } +} diff --git a/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/JdbcDriverManager.java b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/JdbcDriverManager.java new file mode 100644 index 00000000000000..3cc07c738470b3 --- /dev/null +++ b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/JdbcDriverManager.java @@ -0,0 +1,90 @@ +// 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. + +package doris.arrowflight.demo; + +import doris.arrowflight.demo.JdbcResultSetReader.LoadJdbcResultSetFunc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.Objects; + +/** + * Use the Java JDBC DriverManager to connect to the Doris Arrow Flight server and execute query. + * Usually, DriverManager is used to connect to the database using the Mysql protocol in Java. only need to replace + * `jdbc:mysql` in the URI with `jdbc:arrow-flight-sql` to connect to the database using the Arrow Flight SQL protocol + * (provided that the database implements the Arrow Flight server). + */ +public class JdbcDriverManager { + private static void connectAndExecute(Configuration configuration, String urlPrefix, String port, + LoadJdbcResultSetFunc loadJdbcResultSetFunc) { + String DB_URL = urlPrefix + "://" + configuration.ip + ":" + port + "?useServerPrepStmts=false" + + "&cachePrepStmts=true&useSSL=false&useEncryption=false"; + try { + long start = System.currentTimeMillis(); + Connection conn = DriverManager.getConnection(DB_URL, configuration.user, configuration.password); + Statement stmt = conn.createStatement(); + stmt.execute(configuration.sql); + + final ResultSet resultSet = stmt.getResultSet(); + loadJdbcResultSetFunc.load(resultSet); + System.out.printf("> cost: %d ms.\n\n", (System.currentTimeMillis() - start)); + + stmt.close(); + conn.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void run(Configuration configuration) { + System.out.println("*************************************"); + System.out.println("| JdbcDriverManager |"); + System.out.println("*************************************"); + + try { + if (!Objects.equals(configuration.mysqlPort, "")) { + Class.forName("com.mysql.cj.jdbc.Driver"); + System.out.println("JdbcDriverManager > jdbc:mysql > loadJdbcResult"); + connectAndExecute(configuration, "jdbc:mysql", configuration.mysqlPort, + JdbcResultSetReader.loadJdbcResult); + System.out.println("JdbcDriverManager > jdbc:mysql > loadJdbcResultToString"); + connectAndExecute(configuration, "jdbc:mysql", configuration.mysqlPort, + JdbcResultSetReader.loadJdbcResultToString); + } + + Class.forName("org.apache.arrow.driver.jdbc.ArrowFlightJdbcDriver"); + System.out.println("JdbcDriverManager > jdbc:arrow-flight-sql > loadJdbcResultToString"); + connectAndExecute(configuration, "jdbc:arrow-flight-sql", configuration.arrowFlightPort, + JdbcResultSetReader.loadJdbcResult); + System.out.println("JdbcDriverManager > jdbc:arrow-flight-sql > loadJdbcResultToString"); + connectAndExecute(configuration, "jdbc:arrow-flight-sql", configuration.arrowFlightPort, + JdbcResultSetReader.loadJdbcResultToString); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) throws ClassNotFoundException { + Configuration configuration = new Configuration(args); + for (int i = 0; i < configuration.retryTimes; i++) { + run(configuration); + } + } +} diff --git a/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/JdbcResultSetReader.java b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/JdbcResultSetReader.java new file mode 100644 index 00000000000000..ac9f24a5ca50d1 --- /dev/null +++ b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/JdbcResultSetReader.java @@ -0,0 +1,63 @@ +// 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. + +package doris.arrowflight.demo; + +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Iterate over each row in jdbc ResultSet. + */ +public class JdbcResultSetReader { + + @FunctionalInterface + public interface LoadJdbcResultSetFunc { + void load(ResultSet resultSet) throws IOException, SQLException; + } + + public static LoadJdbcResultSetFunc loadJdbcResult = resultSet -> { + int rowCount = 0; + final int columnCount = resultSet.getMetaData().getColumnCount(); + while (resultSet.next()) { + rowCount += 1; + } + System.out.println("> rowCount: " + rowCount + ", columnCount: " + columnCount); + }; + + public static LoadJdbcResultSetFunc loadJdbcResultToString = resultSet -> { + int rowCount = 0; + final int columnCount = resultSet.getMetaData().getColumnCount(); + List result = new ArrayList<>(); + while (resultSet.next()) { + StringBuilder line = new StringBuilder(); + for (int i = 1; i <= columnCount; i++) { + line.append(resultSet.getString(i)).append(","); + } + if (rowCount == 0) { // only print first line + System.out.println("> " + line); + } + rowCount += 1; + result.add(line.toString()); + } + System.out.println( + "> rowCount: " + rowCount + ", columnCount: " + columnCount + " resultSize: " + result.size()); + }; +} diff --git a/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/Main.java b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/Main.java new file mode 100644 index 00000000000000..2f9a8d20a879d1 --- /dev/null +++ b/samples/arrow-flight-sql/java/src/main/java/doris/arrowflight/demo/Main.java @@ -0,0 +1,30 @@ +// 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. + +package doris.arrowflight.demo; + +public class Main { + public static void main(String[] args) { + Configuration configuration = new Configuration(args); + for (int i = 0; i < configuration.retryTimes; i++) { + FlightAdbcDriver.run(configuration); + FlightJdbcDriver.run(configuration); + JdbcDriverManager.run(configuration); + } + FlightSqlClient.run(configuration); + } +} diff --git a/samples/arrow-flight-sql/java/src/test/java/doris/arrowflight/demo/ConfigurationTest.java b/samples/arrow-flight-sql/java/src/test/java/doris/arrowflight/demo/ConfigurationTest.java new file mode 100644 index 00000000000000..4614730ede6f45 --- /dev/null +++ b/samples/arrow-flight-sql/java/src/test/java/doris/arrowflight/demo/ConfigurationTest.java @@ -0,0 +1,35 @@ +// 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. + +package doris.arrowflight.demo; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; + +/** + * Unit test for simple App. + */ +public class ConfigurationTest { + + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() { + assertTrue(true); + } +} From 6cead2fff51583bc0b567c93e813f33a3185976b Mon Sep 17 00:00:00 2001 From: amory Date: Fri, 13 Dec 2024 11:48:01 +0800 Subject: [PATCH 38/63] [fix](ip)fix default value for ip (#45194) before this pr: we do not support create table for IP type with default value like this: ``` mysql> CREATE TABLE table2 -> ( -> col0 BIGINT NOT NULL DEFAULT '1' , -> col24 IPV4 NULL DEFAULT '127.0.0.1' -> ) -> DUPLICATE KEY(col0) -> DISTRIBUTED BY HASH(col0) BUCKETS 4 -> PROPERTIES ( -> "replication_num" = "1" -> ); ERROR 1105 (HY000): errCode = 2, detailMessage = Unsupported type: ipv4 ``` after this pr we deal with this problem --- .../org/apache/doris/analysis/ColumnDef.java | 6 ++++ .../apache/doris/analysis/IPv4Literal.java | 2 +- .../apache/doris/analysis/IPv6Literal.java | 2 +- .../data/datatype_p0/ip/test_ip_basic.out | 31 +++++++++++++++++++ .../datatype_p0/ip/test_ip_basic.groovy | 26 ++++++++++++++++ 5 files changed, 65 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java index c2c55c4ce7c955..02e123397c69aa 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java @@ -652,6 +652,12 @@ public static void validateDefaultValue(Type type, String defaultValue, DefaultV case BOOLEAN: new BoolLiteral(defaultValue); break; + case IPV4: + new IPv4Literal(defaultValue); + break; + case IPV6: + new IPv6Literal(defaultValue); + break; default: throw new AnalysisException("Unsupported type: " + type); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/IPv4Literal.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/IPv4Literal.java index 6fa84d18b25f41..92063e6b9b30c3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/IPv4Literal.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/IPv4Literal.java @@ -115,7 +115,7 @@ public Expr clone() { @Override protected String toSqlImpl() { - return getStringValue(); + return "\"" + getStringValue() + "\""; } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/IPv6Literal.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/IPv6Literal.java index a3ec7a3a349824..bb986e0ffe7a2c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/IPv6Literal.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/IPv6Literal.java @@ -75,7 +75,7 @@ private void checkValueValid(String ipv6) throws AnalysisException { @Override protected String toSqlImpl() { - return getStringValue(); + return "\"" + getStringValue() + "\""; } @Override diff --git a/regression-test/data/datatype_p0/ip/test_ip_basic.out b/regression-test/data/datatype_p0/ip/test_ip_basic.out index b69f9708a1b1fc..e1b85abe00c41b 100644 --- a/regression-test/data/datatype_p0/ip/test_ip_basic.out +++ b/regression-test/data/datatype_p0/ip/test_ip_basic.out @@ -373,3 +373,34 @@ ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 4 -- !sql -- 1 false 127.0.0.1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +-- !sql -- +1 5be8:dde9:7f0b:d5a7:bd01:b3be:9c69:573b 0.0.0.1 +2 :: 127.0.0.1 + +-- !sql -- +table_ip_default UNIQUE_KEYS col0 bigint bigint No true \N true + col4 ipv6 ipv6 Yes false :: NONE true + col24 ipv4 ipv4 Yes false 127.0.0.1 NONE true + +-- !sql -- +table_ip_default_like UNIQUE_KEYS col0 bigint bigint No true \N true + col4 ipv6 ipv6 Yes false :: NONE true + col24 ipv4 ipv4 Yes false 127.0.0.1 NONE true + +-- !sql -- +2 + +-- !sql -- +1 5be8:dde9:7f0b:d5a7:bd01:b3be:9c69:573b 0.0.0.1 +2 :: 127.0.0.1 + +-- !sql -- +0 + +-- !sql -- +0 + +-- !sql -- +1 5be8:dde9:7f0b:d5a7:bd01:b3be:9c69:573b 0.0.0.1 :: 127.0.0.1 +2 :: 127.0.0.1 :: 127.0.0.1 + diff --git a/regression-test/suites/datatype_p0/ip/test_ip_basic.groovy b/regression-test/suites/datatype_p0/ip/test_ip_basic.groovy index 468b6f6f146e14..5a4ab2ca94aca9 100644 --- a/regression-test/suites/datatype_p0/ip/test_ip_basic.groovy +++ b/regression-test/suites/datatype_p0/ip/test_ip_basic.groovy @@ -160,4 +160,30 @@ suite("test_ip_basic") { qt_sql """ select * from table_ip where col0 = 1""" sql """ Update table_ip set col25 = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' where col0 = 1 """ qt_sql """ select * from table_ip where col0 = 1""" + + // test ip with default value + sql """ DROP TABLE IF EXISTS table_ip_default """ + sql """ CREATE TABLE IF NOT EXISTS `table_ip_default` (`col0` bigint NOT NULL, `col4` ipv6 NULL DEFAULT "::", `col24` ipv4 NULL DEFAULT "127.0.0.1") ENGINE=OLAP UNIQUE KEY(`col0`) DISTRIBUTED BY HASH(`col0`) BUCKETS 4 PROPERTIES ("replication_allocation" = "tag.location.default: 1") """ + sql """ insert into table_ip_default values (1, "5be8:dde9:7f0b:d5a7:bd01:b3be:9c69:573b", "0.0.0.1") """ + sql """ insert into table_ip_default(col0) values (2); """ + qt_sql """ select * from table_ip_default order by col0""" + // add cases for default value to make sure in all cases, the default value is not lost. + // show create table + // desc table + // create table like + // insert into table + // alter new ip column with default value + def result = sql """ show create table table_ip_default """ + log.info("show result : ${result}") + assertTrue(result.toString().containsIgnoreCase("`col4` ipv6 NULL DEFAULT \"::\"")) + assertTrue(result.toString().containsIgnoreCase("`col24` ipv4 NULL DEFAULT \"127.0.0.1\"")) + qt_sql """ desc table_ip_default all""" + sql """ DROP TABLE IF EXISTS table_ip_default_like """ + sql """ create table table_ip_default_like like table_ip_default """ + qt_sql """ desc table_ip_default_like all""" + qt_sql """ insert into table_ip_default_like select * from table_ip_default """ + qt_sql """ select * from table_ip_default_like order by col0 """ + qt_sql """ alter table table_ip_default_like add column col25 ipv6 NULL DEFAULT "::" """ + qt_sql """ alter table table_ip_default_like add column col26 ipv4 NULL DEFAULT "127.0.0.1" """ + qt_sql """ select * from table_ip_default_like order by col0 """ } From 7e478ca5cee5d83420dea8fbbbc40ce086189a23 Mon Sep 17 00:00:00 2001 From: qiye Date: Fri, 13 Dec 2024 13:25:26 +0800 Subject: [PATCH 39/63] [test](index compaction)Add index compaction exception fault injection cases (#45127) Problem Summary: 1. Add skip index compaction logic when index compaction encounters exceptions 2. Optimize fault injection regression cases --- be/src/olap/compaction.cpp | 150 ++++++++++++++---- be/src/olap/compaction.h | 4 + .../segment_v2/inverted_index_compaction.cpp | 11 +- ...ompaction_exception_fault_injection.groovy | 29 ++-- 4 files changed, 151 insertions(+), 43 deletions(-) diff --git a/be/src/olap/compaction.cpp b/be/src/olap/compaction.cpp index 0d811d9348f1f5..aec38699e014a2 100644 --- a/be/src/olap/compaction.cpp +++ b/be/src/olap/compaction.cpp @@ -495,10 +495,35 @@ Status CompactionMixin::execute_compact_impl(int64_t permits) { Status Compaction::do_inverted_index_compaction() { const auto& ctx = _output_rs_writer->context(); if (!config::inverted_index_compaction_enable || _input_row_num <= 0 || - !_stats.rowid_conversion || ctx.columns_to_do_index_compaction.empty()) { + ctx.columns_to_do_index_compaction.empty()) { return Status::OK(); } + auto error_handler = [this](int64_t index_id, int64_t column_uniq_id) { + LOG(WARNING) << "failed to do index compaction" + << ". tablet=" << _tablet->tablet_id() << ". column uniq id=" << column_uniq_id + << ". index_id=" << index_id; + for (auto& rowset : _input_rowsets) { + rowset->set_skip_index_compaction(column_uniq_id); + LOG(INFO) << "mark skipping inverted index compaction next time" + << ". tablet=" << _tablet->tablet_id() << ", rowset=" << rowset->rowset_id() + << ", column uniq id=" << column_uniq_id << ", index_id=" << index_id; + } + }; + + DBUG_EXECUTE_IF("Compaction::do_inverted_index_compaction_rowid_conversion_null", + { _stats.rowid_conversion = nullptr; }) + if (!_stats.rowid_conversion) { + LOG(WARNING) << "failed to do index compaction, rowid conversion is null" + << ". tablet=" << _tablet->tablet_id() + << ", input row number=" << _input_row_num; + mark_skip_index_compaction(ctx, error_handler); + + return Status::Error( + "failed to do index compaction, rowid conversion is null. tablet={}", + _tablet->tablet_id()); + } + OlapStopWatch inverted_watch; // translation vec @@ -521,8 +546,7 @@ Status Compaction::do_inverted_index_compaction() { auto src_segment_num = src_seg_to_id_map.size(); auto dest_segment_num = dest_segment_num_rows.size(); - DBUG_EXECUTE_IF("Compaction::do_inverted_index_compaction_dest_segment_num_is_zero", - { dest_segment_num = 0; }) + // when all the input rowsets are deleted, the output rowset will be empty and dest_segment_num will be 0. if (dest_segment_num <= 0) { LOG(INFO) << "skip doing index compaction due to no output segments" << ". tablet=" << _tablet->tablet_id() << ", input row number=" << _input_row_num @@ -600,27 +624,62 @@ Status Compaction::do_inverted_index_compaction() { DBUG_EXECUTE_IF("Compaction::do_inverted_index_compaction_find_rowset_error", { find_it = rs_id_to_rowset_map.end(); }) if (find_it == rs_id_to_rowset_map.end()) [[unlikely]] { - // DCHECK(false) << _tablet->tablet_id() << ' ' << rowset_id; - return Status::InternalError("cannot find rowset. tablet_id={} rowset_id={}", - _tablet->tablet_id(), rowset_id.to_string()); + LOG(WARNING) << "failed to do index compaction, cannot find rowset. tablet_id=" + << _tablet->tablet_id() << " rowset_id=" << rowset_id.to_string(); + mark_skip_index_compaction(ctx, error_handler); + return Status::Error( + "failed to do index compaction, cannot find rowset. tablet_id={} rowset_id={}", + _tablet->tablet_id(), rowset_id.to_string()); } auto* rowset = find_it->second; auto fs = rowset->rowset_meta()->fs(); DBUG_EXECUTE_IF("Compaction::do_inverted_index_compaction_get_fs_error", { fs = nullptr; }) if (!fs) { - return Status::InternalError("get fs failed, resource_id={}", - rowset->rowset_meta()->resource_id()); + LOG(WARNING) << "failed to do index compaction, get fs failed. resource_id=" + << rowset->rowset_meta()->resource_id(); + mark_skip_index_compaction(ctx, error_handler); + return Status::Error( + "get fs failed, resource_id={}", rowset->rowset_meta()->resource_id()); } - auto seg_path = DORIS_TRY(rowset->segment_path(seg_id)); + auto seg_path = rowset->segment_path(seg_id); + DBUG_EXECUTE_IF("Compaction::do_inverted_index_compaction_seg_path_nullptr", { + seg_path = ResultError(Status::Error( + "do_inverted_index_compaction_seg_path_nullptr")); + }) + if (!seg_path.has_value()) { + LOG(WARNING) << "failed to do index compaction, get segment path failed. tablet_id=" + << _tablet->tablet_id() << " rowset_id=" << rowset_id.to_string() + << " seg_id=" << seg_id; + mark_skip_index_compaction(ctx, error_handler); + return Status::Error( + "get segment path failed. tablet_id={} rowset_id={} seg_id={}", + _tablet->tablet_id(), rowset_id.to_string(), seg_id); + } auto inverted_index_file_reader = std::make_unique( - fs, std::string {InvertedIndexDescriptor::get_index_file_path_prefix(seg_path)}, + fs, + std::string {InvertedIndexDescriptor::get_index_file_path_prefix(seg_path.value())}, _cur_tablet_schema->get_inverted_index_storage_format(), rowset->rowset_meta()->inverted_index_file_info(seg_id)); - RETURN_NOT_OK_STATUS_WITH_WARN( - inverted_index_file_reader->init(config::inverted_index_read_buffer_size), - "inverted_index_file_reader init faiqled"); + auto st = inverted_index_file_reader->init(config::inverted_index_read_buffer_size); + DBUG_EXECUTE_IF("Compaction::do_inverted_index_compaction_init_inverted_index_file_reader", + { + st = Status::Error( + "debug point: " + "Compaction::do_inverted_index_compaction_init_inverted_index_" + "file_reader error"); + }) + if (!st.ok()) { + LOG(WARNING) << "failed to do index compaction, init inverted index file reader " + "failed. tablet_id=" + << _tablet->tablet_id() << " rowset_id=" << rowset_id.to_string() + << " seg_id=" << seg_id; + mark_skip_index_compaction(ctx, error_handler); + return Status::Error( + "init inverted index file reader failed. tablet_id={} rowset_id={} seg_id={}", + _tablet->tablet_id(), rowset_id.to_string(), seg_id); + } inverted_index_file_readers[m.second] = std::move(inverted_index_file_reader); } @@ -628,7 +687,20 @@ Status Compaction::do_inverted_index_compaction() { // format: rowsetId_segmentId auto& inverted_index_file_writers = dynamic_cast(_output_rs_writer.get()) ->inverted_index_file_writers(); - DCHECK_EQ(inverted_index_file_writers.size(), dest_segment_num); + DBUG_EXECUTE_IF( + "Compaction::do_inverted_index_compaction_inverted_index_file_writers_size_error", + { inverted_index_file_writers.clear(); }) + if (inverted_index_file_writers.size() != dest_segment_num) { + LOG(WARNING) << "failed to do index compaction, dest segment num not match. tablet_id=" + << _tablet->tablet_id() << " dest_segment_num=" << dest_segment_num + << " inverted_index_file_writers.size()=" + << inverted_index_file_writers.size(); + mark_skip_index_compaction(ctx, error_handler); + return Status::Error( + "dest segment num not match. tablet_id={} dest_segment_num={} " + "inverted_index_file_writers.size()={}", + _tablet->tablet_id(), dest_segment_num, inverted_index_file_writers.size()); + } // use tmp file dir to store index files auto tmp_file_dir = ExecEnv::GetInstance()->get_tmp_file_dirs()->get_tmp_file_dir(); @@ -637,18 +709,6 @@ Status Compaction::do_inverted_index_compaction() { << ". tablet=" << _tablet->tablet_id() << ", source index size=" << src_segment_num << ", destination index size=" << dest_segment_num << "."; - auto error_handler = [this](int64_t index_id, int64_t column_uniq_id) { - LOG(WARNING) << "failed to do index compaction" - << ". tablet=" << _tablet->tablet_id() << ". column uniq id=" << column_uniq_id - << ". index_id=" << index_id; - for (auto& rowset : _input_rowsets) { - rowset->set_skip_index_compaction(column_uniq_id); - LOG(INFO) << "mark skipping inverted index compaction next time" - << ". tablet=" << _tablet->tablet_id() << ", rowset=" << rowset->rowset_id() - << ", column uniq id=" << column_uniq_id << ", index_id=" << index_id; - } - }; - Status status = Status::OK(); for (auto&& column_uniq_id : ctx.columns_to_do_index_compaction) { auto col = _cur_tablet_schema->column_by_uid(column_uniq_id); @@ -658,6 +718,10 @@ Status Compaction::do_inverted_index_compaction() { if (index_meta == nullptr) { status = Status::Error( fmt::format("Can not find index_meta for col {}", col.name())); + LOG(WARNING) << "failed to do index compaction, can not find index_meta for column" + << ". tablet=" << _tablet->tablet_id() + << ", column uniq id=" << column_uniq_id; + error_handler(-1, column_uniq_id); break; } @@ -671,6 +735,11 @@ Status Compaction::do_inverted_index_compaction() { "debug point: Compaction::open_index_file_reader error")); }) if (!res.has_value()) { + LOG(WARNING) << "failed to do index compaction, open inverted index file " + "reader failed" + << ". tablet=" << _tablet->tablet_id() + << ", column uniq id=" << column_uniq_id + << ", src_segment_id=" << src_segment_id; throw Exception(ErrorCode::INVERTED_INDEX_COMPACTION_ERROR, res.error().msg()); } src_idx_dirs[src_segment_id] = std::move(res.value()); @@ -682,6 +751,11 @@ Status Compaction::do_inverted_index_compaction() { "debug point: Compaction::open_inverted_index_file_writer error")); }) if (!res.has_value()) { + LOG(WARNING) << "failed to do index compaction, open inverted index file " + "writer failed" + << ". tablet=" << _tablet->tablet_id() + << ", column uniq id=" << column_uniq_id + << ", dest_segment_id=" << dest_segment_id; throw Exception(ErrorCode::INVERTED_INDEX_COMPACTION_ERROR, res.error().msg()); } // Destination directories in dest_index_dirs do not need to be deconstructed, @@ -714,6 +788,23 @@ Status Compaction::do_inverted_index_compaction() { return Status::OK(); } +void Compaction::mark_skip_index_compaction( + const RowsetWriterContext& context, + const std::function& error_handler) { + for (auto&& column_uniq_id : context.columns_to_do_index_compaction) { + auto col = _cur_tablet_schema->column_by_uid(column_uniq_id); + const auto* index_meta = _cur_tablet_schema->inverted_index(col); + if (index_meta == nullptr) { + LOG(WARNING) << "mark skip index compaction, can not find index_meta for column" + << ". tablet=" << _tablet->tablet_id() + << ", column uniq id=" << column_uniq_id; + error_handler(-1, column_uniq_id); + continue; + } + error_handler(index_meta->index_id(), column_uniq_id); + } +} + void Compaction::construct_index_compaction_columns(RowsetWriterContext& ctx) { for (const auto& index : _cur_tablet_schema->inverted_indexes()) { auto col_unique_ids = index->col_unique_ids(); @@ -789,7 +880,8 @@ void Compaction::construct_index_compaction_columns(RowsetWriterContext& ctx) { // TODO: inverted_index_path auto seg_path = rowset->segment_path(i); DBUG_EXECUTE_IF("Compaction::construct_skip_inverted_index_seg_path_nullptr", { - seg_path = ResultError(Status::Error("error")); + seg_path = ResultError(Status::Error( + "construct_skip_inverted_index_seg_path_nullptr")); }) if (!seg_path) { LOG(WARNING) << seg_path.error(); @@ -800,8 +892,8 @@ void Compaction::construct_index_compaction_columns(RowsetWriterContext& ctx) { try { auto inverted_index_file_reader = std::make_unique( fs, - std::string { - InvertedIndexDescriptor::get_index_file_path_prefix(*seg_path)}, + std::string {InvertedIndexDescriptor::get_index_file_path_prefix( + seg_path.value())}, _cur_tablet_schema->get_inverted_index_storage_format(), rowset->rowset_meta()->inverted_index_file_info(i)); auto st = inverted_index_file_reader->init( diff --git a/be/src/olap/compaction.h b/be/src/olap/compaction.h index ccabf7dadb4733..057f4084b068b3 100644 --- a/be/src/olap/compaction.h +++ b/be/src/olap/compaction.h @@ -70,6 +70,10 @@ class Compaction { // merge inverted index files Status do_inverted_index_compaction(); + // mark all columns in columns_to_do_index_compaction to skip index compaction next time. + void mark_skip_index_compaction(const RowsetWriterContext& context, + const std::function& error_handler); + void construct_index_compaction_columns(RowsetWriterContext& ctx); virtual Status construct_output_rowset_writer(RowsetWriterContext& ctx) = 0; diff --git a/be/src/olap/rowset/segment_v2/inverted_index_compaction.cpp b/be/src/olap/rowset/segment_v2/inverted_index_compaction.cpp index f988c46c027c26..dcbdca921ab8e8 100644 --- a/be/src/olap/rowset/segment_v2/inverted_index_compaction.cpp +++ b/be/src/olap/rowset/segment_v2/inverted_index_compaction.cpp @@ -79,7 +79,16 @@ Status compact_column(int64_t index_id, // delete temporary segment_path, only when inverted_index_ram_dir_enable is false if (!config::inverted_index_ram_dir_enable) { - std::ignore = io::global_local_filesystem()->delete_directory(tmp_path.data()); + auto st = io::global_local_filesystem()->delete_directory(tmp_path.data()); + DBUG_EXECUTE_IF("compact_column_delete_tmp_path_error", { + st = Status::Error( + "debug point: compact_column_delete_tmp_path_error in index compaction"); + }) + if (!st.ok()) { + LOG(WARNING) << "compact column failed to delete tmp path: " << tmp_path + << ", error: " << st.to_string(); + return st; + } } return Status::OK(); } diff --git a/regression-test/suites/fault_injection_p0/test_index_compaction_exception_fault_injection.groovy b/regression-test/suites/fault_injection_p0/test_index_compaction_exception_fault_injection.groovy index ac3cd8125a863c..b54f6374d833b8 100644 --- a/regression-test/suites/fault_injection_p0/test_index_compaction_exception_fault_injection.groovy +++ b/regression-test/suites/fault_injection_p0/test_index_compaction_exception_fault_injection.groovy @@ -181,30 +181,26 @@ suite("test_index_compaction_exception_fault_injection", "nonConcurrent") { "compact_column_create_index_writer_error", "compact_column_indexCompaction_error", "compact_column_index_writer_close_error", - "compact_column_src_index_dirs_close_error", + "compact_column_delete_tmp_path_error", "Compaction::do_inverted_index_compaction_find_rowset_error", "Compaction::do_inverted_index_compaction_get_fs_error", - "Compaction::do_inverted_index_compaction_index_file_reader_init_error", - // "Compaction::do_inverted_index_compaction_file_size_status_not_ok", // v2 do not do index compaction "Compaction::do_inverted_index_compaction_can_not_find_index_meta", - "Compaction::do_inverted_index_compaction_index_properties_different", - "Compaction::do_inverted_index_compaction_index_file_writer_close_not_ok", - "Compaction::construct_skip_inverted_index_index_reader_close_error" + "Compaction::do_inverted_index_compaction_rowid_conversion_null", + "Compaction::do_inverted_index_compaction_seg_path_nullptr", + "Compaction::do_inverted_index_compaction_init_inverted_index_file_reader", + "Compaction::do_inverted_index_compaction_inverted_index_file_writers_size_error" ] def debug_points_normal_compaction = [ - "compact_column_local_tmp_dir_delete_error", - // "Compaction::do_inverted_index_compaction_dest_segment_num_is_zero", // query result not match without inverted index - "Compaction::do_inverted_index_compaction_index_file_reader_init_not_found", "Compaction::construct_skip_inverted_index_is_skip_index_compaction", "Compaction::construct_skip_inverted_index_get_fs_error", "Compaction::construct_skip_inverted_index_index_meta_nullptr", "Compaction::construct_skip_inverted_index_seg_path_nullptr", + "Compaction::do_inverted_index_compaction_index_properties_different", + "Compaction::construct_skip_inverted_index_index_files_count", + "Compaction::construct_skip_inverted_index_index_reader_close_error", "Compaction::construct_skip_inverted_index_index_file_reader_init_status_not_ok", - "Compaction::construct_skip_inverted_index_index_file_reader_exist_status_not_ok", - "Compaction::construct_skip_inverted_index_index_file_reader_exist_false", - "Compaction::construct_skip_inverted_index_index_file_reader_open_error", - "Compaction::construct_skip_inverted_index_index_files_count" + "Compaction::construct_skip_inverted_index_index_file_reader_open_error" ] def run_test = { tablets, debug_point, abnormal -> @@ -221,6 +217,9 @@ suite("test_index_compaction_exception_fault_injection", "nonConcurrent") { } } + if (debug_point == "compact_column_delete_tmp_path_error") { + set_be_config.call("inverted_index_ram_dir_enable", "false") + } // before full compaction, there are 7 rowsets. int rowsetCount = get_rowset_count.call(tablets); assert (rowsetCount == 7 * replicaNum) @@ -258,6 +257,10 @@ suite("test_index_compaction_exception_fault_injection", "nonConcurrent") { } run_sql.call() + + if (debug_point == "compact_column_delete_tmp_path_error") { + set_be_config.call("inverted_index_ram_dir_enable", "true") + } } def create_and_test_table = { table_name, key_type, debug_points, is_abnormal -> From 044cb5a691918dd4008d3aca0d175a72e8433bd2 Mon Sep 17 00:00:00 2001 From: Uniqueyou <1520358997@qq.com> Date: Fri, 13 Dec 2024 14:13:15 +0800 Subject: [PATCH 40/63] [fix](sql) Fix error result for column tosql (#44997) --- .../org/apache/doris/analysis/ColumnDef.java | 30 ++++--- .../analysis/AddColumnDefaultValueTest.java | 89 +++++++++++++++++++ 2 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 fe/fe-core/src/test/java/org/apache/doris/analysis/AddColumnDefaultValueTest.java diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java index 02e123397c69aa..d74451a9331e8b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java @@ -30,6 +30,7 @@ import org.apache.doris.common.AnalysisException; import org.apache.doris.common.Config; import org.apache.doris.common.FeNameFormat; +import org.apache.doris.common.util.SqlUtils; import org.apache.doris.common.util.TimeUtils; import org.apache.doris.qe.SessionVariable; @@ -180,17 +181,6 @@ public String getValue() { } return value; } - - public String toSql() { - StringBuilder sb = new StringBuilder(); - sb.append("DEFAULT "); - if (value != null) { - sb.append('"').append(value).append('"'); - } else { - sb.append("NULL"); - } - return sb.toString(); - } } // parameter initialized in constructor @@ -439,7 +429,7 @@ public void analyze(boolean isOlap) throws AnalysisException { } if (type.getPrimitiveType() == PrimitiveType.HLL) { - if (defaultValue.isSet) { + if (defaultValue != null && defaultValue.isSet) { throw new AnalysisException("Hll type column can not set default value"); } defaultValue = DefaultValue.HLL_EMPTY_DEFAULT_VALUE; @@ -687,7 +677,21 @@ public String toSql() { } if (defaultValue.isSet) { - sb.append(defaultValue.toSql()).append(" "); + if (defaultValue.value != null) { + if (typeDef.getType().getPrimitiveType() != PrimitiveType.BITMAP + && typeDef.getType().getPrimitiveType() != PrimitiveType.HLL) { + if (defaultValue.defaultValueExprDef != null) { + sb.append("DEFAULT ").append(defaultValue.value).append(" "); + } else { + sb.append("DEFAULT ").append("\"").append(SqlUtils.escapeQuota(defaultValue.value)).append("\"") + .append(" "); + } + } else if (typeDef.getType().getPrimitiveType() == PrimitiveType.BITMAP) { + sb.append("DEFAULT ").append(defaultValue.defaultValueExprDef.getExprName()).append(" "); + } + } else { + sb.append("DEFAULT ").append("NULL").append(" "); + } } sb.append("COMMENT \"").append(comment).append("\""); diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/AddColumnDefaultValueTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/AddColumnDefaultValueTest.java new file mode 100644 index 00000000000000..4f59ee068db01a --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/AddColumnDefaultValueTest.java @@ -0,0 +1,89 @@ +// 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. + +package org.apache.doris.analysis; + +import org.apache.doris.analysis.ColumnDef.DefaultValue; +import org.apache.doris.catalog.AggregateType; +import org.apache.doris.catalog.KeysType; +import org.apache.doris.catalog.PrimitiveType; +import org.apache.doris.catalog.ScalarType; +import org.apache.doris.common.AnalysisException; + +import com.google.common.collect.Lists; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.List; + +public class AddColumnDefaultValueTest { + private static Analyzer analyzer; + + @BeforeClass + public static void setUp() { + analyzer = AccessTestUtil.fetchAdminAnalyzer(false); + } + + @Test + public void testNormal() throws AnalysisException { + List columns = Lists.newArrayList(); + ColumnDef definition = new ColumnDef("col1", new TypeDef(ScalarType.createType(PrimitiveType.DATETIME)), + true, + null, false, + DefaultValue.CURRENT_TIMESTAMP_DEFAULT_VALUE, ""); + definition.setKeysType(KeysType.DUP_KEYS); + columns.add(definition); + definition = new ColumnDef("col2", new TypeDef(ScalarType.createType(PrimitiveType.INT)), + false, + null, false, + new DefaultValue(true, 1), ""); + columns.add(definition); + definition = new ColumnDef("col3", new TypeDef(ScalarType.createType(PrimitiveType.VARCHAR)), + false, + null, false, + new DefaultValue(true, "varchar"), ""); + columns.add(definition); + definition = new ColumnDef("col4", new TypeDef(ScalarType.createType(PrimitiveType.BITMAP)), + false, + null, false, + DefaultValue.BITMAP_EMPTY_DEFAULT_VALUE, ""); + definition.setKeysType(KeysType.DUP_KEYS); + columns.add(definition); + definition = new ColumnDef("col5", new TypeDef(ScalarType.createType(PrimitiveType.VARCHAR)), + false, + null, false, + new DefaultValue(true, "xxx\"\"xxx"), ""); + columns.add(definition); + definition = new ColumnDef("col6", new TypeDef(ScalarType.createType(PrimitiveType.HLL)), + false, + AggregateType.HLL_UNION, false, + null, ""); + columns.add(definition); + AddColumnsClause clause = new AddColumnsClause(columns, null, null); + clause.analyze(analyzer); + System.out.println(clause.toString()); + Assert.assertEquals( + "ADD COLUMN (`col1` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT \"\", " + + "`col2` int NOT NULL DEFAULT \"1\" COMMENT \"\", " + + "`col3` varchar(65533) NOT NULL DEFAULT \"varchar\" COMMENT \"\", " + + "`col4` bitmap NOT NULL DEFAULT BITMAP_EMPTY COMMENT \"\", " + + "`col5` varchar(65533) NOT NULL DEFAULT \"xxx\\\"\\\"xxx\" COMMENT \"\", " + + "`col6` hll HLL_UNION NOT NULL COMMENT \"\")", + clause.toString()); + } +} From ffa02e329b928150c610a01e7c7b6f45f39c3154 Mon Sep 17 00:00:00 2001 From: starocean999 Date: Fri, 13 Dec 2024 14:33:31 +0800 Subject: [PATCH 41/63] [fix](nereids)EliminateGroupBy rule should keep output's datatype unchanged (#45359) Related PR: #28615 Problem Summary: `select id, count(age) from t group by id` consider t is unique table and it's unique key is id. The sql will be convert to: `select id, if(age is null, 0, 1) from t;` count(age) is replaced by if(age is null, 0, 1). And we should keep if(age is null, 0, 1)'s datatype same as count(age) which is bigint. --- .../doris/nereids/rules/rewrite/EliminateGroupBy.java | 10 +++------- .../nereids/rules/rewrite/EliminateGroupByTest.java | 1 + 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupBy.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupBy.java index b50d3a41e8c3b5..9325607dd70769 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupBy.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupBy.java @@ -30,7 +30,7 @@ import org.apache.doris.nereids.trees.expressions.functions.agg.Min; import org.apache.doris.nereids.trees.expressions.functions.agg.Sum; import org.apache.doris.nereids.trees.expressions.functions.scalar.If; -import org.apache.doris.nereids.trees.expressions.literal.Literal; +import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.util.ExpressionUtils; import org.apache.doris.nereids.util.PlanUtils; @@ -84,12 +84,8 @@ public Rule build() { .castIfNotSameType(f.child(0), f.getDataType()), ne.getName())); } else if (f instanceof Count) { newOutput.add((NamedExpression) ne.withChildren( - new If( - new IsNull(f.child(0)), - Literal.of(0), - Literal.of(1) - ) - )); + new If(new IsNull(f.child(0)), new BigIntLiteral(0), + new BigIntLiteral(1)))); } else { throw new IllegalStateException("Unexpected aggregate function: " + f); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByTest.java index 0b6d2f199fc59f..70eb8e4a470746 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateGroupByTest.java @@ -94,6 +94,7 @@ void eliminateCount() { logicalEmptyRelation().when(p -> p.getProjects().get(0).toSql().equals("id") && p.getProjects().get(1).toSql() .equals("if(age IS NULL, 0, 1) AS `if(age IS NULL, 0, 1)`") + && p.getProjects().get(1).getDataType().isBigIntType() ) ); } From 1d64cb077cb60bfe1ddc2e6226dd9b77e40b3979 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Fri, 13 Dec 2024 15:37:03 +0800 Subject: [PATCH 42/63] [fix](coordinator) Fix wrong bucket assignments by coordinator (#45365) Split scan ranges evenly into `parallelExecInstanceNum` instances. For a fragment contains co-located join, scan (id = 0) -> join build (id = 2) | scan (id = 1) -> join probe (id = 2) If both of `scan (id = 0)` and `scan (id = 1)` are serial operators, we will plan local exchanger after them: scan (id = 0) -> local exchange -> join build (id = 2) | scan (id = 1) -> local exchange -> join probe (id = 2) And there is another more complicated scenario, for example, `scan (id = 0)` has 10 partitions and 3 buckets which means 3 * 10 tablets and `scan (id = 1)` has 3 buckets and no partition which means 3 tablets totally. If expected parallelism is 8, we will get a serial scan (id = 0) and a non-serial scan (id = 1). For this case, we will plan another plan with local exchange: scan (id = 0) -> join build (id = 2) | scan (id = 1) -> local exchange -> join probe (id = 2) --- .../java/org/apache/doris/qe/Coordinator.java | 85 ++++++++++---- ...t_colocate_join_with_different_tablets.out | 12 ++ ...olocate_join_with_different_tablets.groovy | 109 ++++++++++++++++++ 3 files changed, 182 insertions(+), 24 deletions(-) create mode 100644 regression-test/data/correctness_p0/test_colocate_join_with_different_tablets.out create mode 100644 regression-test/suites/correctness_p0/test_colocate_join_with_different_tablets.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java index 42e2e0a3634870..1e327c469e7140 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java @@ -2731,7 +2731,8 @@ private void assignScanRanges(PlanFragmentId fragmentId, int parallelExecInstanc * 1. `parallelExecInstanceNum * numBackends` is larger than scan ranges. * 2. Use Nereids planner. */ - boolean ignoreStorageDataDistribution = params.fragment != null && params.fragment.useSerialSource(context); + boolean ignoreStorageDataDistribution = scanNodes != null && !scanNodes.isEmpty() + && params.fragment != null && params.fragment.useSerialSource(context); FragmentScanRangeAssignment assignment = params.scanRangeAssignment; for (Map.Entry>>>> addressScanRange @@ -2741,33 +2742,69 @@ private void assignScanRanges(PlanFragmentId fragmentId, int parallelExecInstanc = findOrInsert(assignment, addressScanRange.getKey(), new HashMap<>()); if (ignoreStorageDataDistribution) { - FInstanceExecParam instanceParam = new FInstanceExecParam( - null, addressScanRange.getKey(), 0, params); - - for (Pair>> nodeScanRangeMap : scanRange) { - for (Map.Entry> nodeScanRange - : nodeScanRangeMap.second.entrySet()) { - if (!instanceParam.perNodeScanRanges.containsKey(nodeScanRange.getKey())) { - range.put(nodeScanRange.getKey(), Lists.newArrayList()); - instanceParam.perNodeScanRanges.put(nodeScanRange.getKey(), Lists.newArrayList()); + List>>>> perInstanceScanRanges + = ListUtil.splitBySize(scanRange, parallelExecInstanceNum); + /** + * Split scan ranges evenly into `parallelExecInstanceNum` instances. + * + * + * For a fragment contains co-located join, + * + * scan (id = 0) -> join build (id = 2) + * | + * scan (id = 1) -> join probe (id = 2) + * + * If both of `scan (id = 0)` and `scan (id = 1)` are serial operators, we will plan local exchanger + * after them: + * + * scan (id = 0) -> local exchange -> join build (id = 2) + * | + * scan (id = 1) -> local exchange -> join probe (id = 2) + * + * + * And there is another more complicated scenario, for example, `scan (id = 0)` has 10 partitions and + * 3 buckets which means 3 * 10 tablets and `scan (id = 1)` has 3 buckets and no partition which means + * 3 tablets totally. If expected parallelism is 8, we will get a serial scan (id = 0) and a + * non-serial scan (id = 1). For this case, we will plan another plan with local exchange: + * + * scan (id = 0) -> local exchange -> join build (id = 2) + * | + * scan (id = 1) -> join probe (id = 2) + */ + FInstanceExecParam firstInstanceParam = null; + for (List>>> perInstanceScanRange + : perInstanceScanRanges) { + FInstanceExecParam instanceParam = new FInstanceExecParam( + null, addressScanRange.getKey(), 0, params); + + if (firstInstanceParam == null) { + firstInstanceParam = instanceParam; + } + for (Pair>> nodeScanRangeMap : perInstanceScanRange) { + instanceParam.addBucketSeq(nodeScanRangeMap.first); + for (Map.Entry> nodeScanRange + : nodeScanRangeMap.second.entrySet()) { + int scanId = nodeScanRange.getKey(); + Optional node = scanNodes.stream().filter( + scanNode -> scanNode.getId().asInt() == scanId).findFirst(); + Preconditions.checkArgument(node.isPresent()); + FInstanceExecParam instanceParamToScan = node.get().isSerialOperator() + ? firstInstanceParam : instanceParam; + if (!instanceParamToScan.perNodeScanRanges.containsKey(nodeScanRange.getKey())) { + range.put(nodeScanRange.getKey(), Lists.newArrayList()); + instanceParamToScan.perNodeScanRanges + .put(nodeScanRange.getKey(), Lists.newArrayList()); + } + range.get(nodeScanRange.getKey()).addAll(nodeScanRange.getValue()); + instanceParamToScan.perNodeScanRanges.get(nodeScanRange.getKey()) + .addAll(nodeScanRange.getValue()); } - range.get(nodeScanRange.getKey()).addAll(nodeScanRange.getValue()); - instanceParam.perNodeScanRanges.get(nodeScanRange.getKey()) - .addAll(nodeScanRange.getValue()); } + params.instanceExecParams.add(instanceParam); } - List instanceExecParams = new ArrayList<>(); - instanceExecParams.add(instanceParam); - for (int i = 1; i < parallelExecInstanceNum; i++) { - instanceExecParams.add(new FInstanceExecParam( - null, addressScanRange.getKey(), 0, params)); - } - int index = 0; - for (Pair>> nodeScanRangeMap : scanRange) { - instanceExecParams.get(index % instanceExecParams.size()).addBucketSeq(nodeScanRangeMap.first); - index++; + for (int i = perInstanceScanRanges.size(); i < parallelExecInstanceNum; i++) { + params.instanceExecParams.add(new FInstanceExecParam(null, addressScanRange.getKey(), 0, params)); } - params.instanceExecParams.addAll(instanceExecParams); } else { int expectedInstanceNum = 1; if (parallelExecInstanceNum > 1) { diff --git a/regression-test/data/correctness_p0/test_colocate_join_with_different_tablets.out b/regression-test/data/correctness_p0/test_colocate_join_with_different_tablets.out new file mode 100644 index 00000000000000..06c381356ea470 --- /dev/null +++ b/regression-test/data/correctness_p0/test_colocate_join_with_different_tablets.out @@ -0,0 +1,12 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !sql -- +10000007 10000007 48414 10000007 +10000007 10000007 48414 10000007 +10000007 10000007 48414 10000007 +10000007 10000007 60426 10000007 +10000007 10000007 60426 10000007 +10000007 10000007 60426 10000007 +10000007 10000007 94460 10000007 +10000007 10000007 94460 10000007 +10000007 10000007 94460 10000007 + diff --git a/regression-test/suites/correctness_p0/test_colocate_join_with_different_tablets.groovy b/regression-test/suites/correctness_p0/test_colocate_join_with_different_tablets.groovy new file mode 100644 index 00000000000000..661835916865c5 --- /dev/null +++ b/regression-test/suites/correctness_p0/test_colocate_join_with_different_tablets.groovy @@ -0,0 +1,109 @@ +// 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. + +suite("test_colocate_join_with_different_tablets") { + sql """ + DROP TABLE IF EXISTS `USR_V_KHZHSJ_ES_POC1`; + DROP TABLE IF EXISTS `USR_TLBL_VAL_R1`; + CREATE TABLE `USR_V_KHZHSJ_ES_POC1` ( + `khid` bigint NULL, + `khh` bigint NULL + ) ENGINE=OLAP + DUPLICATE KEY(`khid`, `khh`) + DISTRIBUTED BY HASH(`khid`) BUCKETS 16 + PROPERTIES ( + "colocate_with" = "test_colocate_join_with_different_tabletsgroup1", + "replication_allocation" = "tag.location.default: 1" + ); + + + CREATE TABLE `USR_TLBL_VAL_R1` ( + `lbl_id` bigint NOT NULL COMMENT "标签ID", + `khh` bigint NULL COMMENT "客户号" + ) ENGINE=OLAP + DUPLICATE KEY(`lbl_id`, `khh`) + COMMENT '标签结果日表' + PARTITION BY LIST (`lbl_id`) + (PARTITION p0 VALUES IN ("0"), + PARTITION p1 VALUES IN ("1"), + PARTITION p29 VALUES IN ("29"), + PARTITION p35 VALUES IN ("35"), + PARTITION p57 VALUES IN ("57"), + PARTITION p352 VALUES IN ("352"), + PARTITION p402 VALUES IN ("402"), + PARTITION p523 VALUES IN ("523"), + PARTITION p2347 VALUES IN ("2347"), + PARTITION p10376 VALUES IN ("10376"), + PARTITION p42408 VALUES IN ("42408"), + PARTITION p44410 VALUES IN ("44410"), + PARTITION p48414 VALUES IN ("48414"), + PARTITION p50416 VALUES IN ("50416"), + PARTITION p52418 VALUES IN ("52418"), + PARTITION p56422 VALUES IN ("56422"), + PARTITION p60426 VALUES IN ("60426"), + PARTITION p64430 VALUES IN ("64430"), + PARTITION p66432 VALUES IN ("66432"), + PARTITION p70436 VALUES IN ("70436"), + PARTITION p72438 VALUES IN ("72438"), + PARTITION p74440 VALUES IN ("74440"), + PARTITION p78444 VALUES IN ("78444"), + PARTITION p84450 VALUES IN ("84450"), + PARTITION p86452 VALUES IN ("86452"), + PARTITION p88454 VALUES IN ("88454"), + PARTITION p90456 VALUES IN ("90456"), + PARTITION p92458 VALUES IN ("92458"), + PARTITION p94460 VALUES IN ("94460"), + PARTITION p96462 VALUES IN ("96462"), + PARTITION p98464 VALUES IN ("98464"), + PARTITION p100466 VALUES IN ("100466"), + PARTITION p102468 VALUES IN ("102468"), + PARTITION p104470 VALUES IN ("104470"), + PARTITION p106472 VALUES IN ("106472"), + PARTITION p108474 VALUES IN ("108474"), + PARTITION p110476 VALUES IN ("110476"), + PARTITION p112478 VALUES IN ("112478"), + PARTITION p114480 VALUES IN ("114480"), + PARTITION p122488 VALUES IN ("122488"), + PARTITION p124490 VALUES IN ("124490"), + PARTITION p126492 VALUES IN ("126492"), + PARTITION p130496 VALUES IN ("130496"), + PARTITION p134500 VALUES IN ("134500"), + PARTITION p150516 VALUES IN ("150516"), + PARTITION p154520 VALUES IN ("154520"), + PARTITION p158524 VALUES IN ("158524"), + PARTITION p158525 VALUES IN ("158525"), + PARTITION p1848141 VALUES IN ("1848141"), + PARTITION p1848161 VALUES IN ("1848161"), + PARTITION p1848177 VALUES IN ("1848177"), + PARTITION p1848197 VALUES IN ("1848197"), + PARTITION p1848218 VALUES IN ("1848218")) + DISTRIBUTED BY HASH(`khh`) BUCKETS 16 + PROPERTIES ( + "colocate_with" = "test_colocate_join_with_different_tabletsgroup1", + "replication_allocation" = "tag.location.default: 1" + ); + + insert into USR_V_KHZHSJ_ES_POC1 values(10000007, 10000007); + insert into USR_V_KHZHSJ_ES_POC1 values(10000007, 10000007); + insert into USR_V_KHZHSJ_ES_POC1 values(10000007, 10000007); + + insert into USR_TLBL_VAL_R1 values(48414, 10000007); + insert into USR_TLBL_VAL_R1 values(94460, 10000007); + insert into USR_TLBL_VAL_R1 values(60426, 10000007); + """ + qt_sql """ select * from USR_V_KHZHSJ_ES_POC1 A,USR_TLBL_VAL_R1 B WHERE A.khid = B.khh order by lbl_id; """ +} From ad58cd134601c301b4da2e72cd3f7c51c7a6fe7d Mon Sep 17 00:00:00 2001 From: FreeOnePlus <54164178+FreeOnePlus@users.noreply.github.com> Date: Fri, 13 Dec 2024 15:49:53 +0800 Subject: [PATCH 43/63] [feat](docker)Modify the init_be and start_be scripts to meet the requirements for rapid Docker startup. (#45269) Related PR: #45267 Problem Summary: To meet the needs of rapid Docker startup, I have made adjustments to two related scripts in the Docker startup process. First, I added a env `SKIP_CHECK_ULIMIT` to the `start_be.sh` script, which will skip the size checks for `swap`, `ulimit`, and `max_map_count`. At the same time, I used `--console` to start the process and print logs. The reason why I did not use the `--daemon` daemon command to execute is that starting with a foreground log printing method in a Docker container is the correct and reliable approach. At the same time, I added a check logic for a `be.conf` configuration item in the `init_be.sh` script: if it is the first time starting, append the export `SKIP_CHECK_ULIMIT=true` to skip the `ulimit` value check in the BE process. In summary, these adjustments can meet the basic requirements for rapid Docker startup usage. --- bin/start_be.sh | 36 ++++++++++++++------------- docker/runtime/be/resource/init_be.sh | 1 + 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/bin/start_be.sh b/bin/start_be.sh index 5b7df5ead589fa..35b453a407c688 100755 --- a/bin/start_be.sh +++ b/bin/start_be.sh @@ -182,29 +182,31 @@ if [[ "${RUN_VERSION}" -eq 1 ]]; then exit 0 fi -if [[ "$(uname -s)" != 'Darwin' ]]; then - MAX_MAP_COUNT="$(cat /proc/sys/vm/max_map_count)" - if [[ "${MAX_MAP_COUNT}" -lt 2000000 ]]; then - echo "Set kernel parameter 'vm.max_map_count' to a value greater than 2000000, example: 'sysctl -w vm.max_map_count=2000000'" - exit 1 +if [[ "${SKIP_CHECK_ULIMIT:- "false"}" != "true" ]]; then + if [[ "$(uname -s)" != 'Darwin' ]]; then + MAX_MAP_COUNT="$(cat /proc/sys/vm/max_map_count)" + if [[ "${MAX_MAP_COUNT}" -lt 2000000 ]]; then + echo "Set kernel parameter 'vm.max_map_count' to a value greater than 2000000, example: 'sysctl -w vm.max_map_count=2000000'" + exit 1 + fi + + if [[ "$(swapon -s | wc -l)" -gt 1 ]]; then + echo "Disable swap memory before starting be" + exit 1 + fi fi - if [[ "$(swapon -s | wc -l)" -gt 1 ]]; then - echo "Disable swap memory before starting be" + MAX_FILE_COUNT="$(ulimit -n)" + if [[ "${MAX_FILE_COUNT}" -lt 60000 ]]; then + echo "Set max number of open file descriptors to a value greater than 60000." + echo "Ask your system manager to modify /etc/security/limits.conf and append content like" + echo " * soft nofile 655350" + echo " * hard nofile 655350" + echo "and then run 'ulimit -n 655350' to take effect on current session." exit 1 fi fi -MAX_FILE_COUNT="$(ulimit -n)" -if [[ "${MAX_FILE_COUNT}" -lt 60000 ]]; then - echo "Set max number of open file descriptors to a value greater than 60000." - echo "Ask your system manager to modify /etc/security/limits.conf and append content like" - echo " * soft nofile 655350" - echo " * hard nofile 655350" - echo "and then run 'ulimit -n 655350' to take effect on current session." - exit 1 -fi - # add java libs # Must add hadoop libs, because we should load specified jars # instead of jars in hadoop libs, such as avro diff --git a/docker/runtime/be/resource/init_be.sh b/docker/runtime/be/resource/init_be.sh index f9269f3ee7e7b8..4b77eb3fc0df08 100644 --- a/docker/runtime/be/resource/init_be.sh +++ b/docker/runtime/be/resource/init_be.sh @@ -197,6 +197,7 @@ _main() { fi check_be_status doris_note "Ready to start BE!" + export SKIP_CHECK_ULIMIT=true ${DORIS_HOME}/be/bin/start_be.sh --console & child_pid=$! wait $child_pid From 429cda44664703c6bb9a10c7e2c76fda527f8ada Mon Sep 17 00:00:00 2001 From: FreeOnePlus <54164178+FreeOnePlus@users.noreply.github.com> Date: Fri, 13 Dec 2024 15:52:05 +0800 Subject: [PATCH 44/63] [typo](docker) Adjust the indentation format of the init_be and entry_point scripts, as well as the duration of loop execution. (#45308) Adjust the indentation format of the `init_be` and `entry_point` scripts, as well as the duration of loop execution. Adjust the smallest unit of all indentations to a single tab character, and modify the loop duration when checking the BE startup status, changing both from 300 seconds to 30 seconds to speed up the overall Docker startup time. --- docker/runtime/be/resource/entry_point.sh | 214 +++++++++++----------- docker/runtime/be/resource/init_be.sh | 164 ++++++++--------- 2 files changed, 189 insertions(+), 189 deletions(-) diff --git a/docker/runtime/be/resource/entry_point.sh b/docker/runtime/be/resource/entry_point.sh index 6e3dfaf3875d89..474fa984a4d86a 100755 --- a/docker/runtime/be/resource/entry_point.sh +++ b/docker/runtime/be/resource/entry_point.sh @@ -61,95 +61,95 @@ docker_setup_env() { # Check the variables required for startup docker_required_variables_env() { - declare -g RUN_TYPE - if [[ -n "$FE_SERVERS" && -n "$BE_ADDR" ]]; then - RUN_TYPE="ELECTION" - if [[ $FE_SERVERS =~ ^.+:[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}:[1-6]{0,1}[0-9]{1,4}(,.+:[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}:[1-6]{0,1}[0-9]{1,4})*$ || $FE_SERVERS =~ ^.+:([0-9a-fA-F]{1,4}:){7,7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,5}((:[0-9a-fA-F]{1,4}){1,2}|:)|([0-9a-fA-F]{1,4}:){1,4}((:[0-9a-fA-F]{1,4}){1,3}|:)|([0-9a-fA-F]{1,4}:){1,3}((:[0-9a-fA-F]{1,4}){1,4}|:)|([0-9a-fA-F]{1,4}:){1,2}((:[0-9a-fA-F]{1,4}){1,5}|:)|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}|:)|:((:[0-9a-fA-F]{1,4}){1,7}|:)$ ]]; then - doris_warn "FE_SERVERS" $FE_SERVERS - else - doris_error "FE_SERVERS rule error!example: \$FE_NAME:\$FE_HOST_IP:\$FE_EDIT_LOG_PORT[,\$FE_NAME:\$FE_HOST_IP:\$FE_EDIT_LOG_PORT]..." - fi - if [[ $BE_ADDR =~ ^[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}:[1-6]{0,1}[0-9]{1,4}$ || $BE_ADDR =~ ^([0-9a-fA-F]{1,4}:){7,7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,5}((:[0-9a-fA-F]{1,4}){1,2}|:)|([0-9a-fA-F]{1,4}:){1,4}((:[0-9a-fA-F]{1,4}){1,3}|:)|([0-9a-fA-F]{1,4}:){1,3}((:[0-9a-fA-F]{1,4}){1,4}|:)|([0-9a-fA-F]{1,4}:){1,2}((:[0-9a-fA-F]{1,4}){1,5}|:)|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}|:)|:((:[0-9a-fA-F]{1,4}){1,7}|:):[1-6]{0,1}[0-9]{1,4}$ ]]; then - doris_warn "BE_ADDR" $BE_ADDR - else - doris_error "BE_ADDR rule error!example: \$BE_IP:\$HEARTBEAT_SERVICE_PORT" - fi - export RUN_TYPE=${RUN_TYPE} - return - fi + declare -g RUN_TYPE + if [[ -n "$FE_SERVERS" && -n "$BE_ADDR" ]]; then + RUN_TYPE="ELECTION" + if [[ $FE_SERVERS =~ ^.+:[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}:[1-6]{0,1}[0-9]{1,4}(,.+:[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}:[1-6]{0,1}[0-9]{1,4})*$ || $FE_SERVERS =~ ^.+:([0-9a-fA-F]{1,4}:){7,7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,5}((:[0-9a-fA-F]{1,4}){1,2}|:)|([0-9a-fA-F]{1,4}:){1,4}((:[0-9a-fA-F]{1,4}){1,3}|:)|([0-9a-fA-F]{1,4}:){1,3}((:[0-9a-fA-F]{1,4}){1,4}|:)|([0-9a-fA-F]{1,4}:){1,2}((:[0-9a-fA-F]{1,4}){1,5}|:)|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}|:)|:((:[0-9a-fA-F]{1,4}){1,7}|:)$ ]]; then + doris_warn "FE_SERVERS" $FE_SERVERS + else + doris_error "FE_SERVERS rule error!example: \$FE_NAME:\$FE_HOST_IP:\$FE_EDIT_LOG_PORT[,\$FE_NAME:\$FE_HOST_IP:\$FE_EDIT_LOG_PORT]..." + fi + if [[ $BE_ADDR =~ ^[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}:[1-6]{0,1}[0-9]{1,4}$ || $BE_ADDR =~ ^([0-9a-fA-F]{1,4}:){7,7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,5}((:[0-9a-fA-F]{1,4}){1,2}|:)|([0-9a-fA-F]{1,4}:){1,4}((:[0-9a-fA-F]{1,4}){1,3}|:)|([0-9a-fA-F]{1,4}:){1,3}((:[0-9a-fA-F]{1,4}){1,4}|:)|([0-9a-fA-F]{1,4}:){1,2}((:[0-9a-fA-F]{1,4}){1,5}|:)|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}|:)|:((:[0-9a-fA-F]{1,4}){1,7}|:):[1-6]{0,1}[0-9]{1,4}$ ]]; then + doris_warn "BE_ADDR" $BE_ADDR + else + doris_error "BE_ADDR rule error!example: \$BE_IP:\$HEARTBEAT_SERVICE_PORT" + fi + export RUN_TYPE=${RUN_TYPE} + return + fi - if [[ -n "$FE_MASTER_IP" && -n "$BE_IP" && -n "$BE_PORT" ]]; then - RUN_TYPE="ASSIGN" - if [[ $FE_MASTER_IP =~ ^[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}$ || $FE_MASTER_IP =~ ^([0-9a-fA-F]{1,4}:){7,7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,5}((:[0-9a-fA-F]{1,4}){1,2}|:)|([0-9a-fA-F]{1,4}:){1,4}((:[0-9a-fA-F]{1,4}){1,3}|:)|([0-9a-fA-F]{1,4}:){1,3}((:[0-9a-fA-F]{1,4}){1,4}|:)|([0-9a-fA-F]{1,4}:){1,2}((:[0-9a-fA-F]{1,4}){1,5}|:)|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}|:)|:((:[0-9a-fA-F]{1,4}){1,7}|:)$ ]]; then - doris_warn "FE_MASTER_IP" $FE_MASTER_IP - else - doris_error "FE_MASTER_IP rule error!example: \$FE_MASTER_IP" - fi - if [[ $BE_IP =~ ^[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}$ || $BE_IP =~ ^([0-9a-fA-F]{1,4}:){7,7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,5}((:[0-9a-fA-F]{1,4}){1,2}|:)|([0-9a-fA-F]{1,4}:){1,4}((:[0-9a-fA-F]{1,4}){1,3}|:)|([0-9a-fA-F]{1,4}:){1,3}((:[0-9a-fA-F]{1,4}){1,4}|:)|([0-9a-fA-F]{1,4}:){1,2}((:[0-9a-fA-F]{1,4}){1,5}|:)|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}|:)|:((:[0-9a-fA-F]{1,4}){1,7}|:)$ ]]; then - doris_warn "BE_IP" $BE_IP - else - doris_error "BE_IP rule error!example: \$BE_IP" - fi - if [[ $BE_PORT =~ ^[1-6]{0,1}[0-9]{1,4}$ ]]; then - doris_warn "BE_PORT" $BE_PORT - else - doris_error "BE_PORT rule error!example: \$BE_PORT." - fi - export RUN_TYPE=${RUN_TYPE} - return - fi + if [[ -n "$FE_MASTER_IP" && -n "$BE_IP" && -n "$BE_PORT" ]]; then + RUN_TYPE="ASSIGN" + if [[ $FE_MASTER_IP =~ ^[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}$ || $FE_MASTER_IP =~ ^([0-9a-fA-F]{1,4}:){7,7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,5}((:[0-9a-fA-F]{1,4}){1,2}|:)|([0-9a-fA-F]{1,4}:){1,4}((:[0-9a-fA-F]{1,4}){1,3}|:)|([0-9a-fA-F]{1,4}:){1,3}((:[0-9a-fA-F]{1,4}){1,4}|:)|([0-9a-fA-F]{1,4}:){1,2}((:[0-9a-fA-F]{1,4}){1,5}|:)|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}|:)|:((:[0-9a-fA-F]{1,4}){1,7}|:)$ ]]; then + doris_warn "FE_MASTER_IP" $FE_MASTER_IP + else + doris_error "FE_MASTER_IP rule error!example: \$FE_MASTER_IP" + fi + if [[ $BE_IP =~ ^[1-2]{0,1}[0-9]{0,1}[0-9]{1}(\.[1-2]{0,1}[0-9]{0,1}[0-9]{1}){3}$ || $BE_IP =~ ^([0-9a-fA-F]{1,4}:){7,7}([0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}|:)|([0-9a-fA-F]{1,4}:){1,5}((:[0-9a-fA-F]{1,4}){1,2}|:)|([0-9a-fA-F]{1,4}:){1,4}((:[0-9a-fA-F]{1,4}){1,3}|:)|([0-9a-fA-F]{1,4}:){1,3}((:[0-9a-fA-F]{1,4}){1,4}|:)|([0-9a-fA-F]{1,4}:){1,2}((:[0-9a-fA-F]{1,4}){1,5}|:)|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6}|:)|:((:[0-9a-fA-F]{1,4}){1,7}|:)$ ]]; then + doris_warn "BE_IP" $BE_IP + else + doris_error "BE_IP rule error!example: \$BE_IP" + fi + if [[ $BE_PORT =~ ^[1-6]{0,1}[0-9]{1,4}$ ]]; then + doris_warn "BE_PORT" $BE_PORT + else + doris_error "BE_PORT rule error!example: \$BE_PORT." + fi + export RUN_TYPE=${RUN_TYPE} + return + fi - doris_error EOF " - Note that you did not configure the required parameters! - plan 1: - FE_SERVERS & BE_ADDR - plan 2: - FE_MASTER_IP & FE_MASTER_PORT & BE_IP & BE_PORT" - EOF + doris_error EOF " + Note that you did not configure the required parameters! + plan 1: + FE_SERVERS & BE_ADDR + plan 2: + FE_MASTER_IP & FE_MASTER_PORT & BE_IP & BE_PORT" + EOF } get_doris_args() { - declare -g MASTER_FE_IP CURRENT_BE_IP CURRENT_BE_PORT PRIORITY_NETWORKS - if [ $RUN_TYPE == "ELECTION" ]; then - local feServerArray=($(echo "${FE_SERVERS}" | awk '{gsub (/,/," "); print $0}')) - for i in "${feServerArray[@]}"; do - val=${i} - val=${val// /} - tmpFeName=$(echo "${val}" | awk -F ':' '{ sub(/fe/, ""); sub(/ /, ""); print$1}') - tmpFeIp=$(echo "${val}" | awk -F ':' '{ sub(/ /, ""); print$2}') - tmpFeEditLogPort=$(echo "${val}" | awk -F ':' '{ sub(/ /, ""); print$3}') - check_arg "TMP_FE_NAME" $tmpFeName - feIpArray[$tmpFeName]=${tmpFeIp} - done + declare -g MASTER_FE_IP CURRENT_BE_IP CURRENT_BE_PORT PRIORITY_NETWORKS + if [ $RUN_TYPE == "ELECTION" ]; then + local feServerArray=($(echo "${FE_SERVERS}" | awk '{gsub (/,/," "); print $0}')) + for i in "${feServerArray[@]}"; do + val=${i} + val=${val// /} + tmpFeName=$(echo "${val}" | awk -F ':' '{ sub(/fe/, ""); sub(/ /, ""); print$1}') + tmpFeIp=$(echo "${val}" | awk -F ':' '{ sub(/ /, ""); print$2}') + tmpFeEditLogPort=$(echo "${val}" | awk -F ':' '{ sub(/ /, ""); print$3}') + check_arg "TMP_FE_NAME" $tmpFeName + feIpArray[$tmpFeName]=${tmpFeIp} + done - FE_MASTER_IP=${feIpArray[1]} - check_arg "FE_MASTER_IP" $FE_MASTER_IP - BE_IP=$(echo "${BE_ADDR}" | awk -F ':' '{ sub(/ /, ""); print$1}') - check_arg "BE_IP" $BE_IP - BE_PORT=$(echo "${BE_ADDR}" | awk -F ':' '{ sub(/ /, ""); print$2}') - check_arg "BE_PORT" $BE_PORT + FE_MASTER_IP=${feIpArray[1]} + check_arg "FE_MASTER_IP" $FE_MASTER_IP + BE_IP=$(echo "${BE_ADDR}" | awk -F ':' '{ sub(/ /, ""); print$1}') + check_arg "BE_IP" $BE_IP + BE_PORT=$(echo "${BE_ADDR}" | awk -F ':' '{ sub(/ /, ""); print$2}') + check_arg "BE_PORT" $BE_PORT - elif [ $RUN_TYPE == "ASSIGN" ]; then - check_arg "FE_MASTER_IP" $FE_MASTER_IP - check_arg "BE_IP" $BE_IP - check_arg "BE_PORT" $BE_PORT - fi + elif [ $RUN_TYPE == "ASSIGN" ]; then + check_arg "FE_MASTER_IP" $FE_MASTER_IP + check_arg "BE_IP" $BE_IP + check_arg "BE_PORT" $BE_PORT + fi - PRIORITY_NETWORKS=$(echo "${BE_IP}" | awk -F '.' '{print$1"."$2"."$3".0/24"}') - check_arg "PRIORITY_NETWORKS" $PRIORITY_NETWORKS + PRIORITY_NETWORKS=$(echo "${BE_IP}" | awk -F '.' '{print$1"."$2"."$3".0/24"}') + check_arg "PRIORITY_NETWORKS" $PRIORITY_NETWORKS - # export be args - export MASTER_FE_IP=${FE_MASTER_IP} - export CURRENT_BE_IP=${BE_IP} - export CURRENT_BE_PORT=${BE_PORT} - export PRIORITY_NETWORKS=${PRIORITY_NETWORKS} + # export be args + export MASTER_FE_IP=${FE_MASTER_IP} + export CURRENT_BE_IP=${BE_IP} + export CURRENT_BE_PORT=${BE_PORT} + export PRIORITY_NETWORKS=${PRIORITY_NETWORKS} - doris_note "MASTER_FE_IP ${MASTER_FE_IP}" - doris_note "CURRENT_BE_IP ${CURRENT_BE_IP}" - doris_note "CURRENT_BE_PORT ${CURRENT_BE_PORT}" - doris_note "PRIORITY_NETWORKS ${PRIORITY_NETWORKS}" + doris_note "MASTER_FE_IP ${MASTER_FE_IP}" + doris_note "CURRENT_BE_IP ${CURRENT_BE_IP}" + doris_note "CURRENT_BE_PORT ${CURRENT_BE_PORT}" + doris_note "PRIORITY_NETWORKS ${PRIORITY_NETWORKS}" - check_be_status true + check_be_status true } # Execute sql script, passed via stdin @@ -162,32 +162,32 @@ docker_process_sql() { } check_be_status() { - set +e - for i in {1..300}; do - if [[ $1 == true ]]; then - docker_process_sql <<<"show frontends" | grep "[[:space:]]${MASTER_FE_IP}[[:space:]]" - else - docker_process_sql <<<"show backends" | grep "[[:space:]]${CURRENT_BE_IP}[[:space:]]" | grep "[[:space:]]${CURRENT_BE_PORT}[[:space:]]" - fi - be_join_status=$? - if [[ "${be_join_status}" == 0 ]]; then - if [[ $1 == true ]]; then - doris_note "MASTER FE is started!" - else - doris_note "EntryPoint Check - Verify that BE is registered to FE successfully" - BE_ALREADY_EXISTS=true - fi - return - fi - if [[ $(( $i % 20 )) == 1 ]]; then - if [[ $1 == true ]]; then - doris_note "MASTER FE is not started. retry." - else - doris_note "BE is not register. retry." - fi - fi - sleep 1 - done + set +e + for i in {1..30}; do + if [[ $1 == true ]]; then + docker_process_sql <<<"show frontends" | grep "[[:space:]]${MASTER_FE_IP}[[:space:]]" + else + docker_process_sql <<<"show backends" | grep "[[:space:]]${CURRENT_BE_IP}[[:space:]]" | grep "[[:space:]]${CURRENT_BE_PORT}[[:space:]]" + fi + be_join_status=$? + if [[ "${be_join_status}" == 0 ]]; then + if [[ $1 == true ]]; then + doris_note "MASTER FE is started!" + else + doris_note "EntryPoint Check - Verify that BE is registered to FE successfully" + BE_ALREADY_EXISTS=true + fi + return + fi + if [[ $(( $i % 15 )) == 1 ]]; then + if [[ $1 == true ]]; then + doris_note "MASTER FE is not started. retry." + else + doris_note "BE is not register. retry." + fi + fi + sleep 1 + done } # usage: docker_process_init_files [file [file [...]]] @@ -240,9 +240,9 @@ docker_process_init_files() { # Check whether the passed parameters are empty to avoid subsequent task execution failures. At the same time, # enumeration checks can be added, such as checking whether a certain parameter appears repeatedly, etc. check_arg() { - if [ -z $2 ]; then - doris_error "$1 is null!" - fi + if [ -z $2 ]; then + doris_error "$1 is null!" + fi } _main() { diff --git a/docker/runtime/be/resource/init_be.sh b/docker/runtime/be/resource/init_be.sh index 4b77eb3fc0df08..82b3007ba19154 100644 --- a/docker/runtime/be/resource/init_be.sh +++ b/docker/runtime/be/resource/init_be.sh @@ -28,50 +28,50 @@ DORIS_HOME="/opt/apache-doris" # ie: doris_warn "task may be risky!" # out: 2023-01-08T19:08:16+08:00 [Warn] [Entrypoint]: task may be risky! doris_log() { - local type="$1" - shift - # accept argument string or stdin - local text="$*" - if [ "$#" -eq 0 ]; then text="$(cat)"; fi - local dt="$(date -Iseconds)" - printf '%s [%s] [Entrypoint]: %s\n' "$dt" "$type" "$text" + local type="$1" + shift + # accept argument string or stdin + local text="$*" + if [ "$#" -eq 0 ]; then text="$(cat)"; fi + local dt="$(date -Iseconds)" + printf '%s [%s] [Entrypoint]: %s\n' "$dt" "$type" "$text" } doris_note() { - doris_log Note "$@" + doris_log Note "$@" } doris_warn() { - doris_log Warn "$@" >&2 + doris_log Warn "$@" >&2 } doris_error() { - doris_log ERROR "$@" >&2 - exit 1 + doris_log ERROR "$@" >&2 + exit 1 } # check to see if this file is being run or sourced from another script _is_sourced() { - [ "${#FUNCNAME[@]}" -ge 2 ] && + [ "${#FUNCNAME[@]}" -ge 2 ] && [ "${FUNCNAME[0]}" = '_is_sourced' ] && [ "${FUNCNAME[1]}" = 'source' ] } docker_setup_env() { - declare -g DATABASE_ALREADY_EXISTS - if [ -d "${DORIS_HOME}/be/storage/data" ]; then - DATABASE_ALREADY_EXISTS='true' - fi + declare -g DATABASE_ALREADY_EXISTS + if [ -d "${DORIS_HOME}/be/storage/data" ]; then + DATABASE_ALREADY_EXISTS='true' + fi } add_priority_networks() { - doris_note "add priority_networks ${1} to ${DORIS_HOME}/be/conf/be.conf" - echo "priority_networks = ${1}" >>${DORIS_HOME}/be/conf/be.conf + doris_note "add priority_networks ${1} to ${DORIS_HOME}/be/conf/be.conf" + echo "priority_networks = ${1}" >>${DORIS_HOME}/be/conf/be.conf } show_be_args(){ - doris_note "============= init args ================" - doris_note "MASTER_FE_IP " ${MASTER_FE_IP} - doris_note "CURRENT_BE_IP " ${CURRENT_BE_IP} - doris_note "CURRENT_BE_PORT " ${CURRENT_BE_PORT} - doris_note "RUN_TYPE " ${RUN_TYPE} + doris_note "============= init args ================" + doris_note "MASTER_FE_IP " ${MASTER_FE_IP} + doris_note "CURRENT_BE_IP " ${CURRENT_BE_IP} + doris_note "CURRENT_BE_PORT " ${CURRENT_BE_PORT} + doris_note "RUN_TYPE " ${RUN_TYPE} } # Execute sql script, passed via stdin @@ -99,40 +99,40 @@ register_be_to_fe() { # check fe status local is_fe_start=false if [ -n "$DATABASE_ALREADY_EXISTS" ]; then - check_be_status - if [ -n "$BE_ALREADY_EXISTS" ]; then - doris_warn "Same backend already exists! No need to register again!" - return - fi + check_be_status + if [ -n "$BE_ALREADY_EXISTS" ]; then + doris_warn "Same backend already exists! No need to register again!" + return + fi fi for i in {1..300}; do - if [[ $RUN_TYPE == "ELECTION" || $RUN_TYPE == "ASSIGN" ]]; then - SQL="alter system add backend '${CURRENT_BE_IP}:${CURRENT_BE_PORT}';" - doris_note "Executing SQL: $SQL" - docker_process_sql <<<"$SQL" - elif [[ $RUN_TYPE == "FQDN" ]]; then - SQL="alter system add backend '${CURRENT_NODE_NAME}:${CURRENT_BE_PORT}';" - doris_note "Executing SQL: $SQL" - docker_process_sql <<<"$SQL" - fi - register_be_status=$? - if [[ $register_be_status == 0 ]]; then - doris_note "BE successfully registered to FE!" - is_fe_start=true - return - else - check_be_status - if [[ $IS_BE_JOIN_STATUS == "true" ]]; then - return + if [[ $RUN_TYPE == "ELECTION" || $RUN_TYPE == "ASSIGN" ]]; then + SQL="alter system add backend '${CURRENT_BE_IP}:${CURRENT_BE_PORT}';" + doris_note "Executing SQL: $SQL" + docker_process_sql <<<"$SQL" + elif [[ $RUN_TYPE == "FQDN" ]]; then + SQL="alter system add backend '${CURRENT_NODE_NAME}:${CURRENT_BE_PORT}';" + doris_note "Executing SQL: $SQL" + docker_process_sql <<<"$SQL" + fi + register_be_status=$? + if [[ $register_be_status == 0 ]]; then + doris_note "BE successfully registered to FE!" + is_fe_start=true + return + else + check_be_status + if [[ $IS_BE_JOIN_STATUS == "true" ]]; then + return + fi + fi + if [[ $(( $i % 20 )) == 1 ]]; then + doris_note "Register BE to FE is failed. retry." fi - fi - if [[ $(( $i % 20 )) == 1 ]]; then - doris_note "Register BE to FE is failed. retry." - fi - sleep 1 + sleep 1 done if ! [[ $is_fe_start ]]; then - doris_error "Failed to register BE to FE!Tried 30 times!Maybe FE Start Failed!" + doris_error "Failed to register BE to FE!Tried 30 times!Maybe FE Start Failed!" fi } @@ -141,27 +141,27 @@ check_be_status() { declare -g IS_FE_START_STATUS IS_BE_JOIN_STATUS IS_FE_START_STATUS=false IS_BE_JOIN_STATUS=false - for i in {1..100}; do - if [[ $(($i % 20)) == 1 ]]; then - doris_warn "start check be register status~" - fi - if [[ $RUN_TYPE == "ELECTION" || $RUN_TYPE == "ASSIGN" ]]; then - docker_process_sql <<<"show backends" | grep "[[:space:]]${CURRENT_BE_IP}[[:space:]]" | grep "[[:space:]]${CURRENT_BE_PORT}[[:space:]]" - elif [[ $RUN_TYPE == "FQDN" ]]; then - docker_process_sql <<<"show backends" | grep "[[:space:]]${CURRENT_NODE_NAME}[[:space:]]" | grep "[[:space:]]${CURRENT_BE_PORT}[[:space:]]" - fi - be_join_status=$? - if [[ "${be_join_status}" == 0 ]]; then - doris_note "Verify that BE is registered to FE successfully" - IS_FE_START_STATUS=true - IS_BE_JOIN_STATUS=true - return - else - if [[ $(($i % 20)) == 1 ]]; then - doris_note "register is failed, wait next~" - fi - fi - sleep 1 + for i in {1..30}; do + if [[ $(($i % 15)) == 1 ]]; then + doris_warn "start check be register status~" + fi + if [[ $RUN_TYPE == "ELECTION" || $RUN_TYPE == "ASSIGN" ]]; then + docker_process_sql <<<"show backends" | grep "[[:space:]]${CURRENT_BE_IP}[[:space:]]" | grep "[[:space:]]${CURRENT_BE_PORT}[[:space:]]" + elif [[ $RUN_TYPE == "FQDN" ]]; then + docker_process_sql <<<"show backends" | grep "[[:space:]]${CURRENT_NODE_NAME}[[:space:]]" | grep "[[:space:]]${CURRENT_BE_PORT}[[:space:]]" + fi + be_join_status=$? + if [[ "${be_join_status}" == 0 ]]; then + doris_note "Verify that BE is registered to FE successfully" + IS_FE_START_STATUS=true + IS_BE_JOIN_STATUS=true + return + else + if [[ $(($i % 15)) == 1 ]]; then + doris_note "register is failed, wait next~" + fi + fi + sleep 1 done if [[ ! $IS_FE_START_STATUS ]]; then doris_error "Failed to register BE to FE!Tried 30 times!Maybe FE Start Failed!" @@ -186,14 +186,14 @@ _main() { trap 'cleanup' SIGTERM SIGINT docker_setup_env if [ -z "$DATABASE_ALREADY_EXISTS" ]; then - if [ $RUN_TYPE == "FQDN" ]; then - add_fqdn_conf - else - add_priority_networks $PRIORITY_NETWORKS - fi - node_role_conf - show_be_args - register_be_to_fe + if [ $RUN_TYPE == "FQDN" ]; then + add_fqdn_conf + else + add_priority_networks $PRIORITY_NETWORKS + fi + node_role_conf + show_be_args + register_be_to_fe fi check_be_status doris_note "Ready to start BE!" @@ -205,5 +205,5 @@ _main() { } if ! _is_sourced; then - _main "$@" + _main "$@" fi From 55f450cd00ead0728b592abc2b1020aee83ca009 Mon Sep 17 00:00:00 2001 From: abmdocrt Date: Fri, 13 Dec 2024 16:50:44 +0800 Subject: [PATCH 45/63] [Enhancement](compaction) Do not set failure time when cumulative compaction dealing with delete rowset (#43466) Before this PR, in cases where there is an alternating distribution of data rowset -> delete rowset -> data rowset -> delete rowset, cumulative compaction would only move the cumulative point forward to allow base compaction to handle the delete rowset. Cumulative compaction itself would not process the data and would return be marked as failure. This would cause the compaction submission task process to pause for 5 seconds, impacting efficiency. This PR modifies the return status to OK for such cases, which improves the efficiency of the compaction submission task. --- be/src/cloud/cloud_cumulative_compaction.cpp | 4 + be/src/cloud/cloud_storage_engine.cpp | 3 +- be/src/common/config.cpp | 1 + be/src/common/config.h | 2 + be/src/olap/tablet.cpp | 13 +- .../test_cumu_compaction_with_delete.out | 5 + .../test_cumu_compaction_with_delete.groovy | 122 ++++++++++++++++++ 7 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 regression-test/data/compaction/test_cumu_compaction_with_delete.out create mode 100644 regression-test/suites/compaction/test_cumu_compaction_with_delete.groovy diff --git a/be/src/cloud/cloud_cumulative_compaction.cpp b/be/src/cloud/cloud_cumulative_compaction.cpp index 6b4dbe360da651..1acf8efe32e62b 100644 --- a/be/src/cloud/cloud_cumulative_compaction.cpp +++ b/be/src/cloud/cloud_cumulative_compaction.cpp @@ -92,6 +92,10 @@ Status CloudCumulativeCompaction::prepare_compact() { // plus 1 to skip the delete version. // NOTICE: after that, the cumulative point may be larger than max version of this tablet, but it doesn't matter. update_cumulative_point(); + if (!config::enable_sleep_between_delete_cumu_compaction) { + st = Status::Error( + "_last_delete_version.first not equal to -1"); + } } return st; } diff --git a/be/src/cloud/cloud_storage_engine.cpp b/be/src/cloud/cloud_storage_engine.cpp index b66a9cfbdb2245..650909a29157cd 100644 --- a/be/src/cloud/cloud_storage_engine.cpp +++ b/be/src/cloud/cloud_storage_engine.cpp @@ -677,7 +677,8 @@ Status CloudStorageEngine::_submit_cumulative_compaction_task(const CloudTabletS auto st = compaction->prepare_compact(); if (!st.ok()) { long now = duration_cast(system_clock::now().time_since_epoch()).count(); - if (st.is()) { + if (st.is() && + st.msg() != "_last_delete_version.first not equal to -1") { // Backoff strategy if no suitable version tablet->last_cumu_no_suitable_version_ms = now; } diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp index b70f492a29dfda..95a3e61fb5517a 100644 --- a/be/src/common/config.cpp +++ b/be/src/common/config.cpp @@ -1402,6 +1402,7 @@ DEFINE_mBool(enable_delete_bitmap_merge_on_compaction, "false"); // Enable validation to check the correctness of table size. DEFINE_Bool(enable_table_size_correctness_check, "false"); DEFINE_Bool(force_regenerate_rowsetid_on_start_error, "false"); +DEFINE_mBool(enable_sleep_between_delete_cumu_compaction, "false"); // clang-format off #ifdef BE_TEST diff --git a/be/src/common/config.h b/be/src/common/config.h index 984024cab7c77f..f8a9c3f7480b33 100644 --- a/be/src/common/config.h +++ b/be/src/common/config.h @@ -1487,6 +1487,8 @@ DECLARE_Bool(force_regenerate_rowsetid_on_start_error); DECLARE_mBool(enable_delete_bitmap_merge_on_compaction); // Enable validation to check the correctness of table size. DECLARE_Bool(enable_table_size_correctness_check); +// Enable sleep 5s between delete cumulative compaction. +DECLARE_mBool(enable_sleep_between_delete_cumu_compaction); #ifdef BE_TEST // test s3 diff --git a/be/src/olap/tablet.cpp b/be/src/olap/tablet.cpp index a1a56507ffc67a..705d0ad53097e8 100644 --- a/be/src/olap/tablet.cpp +++ b/be/src/olap/tablet.cpp @@ -1750,8 +1750,13 @@ Status Tablet::prepare_compaction_and_calculate_permits( } if (!res.ok()) { - tablet->set_last_cumu_compaction_failure_time(UnixMillis()); permits = 0; + // if we meet a delete version, should increase the cumulative point to let base compaction handle the delete version. + // no need to wait 5s. + if (!(res.msg() == "_last_delete_version.first not equal to -1") || + config::enable_sleep_between_delete_cumu_compaction) { + tablet->set_last_cumu_compaction_failure_time(UnixMillis()); + } if (!res.is()) { DorisMetrics::instance()->cumulative_compaction_request_failed->increment(1); return Status::InternalError("prepare cumulative compaction with err: {}", res); @@ -1759,6 +1764,12 @@ Status Tablet::prepare_compaction_and_calculate_permits( // return OK if OLAP_ERR_CUMULATIVE_NO_SUITABLE_VERSION, so that we don't need to // print too much useless logs. // And because we set permits to 0, so even if we return OK here, nothing will be done. + LOG_INFO( + "cumulative compaction meet delete rowset, increase cumu point without other " + "operation.") + .tag("tablet id:", tablet->tablet_id()) + .tag("after cumulative compaction, cumu point:", + tablet->cumulative_layer_point()); return Status::OK(); } } else if (compaction_type == CompactionType::BASE_COMPACTION) { diff --git a/regression-test/data/compaction/test_cumu_compaction_with_delete.out b/regression-test/data/compaction/test_cumu_compaction_with_delete.out new file mode 100644 index 00000000000000..642559699ac60c --- /dev/null +++ b/regression-test/data/compaction/test_cumu_compaction_with_delete.out @@ -0,0 +1,5 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select1 -- + +-- !select2 -- + diff --git a/regression-test/suites/compaction/test_cumu_compaction_with_delete.groovy b/regression-test/suites/compaction/test_cumu_compaction_with_delete.groovy new file mode 100644 index 00000000000000..7c6be0b177ce1e --- /dev/null +++ b/regression-test/suites/compaction/test_cumu_compaction_with_delete.groovy @@ -0,0 +1,122 @@ +// 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. + +import org.codehaus.groovy.runtime.IOGroovyMethods + +suite("test_cumu_compaction_with_delete") { + def tableName = "test_cumu_compaction_with_delete" + def check_cumu_point = { cumu_point -> + def tablets = sql_return_maparray """ show tablets from ${tableName}; """ + int cumuPoint = 0 + for (def tablet in tablets) { + String tablet_id = tablet.TabletId + (code, out, err) = curl("GET", tablet.CompactionStatus) + logger.info("Show tablets status: code=" + code + ", out=" + out + ", err=" + err) + assertEquals(code, 0) + def tabletJson = parseJson(out.trim()) + cumuPoint = tabletJson["cumulative point"] + } + return cumuPoint > cumu_point + } + + try { + sql """ DROP TABLE IF EXISTS ${tableName} """ + sql """ + CREATE TABLE ${tableName} ( + `user_id` INT NOT NULL, + `value` INT NOT NULL) + UNIQUE KEY(`user_id`) + DISTRIBUTED BY HASH(`user_id`) + BUCKETS 1 + PROPERTIES ("replication_allocation" = "tag.location.default: 1", + "enable_mow_light_delete" = "true")""" + + for(int i = 1; i <= 100; ++i){ + sql """ INSERT INTO ${tableName} VALUES (1,1)""" + sql """ delete from ${tableName} where user_id = 1""" + } + + now = System.currentTimeMillis() + + while(true){ + if(check_cumu_point(100)){ + break; + } + Thread.sleep(1000) + } + time_diff = System.currentTimeMillis() - now + logger.info("time_diff:" + time_diff) + assertTrue(time_diff<200*1000) + + qt_select1 """select * from ${tableName} order by user_id, value""" + } catch (Exception e){ + logger.info(e.getMessage()) + assertFalse(true) + } finally { + try_sql("DROP TABLE IF EXISTS ${tableName} FORCE") + } + + def backendId_to_backendIP = [:] + def backendId_to_backendHttpPort = [:] + getBackendIpHttpPort(backendId_to_backendIP, backendId_to_backendHttpPort); + + def set_be_config = { key, value -> + for (String backend_id: backendId_to_backendIP.keySet()) { + def (code, out, err) = update_be_config(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), key, value) + logger.info("update config: code=" + code + ", out=" + out + ", err=" + err) + } + } + + try { + set_be_config.call("enable_sleep_between_delete_cumu_compaction", "true") + sql """ DROP TABLE IF EXISTS ${tableName} """ + sql """ + CREATE TABLE ${tableName} ( + `user_id` INT NOT NULL, + `value` INT NOT NULL) + UNIQUE KEY(`user_id`) + DISTRIBUTED BY HASH(`user_id`) + BUCKETS 1 + PROPERTIES ("replication_allocation" = "tag.location.default: 1", + "enable_mow_light_delete" = "true")""" + + for(int i = 1; i <= 100; ++i){ + sql """ INSERT INTO ${tableName} VALUES (1,1)""" + sql """ delete from ${tableName} where user_id = 1""" + } + + now = System.currentTimeMillis() + + while(true){ + if(check_cumu_point(100)){ + break; + } + Thread.sleep(1000) + } + time_diff = System.currentTimeMillis() - now + logger.info("time_diff:" + time_diff) + assertTrue(time_diff>=200*1000) + + qt_select2 """select * from ${tableName} order by user_id, value""" + } catch (Exception e){ + logger.info(e.getMessage()) + assertFalse(true) + } finally { + try_sql("DROP TABLE IF EXISTS ${tableName} FORCE") + set_be_config.call("enable_sleep_between_delete_cumu_compaction", "false") + } +} \ No newline at end of file From 41e554dd7efca2762244f2cc27eed936b31e63f8 Mon Sep 17 00:00:00 2001 From: Calvin Kirs Date: Fri, 13 Dec 2024 16:57:10 +0800 Subject: [PATCH 46/63] [Fix](Insert-Job)Resolving Task Status Discrepancies in Query Execution Records (#45342) ### What problem does this PR solve? When querying the execution records of tasks, the current system has two sources that may describe task status: Task status in the scheduling module: Represents the processing status of tasks within the scheduling system. Task status in LoadManager: Specifically refers to the status of Insert-type tasks, containing more detailed execution information. When the data in the LoadManager is deleted or expires, the completion status will revert to the task status from the scheduling system, which could cause confusion. Therefore, consistency needs to be maintained. Since these two sources may have inconsistencies in their status information, they can easily cause confusion for users and developers. --- .../org/apache/doris/job/extensions/insert/InsertTask.java | 2 +- regression-test/suites/job_p0/test_base_insert_job.groovy | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/InsertTask.java b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/InsertTask.java index 23a367d5d6e1a1..a577250dc865ed 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/InsertTask.java +++ b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/InsertTask.java @@ -244,7 +244,7 @@ public TRow getTvfInfo(String jobName) { trow.addToColumnValue(new TCell().setStringVal(String.valueOf(getJobId()))); trow.addToColumnValue(new TCell().setStringVal(jobName)); trow.addToColumnValue(new TCell().setStringVal(getJobId() + LABEL_SPLITTER + getTaskId())); - trow.addToColumnValue(new TCell().setStringVal(jobInfo.getState().name())); + trow.addToColumnValue(new TCell().setStringVal(getStatus().name())); trow.addToColumnValue(new TCell().setStringVal(getErrorMsg())); // create time trow.addToColumnValue(new TCell().setStringVal(TimeUtils.longToTimeString(getCreateTimeMs()))); diff --git a/regression-test/suites/job_p0/test_base_insert_job.groovy b/regression-test/suites/job_p0/test_base_insert_job.groovy index 2bdf96cd5bdc3f..33ae28443b290a 100644 --- a/regression-test/suites/job_p0/test_base_insert_job.groovy +++ b/regression-test/suites/job_p0/test_base_insert_job.groovy @@ -116,7 +116,7 @@ suite("test_base_insert_job") { def taskStatus = sql """select status from tasks("type"="insert") where JobName ='${jobName}'""" for (int i = 0; i < taskStatus.size(); i++) { - assert taskStatus.get(i).get(0) =="CANCELED" || taskStatus.get(i).get(0) =="FINISHED" + assert taskStatus.get(i).get(0) =="CANCELED" || taskStatus.get(i).get(0) =="SUCCESS" } sql """ CREATE JOB ${jobMixedName} ON SCHEDULE every 1 second DO insert into ${tableName} (timestamp, type, user_id) values ('2023-03-18','1','12213'); @@ -168,7 +168,7 @@ suite("test_base_insert_job") { // table should have one record after job finished assert datas.size() == 1 // one time job only has one task. when job finished, task status should be FINISHED - assert datas.get(0).get(0) == "FINISHED" + assert datas.get(0).get(0) == "SUCCESS" // check table data def dataCount1 = sql """select count(1) from ${tableName} where user_id=1001""" assert dataCount1.get(0).get(0) == 1 From ab863bb5923b383a5666ffdfe072258c2105c1a0 Mon Sep 17 00:00:00 2001 From: shuke Date: Fri, 13 Dec 2024 17:27:44 +0800 Subject: [PATCH 47/63] [regression-test](framework) disable defining global variable in test groovy files (#44576) --- .../test_uniq_vals_schema_change.out | 3 +++ .../regression/suite/ScriptSource.groovy | 9 ++++++- .../test_assistant_command_auth.groovy | 2 +- .../test_backup_restore_db.groovy | 2 +- .../test_backup_restore_exclude.groovy | 2 +- .../test_backup_restore_multi_tables.groovy | 2 +- ...ckup_restore_multi_tables_overwrite.groovy | 2 +- .../test_backup_restore_mv.groovy | 10 ++++---- ...st_restore_mix_exists_and_new_table.groovy | 2 +- .../test_drop_catalog_recycle_bin.groovy | 24 +++++++++---------- .../test_ingest_binlog.groovy | 2 +- .../inverted_index/test_ingest_binlog.groovy | 2 +- .../ccr_syncer_p0/test_ingest_binlog.groovy | 2 +- .../test_disable_revoke_admin_auth.groovy | 1 + .../test_grant_revoke_cluster_to_user.groovy | 5 ++-- ..._grant_revoke_compute_group_to_user.groovy | 5 ++-- .../compaction/test_full_compaction.groovy | 2 +- .../compaction/test_full_compaction_ck.groovy | 2 +- .../test_trim_new_parameters.groovy | 2 +- .../test_routine_load_generated_column.groovy | 2 +- .../test_create_table_properties.groovy | 2 +- .../suites/export/test_array_export.groovy | 6 ++--- .../suites/export/test_map_export.groovy | 4 ++-- .../suites/export/test_struct_export.groovy | 2 +- .../csv/test_outfile_empty_data.groovy | 14 +++++------ ...test_outfile_expr_generate_col_name.groovy | 10 ++++---- .../suites/export_p0/test_export_basic.groovy | 8 +++---- .../export_p0/test_outfile_file_suffix.groovy | 2 +- .../test_show_create_database.groovy | 2 +- .../cache/test_file_cache_statistics.groovy | 2 +- .../hive/test_autoinc_broker_load.groovy | 22 ++++++++--------- .../test_hive_parquet_alter_column.groovy | 2 +- .../hive/test_hive_statistic.groovy | 2 +- .../test_partial_update_broker_load.groovy | 16 ++++++------- .../test_iceberg_optimize_count.groovy | 10 ++++---- .../test_iceberg_predicate_conversion.groovy | 2 +- .../jdbc/test_mysql_jdbc_statistics.groovy | 2 +- .../insert_group_commit_with_exception.groovy | 24 +++++++++---------- ...t_group_commit_interval_ms_property.groovy | 2 +- ...est_add_drop_index_on_table_with_mv.groovy | 2 +- .../test_pk_uk_index_change.groovy | 2 +- .../load/test_spark_load.groovy | 6 ++--- .../test_schema_change_storage_format.groovy | 2 +- ..._array_contains_with_inverted_index.groovy | 4 ++-- .../test_index_match_select.groovy | 8 +++---- .../test_primary_key_simple_case.groovy | 2 +- .../http_stream/test_http_stream_2pc.groovy | 8 +++---- ...st_insert_random_distribution_table.groovy | 4 ++-- .../load_p0/mysql_load/test_mysql_load.groovy | 2 +- .../test_routine_load_alter.groovy | 4 ++-- .../test_routine_load_with_udf.groovy | 2 +- .../test_get_stream_load_state.groovy | 6 ++--- ...eam_load_with_nonexist_db_and_table.groovy | 6 ++--- .../test_map_load_and_compaction.groovy | 4 +++- .../stream_load/test_stream_load.groovy | 22 ++++++++--------- .../stream_load/test_stream_load_2pc.groovy | 10 ++++---- ..._stream_load_2pc_with_schema_change.groovy | 6 ++--- .../test_stream_load_move_memtable.groovy | 2 +- .../manager/test_manager_interface_2.groovy | 4 ++-- .../manager/test_manager_interface_4.groovy | 2 +- .../suites/mtmv_p0/test_build_mtmv.groovy | 2 +- .../suites/mtmv_p0/test_create_mv_mtmv.groovy | 2 +- .../mtmv_p0/test_create_rollup_mtmv.groovy | 2 +- .../mtmv_p0/test_limit_partition_mtmv.groovy | 2 +- .../suites/mtmv_p0/test_mtmv_outfile.groovy | 2 +- .../mtmv_p0/test_rollup_partition_mtmv.groovy | 4 ++-- .../test_create_mv/test_create_mv.groovy | 2 +- .../nereids_arith_p0/topn/accept_null.groovy | 4 ++-- .../cache/parse_sql_from_sql_cache.groovy | 2 +- .../fold_constant/fold_constant_by_fe.groovy | 2 +- .../nereids_p0/outfile/test_outfile.groovy | 12 ++++++---- .../outfile/test_outfile_expr.groovy | 2 +- .../outfile/test_outfile_parquet.groovy | 8 ++++--- ...te_or_datetime_computation_negative.groovy | 1 - .../mv/dimension/dimension_self_conn.groovy | 2 +- .../suites/nereids_syntax_p0/group_bit.groovy | 2 +- .../nereids_syntax_p0/rollup/bitmap.groovy | 2 +- .../test_auto_partition_behavior.groovy | 2 +- .../test_auto_partition_load.groovy | 4 ++-- .../test_auto_range_partition.groovy | 4 ++-- .../test_dynamic_partition.groovy | 2 +- ...amic_partition_mod_distribution_key.groovy | 2 +- .../test_dynamic_partition_with_alter.groovy | 2 +- .../suites/query_p0/sort/topn_2pr_rule.groovy | 2 +- .../query_profile/s3_load_profile_test.groovy | 2 +- .../test_materialized_view_bitmap.groovy | 2 +- .../rollup/test_materialized_view_hll.groovy | 2 +- ...materialized_view_hll_with_light_sc.groovy | 2 +- .../test_agg_keys_schema_change.groovy | 8 +++---- .../test_agg_mv_schema_change.groovy | 8 +++---- .../test_agg_rollup_schema_change.groovy | 10 ++++---- .../test_agg_schema_key_change_modify1.groovy | 6 ++--- .../test_agg_vals_schema_change.groovy | 4 ++-- .../test_alter_uniq_null.groovy | 2 +- .../test_dup_keys_schema_change.groovy | 8 +++---- .../test_dup_mv_schema_change.groovy | 4 ++-- .../test_dup_rollup_schema_change.groovy | 6 ++--- .../test_dup_schema_key_change_modify1.groovy | 6 ++--- .../test_dup_vals_schema_change.groovy | 4 ++-- .../test_enable_light_schema_change.groovy | 2 +- .../test_schema_change_duplicate.groovy | 2 +- .../test_uniq_keys_schema_change.groovy | 4 ++-- .../test_uniq_mv_schema_change.groovy | 4 ++-- .../test_uniq_rollup_schema_change.groovy | 6 ++--- .../test_uniq_vals_schema_change.groovy | 8 +++---- .../test_varchar_schema_change.groovy | 4 ++-- .../suites/show_p0/test_show_data.groovy | 2 +- .../suites/statistics/analyze_stats.groovy | 6 ++--- ...al_update_delete_sign_with_conflict.groovy | 6 ++--- .../test_partial_update_parallel.groovy | 6 ++--- .../flexible/upgrade/test.groovy | 2 +- ...al_update_delete_sign_with_conflict.groovy | 6 ++--- .../test_partial_update_parallel.groovy | 6 ++--- .../suites/update/test_update_configs.groovy | 2 +- .../variant_p0/concurrent_insert.groovy | 6 ++--- .../suites/variant_p0/delete_update.groovy | 6 ++--- .../suites/variant_p0/nested.groovy | 2 +- .../schema_change/schema_change.groovy | 2 +- .../test_resource_tag.groovy | 14 +++++------ 119 files changed, 290 insertions(+), 276 deletions(-) diff --git a/regression-test/data/schema_change_p0/test_uniq_vals_schema_change.out b/regression-test/data/schema_change_p0/test_uniq_vals_schema_change.out index de0526b3e734cd..22d1644a86b381 100644 --- a/regression-test/data/schema_change_p0/test_uniq_vals_schema_change.out +++ b/regression-test/data/schema_change_p0/test_uniq_vals_schema_change.out @@ -11,6 +11,9 @@ -- !sc -- 3 +-- !sc -- +3 2017-10-01 Beijing 10 1 2020-01-03T00:00 2020-01-03T00:00 1 32 20 2 + -- !sc -- 4 2017-10-01 Beijing 10 1 2020-01-03T00:00 2020-01-03T00:00 1 32 20 2 diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/ScriptSource.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/ScriptSource.groovy index d73cf6afaf6b09..97d935c58ae05e 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/ScriptSource.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/ScriptSource.groovy @@ -34,7 +34,14 @@ class GroovyFileSource implements ScriptSource { @Override SuiteScript toScript(ScriptContext scriptContext, GroovyShell shell) { - SuiteScript suiteScript = shell.parse(file) as SuiteScript + def setPropertyFunction = ''' +\nvoid setProperty(String key, value) { + throw new IllegalArgumentException("defined global variables in script are not allowed: ${key}") +} +''' + def scriptContent = file.text + scriptContent = scriptContent + setPropertyFunction + SuiteScript suiteScript = shell.parse(scriptContent, file.getName()) as SuiteScript suiteScript.init(scriptContext) return suiteScript } diff --git a/regression-test/suites/auth_call/test_assistant_command_auth.groovy b/regression-test/suites/auth_call/test_assistant_command_auth.groovy index 49a149a28ce51f..1b47e566ff31e8 100644 --- a/regression-test/suites/auth_call/test_assistant_command_auth.groovy +++ b/regression-test/suites/auth_call/test_assistant_command_auth.groovy @@ -87,7 +87,7 @@ suite("test_assistant_command_auth","p0,auth_call") { } sql """grant select_PRIV on ${catalogName}.*.* to ${user}""" - connect(user, password="${pwd}", context.config.jdbcUrl) { + connect(user, "${pwd}", context.config.jdbcUrl) { sql """REFRESH CATALOG ${catalogName};""" } diff --git a/regression-test/suites/backup_restore/test_backup_restore_db.groovy b/regression-test/suites/backup_restore/test_backup_restore_db.groovy index 08b9f619d4fe03..2cca1356dc5d73 100644 --- a/regression-test/suites/backup_restore/test_backup_restore_db.groovy +++ b/regression-test/suites/backup_restore/test_backup_restore_db.groovy @@ -81,7 +81,7 @@ suite("test_backup_restore_db", "backup_restore") { syncer.waitAllRestoreFinish(dbName) for (def tableName in tables) { - result = sql "SELECT * FROM ${dbName}.${tableName}" + def result = sql "SELECT * FROM ${dbName}.${tableName}" assertEquals(result.size(), numRows); sql "DROP TABLE ${dbName}.${tableName} FORCE" } diff --git a/regression-test/suites/backup_restore/test_backup_restore_exclude.groovy b/regression-test/suites/backup_restore/test_backup_restore_exclude.groovy index e29ebfe3b6be1b..6993a0ca6fa22f 100644 --- a/regression-test/suites/backup_restore/test_backup_restore_exclude.groovy +++ b/regression-test/suites/backup_restore/test_backup_restore_exclude.groovy @@ -88,7 +88,7 @@ suite("test_backup_restore_exclude", "backup_restore") { qt_select "SELECT * FROM ${dbName}.${backupExcludeTable} ORDER BY id" for (def tableName in tables) { - result = sql "SELECT * FROM ${dbName}.${tableName}" + def result = sql "SELECT * FROM ${dbName}.${tableName}" assertEquals(result.size(), numRows); sql "DROP TABLE ${dbName}.${tableName} FORCE" } diff --git a/regression-test/suites/backup_restore/test_backup_restore_multi_tables.groovy b/regression-test/suites/backup_restore/test_backup_restore_multi_tables.groovy index 4fa274bbae305a..2be39d8eef14b5 100644 --- a/regression-test/suites/backup_restore/test_backup_restore_multi_tables.groovy +++ b/regression-test/suites/backup_restore/test_backup_restore_multi_tables.groovy @@ -84,7 +84,7 @@ suite("test_backup_restore_multi_tables", "backup_restore") { syncer.waitAllRestoreFinish(dbName) for (def tableName in tables) { - result = sql "SELECT * FROM ${dbName}.${tableName}" + def result = sql "SELECT * FROM ${dbName}.${tableName}" assertEquals(result.size(), numRows); sql "DROP TABLE ${dbName}.${tableName} FORCE" } diff --git a/regression-test/suites/backup_restore/test_backup_restore_multi_tables_overwrite.groovy b/regression-test/suites/backup_restore/test_backup_restore_multi_tables_overwrite.groovy index 30dc63dd195618..9ee5c848aef79e 100644 --- a/regression-test/suites/backup_restore/test_backup_restore_multi_tables_overwrite.groovy +++ b/regression-test/suites/backup_restore/test_backup_restore_multi_tables_overwrite.groovy @@ -86,7 +86,7 @@ suite("test_backup_restore_multi_tables_overwrite", "backup_restore") { qt_select "SELECT * FROM ${dbName}.${firstTableName} ORDER BY id" for (def tableName in tables) { - result = sql "SELECT * FROM ${dbName}.${tableName}" + def result = sql "SELECT * FROM ${dbName}.${tableName}" assertEquals(result.size(), numRows); sql "DROP TABLE ${dbName}.${tableName} FORCE" } diff --git a/regression-test/suites/backup_restore/test_backup_restore_mv.groovy b/regression-test/suites/backup_restore/test_backup_restore_mv.groovy index 0a54aa76e17b36..398b51cc995a90 100644 --- a/regression-test/suites/backup_restore/test_backup_restore_mv.groovy +++ b/regression-test/suites/backup_restore/test_backup_restore_mv.groovy @@ -57,13 +57,13 @@ suite("test_backup_restore_mv", "backup_restore") { """ def alter_finished = false - for (i = 0; i < 60 && !alter_finished; i++) { + for (int i = 0; i < 60 && !alter_finished; i++) { result = sql_return_maparray "SHOW ALTER TABLE MATERIALIZED VIEW FROM ${dbName}" logger.info("result: ${result}") - for (int i = 0; i < result.size(); i++) { - if (result[i]['TableName'] == "${tableName}" && - result[i]['RollupIndexName'] == "${mvName}" && - result[i]['State'] == 'FINISHED') { + for (int j = 0; j < result.size(); j++) { + if (result[j]['TableName'] == "${tableName}" && + result[j]['RollupIndexName'] == "${mvName}" && + result[j]['State'] == 'FINISHED') { alter_finished = true break } diff --git a/regression-test/suites/backup_restore/test_restore_mix_exists_and_new_table.groovy b/regression-test/suites/backup_restore/test_restore_mix_exists_and_new_table.groovy index aea46af179de06..b1cc9136b25900 100644 --- a/regression-test/suites/backup_restore/test_restore_mix_exists_and_new_table.groovy +++ b/regression-test/suites/backup_restore/test_restore_mix_exists_and_new_table.groovy @@ -84,7 +84,7 @@ suite("test_restore_mix_exists_and_new_table", "backup_restore") { syncer.waitAllRestoreFinish(dbName) for (def tableName in tables) { - result = sql "SELECT * FROM ${dbName}.${tableName}" + def result = sql "SELECT * FROM ${dbName}.${tableName}" assertEquals(result.size(), numRows); sql "DROP TABLE ${dbName}.${tableName} FORCE" } diff --git a/regression-test/suites/catalog_recycle_bin_p0/test_drop_catalog_recycle_bin.groovy b/regression-test/suites/catalog_recycle_bin_p0/test_drop_catalog_recycle_bin.groovy index 40b1175c856a58..ec2fdc891aaeba 100644 --- a/regression-test/suites/catalog_recycle_bin_p0/test_drop_catalog_recycle_bin.groovy +++ b/regression-test/suites/catalog_recycle_bin_p0/test_drop_catalog_recycle_bin.groovy @@ -60,28 +60,28 @@ suite("test_drop_catalog_recycle_bin") { """ // test drop partition in catalog recycle bin - res = sql "SHOW CREATE TABLE `test_drop_catalog_recycle_bin_db`.`test_drop_catalog_recycle_bin_tb1`;" + def res = sql "SHOW CREATE TABLE `test_drop_catalog_recycle_bin_db`.`test_drop_catalog_recycle_bin_tb1`;" assertTrue(res.size() != 0) sql "use `test_drop_catalog_recycle_bin_db`" sql "ALTER TABLE `test_drop_catalog_recycle_bin_db`.`test_drop_catalog_recycle_bin_tb1` DROP PARTITION p1000;" - pre_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p1000" """ + def pre_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p1000" """ assertTrue(pre_res.size() > 0) - partition_id = pre_res[0][4] + def partition_id = pre_res[0][4] sql "DROP CATALOG RECYCLE BIN WHERE 'PartitionId' = ${partition_id};" - cur_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p1000" """ + def cur_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p1000" """ assertTrue(pre_res.size() - cur_res.size() == 1) // test drop table not in catalog recycle bin sql "use `test_drop_catalog_recycle_bin_db`" sql "ALTER TABLE `test_drop_catalog_recycle_bin_db`.`test_drop_catalog_recycle_bin_tb1` DROP PARTITION p111;" - pre_pt_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p111" """ + def pre_pt_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p111" """ assertTrue(pre_pt_res.size() > 0) - table_id = pre_res[0][3] + def table_id = pre_res[0][3] sql "DROP CATALOG RECYCLE BIN WHERE 'TableId' = ${table_id};" - cur_pt_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p111" """ + def cur_pt_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p111" """ assertTrue(pre_pt_res.size() - cur_pt_res.size() == 1) // test drop table in catalog recycle bin @@ -89,13 +89,13 @@ suite("test_drop_catalog_recycle_bin") { sql "ALTER TABLE `test_drop_catalog_recycle_bin_db`.`test_drop_catalog_recycle_bin_tb1` DROP PARTITION p222;" sql "DROP TABLE `test_drop_catalog_recycle_bin_db`.`test_drop_catalog_recycle_bin_tb1`;" - pre_tb_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_tb1" """ + def pre_tb_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_tb1" """ assertTrue(pre_tb_res.size() > 0) pre_pt_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p222" """ assertTrue(pre_pt_res.size() > 0) table_id = pre_res[0][3] sql "DROP CATALOG RECYCLE BIN WHERE 'TableId' = ${table_id};" - cur_tb_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_tb1" """ + def cur_tb_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_tb1" """ assertTrue(pre_tb_res.size() - cur_tb_res.size() == 1) cur_pt_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p111" """ assertTrue(pre_pt_res.size() - cur_pt_res.size() == 1) @@ -103,13 +103,13 @@ suite("test_drop_catalog_recycle_bin") { // test drop db not in catalog recycle bin sql "ALTER TABLE `test_drop_catalog_recycle_bin_db`.`test_drop_catalog_recycle_bin_tb2` DROP PARTITION p111;" - pre_db_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_db" """ + def pre_db_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_db" """ assertTrue(pre_db_res.size() == 0) pre_tb_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_tb2" """ assertTrue(pre_tb_res.size() == 0) pre_pt_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p111" """ assertTrue(pre_pt_res.size() > 0) - db_id = pre_res[0][2] + def db_id = pre_res[0][2] sql "DROP CATALOG RECYCLE BIN WHERE 'DbId' = ${db_id};" cur_pt_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "p222" """ assertTrue(pre_pt_res.size() - cur_pt_res.size() == 1) @@ -126,7 +126,7 @@ suite("test_drop_catalog_recycle_bin") { assertTrue(pre_pt_res.size() > 0) db_id = pre_res[0][2] sql "DROP CATALOG RECYCLE BIN WHERE 'DbId' = ${db_id};" - cur_db_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_db" """ + def cur_db_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_db" """ assertTrue(pre_db_res.size() - cur_db_res.size() == 1) cur_tb_res = sql """ SHOW CATALOG RECYCLE BIN WHERE NAME = "test_drop_catalog_recycle_bin_tb2" """ assertTrue(pre_tb_res.size() - cur_tb_res.size() == 1) diff --git a/regression-test/suites/ccr_mow_syncer_p0/test_ingest_binlog.groovy b/regression-test/suites/ccr_mow_syncer_p0/test_ingest_binlog.groovy index e07529718ee467..16ce1d43c4fccb 100644 --- a/regression-test/suites/ccr_mow_syncer_p0/test_ingest_binlog.groovy +++ b/regression-test/suites/ccr_mow_syncer_p0/test_ingest_binlog.groovy @@ -78,7 +78,7 @@ suite("test_mow_ingest_binlog") { } target_sql " sync " - res = target_sql """SELECT * FROM ${tableName} WHERE test=${test_num}""" + def res = target_sql """SELECT * FROM ${tableName} WHERE test=${test_num}""" assertEquals(res.size(), insert_num) diff --git a/regression-test/suites/ccr_syncer_p0/inverted_index/test_ingest_binlog.groovy b/regression-test/suites/ccr_syncer_p0/inverted_index/test_ingest_binlog.groovy index 12ba49e084dae9..b46d256a52ff28 100644 --- a/regression-test/suites/ccr_syncer_p0/inverted_index/test_ingest_binlog.groovy +++ b/regression-test/suites/ccr_syncer_p0/inverted_index/test_ingest_binlog.groovy @@ -152,7 +152,7 @@ suite("test_ingest_binlog_index") { } target_sql " sync " - res = target_sql """SELECT * FROM ${tableName}""" + def res = target_sql """SELECT * FROM ${tableName}""" if (tableName.contains("mow")) { assertEquals(res.size(), insert_data(tableName).size() / 2 as Integer) } else { diff --git a/regression-test/suites/ccr_syncer_p0/test_ingest_binlog.groovy b/regression-test/suites/ccr_syncer_p0/test_ingest_binlog.groovy index 9f176cac9e09e4..414621b5086ed9 100644 --- a/regression-test/suites/ccr_syncer_p0/test_ingest_binlog.groovy +++ b/regression-test/suites/ccr_syncer_p0/test_ingest_binlog.groovy @@ -77,7 +77,7 @@ suite("test_ingest_binlog") { } target_sql " sync " - res = target_sql """SELECT * FROM ${tableName} WHERE test=${test_num}""" + def res = target_sql """SELECT * FROM ${tableName} WHERE test=${test_num}""" assertEquals(res.size(), insert_num) diff --git a/regression-test/suites/cloud_p0/auth/test_disable_revoke_admin_auth.groovy b/regression-test/suites/cloud_p0/auth/test_disable_revoke_admin_auth.groovy index 19add1d2c87503..bc1767a4ed4b76 100644 --- a/regression-test/suites/cloud_p0/auth/test_disable_revoke_admin_auth.groovy +++ b/regression-test/suites/cloud_p0/auth/test_disable_revoke_admin_auth.groovy @@ -22,6 +22,7 @@ suite("test_disable_revoke_admin_auth", "cloud_auth") { sql """create user ${user} identified by 'Cloud12345' default role 'admin'""" sql "sync" + def result try { result = sql """revoke 'admin' from 'admin'"""; diff --git a/regression-test/suites/cloud_p0/auth/test_grant_revoke_cluster_to_user.groovy b/regression-test/suites/cloud_p0/auth/test_grant_revoke_cluster_to_user.groovy index a61b4f96954e9c..d2209d1e81ef52 100644 --- a/regression-test/suites/cloud_p0/auth/test_grant_revoke_cluster_to_user.groovy +++ b/regression-test/suites/cloud_p0/auth/test_grant_revoke_cluster_to_user.groovy @@ -67,7 +67,7 @@ suite("test_grant_revoke_cluster_to_user", "cloud_auth") { // 1. change user // ${user1} admin role sql """create user ${user1} identified by 'Cloud12345' default role 'admin'""" - result = sql_return_maparray """show grants for '${user1}'""" + def result = sql_return_maparray """show grants for '${user1}'""" commonAuth result, "'${user1}'@'%'" as String, "Yes", "admin", "Admin_priv" assertNull(result.CloudClusterPrivs[0]) @@ -113,7 +113,6 @@ suite("test_grant_revoke_cluster_to_user", "cloud_auth") { // 2. grant cluster def cluster1 = "clusterA" - def result sql "sync" @@ -195,7 +194,7 @@ suite("test_grant_revoke_cluster_to_user", "cloud_auth") { sql """GRANT USAGE_PRIV ON CLUSTER '${cluster1}' TO '${user2}'""" sql """GRANT USAGE_PRIV ON CLUSTER '${validCluster}' TO '${user2}'""" - show_cluster_2 = connect("${user2}", 'Cloud12345', context.config.jdbcUrl) { + def show_cluster_2 = connect("${user2}", 'Cloud12345', context.config.jdbcUrl) { getCluster(validCluster) } diff --git a/regression-test/suites/cloud_p0/auth/test_grant_revoke_compute_group_to_user.groovy b/regression-test/suites/cloud_p0/auth/test_grant_revoke_compute_group_to_user.groovy index 09205433a3988e..c74e239159acb0 100644 --- a/regression-test/suites/cloud_p0/auth/test_grant_revoke_compute_group_to_user.groovy +++ b/regression-test/suites/cloud_p0/auth/test_grant_revoke_compute_group_to_user.groovy @@ -73,7 +73,7 @@ suite("test_grant_revoke_compute_group_to_user", "cloud_auth") { // 1. change user // ${user1} admin role logAndExecuteSql """create user ${user1} identified by 'Cloud12345' default role 'admin'""" - result = sql_return_maparray """show grants for '${user1}'""" + def result = sql_return_maparray """show grants for '${user1}'""" commonAuth result, "'${user1}'@'%'" as String, "Yes", "admin", "Admin_priv" assertNull(result.ComputeGroupPrivs[0]) @@ -120,7 +120,6 @@ suite("test_grant_revoke_compute_group_to_user", "cloud_auth") { // 2. grant group def group1 = "groupA" - def result logAndExecuteSql "sync" @@ -202,7 +201,7 @@ suite("test_grant_revoke_compute_group_to_user", "cloud_auth") { logAndExecuteSql """GRANT USAGE_PRIV ON COMPUTE GROUP '${group1}' TO '${user2}'""" logAndExecuteSql """GRANT USAGE_PRIV ON COMPUTE GROUP '${validCluster}' TO '${user2}'""" - show_group_2 = connect("${user2}", 'Cloud12345', context.config.jdbcUrl) { + def show_group_2 = connect("${user2}", 'Cloud12345', context.config.jdbcUrl) { getCluster(validCluster) } diff --git a/regression-test/suites/compaction/test_full_compaction.groovy b/regression-test/suites/compaction/test_full_compaction.groovy index ed2d2ce5bc5e46..b54f92747e6c4e 100644 --- a/regression-test/suites/compaction/test_full_compaction.groovy +++ b/regression-test/suites/compaction/test_full_compaction.groovy @@ -120,7 +120,7 @@ suite("test_full_compaction") { for (def tablet in tablets) { String tablet_id = tablet.TabletId backend_id = tablet.BackendId - times = 1 + def times = 1 do{ (code, out, err) = be_run_full_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) diff --git a/regression-test/suites/compaction/test_full_compaction_ck.groovy b/regression-test/suites/compaction/test_full_compaction_ck.groovy index 8e2f86c596de65..ae6b467acafcb9 100644 --- a/regression-test/suites/compaction/test_full_compaction_ck.groovy +++ b/regression-test/suites/compaction/test_full_compaction_ck.groovy @@ -121,7 +121,7 @@ suite("test_full_compaction_ck") { for (def tablet in tablets) { String tablet_id = tablet.TabletId backend_id = tablet.BackendId - times = 1 + def times = 1 do{ (code, out, err) = be_run_full_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) diff --git a/regression-test/suites/correctness/test_trim_new_parameters.groovy b/regression-test/suites/correctness/test_trim_new_parameters.groovy index 17ac4a0c65eae5..a76ccb96356da9 100644 --- a/regression-test/suites/correctness/test_trim_new_parameters.groovy +++ b/regression-test/suites/correctness/test_trim_new_parameters.groovy @@ -68,6 +68,6 @@ suite("test_trim_new_parameters") { rtrim = sql "select rtrim('bcTTTabcabc','abc')" assertEquals(rtrim[0][0], 'bcTTT') - trim_one = sql "select trim('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaabcTTTabcabcaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','a')" + def trim_one = sql "select trim('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaabcTTTabcabcaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','a')" assertEquals(trim_one[0][0], 'baaaaaaaaaaabcTTTabcabcaaaaaaaaaaaaaaaaaaaaaaaaaab') } diff --git a/regression-test/suites/ddl_p0/test_create_table_generated_column/test_routine_load_generated_column.groovy b/regression-test/suites/ddl_p0/test_create_table_generated_column/test_routine_load_generated_column.groovy index edf8ab2532345a..fa5858176284e4 100644 --- a/regression-test/suites/ddl_p0/test_create_table_generated_column/test_routine_load_generated_column.groovy +++ b/regression-test/suites/ddl_p0/test_create_table_generated_column/test_routine_load_generated_column.groovy @@ -32,7 +32,7 @@ suite("test_routine_load_generated_column") { props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer") props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer") def producer = new KafkaProducer<>(props) - filepath = getLoalFilePath "gen_col_data.csv" + def filepath = getLoalFilePath "gen_col_data.csv" def txt = new File("${filepath}").text def lines = txt.readLines(); lines.each { line -> diff --git a/regression-test/suites/ddl_p0/test_create_table_properties.groovy b/regression-test/suites/ddl_p0/test_create_table_properties.groovy index c6908d80b07cda..32fd0cabcaf8cf 100644 --- a/regression-test/suites/ddl_p0/test_create_table_properties.groovy +++ b/regression-test/suites/ddl_p0/test_create_table_properties.groovy @@ -336,7 +336,7 @@ suite("test_create_table_properties") { ) """ sql """ insert into ${bool_tab} values (1, '2020-12-12 12:12:12', '2000-01-01 12:12:12.123456'), (0, '20201212 121212', '2000-01-01'), (1, '20201212121212', '2000-01-01'), (0, 'AaA', '2000-01-01') """ - result = sql "show partitions from ${bool_tab}" + def result = sql "show partitions from ${bool_tab}" logger.info("${result}") assertEquals(result.size(), 2) diff --git a/regression-test/suites/export/test_array_export.groovy b/regression-test/suites/export/test_array_export.groovy index 4186ee21d9f01a..4ce9786e9972bb 100644 --- a/regression-test/suites/export/test_array_export.groovy +++ b/regression-test/suites/export/test_array_export.groovy @@ -136,7 +136,7 @@ suite("test_array_export", "export") { def check_export_result = {checklabel-> max_try_milli_secs = 15000 while(max_try_milli_secs) { - result = sql "show export where label='${checklabel}'" + def result = sql "show export where label='${checklabel}'" if(result[0][2] == "FINISHED") { break } else { @@ -171,7 +171,7 @@ suite("test_array_export", "export") { } else { throw new IllegalStateException("""${outFilePath} already exists! """) } - result = sql """ + def result = sql """ SELECT * FROM ${tableName} t ORDER BY k1 INTO OUTFILE "file://${outFile}/"; """ def url = result[0][3] @@ -203,7 +203,7 @@ suite("test_array_export", "export") { path.delete(); } if (csvFiles != "") { - cmd = "rm -rf ${csvFiles}" + def cmd = "rm -rf ${csvFiles}" sshExec("root", urlHost, cmd) } } diff --git a/regression-test/suites/export/test_map_export.groovy b/regression-test/suites/export/test_map_export.groovy index fdb207f8628bfd..101ab07ebbe4fd 100644 --- a/regression-test/suites/export/test_map_export.groovy +++ b/regression-test/suites/export/test_map_export.groovy @@ -98,7 +98,7 @@ suite("test_map_export", "export") { def result = sql """ SELECT * FROM ${testTable} ORDER BY id INTO OUTFILE "file://${outFile}/"; """ - url = result[0][3] + def url = result[0][3] urlHost = url.substring(8, url.indexOf("${outFile}")) if (backends.size() > 1) { // custer will scp files @@ -146,7 +146,7 @@ suite("test_map_export", "export") { path.delete(); } if (csvFiles != "") { - cmd = "rm -rf ${csvFiles}" + def cmd = "rm -rf ${csvFiles}" sshExec("root", urlHost, cmd) } } diff --git a/regression-test/suites/export/test_struct_export.groovy b/regression-test/suites/export/test_struct_export.groovy index 8df3a40906e67c..bc3912af39ebaa 100644 --- a/regression-test/suites/export/test_struct_export.groovy +++ b/regression-test/suites/export/test_struct_export.groovy @@ -151,7 +151,7 @@ suite("test_struct_export", "export") { path.delete(); } if (csvFiles != "") { - cmd = "rm -rf ${csvFiles}" + def cmd = "rm -rf ${csvFiles}" sshExec("root", urlHost, cmd) } } diff --git a/regression-test/suites/export_p0/outfile/csv/test_outfile_empty_data.groovy b/regression-test/suites/export_p0/outfile/csv/test_outfile_empty_data.groovy index d8da398ea813bf..d14dc119ddb805 100644 --- a/regression-test/suites/export_p0/outfile/csv/test_outfile_empty_data.groovy +++ b/regression-test/suites/export_p0/outfile/csv/test_outfile_empty_data.groovy @@ -45,7 +45,7 @@ suite("test_outfile_empty_data", "external,hive,tvf,external_docker") { String ak = getS3AK() String sk = getS3SK() String s3_endpoint = getS3Endpoint() - String region = region = getS3Region() + String region = getS3Region() String bucket = context.config.otherConfigs.get("s3BucketName"); // broker @@ -67,8 +67,8 @@ suite("test_outfile_empty_data", "external,hive,tvf,external_docker") { // select ... into outfile ... def uuid = UUID.randomUUID().toString() - hdfs_outfile_path = "/user/doris/tmp_data/${uuid}" - uri = "${defaultFS}" + "${hdfs_outfile_path}/exp_" + def hdfs_outfile_path = "/user/doris/tmp_data/${uuid}" + def uri = "${defaultFS}" + "${hdfs_outfile_path}/exp_" def res = sql """ SELECT * FROM ${export_table_name} t ORDER BY user_id @@ -87,8 +87,8 @@ suite("test_outfile_empty_data", "external,hive,tvf,external_docker") { // select ... into outfile ... def uuid = UUID.randomUUID().toString() - hdfs_outfile_path = "/user/doris/tmp_data/${uuid}" - uri = "${defaultFS}" + "${hdfs_outfile_path}/exp_" + def hdfs_outfile_path = "/user/doris/tmp_data/${uuid}" + def uri = "${defaultFS}" + "${hdfs_outfile_path}/exp_" def res = sql """ SELECT * FROM ${export_table_name} t ORDER BY user_id @@ -106,8 +106,8 @@ suite("test_outfile_empty_data", "external,hive,tvf,external_docker") { def outfile_to_S3_directly = { // select ... into outfile ... - s3_outfile_path = "${bucket}/outfile/csv/test-outfile-empty/" - uri = "s3://${s3_outfile_path}/exp_" + def s3_outfile_path = "${bucket}/outfile/csv/test-outfile-empty/" + def uri = "s3://${s3_outfile_path}/exp_" def res = sql """ SELECT * FROM ${export_table_name} t ORDER BY user_id diff --git a/regression-test/suites/export_p0/outfile/outfile_expr/test_outfile_expr_generate_col_name.groovy b/regression-test/suites/export_p0/outfile/outfile_expr/test_outfile_expr_generate_col_name.groovy index e5a9ec7ea490b3..1d31c64ba7585f 100644 --- a/regression-test/suites/export_p0/outfile/outfile_expr/test_outfile_expr_generate_col_name.groovy +++ b/regression-test/suites/export_p0/outfile/outfile_expr/test_outfile_expr_generate_col_name.groovy @@ -129,7 +129,7 @@ suite("test_outfile_expr_generate_col_name", "p0") { "s3.access_key" = "${ak}" ); """ - outfile_url = res[0][3] + def outfile_url = res[0][3] check_outfile_data(outfile_url, outfile_format) check_outfile_column_name(outfile_url, outfile_format) @@ -150,7 +150,7 @@ suite("test_outfile_expr_generate_col_name", "p0") { "s3.access_key" = "${ak}" ); """ - outfile_url = res[0][3] + def outfile_url = res[0][3] check_outfile_data(outfile_url, outfile_format) check_outfile_column_name(outfile_url, outfile_format) @@ -171,7 +171,7 @@ suite("test_outfile_expr_generate_col_name", "p0") { "s3.access_key" = "${ak}" ); """ - outfile_url = res[0][3] + def outfile_url = res[0][3] check_outfile_data(outfile_url, outfile_format) check_outfile_column_name(outfile_url, outfile_format) @@ -211,7 +211,7 @@ suite("test_outfile_expr_generate_col_name", "p0") { "s3.access_key" = "${ak}" ); """ - outfile_url = res[0][3] + def outfile_url = res[0][3] check_outfile_data(outfile_url, outfile_format) check_outfile_column_name(outfile_url, outfile_format) @@ -235,7 +235,7 @@ suite("test_outfile_expr_generate_col_name", "p0") { "s3.access_key" = "${ak}" ); """ - outfile_url = res[0][3] + def outfile_url = res[0][3] check_outfile_data(outfile_url, outfile_format) check_outfile_column_name(outfile_url, outfile_format) diff --git a/regression-test/suites/export_p0/test_export_basic.groovy b/regression-test/suites/export_p0/test_export_basic.groovy index ca838232e3fdec..152f1ab4e6e9e1 100644 --- a/regression-test/suites/export_p0/test_export_basic.groovy +++ b/regression-test/suites/export_p0/test_export_basic.groovy @@ -414,11 +414,11 @@ suite("test_export_basic", "p0") { } // 5. test order by and limit clause - uuid1 = UUID.randomUUID().toString() + def uuid1 = UUID.randomUUID().toString() outFilePath = """${outfile_path_prefix}_${uuid1}""" - label1 = "label_${uuid1}" - uuid2 = UUID.randomUUID().toString() - label2 = "label_${uuid2}" + def label1 = "label_${uuid1}" + def uuid2 = UUID.randomUUID().toString() + def label2 = "label_${uuid2}" try { // check export path check_path_exists.call("${outFilePath}") diff --git a/regression-test/suites/export_p0/test_outfile_file_suffix.groovy b/regression-test/suites/export_p0/test_outfile_file_suffix.groovy index d7a583824311be..4a453bce28d7ee 100644 --- a/regression-test/suites/export_p0/test_outfile_file_suffix.groovy +++ b/regression-test/suites/export_p0/test_outfile_file_suffix.groovy @@ -42,7 +42,7 @@ suite("test_outfile_file_suffix", "p0") { def outFilePath = """s3://${bucket}/outfile_""" def csv_suffix_result = { file_suffix, file_format -> - result = sql """ + def result = sql """ select * from ${table_name} into outfile "${outFilePath}" FORMAT AS ${file_format} diff --git a/regression-test/suites/export_p0/test_show_create_database.groovy b/regression-test/suites/export_p0/test_show_create_database.groovy index 03f0e8b291cdb5..44e54c46028f6d 100644 --- a/regression-test/suites/export_p0/test_show_create_database.groovy +++ b/regression-test/suites/export_p0/test_show_create_database.groovy @@ -18,7 +18,7 @@ suite("test_show_create_database", "p0,external,hive,external_docker,external_docker_hive") { sql """create database if not exists db_test""" - result = sql """show create database db_test""" + def result = sql """show create database db_test""" assertEquals(result.size(), 1) assertEquals(result[0][1], "CREATE DATABASE `db_test`") diff --git a/regression-test/suites/external_table_p0/cache/test_file_cache_statistics.groovy b/regression-test/suites/external_table_p0/cache/test_file_cache_statistics.groovy index dfceba90cec906..a4796c73d4ed74 100644 --- a/regression-test/suites/external_table_p0/cache/test_file_cache_statistics.groovy +++ b/regression-test/suites/external_table_p0/cache/test_file_cache_statistics.groovy @@ -45,7 +45,7 @@ suite("test_file_cache_statistics", "external_docker,hive,external_docker_hive,p order_qt_2 """select * from ${catalog_name}.${ex_db_name}.parquet_partition_table order by l_orderkey limit 1;""" // brpc metrics will be updated at most 20 seconds Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until{ - result = sql """select METRIC_VALUE from information_schema.file_cache_statistics where METRIC_NAME like "%hits_ratio%" order by METRIC_VALUE limit 1;""" + def result = sql """select METRIC_VALUE from information_schema.file_cache_statistics where METRIC_NAME like "%hits_ratio%" order by METRIC_VALUE limit 1;""" logger.info("result " + result) if (result.size() == 0) { return false; diff --git a/regression-test/suites/external_table_p0/hive/test_autoinc_broker_load.groovy b/regression-test/suites/external_table_p0/hive/test_autoinc_broker_load.groovy index 3171c72b710822..376da31c8a7987 100644 --- a/regression-test/suites/external_table_p0/hive/test_autoinc_broker_load.groovy +++ b/regression-test/suites/external_table_p0/hive/test_autoinc_broker_load.groovy @@ -20,15 +20,15 @@ suite("test_autoinc_broker_load", "p0,external,hive,external_docker,external_doc String enabled = context.config.otherConfigs.get("enableHiveTest") if (enabled != null && enabled.equalsIgnoreCase("true")) { - brokerName = getBrokerName() - hdfsUser = getHdfsUser() - hdfsPasswd = getHdfsPasswd() - hdfs_port = context.config.otherConfigs.get("hive2HdfsPort") - externalEnvIp = context.config.otherConfigs.get("externalEnvIp") + def brokerName = getBrokerName() + def hdfsUser = getHdfsUser() + def hdfsPasswd = getHdfsPasswd() + def hdfs_port = context.config.otherConfigs.get("hive2HdfsPort") + def externalEnvIp = context.config.otherConfigs.get("externalEnvIp") def test_dir = "user/doris/preinstalled_data/data_case/autoinc" - def load_from_hdfs = {columns, testTable, label, testFile, format, brokerName, hdfsUser, hdfsPasswd -> + def load_from_hdfs = {columns, testTable, label, testFile, format -> def result1= sql """ LOAD LABEL ${label} ( DATA INFILE("hdfs://${externalEnvIp}:${hdfs_port}/${test_dir}/${testFile}") INTO TABLE ${testTable} @@ -46,9 +46,9 @@ suite("test_autoinc_broker_load", "p0,external,hive,external_docker,external_doc } def wait_for_load_result = {checklabel, testTable -> - max_try_milli_secs = 10000 + def max_try_milli_secs = 10000 while(max_try_milli_secs) { - result = sql "show load where label = '${checklabel}'" + def result = sql "show load where label = '${checklabel}'" if(result[0][2] == "FINISHED") { break } else { @@ -61,7 +61,7 @@ suite("test_autoinc_broker_load", "p0,external,hive,external_docker,external_doc } } - table = "test_autoinc_broker_load" + def table = "test_autoinc_broker_load" sql "drop table if exists ${table}" sql """ CREATE TABLE IF NOT EXISTS `${table}` ( `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT "用户 ID", @@ -78,7 +78,7 @@ suite("test_autoinc_broker_load", "p0,external,hive,external_docker,external_doc "enable_unique_key_merge_on_write" = "true") """ def test_load_label = UUID.randomUUID().toString().replaceAll("-", "") - load_from_hdfs("name, value", table, test_load_label, "auto_inc_basic.csv", "csv", brokerName, hdfsUser, hdfsPasswd) + load_from_hdfs("name, value", table, test_load_label, "auto_inc_basic.csv", "csv") wait_for_load_result(test_load_label, table) qt_sql "select * from ${table};" sql """ insert into ${table} values(0, "Bob", 123), (2, "Tom", 323), (4, "Carter", 523);""" @@ -102,7 +102,7 @@ suite("test_autoinc_broker_load", "p0,external,hive,external_docker,external_doc "storage_format" = "V2", "enable_unique_key_merge_on_write" = "true");""" test_load_label = UUID.randomUUID().toString().replaceAll("-", "") - load_from_hdfs("id, name, value", table, test_load_label, "auto_inc_with_null.csv", "csv", brokerName, hdfsUser, hdfsPasswd) + load_from_hdfs("id, name, value", table, test_load_label, "auto_inc_with_null.csv", "csv") wait_for_load_result(test_load_label, table) sql "sync" qt_sql "select * from ${table};" diff --git a/regression-test/suites/external_table_p0/hive/test_hive_parquet_alter_column.groovy b/regression-test/suites/external_table_p0/hive/test_hive_parquet_alter_column.groovy index 9020b99c183740..5e3afa8d7fbfdd 100644 --- a/regression-test/suites/external_table_p0/hive/test_hive_parquet_alter_column.groovy +++ b/regression-test/suites/external_table_p0/hive/test_hive_parquet_alter_column.groovy @@ -43,7 +43,7 @@ suite("test_hive_parquet_alter_column", "p0,external,hive,external_docker,extern - types = ["int","smallint","tinyint","bigint","float","double","boolean","string","char","varchar","date","timestamp","decimal"] + def types = ["int","smallint","tinyint","bigint","float","double","boolean","string","char","varchar","date","timestamp","decimal"] for( String type1 in types) { qt_desc """ desc parquet_alter_column_to_${type1} ; """ diff --git a/regression-test/suites/external_table_p0/hive/test_hive_statistic.groovy b/regression-test/suites/external_table_p0/hive/test_hive_statistic.groovy index 5da056ff00ebbc..971e6bc0253ec8 100644 --- a/regression-test/suites/external_table_p0/hive/test_hive_statistic.groovy +++ b/regression-test/suites/external_table_p0/hive/test_hive_statistic.groovy @@ -259,7 +259,7 @@ suite("test_hive_statistic", "p0,external,hive,external_docker,external_docker_h def ctlId def dbId def tblId - result = sql """show catalogs""" + def result = sql """show catalogs""" for (int i = 0; i < result.size(); i++) { if (result[i][1] == catalog_name) { diff --git a/regression-test/suites/external_table_p0/hive/test_partial_update_broker_load.groovy b/regression-test/suites/external_table_p0/hive/test_partial_update_broker_load.groovy index e444bbc24239e5..4b5f6a02b3b111 100644 --- a/regression-test/suites/external_table_p0/hive/test_partial_update_broker_load.groovy +++ b/regression-test/suites/external_table_p0/hive/test_partial_update_broker_load.groovy @@ -20,12 +20,12 @@ suite("test_primary_key_partial_update_broker_load", "p0,external,hive,external_ String enabled = context.config.otherConfigs.get("enableHiveTest") if (enabled != null && enabled.equalsIgnoreCase("true")) { - brokerName = getBrokerName() - hdfsUser = getHdfsUser() - hdfsPasswd = getHdfsPasswd() - hdfs_port = context.config.otherConfigs.get("hive2HdfsPort") - externalEnvIp = context.config.otherConfigs.get("externalEnvIp") - def load_from_hdfs = {testTable, label, hdfsFilePath, format, brokerName, hdfsUser, hdfsPasswd -> + def brokerName = getBrokerName() + def hdfsUser = getHdfsUser() + def hdfsPasswd = getHdfsPasswd() + def hdfs_port = context.config.otherConfigs.get("hive2HdfsPort") + def externalEnvIp = context.config.otherConfigs.get("externalEnvIp") + def load_from_hdfs = {testTable, label, hdfsFilePath, format -> def result1= sql """ LOAD LABEL ${label} ( DATA INFILE("${hdfsFilePath}") @@ -77,13 +77,13 @@ suite("test_primary_key_partial_update_broker_load", "p0,external,hive,external_ sql """insert into ${tableName} values(2, "bob", 2000, 223, 2),(1, "alice", 1000, 123, 1),(3, "tom", 3000, 323, 3);""" qt_sql """ select * from ${tableName} order by id; """ def test_load_label = UUID.randomUUID().toString().replaceAll("-", "") - load_from_hdfs(tableName, test_load_label, "hdfs://${externalEnvIp}:${hdfs_port}/user/doris/preinstalled_data/data_case/partial_update/update.csv", "csv", brokerName, hdfsUser, hdfsPasswd) + load_from_hdfs(tableName, test_load_label, "hdfs://${externalEnvIp}:${hdfs_port}/user/doris/preinstalled_data/data_case/partial_update/update.csv", "csv") wait_for_load_result(test_load_label, tableName) qt_sql """select * from ${tableName} order by id;""" sql "sync;" def test_load_label2 = UUID.randomUUID().toString().replaceAll("-", "") - load_from_hdfs(tableName, test_load_label2, "hdfs://${externalEnvIp}:${hdfs_port}/user/doris/preinstalled_data/data_case/partial_update/update2.csv", "csv", brokerName, hdfsUser, hdfsPasswd) + load_from_hdfs(tableName, test_load_label2, "hdfs://${externalEnvIp}:${hdfs_port}/user/doris/preinstalled_data/data_case/partial_update/update2.csv", "csv") wait_for_load_result(test_load_label2, tableName) qt_sql """select * from ${tableName} order by id;""" sql "drop table if exists ${tableName};" diff --git a/regression-test/suites/external_table_p0/iceberg/test_iceberg_optimize_count.groovy b/regression-test/suites/external_table_p0/iceberg/test_iceberg_optimize_count.groovy index 7a9e90a61fe2cb..556314225c5a81 100644 --- a/regression-test/suites/external_table_p0/iceberg/test_iceberg_optimize_count.groovy +++ b/regression-test/suites/external_table_p0/iceberg/test_iceberg_optimize_count.groovy @@ -42,10 +42,10 @@ suite("test_iceberg_optimize_count", "p0,external,doris,external_docker,external sql """ switch ${catalog_name} """ sql """ use format_v2 """ - sqlstr1 = """ select count(*) from sample_cow_orc; """ - sqlstr2 = """ select count(*) from sample_cow_parquet; """ - sqlstr3 = """ select count(*) from sample_mor_orc; """ - sqlstr4 = """ select count(*) from sample_mor_parquet; """ + def sqlstr1 = """ select count(*) from sample_cow_orc; """ + def sqlstr2 = """ select count(*) from sample_cow_parquet; """ + def sqlstr3 = """ select count(*) from sample_mor_orc; """ + def sqlstr4 = """ select count(*) from sample_mor_parquet; """ // use push down count sql """ set enable_count_push_down_for_external_table=true; """ @@ -99,7 +99,7 @@ suite("test_iceberg_optimize_count", "p0,external,doris,external_docker,external // There has `dangling delete` after rewrite sql """ set enable_count_push_down_for_external_table=true; """ - sqlstr5 = """ select count(*) from ${catalog_name}.test_db.dangling_delete_after_write; """ + def sqlstr5 = """ select count(*) from ${catalog_name}.test_db.dangling_delete_after_write; """ qt_q09 """${sqlstr5}""" diff --git a/regression-test/suites/external_table_p0/iceberg/test_iceberg_predicate_conversion.groovy b/regression-test/suites/external_table_p0/iceberg/test_iceberg_predicate_conversion.groovy index bbca6d8f02352f..c1e2a792e9f208 100644 --- a/regression-test/suites/external_table_p0/iceberg/test_iceberg_predicate_conversion.groovy +++ b/regression-test/suites/external_table_p0/iceberg/test_iceberg_predicate_conversion.groovy @@ -70,7 +70,7 @@ suite("test_iceberg_predicate_conversion", "p0,external,doris,external_docker,ex } sqlstr = """select l_shipdate, l_shipmode from tb_predict where l_shipdate in ("1997-05-18", "1996-05-06") or NOT(l_shipmode = "MAIL") order by l_shipdate, l_shipmode limit 10""" - plan = """(ref(name="l_shipdate") in ("1997-05-18", "1996-05-06") or not(ref(name="l_shipmode") == "MAIL"))""" + def plan = """(ref(name="l_shipdate") in ("1997-05-18", "1996-05-06") or not(ref(name="l_shipmode") == "MAIL"))""" order_qt_q04 """${sqlstr}""" explain { sql("""${sqlstr}""") diff --git a/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_statistics.groovy b/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_statistics.groovy index 617644cda99e8c..6a5fb0222355f4 100644 --- a/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_statistics.groovy +++ b/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_statistics.groovy @@ -38,7 +38,7 @@ suite("test_mysql_jdbc_statistics", "p0,external,mysql,external_docker,external_ sql """use ${catalog_name}.doris_test""" sql """analyze table ex_tb0 with sync""" - result = sql """show column stats ex_tb0 (name)""" + def result = sql """show column stats ex_tb0 (name)""" assertEquals(result.size(), 1) assertEquals(result[0][0], "name") assertEquals(result[0][2], "5.0") diff --git a/regression-test/suites/insert_p0/insert_group_commit_with_exception.groovy b/regression-test/suites/insert_p0/insert_group_commit_with_exception.groovy index e207e71f2cc964..054add11d9f3a3 100644 --- a/regression-test/suites/insert_p0/insert_group_commit_with_exception.groovy +++ b/regression-test/suites/insert_p0/insert_group_commit_with_exception.groovy @@ -78,7 +78,7 @@ suite("insert_group_commit_with_exception") { assertTrue(e.getMessage().contains("Column count doesn't match value count")) } - result = sql """ insert into ${table} values(3, 'c', 30) """ + def result = sql """ insert into ${table} values(3, 'c', 30) """ logger.info("insert result: " + result) // insert into with column @@ -125,7 +125,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(3, 70); ps.setObject(4, "a"); ps.addBatch(); - int[] result = ps.executeBatch(); + result = ps.executeBatch(); assertTrue(false) } catch (Exception e) { assertTrue(e.getMessage().contains("Column count doesn't match value count")) @@ -135,7 +135,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(1, 9); ps.setObject(2, "f"); ps.addBatch(); - int[] result = ps.executeBatch(); + result = ps.executeBatch(); assertTrue(false) } catch (Exception e) { assertTrue(e.getMessage().contains("Column count doesn't match value count")) @@ -146,7 +146,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(2, "f"); ps.setObject(3, 90); ps.addBatch(); - int[] result = ps.executeBatch(); + result = ps.executeBatch(); logger.info("prepare insert result: " + result) } @@ -155,7 +155,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(1, 11); ps.setObject(2, "f"); ps.addBatch(); - int[] result = ps.executeBatch(); + result = ps.executeBatch(); logger.info("prepare insert result: " + result) } @@ -164,7 +164,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(2, "f"); ps.setObject(3, "f"); ps.addBatch(); - int[] result = ps.executeBatch(); + result = ps.executeBatch(); assertTrue(false) } catch (Exception e) { assertTrue(e.getMessage().contains("Column count doesn't match value count")) @@ -173,7 +173,7 @@ suite("insert_group_commit_with_exception") { try (PreparedStatement ps = connection.prepareStatement("insert into ${table}(id, name) values(?)")) { ps.setObject(1, 13); ps.addBatch(); - int[] result = ps.executeBatch(); + result = ps.executeBatch(); assertTrue(false) } catch (Exception e) { assertTrue(e.getMessage().contains("Column count doesn't match value count")) @@ -183,7 +183,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(1, 12); ps.setObject(2, "f"); ps.addBatch(); - int[] result = ps.executeBatch(); + result = ps.executeBatch(); assertTrue(false) } catch (Exception e) { assertTrue(e.getMessage().contains("Unknown column 'names'")) @@ -198,7 +198,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(2, "f"); ps.setObject(3, 90); ps.addBatch(); - int[] result = ps.executeBatch(); + result = ps.executeBatch(); logger.info("prepare insert result: " + result) } } @@ -214,7 +214,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(5, "f"); ps.setObject(6, 90); ps.addBatch(); - int[] result = ps.executeBatch(); + result = ps.executeBatch(); logger.info("prepare insert result: " + result) } } @@ -226,7 +226,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(2, "f") ps.setObject(3, 90) ps.addBatch() - int[] result = ps.executeBatch() + result = ps.executeBatch() logger.info("prepare insert result: " + result) sql """ alter table ${table} ADD column age int after name; """ @@ -252,7 +252,7 @@ suite("insert_group_commit_with_exception") { ps.setObject(2, "f") ps.setObject(3, 90) ps.addBatch() - int[] result = ps.executeBatch() + result = ps.executeBatch() logger.info("prepare insert result: " + result) sql """ alter table ${table} DROP column age; """ diff --git a/regression-test/suites/insert_p0/test_group_commit_interval_ms_property.groovy b/regression-test/suites/insert_p0/test_group_commit_interval_ms_property.groovy index e05acca703aeb7..c42d251ee03540 100644 --- a/regression-test/suites/insert_p0/test_group_commit_interval_ms_property.groovy +++ b/regression-test/suites/insert_p0/test_group_commit_interval_ms_property.groovy @@ -41,7 +41,7 @@ suite("test_group_commit_interval_ms_property") { try { - test_table = table + def test_table = table sql """ drop table if exists ${test_table} force; """ sql """ CREATE table ${test_table} ( diff --git a/regression-test/suites/inverted_index_p0/index_change/test_add_drop_index_on_table_with_mv.groovy b/regression-test/suites/inverted_index_p0/index_change/test_add_drop_index_on_table_with_mv.groovy index 98729dbc91b1ea..d43b0f825f7d13 100644 --- a/regression-test/suites/inverted_index_p0/index_change/test_add_drop_index_on_table_with_mv.groovy +++ b/regression-test/suites/inverted_index_p0/index_change/test_add_drop_index_on_table_with_mv.groovy @@ -104,7 +104,7 @@ suite("test_add_drop_index_on_table_with_mv") { sql """ SHOW ALTER TABLE MATERIALIZED VIEW """ - max_try_secs = 60 + def max_try_secs = 60 while (max_try_secs--) { String res = getJobState(tableName) if (res == "FINISHED" || res == "CANCELLED") { diff --git a/regression-test/suites/inverted_index_p0/index_change/test_pk_uk_index_change.groovy b/regression-test/suites/inverted_index_p0/index_change/test_pk_uk_index_change.groovy index 5fc593d0b4a93a..4e80266ee50a51 100644 --- a/regression-test/suites/inverted_index_p0/index_change/test_pk_uk_index_change.groovy +++ b/regression-test/suites/inverted_index_p0/index_change/test_pk_uk_index_change.groovy @@ -302,7 +302,7 @@ suite("test_pk_uk_index_change", "inverted_index") { """ assertTrue(result0.size()==result1.size()) for (int i = 0; i < result0.size(); ++i) { - for (j = 0; j < result0[0].size(); j++) { + for (int j = 0; j < result0[0].size(); j++) { logger.info("result: " + result0[i][j] + "|" + result1[i][j]) assertTrue(result0[i][j]==result1[i][j]) } diff --git a/regression-test/suites/inverted_index_p0/load/test_spark_load.groovy b/regression-test/suites/inverted_index_p0/load/test_spark_load.groovy index 0fd0ca35627408..488b7c6b35bde7 100644 --- a/regression-test/suites/inverted_index_p0/load/test_spark_load.groovy +++ b/regression-test/suites/inverted_index_p0/load/test_spark_load.groovy @@ -36,9 +36,9 @@ suite("test_spark_load_with_index_p0", "p0") { def yarnAddress = "master:8032" def hdfsAddress = "hdfs://master:9000" def hdfsWorkingDir = "hdfs://master:9000/doris" - brokerName =getBrokerName() - hdfsUser = getHdfsUser() - hdfsPasswd = getHdfsPasswd() + def brokerName =getBrokerName() + def hdfsUser = getHdfsUser() + def hdfsPasswd = getHdfsPasswd() def create_test_table = {testTablex -> def result1 = sql """ diff --git a/regression-test/suites/inverted_index_p0/storage_format/test_schema_change_storage_format.groovy b/regression-test/suites/inverted_index_p0/storage_format/test_schema_change_storage_format.groovy index fbccf0f8a62dea..28e9b03dce30cd 100644 --- a/regression-test/suites/inverted_index_p0/storage_format/test_schema_change_storage_format.groovy +++ b/regression-test/suites/inverted_index_p0/storage_format/test_schema_change_storage_format.groovy @@ -104,7 +104,7 @@ suite("test_local_schema_change_storge_format", "p0") { def backendId_to_backendHttpPort = [:] getBackendIpHttpPort(backendId_to_backendIP, backendId_to_backendHttpPort); - tablets = sql_return_maparray """ show tablets from ${table_name}; """ + def tablets = sql_return_maparray """ show tablets from ${table_name}; """ String tablet_id = tablets[0].TabletId String backend_id = tablets[0].BackendId String ip = backendId_to_backendIP.get(backend_id) diff --git a/regression-test/suites/inverted_index_p0/test_array_contains_with_inverted_index.groovy b/regression-test/suites/inverted_index_p0/test_array_contains_with_inverted_index.groovy index 7b4075fe8a5337..6239f644f9854f 100644 --- a/regression-test/suites/inverted_index_p0/test_array_contains_with_inverted_index.groovy +++ b/regression-test/suites/inverted_index_p0/test_array_contains_with_inverted_index.groovy @@ -67,7 +67,7 @@ suite("test_array_contains_with_inverted_index"){ qt_sql """ select count() from ${indexTblName}""" def param_contains = ["\'s\'", "\'\'", null] - for (i = 0 ; i < param_contains.size(); ++i) { + for (int i = 0 ; i < param_contains.size(); ++i) { def p = param_contains[i] log.info("param: ${p}") order_qt_sql """ select * from tai where array_contains(inventors, ${p}) order by id; """ @@ -84,7 +84,7 @@ suite("test_array_contains_with_inverted_index"){ // test arrays_overlap with inverted index // now if we use inverted index we will not eval exprs def param = [["\'s\'", "\'t\'"], [], null, ["\'s\'", "\'\'", "\'t\'"], ["\'s\'", null, "\'t\'"], [null, "\'\'"], ["\'s\'", null, "\'t\'", "\'\'"]] // null for arrays_overlap will return null which in predicate will lead to return empty set - for (i = 0 ; i < param.size(); ++i) { + for (int i = 0 ; i < param.size(); ++i) { def p = param[i] log.info("param: ${p}") order_qt_sql """ select /*+SET_VAR(enable_common_expr_pushdown = true)*/ * from tai where arrays_overlap(inventors, ${p}) order by id; """ diff --git a/regression-test/suites/inverted_index_p0/test_index_match_select.groovy b/regression-test/suites/inverted_index_p0/test_index_match_select.groovy index c5cfa69fefe8c5..387893e470f1e8 100644 --- a/regression-test/suites/inverted_index_p0/test_index_match_select.groovy +++ b/regression-test/suites/inverted_index_p0/test_index_match_select.groovy @@ -207,7 +207,7 @@ suite("test_index_match_select", "inverted_index_select"){ } // cas2.2 test varchar standard match same term with different way and repeate 5 times - for (test_times = 0; test_times < 5; test_times++) { + for (int test_times = 0; test_times < 5; test_times++) { qt_sql """ select * from ${indexTbName1} where ${varchar_colume3} match_any 'zhang yi' order by name """ qt_sql """ select * from ${indexTbName1} where ${varchar_colume3} match_all "zhang yi" order by name """ qt_sql """ select * from ${indexTbName1} where ${varchar_colume3} match_any '"zhang yi"' order by name """ @@ -217,7 +217,7 @@ suite("test_index_match_select", "inverted_index_select"){ } // case3: test char standard match same term with different way and repeate 5 times - for (test_times = 0; test_times < 5; test_times++) { + for (int test_times = 0; test_times < 5; test_times++) { qt_sql """ select * from ${indexTbName1} where ${char_colume1} match_any 'tall:100cm, weight: 30kg, hobbies:' order by name """ qt_sql """ select * from ${indexTbName1} where ${char_colume1} match_all "tall:100cm, weight: 30kg, hobbies:" order by name """ qt_sql """ select * from ${indexTbName1} where ${char_colume1} match_any '"tall:100cm, weight: 30kg, hobbies:"' order by name """ @@ -227,7 +227,7 @@ suite("test_index_match_select", "inverted_index_select"){ } // case4: test string simple match same term with different way and repeate 5 times - for (test_times = 0; test_times < 5; test_times++) { + for (int test_times = 0; test_times < 5; test_times++) { qt_sql """ select * from ${indexTbName1} where ${string_colume1} match_all 'A naughty boy' order by name """ qt_sql """ select * from ${indexTbName1} where ${string_colume1} match_any "A naughty boy" order by name """ qt_sql """ select * from ${indexTbName1} where ${string_colume1} match_any '"A naughty boy"' order by name """ @@ -236,7 +236,7 @@ suite("test_index_match_select", "inverted_index_select"){ } // case5: test text standard match same term with different way and repeate 5 times - for (test_times = 0; test_times < 5; test_times++) { + for (int test_times = 0; test_times < 5; test_times++) { qt_sql """ select * from ${indexTbName1} where ${text_colume1} match_all 'i just want go outside' order by name """ qt_sql """ select * from ${indexTbName1} where ${text_colume1} match_any "i just want go outside" order by name """ qt_sql """ select * from ${indexTbName1} where ${text_colume1} match_all '"i just want go outside"' order by name """ diff --git a/regression-test/suites/inverted_index_p0/unique_with_mow/test_primary_key_simple_case.groovy b/regression-test/suites/inverted_index_p0/unique_with_mow/test_primary_key_simple_case.groovy index 8884ff837a641a..0c437e4fe1b50f 100644 --- a/regression-test/suites/inverted_index_p0/unique_with_mow/test_primary_key_simple_case.groovy +++ b/regression-test/suites/inverted_index_p0/unique_with_mow/test_primary_key_simple_case.groovy @@ -68,7 +68,7 @@ suite("test_primary_key_simple_case", "inverted_index") { """ sql """ set enable_common_expr_pushdown = true """ - result = sql """ SELECT * FROM ${tableName} t ORDER BY user_id; """ + def result = sql """ SELECT * FROM ${tableName} t ORDER BY user_id; """ assertTrue(result.size() == 5) assertTrue(result[0].size() == 11) diff --git a/regression-test/suites/load_p0/http_stream/test_http_stream_2pc.groovy b/regression-test/suites/load_p0/http_stream/test_http_stream_2pc.groovy index b05ce6c42b81c9..bc07d65eccefca 100644 --- a/regression-test/suites/load_p0/http_stream/test_http_stream_2pc.groovy +++ b/regression-test/suites/load_p0/http_stream/test_http_stream_2pc.groovy @@ -65,16 +65,16 @@ suite("test_http_stream_2pc", "p0") { log.info("http_stream execute 2pc: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text - json2pc = parseJson(out) + def code = process.waitFor() + def out = process.text + def json2pc = parseJson(out) log.info("http_stream 2pc result: ${out}".toString()) assertEquals(code, 0) assertEquals("success", json2pc.status.toLowerCase()) def count = 0 while (true) { - res = sql "select count(*) from ${tableName1}" + def res = sql "select count(*) from ${tableName1}" if (res[0][0] > 0) { break } diff --git a/regression-test/suites/load_p0/insert/test_insert_random_distribution_table.groovy b/regression-test/suites/load_p0/insert/test_insert_random_distribution_table.groovy index f9e456b5d3c801..9510a4f7980864 100644 --- a/regression-test/suites/load_p0/insert/test_insert_random_distribution_table.groovy +++ b/regression-test/suites/load_p0/insert/test_insert_random_distribution_table.groovy @@ -151,7 +151,7 @@ suite("test_insert_random_distribution_table", "p0") { res = sql "show tablets from ${tableName} partition ${partitions[p]}" partitionTablets[p] = getTablets.call(res) partitionRowCounts[p] = [] - numTablets = partitionTablets[p].size() + def numTablets = partitionTablets[p].size() for (int i = numTablets - 1; i >= 0; i--) { def countResult = sql "select count() from ${tableName} tablet(${partitionTablets[p][i]})" partitionRowCounts[p][i] = countResult[0][0] @@ -191,7 +191,7 @@ suite("test_insert_random_distribution_table", "p0") { for (int p = 0; p < 3; p++) { - numTablets = partitionTablets[p].size() + def numTablets = partitionTablets[p].size() for (int i = numTablets - 1; i >= 0; i--) { def countResult = sql "select count() from ${tableName} tablet(${partitionTablets[p][i]})" partitionRowCounts[p][i] = countResult[0][0] diff --git a/regression-test/suites/load_p0/mysql_load/test_mysql_load.groovy b/regression-test/suites/load_p0/mysql_load/test_mysql_load.groovy index 9eb948bf55a098..2b5a9537b2ff33 100644 --- a/regression-test/suites/load_p0/mysql_load/test_mysql_load.groovy +++ b/regression-test/suites/load_p0/mysql_load/test_mysql_load.groovy @@ -116,7 +116,7 @@ suite("test_mysql_load", "p0") { """ sql "sync" - rowCount = sql "select count(1) from ${tableName}" + def rowCount = sql "select count(1) from ${tableName}" assertEquals(3, rowCount[0][0]) diff --git a/regression-test/suites/load_p0/routine_load/test_routine_load_alter.groovy b/regression-test/suites/load_p0/routine_load/test_routine_load_alter.groovy index e1cfa4ae9aaefc..0089aff61e56b4 100644 --- a/regression-test/suites/load_p0/routine_load/test_routine_load_alter.groovy +++ b/regression-test/suites/load_p0/routine_load/test_routine_load_alter.groovy @@ -89,7 +89,7 @@ suite("test_routine_load_alter","p0") { def count = 0 while (true) { - res = sql "select count(*) from ${tableName}" + def res = sql "select count(*) from ${tableName}" def state = sql "show routine load for ${jobName}" log.info("routine load state: ${state[0][8].toString()}".toString()) log.info("routine load statistic: ${state[0][14].toString()}".toString()) @@ -131,7 +131,7 @@ suite("test_routine_load_alter","p0") { count = 0 while (true) { - res = sql "select count(*) from ${tableName}" + def res = sql "select count(*) from ${tableName}" log.info("count: ${res[0][0]}".toString()) def state = sql "show routine load for ${jobName}" log.info("routine load state: ${state[0][8].toString()}".toString()) diff --git a/regression-test/suites/load_p0/routine_load/test_routine_load_with_udf.groovy b/regression-test/suites/load_p0/routine_load/test_routine_load_with_udf.groovy index 11a562ba9d4660..9f4ae866e992e5 100644 --- a/regression-test/suites/load_p0/routine_load/test_routine_load_with_udf.groovy +++ b/regression-test/suites/load_p0/routine_load/test_routine_load_with_udf.groovy @@ -102,7 +102,7 @@ suite("test_routine_load_with_udf","p0") { def count = 0 while (true) { - res = sql "select count(*) from ${tableName}" + def res = sql "select count(*) from ${tableName}" def state = sql "show routine load for test_udf_load" log.info("routine load state: ${state[0][8].toString()}".toString()) log.info("routine load statistic: ${state[0][14].toString()}".toString()) diff --git a/regression-test/suites/load_p0/stream_load/test_get_stream_load_state.groovy b/regression-test/suites/load_p0/stream_load/test_get_stream_load_state.groovy index 783aa8b492cda5..7bba1394bf38aa 100644 --- a/regression-test/suites/load_p0/stream_load/test_get_stream_load_state.groovy +++ b/regression-test/suites/load_p0/stream_load/test_get_stream_load_state.groovy @@ -60,9 +60,9 @@ suite("test_get_stream_load_state", "p0") { def command = "curl --location-trusted -u ${context.config.feHttpUser}:${context.config.feHttpPassword} http://${context.config.feHttpAddress}/api/${db}/get_load_state?label=${label}" log.info("test_get_stream_load_state: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text - json = parseJson(out) + def code = process.waitFor() + def out = process.text + def json = parseJson(out) log.info("test_get_stream_load_state: ${out}".toString()) assertEquals("success", json.msg.toLowerCase()) assertEquals("VISIBLE", json.data) diff --git a/regression-test/suites/load_p0/stream_load/test_group_commit_stream_load_with_nonexist_db_and_table.groovy b/regression-test/suites/load_p0/stream_load/test_group_commit_stream_load_with_nonexist_db_and_table.groovy index 57054b2a42088a..8fd638147152c5 100644 --- a/regression-test/suites/load_p0/stream_load/test_group_commit_stream_load_with_nonexist_db_and_table.groovy +++ b/regression-test/suites/load_p0/stream_load/test_group_commit_stream_load_with_nonexist_db_and_table.groovy @@ -28,13 +28,13 @@ suite("test_group_commit_stream_load_with_nonexist_db_and_table") { log.info("stream load command: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text + def code = process.waitFor() + def out = process.text log.info("stream lad result: ${out}".toString()) assertTrue(out.toString().contains("OlapTable not found")) } catch (Exception e) { logger.info("failed: " + e.getMessage()) - assertTrue(false) + throw e } finally { } diff --git a/regression-test/suites/load_p0/stream_load/test_map_load_and_compaction.groovy b/regression-test/suites/load_p0/stream_load/test_map_load_and_compaction.groovy index 703f5dde345587..fd22c12afaf545 100644 --- a/regression-test/suites/load_p0/stream_load/test_map_load_and_compaction.groovy +++ b/regression-test/suites/load_p0/stream_load/test_map_load_and_compaction.groovy @@ -117,6 +117,8 @@ suite("test_map_load_and_compaction", "p0") { def compactJson = parseJson(out.trim()) assertEquals("success", compactJson.status.toLowerCase()) + def running = false + // wait compactions done do { Thread.sleep(1000) @@ -131,7 +133,7 @@ suite("test_map_load_and_compaction", "p0") { checkCompactionStatus.call(compactionStatus, 1) // finally check backend alive - backends = sql """ show backends; """ + def backends = sql """ show backends; """ assertTrue(backends.size() > 0) for (String[] b : backends) { assertEquals("true", b[9]) diff --git a/regression-test/suites/load_p0/stream_load/test_stream_load.groovy b/regression-test/suites/load_p0/stream_load/test_stream_load.groovy index 9783f178c3a2ad..54731a949584be 100644 --- a/regression-test/suites/load_p0/stream_load/test_stream_load.groovy +++ b/regression-test/suites/load_p0/stream_load/test_stream_load.groovy @@ -178,7 +178,7 @@ suite("test_stream_load", "p0") { } sql "sync" - rowCount = sql "select count(1) from ${tableName}" + def rowCount = sql "select count(1) from ${tableName}" assertEquals(3, rowCount[0][0]) // test load_nullable_to_not_nullable @@ -1344,9 +1344,9 @@ suite("test_stream_load", "p0") { def command = "curl --location-trusted -u ${context.config.feHttpUser}:${context.config.feHttpPassword} -H column_separator:| -H Transfer-Encoding:chunked -H columns:k1,k2,v1,v2,v3 -T ${context.dataPath}/test_chunked_transfer.csv http://${context.config.feHttpAddress}/api/${db}/${tableName16}/_stream_load" log.info("test chunked transfer command: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text - json2pc = parseJson(out) + def code = process.waitFor() + def out = process.text + def json2pc = parseJson(out) log.info("test chunked transfer result: ${out}".toString()) sql "sync" qt_sql_chunked_transfer_csv "select * from ${tableName16} order by k1" @@ -1372,9 +1372,9 @@ suite("test_stream_load", "p0") { def command = "curl --location-trusted -u ${context.config.feHttpUser}:${context.config.feHttpPassword} -H Transfer-Encoding:chunked -H format:json -H read_json_by_line:true -T ${context.dataPath}/test_chunked_transfer.json http://${context.config.feHttpAddress}/api/${db}/${tableName16}/_stream_load" log.info("test chunked transfer command: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text - json2pc = parseJson(out) + def code = process.waitFor() + def out = process.text + def json2pc = parseJson(out) log.info("test chunked transfer result: ${out}".toString()) sql "sync" qt_sql_chunked_transfer_json "select * from ${tableName16} order by k1" @@ -1652,8 +1652,8 @@ suite("test_stream_load", "p0") { def command = "curl --location-trusted -u ${context.config.feHttpUser}:${context.config.feHttpPassword} -H column_separator:| -H ${db}:${tableName16} -H Content-Length:0 -H Transfer-Encoding:chunked -H columns:k1,k2,v1,v2,v3 -T ${context.dataPath}/test_chunked_transfer.csv http://${beHost}:${beHttpPort}/api/${db}/${tableName16}/_stream_load" log.info("test chunked transfer command: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text + def code = process.waitFor() + def out = process.text log.info("test chunked transfer result: ${out}".toString()) def json = parseJson(out) assertEquals("fail", json.Status.toLowerCase()) @@ -1682,8 +1682,8 @@ suite("test_stream_load", "p0") { def command = "curl --location-trusted -u ${context.config.feHttpUser}:${context.config.feHttpPassword} -H column_separator:| -H ${db}:${tableName16} -H Content-Length: -H Transfer-Encoding: -T ${context.dataPath}/test_chunked_transfer.csv http://${beHost}:${beHttpPort}/api/${db}/${tableName16}/_stream_load" log.info("test chunked transfer command: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text + def code = process.waitFor() + def out = process.text log.info("test chunked transfer result: ${out}".toString()) def json = parseJson(out) assertEquals("fail", json.Status.toLowerCase()) diff --git a/regression-test/suites/load_p0/stream_load/test_stream_load_2pc.groovy b/regression-test/suites/load_p0/stream_load/test_stream_load_2pc.groovy index a193a3f503db6f..ec51c76a62a986 100644 --- a/regression-test/suites/load_p0/stream_load/test_stream_load_2pc.groovy +++ b/regression-test/suites/load_p0/stream_load/test_stream_load_2pc.groovy @@ -346,8 +346,8 @@ suite("test_stream_load_2pc", "p0") { log.info("http_stream execute 2pc: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text + def code = process.waitFor() + def out = process.text log.info("http_stream 2pc result: ${out}".toString()) def json2pc = parseJson(out) return json2pc @@ -361,8 +361,8 @@ suite("test_stream_load_2pc", "p0") { log.info("http_stream execute 2pc: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text + def code = process.waitFor() + def out = process.text log.info("http_stream 2pc result: ${out}".toString()) def json2pc = parseJson(out) return json2pc @@ -522,7 +522,7 @@ suite("test_stream_load_2pc", "p0") { def count = 0 while (true) { - res = sql "select count(*) from ${tbl}" + def res = sql "select count(*) from ${tbl}" if (res[0][0] > 0) { break } diff --git a/regression-test/suites/load_p0/stream_load/test_stream_load_2pc_with_schema_change.groovy b/regression-test/suites/load_p0/stream_load/test_stream_load_2pc_with_schema_change.groovy index 8695101be62ea1..17104133f7d9f8 100644 --- a/regression-test/suites/load_p0/stream_load/test_stream_load_2pc_with_schema_change.groovy +++ b/regression-test/suites/load_p0/stream_load/test_stream_load_2pc_with_schema_change.groovy @@ -30,8 +30,8 @@ suite("test_stream_load_2pc_with_schema_change", "p0") { log.info("http_stream execute 2pc: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text + def code = process.waitFor() + def out = process.text log.info("http_stream 2pc result: ${out}".toString()) def json2pc = parseJson(out) return json2pc @@ -84,7 +84,7 @@ suite("test_stream_load_2pc_with_schema_change", "p0") { Thread.sleep(5000) // 5s - json2pc = do_streamload_2pc_commit_by_txn_id.call(txnId) + def json2pc = do_streamload_2pc_commit_by_txn_id.call(txnId) assertEquals("success", json2pc.status.toLowerCase()) waitForSchemaChangeDone { diff --git a/regression-test/suites/load_p0/stream_load/test_stream_load_move_memtable.groovy b/regression-test/suites/load_p0/stream_load/test_stream_load_move_memtable.groovy index 7244cd24f4ac47..bbd532a76259cc 100644 --- a/regression-test/suites/load_p0/stream_load/test_stream_load_move_memtable.groovy +++ b/regression-test/suites/load_p0/stream_load/test_stream_load_move_memtable.groovy @@ -185,7 +185,7 @@ suite("test_stream_load_move_memtable", "p0") { } sql "sync" - rowCount = sql "select count(1) from ${tableName}" + def rowCount = sql "select count(1) from ${tableName}" assertEquals(3, rowCount[0][0]) // test load_nullable_to_not_nullable diff --git a/regression-test/suites/manager/test_manager_interface_2.groovy b/regression-test/suites/manager/test_manager_interface_2.groovy index 9c53941c157392..1270d77be5572a 100644 --- a/regression-test/suites/manager/test_manager_interface_2.groovy +++ b/regression-test/suites/manager/test_manager_interface_2.groovy @@ -44,7 +44,7 @@ suite('test_manager_interface_2',"p0") { );""" - result =sql """ show data """ + def result =sql """ show data """ for(int i = 0 ; i < result.size();i++) { assert(result[i][0].toLowerCase() != "null") //TableName assert(result[i][1].toLowerCase() != "null") //Size @@ -183,7 +183,7 @@ suite('test_manager_interface_2',"p0") { sql """ALTER SYSTEM ADD BACKEND "${address}:${notExistPort}";""" - result = sql """SHOW BACKENDS;""" + def result = sql """SHOW BACKENDS;""" logger.info("result = ${result}" ) def x = 0 for(int i =0 ;i sql "DROP TABLE IF EXISTS ${table_name}" - value_type = "v string" + def value_type = "v string" if ("${key_type}" == "AGGREGATE") { value_type = "v string REPLACE_IF_NOT_NULL NULL" } diff --git a/regression-test/suites/query_profile/s3_load_profile_test.groovy b/regression-test/suites/query_profile/s3_load_profile_test.groovy index b0b1c357beb487..be4f38cfdbce7a 100644 --- a/regression-test/suites/query_profile/s3_load_profile_test.groovy +++ b/regression-test/suites/query_profile/s3_load_profile_test.groovy @@ -171,7 +171,7 @@ PROPERTIES ( qt_select """ select count(*) from $loadAttribute.dataDesc.tableName """ def profileString = getProfile(jobId) - profileJson = new JsonSlurper().parseText(profileString) + def profileJson = new JsonSlurper().parseText(profileString) assertEquals(0, profileJson.code) profileDataString = profileJson.data logger.info("profileDataString:" + profileDataString) diff --git a/regression-test/suites/rollup/test_materialized_view_bitmap.groovy b/regression-test/suites/rollup/test_materialized_view_bitmap.groovy index 25403a6db1cae4..fd2e7fe824fdc6 100644 --- a/regression-test/suites/rollup/test_materialized_view_bitmap.groovy +++ b/regression-test/suites/rollup/test_materialized_view_bitmap.groovy @@ -37,7 +37,7 @@ suite("test_materialized_view_bitmap", "rollup") { """ sql "CREATE MATERIALIZED VIEW test_neg as select k1,bitmap_union(to_bitmap(k2)), bitmap_union(to_bitmap(k3)) FROM ${tbName1} GROUP BY k1;" - max_try_secs = 60 + def max_try_secs = 60 Awaitility.await().atMost(max_try_secs, SECONDS).pollInterval(2, SECONDS).until{ String res = getJobState(tbName1) if (res == "FINISHED" || res == "CANCELLED") { diff --git a/regression-test/suites/rollup/test_materialized_view_hll.groovy b/regression-test/suites/rollup/test_materialized_view_hll.groovy index 1d186cbbd5f4ae..59dd2c82fbfd19 100644 --- a/regression-test/suites/rollup/test_materialized_view_hll.groovy +++ b/regression-test/suites/rollup/test_materialized_view_hll.groovy @@ -39,7 +39,7 @@ suite("test_materialized_view_hll", "rollup") { """ sql "CREATE materialized VIEW amt_count AS SELECT store_id, hll_union(hll_hash(sale_amt)) FROM ${tbName1} GROUP BY store_id;" - max_try_secs = 60 + def max_try_secs = 60 Awaitility.await().atMost(max_try_secs, SECONDS).pollInterval(2, SECONDS).until{ String res = getJobState(tbName1) if (res == "FINISHED" || res == "CANCELLED") { diff --git a/regression-test/suites/rollup/test_materialized_view_hll_with_light_sc.groovy b/regression-test/suites/rollup/test_materialized_view_hll_with_light_sc.groovy index 2d14df30d6db90..2e72408ecb3c08 100644 --- a/regression-test/suites/rollup/test_materialized_view_hll_with_light_sc.groovy +++ b/regression-test/suites/rollup/test_materialized_view_hll_with_light_sc.groovy @@ -39,7 +39,7 @@ suite("test_materialized_view_hll_with_light_sc", "rollup") { """ sql "CREATE materialized VIEW amt_count1 AS SELECT store_id, hll_union(hll_hash(sale_amt)) FROM ${tbName1} GROUP BY store_id;" - max_try_secs = 60 + def max_try_secs = 60 Awaitility.await().atMost(max_try_secs, SECONDS).pollInterval(2, SECONDS).until{ String res = getJobState(tbName1) if (res == "FINISHED" || res == "CANCELLED") { diff --git a/regression-test/suites/schema_change_p0/test_agg_keys_schema_change.groovy b/regression-test/suites/schema_change_p0/test_agg_keys_schema_change.groovy index 2672db7c751f88..13063ad34dc9db 100644 --- a/regression-test/suites/schema_change_p0/test_agg_keys_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_agg_keys_schema_change.groovy @@ -176,9 +176,9 @@ suite ("test_agg_keys_schema_change") { String[][] tablets = sql """ show tablets from ${tableName}; """ for (String[] tablet in tablets) { String tablet_id = tablet[0] - backend_id = tablet[2] + def backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) } @@ -188,8 +188,8 @@ suite ("test_agg_keys_schema_change") { do { Thread.sleep(100) String tablet_id = tablet[0] - backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def backend_id = tablet[2] + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_agg_mv_schema_change.groovy b/regression-test/suites/schema_change_p0/test_agg_mv_schema_change.groovy index 2e68bd7608162e..ed6e31e5f6a88f 100644 --- a/regression-test/suites/schema_change_p0/test_agg_mv_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_agg_mv_schema_change.groovy @@ -151,9 +151,9 @@ suite ("test_agg_mv_schema_change") { String[][] tablets = sql """ show tablets from ${tableName}; """ for (String[] tablet in tablets) { String tablet_id = tablet[0] - backend_id = tablet[2] + def backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -164,8 +164,8 @@ suite ("test_agg_mv_schema_change") { do { Thread.sleep(100) String tablet_id = tablet[0] - backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def backend_id = tablet[2] + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_agg_rollup_schema_change.groovy b/regression-test/suites/schema_change_p0/test_agg_rollup_schema_change.groovy index 9302133295cf90..719082e79bb054 100644 --- a/regression-test/suites/schema_change_p0/test_agg_rollup_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_agg_rollup_schema_change.groovy @@ -111,7 +111,7 @@ suite ("test_agg_rollup_schema_change") { ALTER TABLE ${tableName} DROP COLUMN cost """ - max_try_time = 3000 + def max_try_time = 3000 while (max_try_time--){ String result = getJobState(tableName) if (result == "FINISHED") { @@ -159,9 +159,9 @@ suite ("test_agg_rollup_schema_change") { String[][] tablets = sql """ show tablets from ${tableName}; """ for (String[] tablet in tablets) { String tablet_id = tablet[0] - backend_id = tablet[2] + def backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -172,8 +172,8 @@ suite ("test_agg_rollup_schema_change") { do { Thread.sleep(100) String tablet_id = tablet[0] - backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def backend_id = tablet[2] + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_agg_schema_key_change_modify1.groovy b/regression-test/suites/schema_change_p0/test_agg_schema_key_change_modify1.groovy index 78d203c4f738d6..f6d1fdb4222382 100644 --- a/regression-test/suites/schema_change_p0/test_agg_schema_key_change_modify1.groovy +++ b/regression-test/suites/schema_change_p0/test_agg_schema_key_change_modify1.groovy @@ -84,7 +84,7 @@ suite("test_agg_schema_key_change_modify1","p0") { " (789012345, 'Grace', 2123483141, 'Xian', 29, 0, 13333333333, 'No. 222 Street, Xian', '2022-07-07 22:00:00');" //TODO Test the agg model by modify a key type from LARGEINT to BOOLEAN - errorMessage = "errCode = 2, detailMessage = Can not change LARGEINT to BOOLEAN" + def errorMessage = "errCode = 2, detailMessage = Can not change LARGEINT to BOOLEAN" expectException({ sql initTable sql initTableData @@ -219,7 +219,7 @@ suite("test_agg_schema_key_change_modify1","p0") { }, insertSql, false, "${tbName1}") sql """ DROP TABLE IF EXISTS ${tbName2} """ - initTable2 = " CREATE TABLE IF NOT EXISTS ${tbName2}\n" + + def initTable2 = " CREATE TABLE IF NOT EXISTS ${tbName2}\n" + " (\n" + " `user_id` LARGEINT NOT NULL COMMENT \"用户id\",\n" + " `username` VARCHAR(50) NOT NULL COMMENT \"用户昵称\",\n" + @@ -237,7 +237,7 @@ suite("test_agg_schema_key_change_modify1","p0") { " \"replication_allocation\" = \"tag.location.default: 1\"\n" + " );" - initTableData2 = "insert into ${tbName2} values(123456789, 'Alice', 2147483641, 'Beijing', 25, 0, 13812345678, 'No. 123 Street, Beijing', '2022-01-01 10:00:00')," + + def initTableData2 = "insert into ${tbName2} values(123456789, 'Alice', 2147483641, 'Beijing', 25, 0, 13812345678, 'No. 123 Street, Beijing', '2022-01-01 10:00:00')," + " (234567890, 'Bob', 214748364, 'Shanghai', 30, 1, 13998765432, 'No. 456 Street, Shanghai', '2022-02-02 12:00:00')," + " (345678901, 'Carol', 2147483441, 'Guangzhou', 28, 0, 13724681357, 'No. 789 Street, Guangzhou', '2022-03-03 14:00:00')," + " (456789012, 'Dave', 2147483141, 'Shenzhen', 35, 1, 13680864279, 'No. 987 Street, Shenzhen', '2022-04-04 16:00:00')," + diff --git a/regression-test/suites/schema_change_p0/test_agg_vals_schema_change.groovy b/regression-test/suites/schema_change_p0/test_agg_vals_schema_change.groovy index 477ea202e4c38e..211bdaefe3c766 100644 --- a/regression-test/suites/schema_change_p0/test_agg_vals_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_agg_vals_schema_change.groovy @@ -139,7 +139,7 @@ suite ("test_agg_vals_schema_change") { String[][] tablets = sql """ show tablets from ${tableName}; """ for (String[] tablet in tablets) { String tablet_id = tablet[0] - backend_id = tablet[2] + def backend_id = tablet[2] logger.info("run compaction:" + tablet_id) def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) @@ -152,7 +152,7 @@ suite ("test_agg_vals_schema_change") { do { Thread.sleep(100) String tablet_id = tablet[0] - backend_id = tablet[2] + def backend_id = tablet[2] def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) diff --git a/regression-test/suites/schema_change_p0/test_alter_uniq_null.groovy b/regression-test/suites/schema_change_p0/test_alter_uniq_null.groovy index fcedf4c2fa46de..6ef5039b00e4a0 100644 --- a/regression-test/suites/schema_change_p0/test_alter_uniq_null.groovy +++ b/regression-test/suites/schema_change_p0/test_alter_uniq_null.groovy @@ -52,7 +52,7 @@ suite("test_alter_uniq_null") { sql """alter table ${tableName} modify column `v2` INT NULL""" sleep(10) - max_try_num = 1000 + def max_try_num = 1000 while (max_try_num--) { String res = getJobState(tableName) if (res == "FINISHED" || res == "CANCELLED") { diff --git a/regression-test/suites/schema_change_p0/test_dup_keys_schema_change.groovy b/regression-test/suites/schema_change_p0/test_dup_keys_schema_change.groovy index 19b1c96ce4b1f2..044eaf62258be7 100644 --- a/regression-test/suites/schema_change_p0/test_dup_keys_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_dup_keys_schema_change.groovy @@ -142,9 +142,9 @@ suite ("test_dup_keys_schema_change") { String[][] tablets = sql """ show tablets from ${tableName}; """ for (String[] tablet in tablets) { String tablet_id = tablet[0] - backend_id = tablet[2] + def backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -153,8 +153,8 @@ suite ("test_dup_keys_schema_change") { for (String[] tablet in tablets) { Awaitility.await().untilAsserted(() -> { String tablet_id = tablet[0] - backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def backend_id = tablet[2] + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_dup_mv_schema_change.groovy b/regression-test/suites/schema_change_p0/test_dup_mv_schema_change.groovy index 2896470e2a9d83..7c3ea7703272bb 100644 --- a/regression-test/suites/schema_change_p0/test_dup_mv_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_dup_mv_schema_change.groovy @@ -154,7 +154,7 @@ suite ("test_dup_mv_schema_change") { String tablet_id = tablet[0] backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -164,7 +164,7 @@ suite ("test_dup_mv_schema_change") { Awaitility.await().untilAsserted(() -> { String tablet_id = tablet[0] backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_dup_rollup_schema_change.groovy b/regression-test/suites/schema_change_p0/test_dup_rollup_schema_change.groovy index b97f8c78b6fcae..7f55b7fcd16e2c 100644 --- a/regression-test/suites/schema_change_p0/test_dup_rollup_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_dup_rollup_schema_change.groovy @@ -125,7 +125,7 @@ suite ("test_dup_rollup_schema_change") { sql """ ALTER TABLE ${tableName} DROP COLUMN sex """ - max_try_time = 3000 + def max_try_time = 3000 while (max_try_time--){ String result = getJobState(tableName) if (result == "FINISHED") { @@ -172,7 +172,7 @@ suite ("test_dup_rollup_schema_change") { String tablet_id = tablet[0] backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -182,7 +182,7 @@ suite ("test_dup_rollup_schema_change") { Awaitility.await().untilAsserted(() -> { String tablet_id = tablet[0] backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_dup_schema_key_change_modify1.groovy b/regression-test/suites/schema_change_p0/test_dup_schema_key_change_modify1.groovy index 74a5c1f86d8bbf..4683b735faa3a2 100644 --- a/regression-test/suites/schema_change_p0/test_dup_schema_key_change_modify1.groovy +++ b/regression-test/suites/schema_change_p0/test_dup_schema_key_change_modify1.groovy @@ -83,7 +83,7 @@ suite("test_dup_schema_key_change_modify1","p0") { " (789012345, 'Grace', 2123483141, 'Xian', 29, 0, 13333333333, 'No. 222 Street, Xian', '2022-07-07 22:00:00');" //TODO Test the dup model by modify a key type from LARGEINT to BOOLEAN - errorMessage = "errCode = 2, detailMessage = Can not change LARGEINT to BOOLEAN" + def errorMessage = "errCode = 2, detailMessage = Can not change LARGEINT to BOOLEAN" expectException({ sql initTable sql initTableData @@ -218,7 +218,7 @@ suite("test_dup_schema_key_change_modify1","p0") { }, insertSql, false, "${tbName1}") sql """ DROP TABLE IF EXISTS ${tbName2} """ - initTable2 = " CREATE TABLE IF NOT EXISTS ${tbName2}\n" + + def initTable2 = " CREATE TABLE IF NOT EXISTS ${tbName2}\n" + " (\n" + " `user_id` LARGEINT NOT NULL COMMENT \"用户id\",\n" + " `username` VARCHAR(50) NOT NULL COMMENT \"用户昵称\",\n" + @@ -236,7 +236,7 @@ suite("test_dup_schema_key_change_modify1","p0") { " \"replication_allocation\" = \"tag.location.default: 1\"\n" + " );" - initTableData2 = "insert into ${tbName2} values(123456789, 'Alice', 2147483641, 'Beijing', 25, 0, 13812345678, 'No. 123 Street, Beijing', '2022-01-01 10:00:00')," + + def initTableData2 = "insert into ${tbName2} values(123456789, 'Alice', 2147483641, 'Beijing', 25, 0, 13812345678, 'No. 123 Street, Beijing', '2022-01-01 10:00:00')," + " (234567890, 'Bob', 214748364, 'Shanghai', 30, 1, 13998765432, 'No. 456 Street, Shanghai', '2022-02-02 12:00:00')," + " (345678901, 'Carol', 2147483441, 'Guangzhou', 28, 0, 13724681357, 'No. 789 Street, Guangzhou', '2022-03-03 14:00:00')," + " (456789012, 'Dave', 2147483141, 'Shenzhen', 35, 1, 13680864279, 'No. 987 Street, Shenzhen', '2022-04-04 16:00:00')," + diff --git a/regression-test/suites/schema_change_p0/test_dup_vals_schema_change.groovy b/regression-test/suites/schema_change_p0/test_dup_vals_schema_change.groovy index db5c4bbd8697ca..e1914bb6c8f249 100644 --- a/regression-test/suites/schema_change_p0/test_dup_vals_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_dup_vals_schema_change.groovy @@ -132,7 +132,7 @@ suite ("test_dup_vals_schema_change") { String tablet_id = tablet[0] backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -142,7 +142,7 @@ suite ("test_dup_vals_schema_change") { Awaitility.await().untilAsserted(() -> { String tablet_id = tablet[0] backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_enable_light_schema_change.groovy b/regression-test/suites/schema_change_p0/test_enable_light_schema_change.groovy index 88d2c8179e0322..96e76a4168d75f 100644 --- a/regression-test/suites/schema_change_p0/test_enable_light_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_enable_light_schema_change.groovy @@ -76,7 +76,7 @@ suite("test_enable_light_schema_change", "p0") { sql """ alter table ${tableName1} order by (k1, k2, k4, k3) """ - max_try_num = 60 + def max_try_num = 60 while (max_try_num--) { String res = getJobState(tableName1) if (res == "FINISHED" || res == "CANCELLED") { diff --git a/regression-test/suites/schema_change_p0/test_schema_change_duplicate.groovy b/regression-test/suites/schema_change_p0/test_schema_change_duplicate.groovy index 6c6660d10551c4..81e4271965ade3 100644 --- a/regression-test/suites/schema_change_p0/test_schema_change_duplicate.groovy +++ b/regression-test/suites/schema_change_p0/test_schema_change_duplicate.groovy @@ -148,7 +148,7 @@ suite("test_schema_change_duplicate", "p0") { time 600 } - int val = 100000 + max_try_num + int val = 100000 + 500 sql """ insert into ${tableName3} values (${val}, 2, 3, 4, 5, 6.6, 1.7, 8.8, 'a', 'b', 'c', '2021-10-30', '2021-10-30 00:00:00', 9527) """ diff --git a/regression-test/suites/schema_change_p0/test_uniq_keys_schema_change.groovy b/regression-test/suites/schema_change_p0/test_uniq_keys_schema_change.groovy index 856f49acd2bb57..b8dcf97e791582 100644 --- a/regression-test/suites/schema_change_p0/test_uniq_keys_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_uniq_keys_schema_change.groovy @@ -127,7 +127,7 @@ suite ("test_uniq_keys_schema_change") { String tablet_id = tablet[0] backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -137,7 +137,7 @@ suite ("test_uniq_keys_schema_change") { Awaitility.await().untilAsserted(() -> { String tablet_id = tablet[0] backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_uniq_mv_schema_change.groovy b/regression-test/suites/schema_change_p0/test_uniq_mv_schema_change.groovy index 54a790248b38f5..f2c961b5aa4c16 100644 --- a/regression-test/suites/schema_change_p0/test_uniq_mv_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_uniq_mv_schema_change.groovy @@ -170,7 +170,7 @@ suite ("test_uniq_mv_schema_change") { String tablet_id = tablet[0] backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -180,7 +180,7 @@ suite ("test_uniq_mv_schema_change") { Awaitility.await().untilAsserted(() -> { String tablet_id = tablet[0] backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_uniq_rollup_schema_change.groovy b/regression-test/suites/schema_change_p0/test_uniq_rollup_schema_change.groovy index 1b82e913e05c15..6fb74ceda4bb53 100644 --- a/regression-test/suites/schema_change_p0/test_uniq_rollup_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_uniq_rollup_schema_change.groovy @@ -131,7 +131,7 @@ suite ("test_uniq_rollup_schema_change") { ALTER TABLE ${tableName} DROP COLUMN cost """ - max_try_time = 300 + def max_try_time = 300 Awaitility.await().atMost(max_try_time, TimeUnit.SECONDS).with().pollDelay(100, TimeUnit.MILLISECONDS).await().until(() -> { String result = getJobState(tableName) if (result == "FINISHED") { @@ -173,7 +173,7 @@ suite ("test_uniq_rollup_schema_change") { String tablet_id = tablet[0] backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -183,7 +183,7 @@ suite ("test_uniq_rollup_schema_change") { Awaitility.await().untilAsserted(() -> { String tablet_id = tablet[0] backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_uniq_vals_schema_change.groovy b/regression-test/suites/schema_change_p0/test_uniq_vals_schema_change.groovy index 7dc530cecb8605..9ca8111d0ff737 100644 --- a/regression-test/suites/schema_change_p0/test_uniq_vals_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_uniq_vals_schema_change.groovy @@ -65,7 +65,7 @@ suite ("test_uniq_vals_schema_change") { (2, '2017-10-01', 'Beijing', 10, 1, '2020-01-03', '2020-01-03', '2020-01-03', 1, 32, 20) """ - qt_sc""" + qt_sc """ select count(*) from ${tableName} """ @@ -101,7 +101,7 @@ suite ("test_uniq_vals_schema_change") { sql """ ALTER TABLE ${tableName} DROP COLUMN last_visit_date """ - qt_sc = sql """ select * from ${tableName} where user_id = 3 """ + qt_sc """ select * from ${tableName} where user_id = 3 """ sql """ INSERT INTO ${tableName} VALUES (4, '2017-10-01', 'Beijing', 10, 1, '2020-01-03', '2020-01-03', 1, 32, 20, 2) @@ -135,7 +135,7 @@ suite ("test_uniq_vals_schema_change") { String tablet_id = tablet[0] backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) //assertEquals(code, 0) } @@ -145,7 +145,7 @@ suite ("test_uniq_vals_schema_change") { Awaitility.await().untilAsserted(() -> { String tablet_id = tablet[0] backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/schema_change_p0/test_varchar_schema_change.groovy b/regression-test/suites/schema_change_p0/test_varchar_schema_change.groovy index e4006e6e62b27f..2bb5e823e8bd17 100644 --- a/regression-test/suites/schema_change_p0/test_varchar_schema_change.groovy +++ b/regression-test/suites/schema_change_p0/test_varchar_schema_change.groovy @@ -113,7 +113,7 @@ suite ("test_varchar_schema_change") { String tablet_id = tablet[0] backend_id = tablet[2] logger.info("run compaction:" + tablet_id) - (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_run_cumulative_compaction(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Run compaction: code=" + code + ", out=" + out + ", err=" + err) } @@ -122,7 +122,7 @@ suite ("test_varchar_schema_change") { Awaitility.await().untilAsserted(() -> { String tablet_id = tablet[0] backend_id = tablet[2] - (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) + def (code, out, err) = be_get_compaction_status(backendId_to_backendIP.get(backend_id), backendId_to_backendHttpPort.get(backend_id), tablet_id) logger.info("Get compaction status: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) def compactionStatus = parseJson(out.trim()) diff --git a/regression-test/suites/show_p0/test_show_data.groovy b/regression-test/suites/show_p0/test_show_data.groovy index 10714a542d49f8..20adc299d55d83 100644 --- a/regression-test/suites/show_p0/test_show_data.groovy +++ b/regression-test/suites/show_p0/test_show_data.groovy @@ -22,7 +22,7 @@ suite("test_show_data") { def jdbcUrlWithoutDbStr = (context.config.jdbcUrl).split(context.config.defaultDb) logger.info("jdbcUrlWithoutDbStr:${jdbcUrlWithoutDbStr}"); - def result2 = connect(context.config.jdbcUser, password = context.config.jdbcPassword, url = jdbcUrlWithoutDbStr[0]) { + def result2 = connect(context.config.jdbcUser, context.config.jdbcPassword, jdbcUrlWithoutDbStr[0]) { sql """show data;""" } diff --git a/regression-test/suites/statistics/analyze_stats.groovy b/regression-test/suites/statistics/analyze_stats.groovy index 69360da6911ba5..3916dd116ad1da 100644 --- a/regression-test/suites/statistics/analyze_stats.groovy +++ b/regression-test/suites/statistics/analyze_stats.groovy @@ -357,7 +357,7 @@ suite("test_analyze") { ANALYZE TABLE analyze_partitioned_tbl_test WITH SYNC """ - part_tbl_analyze_result = sql """ + def part_tbl_analyze_result = sql """ SHOW COLUMN CACHED STATS analyze_partitioned_tbl_test(col1) """ @@ -1006,7 +1006,7 @@ PARTITION `p599` VALUES IN (599) sql """ANALYZE TABLE test_600_partition_table_analyze WITH SYNC""" // 0:column_name | 1:index_name | 2:count | 3:ndv | 4:num_null | 5:data_size | 6:avg_size_byte | 7:min | 8:max | 9:method | 10:type | 11:trigger | 12:query_times | 13:updated_time - id_col_stats = sql """ + def id_col_stats = sql """ SHOW COLUMN CACHED STATS test_600_partition_table_analyze(id); """ @@ -1230,7 +1230,7 @@ PARTITION `p599` VALUES IN (599) def check_column = { r, expected -> expected_result = convert_col_list_str_to_java_collection(expected) - actual_result = convert_col_list_str_to_java_collection(r[0][4]) + def actual_result = convert_col_list_str_to_java_collection(r[0][4]) System.out.println(expected_result) System.out.println(actual_result) return expected_result.containsAll(actual_result) && actual_result.containsAll(expected_result) diff --git a/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_delete_sign_with_conflict.groovy b/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_delete_sign_with_conflict.groovy index 0f67d5cb7c60e1..9438541227ed92 100644 --- a/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_delete_sign_with_conflict.groovy +++ b/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_delete_sign_with_conflict.groovy @@ -69,9 +69,9 @@ suite("test_partial_update_delete_sign_with_conflict") { log.info("http_stream execute 2pc: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text - json2pc = parseJson(out) + def code = process.waitFor() + def out = process.text + def json2pc = parseJson(out) log.info("http_stream 2pc result: ${out}".toString()) assertEquals(code, 0) assertEquals("success", json2pc.status.toLowerCase()) diff --git a/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_parallel.groovy b/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_parallel.groovy index c8523d235b4a67..e76b5d9f7109d0 100644 --- a/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_parallel.groovy +++ b/regression-test/suites/unique_with_mow_c_p0/partial_update/test_partial_update_parallel.groovy @@ -40,7 +40,7 @@ suite("test_primary_key_partial_update_parallel", "p0") { (4, "doris4", 4000, 423, 4), (3, "doris3", 3000, 323, 3);""" - t1 = Thread.startDaemon { + def t1 = Thread.startDaemon { streamLoad { table "${tableName}" @@ -65,7 +65,7 @@ suite("test_primary_key_partial_update_parallel", "p0") { } } - t2 = Thread.startDaemon { + def t2 = Thread.startDaemon { streamLoad { table "${tableName}" @@ -90,7 +90,7 @@ suite("test_primary_key_partial_update_parallel", "p0") { } } - t3 = Thread.startDaemon { + def t3 = Thread.startDaemon { streamLoad { table "${tableName}" diff --git a/regression-test/suites/unique_with_mow_p0/flexible/upgrade/test.groovy b/regression-test/suites/unique_with_mow_p0/flexible/upgrade/test.groovy index 91fa2267032ea1..5fabb4b49be201 100644 --- a/regression-test/suites/unique_with_mow_p0/flexible/upgrade/test.groovy +++ b/regression-test/suites/unique_with_mow_p0/flexible/upgrade/test.groovy @@ -21,7 +21,7 @@ suite('test_flexible_partial_update_upgrade', 'p0,restart_fe') { logger.info("current params: use_row_store: ${use_row_store}") def tableName = "test_f_upgrade_${use_row_store}" sql """alter table ${tableName} enable feature "UPDATE_FLEXIBLE_COLUMNS"; """ - show_res = sql "show create table ${tableName}" + def show_res = sql "show create table ${tableName}" assertTrue(show_res.toString().contains('"enable_unique_key_skip_bitmap_column" = "true"')) qt_sql "select k,v1,v2,v3,v4,v5 from ${tableName} order by k;" diff --git a/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_delete_sign_with_conflict.groovy b/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_delete_sign_with_conflict.groovy index 7e2cd9cdfe308a..ec03ac336e7dae 100644 --- a/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_delete_sign_with_conflict.groovy +++ b/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_delete_sign_with_conflict.groovy @@ -65,9 +65,9 @@ suite("test_partial_update_delete_sign_with_conflict") { log.info("http_stream execute 2pc: ${command}") def process = command.execute() - code = process.waitFor() - out = process.text - json2pc = parseJson(out) + def code = process.waitFor() + def out = process.text + def json2pc = parseJson(out) log.info("http_stream 2pc result: ${out}".toString()) assertEquals(code, 0) assertEquals("success", json2pc.status.toLowerCase()) diff --git a/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_parallel.groovy b/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_parallel.groovy index e2fa3a7903a0c0..611d4d1da432c9 100644 --- a/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_parallel.groovy +++ b/regression-test/suites/unique_with_mow_p0/partial_update/test_partial_update_parallel.groovy @@ -38,7 +38,7 @@ suite("test_primary_key_partial_update_parallel", "p0") { (4, "doris4", 4000, 423, 4), (3, "doris3", 3000, 323, 3);""" - t1 = Thread.startDaemon { + def t1 = Thread.startDaemon { streamLoad { table "${tableName}" @@ -52,7 +52,7 @@ suite("test_primary_key_partial_update_parallel", "p0") { } } - t2 = Thread.startDaemon { + def t2 = Thread.startDaemon { streamLoad { table "${tableName}" @@ -66,7 +66,7 @@ suite("test_primary_key_partial_update_parallel", "p0") { } } - t3 = Thread.startDaemon { + def t3 = Thread.startDaemon { streamLoad { table "${tableName}" diff --git a/regression-test/suites/update/test_update_configs.groovy b/regression-test/suites/update/test_update_configs.groovy index cbce43293c1c9a..6032682103c673 100644 --- a/regression-test/suites/update/test_update_configs.groovy +++ b/regression-test/suites/update/test_update_configs.groovy @@ -49,7 +49,7 @@ suite("test_update_configs", "p0") { (code, out, err) = show_be_config(beIp, bePort) logger.info("Show config: code=" + code + ", out=" + out + ", err=" + err) assertEquals(code, 0) - configList2 = parseJson(out.trim()) + def configList2 = parseJson(out.trim()) assert configList instanceof List for (Object ele in (List) configList2) { assert ele instanceof List diff --git a/regression-test/suites/variant_p0/concurrent_insert.groovy b/regression-test/suites/variant_p0/concurrent_insert.groovy index 0bbbfce789a3f3..4daa7750045cc1 100644 --- a/regression-test/suites/variant_p0/concurrent_insert.groovy +++ b/regression-test/suites/variant_p0/concurrent_insert.groovy @@ -28,19 +28,19 @@ suite("regression_test_variant_concurrent_schema_update", ""){ DISTRIBUTED BY HASH(k) BUCKETS 3 properties("replication_num" = "1"); """ - t1 = Thread.startDaemon { + def t1 = Thread.startDaemon { for (int k = 1; k <= 60; k++) { int x = k % 10; sql """insert into ${table_name} values(${x}, '{"k${x}" : ${x}, "x${k}" : 123}', '{"k${x}" : ${x}, "x${k}" : 123}')""" } } - t2 = Thread.startDaemon { + def t2 = Thread.startDaemon { for (int k = 61; k <= 120; k++) { int x = k % 10; sql """insert into ${table_name} values(${x}, '{"k${x}" : ${x}, "x${k}" : 123}', '{"k${x}" : ${x}, "x${k}" : 123}')""" } } - t3 = Thread.startDaemon { + def t3 = Thread.startDaemon { for (int k = 121; k <= 180; k++) { int x = k % 10; sql """insert into ${table_name} values(${x}, '{"k${x}" : ${x}, "x${k}" : 123}', '{"k${x}" : ${x}, "x${k}" : 123}')""" diff --git a/regression-test/suites/variant_p0/delete_update.groovy b/regression-test/suites/variant_p0/delete_update.groovy index 3d905d07e05c6d..7317b2c3145cea 100644 --- a/regression-test/suites/variant_p0/delete_update.groovy +++ b/regression-test/suites/variant_p0/delete_update.groovy @@ -75,19 +75,19 @@ suite("regression_test_variant_delete_and_update", "variant_type"){ // delete & insert concurrently sql "set enable_unique_key_partial_update=true;" sql "sync" - t1 = Thread.startDaemon { + def t1 = Thread.startDaemon { for (int k = 1; k <= 60; k++) { int x = new Random().nextInt(61) % 10; sql """insert into ${table_name}(k,vs) values(${x}, '{"k${x}" : ${x}}'),(${x+1}, '{"k${x+1}" : ${x+1}}'),(${x+2}, '{"k${x+2}" : ${x+2}}'),(${x+3}, '{"k${x+3}" : ${x+3}}')""" } } - t2 = Thread.startDaemon { + def t2 = Thread.startDaemon { for (int k = 1; k <= 60; k++) { int x = new Random().nextInt(61) % 10; sql """insert into ${table_name}(k,v) values(${x}, '{"k${x}" : ${x}}'),(${x+1}, '{"k${x+1}" : ${x+1}}'),(${x+2}, '{"k${x+2}" : ${x+2}}'),(${x+3}, '{"k${x+3}" : ${x+3}}')""" } } - t3 = Thread.startDaemon { + def t3 = Thread.startDaemon { for (int k = 1; k <= 60; k++) { int x = new Random().nextInt(61) % 10; sql """insert into ${table_name}(k,v) values(${x}, '{"k${x}" : ${x}}'),(${x+1}, '{"k${x+1}" : ${x+1}}'),(${x+2}, '{"k${x+2}" : ${x+2}}'),(${x+3}, '{"k${x+3}" : ${x+3}}')""" diff --git a/regression-test/suites/variant_p0/nested.groovy b/regression-test/suites/variant_p0/nested.groovy index 25bd682d43aca4..7df361c5731644 100644 --- a/regression-test/suites/variant_p0/nested.groovy +++ b/regression-test/suites/variant_p0/nested.groovy @@ -73,7 +73,7 @@ suite("regression_test_variant_nested", "p0"){ qt_sql """ select * from var_nested order by k limit 101 """ - for (i = 101; i < 121; ++i) { + for (int i = 101; i < 121; ++i) { sql """insert into var_nested values (${i}, '{"nested${i}" : {"nested": [{"yyyxxxx" : "11111"},{"ax1111" : "1111"},{"axxxb": 100, "xxxy111": 111}, {"ddsss":1024, "aaa" : "11"}, {"xx" : 10}]}, "not nested" : 1024, "not nested2" : {"llll" : 123}}');""" } def trigger_full_compaction_on_tablets = { tablets -> diff --git a/regression-test/suites/variant_p0/schema_change/schema_change.groovy b/regression-test/suites/variant_p0/schema_change/schema_change.groovy index 42cef32c8e5641..877874b7e03040 100644 --- a/regression-test/suites/variant_p0/schema_change/schema_change.groovy +++ b/regression-test/suites/variant_p0/schema_change/schema_change.groovy @@ -32,7 +32,7 @@ suite("regression_test_variant_schema_change", "variant_type"){ def useTime = 0 def wait_for_latest_op_on_table_finish = { tableName, OpTimeout -> for(int t = delta_time; t <= OpTimeout; t += delta_time){ - alter_res = sql """SHOW ALTER TABLE COLUMN WHERE TableName = "${tableName}" ORDER BY CreateTime DESC LIMIT 1;""" + def alter_res = sql """SHOW ALTER TABLE COLUMN WHERE TableName = "${tableName}" ORDER BY CreateTime DESC LIMIT 1;""" alter_res = alter_res.toString() if(alter_res.contains("FINISHED")) { sleep(3000) // wait change table state to normal diff --git a/regression-test/suites/workload_manager_p0/test_resource_tag.groovy b/regression-test/suites/workload_manager_p0/test_resource_tag.groovy index d6557645eb8759..fa7ba680143248 100644 --- a/regression-test/suites/workload_manager_p0/test_resource_tag.groovy +++ b/regression-test/suites/workload_manager_p0/test_resource_tag.groovy @@ -29,7 +29,7 @@ suite("test_resource_tag") { } // test query - connect(user = 'test_rg', password = '', url = context.config.jdbcUrl) { + connect('test_rg', '', context.config.jdbcUrl) { sql "drop table if exists test_skip_rg_bad_replica_tab;" sql """ CREATE TABLE test_skip_rg_bad_replica_tab @@ -55,7 +55,7 @@ suite("test_resource_tag") { } sql "set property for test_rg 'allow_resource_tag_downgrade' = 'true';" - connect(user = 'test_rg', password = '', url = context.config.jdbcUrl) { + connect('test_rg', '', context.config.jdbcUrl) { sql "select count(1) as t2 from test_skip_rg_bad_replica_tab;" sql "drop table test_skip_rg_bad_replica_tab"; } @@ -76,8 +76,8 @@ suite("test_resource_tag") { def test_failed_command = "curl --location-trusted -u test_rg: -H column_separator:| -H Transfer-Encoding:chunked -H columns:k1,k2 -T ${context.dataPath}/skip_rg_test_table.csv http://${context.config.feHttpAddress}/api/${context.config.defaultDb}/skip_rg_test_table/_stream_load" log.info("stream load skip_rg_test_table failed test cmd: ${test_failed_command}") def process = test_failed_command.execute() - code1 = process.waitFor() - out1 = process.text + def code1 = process.waitFor() + def out1 = process.text log.info("stream load skip_rg_test_table failed test result, ${out1}".toString()) assertTrue("${out1}".toString().contains("No backend load available") || "${out1}".toString().contains("No available backends")) @@ -85,9 +85,9 @@ suite("test_resource_tag") { def test_succ_command = "curl --location-trusted -u test_rg: -H column_separator:| -H Transfer-Encoding:chunked -H columns:k1,k2 -T ${context.dataPath}/skip_rg_test_table.csv http://${context.config.feHttpAddress}/api/${context.config.defaultDb}/skip_rg_test_table/_stream_load" def process2 = test_succ_command.execute() - code2 = process2.waitFor() - out2 = process2.text - jsonRet = parseJson(out2) + def code2 = process2.waitFor() + def out2 = process2.text + def jsonRet = parseJson(out2) log.info("stream load skip_rg_test_table succ test result, ${out2}".toString()) assertFalse("${out2}".toString().contains("No backend load available")) assertTrue(jsonRet['Status'] == 'Success') From 2ca753feb84c6931aedb760c1d2b3e9be3ead310 Mon Sep 17 00:00:00 2001 From: LiBinfeng Date: Fri, 13 Dec 2024 17:40:52 +0800 Subject: [PATCH 48/63] [fix](Nereids) fix cases unstable when using profile to check is nereids execution (#45384) Problem Summary: when commands running in doris using profile to check whether it's plan is generated by nereids, it would randomly failed because profile is not always generated on time. solved by remove this check and check whether command was running by nereids by reviewer --- .../doris/regression/suite/Suite.groovy | 35 ++----------------- .../test_nereids_admin_check_tablet.groovy | 4 +++ .../ddl/show_trash/test_nereids_trash.groovy | 4 +++ ..._nereids_show_tablet_storage_format.groovy | 4 +++ 4 files changed, 15 insertions(+), 32 deletions(-) diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy index 59722d72d952fe..f5d811514b375d 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy @@ -713,41 +713,12 @@ class Suite implements GroovyInterceptable { } void checkNereidsExecute(String sqlString) { - String tag = UUID.randomUUID().toString(); - log.info("start check" + tag) - String finalSqlString = "--" + tag + "\n" + sqlString - ProfileAction profileAction = new ProfileAction(context, tag) - profileAction.run { - log.info("start profile run" + tag) - sql (finalSqlString) - } - profileAction.check { - profileString, exception -> - log.info("start profile check" + tag) - log.info(profileString) - Assertions.assertTrue(profileString.contains("- Is Nereids: Yes")) - } - profileAction.run() + sql (sqlString) } String checkNereidsExecuteWithResult(String sqlString) { - String tag = UUID.randomUUID().toString(); - String result = null; - log.info("start check" + tag) - String finalSqlString = "--" + tag + "\n" + sqlString - ProfileAction profileAction = new ProfileAction(context, tag) - profileAction.run { - log.info("start profile run" + tag) - result = sql (finalSqlString) - } - profileAction.check { - profileString, exception -> - log.info("start profile check" + tag) - log.info(profileString) - Assertions.assertTrue(profileString.contains("- Is Nereids: Yes")) - } - profileAction.run() - return result; + String result = sql (sqlString); + return result } void createMV(String sql) { diff --git a/regression-test/suites/nereids_p0/admin/test_nereids_admin_check_tablet.groovy b/regression-test/suites/nereids_p0/admin/test_nereids_admin_check_tablet.groovy index 8812e09ea9f6f3..f96d8329f02a08 100644 --- a/regression-test/suites/nereids_p0/admin/test_nereids_admin_check_tablet.groovy +++ b/regression-test/suites/nereids_p0/admin/test_nereids_admin_check_tablet.groovy @@ -17,6 +17,10 @@ suite("test_nereids_admin_check_tablet") { + //cloud-mode + if (isCloudMode()) { + return + } def table = "test_nereids_admin_check_tablet" // create table and insert data sql """ drop table if exists ${table} force""" diff --git a/regression-test/suites/nereids_p0/ddl/show_trash/test_nereids_trash.groovy b/regression-test/suites/nereids_p0/ddl/show_trash/test_nereids_trash.groovy index 26a57c7e82d06f..f9b486a97fd014 100644 --- a/regression-test/suites/nereids_p0/ddl/show_trash/test_nereids_trash.groovy +++ b/regression-test/suites/nereids_p0/ddl/show_trash/test_nereids_trash.groovy @@ -20,6 +20,10 @@ suite("show_trash_nereids") { checkNereidsExecute("""show trash;""") checkNereidsExecute("""show trash on "127.0.0.1:9050";""") + //cloud-mode + if (isCloudMode()) { + return + } checkNereidsExecute("""ADMIN CLEAN TRASH;""") checkNereidsExecute("""ADMIN CLEAN TRASH ON ("127.0.0.1:9050");""") checkNereidsExecute("""ADMIN CLEAN TRASH ON ("192.168.0.1:9050", "192.168.0.2:9050", "192.168.0.3:9050");""") diff --git a/regression-test/suites/nereids_p0/show/test_nereids_show_tablet_storage_format.groovy b/regression-test/suites/nereids_p0/show/test_nereids_show_tablet_storage_format.groovy index b4b78bd1c28729..85b087fc19b291 100644 --- a/regression-test/suites/nereids_p0/show/test_nereids_show_tablet_storage_format.groovy +++ b/regression-test/suites/nereids_p0/show/test_nereids_show_tablet_storage_format.groovy @@ -17,6 +17,10 @@ suite("test_nereids_show_tablet_storage_format") { + //cloud-mode + if (isCloudMode()) { + return + } checkNereidsExecute("""show tablet storage format;""") checkNereidsExecute("""show tablet storage format verbose;""") checkNereidsExecute("""admin show tablet storage format;""") From 475571b15204280b04e499e7b97c337b372a4e46 Mon Sep 17 00:00:00 2001 From: yujun Date: Fri, 13 Dec 2024 18:53:54 +0800 Subject: [PATCH 49/63] [feat](nereids) simplify comparison predicate rule add check data type limit (#44732) simplify comparison, check data type's limit, like: suppose a is tinyint, so its range should be [-128, 127], then we can simplify: a = -129 => false cast (a as small int) = small int(-129) => false a <= -129 => false a > -129 => true a <= -128 => a = -128 currently data type check only support tinyint, small int, int, big int, decimalv3. if data type is float like, compare them with literal may lost precision, but maybe suport it later. This PR need more test. --- .../rules/SimplifyComparisonPredicate.java | 184 ++++++++---- .../doris/nereids/util/ExpressionUtils.java | 16 ++ .../doris/nereids/util/TypeCoercionUtils.java | 44 +++ .../SimplifyComparisonPredicateTest.java | 263 +++++++++++++++++- .../pull_up_predicate_literal.out | 110 +------- .../predicate_infer/infer_predicate.out | 10 +- .../predicate_infer/infer_predicate.groovy | 7 +- 7 files changed, 462 insertions(+), 172 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicate.java index cb61795865239b..5f14d9625e0849 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicate.java @@ -17,18 +17,17 @@ package org.apache.doris.nereids.rules.expression.rules; +import org.apache.doris.common.Pair; import org.apache.doris.nereids.rules.expression.AbstractExpressionRewriteRule; import org.apache.doris.nereids.rules.expression.ExpressionPatternMatcher; import org.apache.doris.nereids.rules.expression.ExpressionPatternRuleFactory; import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext; -import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.Cast; import org.apache.doris.nereids.trees.expressions.ComparisonPredicate; import org.apache.doris.nereids.trees.expressions.EqualTo; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.GreaterThan; import org.apache.doris.nereids.trees.expressions.GreaterThanEqual; -import org.apache.doris.nereids.trees.expressions.IsNull; import org.apache.doris.nereids.trees.expressions.LessThan; import org.apache.doris.nereids.trees.expressions.LessThanEqual; import org.apache.doris.nereids.trees.expressions.NullSafeEqual; @@ -44,16 +43,16 @@ import org.apache.doris.nereids.trees.expressions.literal.IntegerLikeLiteral; import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral; import org.apache.doris.nereids.trees.expressions.literal.Literal; -import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; +import org.apache.doris.nereids.trees.expressions.literal.NumericLiteral; import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; -import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.DateTimeType; import org.apache.doris.nereids.types.DateTimeV2Type; import org.apache.doris.nereids.types.DateType; import org.apache.doris.nereids.types.DateV2Type; import org.apache.doris.nereids.types.DecimalV3Type; import org.apache.doris.nereids.types.coercion.DateLikeType; +import org.apache.doris.nereids.util.ExpressionUtils; import org.apache.doris.nereids.util.TypeCoercionUtils; import com.google.common.base.Preconditions; @@ -62,9 +61,10 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; +import java.util.Optional; /** - * simplify comparison + * simplify comparison, not support large int. * such as: cast(c1 as DateV2) >= DateV2Literal --> c1 >= DateLiteral * cast(c1 AS double) > 2.0 --> c1 >= 2 (c1 is integer like type) */ @@ -98,22 +98,25 @@ public static Expression simplify(ComparisonPredicate cp) { Expression left = cp.left(); Expression right = cp.right(); - // float like type: float, double - if (left.getDataType().isFloatLikeType() && right.getDataType().isFloatLikeType()) { - return processFloatLikeTypeCoercion(cp, left, right); - } + Expression result; - // decimalv3 type - if (left.getDataType() instanceof DecimalV3Type && right.getDataType() instanceof DecimalV3Type) { - return processDecimalV3TypeCoercion(cp, left, right); + // process type coercion + if (left.getDataType().isFloatLikeType() && right.getDataType().isFloatLikeType()) { + result = processFloatLikeTypeCoercion(cp, left, right); + } else if (left.getDataType() instanceof DecimalV3Type && right.getDataType() instanceof DecimalV3Type) { + result = processDecimalV3TypeCoercion(cp, left, right); + } else if (left.getDataType() instanceof DateLikeType && right.getDataType() instanceof DateLikeType) { + result = processDateLikeTypeCoercion(cp, left, right); + } else { + result = cp; } - // date like type - if (left.getDataType() instanceof DateLikeType && right.getDataType() instanceof DateLikeType) { - return processDateLikeTypeCoercion(cp, left, right); + if (result instanceof ComparisonPredicate && ((ComparisonPredicate) result).right() instanceof NumericLiteral) { + ComparisonPredicate cmp = (ComparisonPredicate) result; + result = processTypeRangeLimitComparison(cmp, cmp.left(), (NumericLiteral) cmp.right()); } - return cp; + return result; } private static Expression processComparisonPredicateDateTimeV2Literal( @@ -128,17 +131,13 @@ private static Expression processComparisonPredicateDateTimeV2Literal( if (right.getMicroSecond() == originValue) { return comparisonPredicate.withChildren(left, right); } else { - if (left.nullable()) { - // TODO: the ideal way is to return an If expr like: - // return new If(new IsNull(left), new NullLiteral(BooleanType.INSTANCE), - // BooleanLiteral.of(false)); - // but current fold constant rule can't handle such complex expr with null literal - // before supporting complex conjuncts with null literal folding rules, - // we use a trick way like this: - return new And(new IsNull(left), new NullLiteral(BooleanType.INSTANCE)); - } else { - return BooleanLiteral.of(false); - } + // TODO: the ideal way is to return an If expr like: + // return new If(new IsNull(left), new NullLiteral(BooleanType.INSTANCE), + // BooleanLiteral.of(false)); + // but current fold constant rule can't handle such complex expr with null literal + // before supporting complex conjuncts with null literal folding rules, + // we use a trick way like this: + return ExpressionUtils.falseOrNull(left); } } else if (comparisonPredicate instanceof NullSafeEqual) { long originValue = right.getMicroSecond(); @@ -239,18 +238,13 @@ private static Expression processDecimalV3TypeCoercion(ComparisonPredicate compa comparisonPredicate.withChildren(left, new DecimalV3Literal( literal.getValue().setScale(toScale, RoundingMode.UNNECESSARY)))); } catch (ArithmeticException e) { - if (left.nullable()) { - // TODO: the ideal way is to return an If expr like: - // return new If(new IsNull(left), new NullLiteral(BooleanType.INSTANCE), - // BooleanLiteral.of(false)); - // but current fold constant rule can't handle such complex expr with null literal - // before supporting complex conjuncts with null literal folding rules, - // we use a trick way like this: - return new And(new IsNull(left), - new NullLiteral(BooleanType.INSTANCE)); - } else { - return BooleanLiteral.of(false); - } + // TODO: the ideal way is to return an If expr like: + // return new If(new IsNull(left), new NullLiteral(BooleanType.INSTANCE), + // BooleanLiteral.of(false)); + // but current fold constant rule can't handle such complex expr with null literal + // before supporting complex conjuncts with null literal folding rules, + // we use a trick way like this: + return ExpressionUtils.falseOrNull(left); } } else if (comparisonPredicate instanceof NullSafeEqual) { try { @@ -281,21 +275,18 @@ private static Expression processDecimalV3TypeCoercion(ComparisonPredicate compa private static Expression processIntegerDecimalLiteralComparison( ComparisonPredicate comparisonPredicate, Expression left, BigDecimal literal) { // we only process isIntegerLikeType, which are tinyint, smallint, int, bigint - if (literal.compareTo(new BigDecimal(Long.MAX_VALUE)) <= 0) { + if (literal.compareTo(new BigDecimal(Long.MIN_VALUE)) >= 0 + && literal.compareTo(new BigDecimal(Long.MAX_VALUE)) <= 0) { literal = literal.stripTrailingZeros(); if (literal.scale() > 0) { if (comparisonPredicate instanceof EqualTo) { - if (left.nullable()) { - // TODO: the ideal way is to return an If expr like: - // return new If(new IsNull(left), new NullLiteral(BooleanType.INSTANCE), - // BooleanLiteral.of(false)); - // but current fold constant rule can't handle such complex expr with null literal - // before supporting complex conjuncts with null literal folding rules, - // we use a trick way like this: - return new And(new IsNull(left), new NullLiteral(BooleanType.INSTANCE)); - } else { - return BooleanLiteral.of(false); - } + // TODO: the ideal way is to return an If expr like: + // return new If(new IsNull(left), new NullLiteral(BooleanType.INSTANCE), + // BooleanLiteral.of(false)); + // but current fold constant rule can't handle such complex expr with null literal + // before supporting complex conjuncts with null literal folding rules, + // we use a trick way like this: + return ExpressionUtils.falseOrNull(left); } else if (comparisonPredicate instanceof NullSafeEqual) { return BooleanLiteral.of(false); } else if (comparisonPredicate instanceof GreaterThan @@ -320,10 +311,95 @@ private static Expression processIntegerDecimalLiteralComparison( return comparisonPredicate; } + private static Expression processTypeRangeLimitComparison(ComparisonPredicate cp, Expression left, + NumericLiteral right) { + BigDecimal typeMinValue = null; + BigDecimal typeMaxValue = null; + // cmp float like have lost precision, for example float.max_value + 0.01 still eval to float.max_value + if (left.getDataType().isIntegerLikeType() || left.getDataType().isDecimalV3Type()) { + Optional> minMaxOpt = + TypeCoercionUtils.getDataTypeMinMaxValue(left.getDataType()); + if (minMaxOpt.isPresent()) { + typeMinValue = minMaxOpt.get().first; + typeMaxValue = minMaxOpt.get().second; + } + } + + // cast(child as dataType2) range should be: + // [ max(childDataType.min_value, dataType2.min_value), min(childDataType.max_value, dataType2.max_value)] + if (left instanceof Cast) { + left = ((Cast) left).child(); + if (left.getDataType().isIntegerLikeType() || left.getDataType().isDecimalV3Type()) { + Optional> minMaxOpt = + TypeCoercionUtils.getDataTypeMinMaxValue(left.getDataType()); + if (minMaxOpt.isPresent()) { + if (typeMinValue == null || typeMinValue.compareTo(minMaxOpt.get().first) < 0) { + typeMinValue = minMaxOpt.get().first; + } + if (typeMaxValue == null || typeMaxValue.compareTo(minMaxOpt.get().second) > 0) { + typeMaxValue = minMaxOpt.get().second; + } + } + } + } + + if (typeMinValue == null || typeMaxValue == null) { + return cp; + } + BigDecimal literal = new BigDecimal(right.getStringValue()); + int cmpMin = literal.compareTo(typeMinValue); + int cmpMax = literal.compareTo(typeMaxValue); + if (cp instanceof EqualTo) { + if (cmpMin < 0 || cmpMax > 0) { + return ExpressionUtils.falseOrNull(left); + } + } else if (cp instanceof NullSafeEqual) { + if (cmpMin < 0 || cmpMax > 0) { + return BooleanLiteral.of(false); + } + } else if (cp instanceof GreaterThan) { + if (cmpMin < 0) { + return ExpressionUtils.trueOrNull(left); + } + if (cmpMax >= 0) { + return ExpressionUtils.falseOrNull(left); + } + } else if (cp instanceof GreaterThanEqual) { + if (cmpMin <= 0) { + return ExpressionUtils.trueOrNull(left); + } + if (cmpMax == 0) { + return new EqualTo(cp.left(), cp.right()); + } + if (cmpMax > 0) { + return ExpressionUtils.falseOrNull(left); + } + } else if (cp instanceof LessThan) { + if (cmpMin <= 0) { + return ExpressionUtils.falseOrNull(left); + } + if (cmpMax > 0) { + return ExpressionUtils.trueOrNull(left); + } + } else if (cp instanceof LessThanEqual) { + if (cmpMin < 0) { + return ExpressionUtils.falseOrNull(left); + } + if (cmpMin == 0) { + return new EqualTo(cp.left(), cp.right()); + } + if (cmpMax >= 0) { + return ExpressionUtils.trueOrNull(left); + } + } + return cp; + } + private static IntegerLikeLiteral convertDecimalToIntegerLikeLiteral(BigDecimal decimal) { - Preconditions.checkArgument( - decimal.scale() <= 0 && decimal.compareTo(new BigDecimal(Long.MAX_VALUE)) <= 0, - "decimal literal must have 0 scale and smaller than Long.MAX_VALUE"); + Preconditions.checkArgument(decimal.scale() <= 0 + && decimal.compareTo(new BigDecimal(Long.MIN_VALUE)) >= 0 + && decimal.compareTo(new BigDecimal(Long.MAX_VALUE)) <= 0, + "decimal literal must have 0 scale and in range [Long.MIN_VALUE, Long.MAX_VALUE]"); long val = decimal.longValue(); if (val >= Byte.MIN_VALUE && val <= Byte.MAX_VALUE) { return new TinyIntLiteral((byte) val); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java index 22b681a6246d92..25637d1b816656 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java @@ -260,6 +260,22 @@ public static Expression or(Collection expressions) { } } + public static Expression falseOrNull(Expression expression) { + if (expression.nullable()) { + return new And(new IsNull(expression), new NullLiteral(BooleanType.INSTANCE)); + } else { + return BooleanLiteral.FALSE; + } + } + + public static Expression trueOrNull(Expression expression) { + if (expression.nullable()) { + return new Or(new Not(new IsNull(expression)), new NullLiteral(BooleanType.INSTANCE)); + } else { + return BooleanLiteral.TRUE; + } + } + /** * Use AND/OR to combine expressions together. */ diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java index 603a891d2d2a49..1da4353d20da33 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java @@ -21,6 +21,7 @@ import org.apache.doris.catalog.ScalarType; import org.apache.doris.catalog.Type; import org.apache.doris.common.Config; +import org.apache.doris.common.Pair; import org.apache.doris.nereids.annotation.Developing; import org.apache.doris.nereids.exceptions.AnalysisException; import org.apache.doris.nereids.trees.expressions.Add; @@ -116,6 +117,7 @@ import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -1773,6 +1775,48 @@ private static Expression processDecimalV3BinaryArithmetic(BinaryArithmetic bina castIfNotSameType(right, dt2)); } + /** + * get min and max value of a data type + * + * @param dataType specific data type + * @return min and max values pair + */ + public static Optional> getDataTypeMinMaxValue(DataType dataType) { + if (dataType.isTinyIntType()) { + return Optional.of(Pair.of(new BigDecimal(Byte.MIN_VALUE), new BigDecimal(Byte.MAX_VALUE))); + } else if (dataType.isSmallIntType()) { + return Optional.of(Pair.of(new BigDecimal(Short.MIN_VALUE), new BigDecimal(Short.MAX_VALUE))); + } else if (dataType.isIntegerType()) { + return Optional.of(Pair.of(new BigDecimal(Integer.MIN_VALUE), new BigDecimal(Integer.MAX_VALUE))); + } else if (dataType.isBigIntType()) { + return Optional.of(Pair.of(new BigDecimal(Long.MIN_VALUE), new BigDecimal(Long.MAX_VALUE))); + } else if (dataType.isLargeIntType()) { + return Optional.of(Pair.of(new BigDecimal(LargeIntType.MIN_VALUE), new BigDecimal(LargeIntType.MAX_VALUE))); + } else if (dataType.isFloatType()) { + return Optional.of(Pair.of(BigDecimal.valueOf(-Float.MAX_VALUE), new BigDecimal(Float.MAX_VALUE))); + } else if (dataType.isDoubleType()) { + return Optional.of(Pair.of(BigDecimal.valueOf(-Double.MAX_VALUE), new BigDecimal(Double.MAX_VALUE))); + } else if (dataType.isDecimalV3Type()) { + DecimalV3Type type = (DecimalV3Type) dataType; + int precision = type.getPrecision(); + int scale = type.getScale(); + if (scale >= 0) { + StringBuilder sb = new StringBuilder(); + sb.append(StringUtils.repeat('9', precision - scale)); + if (sb.length() == 0) { + sb.append('0'); + } + if (scale > 0) { + sb.append('.'); + sb.append(StringUtils.repeat('9', scale)); + } + return Optional.of(Pair.of(new BigDecimal("-" + sb.toString()), new BigDecimal(sb.toString()))); + } + } + + return Optional.empty(); + } + private static boolean supportCompare(DataType dataType) { if (dataType.isArrayType()) { return true; diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateTest.java index 84ebd7c7250198..9202c1e202469d 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateTest.java @@ -17,10 +17,12 @@ package org.apache.doris.nereids.rules.expression.rules; +import org.apache.doris.common.Pair; import org.apache.doris.nereids.rules.expression.ExpressionRewriteTestHelper; import org.apache.doris.nereids.rules.expression.ExpressionRuleExecutor; import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.Cast; +import org.apache.doris.nereids.trees.expressions.ComparisonPredicate; import org.apache.doris.nereids.trees.expressions.EqualTo; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.GreaterThan; @@ -38,17 +40,29 @@ import org.apache.doris.nereids.trees.expressions.literal.DateV2Literal; import org.apache.doris.nereids.trees.expressions.literal.DecimalV3Literal; import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral; +import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral; +import org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; +import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral; +import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; +import org.apache.doris.nereids.types.BigIntType; import org.apache.doris.nereids.types.BooleanType; +import org.apache.doris.nereids.types.DataType; import org.apache.doris.nereids.types.DateTimeV2Type; import org.apache.doris.nereids.types.DecimalV3Type; import org.apache.doris.nereids.types.DoubleType; +import org.apache.doris.nereids.types.IntegerType; +import org.apache.doris.nereids.types.SmallIntType; +import org.apache.doris.nereids.types.TinyIntType; +import org.apache.doris.nereids.util.ExpressionUtils; import com.google.common.collect.ImmutableList; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; class SimplifyComparisonPredicateTest extends ExpressionRewriteTestHelper { @Test @@ -233,63 +247,292 @@ void testDecimalV3Literal() { Assertions.assertEquals(BooleanLiteral.FALSE, rewrittenExpression); // > right literal should round floor - leftChild = new DecimalV3Literal(new BigDecimal("1.24")); + leftChild = new DecimalV3Literal(new BigDecimal("10.24")); left = new Cast(leftChild, DecimalV3Type.createDecimalV3Type(5, 3)); right = new DecimalV3Literal(new BigDecimal("12.345")); expression = new GreaterThan(left, right); rewrittenExpression = executor.rewrite(expression, context); - Assertions.assertInstanceOf(Cast.class, rewrittenExpression.child(0)); Assertions.assertEquals(DecimalV3Type.createDecimalV3Type(4, 2), rewrittenExpression.child(0).getDataType()); Assertions.assertInstanceOf(DecimalV3Literal.class, rewrittenExpression.child(1)); Assertions.assertEquals(new BigDecimal("12.34"), ((DecimalV3Literal) rewrittenExpression.child(1)).getValue()); // <= right literal should round floor - leftChild = new DecimalV3Literal(new BigDecimal("1.24")); + leftChild = new DecimalV3Literal(new BigDecimal("10.24")); left = new Cast(leftChild, DecimalV3Type.createDecimalV3Type(5, 3)); right = new DecimalV3Literal(new BigDecimal("12.345")); expression = new LessThanEqual(left, right); rewrittenExpression = executor.rewrite(expression, context); - Assertions.assertInstanceOf(Cast.class, rewrittenExpression.child(0)); Assertions.assertEquals(DecimalV3Type.createDecimalV3Type(4, 2), rewrittenExpression.child(0).getDataType()); Assertions.assertInstanceOf(DecimalV3Literal.class, rewrittenExpression.child(1)); Assertions.assertEquals(new BigDecimal("12.34"), ((DecimalV3Literal) rewrittenExpression.child(1)).getValue()); // >= right literal should round ceiling - leftChild = new DecimalV3Literal(new BigDecimal("1.24")); + leftChild = new DecimalV3Literal(new BigDecimal("10.24")); left = new Cast(leftChild, DecimalV3Type.createDecimalV3Type(5, 3)); right = new DecimalV3Literal(new BigDecimal("12.345")); expression = new GreaterThanEqual(left, right); rewrittenExpression = executor.rewrite(expression, context); - Assertions.assertInstanceOf(Cast.class, rewrittenExpression.child(0)); Assertions.assertEquals(DecimalV3Type.createDecimalV3Type(4, 2), rewrittenExpression.child(0).getDataType()); Assertions.assertInstanceOf(DecimalV3Literal.class, rewrittenExpression.child(1)); Assertions.assertEquals(new BigDecimal("12.35"), ((DecimalV3Literal) rewrittenExpression.child(1)).getValue()); // < right literal should round ceiling - leftChild = new DecimalV3Literal(new BigDecimal("1.24")); + leftChild = new DecimalV3Literal(new BigDecimal("10.24")); left = new Cast(leftChild, DecimalV3Type.createDecimalV3Type(5, 3)); right = new DecimalV3Literal(new BigDecimal("12.345")); expression = new LessThan(left, right); rewrittenExpression = executor.rewrite(expression, context); - Assertions.assertInstanceOf(Cast.class, rewrittenExpression.child(0)); Assertions.assertEquals(DecimalV3Type.createDecimalV3Type(4, 2), rewrittenExpression.child(0).getDataType()); Assertions.assertInstanceOf(DecimalV3Literal.class, rewrittenExpression.child(1)); Assertions.assertEquals(new BigDecimal("12.35"), ((DecimalV3Literal) rewrittenExpression.child(1)).getValue()); // left's child range smaller than right literal - leftChild = new DecimalV3Literal(new BigDecimal("1234.12")); + leftChild = new DecimalV3Literal(new BigDecimal("12340.12")); left = new Cast(leftChild, DecimalV3Type.createDecimalV3Type(10, 5)); right = new DecimalV3Literal(new BigDecimal("12345.12000")); expression = new EqualTo(left, right); rewrittenExpression = executor.rewrite(expression, context); - Assertions.assertInstanceOf(Cast.class, rewrittenExpression.child(0)); Assertions.assertEquals(DecimalV3Type.createDecimalV3Type(7, 2), rewrittenExpression.child(0).getDataType()); Assertions.assertInstanceOf(DecimalV3Literal.class, rewrittenExpression.child(1)); Assertions.assertEquals(new BigDecimal("12345.12"), ((DecimalV3Literal) rewrittenExpression.child(1)).getValue()); } + + private enum RangeLimitResult { + TRUE, // eval to true + FALSE, // eval to false + EQUALS, // eval to equals + NO_CHANGE_CP // no change cmp type + } + + @Test + void testTypeRangeLimit() { + executor = new ExpressionRuleExecutor(ImmutableList.of( + bottomUp(SimplifyComparisonPredicate.INSTANCE) + )); + + checkTypeRangeLimit(TinyIntType.INSTANCE, + ImmutableList.of( + Pair.of(new SmallIntLiteral((short) -129), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-129")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-128.1")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-1000.1")), null), + Pair.of(new DoubleLiteral(-129.0), new SmallIntLiteral((short) -129)), + Pair.of(new DoubleLiteral(-128.1), new DecimalV3Literal(new BigDecimal("-128.1")))), + ImmutableList.of( + Pair.of(new TinyIntLiteral((byte) -128), null), + Pair.of(new SmallIntLiteral((short) -128), null), + Pair.of(new IntegerLiteral(-128), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-128")), new TinyIntLiteral((byte) -128)), + Pair.of(new DoubleLiteral(-128.0), new TinyIntLiteral((byte) -128))), + ImmutableList.of( + Pair.of(new TinyIntLiteral((byte) -127), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-127")), new TinyIntLiteral((byte) -127)), + Pair.of(new DoubleLiteral(-127.0), new TinyIntLiteral((byte) -127)), + Pair.of(new TinyIntLiteral((byte) 126), null), + Pair.of(new DoubleLiteral(126.0), new TinyIntLiteral((byte) 126))), + ImmutableList.of( + Pair.of(new TinyIntLiteral((byte) 127), null), + Pair.of(new DecimalV3Literal(new BigDecimal("127")), new TinyIntLiteral((byte) 127)), + Pair.of(new DecimalV3Literal(new BigDecimal("127.00")), new TinyIntLiteral((byte) 127)), + Pair.of(new DoubleLiteral(127.0), new TinyIntLiteral((byte) 127))), + ImmutableList.of( + Pair.of(new SmallIntLiteral((short) 128), null), + Pair.of(new DecimalV3Literal(new BigDecimal("128.02")), null), + Pair.of(new DoubleLiteral(128.0), new SmallIntLiteral((short) 128)), + Pair.of(new DoubleLiteral(127.1), new DecimalV3Literal(new BigDecimal("127.1"))))); + + checkTypeRangeLimit(SmallIntType.INSTANCE, + ImmutableList.of( + Pair.of(new IntegerLiteral(-32769), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-32769")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-32768.1")), null), + Pair.of(new DoubleLiteral(-32769.0), new IntegerLiteral(-32769)), + Pair.of(new DoubleLiteral(-32769.1), new DecimalV3Literal(new BigDecimal("-32769.1")))), + ImmutableList.of( + Pair.of(new SmallIntLiteral((short) -32768), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-32768")), new SmallIntLiteral((short) -32768)), + Pair.of(new DoubleLiteral(-32768.0), new SmallIntLiteral((short) -32768))), + ImmutableList.of( + Pair.of(new SmallIntLiteral((short) -32767), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-32767")), new SmallIntLiteral((short) -32767)), + Pair.of(new DoubleLiteral(-32767.0), new SmallIntLiteral((short) -32767)), + Pair.of(new SmallIntLiteral((short) 32766), null), + Pair.of(new DoubleLiteral(32766.0), new SmallIntLiteral((short) 32766))), + ImmutableList.of( + Pair.of(new SmallIntLiteral((short) 32767), null), + Pair.of(new DecimalV3Literal(new BigDecimal("32767")), new SmallIntLiteral((short) 32767)), + Pair.of(new DecimalV3Literal(new BigDecimal("32767.00")), new SmallIntLiteral((short) 32767)), + Pair.of(new DoubleLiteral(32767.0), new SmallIntLiteral((short) 32767))), + ImmutableList.of( + Pair.of(new IntegerLiteral(32768), null), + Pair.of(new DecimalV3Literal(new BigDecimal("32768.02")), null), + Pair.of(new DoubleLiteral(32768.0), new IntegerLiteral(32768)), + Pair.of(new DoubleLiteral(32768.1), new DecimalV3Literal(new BigDecimal("32768.1"))))); + + checkTypeRangeLimit(IntegerType.INSTANCE, + ImmutableList.of( + Pair.of(new BigIntLiteral(-2147483649L), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-2147483649")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-2147483649.1")), null), + Pair.of(new DoubleLiteral(-2147483649.0), new BigIntLiteral(-2147483649L)), + Pair.of(new DoubleLiteral(-2147483649.1), new DecimalV3Literal(new BigDecimal("-2147483649.1")))), + ImmutableList.of( + Pair.of(new IntegerLiteral(-2147483648), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-2147483648.0")), new IntegerLiteral(-2147483648)), + Pair.of(new DoubleLiteral(-2147483648.0), new IntegerLiteral(-2147483648))), + ImmutableList.of( + Pair.of(new TinyIntLiteral((byte) 0), null), + Pair.of(new SmallIntLiteral((short) 0), null), + Pair.of(new IntegerLiteral(-2147483647), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-2147483647")), new IntegerLiteral(-2147483647)), + Pair.of(new DoubleLiteral(-2147483647.0), new IntegerLiteral(-2147483647)), + Pair.of(new IntegerLiteral(2147483646), null), + Pair.of(new DoubleLiteral(2147483646.0), new IntegerLiteral(2147483646))), + ImmutableList.of( + Pair.of(new IntegerLiteral(2147483647), null), + Pair.of(new DecimalV3Literal(new BigDecimal("2147483647")), new IntegerLiteral(2147483647)), + Pair.of(new DecimalV3Literal(new BigDecimal("2147483647.00")), new IntegerLiteral(2147483647)), + Pair.of(new DoubleLiteral(2147483647.0), new IntegerLiteral(2147483647))), + ImmutableList.of( + Pair.of(new BigIntLiteral(2147483648L), null), + Pair.of(new DecimalV3Literal(new BigDecimal("2147483648.02")), null), + Pair.of(new DoubleLiteral(2147483648.0), new BigIntLiteral(2147483648L)), + Pair.of(new DoubleLiteral(2147483647.1), new DecimalV3Literal(new BigDecimal("2147483647.1"))))); + + checkTypeRangeLimit(BigIntType.INSTANCE, + ImmutableList.of( + Pair.of(new LargeIntLiteral(new BigInteger("-9223372036854775809")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-9223372036854775809")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-9223372036854775808.1")), null), + Pair.of(new DoubleLiteral(-9223372036854775809.0), new LargeIntLiteral(new BigInteger("-9223372036854775809"))), + Pair.of(new DoubleLiteral(-9223372036854775808.1), new DecimalV3Literal(new BigDecimal("-9223372036854775808.1")))), + ImmutableList.of( + Pair.of(new BigIntLiteral(-9223372036854775808L), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-9223372036854775808")), new BigIntLiteral(-9223372036854775808L))), + ImmutableList.of( + Pair.of(new BigIntLiteral(-9223372036854775807L), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-9223372036854775807")), new BigIntLiteral(-9223372036854775807L)), + Pair.of(new DoubleLiteral(-9223372036854775000.0), new BigIntLiteral(-9223372036854775000L)), + Pair.of(new BigIntLiteral(9223372036854775806L), null), + Pair.of(new DoubleLiteral(9223372036854775000.0), new BigIntLiteral(9223372036854775000L))), + ImmutableList.of( + Pair.of(new BigIntLiteral(9223372036854775807L), null), + Pair.of(new DecimalV3Literal(new BigDecimal("9223372036854775807")), new BigIntLiteral(9223372036854775807L)), + Pair.of(new DecimalV3Literal(new BigDecimal("9223372036854775807.00")), new BigIntLiteral(9223372036854775807L))), + ImmutableList.of( + Pair.of(new LargeIntLiteral(new BigInteger("9223372036854775808")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("9223372036854775807.02")), null), + Pair.of(new DoubleLiteral(9223372036854775808.0), new LargeIntLiteral(new BigInteger("9223372036854775808"))), + Pair.of(new DoubleLiteral(9223372036854775807.1), new DecimalV3Literal(new BigDecimal("9223372036854775807.1"))))); + + checkTypeRangeLimit(DecimalV3Type.createDecimalV3Type(5, 2), + ImmutableList.of( + Pair.of(new IntegerLiteral(-1000), null), + Pair.of(new DoubleLiteral(-1000.1), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-999.999")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-1000.00")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("-1000.0123")), null)), + ImmutableList.of( + Pair.of(new DecimalV3Literal(new BigDecimal("-999.99")), null)), + ImmutableList.of( + Pair.of(new DecimalV3Literal(new BigDecimal("100.4")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("100")), null)), + ImmutableList.of( + Pair.of(new DecimalV3Literal(new BigDecimal("999.99")), null)), + ImmutableList.of( + Pair.of(new IntegerLiteral(1000), null), + Pair.of(new DoubleLiteral(1000.1), null), + Pair.of(new DecimalV3Literal(new BigDecimal("1000")), null), + Pair.of(new DecimalV3Literal(new BigDecimal("999.999")), null))); + } + + // each expr list item is: pair + // if rewritten right literal = null, then rewritten right literal = origin right literal + void checkTypeRangeLimit(DataType dataType, List> lessThanMinExpr, + List> minExpr, List> betweenMinMaxExpr, + List> maxExpr, List> greaterThanMaxExpr) { + // due to ComparisonPredicate constructor require not null left and right child, + // use a dummyExpr as ComparisonPredicate's child + Expression dummyExpr = new SmallIntLiteral((short) 100); + // cp -> list of cp with lessThanMinExpr, minExpr, betweenMinMaxExpr, maxExpr, greaterThanMaxExpr + List>> cmpResults = ImmutableList.of( + Pair.of(new EqualTo(dummyExpr, dummyExpr), ImmutableList.of( + RangeLimitResult.FALSE, RangeLimitResult.NO_CHANGE_CP, RangeLimitResult.NO_CHANGE_CP, + RangeLimitResult.NO_CHANGE_CP, RangeLimitResult.FALSE)), + Pair.of(new NullSafeEqual(dummyExpr, dummyExpr), ImmutableList.of( + RangeLimitResult.FALSE, RangeLimitResult.NO_CHANGE_CP, RangeLimitResult.NO_CHANGE_CP, + RangeLimitResult.NO_CHANGE_CP, RangeLimitResult.FALSE)), + Pair.of(new GreaterThan(dummyExpr, dummyExpr), ImmutableList.of( + RangeLimitResult.TRUE, RangeLimitResult.NO_CHANGE_CP, RangeLimitResult.NO_CHANGE_CP, + RangeLimitResult.FALSE, RangeLimitResult.FALSE)), + Pair.of(new GreaterThanEqual(dummyExpr, dummyExpr), ImmutableList.of( + RangeLimitResult.TRUE, RangeLimitResult.TRUE, RangeLimitResult.NO_CHANGE_CP, + RangeLimitResult.EQUALS, RangeLimitResult.FALSE)), + Pair.of(new LessThan(dummyExpr, dummyExpr), ImmutableList.of( + RangeLimitResult.FALSE, RangeLimitResult.FALSE, RangeLimitResult.NO_CHANGE_CP, + RangeLimitResult.NO_CHANGE_CP, RangeLimitResult.TRUE)), + Pair.of(new LessThanEqual(dummyExpr, dummyExpr), ImmutableList.of( + RangeLimitResult.FALSE, RangeLimitResult.EQUALS, RangeLimitResult.NO_CHANGE_CP, + RangeLimitResult.TRUE, RangeLimitResult.TRUE)) + ); + + for (Pair> cmpResult : cmpResults) { + ComparisonPredicate cp = cmpResult.first; + List result = cmpResult.second; + checkTypeRangeLimitWithComparison(dataType, cp, lessThanMinExpr, result.get(0)); + checkTypeRangeLimitWithComparison(dataType, cp, minExpr, result.get(1)); + checkTypeRangeLimitWithComparison(dataType, cp, betweenMinMaxExpr, result.get(2)); + checkTypeRangeLimitWithComparison(dataType, cp, maxExpr, result.get(3)); + checkTypeRangeLimitWithComparison(dataType, cp, greaterThanMaxExpr, result.get(4)); + } + } + + void checkTypeRangeLimitWithComparison(DataType dataType, ComparisonPredicate cp, + List> exprs, RangeLimitResult result) { + Expression slot = new SlotReference("slot", dataType, true); + for (Pair pair : exprs) { + Expression right = pair.first; + Expression rewriteRight = pair.second; + if (rewriteRight == null) { + rewriteRight = right; + } + Expression left = slot; + if (!left.getDataType().equals(right.getDataType())) { + left = new Cast(slot, right.getDataType()); + } + Expression originExpr = cp.withChildren(left, right); + Expression rewrittenExpr = executor.rewrite(originExpr, context); + Expression expectExpr = null; + // System.out.println("slot type: " + slot.getDataType() + ", literal type: " + right.getDataType()); + // System.out.println("origin expr: " + originExpr); + // System.out.println("rewrite expr: " + rewrittenExpr); + switch (result) { + case TRUE: + expectExpr = cp instanceof NullSafeEqual ? BooleanLiteral.TRUE + : ExpressionUtils.trueOrNull(slot); + break; + case FALSE: + expectExpr = cp instanceof NullSafeEqual ? BooleanLiteral.FALSE + : ExpressionUtils.falseOrNull(slot); + break; + case EQUALS: + Expression expectLeft = slot.getDataType().equals(rewriteRight.getDataType()) ? slot : left; + expectExpr = new EqualTo(expectLeft, rewriteRight); + break; + case NO_CHANGE_CP: + Assertions.assertInstanceOf(cp.getClass(), rewrittenExpr); + break; + default: + Assertions.assertTrue(false); + } + if (expectExpr != null) { + Assertions.assertEquals(expectExpr, rewrittenExpr); + } + } + } } diff --git a/regression-test/data/nereids_rules_p0/infer_predicate/pull_up_predicate_literal.out b/regression-test/data/nereids_rules_p0/infer_predicate/pull_up_predicate_literal.out index 524559cabeb34d..920289be66c360 100644 --- a/regression-test/data/nereids_rules_p0/infer_predicate/pull_up_predicate_literal.out +++ b/regression-test/data/nereids_rules_p0/infer_predicate/pull_up_predicate_literal.out @@ -262,15 +262,7 @@ PhysicalResultSink -- !const_value_and_join_column_type16 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_tinyint as SMALLINT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_tinyint as SMALLINT) = 32767)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type17 -- PhysicalResultSink @@ -414,27 +406,11 @@ PhysicalResultSink -- !const_value_and_join_column_type32 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_tinyint as INT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_tinyint as INT) = 32768)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type33 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_smallint as INT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_smallint as INT) = 32768)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type34 -- PhysicalResultSink @@ -566,39 +542,15 @@ PhysicalResultSink -- !const_value_and_join_column_type48 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_tinyint as BIGINT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_tinyint as BIGINT) = 214748364799)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type49 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_smallint as BIGINT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_smallint as BIGINT) = 214748364799)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type50 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_int as BIGINT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_int as BIGINT) = 214748364799)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type51 -- PhysicalResultSink @@ -718,51 +670,19 @@ PhysicalResultSink -- !const_value_and_join_column_type64 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_tinyint as LARGEINT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_tinyint as LARGEINT) = 922337203685477580722)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type65 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_smallint as LARGEINT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_smallint as LARGEINT) = 922337203685477580722)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type66 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_int as LARGEINT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_int as LARGEINT) = 922337203685477580722)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type67 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_bigint as LARGEINT) = t.c1)) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_bigint as LARGEINT) = 922337203685477580722)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type68 -- PhysicalResultSink @@ -814,15 +734,7 @@ PhysicalResultSink -- !const_value_and_join_column_type72 -- PhysicalResultSink ---PhysicalProject -----hashJoin[INNER_JOIN] hashCondition=((expr_cast(d_decimal as DOUBLE) = expr_cast(c1 as DOUBLE))) otherCondition=() -------PhysicalLimit[GLOBAL] ---------PhysicalLimit[LOCAL] -----------PhysicalProject -------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal] -------PhysicalProject ---------filter((cast(d_decimal as DOUBLE) = 9.223372036854776E20)) -----------PhysicalOlapScan[test_types] +--PhysicalEmptyRelation -- !const_value_and_join_column_type73 -- PhysicalResultSink diff --git a/regression-test/data/nereids_rules_p0/predicate_infer/infer_predicate.out b/regression-test/data/nereids_rules_p0/predicate_infer/infer_predicate.out index 288c30bb28c1cf..fb99fe6169c1d9 100644 --- a/regression-test/data/nereids_rules_p0/predicate_infer/infer_predicate.out +++ b/regression-test/data/nereids_rules_p0/predicate_infer/infer_predicate.out @@ -374,23 +374,23 @@ PhysicalResultSink -- !infer9 -- PhysicalResultSink --hashJoin[INNER_JOIN] hashCondition=((t1.id = t2.id)) otherCondition=() -----filter((cast(id as BIGINT) = 2147483648)) +----filter((t1.id = 12345)) ------PhysicalOlapScan[t1] -----filter((cast(id as BIGINT) = 2147483648)) +----filter((t2.id = 12345)) ------PhysicalOlapScan[t2] -- !infer10 -- PhysicalResultSink --hashJoin[INNER_JOIN] hashCondition=((expr_cast(id as SMALLINT) = expr_cast(id as SMALLINT))) otherCondition=() -----filter((cast(id as BIGINT) = 2147483648)) +----filter((t1.id = 12345)) ------PhysicalOlapScan[t1] ----PhysicalOlapScan[t2] -- !infer11 -- PhysicalResultSink --hashJoin[INNER_JOIN] hashCondition=((expr_cast(id as LARGEINT) = expr_cast(id as LARGEINT))) otherCondition=() -----filter((cast(id as BIGINT) = 2147483648)) +----filter((t1.id = 12345)) ------PhysicalOlapScan[t1] -----filter((cast(id as BIGINT) = 2147483648)) +----filter((t2.id = 12345)) ------PhysicalOlapScan[t2] diff --git a/regression-test/suites/nereids_rules_p0/predicate_infer/infer_predicate.groovy b/regression-test/suites/nereids_rules_p0/predicate_infer/infer_predicate.groovy index af985ecd7ee10e..6237d5d66e8ef3 100644 --- a/regression-test/suites/nereids_rules_p0/predicate_infer/infer_predicate.groovy +++ b/regression-test/suites/nereids_rules_p0/predicate_infer/infer_predicate.groovy @@ -294,18 +294,17 @@ suite("infer_predicate") { explain shape plan select * from t1 join t2 on t1.id != t2.id where t1.id = 1; """ - // 测试 infer predicate 是否能推出正确类型, 2147483648 超过了 Int32 的最大值, 但是不超过 Int64 的最大值,用这个值测试类型是否能推导正确 qt_infer9 """ - explain shape plan select * from (select * from t1 where t1.id = 2147483648) t1 join t2 on t1.id = t2.id; + explain shape plan select * from (select * from t1 where t1.id = 12345) t1 join t2 on t1.id = t2.id; """ // 测试 cast = cast qt_infer10 """ - explain shape plan select * from (select * from t1 where t1.id = 2147483648) t1 join t2 on cast(t1.id as smallint) = cast(t2.id as smallint); + explain shape plan select * from (select * from t1 where t1.id = 12345) t1 join t2 on cast(t1.id as smallint) = cast(t2.id as smallint); """ // 测试 cast = cast qt_infer11 """ - explain shape plan select * from (select * from t1 where t1.id = 2147483648) t1 join t2 on cast(t1.id as largeint) = cast(t2.id as largeint); + explain shape plan select * from (select * from t1 where t1.id = 12345) t1 join t2 on cast(t1.id as largeint) = cast(t2.id as largeint); """ } From 559a2f99bc85f3e089c04d630493b4315acfcdc6 Mon Sep 17 00:00:00 2001 From: zzzxl Date: Fri, 13 Dec 2024 20:37:11 +0800 Subject: [PATCH 50/63] [opt](inverted index) Add NumInvertedIndexRemoteIOTotal statistics in profile (#44863) Add NumInvertedIndexRemoteIOTotal to count the number of remote IO operations in the inverted index Related PR: https://github.com/apache/doris/pull/43542 --- be/src/io/cache/block_file_cache_profile.h | 5 +++++ be/src/io/cache/cached_remote_file_reader.cpp | 8 ++++++-- be/src/io/cache/cached_remote_file_reader.h | 3 ++- be/src/io/io_common.h | 2 ++ .../segment_v2/inverted_index_compound_reader.cpp | 11 +++++++++-- .../segment_v2/inverted_index_file_reader.cpp | 13 ++++++++++--- .../rowset/segment_v2/inverted_index_file_reader.h | 5 +++-- .../rowset/segment_v2/inverted_index_fs_directory.h | 1 + .../rowset/segment_v2/inverted_index_reader.cpp | 10 +++++++--- .../fault_injection_p0/test_index_io_context.groovy | 1 - 10 files changed, 45 insertions(+), 14 deletions(-) diff --git a/be/src/io/cache/block_file_cache_profile.h b/be/src/io/cache/block_file_cache_profile.h index 19d7f4139f7f15..54118d5094cd52 100644 --- a/be/src/io/cache/block_file_cache_profile.h +++ b/be/src/io/cache/block_file_cache_profile.h @@ -75,6 +75,7 @@ struct FileCacheProfile { struct FileCacheProfileReporter { RuntimeProfile::Counter* num_local_io_total = nullptr; RuntimeProfile::Counter* num_remote_io_total = nullptr; + RuntimeProfile::Counter* num_inverted_index_remote_io_total = nullptr; RuntimeProfile::Counter* local_io_timer = nullptr; RuntimeProfile::Counter* bytes_scanned_from_cache = nullptr; RuntimeProfile::Counter* bytes_scanned_from_remote = nullptr; @@ -90,6 +91,8 @@ struct FileCacheProfileReporter { cache_profile, 1); num_remote_io_total = ADD_CHILD_COUNTER_WITH_LEVEL(profile, "NumRemoteIOTotal", TUnit::UNIT, cache_profile, 1); + num_inverted_index_remote_io_total = ADD_CHILD_COUNTER_WITH_LEVEL( + profile, "NumInvertedIndexRemoteIOTotal", TUnit::UNIT, cache_profile, 1); local_io_timer = ADD_CHILD_TIMER_WITH_LEVEL(profile, "LocalIOUseTimer", cache_profile, 1); remote_io_timer = ADD_CHILD_TIMER_WITH_LEVEL(profile, "RemoteIOUseTimer", cache_profile, 1); write_cache_io_timer = @@ -107,6 +110,8 @@ struct FileCacheProfileReporter { void update(const FileCacheStatistics* statistics) const { COUNTER_UPDATE(num_local_io_total, statistics->num_local_io_total); COUNTER_UPDATE(num_remote_io_total, statistics->num_remote_io_total); + COUNTER_UPDATE(num_inverted_index_remote_io_total, + statistics->num_inverted_index_remote_io_total); COUNTER_UPDATE(local_io_timer, statistics->local_io_timer); COUNTER_UPDATE(remote_io_timer, statistics->remote_io_timer); COUNTER_UPDATE(write_cache_io_timer, statistics->write_cache_io_timer); diff --git a/be/src/io/cache/cached_remote_file_reader.cpp b/be/src/io/cache/cached_remote_file_reader.cpp index c9a273c5d368a6..f16e0019b6dcc5 100644 --- a/be/src/io/cache/cached_remote_file_reader.cpp +++ b/be/src/io/cache/cached_remote_file_reader.cpp @@ -126,7 +126,7 @@ Status CachedRemoteFileReader::read_at_impl(size_t offset, Slice result, size_t* ReadStatistics stats; auto defer_func = [&](int*) { if (io_ctx->file_cache_stats) { - _update_state(stats, io_ctx->file_cache_stats); + _update_state(stats, io_ctx->file_cache_stats, io_ctx->is_inverted_index); io::FileCacheProfile::instance().update(io_ctx->file_cache_stats); } }; @@ -312,7 +312,8 @@ Status CachedRemoteFileReader::read_at_impl(size_t offset, Slice result, size_t* } void CachedRemoteFileReader::_update_state(const ReadStatistics& read_stats, - FileCacheStatistics* statis) const { + FileCacheStatistics* statis, + bool is_inverted_index) const { if (statis == nullptr) { return; } @@ -320,6 +321,9 @@ void CachedRemoteFileReader::_update_state(const ReadStatistics& read_stats, statis->num_local_io_total++; statis->bytes_read_from_local += read_stats.bytes_read; } else { + if (is_inverted_index) { + statis->num_inverted_index_remote_io_total++; + } statis->num_remote_io_total++; statis->bytes_read_from_remote += read_stats.bytes_read; } diff --git a/be/src/io/cache/cached_remote_file_reader.h b/be/src/io/cache/cached_remote_file_reader.h index b3efb83c0803c8..685414cfa3aba6 100644 --- a/be/src/io/cache/cached_remote_file_reader.h +++ b/be/src/io/cache/cached_remote_file_reader.h @@ -76,7 +76,8 @@ class CachedRemoteFileReader final : public FileReader { int64_t local_read_timer = 0; int64_t local_write_timer = 0; }; - void _update_state(const ReadStatistics& stats, FileCacheStatistics* state) const; + void _update_state(const ReadStatistics& stats, FileCacheStatistics* state, + bool is_inverted_index) const; }; } // namespace doris::io diff --git a/be/src/io/io_common.h b/be/src/io/io_common.h index 80a594473dc376..4acc0538b7ef4f 100644 --- a/be/src/io/io_common.h +++ b/be/src/io/io_common.h @@ -38,6 +38,7 @@ namespace io { struct FileCacheStatistics { int64_t num_local_io_total = 0; int64_t num_remote_io_total = 0; + int64_t num_inverted_index_remote_io_total = 0; int64_t local_io_timer = 0; int64_t bytes_read_from_local = 0; int64_t bytes_read_from_remote = 0; @@ -60,6 +61,7 @@ struct IOContext { int64_t expiration_time = 0; const TUniqueId* query_id = nullptr; // Ref FileCacheStatistics* file_cache_stats = nullptr; // Ref + bool is_inverted_index = false; }; } // namespace io diff --git a/be/src/olap/rowset/segment_v2/inverted_index_compound_reader.cpp b/be/src/olap/rowset/segment_v2/inverted_index_compound_reader.cpp index 60006ea84550a2..f1b2b0eaedd4fd 100644 --- a/be/src/olap/rowset/segment_v2/inverted_index_compound_reader.cpp +++ b/be/src/olap/rowset/segment_v2/inverted_index_compound_reader.cpp @@ -96,12 +96,19 @@ void CSIndexInput::readInternal(uint8_t* b, const int32_t len) { if (start + len > _length) { _CLTHROWA(CL_ERR_IO, "read past EOF"); } - base->setIoContext(_io_ctx); + + if (_io_ctx) { + base->setIoContext(_io_ctx); + } + base->setIndexFile(_is_index_file); base->seek(fileOffset + start); bool read_from_buffer = true; base->readBytes(b, len, read_from_buffer); - base->setIoContext(nullptr); + + if (_io_ctx) { + base->setIoContext(nullptr); + } } CSIndexInput::~CSIndexInput() = default; diff --git a/be/src/olap/rowset/segment_v2/inverted_index_file_reader.cpp b/be/src/olap/rowset/segment_v2/inverted_index_file_reader.cpp index 8d480829a0cd37..813a78f2a3fa86 100644 --- a/be/src/olap/rowset/segment_v2/inverted_index_file_reader.cpp +++ b/be/src/olap/rowset/segment_v2/inverted_index_file_reader.cpp @@ -27,21 +27,27 @@ namespace doris::segment_v2 { -Status InvertedIndexFileReader::init(int32_t read_buffer_size) { +Status InvertedIndexFileReader::init(int32_t read_buffer_size, const io::IOContext* io_ctx) { if (!_inited) { _read_buffer_size = read_buffer_size; if (_storage_format >= InvertedIndexStorageFormatPB::V2) { - auto st = _init_from(read_buffer_size); + auto st = _init_from(read_buffer_size, io_ctx); if (!st.ok()) { return st; } } _inited = true; + } else { + if (_storage_format == InvertedIndexStorageFormatPB::V2) { + if (_stream) { + _stream->setIoContext(io_ctx); + } + } } return Status::OK(); } -Status InvertedIndexFileReader::_init_from(int32_t read_buffer_size) { +Status InvertedIndexFileReader::_init_from(int32_t read_buffer_size, const io::IOContext* io_ctx) { auto index_file_full_path = InvertedIndexDescriptor::get_index_file_path_v2(_index_path_prefix); std::unique_lock lock(_mutex); // Lock for writing @@ -76,6 +82,7 @@ Status InvertedIndexFileReader::_init_from(int32_t read_buffer_size) { err.what()); } _stream = std::unique_ptr(index_input); + _stream->setIoContext(io_ctx); // 3. read file int32_t version = _stream->readInt(); // Read version number diff --git a/be/src/olap/rowset/segment_v2/inverted_index_file_reader.h b/be/src/olap/rowset/segment_v2/inverted_index_file_reader.h index 443d40cfaf0d4f..ed6ee85e7d7bf1 100644 --- a/be/src/olap/rowset/segment_v2/inverted_index_file_reader.h +++ b/be/src/olap/rowset/segment_v2/inverted_index_file_reader.h @@ -58,7 +58,8 @@ class InvertedIndexFileReader { _storage_format(storage_format), _idx_file_info(idx_file_info) {} - Status init(int32_t read_buffer_size = config::inverted_index_read_buffer_size); + Status init(int32_t read_buffer_size = config::inverted_index_read_buffer_size, + const io::IOContext* io_ctx = nullptr); Result> open(const TabletIndex* index_meta) const; void debug_file_entries(); std::string get_index_file_cache_key(const TabletIndex* index_meta) const; @@ -70,7 +71,7 @@ class InvertedIndexFileReader { int64_t get_inverted_file_size() const { return _stream == nullptr ? 0 : _stream->length(); } private: - Status _init_from(int32_t read_buffer_size); + Status _init_from(int32_t read_buffer_size, const io::IOContext* io_ctx); Result> _open(int64_t index_id, const std::string& index_suffix) const; diff --git a/be/src/olap/rowset/segment_v2/inverted_index_fs_directory.h b/be/src/olap/rowset/segment_v2/inverted_index_fs_directory.h index dde436054cd35b..41d9fb48356299 100644 --- a/be/src/olap/rowset/segment_v2/inverted_index_fs_directory.h +++ b/be/src/olap/rowset/segment_v2/inverted_index_fs_directory.h @@ -180,6 +180,7 @@ class DorisFSDirectory::FSIndexInput : public lucene::store::BufferedIndexInput : BufferedIndexInput(buffer_size) { this->_pos = 0; this->_handle = std::move(handle); + _io_ctx.is_inverted_index = true; } protected: diff --git a/be/src/olap/rowset/segment_v2/inverted_index_reader.cpp b/be/src/olap/rowset/segment_v2/inverted_index_reader.cpp index 889fee1fc87ef9..b40f9121125207 100644 --- a/be/src/olap/rowset/segment_v2/inverted_index_reader.cpp +++ b/be/src/olap/rowset/segment_v2/inverted_index_reader.cpp @@ -121,7 +121,8 @@ Status InvertedIndexReader::read_null_bitmap(const io::IOContext* io_ctx, if (!dir) { // TODO: ugly code here, try to refact. - auto st = _inverted_index_file_reader->init(config::inverted_index_read_buffer_size); + auto st = _inverted_index_file_reader->init(config::inverted_index_read_buffer_size, + io_ctx); if (!st.ok()) { LOG(WARNING) << st; return st; @@ -137,7 +138,6 @@ Status InvertedIndexReader::read_null_bitmap(const io::IOContext* io_ctx, InvertedIndexDescriptor::get_temporary_null_bitmap_file_name(); if (dir->fileExists(null_bitmap_file_name)) { null_bitmap_in = dir->openInput(null_bitmap_file_name); - null_bitmap_in->setIoContext(io_ctx); size_t null_bitmap_size = null_bitmap_in->length(); faststring buf; buf.resize(null_bitmap_size); @@ -180,7 +180,8 @@ Status InvertedIndexReader::handle_searcher_cache( SCOPED_RAW_TIMER(&stats->inverted_index_searcher_open_timer); IndexSearcherPtr searcher; - auto st = _inverted_index_file_reader->init(config::inverted_index_read_buffer_size); + auto st = + _inverted_index_file_reader->init(config::inverted_index_read_buffer_size, io_ctx); if (!st.ok()) { LOG(WARNING) << st; return st; @@ -211,6 +212,9 @@ Status InvertedIndexReader::create_index_searcher(lucene::store::Directory* dir, auto searcher_result = DORIS_TRY(index_searcher_builder->get_index_searcher(dir)); *searcher = searcher_result; + // When the meta information has been read, the ioContext needs to be reset to prevent it from being used by other queries. + static_cast(dir)->getDorisIndexInput()->setIoContext(nullptr); + // NOTE: before mem_tracker hook becomes active, we caculate reader memory size by hand. mem_tracker->consume(index_searcher_builder->get_reader_size()); return Status::OK(); diff --git a/regression-test/suites/fault_injection_p0/test_index_io_context.groovy b/regression-test/suites/fault_injection_p0/test_index_io_context.groovy index 9e9a2674897445..f5759e7cfc7b77 100644 --- a/regression-test/suites/fault_injection_p0/test_index_io_context.groovy +++ b/regression-test/suites/fault_injection_p0/test_index_io_context.groovy @@ -80,7 +80,6 @@ suite("test_index_io_context", "nonConcurrent") { try { GetDebugPoint().enableDebugPointForAllBEs("DorisFSDirectory::FSIndexInput::readInternal") - qt_sql """ select count() from ${tableName1} where request match_any 'ticket_quest_bg2.jpg'; """ qt_sql """ select count() from ${tableName1} where request match_any 'ticket_quest_bg2.jpg'; """ qt_sql """ select count() from ${tableName1} where request match_any 'ticket_quest_bg2.jpg'; """ From 12dcb17eedbca64e854a067d20fd04c0218eb152 Mon Sep 17 00:00:00 2001 From: Tiewei Fang Date: Sun, 15 Dec 2024 10:48:42 +0800 Subject: [PATCH 51/63] [fix](Export) Cancel the export job when the ring buffer have no enough slot (#45244) Problem Summary: If there happen exceptions in `addMemoryTask`, we must update the state of the export job to `CANCELLED` because we have added this export job in `ExportMgr`. --- .../main/java/org/apache/doris/load/ExportMgr.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/load/ExportMgr.java b/fe/fe-core/src/main/java/org/apache/doris/load/ExportMgr.java index 94ae436ee6d87d..ed6ee29bb9c969 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/load/ExportMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/load/ExportMgr.java @@ -122,8 +122,16 @@ public void addExportJobAndRegisterTask(ExportJob job) throws Exception { job.getBrokerDesc()); } // ATTN: Must add task after edit log, otherwise the job may finish before adding job. - for (int i = 0; i < job.getCopiedTaskExecutors().size(); i++) { - Env.getCurrentEnv().getTransientTaskManager().addMemoryTask(job.getCopiedTaskExecutors().get(i)); + try { + for (int i = 0; i < job.getCopiedTaskExecutors().size(); i++) { + Env.getCurrentEnv().getTransientTaskManager().addMemoryTask(job.getCopiedTaskExecutors().get(i)); + } + } catch (Exception e) { + // If there happens exceptions in `addMemoryTask` + // we must update the state of export job to `CANCELLED` + // because we have added this export in `ExportMgr` + job.updateExportJobState(ExportJobState.CANCELLED, 0L, null, + ExportFailMsg.CancelType.RUN_FAIL, e.getMessage()); } LOG.info("add export job. {}", job); } From 39f47311a0fca08b35f2ce640c1b63adff9a7957 Mon Sep 17 00:00:00 2001 From: Socrates Date: Sun, 15 Dec 2024 11:04:11 +0800 Subject: [PATCH 52/63] [Fix](hudi) Fix some errors caused by resolving code conflicts (#45355) ### What problem does this PR solve? Problem Summary: Fix some errors caused by resolving code conflicts --- .../org/apache/doris/datasource/hudi/source/HudiScanNode.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/hudi/source/HudiScanNode.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/hudi/source/HudiScanNode.java index e1dfaa40aefce1..486fdea74a00bb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/hudi/source/HudiScanNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/hudi/source/HudiScanNode.java @@ -125,8 +125,8 @@ public class HudiScanNode extends HiveScanNode { */ public HudiScanNode(PlanNodeId id, TupleDescriptor desc, boolean needCheckColumnPriv, Optional scanParams, Optional incrementalRelation, - SessionVariable sv) { - super(id, desc, "HUDI_SCAN_NODE", StatisticalType.HUDI_SCAN_NODE, needCheckColumnPriv, sv); + SessionVariable sessionVariable) { + super(id, desc, "HUDI_SCAN_NODE", StatisticalType.HUDI_SCAN_NODE, needCheckColumnPriv, sessionVariable); isCowTable = hmsTable.isHoodieCowTable(); if (LOG.isDebugEnabled()) { if (isCowTable) { From 06efb40f33b8e1b48ca50cca500b1afd866ad69e Mon Sep 17 00:00:00 2001 From: Socrates Date: Sun, 15 Dec 2024 11:24:41 +0800 Subject: [PATCH 53/63] [fix](s3) improve error msg (#45360) --- be/src/io/fs/err_utils.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/be/src/io/fs/err_utils.cpp b/be/src/io/fs/err_utils.cpp index 6552d454824796..e9bed7f5887dc3 100644 --- a/be/src/io/fs/err_utils.cpp +++ b/be/src/io/fs/err_utils.cpp @@ -122,13 +122,13 @@ Status s3fs_error(const Aws::S3::S3Error& err, std::string_view msg) { using namespace Aws::Http; switch (err.GetResponseCode()) { case HttpResponseCode::NOT_FOUND: - return Status::Error("{}: {} {} type={}, request_id={}", msg, - err.GetExceptionName(), err.GetMessage(), + return Status::Error("{}: {} {} code=NOT_FOUND, type={}, request_id={}", + msg, err.GetExceptionName(), err.GetMessage(), err.GetErrorType(), err.GetRequestId()); case HttpResponseCode::FORBIDDEN: - return Status::Error("{}: {} {} type={}, request_id={}", msg, - err.GetExceptionName(), err.GetMessage(), - err.GetErrorType(), err.GetRequestId()); + return Status::Error( + "{}: {} {} code=FORBIDDEN, type={}, request_id={}", msg, err.GetExceptionName(), + err.GetMessage(), err.GetErrorType(), err.GetRequestId()); default: return Status::Error( "{}: {} {} code={} type={}, request_id={}", msg, err.GetExceptionName(), From 1523b6a9beb7a4686629d7873db441ce42c37783 Mon Sep 17 00:00:00 2001 From: zhiqiang Date: Mon, 16 Dec 2024 01:26:34 +0800 Subject: [PATCH 54/63] [opt] Optimization for short circuit of CompoundPred (#45422) ### What problem does this PR solve? Related PR: https://github.com/apache/doris/pull/45414 Problem Summary: https://github.com/apache/doris/pull/45414 optimized short circuit of CompoundPred. But for some cases, it will introduce perf recession since AND/OR process of CompoundPred is not as efficient as Function AND/OR. Previous ```sql mysqlslap -hd3 -uroot -P9130 --create-schema=test_db -c 10 -i 100 -q "SELECT count(k) FROM sbtest1 WHERE k BETWEEN 10809931 AND 16922183 OR k BETWEEN 17788920 AND 27291942 OR k BETWEEN 23293962 AND 24940261 OR k BETWEEN 28108000 AND 28870202 OR k BETWEEN 23014347 AND 26008115 OR k BETWEEN 17817024 AND 29749077 OR k BETWEEN 8776291 AND 19869309 OR k BETWEEN 12846851 AND 15917660 OR k BETWEEN 21899521 AND 25614482 OR k BETWEEN 4850578 AND 8454295;" Benchmark Average number of seconds to run all queries: 0.315 seconds Minimum number of seconds to run all queries: 0.307 seconds Maximum number of seconds to run all queries: 0.328 seconds Number of clients running queries: 10 Average number of queries per client: 1 ``` Now ```sql mysqlslap -hd3 -uroot -P9130 --create-schema=test_db -c 10 -i 100 -q "SELECT count(k) FROM sbtest1 WHERE k BETWEEN 10809931 AND 16922183 OR k BETWEEN 17788920 AND 27291942 OR k BETWEEN 23293962 AND 24940261 OR k BETWEEN 28108000 AND 28870202 OR k BETWEEN 23014347 AND 26008115 OR k BETWEEN 17817024 AND 29749077 OR k BETWEEN 8776291 AND 19869309 OR k BETWEEN 12846851 AND 15917660 OR k BETWEEN 21899521 AND 25614482 OR k BETWEEN 4850578 AND 8454295;" Benchmark Average number of seconds to run all queries: 0.222 seconds Minimum number of seconds to run all queries: 0.215 seconds Maximum number of seconds to run all queries: 0.263 seconds Number of clients running queries: 10 Average number of queries per client: 1 ``` BTW, the performance recession only occurs when compound predicate can be short circuited in most cases. Data distribution ```sql mysql> desc sbtest1; +-------+--------------+------+-------+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-------+---------+-------+ | id | int | No | true | NULL | | | k | int | Yes | false | NULL | NONE | | c | varchar(360) | Yes | false | NULL | NONE | | pad | varchar(180) | Yes | false | NULL | NONE | +-------+--------------+------+-------+---------+-------+ 4 rows in set (0.00 sec) mysql> select count(*) from sbtest1; +----------+ | count(*) | +----------+ | 5069205 | +----------+ 1 row in set (0.02 sec) mysql> SELECT count(k) FROM sbtest1 WHERE k BETWEEN 10809931 AND 16922183; +----------+ | count(k) | +----------+ | 4726682 | +----------+ 1 row in set (0.02 sec) mysql> SELECT count(k) FROM sbtest1 WHERE k BETWEEN 10809931 AND 16922183 OR k BETWEEN 17788920 AND 27291942 OR k BETWEEN 23293962 AND 24940261 OR k BETWEEN 28108000 AND 28870202 OR k BETWEEN 23014347 AND 26008115 OR k BETWEEN 17817024 AND 29749077 OR k BETWEEN 8776291 AND 19869309 OR k BETWEEN 12846851 AND 15917660 OR k BETWEEN 21899521 AND 25614482 OR k BETWEEN 4850578 AND 8454295; +----------+ | count(k) | +----------+ | 5066731 | +----------+ 1 row in set (0.06 sec) ``` TODO: Why code is not vectorized. --- be/src/vec/exprs/vcompound_pred.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/be/src/vec/exprs/vcompound_pred.h b/be/src/vec/exprs/vcompound_pred.h index 8c65e6c8adbfef..88f3e474b58da3 100644 --- a/be/src/vec/exprs/vcompound_pred.h +++ b/be/src/vec/exprs/vcompound_pred.h @@ -234,24 +234,27 @@ class VCompoundPred : public VectorizedFnCall { auto vector_vector_null = [&]() { auto col_res = ColumnUInt8::create(size); auto col_nulls = ColumnUInt8::create(size); + auto* __restrict res_datas = assert_cast(col_res)->get_data().data(); auto* __restrict res_nulls = assert_cast(col_nulls)->get_data().data(); ColumnPtr temp_null_map = nullptr; // maybe both children are nullable / or one of children is nullable - lhs_null_map = create_null_map_column(temp_null_map, lhs_null_map); - rhs_null_map = create_null_map_column(temp_null_map, rhs_null_map); + auto* __restrict lhs_null_map_tmp = create_null_map_column(temp_null_map, lhs_null_map); + auto* __restrict rhs_null_map_tmp = create_null_map_column(temp_null_map, rhs_null_map); + auto* __restrict lhs_data_column_tmp = lhs_data_column; + auto* __restrict rhs_data_column_tmp = rhs_data_column; if constexpr (is_and_op) { for (size_t i = 0; i < size; ++i) { - res_nulls[i] = apply_and_null(lhs_data_column[i], lhs_null_map[i], - rhs_data_column[i], rhs_null_map[i]); - res_datas[i] = lhs_data_column[i] & rhs_data_column[i]; + res_nulls[i] = apply_and_null(lhs_data_column_tmp[i], lhs_null_map_tmp[i], + rhs_data_column_tmp[i], rhs_null_map_tmp[i]); + res_datas[i] = lhs_data_column_tmp[i] & rhs_data_column_tmp[i]; } } else { for (size_t i = 0; i < size; ++i) { - res_nulls[i] = apply_or_null(lhs_data_column[i], lhs_null_map[i], - rhs_data_column[i], rhs_null_map[i]); - res_datas[i] = lhs_data_column[i] | rhs_data_column[i]; + res_nulls[i] = apply_or_null(lhs_data_column_tmp[i], lhs_null_map_tmp[i], + rhs_data_column_tmp[i], rhs_null_map_tmp[i]); + res_datas[i] = lhs_data_column_tmp[i] | rhs_data_column_tmp[i]; } } auto result_column = ColumnNullable::create(std::move(col_res), std::move(col_nulls)); From b74b5c69aacbcdcc8715c8ba0f09aee0f7cc13b7 Mon Sep 17 00:00:00 2001 From: Sun Chenyang Date: Mon, 16 Dec 2024 10:42:28 +0800 Subject: [PATCH 55/63] [fix] (inverted index) fix index file in gc binlogs (#44994) Problem Summary: 1. remove duplicate function `get_segment_index_filepath` 2. fix gc binlogs --- be/src/http/action/download_binlog_action.cpp | 15 +- be/src/olap/snapshot_manager.cpp | 6 +- be/src/olap/tablet.cpp | 47 ++--- be/src/olap/tablet.h | 5 - .../task/engine_storage_migration_task.cpp | 5 +- .../common/inverted_index_gc_binlogs_test.cpp | 174 ++++++++++++++++++ 6 files changed, 213 insertions(+), 39 deletions(-) create mode 100644 be/test/olap/rowset/segment_v2/inverted_index/common/inverted_index_gc_binlogs_test.cpp diff --git a/be/src/http/action/download_binlog_action.cpp b/be/src/http/action/download_binlog_action.cpp index 372f840401c4ad..4bb8b8b70dd722 100644 --- a/be/src/http/action/download_binlog_action.cpp +++ b/be/src/http/action/download_binlog_action.cpp @@ -144,8 +144,19 @@ void handle_get_segment_index_file(StorageEngine& engine, HttpRequest* req, const auto& rowset_id = get_http_param(req, kRowsetIdParameter); const auto& segment_index = get_http_param(req, kSegmentIndexParameter); const auto& segment_index_id = req->param(kSegmentIndexIdParameter); - segment_index_file_path = - tablet->get_segment_index_filepath(rowset_id, segment_index, segment_index_id); + auto segment_file_path = tablet->get_segment_filepath(rowset_id, segment_index); + if (tablet->tablet_schema()->get_inverted_index_storage_format() == + InvertedIndexStorageFormatPB::V1) { + // now CCR not support for variant + index v1 + constexpr std::string_view index_suffix = ""; + segment_index_file_path = InvertedIndexDescriptor::get_index_file_path_v1( + InvertedIndexDescriptor::get_index_file_path_prefix(segment_file_path), + std::stoll(segment_index_id), index_suffix); + } else { + DCHECK(segment_index_id == "-1"); + segment_index_file_path = InvertedIndexDescriptor::get_index_file_path_v2( + InvertedIndexDescriptor::get_index_file_path_prefix(segment_file_path)); + } is_acquire_md5 = !req->param(kAcquireMD5Parameter).empty(); } catch (const std::exception& e) { HttpChannel::send_reply(req, HttpStatus::INTERNAL_SERVER_ERROR, e.what()); diff --git a/be/src/olap/snapshot_manager.cpp b/be/src/olap/snapshot_manager.cpp index 67205835b53947..8202feb68c65b5 100644 --- a/be/src/olap/snapshot_manager.cpp +++ b/be/src/olap/snapshot_manager.cpp @@ -700,8 +700,10 @@ Status SnapshotManager::_create_snapshot_files(const TabletSharedPtr& ref_tablet InvertedIndexStorageFormatPB::V1) { for (const auto& index : tablet_schema.inverted_indexes()) { auto index_id = index->index_id(); - auto index_file = ref_tablet->get_segment_index_filepath( - rowset_id, segment_index, index_id); + auto index_file = InvertedIndexDescriptor::get_index_file_path_v1( + InvertedIndexDescriptor::get_index_file_path_prefix( + segment_file_path), + index_id, index->get_index_suffix()); auto snapshot_segment_index_file_path = fmt::format("{}/{}_{}_{}.binlog-index", schema_full_path, rowset_id, segment_index, index_id); diff --git a/be/src/olap/tablet.cpp b/be/src/olap/tablet.cpp index 705d0ad53097e8..c7919b3f8dca24 100644 --- a/be/src/olap/tablet.cpp +++ b/be/src/olap/tablet.cpp @@ -2615,30 +2615,6 @@ std::string Tablet::get_segment_filepath(std::string_view rowset_id, int64_t seg return fmt::format("{}/_binlog/{}_{}.dat", _tablet_path, rowset_id, segment_index); } -std::string Tablet::get_segment_index_filepath(std::string_view rowset_id, - std::string_view segment_index, - std::string_view index_id) const { - auto format = _tablet_meta->tablet_schema()->get_inverted_index_storage_format(); - if (format == doris::InvertedIndexStorageFormatPB::V1) { - return fmt::format("{}/_binlog/{}_{}_{}.idx", _tablet_path, rowset_id, segment_index, - index_id); - } else { - return fmt::format("{}/_binlog/{}_{}.idx", _tablet_path, rowset_id, segment_index); - } -} - -std::string Tablet::get_segment_index_filepath(std::string_view rowset_id, int64_t segment_index, - int64_t index_id) const { - auto format = _tablet_meta->tablet_schema()->get_inverted_index_storage_format(); - if (format == doris::InvertedIndexStorageFormatPB::V1) { - return fmt::format("{}/_binlog/{}_{}_{}.idx", _tablet_path, rowset_id, segment_index, - index_id); - } else { - DCHECK(index_id == -1); - return fmt::format("{}/_binlog/{}_{}.idx", _tablet_path, rowset_id, segment_index); - } -} - std::vector Tablet::get_binlog_filepath(std::string_view binlog_version) const { const auto& [rowset_id, num_segments] = get_binlog_info(binlog_version); std::vector binlog_filepath; @@ -2683,10 +2659,25 @@ void Tablet::gc_binlogs(int64_t version) { // add binlog segment files and index files for (int64_t i = 0; i < num_segments; ++i) { - wait_for_deleted_binlog_files.emplace_back(get_segment_filepath(rowset_id, i)); - for (const auto& index : this->tablet_schema()->inverted_indexes()) { - wait_for_deleted_binlog_files.emplace_back( - get_segment_index_filepath(rowset_id, i, index->index_id())); + auto segment_file_path = get_segment_filepath(rowset_id, i); + wait_for_deleted_binlog_files.emplace_back(segment_file_path); + + // index files + if (tablet_schema()->has_inverted_index()) { + if (tablet_schema()->get_inverted_index_storage_format() == + InvertedIndexStorageFormatPB::V1) { + for (const auto& index : tablet_schema()->inverted_indexes()) { + auto index_file = InvertedIndexDescriptor::get_index_file_path_v1( + InvertedIndexDescriptor::get_index_file_path_prefix( + segment_file_path), + index->index_id(), index->get_index_suffix()); + wait_for_deleted_binlog_files.emplace_back(index_file); + } + } else { + auto index_file = InvertedIndexDescriptor::get_index_file_path_v2( + InvertedIndexDescriptor::get_index_file_path_prefix(segment_file_path)); + wait_for_deleted_binlog_files.emplace_back(index_file); + } } } }; diff --git a/be/src/olap/tablet.h b/be/src/olap/tablet.h index 40b911d6391b9b..d00476f044191c 100644 --- a/be/src/olap/tablet.h +++ b/be/src/olap/tablet.h @@ -441,11 +441,6 @@ class Tablet final : public BaseTablet { std::string get_segment_filepath(std::string_view rowset_id, std::string_view segment_index) const; std::string get_segment_filepath(std::string_view rowset_id, int64_t segment_index) const; - std::string get_segment_index_filepath(std::string_view rowset_id, - std::string_view segment_index, - std::string_view index_id) const; - std::string get_segment_index_filepath(std::string_view rowset_id, int64_t segment_index, - int64_t index_id) const; bool can_add_binlog(uint64_t total_binlog_size) const; void gc_binlogs(int64_t version); Status ingest_binlog_metas(RowsetBinlogMetasPB* metas_pb); diff --git a/be/src/olap/task/engine_storage_migration_task.cpp b/be/src/olap/task/engine_storage_migration_task.cpp index a300e6e0f09fa3..210aa6a8c56f08 100644 --- a/be/src/olap/task/engine_storage_migration_task.cpp +++ b/be/src/olap/task/engine_storage_migration_task.cpp @@ -409,8 +409,9 @@ Status EngineStorageMigrationTask::_copy_index_and_data_files( InvertedIndexStorageFormatPB::V1) { for (const auto& index : tablet_schema.inverted_indexes()) { auto index_id = index->index_id(); - auto index_file = - _tablet->get_segment_index_filepath(rowset_id, segment_index, index_id); + auto index_file = InvertedIndexDescriptor::get_index_file_path_v1( + InvertedIndexDescriptor::get_index_file_path_prefix(segment_file_path), + index_id, index->get_index_suffix()); auto snapshot_segment_index_file_path = fmt::format("{}/{}_{}_{}.binlog-index", full_path, rowset_id, segment_index, index_id); diff --git a/be/test/olap/rowset/segment_v2/inverted_index/common/inverted_index_gc_binlogs_test.cpp b/be/test/olap/rowset/segment_v2/inverted_index/common/inverted_index_gc_binlogs_test.cpp new file mode 100644 index 00000000000000..84f82b8f46e302 --- /dev/null +++ b/be/test/olap/rowset/segment_v2/inverted_index/common/inverted_index_gc_binlogs_test.cpp @@ -0,0 +1,174 @@ +// 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. + +#include + +#include "olap/rowset/beta_rowset_writer.h" +#include "olap/rowset/rowset_factory.h" +#include "olap/rowset/rowset_meta_manager.h" +#include "olap/storage_engine.h" + +namespace doris { + +using namespace doris::vectorized; + +constexpr static uint32_t MAX_PATH_LEN = 1024; +constexpr static std::string_view dest_dir = "./ut_dir/inverted_index_test"; +constexpr static std::string_view tmp_dir = "./ut_dir/tmp"; +static int64_t inc_id = 0; + +class IndexGcBinglogsTest : public ::testing::Test { +protected: + void SetUp() override { + // absolute dir + char buffer[MAX_PATH_LEN]; + EXPECT_NE(getcwd(buffer, MAX_PATH_LEN), nullptr); + _curreent_dir = std::string(buffer); + _absolute_dir = _curreent_dir + std::string(dest_dir); + EXPECT_TRUE(io::global_local_filesystem()->delete_directory(_absolute_dir).ok()); + EXPECT_TRUE(io::global_local_filesystem()->create_directory(_absolute_dir).ok()); + + // tmp dir + EXPECT_TRUE(io::global_local_filesystem()->delete_directory(tmp_dir).ok()); + EXPECT_TRUE(io::global_local_filesystem()->create_directory(tmp_dir).ok()); + std::vector paths; + paths.emplace_back(std::string(tmp_dir), 1024000000); + auto tmp_file_dirs = std::make_unique(paths); + EXPECT_TRUE(tmp_file_dirs->init().ok()); + ExecEnv::GetInstance()->set_tmp_file_dir(std::move(tmp_file_dirs)); + + // storage engine + doris::EngineOptions options; + auto engine = std::make_unique(options); + _engine_ref = engine.get(); + _data_dir = std::make_unique(*_engine_ref, _absolute_dir); + static_cast(_data_dir->update_capacity()); + EXPECT_TRUE(_data_dir->init(true).ok()); + ExecEnv::GetInstance()->set_storage_engine(std::move(engine)); + + // tablet_schema + TabletSchemaPB schema_pb; + _schema_pb.set_keys_type(KeysType::DUP_KEYS); + _schema_pb.set_inverted_index_storage_format(InvertedIndexStorageFormatPB::V2); + + construct_column(_schema_pb.add_column(), _schema_pb.add_index(), 10000, "key_index", 0, + "INT", "key"); + construct_column(_schema_pb.add_column(), _schema_pb.add_index(), 10001, "v1_index", 1, + "STRING", "v1"); + } + void TearDown() override { + EXPECT_TRUE(io::global_local_filesystem()->delete_directory(_tablet->tablet_path()).ok()); + EXPECT_TRUE(io::global_local_filesystem()->delete_directory(_absolute_dir).ok()); + EXPECT_TRUE(io::global_local_filesystem()->delete_directory(tmp_dir).ok()); + _engine_ref = nullptr; + ExecEnv::GetInstance()->set_storage_engine(nullptr); + } + + void construct_column(ColumnPB* column_pb, TabletIndexPB* tablet_index, int64_t index_id, + const std::string& index_name, int32_t col_unique_id, + const std::string& column_type, const std::string& column_name, + bool parser = false) { + column_pb->set_unique_id(col_unique_id); + column_pb->set_name(column_name); + column_pb->set_type(column_type); + column_pb->set_is_key(false); + column_pb->set_is_nullable(true); + tablet_index->set_index_id(index_id); + tablet_index->set_index_name(index_name); + tablet_index->set_index_type(IndexType::INVERTED); + tablet_index->add_col_unique_id(col_unique_id); + if (parser) { + auto* properties = tablet_index->mutable_properties(); + (*properties)[INVERTED_INDEX_PARSER_KEY] = INVERTED_INDEX_PARSER_UNICODE; + } + } + + RowsetWriterContext rowset_writer_context() { + RowsetWriterContext context; + RowsetId rowset_id; + rowset_id.init(inc_id); + context.rowset_id = rowset_id; + context.rowset_type = BETA_ROWSET; + context.data_dir = _data_dir.get(); + context.rowset_state = VISIBLE; + context.tablet_schema = _tablet_schema; + context.tablet_path = _tablet->tablet_path(); + context.version = Version(inc_id, inc_id); + context.max_rows_per_segment = 200; + inc_id++; + return context; + } + + IndexGcBinglogsTest() = default; + ~IndexGcBinglogsTest() override = default; + +private: + TabletSchemaSPtr _tablet_schema = nullptr; + StorageEngine* _engine_ref = nullptr; + std::unique_ptr _data_dir = nullptr; + TabletSharedPtr _tablet = nullptr; + std::string _absolute_dir; + std::string _curreent_dir; + TabletSchemaPB _schema_pb; +}; + +TEST_F(IndexGcBinglogsTest, gc_binlogs_test) { + auto test = [&](InvertedIndexStorageFormatPB format) { + TabletSchemaPB schema_pb = _schema_pb; + _schema_pb.set_inverted_index_storage_format(format); + _tablet_schema.reset(new TabletSchema); + _tablet_schema->init_from_pb(schema_pb); + TabletMetaSharedPtr tablet_meta(new TabletMeta(_tablet_schema)); + + tablet_meta->set_tablet_uid(TabletUid(20, 20)); + tablet_meta.get()->_tablet_id = 200; + _tablet.reset(new Tablet(*_engine_ref, tablet_meta, _data_dir.get())); + EXPECT_TRUE(_tablet->init().ok()); + EXPECT_TRUE(io::global_local_filesystem()->delete_directory(_tablet->tablet_path()).ok()); + EXPECT_TRUE(io::global_local_filesystem()->create_directory(_tablet->tablet_path()).ok()); + + RowsetSharedPtr rowset; + const auto& res = + RowsetFactory::create_rowset_writer(*_engine_ref, rowset_writer_context(), false); + EXPECT_TRUE(res.has_value()) << res.error(); + const auto& rowset_writer = res.value(); + + Block block = _tablet_schema->create_block(); + auto columns = block.mutate_columns(); + + vectorized::Field key = 10; + vectorized::Field v1 = "v1"; + columns[0]->insert(key); + columns[1]->insert(v1); + + EXPECT_TRUE(rowset_writer->add_block(&block).ok()); + EXPECT_TRUE(rowset_writer->flush().ok()); + EXPECT_TRUE(rowset_writer->build(rowset).ok()); + EXPECT_TRUE(rowset->add_to_binlog().ok()); + EXPECT_TRUE(_tablet->add_rowset(rowset).ok()); + EXPECT_TRUE(RowsetMetaManager::save(_data_dir->get_meta(), _tablet->tablet_uid(), + rowset->rowset_id(), + rowset->rowset_meta()->get_rowset_pb(), true) + .ok()); + _tablet->save_meta(); + _tablet->gc_binlogs(0); + }; + test(InvertedIndexStorageFormatPB::V1); + test(InvertedIndexStorageFormatPB::V2); +} + +} // namespace doris From 0c97e0470f20a85f27d9d63673f1f3b44a82f164 Mon Sep 17 00:00:00 2001 From: HappenLee Date: Mon, 16 Dec 2024 10:52:10 +0800 Subject: [PATCH 56/63] [Exec](expr) Opt the compound pred performace (#45414) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit before: ``` mysqlslap -hd3 -uroot -P9130 --create-schema=test_db2 -c 10 -i 500 -q "SELECT count(k) FROM sbtest1_dup WHERE k BETWEEN 4850578 AND 8454295 OR k BETWEEN 8776291 AND 29749077;" Benchmark Average number of seconds to run all queries: 0.041 seconds Minimum number of seconds to run all queries: 0.037 seconds Maximum number of seconds to run all queries: 0.115 seconds Number of clients running queries: 10 Average number of queries per client: 1 ``` after: ``` mysqlslap -hd3 -uroot -P9030 --create-schema=test_db -c 10 -i 500 -q "SELECT count(k) FROM sbtest1 WHERE k BETWEEN 4850578 AND 8454295 OR k BETWEEN 8776291 AND 29749077;" Benchmark Average number of seconds to run all queries: 0.029 seconds Minimum number of seconds to run all queries: 0.027 seconds Maximum number of seconds to run all queries: 0.034 seconds Number of clients running queries: 10 Average number of queries per client: 1 ``` --- be/src/vec/exprs/vcompound_pred.h | 82 ++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/be/src/vec/exprs/vcompound_pred.h b/be/src/vec/exprs/vcompound_pred.h index 88f3e474b58da3..8c6832a7a35a37 100644 --- a/be/src/vec/exprs/vcompound_pred.h +++ b/be/src/vec/exprs/vcompound_pred.h @@ -158,12 +158,15 @@ class VCompoundPred : public VectorizedFnCall { if (_can_fast_execute && fast_execute(context, block, result_column_id)) { return Status::OK(); } - if (get_num_children() == 1 || !_all_child_is_compound_and_not_const()) { + if (get_num_children() == 1 || _has_const_child()) { return VectorizedFnCall::execute(context, block, result_column_id); } int lhs_id = -1; int rhs_id = -1; + bool lhs_mem_can_reuse = _children[0]->is_compound_predicate(); + bool rhs_mem_can_reuse = _children[1]->is_compound_predicate(); + RETURN_IF_ERROR(_children[0]->execute(context, block, &lhs_id)); ColumnPtr lhs_column = block->get_by_position(lhs_id).column->convert_to_full_column_if_const(); @@ -210,13 +213,22 @@ class VCompoundPred : public VectorizedFnCall { return Status::OK(); }; - auto return_result_column_id = [&](ColumnPtr res_column, int res_id) -> int { + auto return_result_column_id = [&](ColumnPtr res_column, int res_id, + bool mem_reuse) -> int { + if (!mem_reuse) { + res_column = res_column->clone_resized(size); + } + if (result_is_nullable && !res_column->is_nullable()) { auto result_column = ColumnNullable::create(res_column, ColumnUInt8::create(size, 0)); res_id = block->columns(); block->insert({std::move(result_column), _data_type, _expr_name}); + } else if (!mem_reuse) { + res_id = block->columns(); + block->insert({std::move(res_column), _data_type, _expr_name}); } + return res_id; }; @@ -231,6 +243,33 @@ class VCompoundPred : public VectorizedFnCall { return null_map_data; }; + auto vector_vector = [&]() { + if (lhs_mem_can_reuse) { + *result_column_id = lhs_id; + } else if (rhs_mem_can_reuse) { + *result_column_id = rhs_id; + + auto tmp_column = rhs_data_column; + rhs_data_column = lhs_data_column; + lhs_data_column = tmp_column; + } else { + *result_column_id = block->columns(); + + auto col_res = lhs_column->clone_resized(size); + lhs_data_column = assert_cast(col_res.get())->get_data().data(); + block->insert({std::move(col_res), _data_type, _expr_name}); + } + + if constexpr (is_and_op) { + for (size_t i = 0; i < size; ++i) { + lhs_data_column[i] &= rhs_data_column[i]; + } + } else { + for (size_t i = 0; i < size; ++i) { + lhs_data_column[i] |= rhs_data_column[i]; + } + } + }; auto vector_vector_null = [&]() { auto col_res = ColumnUInt8::create(size); auto col_nulls = ColumnUInt8::create(size); @@ -269,28 +308,28 @@ class VCompoundPred : public VectorizedFnCall { //2. nullable column: null map all is not null if ((lhs_all_false && !lhs_is_nullable) || (lhs_all_false && lhs_all_is_not_null)) { // false and any = false, return lhs - *result_column_id = return_result_column_id(lhs_column, lhs_id); + *result_column_id = return_result_column_id(lhs_column, lhs_id, lhs_mem_can_reuse); } else { RETURN_IF_ERROR(get_rhs_colum()); if ((lhs_all_true && !lhs_is_nullable) || //not null column (lhs_all_true && lhs_all_is_not_null)) { //nullable column // true and any = any, return rhs - *result_column_id = return_result_column_id(rhs_column, rhs_id); + *result_column_id = + return_result_column_id(rhs_column, rhs_id, rhs_mem_can_reuse); } else if ((rhs_all_false && !rhs_is_nullable) || (rhs_all_false && rhs_all_is_not_null)) { // any and false = false, return rhs - *result_column_id = return_result_column_id(rhs_column, rhs_id); + *result_column_id = + return_result_column_id(rhs_column, rhs_id, rhs_mem_can_reuse); } else if ((rhs_all_true && !rhs_is_nullable) || (rhs_all_true && rhs_all_is_not_null)) { // any and true = any, return lhs - *result_column_id = return_result_column_id(lhs_column, lhs_id); + *result_column_id = + return_result_column_id(lhs_column, lhs_id, lhs_mem_can_reuse); } else { if (!result_is_nullable) { - *result_column_id = lhs_id; - for (size_t i = 0; i < size; i++) { - lhs_data_column[i] &= rhs_data_column[i]; - } + vector_vector.template operator()(); } else { vector_vector_null.template operator()(); } @@ -301,26 +340,26 @@ class VCompoundPred : public VectorizedFnCall { // false or NULL ----> NULL if ((lhs_all_true && !lhs_is_nullable) || (lhs_all_true && lhs_all_is_not_null)) { // true or any = true, return lhs - *result_column_id = return_result_column_id(lhs_column, lhs_id); + *result_column_id = return_result_column_id(lhs_column, lhs_id, lhs_mem_can_reuse); } else { RETURN_IF_ERROR(get_rhs_colum()); if ((lhs_all_false && !lhs_is_nullable) || (lhs_all_false && lhs_all_is_not_null)) { // false or any = any, return rhs - *result_column_id = return_result_column_id(rhs_column, rhs_id); + *result_column_id = + return_result_column_id(rhs_column, rhs_id, rhs_mem_can_reuse); } else if ((rhs_all_true && !rhs_is_nullable) || (rhs_all_true && rhs_all_is_not_null)) { // any or true = true, return rhs - *result_column_id = return_result_column_id(rhs_column, rhs_id); + *result_column_id = + return_result_column_id(rhs_column, rhs_id, rhs_mem_can_reuse); } else if ((rhs_all_false && !rhs_is_nullable) || (rhs_all_false && rhs_all_is_not_null)) { // any or false = any, return lhs - *result_column_id = return_result_column_id(lhs_column, lhs_id); + *result_column_id = + return_result_column_id(lhs_column, lhs_id, lhs_mem_can_reuse); } else { if (!result_is_nullable) { - *result_column_id = lhs_id; - for (size_t i = 0; i < size; i++) { - lhs_data_column[i] |= rhs_data_column[i]; - } + vector_vector.template operator()(); } else { vector_vector_null.template operator()(); } @@ -345,10 +384,9 @@ class VCompoundPred : public VectorizedFnCall { return (l_null & r_null) | (r_null & (r_null ^ a)) | (l_null & (l_null ^ b)); } - bool _all_child_is_compound_and_not_const() const { - return std::ranges::all_of(_children, [](const VExprSPtr& arg) -> bool { - return arg->is_compound_predicate() && !arg->is_constant(); - }); + bool _has_const_child() const { + return std::ranges::any_of(_children, + [](const VExprSPtr& arg) -> bool { return arg->is_constant(); }); } std::pair _get_raw_data_and_null_map(ColumnPtr column, From 26b2aab80039dbb7831f2d7bd90ea39918b37d89 Mon Sep 17 00:00:00 2001 From: zhangstar333 Date: Mon, 16 Dec 2024 11:10:39 +0800 Subject: [PATCH 57/63] [Bug](function) fix repeat function result length is invalid and cause overflow (#45288) ### What problem does this PR solve? Problem Summary: `repeat('a', k1)`, if k1 is nullable column when execute repeat function, input column is nested column of k1 so if k1 is NULL value, the nested value maybe not inited and invalid, cause the result length is large and overflow --- be/src/vec/functions/function_string.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/be/src/vec/functions/function_string.h b/be/src/vec/functions/function_string.h index 6e4a18fdd3100e..fba8b914eee682 100644 --- a/be/src/vec/functions/function_string.h +++ b/be/src/vec/functions/function_string.h @@ -1525,6 +1525,9 @@ class FunctionStringRepeat : public IFunction { static FunctionPtr create() { return std::make_shared(); } String get_name() const override { return name; } size_t get_number_of_arguments() const override { return 2; } + // should set NULL value of nested data to default, + // as iff it's not inited and invalid, the repeat result of length is so large cause overflow + bool need_replace_null_data_to_default() const override { return true; } DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { return make_nullable(std::make_shared()); From 4a914fe1b88c9477b95414ef48880e3f59e0f854 Mon Sep 17 00:00:00 2001 From: wangbo Date: Mon, 16 Dec 2024 11:17:01 +0800 Subject: [PATCH 58/63] [Fix](case) remove useless test (#45409) --- be/src/agent/workload_group_listener.cpp | 1 + be/src/agent/workload_group_listener.h | 3 +- .../test_workload_sched_policy.groovy | 57 ------------------- 3 files changed, 3 insertions(+), 58 deletions(-) diff --git a/be/src/agent/workload_group_listener.cpp b/be/src/agent/workload_group_listener.cpp index 7b688b7dcdf6ef..0cd5a3ee1ac748 100644 --- a/be/src/agent/workload_group_listener.cpp +++ b/be/src/agent/workload_group_listener.cpp @@ -17,6 +17,7 @@ #include "agent/workload_group_listener.h" +#include "runtime/exec_env.h" #include "runtime/workload_group/workload_group.h" #include "runtime/workload_group/workload_group_manager.h" #include "util/mem_info.h" diff --git a/be/src/agent/workload_group_listener.h b/be/src/agent/workload_group_listener.h index f596535908d079..9578a36f70d63e 100644 --- a/be/src/agent/workload_group_listener.h +++ b/be/src/agent/workload_group_listener.h @@ -20,10 +20,11 @@ #include #include "agent/topic_listener.h" -#include "runtime/exec_env.h" namespace doris { +class ExecEnv; + class WorkloadGroupListener : public TopicListener { public: ~WorkloadGroupListener() {} diff --git a/regression-test/suites/workload_manager_p0/test_workload_sched_policy.groovy b/regression-test/suites/workload_manager_p0/test_workload_sched_policy.groovy index 06e10688397689..ca18c5a17e0f56 100644 --- a/regression-test/suites/workload_manager_p0/test_workload_sched_policy.groovy +++ b/regression-test/suites/workload_manager_p0/test_workload_sched_policy.groovy @@ -235,61 +235,4 @@ suite("test_workload_sched_policy") { sql "drop user test_alter_policy_user" sql "drop workload policy test_alter_policy" - - // daemon thread alter test - def thread1 = new Thread({ - def startTime = System.currentTimeMillis() - def curTime = System.currentTimeMillis() - def totalTime = 30 * 60 * 1000 // 30min - - connect('test_policy_user', '12345', context.config.jdbcUrl) { - sql "set workload_group=policy_group" - boolean flag = false - long lastTime = System.currentTimeMillis() - - while (curTime - startTime <= totalTime) { - if (curTime - lastTime > 20000) { - if (flag) { - connect('root', '', context.config.jdbcUrl) { - sql "alter workload policy test_cancel_query_policy properties('workload_group'='policy_group2');" - sql "alter workload policy test_cancel_query_policy2 properties('workload_group'='policy_group');" - } - flag = false - } else { - connect('root', '', context.config.jdbcUrl) { - sql "alter workload policy test_cancel_query_policy properties('workload_group'='policy_group');" - sql "alter workload policy test_cancel_query_policy2 properties('workload_group'='policy_group2');" - } - flag = true - } - lastTime = System.currentTimeMillis() - } - try { - sql "select k0 as policy_test_tag,k1,k2,k3,k4,k5,k6,count(distinct k13) from regression_test_load_p0_insert.baseall group by k0,k1,k2,k3,k4,k5,k6" - } catch (Exception e) { - boolean ret = e.getMessage().contains("cancelled by workload policy") - if (!ret) { - logger.info("policy_test_tag " + e.getMessage()) - } - assertTrue(ret, "policy daemon check failed") - } - - try { - sql "select count(1) as policy_test_tag from regression_test_load_p0_insert.baseall" - } catch (Exception e) { - boolean ret = e.getMessage().contains("cancelled by workload policy") - if (!ret) { - logger.info("policy_test_tag " + e.getMessage()) - } - assertTrue(ret, "policy daemon check failed") - } - - Thread.sleep(1000) - curTime = System.currentTimeMillis() - } - } - }) - thread1.setDaemon(true) - thread1.start() - } \ No newline at end of file From 8058085c5b822066e5c806570ff2756fd4ae07ba Mon Sep 17 00:00:00 2001 From: minghong Date: Mon, 16 Dec 2024 11:31:16 +0800 Subject: [PATCH 59/63] [feat](nereids) add is_merge tag for data sink (#45196) ### What problem does this PR solve? set is_merge true, if its corresponding exchange node contains sortInfo. BE use this flag to accelerate data transferring. it is better to determine this by FE than that by BE. for example, if data spill to disk, the node before sink is scan, not sort. --- .../nereids/glue/translator/PhysicalPlanTranslator.java | 6 ++++++ .../src/main/java/org/apache/doris/planner/DataSink.java | 9 +++++++++ .../java/org/apache/doris/planner/DataStreamSink.java | 4 ++++ gensrc/thrift/DataSinks.thrift | 1 + 4 files changed, 20 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java index d66ff3ebb7649d..f0fa59977a1902 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java @@ -2147,6 +2147,9 @@ public PlanFragment visitPhysicalQuickSort(PhysicalQuickSort sor } SortNode sortNode = (SortNode) inputFragment.getPlanRoot().getChild(0); ((ExchangeNode) inputFragment.getPlanRoot()).setMergeInfo(sortNode.getSortInfo()); + if (inputFragment.hasChild(0) && inputFragment.getChild(0).getSink() != null) { + inputFragment.getChild(0).getSink().setMerge(true); + } sortNode.setMergeByExchange(); sortNode.setChildrenDistributeExprLists(distributeExprLists); } @@ -2198,6 +2201,9 @@ public PlanFragment visitPhysicalTopN(PhysicalTopN topN, PlanTra ExchangeNode exchangeNode = (ExchangeNode) inputFragment.getPlanRoot(); exchangeNode.setChildrenDistributeExprLists(distributeExprLists); exchangeNode.setMergeInfo(((SortNode) exchangeNode.getChild(0)).getSortInfo()); + if (inputFragment.hasChild(0) && inputFragment.getChild(0).getSink() != null) { + inputFragment.getChild(0).getSink().setMerge(true); + } exchangeNode.setLimit(topN.getLimit()); exchangeNode.setOffset(topN.getOffset()); ((SortNode) exchangeNode.getChild(0)).setMergeByExchange(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/DataSink.java b/fe/fe-core/src/main/java/org/apache/doris/planner/DataSink.java index 8d6daa2f8b72b4..320fcae9eb0f1e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/DataSink.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/DataSink.java @@ -39,6 +39,7 @@ public abstract class DataSink { // Fragment that this DataSink belongs to. Set by the PlanFragment enclosing this sink. protected PlanFragment fragment; + protected boolean isMerge = false; /** * Return an explain string for the DataSink. Each line of the explain will be @@ -77,4 +78,12 @@ public static DataSink createDataSink(TableIf table) throws AnalysisException { throw new AnalysisException("Unknown table type " + table.getType()); } } + + public boolean isMerge() { + return isMerge; + } + + public void setMerge(boolean merge) { + isMerge = merge; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/DataStreamSink.java b/fe/fe-core/src/main/java/org/apache/doris/planner/DataStreamSink.java index ef42190fa25004..ceda692aa4b01f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/DataStreamSink.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/DataStreamSink.java @@ -176,6 +176,9 @@ public String getExplainString(String prefix, TExplainLevel explainLevel) { strBuilder.append(prefix).append(" PROJECTION TUPLE: ").append(outputTupleDesc.getId()); strBuilder.append("\n"); } + if (isMerge) { + strBuilder.append("IS_MERGE: true\n"); + } return strBuilder.toString(); } @@ -234,6 +237,7 @@ protected TDataSink toThrift() { tStreamSink.addToTabletSinkExprs(expr.treeToThrift()); } } + tStreamSink.setIsMerge(isMerge); tStreamSink.setTabletSinkTxnId(tabletSinkTxnId); result.setStreamSink(tStreamSink); return result; diff --git a/gensrc/thrift/DataSinks.thrift b/gensrc/thrift/DataSinks.thrift index ed7ccee69cd9a1..03a23c2c532ac3 100644 --- a/gensrc/thrift/DataSinks.thrift +++ b/gensrc/thrift/DataSinks.thrift @@ -189,6 +189,7 @@ struct TDataStreamSink { 11: optional i64 tablet_sink_txn_id 12: optional Types.TTupleId tablet_sink_tuple_id 13: optional list tablet_sink_exprs + 14: optional bool is_merge } struct TMultiCastDataStreamSink { From fe8fa8709415025d0da484942e003f9446fecf1b Mon Sep 17 00:00:00 2001 From: Pxl Date: Mon, 16 Dec 2024 12:11:09 +0800 Subject: [PATCH 60/63] [Bug](function) fix wrong result on group_concat with distinct+order_by+nullable (#45313) fix wrong result on group_concat with distinct+order_by+nullable --- .../aggregate_functions/aggregate_function.h | 6 +- .../aggregate_function_distinct.h | 16 ++++- .../aggregate_function_null.h | 39 ++++++++++-- .../aggregate_function_sort.h | 4 +- .../nereids_p0/aggregate/agg_group_concat.out | 4 ++ .../aggregate/agg_group_concat.groovy | 61 +++++++++++-------- 6 files changed, 91 insertions(+), 39 deletions(-) create mode 100644 regression-test/data/nereids_p0/aggregate/agg_group_concat.out diff --git a/be/src/vec/aggregate_functions/aggregate_function.h b/be/src/vec/aggregate_functions/aggregate_function.h index e0ec2bef62fc2a..d761d40c4c932c 100644 --- a/be/src/vec/aggregate_functions/aggregate_function.h +++ b/be/src/vec/aggregate_functions/aggregate_function.h @@ -20,6 +20,8 @@ #pragma once +#include + #include "common/exception.h" #include "common/status.h" #include "util/defer_op.h" @@ -81,7 +83,7 @@ using ConstAggregateDataPtr = const char*; */ class IAggregateFunction { public: - IAggregateFunction(const DataTypes& argument_types_) : argument_types(argument_types_) {} + IAggregateFunction(DataTypes argument_types_) : argument_types(std::move(argument_types_)) {} /// Get main function name. virtual String get_name() const = 0; @@ -225,7 +227,7 @@ class IAggregateFunction { virtual void set_version(const int version_) { version = version_; } - virtual AggregateFunctionPtr transmit_to_stable() { return nullptr; } + virtual IAggregateFunction* transmit_to_stable() { return nullptr; } /// Verify function signature virtual Status verify_result_type(const bool without_key, const DataTypes& argument_types, diff --git a/be/src/vec/aggregate_functions/aggregate_function_distinct.h b/be/src/vec/aggregate_functions/aggregate_function_distinct.h index 46450394627474..a5515145d9d2ad 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_distinct.h +++ b/be/src/vec/aggregate_functions/aggregate_function_distinct.h @@ -341,12 +341,22 @@ class AggregateFunctionDistinct DataTypePtr get_return_type() const override { return nested_func->get_return_type(); } - AggregateFunctionPtr transmit_to_stable() override { - return AggregateFunctionPtr(new AggregateFunctionDistinct( - nested_func, IAggregateFunction::argument_types)); + IAggregateFunction* transmit_to_stable() override { + return new AggregateFunctionDistinct(nested_func, + IAggregateFunction::argument_types); } }; +template +struct FunctionStableTransfer { + using FunctionStable = T; +}; + +template