text:
<?php

namespace common\traits;

use Yii;
use yii\helpers\ArrayHelper;
use common\models\Language;
use common\models\Translate;

trait TranslateTrait
{
    // abstract public static function tableName();
    // abstract public function getPrimaryKey($asArray = false);

    public static function transTableName($tableName = '')
    {
        if (empty($tableName)) $tableName = static::tableName();
        return str_replace(['{{%', '}}'], ['', ''], $tableName);
    }

    public function getTranslate()
    {
        return $this->hasMany(Translate::className(), ['table_id' => 'id'])->andOnCondition(['table_name' => static::transTableName()]);
    }

    public function getTranslated()
    {
        return $this->hasMany(Translate::className(), ['table_id' => 'id'])->andOnCondition(['table_name' => static::transTableName(), 'language' => Yii::$app->language]);
    }

    public function translatedField($field, $default = null)
    {
        $query = Translate::find()->where([
            'table_name' => static::transTableName(),
            'table_id' => $this->getPrimaryKey(),
            'table_field' => $field,
            'language' => Yii::$app->language,
        ])->asArray()->one();

        if ($query) {
            return $query['field_value'];
        } else {
            return $default;
        }
    }

    public function saveTranslate($data)
    {
        if (is_array($data) && $data) {
            foreach ($data as $langKey => $val) {
                if (is_array($val) && $val) {
                    foreach ($val as $field => $value) {
                        if (is_array($value)) {
                            $value = json_encode($value);
                        }

                        $model = Translate::findOne([
                            'table_name' => static::transTableName(),
                            'table_id' => $this->getPrimaryKey(),
                            'table_field' => $field,
                            'language' => $langKey,
                        ]);
                        if ($model) {
                            $model->field_value = $value;
                            $model->updated_at = time();
                            $model->save();
                        } else {
                            $model = new Translate();
                            $model->table_name = static::transTableName();
                            $model->table_id = $this->getPrimaryKey();
                            $model->table_field = $field;
                            $model->field_value = $value;
                            $model->language = $langKey;
                            $model->save();
                        }
                    }
                }
            }
        }
    }

    public function combineTranslate($data)
    {
        if (is_array($data) && $data) {
            $combined = [];
            $langKeys = array_keys(Yii::$app->controller->languageList);
            if ($langKeys) {
                $default = $langKeys['0'];
                if (isset($data[$default]) && is_array($data[$default])) {
                    foreach ($data[$default] as $field => $value) {
                        $combined[$field] = $value;
                    }
                }
            }
            if ($combined) {
                foreach ($combined as $key => $val) {
                    try {
                        $this->{$key} = $val;
                    } catch (\Exception $e) {
                    }
                }
            }
        }
    }

    public function deleteAllTranslate()
    {
        Translate::deleteAll([
            'table_name' => static::transTableName(),
            'table_id' => $this->getPrimaryKey(),
        ]);
    }

    public static function leftJoinTranslate($query)
    {
        $tableName = static::tableName();
        $transTable = Translate::tableName();
        $pureTable = static::transTableName($tableName);
        $query->leftJoin($transTable, "{$tableName}.id = {$transTable}.table_id AND {$transTable}.table_name = '{$pureTable}'");

        return $query;
    }

    public static function fieldFilterTranslate($query, $field, $value)
    {
        $transTable = Translate::tableName();
        $language = Yii::$app->language;

        if ($value) {
            $query->andWhere("{$transTable}.table_field = '{$field}' AND {$transTable}.field_value LIKE '%{$value}%' AND {$transTable}.language = '{$language}'");
        }

        return $query;
    }

    public static function combineTranslatedData($data)
    {
        if (!is_array($data) || !$data) return $data;

        // Single
        $isSingle = isset($data['id']);
        $data = $isSingle ? [$data] : $data;

        $newData = [];
        foreach ($data as $key => $val) {
            if (isset($val['translated']) && $val['translated']) {
                foreach ($val['translated'] as $k => $v) {
                    $val[$v['table_field']] = $v['field_value'];
                }
                unset($val['translated']);
            }
            $newData[] = $val;
        }

        return $isSingle ? $newData[0] : $newData;
    }
}

redpajama_set_name: RedPajamaGithub


text:
FOUNDATION_EXPORT double AttributionsVersionNumber;
FOUNDATION_EXPORT const unsigned char AttributionsVersionString[];


text:
package me.tatarka.bindingcollectionadapter2;

import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;
import androidx.test.annotation.UiThreadTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ListView;
import android.widget.WrapperListAdapter;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Arrays;
import java.util.List;

import me.tatarka.bindingcollectionadapter2.test.R;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(AndroidJUnit4.class)
public class ListViewInflationTest {

    @Rule
    public ActivityTestRule<EmptyActivity> activityTestRule = new ActivityTestRule<>(EmptyActivity.class);

    private LayoutInflater inflater;

    @Before
    public void setup() throws Exception {
        inflater = LayoutInflater.from(activityTestRule.getActivity());
    }

    @Test
    @UiThreadTest
    public void listView() {
        List<String> items = Arrays.asList("one", "two", "three");
        TestHelpers.ViewModel viewModel = new TestHelpers.ViewModel.Builder(items, ItemBinding.<String>of(me.tatarka.bindingcollectionadapter2.BR.item, R.layout.item)).build();
        ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.list_view, null, false);
        binding.setVariable(me.tatarka.bindingcollectionadapter2.BR.viewModel, viewModel);
        binding.executePendingBindings();

        ListView listView = (ListView) binding.getRoot();
        @SuppressWarnings("unchecked")
        BindingListViewAdapter<String> adapter = (BindingListViewAdapter<String>) listView.getAdapter();

        assertThat(TestHelpers.iterable(adapter)).containsExactlyElementsOf(items);
    }

    @Test
    @UiThreadTest
    public void listViewSelector() {
        List<String> items = Arrays.asList("one", "two", "three");
        TestHelpers.ViewModel viewModel = new TestHelpers.ViewModel.Builder(items, ItemBinding.<String>of(me.tatarka.bindingcollectionadapter2.BR.item, R.layout.item)).build();
        ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.list_view_selector, null, false);
        binding.setVariable(me.tatarka.bindingcollectionadapter2.BR.viewModel, viewModel);
        binding.executePendingBindings();

        ListView listView = (ListView) binding.getRoot();
        @SuppressWarnings("unchecked")
        BindingListViewAdapter<String> adapter = (BindingListViewAdapter<String>) listView.getAdapter();

        assertThat(TestHelpers.iterable(adapter)).containsExactlyElementsOf(items);
    }

    @Test
    @UiThreadTest
    public void listViewItemIds() {
        List<String> items = Arrays.asList("one", "two", "three");
        List<Long> itemIds = Arrays.asList(1L, 2L, 3L);
        TestHelpers.ViewModel viewModel = new TestHelpers.ViewModel.Builder(items, ItemBinding.<String>of(me.tatarka.bindingcollectionadapter2.BR.item, R.layout.item)).itemIds(itemIds).build();
        ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.list_view_id, null, false);
        binding.setVariable(me.tatarka.bindingcollectionadapter2.BR.viewModel, viewModel);
        binding.executePendingBindings();

        ListView listView = (ListView) binding.getRoot();
        @SuppressWarnings("unchecked")
        BindingListViewAdapter<String> adapter = (BindingListViewAdapter<String>) listView.getAdapter();

        assertThat(TestHelpers.iterableIds(adapter)).containsExactlyElementsOf(itemIds);
    }

    @Test
    @UiThreadTest
    public void listViewItemIsEnabled() {
        List<String> items = Arrays.asList("one", "two", "three");
        List<Boolean> itemIsEnabled = Arrays.asList(true, true, false);
        TestHelpers.ViewModel viewModel = new TestHelpers.ViewModel.Builder(items, ItemBinding.<String>of(me.tatarka.bindingcollectionadapter2.BR.item, R.layout.item)).itemIsEnabled(itemIsEnabled).build();
        ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.list_view_is_enabled, null, false);
        binding.setVariable(me.tatarka.bindingcollectionadapter2.BR.viewModel, viewModel);
        binding.executePendingBindings();

        ListView listView = (ListView) binding.getRoot();
        @SuppressWarnings("unchecked")
        BindingListViewAdapter<String> adapter = (BindingListViewAdapter<String>) listView.getAdapter();

        assertThat(TestHelpers.iterableIsEnabled(adapter)).containsExactlyElementsOf(itemIsEnabled);
    }

    @Test
    @UiThreadTest
    public void listViewAdapter() {
        List<String> items = Arrays.asList("one", "two", "three");
        TestHelpers.ViewModel viewModel = new TestHelpers.ViewModel.Builder(items, ItemBinding.<String>of(me.tatarka.bindingcollectionadapter2.BR.item, R.layout.item)).build();
        ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.list_view_adapter, null, false);
        binding.setVariable(me.tatarka.bindingcollectionadapter2.BR.viewModel, viewModel);
        binding.executePendingBindings();

        ListView listView = (ListView) binding.getRoot();
        @SuppressWarnings("unchecked")
        BindingListViewAdapter<String> adapter = (BindingListViewAdapter<String>) listView.getAdapter();

        assertThat(adapter).isInstanceOf(TestHelpers.MyBindingListViewAdapter.class);
    }

    @Test
    @UiThreadTest
    public void listViewAdapterItemIds() {
        List<String> items = Arrays.asList("one", "two", "three");
        List<Long> itemIds = Arrays.asList(1L, 2L, 3L);
        TestHelpers.ViewModel viewModel = new TestHelpers.ViewModel.Builder(items, ItemBinding.<String>of(me.tatarka.bindingcollectionadapter2.BR.item, R.layout.item)).itemIds(itemIds).build();
        ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.list_view_adapter_id, null, false);
        binding.setVariable(me.tatarka.bindingcollectionadapter2.BR.viewModel, viewModel);
        binding.executePendingBindings();

        ListView listView = (ListView) binding.getRoot();
        @SuppressWarnings("unchecked")
        BindingListViewAdapter<String> adapter = (BindingListViewAdapter<String>) listView.getAdapter();

        assertThat(adapter).isInstanceOf(TestHelpers.MyBindingListViewAdapter.class);
        assertThat(TestHelpers.iterableIds(adapter)).containsExactlyElementsOf(itemIds);
    }

    @Test
    @UiThreadTest
    public void listViewHeaderAdapter() {
        List<String> items = Arrays.asList("one", "two", "three");
        TestHelpers.ViewModel viewModel = new TestHelpers.ViewModel.Builder(items, ItemBinding.<String>of(me.tatarka.bindingcollectionadapter2.BR.item, R.layout.item)).build();
        ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.list_view, null, false);
        binding.setVariable(me.tatarka.bindingcollectionadapter2.BR.viewModel, viewModel);
        binding.executePendingBindings();
        // addHeaderView must be called after the adapter is set.
        ((ListView) binding.getRoot()).addHeaderView(new View(binding.getRoot().getContext()));
        // Trigger rebind to exercise the case when the adapter it wrapped in a HeaderListViewAdapter
        binding.setVariable(me.tatarka.bindingcollectionadapter2.BR.viewModel, viewModel);
        binding.executePendingBindings();

        ListView listView = (ListView) binding.getRoot();
        @SuppressWarnings("unchecked")
        BindingListViewAdapter<String> adapter = (BindingListViewAdapter<String>) ((WrapperListAdapter) listView.getAdapter()).getWrappedAdapter();

        assertThat(TestHelpers.iterable(adapter)).containsExactlyElementsOf(items);
    }
}


text:
/**
 * Dummy class to make git and maven happy.
 */
public class DummyTest {
}


text:
package com.microsoft.azure.management.cosmosdb.v2020_06_01_preview.implementation;

import com.microsoft.azure.management.cosmosdb.v2020_06_01_preview.GremlinGraphGetResults;
import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl;
import rx.Observable;
import com.microsoft.azure.management.cosmosdb.v2020_06_01_preview.GremlinGraphCreateUpdateParameters;
import com.microsoft.azure.management.cosmosdb.v2020_06_01_preview.GremlinGraphGetPropertiesOptions;
import com.microsoft.azure.management.cosmosdb.v2020_06_01_preview.GremlinGraphGetPropertiesResource;
import java.util.Map;
import com.microsoft.azure.management.cosmosdb.v2020_06_01_preview.ManagedServiceIdentity;
import com.microsoft.azure.management.cosmosdb.v2020_06_01_preview.CreateUpdateOptions;
import com.microsoft.azure.management.cosmosdb.v2020_06_01_preview.GremlinGraphResource;
import rx.functions.Func1;

class GremlinGraphGetResultsImpl extends CreatableUpdatableImpl<GremlinGraphGetResults, GremlinGraphGetResultsInner, GremlinGraphGetResultsImpl> implements GremlinGraphGetResults, GremlinGraphGetResults.Definition, GremlinGraphGetResults.Update {
    private final CosmosDBManager manager;
    private String resourceGroupName;
    private String accountName;
    private String databaseName;
    private String graphName;
    private GremlinGraphCreateUpdateParameters createOrUpdateParameter;

    GremlinGraphGetResultsImpl(String name, CosmosDBManager manager) {
        super(name, new GremlinGraphGetResultsInner());
        this.manager = manager;
        // Set resource name
        this.graphName = name;
        //
        this.createOrUpdateParameter = new GremlinGraphCreateUpdateParameters();
    }

    GremlinGraphGetResultsImpl(GremlinGraphGetResultsInner inner, CosmosDBManager manager) {
        super(inner.name(), inner);
        this.manager = manager;
        // Set resource name
        this.graphName = inner.name();
        // set resource ancestor and positional variables
        this.resourceGroupName = IdParsingUtils.getValueFromIdByName(inner.id(), "resourceGroups");
        this.accountName = IdParsingUtils.getValueFromIdByName(inner.id(), "databaseAccounts");
        this.databaseName = IdParsingUtils.getValueFromIdByName(inner.id(), "gremlinDatabases");
        this.graphName = IdParsingUtils.getValueFromIdByName(inner.id(), "graphs");
        //
        this.createOrUpdateParameter = new GremlinGraphCreateUpdateParameters();
    }

    @Override
    public CosmosDBManager manager() {
        return this.manager;
    }

    @Override
    public Observable<GremlinGraphGetResults> createResourceAsync() {
        GremlinResourcesInner client = this.manager().inner().gremlinResources();
        return client.createUpdateGremlinGraphAsync(this.resourceGroupName, this.accountName, this.databaseName, this.graphName, this.createOrUpdateParameter)
            .map(new Func1<GremlinGraphGetResultsInner, GremlinGraphGetResultsInner>() {
               @Override
               public GremlinGraphGetResultsInner call(GremlinGraphGetResultsInner resource) {
                   resetCreateUpdateParameters();
                   return resource;
               }
            })
            .map(innerToFluentMap(this));
    }

    @Override
    public Observable<GremlinGraphGetResults> updateResourceAsync() {
        GremlinResourcesInner client = this.manager().inner().gremlinResources();
        return client.createUpdateGremlinGraphAsync(this.resourceGroupName, this.accountName, this.databaseName, this.graphName, this.createOrUpdateParameter)
            .map(new Func1<GremlinGraphGetResultsInner, GremlinGraphGetResultsInner>() {
               @Override
               public GremlinGraphGetResultsInner call(GremlinGraphGetResultsInner resource) {
                   resetCreateUpdateParameters();
                   return resource;
               }
            })
            .map(innerToFluentMap(this));
    }

    @Override
    protected Observable<GremlinGraphGetResultsInner> getInnerAsync() {
        GremlinResourcesInner client = this.manager().inner().gremlinResources();
        return client.getGremlinGraphAsync(this.resourceGroupName, this.accountName, this.databaseName, this.graphName);
    }

    @Override
    public boolean isInCreateMode() {
        return this.inner().id() == null;
    }

    private void resetCreateUpdateParameters() {
        this.createOrUpdateParameter = new GremlinGraphCreateUpdateParameters();
    }

    @Override
    public String id() {
        return this.inner().id();
    }

    @Override
    public ManagedServiceIdentity identity() {
        return this.inner().identity();
    }

    @Override
    public String location() {
        return this.inner().location();
    }

    @Override
    public String name() {
        return this.inner().name();
    }

    @Override
    public GremlinGraphGetPropertiesOptions options() {
        return this.inner().options();
    }

    @Override
    public GremlinGraphGetPropertiesResource resource() {
        return this.inner().resource();
    }

    @Override
    public Map<String, String> tags() {
        return this.inner().getTags();
    }

    @Override
    public String type() {
        return this.inner().type();
    }

    @Override
    public GremlinGraphGetResultsImpl withExistingGremlinDatabasis(String resourceGroupName, String accountName, String databaseName) {
        this.resourceGroupName = resourceGroupName;
        this.accountName = accountName;
        this.databaseName = databaseName;
        return this;
    }

    @Override
    public GremlinGraphGetResultsImpl withLocation(String location) {
        this.createOrUpdateParameter.withLocation(location);
        return this;
    }

    @Override
    public GremlinGraphGetResultsImpl withOptions(CreateUpdateOptions options) {
        this.createOrUpdateParameter.withOptions(options);
        return this;
    }

    @Override
    public GremlinGraphGetResultsImpl withResource(GremlinGraphResource resource) {
        this.createOrUpdateParameter.withResource(resource);
        return this;
    }

    @Override
    public GremlinGraphGetResultsImpl withIdentity(ManagedServiceIdentity identity) {
        this.createOrUpdateParameter.withIdentity(identity);
        return this;
    }

    @Override
    public GremlinGraphGetResultsImpl withTags(Map<String, String> tags) {
        this.createOrUpdateParameter.withTags(tags);
        return this;
    }

}


text:
"""Airflow module for email backend using AWS SES"""
from __future__ import annotations

from typing import Any

from airflow.providers.amazon.aws.hooks.ses import SesHook

def send_email(
    to: list[str] | str,
    subject: str,
    html_content: str,
    files: list | None = None,
    cc: list[str] | str | None = None,
    bcc: list[str] | str | None = None,
    mime_subtype: str = 'mixed',
    mime_charset: str = 'utf-8',
    conn_id: str = 'aws_default',
    from_email: str | None = None,
    custom_headers: dict[str, Any] | None = None,
    **kwargs,
) -> None:
    """Email backend for SES."""
    if from_email is None:
        raise RuntimeError("The `from_email' configuration has to be set for the SES emailer.")
    hook = SesHook(aws_conn_id=conn_id)
    hook.send_email(
        mail_from=from_email,
        to=to,
        subject=subject,
        html_content=html_content,
        files=files,
        cc=cc,
        bcc=bcc,
        mime_subtype=mime_subtype,
        mime_charset=mime_charset,
        custom_headers=custom_headers,
    )


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Statistics of ccomp in UD_Beja-NSC</title>
    <link rel="root" href=""/>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
    <link rel="stylesheet" type="text/css" href="../../css/jquery-ui-redmond.css"/>
    <link rel="stylesheet" type="text/css" href="../../css/style.css"/>
    <link rel="stylesheet" type="text/css" href="../../css/style-vis.css"/>
    <link rel="stylesheet" type="text/css" href="../../css/hint.css"/>

          home

          edit page
          issue tracker

          <gcse:search></gcse:search>

        This page pertains to UD version 2.

            It appears that you have Javascript disabled.
            Please consider enabling Javascript for this page to see the visualizations.

Treebank Statistics: UD_Beja-NSC: Relations: ccomp

This relation is universal.

9 nodes (1%) are attached to their parents as ccomp.

9 instances of ccomp (100%) are right-to-left (child precedes parent).
Average distance between parent and child is 2.88888888888889.

The following 1 pairs of parts of speech are connected with ccomp: <tt>VERB</tt>-<tt>VERB</tt> (9; 100% instances).

# visual-style 7	bgColor:blue
# visual-style 7	fgColor:white
# visual-style 13	bgColor:blue
# visual-style 13	fgColor:white
# visual-style 13 7 ccomp	color:blue
1	uː=	_	DET	DET	Case=Nom|Definite=Def|Gender=Masc|Number=Sing	2	det	_	AlignBegin=18153|AlignEnd=18282|GE=[DEF].[SG].[M].[NOM]=|RX=[DET]=|TokenType=Clit
2	mbʔaɖ	_	NOUN	N	Gender=Masc	7	nsubj	_	AlignBegin=18282|AlignEnd=18411|GE=mat|Gloss=mat|RX=[N].[M]|TokenType=Stem
3	han	_	PART	PTCL	_	2	advmod	_	AlignBegin=18411|AlignEnd=18669|GE=also|Gloss=also|RX=[PTCL].[FOC]|TokenType=Stem
4	/	_	PUNCT	PUNCT	_	2	punct	_	AlignBegin=18669|AlignEnd=19258|TokenType=Break
5	waʤʤai	_	NOUN	N	Gender=Masc	6	nmod	_	AlignBegin=19258|AlignEnd=19634|GE=appointment-[GEN]|Gloss=appointment|MGloss=appointment-GEN|MSeg=waʤʤa-i|RX=[N].[M]-[CASE]|TokenType=Stem
6	gaw	_	NOUN	N	Gender=Masc	7	obj	_	AlignBegin=19634|AlignEnd=20011|GE=house|Gloss=house|RX=[N].[M]|TokenType=Stem
7	iːkti	_	VERB	V1,IRG	Aspect=Aor|Gender=Masc|Number=Sing|VerbClass=1	13	ccomp	_	AlignBegin=20011|AlignEnd=20261|GE=[3SG].[M]-become\[AOR]|Gloss=become|MGloss=3SG.M-become\AOR|MSeg=iː-kti|RX=[PNG]-[V1].[IRG]|TokenType=Stem
8	=jeːt	_	SCONJ	CONJ	Gender=Fem	7	mark	_	AlignBegin=20261|AlignEnd=20387|ExtPos=SCONJ|GE==[REL].[F]|Idiom=Yes|RX==[CONJ]|TokenType=Clit
9	/	_	X	PUNCT	_	8	fixed	_	AlignBegin=20387|AlignEnd=20764|InIdiom=Yes|TokenType=Break
10	toː=	_	DET	DET	Case=Acc|Definite=Def|Gender=Fem|Number=Sing	8	fixed	_	AlignBegin=20764|AlignEnd=20867|GE=[DEF].[SG].[F].[ACC]=|InIdiom=Yes|RX=[DET]=|TokenType=Clit
11	na	_	NOUN	CONJ	_	8	fixed	_	AlignBegin=20867|AlignEnd=20970|GE=thing|Gloss=thing|InIdiom=Yes|RX=[CONJ]|TokenType=Stem
12	/	_	PUNCT	PUNCT	_	7	punct	_	AlignBegin=20970|AlignEnd=21408|TokenType=Break
13	akan	_	VERB	V1,IRG	Aspect=Perf|Number=Sing|VerbClass=1|Voice=Mid	16	parataxis:mod	_	AlignBegin=21408|AlignEnd=21657|GE=[1SG]-know\[MID].[PFV]|Gloss=know|MGloss=1SG-know\MID.PFV|MSeg=a-kan|RX=[PNG]-[V1].[DER].[IRG]|TokenType=Stem
14	/	_	PUNCT	PUNCT	_	13	punct	_	AlignBegin=21657|AlignEnd=22569|TokenType=Break
15	hoːj	_	PRON	PRO	Case=Abl	16	iobj	_	AlignBegin=22569|AlignEnd=22777|GE=[ABL].[3]|RX=[PRO]|TokenType=Stem
16	amoːk	_	VERB	V1	Aspect=Perf|Number=Sing|VerbClass=1	17	parataxis	_	AlignBegin=22777|AlignEnd=22986|GE=[1SG]-take_shelter\[INT].[PFV]|Gloss=take_shelter|MGloss=1SG-take_shelter\INT.PFV|MSeg=a-moːk|ReportedSpeech=Yes|RX=[PNG]-[V1].[DER]|TokenType=Stem
17	ini	_	VERB	V1,IRG	Aspect=Perf|Gender=Masc|Number=Sing|VerbClass=1	0	root	_	AlignBegin=22986|AlignEnd=23195|GE=[3SG].[M]-say\[PFV]|Gloss=say|MGloss=3SG.M-say\PFV|MSeg=i-ni|RX=[PNG]-[V1].[IRG]|TokenType=Stem
18	//	_	PUNCT	PUNCT	_	17	punct	_	AlignBegin=23195|AlignEnd=23859|TokenType=Break

© 2014–2021
            Universal Dependencies contributors.
            Site powered by Annodoc and brat
.


text:
package kv_test

import (
	"context"
	"encoding/json"
	"fmt"
	"testing"
	"time"

	"github.com/influxdata/influxdb/v2/kit/platform"
	"github.com/influxdata/influxdb/v2/kit/platform/errors"
	"github.com/influxdata/influxdb/v2/kv"
	"github.com/influxdata/influxdb/v2/kv/migration"
	itesting "github.com/influxdata/influxdb/v2/testing"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestStoreBase(t *testing.T) {
	newStoreBase := func(t *testing.T, bktSuffix string, encKeyFn, encBodyFn kv.EncodeEntFn, decFn kv.DecodeBucketValFn, decToEntFn kv.ConvertValToEntFn) (*kv.StoreBase, func(), kv.Store) {
		t.Helper()

		svc, done := itesting.NewTestBoltStore(t)

		bucket := []byte("foo_" + bktSuffix)
		store := kv.NewStoreBase("foo", bucket, encKeyFn, encBodyFn, decFn, decToEntFn)

		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()

		migrationName := fmt.Sprintf("create bucket %q", string(bucket))
		migration.CreateBuckets(migrationName, bucket).Up(ctx, svc)

		return store, done, svc
	}

	newFooStoreBase := func(t *testing.T, bktSuffix string) (*kv.StoreBase, func(), kv.Store) {
		return newStoreBase(t, bktSuffix, kv.EncIDKey, kv.EncBodyJSON, decJSONFooFn, decFooEntFn)
	}

	t.Run("Put", func(t *testing.T) {
		t.Run("basic", func(t *testing.T) {
			base, done, kvStore := newFooStoreBase(t, "put")
			defer done()

			testPutBase(t, kvStore, base, base.BktName)
		})

		t.Run("new", func(t *testing.T) {
			base, done, kvStore := newFooStoreBase(t, "put")
			defer done()

			expected := newFooEnt(3, 33, "name3")
			update(t, kvStore, func(tx kv.Tx) error {
				return base.Put(context.TODO(), tx, expected, kv.PutNew())
			})

			var actual interface{}
			view(t, kvStore, func(tx kv.Tx) error {
				f, err := base.FindEnt(context.TODO(), tx, kv.Entity{PK: expected.PK})
				actual = f
				return err
			})

			assert.Equal(t, expected.Body, actual)
		})

		t.Run("update", func(t *testing.T) {
			base, done, kvStore := newFooStoreBase(t, "put")
			defer done()

			expected := testPutBase(t, kvStore, base, base.BktName)

			updateEnt := newFooEnt(expected.ID, expected.OrgID, "new name")
			update(t, kvStore, func(tx kv.Tx) error {
				return base.Put(context.TODO(), tx, updateEnt, kv.PutUpdate())
			})

			var actual interface{}
			view(t, kvStore, func(tx kv.Tx) error {
				f, err := base.FindEnt(context.TODO(), tx, kv.Entity{PK: kv.EncID(expected.ID)})
				actual = f
				return err
			})

			expected.Name = "new name"
			assert.Equal(t, expected, actual)
		})

		t.Run("error cases", func(t *testing.T) {
			t.Run("new entity conflicts with existing", func(t *testing.T) {
				base, done, kvStore := newFooStoreBase(t, "put")
				defer done()

				expected := testPutBase(t, kvStore, base, base.BktName)

				err := kvStore.Update(context.TODO(), func(tx kv.Tx) error {
					entCopy := newFooEnt(expected.ID, expected.OrgID, expected.Name)
					return base.Put(context.TODO(), tx, entCopy, kv.PutNew())
				})
				require.Error(t, err)
				assert.Equal(t, errors.EConflict, errors.ErrorCode(err))
			})
		})

		t.Run("updating entity that does not exist", func(t *testing.T) {
			base, done, kvStore := newFooStoreBase(t, "put")
			defer done()

			expected := testPutBase(t, kvStore, base, base.BktName)

			err := kvStore.Update(context.TODO(), func(tx kv.Tx) error {
				// ent by id does not exist
				entCopy := newFooEnt(333, expected.OrgID, "name1")
				return base.Put(context.TODO(), tx, entCopy, kv.PutUpdate())
			})
			require.Error(t, err)
			assert.Equal(t, errors.ENotFound, errors.ErrorCode(err))
		})
	})

	t.Run("DeleteEnt", func(t *testing.T) {
		base, done, kvStore := newFooStoreBase(t, "delete_ent")
		defer done()

		testDeleteEntBase(t, kvStore, base)
	})

	t.Run("Delete", func(t *testing.T) {
		testDeleteBase(t, func(t *testing.T, suffix string) (storeBase, func(), kv.Store) {
			return newFooStoreBase(t, suffix)
		})
	})

	t.Run("FindEnt", func(t *testing.T) {
		base, done, kvStore := newFooStoreBase(t, "find_ent")
		defer done()

		testFindEnt(t, kvStore, base)
	})

	t.Run("Find", func(t *testing.T) {
		testFind(t, func(t *testing.T, suffix string) (storeBase, func(), kv.Store) {
			return newFooStoreBase(t, suffix)
		})
	})
}

func testPutBase(t *testing.T, kvStore kv.Store, base storeBase, bktName []byte) foo {
	t.Helper()

	expected := foo{
		ID:    1,
		OrgID: 9000,
		Name:  "foo_1",
	}

	update(t, kvStore, func(tx kv.Tx) error {
		return base.Put(context.TODO(), tx, kv.Entity{
			PK:        kv.EncID(expected.ID),
			UniqueKey: kv.Encode(kv.EncID(expected.OrgID), kv.EncString(expected.Name)),
			Body:      expected,
		})
	})

	var actual foo
	decodeJSON(t, getEntRaw(t, kvStore, bktName, encodeID(t, expected.ID)), &actual)

	assert.Equal(t, expected, actual)

	return expected
}

func testDeleteEntBase(t *testing.T, kvStore kv.Store, base storeBase) kv.Entity {
	t.Helper()

	expected := newFooEnt(1, 9000, "foo_1")
	seedEnts(t, kvStore, base, expected)

	update(t, kvStore, func(tx kv.Tx) error {
		return base.DeleteEnt(context.TODO(), tx, kv.Entity{PK: expected.PK})
	})

	err := kvStore.View(context.TODO(), func(tx kv.Tx) error {
		_, err := base.FindEnt(context.TODO(), tx, kv.Entity{PK: expected.PK})
		return err
	})
	isNotFoundErr(t, err)
	return expected
}

func testDeleteBase(t *testing.T, fn func(t *testing.T, suffix string) (storeBase, func(), kv.Store), assertFns ...func(*testing.T, kv.Store, storeBase, []foo)) {
	expectedEnts := []kv.Entity{
		newFooEnt(1, 9000, "foo_0"),
		newFooEnt(2, 9000, "foo_1"),
		newFooEnt(3, 9003, "foo_2"),
		newFooEnt(4, 9004, "foo_3"),
	}

	tests := []struct {
		name     string
		opts     kv.DeleteOpts
		expected []interface{}
	}{
		{
			name: "delete all",
			opts: kv.DeleteOpts{
				FilterFn: func(k []byte, v interface{}) bool {
					return true
				},
			},
		},
		{
			name: "delete IDs less than 4",
			opts: kv.DeleteOpts{
				FilterFn: func(k []byte, v interface{}) bool {
					if f, ok := v.(foo); ok {
						return f.ID < 4
					}
					return true
				},
			},
			expected: toIfaces(expectedEnts[3]),
		},
	}

	for _, tt := range tests {
		fn := func(t *testing.T) {
			t.Helper()

			base, done, kvStore := fn(t, "delete")
			defer done()

			seedEnts(t, kvStore, base, expectedEnts...)

			update(t, kvStore, func(tx kv.Tx) error {
				return base.Delete(context.TODO(), tx, tt.opts)
			})

			var actuals []interface{}
			view(t, kvStore, func(tx kv.Tx) error {
				return base.Find(context.TODO(), tx, kv.FindOpts{
					CaptureFn: func(key []byte, decodedVal interface{}) error {
						actuals = append(actuals, decodedVal)
						return nil
					},
				})
			})

			assert.Equal(t, tt.expected, actuals)

			var entsLeft []foo
			for _, expected := range tt.expected {
				ent, ok := expected.(foo)
				require.Truef(t, ok, "got: %#v", expected)
				entsLeft = append(entsLeft, ent)
			}

			for _, assertFn := range assertFns {
				assertFn(t, kvStore, base, entsLeft)
			}
		}
		t.Run(tt.name, fn)
	}
}

func testFindEnt(t *testing.T, kvStore kv.Store, base storeBase) kv.Entity {
	t.Helper()

	expected := newFooEnt(1, 9000, "foo_1")
	seedEnts(t, kvStore, base, expected)

	var actual interface{}
	view(t, kvStore, func(tx kv.Tx) error {
		f, err := base.FindEnt(context.TODO(), tx, kv.Entity{PK: expected.PK})
		actual = f
		return err
	})

	assert.Equal(t, expected.Body, actual)

	return expected
}

func testFind(t *testing.T, fn func(t *testing.T, suffix string) (storeBase, func(), kv.Store)) {
	t.Helper()

	expectedEnts := []kv.Entity{
		newFooEnt(1, 9000, "foo_0"),
		newFooEnt(2000, 9000, "foo_1"),
		newFooEnt(3000000, 9003, "foo_2"),
		newFooEnt(4000000000, 9004, "foo_3"),
	}

	tests := []struct {
		name     string
		opts     kv.FindOpts
		expected []interface{}
	}{
		{
			name:     "no options",
			expected: toIfaces(expectedEnts...),
		},
		{
			name:     "with order descending",
			opts:     kv.FindOpts{Descending: true},
			expected: reverseSlc(toIfaces(expectedEnts...)),
		},
		{
			name:     "with limit",
			opts:     kv.FindOpts{Limit: 1},
			expected: toIfaces(expectedEnts[0]),
		},
		{
			name:     "with offset",
			opts:     kv.FindOpts{Offset: 1},
			expected: toIfaces(expectedEnts[1:]...),
		},
		{
			name: "with offset and limit",
			opts: kv.FindOpts{
				Limit:  1,
				Offset: 1,
			},
			expected: toIfaces(expectedEnts[1]),
		},
		{
			name: "with descending, offset, and limit",
			opts: kv.FindOpts{
				Descending: true,
				Limit:      1,
				Offset:     1,
			},
			expected: toIfaces(expectedEnts[2]),
		},
		{
			name: "with id prefix",
			opts: kv.FindOpts{
				Prefix: encodeID(t, 3000000)[:platform.IDLength-5],
			},
			expected: toIfaces(expectedEnts[2], expectedEnts[3]),
		},
	}

	for _, tt := range tests {
		fn := func(t *testing.T) {
			base, done, kvStore := fn(t, "find")
			defer done()

			seedEnts(t, kvStore, base, expectedEnts...)

			var actuals []interface{}
			tt.opts.CaptureFn = func(key []byte, decodedVal interface{}) error {
				actuals = append(actuals, decodedVal)
				return nil
			}

			view(t, kvStore, func(tx kv.Tx) error {
				return base.Find(context.TODO(), tx, tt.opts)
			})

			assert.Equal(t, tt.expected, actuals)
		}
		t.Run(tt.name, fn)
	}
}

type foo struct {
	ID    platform.ID
	OrgID platform.ID

	Name string
}

func decodeJSON(t *testing.T, b []byte, v interface{}) {
	t.Helper()
	require.NoError(t, json.Unmarshal(b, &v))
}

type storeBase interface {
	Delete(ctx context.Context, tx kv.Tx, opts kv.DeleteOpts) error
	DeleteEnt(ctx context.Context, tx kv.Tx, ent kv.Entity) error
	FindEnt(ctx context.Context, tx kv.Tx, ent kv.Entity) (interface{}, error)
	Find(ctx context.Context, tx kv.Tx, opts kv.FindOpts) error
	Put(ctx context.Context, tx kv.Tx, ent kv.Entity, opts ...kv.PutOptionFn) error
}

func seedEnts(t *testing.T, kvStore kv.Store, store storeBase, ents ...kv.Entity) {
	t.Helper()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	for _, ent := range ents {
		update(t, kvStore, func(tx kv.Tx) error { return store.Put(ctx, tx, ent) })
	}
}

func update(t *testing.T, kvStore kv.Store, fn func(tx kv.Tx) error) {
	t.Helper()

	require.NoError(t, kvStore.Update(context.TODO(), fn))
}

func view(t *testing.T, kvStore kv.Store, fn func(tx kv.Tx) error) {
	t.Helper()
	require.NoError(t, kvStore.View(context.TODO(), fn))
}

func getEntRaw(t *testing.T, kvStore kv.Store, bktName []byte, key []byte) []byte {
	t.Helper()

	var actualRaw []byte
	err := kvStore.View(context.TODO(), func(tx kv.Tx) error {
		b, err := tx.Bucket(bktName)
		require.NoError(t, err)

		actualRaw, err = b.Get(key)
		return err
	})
	require.NoError(t, err)
	return actualRaw
}

func encodeID(t *testing.T, id platform.ID) []byte {
	t.Helper()

	b, err := id.Encode()
	require.NoError(t, err)
	return b
}

func decJSONFooFn(key, val []byte) ([]byte, interface{}, error) {
	var f foo
	if err := json.Unmarshal(val, &f); err != nil {
		return nil, nil, err
	}
	return key, f, nil
}

func decFooEntFn(k []byte, v interface{}) (kv.Entity, error) {
	f, ok := v.(foo)
	if !ok {
		return kv.Entity{}, fmt.Errorf("invalid entry: %#v", v)
	}
	return kv.Entity{
		PK:        kv.EncID(f.ID),
		UniqueKey: kv.Encode(kv.EncID(f.OrgID), kv.EncString(f.Name)),
		Body:      f,
	}, nil
}

func newFooEnt(id, orgID platform.ID, name string) kv.Entity {
	f := foo{ID: id, Name: name, OrgID: orgID}
	return kv.Entity{
		PK:        kv.EncID(f.ID),
		UniqueKey: kv.Encode(kv.EncID(f.OrgID), kv.EncString(f.Name)),
		Body:      f,
	}
}

func isNotFoundErr(t *testing.T, err error) {
	t.Helper()

	iErr, ok := err.(*errors.Error)
	if !ok {
		require.FailNowf(t, "expected an *influxdb.Error type", "got: %#v", err)
	}
	assert.Equal(t, errors.ENotFound, iErr.Code)
}

func toIfaces(ents ...kv.Entity) []interface{} {
	var actuals []interface{}
	for _, ent := range ents {
		actuals = append(actuals, ent.Body)
	}
	return actuals
}

func reverseSlc(slc []interface{}) []interface{} {
	for i, j := 0, len(slc)-1; i < j; i, j = i+1, j-1 {
		slc[i], slc[j] = slc[j], slc[i]
	}
	return slc
}


text:
package cct.j3d;

import java.util.Enumeration;

import org.scijava.java3d.Transform3D;
import org.scijava.java3d.TransformGroup;
import org.scijava.vecmath.Matrix3d;

import org.scijava.java3d.utils.behaviors.mouse.MouseBehaviorCallback;
import org.scijava.java3d.utils.behaviors.mouse.MouseRotate;

/**
 *
Title: Picking

 *
 *
Description:

 *
 *
Copyright: Copyright (c) 2005

 *
 *
Company:

 *
 * @author not attributable
 * @version 1.0
 */
public class MyMouseRotate
    extends MouseRotate {

   //private SampleFrame daddy = null;
   private Java3dUniverse dad = null;
   protected Transform3D inverseTrans = null;
   protected Matrix3d rotation = null;

   private MouseBehaviorCallback callback = null;

   /**
    * Creates a rotate behavior given the transform group.
    * @param transformGroup The transformGroup to operate on.
    */
   public MyMouseRotate(TransformGroup transformGroup) {
      super(transformGroup);
   }

   /**
    * Creates a default mouse rotate behavior.
    **/
   public MyMouseRotate() {
      super();
   }

   /**
    * Creates a rotate behavior.
    * Note that this behavior still needs a transform
    * group to work on (use setTransformGroup(tg)) and
    * the transform group must add this behavior.
    * @param flags interesting flags (wakeup conditions).
    */
   public MyMouseRotate(int flags) {
      super(flags);
   }

   @Override
  public void initialize() {
      super.initialize();
   }

   /**
    * Return the x-axis movement multipler.
    **/

   @Override
  public double getXFactor() {
      return super.getXFactor();
   }

   /**
    * Return the y-axis movement multipler.
    **/

   @Override
  public double getYFactor() {
      return super.getYFactor();
   }

   /**
    * Set the x-axis amd y-axis movement multipler with factor.
    **/

   @Override
  public void setFactor(double factor) {
      super.setFactor(factor);

   }

   @Override
  public void processStimulus(Enumeration criteria) {

      super.processStimulus(criteria);

      //logger.info("processStimulus: labels; "+ daddy.areLabels());

      /*
             if (daddy != null && daddy.areLabels()) {
         daddy.updateLabels();
             }
             else if (dad != null && dad.areLabels()) {
         dad.updateLabels();
             }
       */

      if (dad != null && dad.areLabels()) {
         dad.updateLabels();
         //this.notifyAll();
      }

   }

   /**
    * Users can overload this method  which is called every time
    * the Behavior updates the transform
    *
    * Default implementation does nothing
    */
   @Override
  public void transformChanged(Transform3D transform) {

   }

   /**
    * The transformChanged method in the callback class will
    * be called every time the transform is updated
    */
   @Override
  public void setupCallback(MouseBehaviorCallback callback) {
      this.callback = callback;
   }

   // --- And now, custom functions...

   /*
       public MyMouseRotate(SampleFrame parent, TransformGroup transformGroup) {
      super(transformGroup);
      daddy = parent;
       }
    */

   public MyMouseRotate(Java3dUniverse parent, TransformGroup transformGroup) {
      super(transformGroup);
      dad = parent;
   }

   /*
       public void setParentFrame(SampleFrame dad) {
      daddy = dad;
       }
    */

   public void setParentFrame(Java3dUniverse parent) {
      dad = parent;
   }

}


text:
namespace zetasql {
namespace functions {
namespace {

// Minimum and maximum decimal exponent of numbers representable as double.
// "numeric_limits<double>::digits10 - 1"  is to take into account subnormal
// numbers.
const int kDoubleMinExponent = std::numeric_limits<double>::min_exponent10
                             - std::numeric_limits<double>::digits10 - 1;
const int kDoubleMaxExponent = std::numeric_limits<double>::max_exponent10;

// Minimum and maximum decimal exponent of numbers representable as float.
// "numeric_limits<float>::digits10 - 1"  is to take into account subnormal
// numbers.
const int kFloatMinExponent = std::numeric_limits<float>::min_exponent10
                            - std::numeric_limits<float>::digits10 - 1;
const int kFloatMaxExponent = std::numeric_limits<float>::max_exponent10;

// Precomputed powers of 10 in the entire ranges
// [kDoubleMinExponent, kDoubleMaxExponent] and
// [kFloatMinExponent, kFloatMaxExponent].
// We use "long double" instead of double and "double" for float exponents
// to avoid getting into subnormal numbers, and thus keeping relative error
// better than epsilon.
// Note that on some platforms "long double" may be the same type as double.
// On such platforms results of RoundDecimal() and TruncDecimal() will
// have error greater than 1 ULP if 10^(-digits) is a subnormal double number.
static long double kDecimalExponentDouble[kDoubleMaxExponent -
                                          kDoubleMinExponent + 1];
static double kDecimalExponentFloat[kFloatMaxExponent -
                                    kFloatMinExponent + 1];

void InitExponents() {
  for (int i = 0; i < ABSL_ARRAYSIZE(kDecimalExponentDouble); ++i) {
    // Note: exp10 and exp10l are GNU extensions. Fall back to pow and powl if
    // they're not available.
#ifdef _GNU_SOURCE
    kDecimalExponentDouble[i] = exp10l(i + kDoubleMinExponent);
#else
    kDecimalExponentDouble[i] = powl(10.0, i + kDoubleMinExponent);
#endif
  }
  for (int i = 0; i < ABSL_ARRAYSIZE(kDecimalExponentFloat); ++i) {
#ifdef _GNU_SOURCE
    kDecimalExponentFloat[i] = exp10(i + kFloatMinExponent);
#else
    kDecimalExponentFloat[i] = pow(10.0, i + kFloatMinExponent);
#endif
  }
}

namespace {
static bool module_initialization_complete = []() {
  InitExponents();
  return true;
} ();
}  // namespace

// This function assumes that the FromType is same or wider than the ToType.
template <typename FromType, typename ToType>
static inline bool CastRounded(FromType in, ToType* out) {
  static_assert(std::is_floating_point<FromType>::value,
                "FromType must be floating point type");
  static_assert(std::is_floating_point<ToType>::value,
                "ToType must be floating point type");
  static_assert(std::numeric_limits<FromType>::lowest() <=
                        std::numeric_limits<ToType>::lowest() &&
                    std::numeric_limits<FromType>::max() >=
                        std::numeric_limits<ToType>::max(),
                "FromType must be wider than or equal to ToType");
  if ((in >= std::numeric_limits<ToType>::lowest() &&
       in <= std::numeric_limits<ToType>::max()) ||
      ABSL_PREDICT_FALSE(!std::isfinite(in))) {
    *out = static_cast<ToType>(in);
    return true;
  } else {
    return false;
  }
}

}  // anonymous namespace

template <>
bool RoundDecimal(double in, int64_t digits, double *out,
                  absl::Status* error) {
  digits = -digits;
  if (digits > kDoubleMaxExponent) {
    *out = 0.0;
    return true;
  } else if (digits < kDoubleMinExponent) {
    *out = in;
    return true;
  }
  const long double exp = kDecimalExponentDouble[digits - kDoubleMinExponent];

  long double x = in / exp;
  if (std::numeric_limits<long double>::max_exponent <
          std::numeric_limits<double>::max_exponent * 2 &&
      ABSL_PREDICT_FALSE(!std::isfinite(x))) {
    // "in / exp" overflows when "in" is a big number and we are rounding
    // digits to the right of the decimal point (digits > 0). In that case the
    // rounded value would be the same as "in" and we just return
    // the value of "in".
    *out = in;
    return true;
  }
  long double result = roundl(x) * exp;
  // 'result' may overflow if the exponent size of long double is insufficient
  // for the rounded result.
  if (std::numeric_limits<long double>::max_exponent <
          std::numeric_limits<double>::max_exponent * 2 &&
      ABSL_PREDICT_FALSE(!std::isfinite(result) && std::isfinite(in))) {
    return internal::SetFloatingPointOverflow(
        absl::StrCat("ROUND(", in, ", ", digits, ")"), error);
  }
  // Converting the result from long double to double may overflow.
  if (sizeof(long double) > sizeof(double)) {
    if (!CastRounded<long double, double>(result, out)) {
      return internal::SetFloatingPointOverflow(
          absl::StrCat("ROUND(", in, ", ", digits, ")"), error);
    } else {
      return true;
    }
  } else {
    *out = static_cast<double>(result);
    return true;
  }
}

template <>
bool RoundDecimal(float in, int64_t digits, float *out,
                  absl::Status* error) {
  static_assert(std::numeric_limits<double>::max_exponent >=
                std::numeric_limits<float>::max_exponent * 2 ,
                "double's exponent must be wider than float's");
  digits = -digits;
  if (digits > kFloatMaxExponent) {
    *out = 0.0;
    return true;
  } else if (digits < kFloatMinExponent) {
    *out = in;
    return true;
  }
  double exp = kDecimalExponentFloat[digits - kFloatMinExponent];
  // round(in / exp) * exp will never overflow due to the static_assert above.
  // Converting the result from double to float may overflow.
  if (!CastRounded<double, float>(round(in / exp) * exp, out)) {
    return internal::SetFloatingPointOverflow(
        absl::StrCat("ROUND(", in, ", ", digits, ")"), error);
  } else {
    return true;
  }
}
template <>
bool TruncDecimal(double in, int64_t digits, double *out,
                  absl::Status* error) {
  digits = -digits;
  if (digits > kDoubleMaxExponent) {
    *out = 0.0;
    return true;
  } else if (digits < kDoubleMinExponent) {
    *out = in;
    return true;
  }
  const long double exp = kDecimalExponentDouble[digits - kDoubleMinExponent];

  long double x = in / exp;
  if (std::numeric_limits<long double>::max_exponent <
          std::numeric_limits<double>::max_exponent * 2 &&
      ABSL_PREDICT_FALSE(!std::isfinite(x))) {
    // "in / exp" overflows when "in" is a big number and we are rounding
    // digits to the right of the decimal point (digits > 0). In that case the
    // truncated value would be the same as "in" and we just return
    // the value of "in".
    *out = in;
    return true;
  }
  *out = truncl(x) * exp;
  // Because truncl always rounds towards zero, the output value is less than
  // the input, so we do not expect an overflow to occur here.
  return true;
}

template <>
bool TruncDecimal(float in, int64_t digits, float *out,
                  absl::Status* error) {
  static_assert(std::numeric_limits<double>::max_exponent >=
                std::numeric_limits<float>::max_exponent * 2 ,
                "double's exponent must be wider than float's");
  digits = -digits;
  if (digits > kFloatMaxExponent) {
    *out = 0.0;
    return true;
  } else if (digits < kFloatMinExponent) {
    *out = in;
    return true;
  }
  double exp = kDecimalExponentFloat[digits - kFloatMinExponent];
  *out = trunc(in / exp) * exp;
  // trunc(in / exp) * exp will never overflow due to the static_assert above.
  // Because truncl always rounds towards zero, the output value is less than
  // the input, so we do not expect an overflow to occur here.
  return true;
}

template <>
bool Round(NumericValue in, NumericValue *out, absl::Status* error) {
  auto status_or_numeric = in.Round(0);
  if (!status_or_numeric.ok()) {
    return internal::SetFloatingPointOverflow(
        absl::StrCat("ROUND(", in.ToString(), ")"), error);
  }
  *out = status_or_numeric.value();
  return true;
}

template <>
bool RoundDecimal(NumericValue in, int64_t digits, NumericValue *out,
                  absl::Status* error) {
  auto status_or_numeric = in.Round(digits);
  if (!status_or_numeric.ok()) {
    return internal::SetFloatingPointOverflow(
        absl::StrCat("ROUND(", in.ToString(), ", ", digits, ")"), error);
  }
  *out = status_or_numeric.value();
  return true;
}

template <>
bool Trunc(NumericValue in, NumericValue *out, absl::Status* error) {
  *out = in.Trunc(0);
  return true;
}

template <>
bool TruncDecimal(NumericValue in, int64_t digits, NumericValue* out,
                  absl::Status* error) {
  *out = in.Trunc(digits);
  return true;
}

template <>
bool Ceil(NumericValue in, NumericValue *out, absl::Status* error) {
  auto status_or_numeric = in.Ceiling();
  if (!status_or_numeric.ok()) {
    return internal::SetFloatingPointOverflow(
        absl::StrCat("CEIL(", in.ToString(), ")"), error);
  }
  *out = status_or_numeric.value();
  return true;
}

template <>
bool Floor(NumericValue in, NumericValue *out, absl::Status* error) {
  auto status_or_numeric = in.Floor();
  if (!status_or_numeric.ok()) {
    return internal::SetFloatingPointOverflow(
        absl::StrCat("FLOOR(", in.ToString(), ")"), error);
  }
  *out = status_or_numeric.value();
  return true;
}

template <>
bool Pow(NumericValue in1, NumericValue in2, NumericValue* out,
         absl::Status* error) {
  auto status_or_numeric = in1.Power(in2);
  if (!status_or_numeric.ok()) {
    return internal::SetFloatingPointError(
        absl::StrCat("POW(", in1.ToString(), ", ", in2.ToString(), ")"), error);
  }
  *out = status_or_numeric.value();
  return true;
}

}  // namespace functions
}  // namespace zetasql


text:
jest.mock("fs");
const fs = require("fs");

const ServiceBroker = require("../../../src/service-broker");
const Transit = require("../../../src/transit");
const P = require("../../../src/packets");
const E = require("../../../src/errors");
const net = require("net");
const { protectReject } = require("../utils");

// const lolex = require("lolex");
jest.mock("../../../src/transporters/tcp/tcp-reader");

let TcpReader = require("../../../src/transporters/tcp/tcp-reader");
TcpReader.mockImplementation(() => {
	return {
		listen: jest.fn()
	};
});

jest.mock("../../../src/transporters/tcp/tcp-writer");
let TcpWriter = require("../../../src/transporters/tcp/tcp-writer");
TcpWriter.mockImplementation(() => {
	let callbacks = {};
	return {
		on: jest.fn((name, cb) => {
			callbacks[name] = cb;
		}),
		__callbacks: callbacks
	};
});

jest.mock("../../../src/transporters/tcp/udp-broadcaster");
let UdpServer = require("../../../src/transporters/tcp/udp-broadcaster");
UdpServer.mockImplementation(() => {
	let callbacks = {};
	return {
		on: jest.fn((name, cb) => {
			callbacks[name] = cb;
		}),
		__callbacks: callbacks,
		bind: jest.fn()
	};
});

const TcpTransporter = require("../../../src/transporters/tcp");

describe("Test TcpTransporter constructor", () => {

	it("check constructor", () => {
		let transporter = new TcpTransporter();
		expect(transporter).toBeDefined();
		expect(transporter.opts).toEqual({
			udpDiscovery: true,
			udpReuseAddr: true,
			udpMaxDiscovery: 0,
			udpBindAddress: null,
			udpPort: 4445,
			udpPeriod: 30,
			udpMulticast: "239.0.0.0",
			udpMulticastTTL: 1,
			udpBroadcast: false,
			port: null,
			urls: null,
			useHostname: true,
			gossipPeriod: 2,
			maxConnections: 32,
			maxPacketSize: 1 * 1024 * 1024
		});
		expect(transporter.connected).toBe(false);
		expect(transporter.hasBuiltInBalancer).toBe(false);

		expect(transporter.reader).toBeNull();
		expect(transporter.writer).toBeNull();
		expect(transporter.udpServer).toBeNull();
		expect(transporter.gossipTimer).toBeNull();
	});

	// it("check constructor with string param", () => {
	// 	let transporter = new TcpTransporter("nats://localhost");
	// 	expect(transporter.opts).toEqual();
	// });

	it("check constructor with options", () => {
		let opts = { udpDiscovery: false, udpBindAddress: "10.0.0.4", port: 5555, udpBroadcast: true };
		let transporter = new TcpTransporter(opts);
		expect(transporter.opts).toEqual({
			udpDiscovery: false,
			udpReuseAddr: true,
			udpMaxDiscovery: 0,
			udpBindAddress: "10.0.0.4",
			udpPort: 4445,
			udpPeriod: 30,
			udpBroadcast: true,
			udpMulticast: "239.0.0.0",
			udpMulticastTTL: 1,
			port: 5555,
			urls: null,
			useHostname: true,
			gossipPeriod: 2,
			maxConnections: 32,
			maxPacketSize: 1 * 1024 * 1024
		});
	});

});

describe("Test TcpTransporter init", () => {
	const broker = new ServiceBroker({ logger: false, transporter: "fake" });
	const transporter = new TcpTransporter({});

	it("check init", () => {
		expect(broker.registry.nodes.disableHeartbeatChecks).toBe(false);
		transporter.init(broker.transit, jest.fn(), jest.fn());

		expect(broker.registry.nodes.disableHeartbeatChecks).toBe(true);
		expect(transporter.registry).toBe(broker.registry);
		expect(transporter.nodes).toBe(broker.registry.nodes);
	});

});

describe("Test TcpTransporter connect & disconnect & reconnect", () => {
	let broker = new ServiceBroker({ logger: false });
	let transit = new Transit(broker);
	let msgHandler = jest.fn();
	let transporter;

	beforeEach(() => {
		transporter = new TcpTransporter({ port: 1234 });
		transporter.init(transit, msgHandler);

		transporter.startTcpServer = jest.fn();
		transporter.startUdpServer = jest.fn();
		transporter.startTimers = jest.fn();
		transporter.stopTimers = jest.fn();
		transporter.loadUrls = jest.fn();
	});

	it("check connect", () => {
		transporter.onConnected = jest.fn(() => Promise.resolve());
		broker.registry.regenerateLocalRawInfo = jest.fn();

		let p = transporter.connect().catch(protectReject).then(() => {
			expect(transporter.connected).toBe(true);
			expect(transporter.startTcpServer).toHaveBeenCalledTimes(1);
			expect(transporter.startUdpServer).toHaveBeenCalledTimes(1);
			expect(transporter.startTimers).toHaveBeenCalledTimes(1);

			expect(broker.registry.nodes.localNode.port).toBe(1234);

			expect(broker.registry.regenerateLocalRawInfo).toHaveBeenCalledTimes(1);

			expect(transporter.onConnected).toHaveBeenCalledTimes(1);
			expect(transporter.loadUrls).toHaveBeenCalledTimes(0);
		});

		return p;
	});

	it("check connect with loadUrls", () => {
		transporter.onConnected = jest.fn(() => Promise.resolve());
		transporter.opts.urls = [];

		let p = transporter.connect().catch(protectReject).then(() => {
			expect(transporter.connected).toBe(true);
			expect(transporter.startTcpServer).toHaveBeenCalledTimes(1);
			expect(transporter.startUdpServer).toHaveBeenCalledTimes(1);
			expect(transporter.startTimers).toHaveBeenCalledTimes(1);

			expect(broker.registry.nodes.localNode.port).toBe(1234);

			expect(transporter.onConnected).toHaveBeenCalledTimes(1);
			expect(transporter.loadUrls).toHaveBeenCalledTimes(1);
		});

		return p;
	});

	it("check disconnect", () => {
		transporter.reader = { close: jest.fn() };
		transporter.writer = { close: jest.fn() };
		transporter.udpServer = { close: jest.fn() };

		return transporter.connect().catch(protectReject).then(() => {
			transporter.disconnect();
			expect(transporter.connected).toBe(false);
			expect(transporter.stopTimers).toHaveBeenCalledTimes(1);
			expect(transporter.reader.close).toHaveBeenCalledTimes(1);
			expect(transporter.writer.close).toHaveBeenCalledTimes(1);
			expect(transporter.udpServer.close).toHaveBeenCalledTimes(1);
		});
	});

});

describe("Test TcpTransporter getLocalNodeInfo & getNodeInfo", () => {
	let broker = new ServiceBroker({ logger: false });
	let transit = new Transit(broker);
	let msgHandler = jest.fn();
	let transporter = new TcpTransporter({ port: 1234 });
	transporter.init(transit, msgHandler);

	it("should return nodes.localNode", () => {
		expect(transporter.getLocalNodeInfo()).toBe(transporter.nodes.localNode);
	});

	it("should return with selected node", () => {
		let node = {};
		transporter.nodes.get = jest.fn(() => node);
		expect(transporter.getNodeInfo("node-2")).toBe(node);
		expect(transporter.nodes.get).toHaveBeenCalledTimes(1);
		expect(transporter.nodes.get).toHaveBeenCalledWith("node-2");
	});

});

describe("Test TcpTransporter subscribe & publish", () => {
	let transporter;

	beforeEach(() => {
		transporter = new TcpTransporter();
		transporter.init(new Transit(new ServiceBroker({ logger: false, namespace: "TEST", nodeID: "node-123" })));

		transporter.writer = {
			send: jest.fn(() => Promise.resolve())
		};

		transporter.startTcpServer = jest.fn();
		transporter.startUdpServer = jest.fn();
		transporter.startTimers = jest.fn();
		transporter.stopTimers = jest.fn();

		transporter.serialize = jest.fn(() => Buffer.from("json data"));

		return transporter.connect();
	});

	it("should send packet with target", () => {

		const packet = new P.Packet(P.PACKET_EVENT, "node2", {});
		return transporter.publish(packet)
			.catch(protectReject).then(() => {
				expect(transporter.writer.send).toHaveBeenCalledTimes(1);
				expect(transporter.writer.send).toHaveBeenCalledWith(
					"node2",
					1,
					Buffer.from("json data")
				);

				expect(transporter.serialize).toHaveBeenCalledTimes(1);
				expect(transporter.serialize).toHaveBeenCalledWith(packet);
			});
	});

	it("should call disconnect if can't send packet", () => {
		transporter.serialize.mockClear();
		transporter.writer.send = jest.fn(() => Promise.reject());
		transporter.nodes.disconnected = jest.fn();

		const packet = new P.Packet(P.PACKET_EVENT, "node2", {});
		return transporter.publish(packet)
			.then(protectReject).catch(() => {
				expect(transporter.writer.send).toHaveBeenCalledTimes(1);
				expect(transporter.writer.send).toHaveBeenCalledWith(
					"node2",
					1,
					Buffer.from("json data")
				);

				expect(transporter.nodes.disconnected).toHaveBeenCalledTimes(1);
				expect(transporter.nodes.disconnected).toHaveBeenCalledWith("node2", true);
			});
	});

	it("should not send without target", () => {
		transporter.serialize.mockClear();
		transporter.writer.send.mockClear();

		const packet = new P.Packet(P.PACKET_EVENT, null, {});
		return transporter.publish(packet)
			.catch(protectReject).then(() => {
				expect(transporter.writer.send).toHaveBeenCalledTimes(0);
				expect(transporter.serialize).toHaveBeenCalledTimes(0);
			});
	});

	it("should not send declined packets", () => {
		transporter.serialize.mockClear();
		transporter.writer.send.mockClear();

		const packet = new P.Packet(P.PACKET_DISCOVER);
		return transporter.publish(packet)
			.catch(protectReject).then(() => {
				expect(transporter.writer.send).toHaveBeenCalledTimes(0);
				expect(transporter.serialize).toHaveBeenCalledTimes(0);
			});
	});

});

describe("Test TcpTransporter nodes functions", () => {
	let broker = new ServiceBroker({ logger: false, namespace: "TEST", nodeID: "node-123" });
	let transit = new Transit(broker);
	let transporter;

	beforeEach(() => {
		transporter = new TcpTransporter();
		transporter.init(transit);

		transporter.startTcpServer = jest.fn();
		transporter.startUdpServer = jest.fn();
		transporter.startTimers = jest.fn();
		transporter.stopTimers = jest.fn();

		return transporter.connect();
	});

	it("should create an offline node", () => {
		expect(transporter.nodes.toArray().length).toBe(1);

		const node = transporter.addOfflineNode("node-123", "10.20.30.40", 12345);
		expect(node.id).toBe("node-123");
		expect(node.local).toBe(false);
		expect(node.hostname).toBe("10.20.30.40");
		expect(node.ipList).toEqual(["10.20.30.40"]);
		expect(node.port).toBe(12345);
		expect(node.available).toBe(false);
		expect(node.seq).toBe(0);
		expect(node.offlineSince).toBeDefined();

		expect(transporter.getNode("node-123")).toBe(node);
	});

	it("check getNodeAddress method", () => {
		const node = transporter.addOfflineNode("node-123", "10.20.30.40", 12345);
		node.udpAddress = "udp-address";
		node.hostname = "server-host";

		expect(transporter.getNodeAddress(node)).toBe("udp-address");

		node.udpAddress = null;
		expect(transporter.getNodeAddress(node)).toBe("server-host");

		transporter.opts.useHostname = false;
		expect(transporter.getNodeAddress(node)).toBe("10.20.30.40");

		transporter.opts.useHostname = true;
		node.hostname = null;
		expect(transporter.getNodeAddress(node)).toBe("10.20.30.40");

		node.ipList = [];
		expect(transporter.getNodeAddress(node)).toBeNull();
	});
});

describe("Test TcpTransporter startTcpServer", () => {
	let broker = new ServiceBroker({ logger: false, namespace: "TEST", nodeID: "node-123" });
	let transit = new Transit(broker);
	let transporter;

	beforeEach(() => {
		transporter = new TcpTransporter();
		transporter.init(transit);
	});

	it("check startTcpServer", () => {
		transporter.startTcpServer();

		expect(TcpWriter).toHaveBeenCalledTimes(1);
		expect(TcpWriter).toHaveBeenCalledWith(transporter, transporter.opts);

		expect(TcpReader).toHaveBeenCalledTimes(1);
		expect(TcpReader).toHaveBeenCalledWith(transporter, transporter.opts);

		expect(transporter.writer.on).toHaveBeenCalledTimes(2);
		expect(transporter.writer.on).toHaveBeenCalledWith("error", jasmine.any(Function));
		expect(transporter.writer.on).toHaveBeenCalledWith("end", jasmine.any(Function));

		expect(transporter.reader.listen).toHaveBeenCalledTimes(1);
		expect(transporter.reader.listen).toHaveBeenCalledWith();
	});

	it("check writer error handler", () => {
		transporter.startTcpServer();
		transporter.nodes.disconnected = jest.fn();

		transporter.writer.__callbacks.error(null, "node-2");

		expect(transporter.nodes.disconnected).toHaveBeenCalledTimes(1);
		expect(transporter.nodes.disconnected).toHaveBeenCalledWith("node-2", false);
	});

	it("check writer end handler", () => {
		transporter.startTcpServer();
		transporter.nodes.disconnected = jest.fn();

		transporter.writer.__callbacks.end("node-2");

		expect(transporter.nodes.disconnected).toHaveBeenCalledTimes(1);
		expect(transporter.nodes.disconnected).toHaveBeenCalledWith("node-2", false);
	});

});

describe("Test TcpTransporter startUdpServer", () => {
	let broker = new ServiceBroker({ logger: false, namespace: "TEST", nodeID: "node-123" });
	let transit = new Transit(broker);
	let transporter;

	beforeEach(() => {
		transporter = new TcpTransporter();
		transporter.init(transit);
	});

	it("check startUdpServer", () => {
		transporter.startUdpServer();

		expect(UdpServer).toHaveBeenCalledTimes(1);
		expect(UdpServer).toHaveBeenCalledWith(transporter, transporter.opts);

		expect(transporter.udpServer.on).toHaveBeenCalledTimes(1);
		expect(transporter.udpServer.on).toHaveBeenCalledWith("message", jasmine.any(Function));

		expect(transporter.udpServer.bind).toHaveBeenCalledTimes(1);
		expect(transporter.udpServer.bind).toHaveBeenCalledWith();
	});

	it("check UDP server message handler if new node", () => {
		transporter.startUdpServer();
		transporter.nodes.get = jest.fn(() => null);
		const node = {};
		transporter.addOfflineNode = jest.fn(() => node);

		transporter.udpServer.__callbacks.message("node-2", "10.20.30.40", 12345);

		expect(node.udpAddress).toBe("10.20.30.40");

		expect(transporter.nodes.get).toHaveBeenCalledTimes(1);
		expect(transporter.nodes.get).toHaveBeenCalledWith("node-2");

		expect(transporter.addOfflineNode).toHaveBeenCalledTimes(1);
		expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-2", "10.20.30.40", 12345);
	});

	it("check UDP server message handler if offline node", () => {
		transporter.startUdpServer();

		const node = { ipList: [], available: false };
		transporter.nodes.get = jest.fn(() => node);
		transporter.addOfflineNode = jest.fn(() => node);

		transporter.udpServer.__callbacks.message("node-2", "10.20.30.40", 12345);

		expect(node.hostname).toBe("10.20.30.40");
		expect(node.ipList).toEqual(["10.20.30.40"]);
		expect(node.port).toBe(12345);
		expect(node.udpAddress).toBe("10.20.30.40");

		expect(transporter.nodes.get).toHaveBeenCalledTimes(1);
		expect(transporter.nodes.get).toHaveBeenCalledWith("node-2");

		expect(transporter.addOfflineNode).toHaveBeenCalledTimes(0);
	});

	it("check UDP server message handler if available node", () => {
		transporter.startUdpServer();

		const node = { ipList: [], available: true, hostname: "old", port: 1000 };
		transporter.nodes.get = jest.fn(() => node);
		transporter.addOfflineNode = jest.fn(() => node);

		transporter.udpServer.__callbacks.message("node-2", "10.20.30.40", 12345);

		expect(node.hostname).toBe("old");
		expect(node.ipList).toEqual([]);
		expect(node.port).toBe(1000);
		expect(node.udpAddress).toBe("10.20.30.40");

		expect(transporter.nodes.get).toHaveBeenCalledTimes(1);
		expect(transporter.nodes.get).toHaveBeenCalledWith("node-2");

		expect(transporter.addOfflineNode).toHaveBeenCalledTimes(0);
	});

});

describe("Test TcpTransporter startUdpServer", () => {
	let broker = new ServiceBroker({ logger: false, namespace: "TEST", nodeID: "node-123" });
	let transit = new Transit(broker);
	let transporter;

	beforeEach(() => {
		transporter = new TcpTransporter();
		transporter.init(transit);
	});

	it("check startTimers", () => {
		expect(transporter.gossipTimer).toBeNull();
		transporter.startTimers();
		expect(transporter.gossipTimer).toBeDefined();
	});

	it("check startTimers", () => {
		transporter.startTimers();
		expect(transporter.gossipTimer).toBeDefined();
		transporter.stopTimers();
		expect(transporter.gossipTimer).toBeNull();
	});

});

describe("Test TcpTransporter loadUrls", () => {
	let broker = new ServiceBroker({ logger: false, namespace: "TEST", nodeID: "node-123" });
	let transit = new Transit(broker);

	function createTransporter(opts) {
		const transporter = new TcpTransporter(opts);
		transporter.init(transit);
		transporter.logger.warn = jest.fn();
		transporter.addOfflineNode = jest.fn();

		return transporter.loadUrls().then(() => transporter);
	}

	it("check with null", () => {
		return createTransporter({
			urls: null
		}).catch(protectReject).then(transporter => {
			expect(transporter.addOfflineNode).toHaveBeenCalledTimes(0);
			expect(transporter.logger.warn).toHaveBeenCalledTimes(0);
			expect(transporter.nodes.disableOfflineNodeRemoving).toBe(false);
		});
	});

	it("check with empty string", () => {
		return createTransporter({
			urls: ""
		}).catch(protectReject).then(transporter => {
			expect(transporter.addOfflineNode).toHaveBeenCalledTimes(0);
			expect(transporter.logger.warn).toHaveBeenCalledTimes(0);
			expect(transporter.nodes.disableOfflineNodeRemoving).toBe(false);
		});
	});

	it("check with empty array", () => {
		return createTransporter({
			urls: []
		}).catch(protectReject).then(transporter => {
			expect(transporter.addOfflineNode).toHaveBeenCalledTimes(0);
			expect(transporter.logger.warn).toHaveBeenCalledTimes(0);
			expect(transporter.nodes.disableOfflineNodeRemoving).toBe(false);
		});
	});

	it("check with string", () => {
		return createTransporter({
			urls: "tcp://192.168.0.1:5001/node-1, tcp://192.168.0.2:5002/node-2,192.168.0.3:5003/node-3,tcp://192.168.0.4:5004,tcp://192.168.0.123:5123/node-123,192.168.0.5/node-5",
			port: 1234
		}).catch(protectReject).then(transporter => {
			expect(transporter.addOfflineNode).toHaveBeenCalledTimes(3);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-1", "192.168.0.1", 5001);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-2", "192.168.0.2", 5002);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-3", "192.168.0.3", 5003);

			expect(transporter.logger.warn).toHaveBeenCalledTimes(2);
			expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing nodeID. URL:", "192.168.0.4:5004");
			expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing port. URL:", "192.168.0.5/node-5");

			expect(transporter.opts.port).toBe(1234);
			expect(transporter.nodes.disableOfflineNodeRemoving).toBe(true);
		});
	});

	it("check with connection string", () => {
		return createTransporter("tcp://192.168.0.1:5001/node-1, tcp://192.168.0.2:5002/node-2,192.168.0.3:5003/node-3,tcp://192.168.0.4:5004,tcp://192.168.0.123:5123/node-123,192.168.0.5/node-5")
			.catch(protectReject).then(transporter => {
				expect(transporter.addOfflineNode).toHaveBeenCalledTimes(3);
				expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-1", "192.168.0.1", 5001);
				expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-2", "192.168.0.2", 5002);
				expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-3", "192.168.0.3", 5003);

				expect(transporter.logger.warn).toHaveBeenCalledTimes(2);
				expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing nodeID. URL:", "192.168.0.4:5004");
				expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing port. URL:", "192.168.0.5/node-5");

				expect(transporter.opts.port).toBe(5123);
				expect(transporter.nodes.disableOfflineNodeRemoving).toBe(true);
			});
	});

	it("check with array", () => {
		return createTransporter({
			urls: [
				"tcp://192.168.0.1:5001/node-1",
				"tcp://192.168.0.2:5002/node-2",
				"192.168.0.3:5003/node-3",
				"tcp://192.168.0.4:5004",
				"tcp://192.168.0.123:5123/node-123",
				"192.168.0.5/node-5"
			]
		}).catch(protectReject).then(transporter => {
			expect(transporter.addOfflineNode).toHaveBeenCalledTimes(3);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-1", "192.168.0.1", 5001);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-2", "192.168.0.2", 5002);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-3", "192.168.0.3", 5003);

			expect(transporter.logger.warn).toHaveBeenCalledTimes(2);
			expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing nodeID. URL:", "192.168.0.4:5004");
			expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing port. URL:", "192.168.0.5/node-5");

			expect(transporter.nodes.disableOfflineNodeRemoving).toBe(true);
		});
	});

	it("check with object", () => {
		return createTransporter({
			urls: {
				"node-1": "tcp://192.168.0.1:5001",
				"node-2": "tcp://192.168.0.2:5002",
				"node-3": "192.168.0.3:5003",
				"node-4": "tcp://192.168.0.4:5004",
				"node-123": "tcp://192.168.0.123:5123",
				"node-5": "192.168.0.5"
			}
		}).catch(protectReject).then(transporter => {
			expect(transporter.addOfflineNode).toHaveBeenCalledTimes(4);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-1", "192.168.0.1", 5001);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-2", "192.168.0.2", 5002);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-3", "192.168.0.3", 5003);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-4", "192.168.0.4", 5004);

			expect(transporter.logger.warn).toHaveBeenCalledTimes(1);
			expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing port. URL:", "192.168.0.5/node-5");

			expect(transporter.nodes.disableOfflineNodeRemoving).toBe(true);
		});
	});

	describe("check with file path", () => {

		it("should parse txt file", () => {
			fs.readFileSync = jest.fn(() => "tcp://192.168.0.1:5001/node-1\ntcp://192.168.0.2:5002/node-2\n\n192.168.0.3:5003/node-3\ntcp://192.168.0.4:5004\ntcp://192.168.0.123:5123/node-123\n192.168.0.5/node-5\n");

			return createTransporter({
				urls: "file://./registry/nodes.txt"
			}).catch(protectReject).then(transporter => {
				expect(fs.readFileSync).toHaveBeenCalledTimes(1);
				expect(fs.readFileSync).toHaveBeenCalledWith("./registry/nodes.txt");

				expect(transporter.addOfflineNode).toHaveBeenCalledTimes(3);
				expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-1", "192.168.0.1", 5001);
				expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-2", "192.168.0.2", 5002);
				expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-3", "192.168.0.3", 5003);

				expect(transporter.logger.warn).toHaveBeenCalledTimes(2);
				expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing nodeID. URL:", "192.168.0.4:5004");
				expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing port. URL:", "192.168.0.5/node-5");

				expect(transporter.nodes.disableOfflineNodeRemoving).toBe(true);
			});
		});

		it("should parse json file", () => {
			fs.readFileSync = jest.fn(() => {
				return `
[
				"tcp://192.168.0.1:5001/node-1",
				"tcp://192.168.0.2:5002/node-2",
				"192.168.0.3:5003/node-3",
				"tcp://192.168.0.4:5004",
				"tcp://192.168.0.123:5123/node-123",
				"192.168.0.5/node-5"
]
`;
			});

			return createTransporter({
				urls: "file://./registry/nodes.json"
			}).catch(protectReject).then(transporter => {
				expect(fs.readFileSync).toHaveBeenCalledTimes(1);
				expect(fs.readFileSync).toHaveBeenCalledWith("./registry/nodes.json");

				expect(transporter.addOfflineNode).toHaveBeenCalledTimes(3);
				expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-1", "192.168.0.1", 5001);
				expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-2", "192.168.0.2", 5002);
				expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-3", "192.168.0.3", 5003);

				expect(transporter.logger.warn).toHaveBeenCalledTimes(2);
				expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing nodeID. URL:", "192.168.0.4:5004");
				expect(transporter.logger.warn).toHaveBeenCalledWith("Invalid endpoint URL. Missing port. URL:", "192.168.0.5/node-5");

				expect(transporter.nodes.disableOfflineNodeRemoving).toBe(true);
			});
		});
	});
});

describe("Test TcpTransporter onIncomingMessage", () => {
	let broker = new ServiceBroker({ logger: false, namespace: "TEST", nodeID: "node-123" });
	let transit = new Transit(broker);
	let transporter;

	beforeEach(() => {
		transporter = new TcpTransporter();
		transporter.init(transit);

		transporter.processGossipHello = jest.fn();
		transporter.processGossipRequest = jest.fn();
		transporter.processGossipResponse = jest.fn();
		transporter.incomingMessage = jest.fn();
	});

	it("should call processGossipHello", () => {
		let socket = {};
		transporter.onIncomingMessage(P.PACKET_GOSSIP_HELLO, "message", socket);

		expect(transporter.processGossipHello).toHaveBeenCalledTimes(1);
		expect(transporter.processGossipHello).toHaveBeenCalledWith("message", socket);
	});

	it("should call processGossipRequest", () => {
		transporter.onIncomingMessage(P.PACKET_GOSSIP_REQ, "message");

		expect(transporter.processGossipRequest).toHaveBeenCalledTimes(1);
		expect(transporter.processGossipRequest).toHaveBeenCalledWith("message");
	});

	it("should call processGossipResponse", () => {
		transporter.onIncomingMessage(P.PACKET_GOSSIP_RES, "message");

		expect(transporter.processGossipResponse).toHaveBeenCalledTimes(1);
		expect(transporter.processGossipResponse).toHaveBeenCalledWith("message");
	});

	it("should call incomingMessage", () => {
		transporter.onIncomingMessage(P.PACKET_REQUEST, "message");

		expect(transporter.incomingMessage).toHaveBeenCalledTimes(1);
		expect(transporter.incomingMessage).toHaveBeenCalledWith(P.PACKET_REQUEST, "message");

		transporter.onIncomingMessage(P.PACKET_EVENT, "message 2");

		expect(transporter.incomingMessage).toHaveBeenCalledTimes(2);
		expect(transporter.incomingMessage).toHaveBeenCalledWith(P.PACKET_EVENT, "message 2");
	});

});

describe("Test Gossip methods", () => {
	let broker = new ServiceBroker({ logger: false, namespace: "TEST", nodeID: "node-1" });
	let transit = new Transit(broker);
	let transporter;

	beforeEach(() => {
		transporter = new TcpTransporter();
		transporter.init(transit);
	});

	describe("Test onIncomingMessage", () => {

		it("should call processGossipHello", () => {
			const msg = {};
			const socket = {};
			transporter.processGossipHello = jest.fn();

			transporter.onIncomingMessage(P.PACKET_GOSSIP_HELLO, msg, socket);

			expect(transporter.processGossipHello).toHaveBeenCalledTimes(1);
			expect(transporter.processGossipHello).toHaveBeenCalledWith(msg, socket);
		});

		it("should call processGossipRequest", () => {
			const msg = {};
			transporter.processGossipRequest = jest.fn();

			transporter.onIncomingMessage(P.PACKET_GOSSIP_REQ, msg);

			expect(transporter.processGossipRequest).toHaveBeenCalledTimes(1);
			expect(transporter.processGossipRequest).toHaveBeenCalledWith(msg);
		});

		it("should call processGossipResponse", () => {
			const msg = {};
			transporter.processGossipResponse = jest.fn();

			transporter.onIncomingMessage(P.PACKET_GOSSIP_RES, msg);

			expect(transporter.processGossipResponse).toHaveBeenCalledTimes(1);
			expect(transporter.processGossipResponse).toHaveBeenCalledWith(msg);
		});

		it("should call incomingMessage", () => {
			const msg = {};
			transporter.incomingMessage = jest.fn();

			transporter.onIncomingMessage(P.PACKET_REQUEST, msg);
			expect(transporter.incomingMessage).toHaveBeenCalledTimes(1);
			expect(transporter.incomingMessage).toHaveBeenCalledWith(P.PACKET_REQUEST, msg);

			transporter.onIncomingMessage(P.PACKET_EVENT, msg);
			expect(transporter.incomingMessage).toHaveBeenCalledTimes(2);
			expect(transporter.incomingMessage).toHaveBeenCalledWith(P.PACKET_EVENT, msg);
		});

	});

	describe("Test sendHello", () => {

		it("should throw error if nodeID is unknown", () => {
			transporter.getNode = jest.fn();

			return transporter.sendHello("node-xy").then(protectReject).catch(err => {
				expect(err).toBeInstanceOf(E.MoleculerServerError);
				expect(err.message).toBe("Missing node info for 'node-xy'");
			});
		});

		it("should publish a HELLO packet", () => {
			transporter.getNode = jest.fn(() => ({
				id: "node-2",
				ipList: ["192.168.1.2"]
			}));
			transporter.publish = jest.fn(() => Promise.resolve());
			transporter.getNodeAddress = jest.fn(() => "node-1-host");

			transporter.sendHello("node-2");

			expect(transporter.publish).toHaveBeenCalledTimes(1);
			expect(transporter.publish).toHaveBeenCalledWith({
				type: "GOSSIP_HELLO",
				target: "node-2",
				payload: {
					host: "node-1-host",
					port: null
				}
			});
		});

	});

	describe("Test processGossipHello", () => {

		it("should create as offline node", () => {
			transporter.addOfflineNode = jest.fn();
			transporter.nodes.get = jest.fn();
			transporter.deserialize = jest.fn(() => ({
				payload: {
					sender: "node-2",
					host: "node-2-host",
					port: 5555
				}
			}));

			transporter.processGossipHello("message");

			expect(transporter.deserialize).toHaveBeenCalledTimes(1);
			expect(transporter.deserialize).toHaveBeenCalledWith(P.PACKET_GOSSIP_HELLO, "message");

			expect(transporter.nodes.get).toHaveBeenCalledTimes(1);
			expect(transporter.nodes.get).toHaveBeenCalledWith("node-2");

			expect(transporter.addOfflineNode).toHaveBeenCalledTimes(1);
			expect(transporter.addOfflineNode).toHaveBeenCalledWith("node-2", "node-2-host", 5555);
		});

		it("should not create as offline node if already exists", () => {
			transporter.addOfflineNode = jest.fn();
			transporter.nodes.get = jest.fn(() => ({}));
			transporter.deserialize = jest.fn(() => ({
				payload: {
					sender: "node-2",
					host: "node-2-host",
					port: 5555
				}
			}));

			transporter.processGossipHello("message");

			expect(transporter.nodes.get).toHaveBeenCalledTimes(1);
			expect(transporter.nodes.get).toHaveBeenCalledWith("node-2");

			expect(transporter.addOfflineNode).toHaveBeenCalledTimes(0);
		});

	});

	describe("Test sendGossipToRandomEndpoint", () => {
		const endpoints = [
			{ id: "node-1" },
			{ id: "node-2" },
			{ id: "node-3" },
			{ id: "node-4" },
		];

		const data = {
			a: 5
		};

		it("should not publish if no endpoint", () => {
			transporter.publish = jest.fn(() => Promise.resolve());

			transporter.sendGossipToRandomEndpoint(data, []);

			expect(transporter.publish).toHaveBeenCalledTimes(0);
		});

		it("should select a random endpoint and publish", () => {
			Math.random = jest.fn(() => .6);
			transporter.publish = jest.fn(() => Promise.resolve());

			transporter.sendGossipToRandomEndpoint(data, endpoints);

			expect(transporter.publish).toHaveBeenCalledTimes(1);
			expect(transporter.publish).toHaveBeenCalledWith({
				type: "GOSSIP_REQ",
				target: "node-3",
				payload: {
					a: 5
				}
			});
		});

	});

	describe("Test sendGossipRequest", () => {

		beforeEach(() => {
			Math.random = jest.fn(() => 0);
			transporter.sendGossipToRandomEndpoint = jest.fn();
		});

		it("should send nothing, if no other nodes", () => {
			transporter.nodes.toArray = jest.fn(() => ([
				{ id: "node-1", local: true }
			]));

			transporter.sendGossipRequest();

			expect(transporter.sendGossipToRandomEndpoint).toHaveBeenCalledTimes(0);
		});

		it("should send info to online node", () => {
			const nodes = [
				{ id: "node-1", local: true, available: true,  seq: 5, cpu: 12, cpuSeq: 2 },
				{ id: "node-2", local: false, available: true, seq: 3 },
			];
			transporter.nodes.toArray = jest.fn(() => nodes);

			transporter.sendGossipRequest();

			expect(transporter.sendGossipToRandomEndpoint).toHaveBeenCalledTimes(1);
			expect(transporter.sendGossipToRandomEndpoint).toHaveBeenCalledWith({
				online: {
					"node-1": [5, 2, 12],
					"node-2": [3, 0, 0]
				}
			},[ nodes[1]]);
		});

		it("should send info to offline node", () => {
			const nodes = [
				{ id: "node-1", local: true, available: true,  seq: 5, cpu: 12, cpuSeq: 2 },
				{ id: "node-2", local: false, available: false, seq: 4 },
			];
			transporter.nodes.toArray = jest.fn(() => nodes);

			transporter.sendGossipRequest();

			expect(transporter.sendGossipToRandomEndpoint).toHaveBeenCalledTimes(1);
			expect(transporter.sendGossipToRandomEndpoint).toHaveBeenCalledWith({
				online: {
					"node-1": [5, 2, 12]
				},
				offline: {
					"node-2": 4
				}
			},[ nodes[1]]);
		});

		it("should send info to online & offline nodes", () => {
			const nodes = [
				{ id: "node-1", local: true,  available: true,  seq: 10, cpu: 11, cpuSeq: 100 },
				{ id: "node-2", local: false, available: true,  seq: 20, cpu: 22, cpuSeq: 200 },
				{ id: "node-3", local: false, available: true,  seq: 30, cpu: 33, cpuSeq: 300 },
				{ id: "node-4", local: false, available: false, seq: 40, cpu: 44, cpuSeq: 400 },
				{ id: "node-5", local: false, available: false, seq: 50, cpu: 55, cpuSeq: 500 },
			];
			transporter.nodes.toArray = jest.fn(() => nodes);

			transporter.sendGossipRequest();

			expect(transporter.sendGossipToRandomEndpoint).toHaveBeenCalledTimes(2);
			expect(transporter.sendGossipToRandomEndpoint).toHaveBeenCalledWith({
				online: {
					"node-1": [10, 100, 11],
					"node-2": [20, 200, 22],
					"node-3": [30, 300, 33],
				},
				offline: {
					"node-4": 40,
					"node-5": 50,
				}
			},[ nodes[1], nodes[2]]);
			expect(transporter.sendGossipToRandomEndpoint).toHaveBeenCalledWith({
				online: {
					"node-1": [10, 100, 11],
					"node-2": [20, 200, 22],
					"node-3": [30, 300, 33],
				},
				offline: {
					"node-4": 40,
					"node-5": 50,
				}
			},[ nodes[3], nodes[4]]);
		});

	});

	describe("Test processGossipRequest", () => {

		beforeEach(() => {
			Math.random = jest.fn(() => 0);
			transporter.deserialize = jest.fn((type, msg) => msg);
			transporter.publish = jest.fn(() => Promise.resolve());
			transporter.nodes.get = jest.fn(() => ({ id: "node-2" }));
			transporter.nodes.disconnected = jest.fn(() => null);
			transporter.registry.getNodeInfo = jest.fn(id => ({ info: id }));
		});

		it("should update local info and send new node info", () => {
			const nodes = [
				{ id: "node-1", local: true,  available: true,  seq: 10, cpu: 11, cpuSeq: 100 },
				{ id: "node-2", local: false, available: true,  seq: 20, cpu: 22, cpuSeq: 200 },
				{ id: "node-3", local: false, available: true,  seq: 30, cpu: 33, cpuSeq: 300 },
				{ id: "node-4", local: false, available: false, seq: 40, cpu: 44, cpuSeq: 400 },
				{ id: "node-5", local: false, available: false, seq: 50, cpu: 55, cpuSeq: 500 },
				{ id: "node-6", local: false, available: false, seq: 60, cpu: 66, cpuSeq: 600 },
			];
			transporter.nodes.toArray = jest.fn(() => nodes);

			transporter.processGossipRequest({
				sender: "node-2",
				payload: {
					online: {
						"node-1": [15, 100, 11], // Local - do nothing
						"node-2": [18, 180, 10], // We got older info, send newer
						"node-5": [48, 500, 55], // We got older info, send it is offline
						"node-6": [66, 606, 6], // We got newer info, but we think it is offline, skip
						"node-7": [70, 700, 77], // We don't know it, skip
					},
					offline: {
						"node-4": 41, // Newer seq
						"node-3": 33, // Newer seq, Gone to offline, we change it to offline
						"node-8": 88, // We don't know it, skip
					}
				}
			});

			expect(transporter.registry.getNodeInfo).toHaveBeenCalledTimes(1);
			expect(transporter.registry.getNodeInfo).toHaveBeenCalledWith("node-2");

			expect(transporter.nodes.disconnected).toHaveBeenCalledTimes(1);
			expect(transporter.nodes.disconnected).toHaveBeenCalledWith("node-3", false);
			expect(nodes[2].seq).toBe(33);

			expect(transporter.publish).toHaveBeenCalledTimes(1);
			expect(transporter.publish).toHaveBeenCalledWith({
				type: "GOSSIP_RES",
				target: "node-2",
				payload: {
					"online": {
						"node-2": [{"info": "node-2"}, 200, 22]
					},
					"offline": {
						"node-5": 50
					},
				}
			});
		});

		it("should update local info and send new node info and inc our seq", () => {
			const heartbeat = jest.fn();
			const nodes = [
				{ id: "node-1", local: true,  available: true,  seq: 1, cpu: 11, cpuSeq: 100 },
				{ id: "node-2", local: false, available: true,  seq: 20, cpu: 22, cpuSeq: 200, heartbeat },
				{ id: "node-3", local: false, available: true,  seq: 30, cpu: 33, cpuSeq: 300 },
				{ id: "node-4", local: false, available: false, seq: 40, cpu: 44, cpuSeq: 400 },
				{ id: "node-5", local: false, available: false, seq: 50, cpu: 55, cpuSeq: 500 },
				{ id: "node-6", local: false, available: false, seq: 60, cpu: 66, cpuSeq: 600 },
				{ id: "node-7", local: false, available: true, seq: 70, cpu: null, cpuSeq: null },
				{ id: "node-8", local: false, available: true, seq: 80, cpu: 88, cpuSeq: 800 },
			];
			transporter.nodes.toArray = jest.fn(() => nodes);
			transporter.nodes.get = jest.fn(() => ({ id: "node-10" }));
			transporter.registry.getNodeInfo = jest.fn(id => ({ info: id }));
			transporter.registry.getLocalNodeInfo = jest.fn(() => ({ info: "node-1" }));

			transporter.processGossipRequest({
				sender: "node-10",
				payload: {
					online: {
						"node-2": [20, 220, 25], // We got newer CPU info, update local
						"node-3": [30, 300, 33], // No changes, skip
						// No node-7, send back with info
						"node-8": [80, 777, 77], // Whet got older CPU info, send back newer
					},
					offline: {
						"node-1": 33, // Local - inc seq & send we are online
						// No "node-4", send back
						// No "node-5", send back
						"node-6": 60, // No changes, skip
					}
				}
			});

			// Local Seq Incremented
			expect(nodes[0].seq).toBe(34);

			expect(transporter.registry.getNodeInfo).toHaveBeenCalledTimes(1);
			expect(transporter.registry.getNodeInfo).toHaveBeenCalledWith("node-7");

			expect(transporter.registry.getLocalNodeInfo).toHaveBeenCalledTimes(1);
			expect(transporter.registry.getLocalNodeInfo).toHaveBeenCalledWith(true);

			// Update 'node-2'
			expect(heartbeat).toHaveBeenCalledTimes(1);
			expect(heartbeat).toHaveBeenCalledWith({ cpu: 25, cpuSeq: 220 });

			expect(transporter.nodes.disconnected).toHaveBeenCalledTimes(0);

			expect(transporter.publish).toHaveBeenCalledTimes(1);
			expect(transporter.publish).toHaveBeenCalledWith({
				type: "GOSSIP_RES",
				target: "node-10",
				payload: {
					online: {
						"node-1": [{"info": "node-1"}, 100, 11],
						"node-7": [{"info": "node-7"}, 0, 0],
						"node-8": [800, 88]
					},
					offline: {
						"node-4": 40,
						"node-5": 50
					},
				}
			});
		});
	});

	describe("Test processGossipResponse", () => {

		beforeEach(() => {
			Math.random = jest.fn(() => 0);
			transporter.deserialize = jest.fn((type, msg) => msg);
			transporter.nodes.disconnected = jest.fn();
			transporter.nodes.processNodeInfo = jest.fn();
		});

		it("should update local info and send new node info", () => {
			const heartbeat = jest.fn();
			const nodes = [
				// Online nodes
				{ id: "node-1", local: true,  available: true,  seq: 10, cpu: 11, cpuSeq: 100 },
				{ id: "node-2", local: false, available: true,  seq: 20, cpu: 22, cpuSeq: 200 },
				{ id: "node-3", local: false, available: true,  seq: 30, cpu: 33, cpuSeq: 300 },
				{ id: "node-4", local: false, available: true,  seq: 40, cpu: 44, cpuSeq: 400 },
				{ id: "node-5", local: false, available: true, seq: 50, cpu: 55, cpuSeq: 500, heartbeat },
				//{ id: "node-6", local: false, available: true, seq: 60, cpu: 66, cpuSeq: 600 },

				// Offline nodes
				{ id: "node-7", local: false, available: false, seq: 70, cpu: 77, cpuSeq: 700 },
				{ id: "node-8", local: false, available: false, seq: 80, cpu: 88, cpuSeq: 800 },
				{ id: "node-9", local: false, available: false, seq: 90, cpu: 99, cpuSeq: 900 },
				{ id: "node-10", local: false, available: true, seq: 100, cpu: 100, cpuSeq: 1000 },
			];
			transporter.nodes.toArray = jest.fn(() => nodes);
			transporter.nodes.get = jest.fn(id => nodes.find(n => n.id == id));

			transporter.processGossipResponse({
				sender: "node-2",
				payload: {
					online: {
						"node-1": [{ seq: 15 }, 100, 11], // Local - skip
						"node-2": [{ seq: 18 }, 180, 10], // We got older info, skip
						"node-5": [550, 5], // We got only new CPU info, update
						"node-6": [{ seq: 66 }, 660, 6], // We got newer info from unknow node, update
						"node-7": [{ seq: 77 }], // We got only new info from offline node, update
					},
					offline: {
						"node-8": 88, // We got newer seq, update
						"node-9": 33, // We got older seq, skip
						"node-10": 101, // We got newer seq from online node, disconnect and save seq
						"node-11": 110, // Unknow node, skip
					}
				}
			});

			// Update 'node-5' cpu
			expect(heartbeat).toHaveBeenCalledTimes(1);
			expect(heartbeat).toHaveBeenCalledWith({ cpu: 5, cpuSeq: 550 });

			// Update 'node-6' & 'node-7'
			expect(transporter.nodes.processNodeInfo).toHaveBeenCalledTimes(2);
			expect(transporter.nodes.processNodeInfo).toHaveBeenCalledWith({"sender": "node-6", "seq": 66});
			expect(transporter.nodes.processNodeInfo).toHaveBeenCalledWith({"sender": "node-7", "seq": 77});

			// Update 'node-8' seq
			expect(nodes[6].seq).toBe(88);

			// Disconnect 'node-10'
			expect(transporter.nodes.disconnected).toHaveBeenCalledTimes(1);
			expect(transporter.nodes.disconnected).toHaveBeenCalledWith("node-10", false);
			expect(nodes[8].seq).toBe(101);

		});

	});

});


text:
namespace NetworkClient {

//----------------------------------------------------------------------------//

class NETWORK_CLIENT_EXPORTED AbstractMessageHandler : public QObject
{
    Q_OBJECT

public:
    explicit AbstractMessageHandler(QObject *parent = nullptr);
    virtual ~AbstractMessageHandler() override;

signals:
    void outboundMessage(QByteArray data);

public slots:
    virtual void onInboundMessage(int serverState, QByteArray data) = 0;
};

//----------------------------------------------------------------------------//

} // namespace NetworkClient

//----------------------------------------------------------------------------//

#endif // ABSTRACTMESSAGEHANDLER_HPP

//----------------------------------------------------------------------------//