text:
package org.elasticsearch.common.settings;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.cluster.routing.allocation.DiskThresholdSettings;
import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider;
import org.elasticsearch.cluster.routing.allocation.decider.ShardsLimitAllocationDecider;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportSettings;
import org.junit.Test;

import io.crate.types.ArrayType;
import io.crate.types.DataTypes;

public class ScopedSettingsTests extends ESTestCase {

    @Test
    public void testResetSetting() {
        Setting<Integer> dynamicSetting = Setting.intSetting("some.dyn.setting", 1, Property.Dynamic, Property.NodeScope);
        Setting<Integer> staticSetting = Setting.intSetting("some.static.setting", 1, Property.NodeScope);
        Settings currentSettings = Settings.builder().put("some.dyn.setting", 5).put("some.static.setting", 6).put("archived.foo.bar", 9)
            .build();
        ClusterSettings service = new ClusterSettings(currentSettings
            , new HashSet<>(Arrays.asList(dynamicSetting, staticSetting)));

        expectThrows(IllegalArgumentException.class, () ->
        service.updateDynamicSettings(Settings.builder().put("some.dyn.setting", 8).putNull("some.static.setting").build(),
            Settings.builder().put(currentSettings), Settings.builder(), "node"));

        Settings.Builder target = Settings.builder().put(currentSettings);
        Settings.Builder update = Settings.builder();
        assertTrue(service.updateDynamicSettings(Settings.builder().put("some.dyn.setting", 8).build(),
            target, update, "node"));
        assertEquals(8, dynamicSetting.get(target.build()).intValue());
        assertEquals(6, staticSetting.get(target.build()).intValue());
        assertEquals(9, target.build().getAsInt("archived.foo.bar", null).intValue());

        target = Settings.builder().put(currentSettings);
        update = Settings.builder();
        assertTrue(service.updateDynamicSettings(Settings.builder().putNull("some.dyn.setting").build(),
            target, update, "node"));
        assertEquals(1, dynamicSetting.get(target.build()).intValue());
        assertEquals(6, staticSetting.get(target.build()).intValue());
        assertEquals(9, target.build().getAsInt("archived.foo.bar", null).intValue());

        target = Settings.builder().put(currentSettings);
        update = Settings.builder();
        assertTrue(service.updateDynamicSettings(Settings.builder().putNull("archived.foo.bar").build(),
            target, update, "node"));
        assertEquals(5, dynamicSetting.get(target.build()).intValue());
        assertEquals(6, staticSetting.get(target.build()).intValue());
        assertNull(target.build().getAsInt("archived.foo.bar", null));

        target = Settings.builder().put(currentSettings);
        update = Settings.builder();
        assertTrue(service.updateDynamicSettings(Settings.builder().putNull("some.*").build(),
            target, update, "node"));
        assertEquals(1, dynamicSetting.get(target.build()).intValue());
        assertEquals(6, staticSetting.get(target.build()).intValue());
        assertEquals(9, target.build().getAsInt("archived.foo.bar", null).intValue());

        target = Settings.builder().put(currentSettings);
        update = Settings.builder();
        assertTrue(service.updateDynamicSettings(Settings.builder().putNull("*").build(),
            target, update, "node"));
        assertEquals(1, dynamicSetting.get(target.build()).intValue());
        assertEquals(6, staticSetting.get(target.build()).intValue());
        assertNull(target.build().getAsInt("archived.foo.bar", null));
    }

    @Test
    public void testResetSettingWithIPValidator() {
        Settings currentSettings = Settings.builder().put("index.routing.allocation.require._ip", "192.168.0.1,127.0.0.1")
            .put("index.some.dyn.setting", 1)
            .build();
        Setting<Integer> dynamicSetting = Setting.intSetting("index.some.dyn.setting", 1, Property.Dynamic, Property.IndexScope);

        IndexScopedSettings settings = new IndexScopedSettings(currentSettings,
            new HashSet<>(Arrays.asList(dynamicSetting, IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING)));
        Map<String, String> s = IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getAsMap(currentSettings);
        assertEquals(1, s.size());
        assertEquals("192.168.0.1,127.0.0.1", s.get("_ip"));
        Settings.Builder builder = Settings.builder();
        Settings updates = Settings.builder().putNull("index.routing.allocation.require._ip")
            .put("index.some.dyn.setting", 1).build();
        settings.validate(updates, false);
        settings.updateDynamicSettings(updates,
            Settings.builder().put(currentSettings), builder, "node");
        currentSettings = builder.build();
        s = IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getAsMap(currentSettings);
        assertEquals(0, s.size());
        assertEquals(1, dynamicSetting.get(currentSettings).intValue());
        assertEquals(1, currentSettings.size());
    }

    @Test
    public void testAddConsumer() {
        Setting<Integer> testSetting = Setting.intSetting("foo.bar", 1, Property.Dynamic, Property.NodeScope);
        Setting<Integer> testSetting2 = Setting.intSetting("foo.bar.baz", 1, Property.Dynamic, Property.NodeScope);
        AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY, Collections.singleton(testSetting));

        AtomicInteger consumer = new AtomicInteger();
        service.addSettingsUpdateConsumer(testSetting, consumer::set);
        AtomicInteger consumer2 = new AtomicInteger();
        try {
            service.addSettingsUpdateConsumer(testSetting2, consumer2::set);
            fail("setting not registered");
        } catch (IllegalArgumentException ex) {
            assertEquals("Setting is not registered for key [foo.bar.baz]", ex.getMessage());
        }

        try {
            service.addSettingsUpdateConsumer(testSetting, testSetting2, (a, b) -> {
                consumer.set(a);
                consumer2.set(b);
            });
            fail("setting not registered");
        } catch (IllegalArgumentException ex) {
            assertEquals("Setting is not registered for key [foo.bar.baz]", ex.getMessage());
        }
        assertEquals(0, consumer.get());
        assertEquals(0, consumer2.get());
        service.applySettings(Settings.builder().put("foo.bar", 2).put("foo.bar.baz", 15).build());
        assertEquals(2, consumer.get());
        assertEquals(0, consumer2.get());
    }

    @Test
    public void testDependentSettings() {
        Setting.AffixSetting<String> stringSetting = Setting.affixKeySetting("foo.", "name",
            (k) -> Setting.simpleString(k, Property.Dynamic, Property.NodeScope));
        Setting.AffixSetting<Integer> intSetting = Setting.affixKeySetting("foo.", "bar",
            (k) ->  Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope), () -> stringSetting);

        AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY, new HashSet<>(Arrays.asList(intSetting, stringSetting)));

        IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
            () -> service.validate(Settings.builder().put("foo.test.bar", 7).build(), true));
        assertEquals("missing required setting [foo.test.name] for setting [foo.test.bar]", iae.getMessage());

        service.validate(Settings.builder()
            .put("foo.test.name", "test")
            .put("foo.test.bar", 7)
            .build(), true);

        service.validate(Settings.builder().put("foo.test.bar", 7).build(), false);
    }

    @Test
    public void testDependentSettingsValidate() {
        Setting.AffixSetting<String> stringSetting = Setting.affixKeySetting(
            "foo.",
            "name",
            (k) -> Setting.simpleString(k, Property.Dynamic, Property.NodeScope));
        Setting.AffixSetting<Integer> intSetting = Setting.affixKeySetting(
            "foo.",
            "bar",
            (k) -> Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope),
            new Setting.AffixSettingDependency() {

                @Override
                public Setting.AffixSetting getSetting() {
                    return stringSetting;
                }

                @Override
                public void validate(final String key, final Object value, final Object dependency) {
                    if ("valid".equals(dependency) == false) {
                        throw new SettingsException("[" + key + "] is set but [name] is [" + dependency + "]");
                    }
                }
            });

        AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY, new HashSet<>(Arrays.asList(intSetting, stringSetting)));

        SettingsException iae = expectThrows(
            SettingsException.class,
            () -> service.validate(Settings.builder().put("foo.test.bar", 7).put("foo.test.name", "invalid").build(), true));
        assertEquals("[foo.test.bar] is set but [name] is [invalid]", iae.getMessage());

        service.validate(Settings.builder()
                .put("foo.test.bar", 7)
                .put("foo.test.name", "valid")
                .build(),
            true);

        service.validate(Settings.builder()
            .put("foo.test.bar", 7)
            .put("foo.test.name", "invalid")
            .build(),
            false);
    }

    public void testDependentSettingsWithFallback() {
        Setting.AffixSetting<String> nameFallbackSetting =
                Setting.affixKeySetting("fallback.", "name", k -> Setting.simpleString(k, Property.Dynamic, Property.NodeScope));
        Setting.AffixSetting<String> nameSetting = Setting.affixKeySetting(
                "foo.",
                "name",
                k -> Setting.simpleString(
                        k,
                        "_na_".equals(k)
                                ? nameFallbackSetting.getConcreteSettingForNamespace(k)
                                : nameFallbackSetting.getConcreteSetting(k.replaceAll("^foo", "fallback")),
                        Property.Dynamic,
                        Property.NodeScope));
        Setting.AffixSetting<Integer> barSetting = Setting.affixKeySetting(
            "foo.",
            "bar",
            k -> Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope),
            () -> nameSetting);

        final AbstractScopedSettings service =
                new ClusterSettings(Settings.EMPTY,new HashSet<>(Arrays.asList(nameFallbackSetting, nameSetting, barSetting)));

        final IllegalArgumentException e = expectThrows(
                IllegalArgumentException.class,
                () -> service.validate(Settings.builder().put("foo.test.bar", 7).build(), true));
        assertThat(e, hasToString(containsString("missing required setting [foo.test.name] for setting [foo.test.bar]")));

        service.validate(Settings.builder().put("foo.test.name", "test").put("foo.test.bar", 7).build(), true);
        service.validate(Settings.builder().put("fallback.test.name", "test").put("foo.test.bar", 7).build(), true);
    }

    @Test
    public void testAddConsumerAffix() {
        Setting.AffixSetting<Integer> intSetting = Setting.affixKeySetting("foo.", "bar",
            (k) ->  Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope));
        Setting.AffixSetting<List<Integer>> listSetting = Setting.affixKeySetting("foo.", "list",
            (k) -> Setting.listSetting(k, Arrays.asList("1"), Integer::parseInt, new ArrayType<>(DataTypes.INTEGER), Property.Dynamic, Property.NodeScope));
        AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY,new HashSet<>(Arrays.asList(intSetting, listSetting)));
        Map<String, List<Integer>> listResults = new HashMap<>();
        Map<String, Integer> intResults = new HashMap<>();

        BiConsumer<String, Integer> intConsumer = intResults::put;
        BiConsumer<String, List<Integer>> listConsumer = listResults::put;

        service.addAffixUpdateConsumer(listSetting, listConsumer, (s, k) -> {});
        service.addAffixUpdateConsumer(intSetting, intConsumer, (s, k) -> {});
        assertEquals(0, listResults.size());
        assertEquals(0, intResults.size());
        service.applySettings(Settings.builder()
            .put("foo.test.bar", 2)
            .put("foo.test_1.bar", 7)
            .putList("foo.test_list.list", "16", "17")
            .putList("foo.test_list_1.list", "18", "19", "20")
            .build());
        assertEquals(2, intResults.get("test").intValue());
        assertEquals(7, intResults.get("test_1").intValue());
        assertEquals(Arrays.asList(16, 17), listResults.get("test_list"));
        assertEquals(Arrays.asList(18, 19, 20), listResults.get("test_list_1"));
        assertEquals(2, listResults.size());
        assertEquals(2, intResults.size());

        listResults.clear();
        intResults.clear();

        service.applySettings(Settings.builder()
            .put("foo.test.bar", 2)
            .put("foo.test_1.bar", 8)
            .putList("foo.test_list.list", "16", "17")
            .putNull("foo.test_list_1.list")
            .build());
        assertNull("test wasn't changed", intResults.get("test"));
        assertEquals(8, intResults.get("test_1").intValue());
        assertNull("test_list wasn't changed", listResults.get("test_list"));
        assertEquals(Arrays.asList(1), listResults.get("test_list_1")); // reset to default
        assertEquals(1, listResults.size());
        assertEquals(1, intResults.size());
    }

    @Test
    public void testAddConsumerAffixMap() {
        Setting.AffixSetting<Integer> intSetting = Setting.affixKeySetting("foo.", "bar",
            (k) ->  Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope));
        Setting.AffixSetting<List<Integer>> listSetting = Setting.affixKeySetting("foo.", "list",
            (k) -> Setting.listSetting(k, Arrays.asList("1"), Integer::parseInt, DataTypes.INTEGER_ARRAY, Property.Dynamic, Property.NodeScope));
        AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY,new HashSet<>(Arrays.asList(intSetting, listSetting)));
        Map<String, List<Integer>> listResults = new HashMap<>();
        Map<String, Integer> intResults = new HashMap<>();

        Consumer<Map<String,Integer>> intConsumer = (map) -> {
            intResults.clear();
            intResults.putAll(map);
        };
        Consumer<Map<String, List<Integer>>> listConsumer = (map) -> {
            listResults.clear();
            listResults.putAll(map);
        };
        service.addAffixMapUpdateConsumer(listSetting, listConsumer, (s, k) -> {});
        service.addAffixMapUpdateConsumer(intSetting, intConsumer, (s, k) -> {});
        assertEquals(0, listResults.size());
        assertEquals(0, intResults.size());
        service.applySettings(Settings.builder()
            .put("foo.test.bar", 2)
            .put("foo.test_1.bar", 7)
            .putList("foo.test_list.list", "16", "17")
            .putList("foo.test_list_1.list", "18", "19", "20")
            .build());
        assertEquals(2, intResults.get("test").intValue());
        assertEquals(7, intResults.get("test_1").intValue());
        assertEquals(Arrays.asList(16, 17), listResults.get("test_list"));
        assertEquals(Arrays.asList(18, 19, 20), listResults.get("test_list_1"));
        assertEquals(2, listResults.size());
        assertEquals(2, intResults.size());

        service.applySettings(Settings.builder()
            .put("foo.test.bar", 2)
            .put("foo.test_1.bar", 7)
            .putList("foo.test_list.list", "16", "17")
            .putList("foo.test_list_1.list", "18", "19", "20")
            .build());

        assertEquals(2, intResults.get("test").intValue());
        assertEquals(7, intResults.get("test_1").intValue());
        assertEquals(Arrays.asList(16, 17), listResults.get("test_list"));
        assertEquals(Arrays.asList(18, 19, 20), listResults.get("test_list_1"));
        assertEquals(2, listResults.size());
        assertEquals(2, intResults.size());

        listResults.clear();
        intResults.clear();

        service.applySettings(Settings.builder()
            .put("foo.test.bar", 2)
            .put("foo.test_1.bar", 8)
            .putList("foo.test_list.list", "16", "17")
            .putNull("foo.test_list_1.list")
            .build());
        assertNull("test wasn't changed", intResults.get("test"));
        assertEquals(8, intResults.get("test_1").intValue());
        assertNull("test_list wasn't changed", listResults.get("test_list"));
        assertEquals(Arrays.asList(1), listResults.get("test_list_1")); // reset to default
        assertEquals(1, listResults.size());
        assertEquals(1, intResults.size());
    }

    @Test
    public void testAffixMapConsumerNotCalledWithNull() {
        Setting.AffixSetting<Integer> prefixSetting = Setting.prefixKeySetting("eggplant.",
                (k) ->  Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope));
        Setting.AffixSetting<Integer> otherSetting = Setting.prefixKeySetting("other.",
                (k) ->  Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope));
        AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY,new HashSet<>(Arrays.asList(prefixSetting, otherSetting)));
        Map<String, Integer> affixResults = new HashMap<>();

        Consumer<Map<String,Integer>> consumer = (map) -> {
            logger.info("--> consuming settings {}", map);
            affixResults.clear();
            affixResults.putAll(map);
        };
        service.addAffixMapUpdateConsumer(prefixSetting, consumer, (s, k) -> {});
        assertEquals(0, affixResults.size());
        service.applySettings(Settings.builder()
                .put("eggplant._name", 2)
                .build());
        assertThat(affixResults.size(), equalTo(1));
        assertThat(affixResults.get("_name"), equalTo(2));

        service.applySettings(Settings.builder()
                .put("eggplant._name", 2)
                .put("other.thing", 3)
                .build());

        assertThat(affixResults.get("_name"), equalTo(2));
    }

    @Test
    public void testApply() {
        Setting<Integer> testSetting = Setting.intSetting("foo.bar", 1, Property.Dynamic, Property.NodeScope);
        Setting<Integer> testSetting2 = Setting.intSetting("foo.bar.baz", 1, Property.Dynamic, Property.NodeScope);
        AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY, new HashSet<>(Arrays.asList(testSetting, testSetting2)));

        AtomicInteger consumer = new AtomicInteger();
        service.addSettingsUpdateConsumer(testSetting, consumer::set);
        AtomicInteger consumer2 = new AtomicInteger();
        service.addSettingsUpdateConsumer(testSetting2, consumer2::set, (s) -> assertTrue(s > 0));

        AtomicInteger aC = new AtomicInteger();
        AtomicInteger bC = new AtomicInteger();
        service.addSettingsUpdateConsumer(testSetting, testSetting2, (a, b) -> {
            aC.set(a);
            bC.set(b);
        });

        assertEquals(0, consumer.get());
        assertEquals(0, consumer2.get());
        assertEquals(0, aC.get());
        assertEquals(0, bC.get());
        try {
            service.applySettings(Settings.builder().put("foo.bar", 2).put("foo.bar.baz", -15).build());
            fail("invalid value");
        } catch (IllegalArgumentException ex) {
            assertEquals("illegal value can't update [foo.bar.baz] from [1] to [-15]", ex.getMessage());
        }
        assertEquals(0, consumer.get());
        assertEquals(0, consumer2.get());
        assertEquals(0, aC.get());
        assertEquals(0, bC.get());
        try {
            service.validateUpdate(Settings.builder().put("foo.bar", 2).put("foo.bar.baz", -15).build());
            fail("invalid value");
        } catch (IllegalArgumentException ex) {
            assertEquals("illegal value can't update [foo.bar.baz] from [1] to [-15]", ex.getMessage());
        }

        assertEquals(0, consumer.get());
        assertEquals(0, consumer2.get());
        assertEquals(0, aC.get());
        assertEquals(0, bC.get());
        service.validateUpdate(Settings.builder().put("foo.bar", 2).put("foo.bar.baz", 15).build());
        assertEquals(0, consumer.get());
        assertEquals(0, consumer2.get());
        assertEquals(0, aC.get());
        assertEquals(0, bC.get());

        service.applySettings(Settings.builder().put("foo.bar", 2).put("foo.bar.baz", 15).build());
        assertEquals(2, consumer.get());
        assertEquals(15, consumer2.get());
        assertEquals(2, aC.get());
        assertEquals(15, bC.get());
    }

    @Test
    public void testGet() {
        ClusterSettings settings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
        // affix setting - complex matcher
        Setting setting = settings.get("cluster.routing.allocation.require.value");
        assertEquals(setting,
            FilterAllocationDecider.CLUSTER_ROUTING_REQUIRE_GROUP_SETTING.getConcreteSetting("cluster.routing.allocation.require.value"));

        setting = settings.get("cluster.routing.allocation.total_shards_per_node");
        assertEquals(setting, ShardsLimitAllocationDecider.CLUSTER_TOTAL_SHARDS_PER_NODE_SETTING);

        // array settings - complex matcher
        assertNotNull(settings.get("transport.tracer.include." + randomIntBetween(1, 100)));
        assertSame(TransportSettings.TRACE_LOG_INCLUDE_SETTING, settings.get("transport.tracer.include." + randomIntBetween(1, 100)));

        // array settings - complex matcher - only accepts numbers
        assertNull(settings.get("transport.tracer.include.FOO"));
    }

    @Test
    public void testIsDynamic(){
        ClusterSettings settings =
            new ClusterSettings(Settings.EMPTY,
                new HashSet<>(Arrays.asList(Setting.intSetting("foo.bar", 1, Property.Dynamic, Property.NodeScope),
                    Setting.intSetting("foo.bar.baz", 1, Property.NodeScope))));
        assertFalse(settings.isDynamicSetting("foo.bar.baz"));
        assertTrue(settings.isDynamicSetting("foo.bar"));
        assertNotNull(settings.get("foo.bar.baz"));
        settings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
        assertTrue(settings.isDynamicSetting("transport.tracer.include." + randomIntBetween(1, 100)));
        assertFalse(settings.isDynamicSetting("transport.tracer.include.BOOM"));
        assertTrue(settings.isDynamicSetting("cluster.routing.allocation.require.value"));
    }

    @Test
    public void testIsFinal() {
        ClusterSettings settings =
            new ClusterSettings(Settings.EMPTY,
                new HashSet<>(Arrays.asList(Setting.intSetting("foo.int", 1, Property.Final, Property.NodeScope),
                    Setting.groupSetting("foo.group.",  Property.Final, Property.NodeScope),
                    Setting.groupSetting("foo.list.",  Property.Final, Property.NodeScope),
                    Setting.intSetting("foo.int.baz", 1, Property.NodeScope))));

        assertFalse(settings.isFinalSetting("foo.int.baz"));
        assertTrue(settings.isFinalSetting("foo.int"));

        assertFalse(settings.isFinalSetting("foo.list"));
        assertTrue(settings.isFinalSetting("foo.list.0.key"));
        assertTrue(settings.isFinalSetting("foo.list.key"));

        assertFalse(settings.isFinalSetting("foo.group"));
        assertTrue(settings.isFinalSetting("foo.group.key"));
    }

    @Test
    public void testDiff() throws IOException {
        Setting<Integer> fooBarBaz = Setting.intSetting("foo.bar.baz", 1, Property.NodeScope);
        Setting<Integer> fooBar = Setting.intSetting("foo.bar", 1, Property.Dynamic, Property.NodeScope);
        Setting<Settings> someGroup = Setting.groupSetting("some.group.", Property.Dynamic, Property.NodeScope);
        Setting<Boolean> someAffix = Setting.affixKeySetting("some.prefix.", "somekey", (key) -> Setting.boolSetting(key, true,
            Property.NodeScope));
        Setting<List<String>> foorBarQuux =
                Setting.listSetting("foo.bar.quux", Arrays.asList("a", "b", "c"), Function.identity(), DataTypes.STRING, Property.NodeScope);
        ClusterSettings settings = new ClusterSettings(Settings.EMPTY, new HashSet<>(Arrays.asList(fooBar, fooBarBaz, foorBarQuux,
            someGroup, someAffix)));
        Settings diff = settings.diff(Settings.builder().put("foo.bar", 5).build(), Settings.EMPTY);
        assertEquals(2, diff.size());
        assertThat(diff.getAsInt("foo.bar.baz", null), equalTo(1));
        assertEquals(diff.getAsList("foo.bar.quux", null), Arrays.asList("a", "b", "c"));

        diff = settings.diff(
                Settings.builder().put("foo.bar", 5).build(),
                Settings.builder().put("foo.bar.baz", 17).putList("foo.bar.quux", "d", "e", "f").build());
        assertEquals(2, diff.size());
        assertThat(diff.getAsInt("foo.bar.baz", null), equalTo(17));
        assertEquals(diff.getAsList("foo.bar.quux", null), Arrays.asList("d", "e", "f"));

        diff = settings.diff(
            Settings.builder().put("some.group.foo", 5).build(),
            Settings.builder().put("some.group.foobar", 17).put("some.group.foo", 25).build());
        assertEquals(4, diff.size());
        assertThat(diff.getAsInt("some.group.foobar", null), equalTo(17));
        assertNull(diff.get("some.group.foo"));
        assertEquals(diff.getAsList("foo.bar.quux", null), Arrays.asList("a", "b", "c"));
        assertThat(diff.getAsInt("foo.bar.baz", null), equalTo(1));
        assertThat(diff.getAsInt("foo.bar", null), equalTo(1));

        diff = settings.diff(
            Settings.builder().put("some.prefix.foo.somekey", 5).build(),
            Settings.builder().put("some.prefix.foobar.somekey", 17).put("some.prefix.foo.somekey", 18).build());
        assertEquals(4, diff.size());
        assertThat(diff.getAsInt("some.prefix.foobar.somekey", null), equalTo(17));
        assertNull(diff.get("some.prefix.foo.somekey"));
        assertEquals(diff.getAsList("foo.bar.quux", null), Arrays.asList("a", "b", "c"));
        assertThat(diff.getAsInt("foo.bar.baz", null), equalTo(1));
        assertThat(diff.getAsInt("foo.bar", null), equalTo(1));
    }

    @Test
    public void testDiffWithAffixAndComplexMatcher() {
        Setting<Integer> fooBarBaz = Setting.intSetting("foo.bar.baz", 1, Property.NodeScope);
        Setting<Integer> fooBar = Setting.intSetting("foo.bar", 1, Property.Dynamic, Property.NodeScope);
        Setting<Settings> someGroup = Setting.groupSetting("some.group.", Property.Dynamic, Property.NodeScope);
        Setting<Boolean> someAffix = Setting.affixKeySetting("some.prefix.", "somekey", (key) -> Setting.boolSetting(key, true,
            Property.NodeScope));
        Setting<List<String>> foorBarQuux = Setting.affixKeySetting("foo.", "quux",
            (key) -> Setting.listSetting(key,  Arrays.asList("a", "b", "c"), Function.identity(), DataTypes.STRING_ARRAY, Property.NodeScope));
        ClusterSettings settings = new ClusterSettings(Settings.EMPTY, new HashSet<>(Arrays.asList(fooBar, fooBarBaz, foorBarQuux,
            someGroup, someAffix)));
        Settings diff = settings.diff(Settings.builder().put("foo.bar", 5).build(), Settings.EMPTY);
        assertEquals(1, diff.size());
        assertThat(diff.getAsInt("foo.bar.baz", null), equalTo(1));
        assertNull(diff.getAsList("foo.bar.quux", null)); // affix settings don't know their concrete keys

        diff = settings.diff(
            Settings.builder().put("foo.bar", 5).build(),
            Settings.builder().put("foo.bar.baz", 17).putList("foo.bar.quux", "d", "e", "f").build());
        assertEquals(2, diff.size());
        assertThat(diff.getAsInt("foo.bar.baz", null), equalTo(17));
        assertEquals(diff.getAsList("foo.bar.quux", null), Arrays.asList("d", "e", "f"));

        diff = settings.diff(
            Settings.builder().put("some.group.foo", 5).build(),
            Settings.builder().put("some.group.foobar", 17).put("some.group.foo", 25).build());
        assertEquals(3, diff.size());
        assertThat(diff.getAsInt("some.group.foobar", null), equalTo(17));
        assertNull(diff.get("some.group.foo"));
        assertNull(diff.getAsList("foo.bar.quux", null)); // affix settings don't know their concrete keys
        assertThat(diff.getAsInt("foo.bar.baz", null), equalTo(1));
        assertThat(diff.getAsInt("foo.bar", null), equalTo(1));

        diff = settings.diff(
            Settings.builder().put("some.prefix.foo.somekey", 5).build(),
            Settings.builder().put("some.prefix.foobar.somekey", 17).put("some.prefix.foo.somekey", 18).build());
        assertEquals(3, diff.size());
        assertThat(diff.getAsInt("some.prefix.foobar.somekey", null), equalTo(17));
        assertNull(diff.get("some.prefix.foo.somekey"));
        assertNull(diff.getAsList("foo.bar.quux", null)); // affix settings don't know their concrete keys
        assertThat(diff.getAsInt("foo.bar.baz", null), equalTo(1));
        assertThat(diff.getAsInt("foo.bar", null), equalTo(1));

        diff = settings.diff(
            Settings.builder().put("some.prefix.foo.somekey", 5).build(),
            Settings.builder().put("some.prefix.foobar.somekey", 17).put("some.prefix.foo.somekey", 18)
            .putList("foo.bar.quux", "x", "y", "z")
            .putList("foo.baz.quux", "d", "e", "f")
                .build());
        assertEquals(5, diff.size());
        assertThat(diff.getAsInt("some.prefix.foobar.somekey", null), equalTo(17));
        assertNull(diff.get("some.prefix.foo.somekey"));
        assertEquals(diff.getAsList("foo.bar.quux", null), Arrays.asList("x", "y", "z"));
        assertEquals(diff.getAsList("foo.baz.quux", null), Arrays.asList("d", "e", "f"));
        assertThat(diff.getAsInt("foo.bar.baz", null), equalTo(1));
        assertThat(diff.getAsInt("foo.bar", null), equalTo(1));
    }

    @Test
    public void testUpdateTracer() {
        ClusterSettings settings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
        AtomicReference<List<String>> ref = new AtomicReference<>();
        settings.addSettingsUpdateConsumer(TransportSettings.TRACE_LOG_INCLUDE_SETTING, ref::set);
        settings.applySettings(Settings.builder()
                .putList("transport.tracer.include", "internal:index/shard/recovery/*", "internal:gateway/local*").build());
        assertNotNull(ref.get().size());
        assertEquals(ref.get().size(), 2);
        assertTrue(ref.get().contains("internal:index/shard/recovery/*"));
        assertTrue(ref.get().contains("internal:gateway/local*"));
    }

    @Test
    public void testGetSetting() {
        IndexScopedSettings settings = new IndexScopedSettings(
           Settings.EMPTY,
            IndexScopedSettings.BUILT_IN_INDEX_SETTINGS);
        IndexScopedSettings copy = settings.copy(Settings.builder().put("index.store.type", "boom").build(),
                newIndexMeta("foo", Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 3).build()));
        assertEquals(3, copy.get(IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING).intValue());
        assertEquals(1, copy.get(IndexMetadata.INDEX_NUMBER_OF_SHARDS_SETTING).intValue());
        assertEquals("boom", copy.get(IndexModule.INDEX_STORE_TYPE_SETTING)); // test fallback to node settings
    }

    @Test
    public void testValidateWithSuggestion() {
        IndexScopedSettings settings = new IndexScopedSettings(
            Settings.EMPTY,
            IndexScopedSettings.BUILT_IN_INDEX_SETTINGS);
        IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
            () -> settings.validate(Settings.builder().put("index.numbe_of_replica", "1").build(), false));
        assertEquals(iae.getMessage(), "unknown setting [index.numbe_of_replica] did you mean [index.number_of_replicas]?");
    }

    @Test
    public void testValidate() {
        IndexScopedSettings settings = new IndexScopedSettings(
            Settings.EMPTY,
            IndexScopedSettings.BUILT_IN_INDEX_SETTINGS);
        String unknownMsgSuffix = " please check that any required plugins are installed, or check the breaking changes documentation for" +
            " removed settings";
        settings.validate(Settings.builder().put("index.store.type", "boom").build(), false);

        IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
            settings.validate(Settings.builder().put("index.store.type", "boom").put("i.am.not.a.setting", true).build(), false));
        assertEquals("unknown setting [i.am.not.a.setting]" + unknownMsgSuffix, e.getMessage());

        e = expectThrows(IllegalArgumentException.class, () ->
            settings.validate(Settings.builder().put("index.store.type", "boom").put("index.number_of_replicas", true).build(), false));
        assertEquals("Failed to parse value [true] for setting [index.number_of_replicas]", e.getMessage());

        e = expectThrows(IllegalArgumentException.class, () ->
            settings.validate("index.number_of_replicas", Settings.builder().put("index.number_of_replicas", "true").build(), false));
        assertEquals("Failed to parse value [true] for setting [index.number_of_replicas]", e.getMessage());
    }

    public static IndexMetadata newIndexMeta(String name, Settings indexSettings) {
        Settings build = Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
            .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 1)
            .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
            .put(indexSettings)
            .build();
        IndexMetadata metadata = IndexMetadata.builder(name).settings(build).build();
        return metadata;
    }

    @Test
    public void testKeyPattern() {
        assertTrue(AbstractScopedSettings.isValidKey("a.b.c-b.d"));
        assertTrue(AbstractScopedSettings.isValidKey("a.b.c.d"));
        assertTrue(AbstractScopedSettings.isValidKey("a.b_012.c_b.d"));
        assertTrue(AbstractScopedSettings.isValidKey("a"));
        assertFalse(AbstractScopedSettings.isValidKey("a b"));
        assertFalse(AbstractScopedSettings.isValidKey(""));
        assertFalse(AbstractScopedSettings.isValidKey("\""));

        try {
            new IndexScopedSettings(
                Settings.EMPTY, Collections.singleton(Setting.groupSetting("foo.bar.", Property.IndexScope)));
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("illegal settings key: [foo.bar.] must start with [index.]", e.getMessage());
        }

        try {
            new IndexScopedSettings(
                Settings.EMPTY, Collections.singleton(Setting.simpleString("foo.bar", Property.IndexScope)));
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("illegal settings key: [foo.bar] must start with [index.]", e.getMessage());
        }

        try {
            new IndexScopedSettings(
                Settings.EMPTY, Collections.singleton(Setting.groupSetting("index. foo.", Property.IndexScope)));
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("illegal settings key: [index. foo.]", e.getMessage());
        }
        new IndexScopedSettings(
            Settings.EMPTY, Collections.singleton(Setting.groupSetting("index.", Property.IndexScope)));
        try {
            new IndexScopedSettings(
                Settings.EMPTY, Collections.singleton(Setting.boolSetting("index.", true, Property.IndexScope)));
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("illegal settings key: [index.]", e.getMessage());
        }
        new IndexScopedSettings(
            Settings.EMPTY, Collections.singleton(Setting.boolSetting("index.boo", true, Property.IndexScope)));

        new ClusterSettings(
            Settings.EMPTY, Collections.singleton(Setting.boolSetting("index.boo", true, Property.NodeScope)));
    }

    @Test
    public void testAffixKeyPattern() {
        assertTrue(AbstractScopedSettings.isValidAffixKey("prefix.*.suffix"));
        assertTrue(AbstractScopedSettings.isValidAffixKey("prefix.*.split.suffix"));
        assertTrue(AbstractScopedSettings.isValidAffixKey("split.prefix.*.split.suffix"));
        assertFalse(AbstractScopedSettings.isValidAffixKey("prefix.*.suffix."));
        assertFalse(AbstractScopedSettings.isValidAffixKey("prefix.*"));
        assertFalse(AbstractScopedSettings.isValidAffixKey("*.suffix"));
        assertFalse(AbstractScopedSettings.isValidAffixKey("*"));
        assertFalse(AbstractScopedSettings.isValidAffixKey(""));
    }

    @Test
    public void testLoggingUpdates() {
        final Level level = LogManager.getRootLogger().getLevel();
        final Level testLevel = LogManager.getLogger("test").getLevel();
        Level property = randomFrom(Level.values());
        Settings.Builder builder = Settings.builder().put("logger.level", property);
        try {
            ClusterSettings settings = new ClusterSettings(builder.build(), ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
            IllegalArgumentException ex =
                expectThrows(
                    IllegalArgumentException.class,
                    () -> settings.validate(Settings.builder().put("logger._root", "boom").build(), false));
            assertEquals("Unknown level constant [BOOM].", ex.getMessage());
            assertEquals(level, LogManager.getRootLogger().getLevel());
            settings.applySettings(Settings.builder().put("logger._root", "TRACE").build());
            assertEquals(Level.TRACE, LogManager.getRootLogger().getLevel());
            settings.applySettings(Settings.builder().build());
            assertEquals(property, LogManager.getRootLogger().getLevel());
            settings.applySettings(Settings.builder().put("logger.test", "TRACE").build());
            assertEquals(Level.TRACE, LogManager.getLogger("test").getLevel());
            settings.applySettings(Settings.builder().build());
            assertEquals(property, LogManager.getLogger("test").getLevel());
        } finally {
            Loggers.setLevel(LogManager.getRootLogger(), level);
            Loggers.setLevel(LogManager.getLogger("test"), testLevel);
        }
    }

    @Test
    public void testFallbackToLoggerLevel() {
        final Level level = LogManager.getRootLogger().getLevel();
        try {
            ClusterSettings settings =
                new ClusterSettings(Settings.builder().put("logger.level", "ERROR").build(), ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
            assertEquals(level, LogManager.getRootLogger().getLevel());
            settings.applySettings(Settings.builder().put("logger._root", "TRACE").build());
            assertEquals(Level.TRACE, LogManager.getRootLogger().getLevel());
            settings.applySettings(Settings.builder().build()); // here we fall back to 'logger.level' which is our default.
            assertEquals(Level.ERROR, LogManager.getRootLogger().getLevel());
        } finally {
            Loggers.setLevel(LogManager.getRootLogger(), level);
        }
    }

    @Test
    public void testOverlappingComplexMatchSettings() {
        Set<Setting<?>> settings = new LinkedHashSet<>(2);
        final boolean groupFirst = randomBoolean();
        final Setting<?> groupSetting = Setting.groupSetting("foo.", Property.NodeScope);
        final Setting<?> listSetting =
            Setting.listSetting("foo.bar", Collections.emptyList(), Function.identity(), DataTypes.STRING_ARRAY, Property.NodeScope);
        settings.add(groupFirst ? groupSetting : listSetting);
        settings.add(groupFirst ? listSetting : groupSetting);

        try {
            new ClusterSettings(Settings.EMPTY, settings);
            fail("an exception should have been thrown because settings overlap");
        } catch (IllegalArgumentException e) {
            if (groupFirst) {
                assertEquals("complex setting key: [foo.bar] overlaps existing setting key: [foo.]", e.getMessage());
            } else {
                assertEquals("complex setting key: [foo.] overlaps existing setting key: [foo.bar]", e.getMessage());
            }
        }
    }

    @Test
    public void testUpdateNumberOfShardsFail() {
        IndexScopedSettings settings = new IndexScopedSettings(Settings.EMPTY,
            IndexScopedSettings.BUILT_IN_INDEX_SETTINGS);
        IllegalArgumentException ex = expectThrows(IllegalArgumentException.class,
            () -> settings.updateSettings(Settings.builder().put("index.number_of_shards", 8).build(),
                Settings.builder(), Settings.builder(), "index"));
        assertThat(ex.getMessage(),
            containsString("final index setting [index.number_of_shards], not updateable"));
    }

    @Test
    public void testFinalSettingUpdateFail() {
        Setting<Integer> finalSetting = Setting.intSetting("some.final.setting", 1, Property.Final, Property.NodeScope);
        Setting<Settings> finalGroupSetting = Setting.groupSetting("some.final.group.", Property.Final, Property.NodeScope);
        Settings currentSettings = Settings.builder()
            .put("some.final.setting", 9)
            .put("some.final.group.foo", 7)
            .build();
        ClusterSettings service = new ClusterSettings(currentSettings
            , new HashSet<>(Arrays.asList(finalSetting, finalGroupSetting)));

        IllegalArgumentException exc = expectThrows(IllegalArgumentException.class, () ->
            service.updateDynamicSettings(Settings.builder().put("some.final.setting", 8).build(),
                Settings.builder().put(currentSettings), Settings.builder(), "node"));
        assertThat(exc.getMessage(), containsString("final node setting [some.final.setting]"));

        exc = expectThrows(IllegalArgumentException.class, () ->
            service.updateDynamicSettings(Settings.builder().putNull("some.final.setting").build(),
                Settings.builder().put(currentSettings), Settings.builder(), "node"));
        assertThat(exc.getMessage(), containsString("final node setting [some.final.setting]"));

        exc = expectThrows(IllegalArgumentException.class, () ->
            service.updateSettings(Settings.builder().put("some.final.group.new", 8).build(),
                Settings.builder().put(currentSettings), Settings.builder(), "node"));
        assertThat(exc.getMessage(), containsString("final node setting [some.final.group.new]"));

        exc = expectThrows(IllegalArgumentException.class, () ->
            service.updateSettings(Settings.builder().put("some.final.group.foo", 5).build(),
                Settings.builder().put(currentSettings), Settings.builder(), "node"));
        assertThat(exc.getMessage(), containsString("final node setting [some.final.group.foo]"));
    }

    @Test
    public void testInternalIndexSettingsFailsValidation() {
        final Setting<String> indexInternalSetting = Setting.simpleString("index.internal", Property.InternalIndex, Property.IndexScope);
        final IndexScopedSettings indexScopedSettings =
                new IndexScopedSettings(Settings.EMPTY, Collections.singleton(indexInternalSetting));
        final IllegalArgumentException e = expectThrows(
                IllegalArgumentException.class,
                () -> {
                    final Settings settings = Settings.builder().put("index.internal", "internal").build();
                    indexScopedSettings.validate(settings, false, /* validateInternalOrPrivateIndex */ true);
                });
        final String message = "can not update internal setting [index.internal]; this setting is managed via a dedicated API";
        assertThat(e, hasToString(containsString(message)));
    }

    @Test
    public void testPrivateIndexSettingsFailsValidation() {
        final Setting<String> indexInternalSetting = Setting.simpleString("index.private", Property.PrivateIndex, Property.IndexScope);
        final IndexScopedSettings indexScopedSettings =
                new IndexScopedSettings(Settings.EMPTY, Collections.singleton(indexInternalSetting));
        final IllegalArgumentException e = expectThrows(
                IllegalArgumentException.class,
                () -> {
                    final Settings settings = Settings.builder().put("index.private", "private").build();
                    indexScopedSettings.validate(settings, false, /* validateInternalOrPrivateIndex */ true);
                });
        final String message = "can not update private setting [index.private]; this setting is managed by CrateDB";
        assertThat(e, hasToString(containsString(message)));
    }

    @Test
    public void testInternalIndexSettingsSkipValidation() {
        final Setting<String> internalIndexSetting = Setting.simpleString("index.internal", Property.InternalIndex, Property.IndexScope);
        final IndexScopedSettings indexScopedSettings =
                new IndexScopedSettings(Settings.EMPTY, Collections.singleton(internalIndexSetting));
        // nothing should happen, validation should not throw an exception
        final Settings settings = Settings.builder().put("index.internal", "internal").build();
        indexScopedSettings.validate(settings, false, /* validateInternalOrPrivateIndex */ false);
    }

    @Test
    public void testPrivateIndexSettingsSkipValidation() {
        final Setting<String> internalIndexSetting = Setting.simpleString("index.private", Property.PrivateIndex, Property.IndexScope);
        final IndexScopedSettings indexScopedSettings =
                new IndexScopedSettings(Settings.EMPTY, Collections.singleton(internalIndexSetting));
        // nothing should happen, validation should not throw an exception
        final Settings settings = Settings.builder().put("index.private", "private").build();
        indexScopedSettings.validate(settings, false, /* validateInternalOrPrivateIndex */ false);
    }

    @Test
    public void testUpgradeSetting() {
        final Setting<String> oldSetting = Setting.simpleString("foo.old", Property.NodeScope);
        final Setting<String> newSetting = Setting.simpleString("foo.new", Property.NodeScope);
        final Setting<String> remainingSetting = Setting.simpleString("foo.remaining", Property.NodeScope);

        final AbstractScopedSettings service =
                new ClusterSettings(
                        Settings.EMPTY,
                        List.of(),
                        new HashSet<>(Arrays.asList(oldSetting, newSetting, remainingSetting)),
                        Collections.singleton(new SettingUpgrader<String>() {

                            @Override
                            public Setting<String> getSetting() {
                                return oldSetting;
                            }

                            @Override
                            public String getKey(final String key) {
                                return "foo.new";
                            }

                            @Override
                            public String getValue(final String value) {
                                return "new." + value;
                            }

                        }));

        final Settings settings =
                Settings.builder()
                        .put("foo.old", randomAlphaOfLength(8))
                        .put("foo.remaining", randomAlphaOfLength(8))
                        .build();
        final Settings upgradedSettings = service.upgradeSettings(settings);
        assertFalse(oldSetting.exists(upgradedSettings));
        assertTrue(newSetting.exists(upgradedSettings));
        assertThat(newSetting.get(upgradedSettings), equalTo("new." + oldSetting.get(settings)));
        assertTrue(remainingSetting.exists(upgradedSettings));
        assertThat(remainingSetting.get(upgradedSettings), equalTo(remainingSetting.get(settings)));
    }

    @Test
    public void testUpgradeSettingsNoChangesPreservesInstance() {
        final Setting<String> oldSetting = Setting.simpleString("foo.old", Property.NodeScope);
        final Setting<String> newSetting = Setting.simpleString("foo.new", Property.NodeScope);
        final Setting<String> remainingSetting = Setting.simpleString("foo.remaining", Property.NodeScope);

        final AbstractScopedSettings service =
                new ClusterSettings(
                        Settings.EMPTY,
                        List.of(),
                        new HashSet<>(Arrays.asList(oldSetting, newSetting, remainingSetting)),
                        Collections.singleton(new SettingUpgrader<String>() {

                            @Override
                            public Setting<String> getSetting() {
                                return oldSetting;
                            }

                            @Override
                            public String getKey(final String key) {
                                return "foo.new";
                            }

                        }));

        final Settings settings = Settings.builder().put("foo.remaining", randomAlphaOfLength(8)).build();
        final Settings upgradedSettings = service.upgradeSettings(settings);
        assertThat(upgradedSettings, sameInstance(settings));
    }

    @Test
    public void testUpgradeComplexSetting() {
        final Setting.AffixSetting<String> oldSetting =
                Setting.affixKeySetting("foo.old.", "suffix", key -> Setting.simpleString(key, Property.NodeScope));
        final Setting.AffixSetting<String> newSetting =
                Setting.affixKeySetting("foo.new.", "suffix", key -> Setting.simpleString(key, Property.NodeScope));
        final Setting.AffixSetting<String> remainingSetting =
                Setting.affixKeySetting("foo.remaining.", "suffix", key -> Setting.simpleString(key, Property.NodeScope));

        final AbstractScopedSettings service =
                new ClusterSettings(
                        Settings.EMPTY,
                        List.of(),
                        new HashSet<>(Arrays.asList(oldSetting, newSetting, remainingSetting)),
                        Collections.singleton(new SettingUpgrader<String>() {

                            @Override
                            public Setting<String> getSetting() {
                                return oldSetting;
                            }

                            @Override
                            public String getKey(final String key) {
                                return key.replaceFirst("^foo\\.old", "foo\\.new");
                            }

                            @Override
                            public String getValue(final String value) {
                                return "new." + value;
                            }

                        }));

        final int count = randomIntBetween(1, 8);
        final List<String> concretes = new ArrayList<>(count);
        final Settings.Builder builder = Settings.builder();
        for (int i = 0; i < count; i++) {
            final String concrete = randomAlphaOfLength(8);
            concretes.add(concrete);
            builder.put("foo.old." + concrete + ".suffix", randomAlphaOfLength(8));
            builder.put("foo.remaining." + concrete + ".suffix", randomAlphaOfLength(8));
        }
        final Settings settings = builder.build();
        final Settings upgradedSettings = service.upgradeSettings(settings);
        for (final String concrete : concretes) {
            assertFalse(oldSetting.getConcreteSettingForNamespace(concrete).exists(upgradedSettings));
            assertTrue(newSetting.getConcreteSettingForNamespace(concrete).exists(upgradedSettings));
            assertThat(
                    newSetting.getConcreteSettingForNamespace(concrete).get(upgradedSettings),
                    equalTo("new." + oldSetting.getConcreteSettingForNamespace(concrete).get(settings)));
            assertTrue(remainingSetting.getConcreteSettingForNamespace(concrete).exists(upgradedSettings));
            assertThat(
                    remainingSetting.getConcreteSettingForNamespace(concrete).get(upgradedSettings),
                    equalTo(remainingSetting.getConcreteSettingForNamespace(concrete).get(settings)));
        }
    }

    @Test
    public void testUpgradeListSetting() {
        final Setting<List<String>> oldSetting =
                Setting.listSetting("foo.old", Collections.emptyList(), Function.identity(), DataTypes.STRING_ARRAY, Property.NodeScope);
        final Setting<List<String>> newSetting =
                Setting.listSetting("foo.new", Collections.emptyList(), Function.identity(), DataTypes.STRING_ARRAY, Property.NodeScope);

        final AbstractScopedSettings service =
                new ClusterSettings(
                        Settings.EMPTY,
                        List.of(),
                        new HashSet<>(Arrays.asList(oldSetting, newSetting)),
                        Collections.singleton(new SettingUpgrader<List<String>>() {

                            @Override
                            public Setting<List<String>> getSetting() {
                                return oldSetting;
                            }

                            @Override
                            public String getKey(final String key) {
                                return "foo.new";
                            }

                            @Override
                            public List<String> getListValue(final List<String> value) {
                                return value.stream().map(s -> "new." + s).collect(Collectors.toList());
                            }
                        }));

        final int length = randomIntBetween(0, 16);
        final List<String> values = length == 0 ? Collections.emptyList() : new ArrayList<>(length);
        for (int i = 0; i < length; i++) {
            values.add(randomAlphaOfLength(8));
        }

        final Settings settings = Settings.builder().putList("foo.old", values).build();
        final Settings upgradedSettings = service.upgradeSettings(settings);
        assertFalse(oldSetting.exists(upgradedSettings));
        assertTrue(newSetting.exists(upgradedSettings));
        assertThat(
                newSetting.get(upgradedSettings),
                equalTo(oldSetting.get(settings).stream().map(s -> "new." + s).collect(Collectors.toList())));
    }

    @Test
    public void test_update_setting_with_dependency() throws Exception {
        Setting<String> low = DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK_SETTING;
        Setting<String> high = DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_HIGH_DISK_WATERMARK_SETTING;
        Setting<String> flood = DiskThresholdSettings.CLUSTER_ROUTING_ALLOCATION_DISK_FLOOD_STAGE_WATERMARK_SETTING;

        ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, Set.of(low, high, flood));
        Settings.Builder target = Settings.builder();
        clusterSettings.updateDynamicSettings(
            Settings.builder().put(high.getKey(), "95%").build(),
            target,
            Settings.builder(),
            "update high to 95%"
        );
        clusterSettings.applySettings(target.build());
        clusterSettings.updateDynamicSettings(
            Settings.builder().put(low.getKey(), "91%").build(),
            Settings.builder(),
            Settings.builder(),
            "update low to 91%"
        );
    }
}


The following is a transcription taken from an interview with Sally Fallon and Maximus Mark Ottobre on Weston Price, the wonders of raw milk and the benefits of butter.
This podcast is proudly brought to you by maximusmark.com and Enterprise Fitness. Search www.maximusmark.com/radio for more great podcasts just like this one or search iTunes, Maximus Mark.
Mark: Hey folks, it's Maximus Mark and welcome to the show that punches you in the face with information but in a good way, it's Maximus Mark Radio.
Today's guest is what we would call nutrition royalty. She is the co-founder and president of the Weston A. Price Organization. She is the author of "Nourishing Traditions", "Eat Fat, Lose Fat", and has tons of articles published at www.westonaprice.org. You can find articles on anything from raw milk, raw honey, cheese, Vitamin A, what to eat when you're pregnant, plus a whole bunch of other topics. The website is a gift and I know I spend many hours researching on the Weston A. Price website when I need to look something up. So, it is an absolute pleasure to welcome to the show, Sally Fallon.
Welcome to the show, Sally.
Sally: Thank you. Thanks for having me.
Mark: Absolute pleasure. We all have been following Weston A. Price for such a long time since I got into nutrition, so, love to get the listeners and catch them up in a speed, if this is kind of the first time hearing about Weston A. Price. But before we get into that, how did you become one of the world's shining lights in health and nutrition today?
Sally: I sort of almost feel like I've got dragged into it. It was just a result of my own personal journey where two things came together, first of all, is my love of cooking and my devotion to really delicious high fat, high cholesterol foods which I love and love to cook and then reading Dr. Price's book "Nutrition and Physical Degeneration", that happened in the early 1970's. It's a life changing book and showed that these are the various foods that kept people healthy for generations. So, I raised my family this way and I raised my kids with these types of foods, they were superbly healthy. When my youngest was in school full time, I turned my attention to writing the book "Nourishing Traditions", and when that was through, we felt there was a need for an organization to keep looking at sciences that came through to educate the people on the principles of healthy diet. That's when we set up Weston A. Price Foundation.
Mark: Who was Weston A. Price?
Sally: He was actually a dentist in the 1920's and 1930's. He travelled throughout the world looking in healthy populations in order to answer the question what is the healthy diet. He mainly looked at people's teeth and for him the sign of good health was the complete absence of cavities and absence of dental deformity that means no crown or crooked teeth, and that told him that the population on the whole was a healthy population. He took photographs and wrote up his findings in this book "Nutrition and Physical Degeneration" which has been a very influential book for many people.
Mark: Mainstream nutrition don't really like the work of Weston A. Price in a lot of ways because it kind of really disproves a lot of main-stream non-sense…eg. Have 11 servings of grains a day. Can you speak on that a little bit?
Sally: Yes, absolutely. What Dr. Price found was very different from what we've been told of the healthy diet today. Our healthy diet today is supposed to be based on all of these carbohydrates, mostly grains, like white flower. There were cultures that Dr. Price studied, looked at, that had grains in their diet but these were whole grains and in addition to that, these were grains that were prepared very carefully by soaking or souring process, or in the case of people who eat bread, the bread was sourdough bread which is a kind of fermentation. Because grains have a lot of anti-nutrients and even irritants in them and with as we're finding out today with all the celiac disease. Proper preparation takes care of these components.
Mark: Could you also argue that grains back in then, I guess, 1930's and 40's was a very different organism to what it is today?
Sally: Yes, that's another point. I also make that with the celiac disease. Is it the gluten that's causing the problem or is it all hormones and pesticides and fumigants and all these other components that they put on grains. The typical grain gets 10 chemicals applied to it from seed to final product.
The book Nutrition and Physical Degeneration is filled with photos just like this comparing dental health of cultures that ate a healthy diet and those that didn't.
Mark: Is that worldwide or is that just in the US mainly?
Sally: That I don't know. It's certainly in the US.
Mark: A lot of people, I guess again, must be hearing of Weston A. price Organization for the first time, what does it stand for? What is Weston A. Price Organization all about?
Sally: We are a non-profit, nutrition education foundation, dedicated to providing accurate information about diet and health. We have no ties with the industry or with government. We focus in particular on educating people about eating healthy fats and those are fats are like butter, lard, tallow, coconut oils and the traditional fats that people use.
One of the statements in our mission statement is the scientific validation of traditional food ways. There's so much pro and con in the scientific literature you can support almost any position drawing on scientific studies. But we feel that if we can show that the study validates the food ways then we ought to take that study pretty seriously.
The man, the myth, the legend… Weston Price!
Sally: The children did the junk food man song. Yes, we have a 4-day conference once a year and we just finished our conference. I consider it the premier nutrition conference of really international in the world and we have a children's program, we feature really delicious meals, and a varied agenda people can hear highly detailed scientific talks or go to cooking classes or anything in between.
Mark: That's fantastic. I heard you on another radio station a couple of days ago campaigning about raw milk and debating someone on raw milk. That's something I guess you are heavily involved in right now. Before getting to the raw milk issue, what do you think are the major problems with the world's food supply and why is something like raw milk is illegal?
Sally: Food supply has been industrialized and processed, overly processed. By industrializing, let's start with the animals. The animals have been put inside, no green grass and no sunlight so the three most important vitamins according to Dr. Price had disappeared in the food supply, that's Vitamin A, D and K. These vitamins are necessary for utilizing the minerals and the other vitamins in foods, so without them, the minerals and the other vitamins pretty much go to waste. So that's one thing that's happened. It's just horrendous what we do to the food after that, the oil processing, the flour processing, sweetener processing and food flavorings and all of these are put together to make junk food.
Mark: So I really want to reinforce the significance of what you've just said. The vitamins, make sure we get this right, Vitamins, A, K, D and E is that correct? And they are synergistic vitamins for the absorption of all the other vitamins, is that right?
Sally: That's A, D and K. Vitamin E is important too but that's a fat soluble vitamin. But the three that Dr. Price looked at and found wherein such high levels in traditional diets were A, D and K and where do we get these vitamins? Well, we get them from certain seafood's, not with skins and fillets, we get them from shellfish, fish eggs, fish liver, fish liver oils. In the land animals, we get it from butter, cream, egg yolks, organ meats and meat fats of animals raised outside on pasture and sunlight. These are the very foods that we're told we shouldn't eat. They've been demonized.
Mark: Why is selling like raw milk, which is a super food, so to speak, why selling something like that illegal?
Sally: Well, first of all I need to stress, at least in the United States, it's not illegal to purchase, possess or consume raw milk. It's only illegal in some states to sell it and that tells you right there that laws against raw milk are for economic reasons. They use health and safety as an excuse but really these laws are there to protect the dairy industry and to prevent the dairy industry from having to compete with farmers selling directly and getting much higher prices for their milk.
Mark: Right. Okay. So it's another case of food industry becoming government and making its own rules.
Sally: Yes, exactly. They're very tight, the FDA and Agriculture Department and the dairy industry. You know, fewer and fewer people can actually consume pasteurized and ultra pasteurized milk in the market, for this milk it's going down 1% per year… it has for 30 years. Eventually, there isn't going to be anyone consuming commercial/fluid milk, they just won't be able to. A lot of people have found that they can't consume pasteurized milk but they do fine on raw milk.
Mark: You probably get this question a lot, and probably debated this question a lot, but shouldn't we fear raw milk? Isn't that dangerous… How do you answer that question?
Sally: It depends on where it comes from. Raw milk from a confinement dairy would be dangerous, it would be quite risky. Raw milk from a small farm or the cows are on pasture, producing clean conditions, this is an inherently safe food because there are components in the raw milk that kill pathogens and that also supports the immune system.
Mark: What about the E. coli? That's another concern that's always been raised.
Sally: Well, yes. When animals are pasture fed, the E. coli goes way down or even disappears.
Mark: So when we drink it, it's not even in the milk?
Sally: Right, and the milk kills the pathogens. Milk that's cleanly made you can test it for pathogens and they're not there.
Mark: Right. So let's shift into training questions on nutrition. First question is, what's your thought on things like protein powders?
Sally: We are very much opposed to protein powders. They can be quite dangerous. The problem with too much protein is it rapidly depletes Vitamin A and when you deplete Vitamin A, you are prone to everything from immune disorders to cancer, to chronic fatigue, and all sorts of horrendous health problems that doctors don't know what to do about. Eating lean meats, egg whites without the yolk, skimmed milk or protein powders, all of these practices have the danger of depleting your Vitamin A, and probably protein powder's the most. If you're taking a protein powder, you can get up to 30 to 40% of your diet as protein and you don't find that in any traditional diet. You find 20% that's the maximum.
Mark: And how much would fat be?
Sally: The fat? The fat vary from region to region, in the Arctic it's up to 80% of calories… 80% fat, 20% protein. In some parts of Africa, the fat is about 30% of calories and the remainder is carbohydrates. Don't forget the body can take carbohydrates and turn them into fats, that's what it does with carbohydrates, but the key thing is to get the fat soluble vitamins one way or the other.
Mark: So, another thing that I guess always gets raised is I guess ketosis and diabetic-ketogenic-acidosis when you start promoting high fat diet. Are you able to touch on ketosis and just explain to the listeners why perhaps it's not such a terrible thing?
Sally: Ketosis is not the same as ketogenic acidosis which is a very severe condition that happens with diabetics, they're two different things. All I can say is that Price found no problems with the Eskimo population that was eating this way. One way or another, the body adjusts to it. And some believe that the ketones are better fuel for our brain than glucose.
Mark: I guess the insulin and glucagon response, it stops ketone accumulating in the liver as well. So it doesn't become a problem.
Sally: I think it would make an excellent post-workout drink and I would add some extra cream to it. That's what the athletes did in Switzerland and I would not be afraid at all of the high fat to the diet for the athletes. That's what Dr. Price found with the athletes in Switzerland. They drink bowls of pure cream during their athletic contest. There have been studies showing that you have a lot more stamina and strength with the high fat diet compared to a high carbohydrate diet.
Mark: Do they have the bowls of cream with anything?
Sally: This is what Dr. Price described; during the athletic event they drank bowls of pure cream. So it wasn't the carbohydrate loading going on in here.
Is there any link with information or autoimmune issues even with raw milk?
Sally: Raw milk, because of it built the immune system would help with immune issues. By the way, saturated fat is very supportive of the immune system so you want the cream or the butterfat in the milk.
Mark: Right. Of all the cultures that Weston A. Price studied, which one do you… or top 2… which one are you most taken by? Is there a particular culture that I guess you model more from than others?
Sally: Well, I'm very interested in the Swiss culture, that was the first one that he visited because their chief foods were raw milk and sourdough rye bread and they did have some meat and soups, but most calories were raw milk and the bread. This is very interesting because you have the Paleo dieters out there saying that the reason we have so many health problems today is we're eating these two foods that are new to the human species, dairy foods and grains, and yet here's a superbly healthy population that lived mainly on dairy foods and grains.
So our message is you don't have to get these foods out of the diet, you don't have to eliminate them, you just need to make sure that they're the right kind of dairy foods and the right kind of grains. I think that's good news to people. We really don't want to be telling people they can't have these or they can't have that. Our philosophy is here's how, here's how to eat fat, here's how to eat salt, here's how to eat sweet things, here's how to eat grains. So you can be inclusive rather than exclusive.
Sally: And prepare them properly.
Mark: So you prepare them yourself and make sure they're not genetically modified or any of that type of thing.
Sally: Well they need to be soaked or fermented or made into sourdough.
Sally: That's quite not right, its a half a stick. That's four tablespoons.
Mark: Yes, I actually make a shake after training that's consist of raw eggs, raw milk, unheated honey and raw butter. People think I'm absolutely crazy for putting butter in my post-workout shakes and I used to explain that the high butter and high fat is mostly medium and short-chained triglycerides plus Vitamin A, D and K that's in butter. I guess in your own words, I love to hear, why is butter such a super food?
Sally: Well, butter is just the perfect fat as you say if it's from grass-fed cow that has A, D, E and K. It's a terrific source of trace minerals. It has CLA which helps you build muscle. It has a great balance of fatty acids, actually only about 11% are the short and medium-chained fatty acid but it's got arachidonic acid which is critical for neurological function. It has a little Omega-3. It just has a plethora of fatty acids and it has lecithin which helps you use cholesterol properly. It has single lipids which help digestion. You couldn't design a better fat. It is just crazy that we have demonized this healthy fat.
Butter is a superfood… Move over Goji berries!!
Mark: I guess one of the misconceptions is that if I eat butter I'm going to get fat. What's wrong with that statement?
Sally: Butter supports thyroid function big time, the combination of Vitamin A and iodine so a lot of times when people switch to butter they lose weight. I often say, you know its what you put that butter on makes you gain weight. So if you adopt this diet, or eating a lot of butter, you probably going to have to cut back on the carbohydrates.
Mark: I think I remember reading Weston A. Price correlated the health of different cultures to the actual nutritious value of the butter. Is that right?
Sally: Yes, he was always testing butter from different parts of the world because he found a huge variation in the Vitamin A and Vitamin D content depending on how much sunlight there was and how much green grass there was. This was a terrible thing that's happened with industrial agriculture culture. Unless you buy directly from a grass-based farmer, you got to be getting butter from confinement cows, which is not a good source of A and D.
Mark: Yeah, it changes the structure of the butter. Is butter one thing that you pretty much tell everyone to start to include in their diet?
Sally: Oh yes, absolutely. If you're very intolerant of dairy, you can use ghee.
Mark: And most of the time, people use if they have intolerance to dairy butter's still okay because there are no protein strands in butter. Is that right?
Sally: Well, there's a little bit of protein in butter, little bit of milk solids in butter, but most people tolerate butter very well.
Mark: Yes, fantastic. Just want to switch now to I guess raw food. I had both Aajonus Vonderplanitz and Randy Roach on the show a while back. They're both raw food and I guess raw meat eaters. From previous podcast, I heard you say you're a little concerned about the raw meat phase or the raw meat diet?
Sally: Well, all traditional cultures have some raw animal foods in the diet. So I do think we need some raw animal foods included in the diet. This can just be raw milk, raw cheese, raw oysters or raw meat.
I tell you that raw chicken or raw pork make me a little queasy, I wouldn't recommend that. I think you eat that at your own risk. Raw beef and lamb are great but what I'm concerned about is the all-raw philosophy because all traditional cultures cooked. Usually what they cooked was the plant foods; and most plant foods contain toxins that are neutralized by cooking. The grains definitely need to be cooked. It's fine to have cooked meat and make soups and things like that. Potatoes definitely should be cooked; they contain a toxin when raw. Once again, people put themselves on these weird extreme diets that kind of separate them from the rest of mankind and don't necessarily do them any good.
Mark: Yeah right. That's a really good way to put it.
If someone wants to get as strong as humanly possible, what would you advise them to eat?
Sally: Gosh… I'm not into bodybuilding… However I would definitely have foods rich in Vitamin D, because Vitamin D is necessary for muscle firmness and integrity. So, lots of shellfish, lots of butter and cream, lard… I would cook in lard which is a rich source of Vitamin D.
Mark: What's the difference between lard and butter?
Sally: Lard is the fat of pigs and it's a very rich source of Vitamin D. I would definitely include organ meats. Things like liver at least a couple times a week. A number of studies on animals have shown that animals that ate liver had lot more stamina.
Mark: Yeah, right. That's good.
What's your thought on food intolerance testing with things like broccoli and beef are coming up as intolerant foods?
Sally: I'm a little skeptical of food intolerance testing because you get so many false positives. There's a "Pulse Test" that's described in my book "Nourishing Traditions" where if you're suspicious of a food that's causing you problem, you go off that food for 4 to 5 days and then you just eat a serving of that food by itself, testing your pulse before and after. If pulse shoots up, that's a sign that you do have a problem with that food. I think that's a much better way of doing it.
Mark: Well, that's a really easy way to do it. How did you discover that one?
Sally: There was a book written about it. I think it's called the "Pulse Test", way back in the 70's or 80's.
Sally: Right, your pulse goes up.
Mark: That's a really, really good tip.
How does one get involved and become a member of the Weston A. Price Organization?
Sally: Just go to www.westonaprice.org and there's a button there, "Join Now", and you can join online. Members receive our quarterly journal and all of our informational alerts. We have a lot of members in Australia and quite a few local chapters in Australia.
Mark: Excellent. Is there a cost or fee to join or is it free?
Sally: Yeah, for overseas it's $50 and that just pays for the extra postage, in US it's $40, and for students and seniors $25 and we'll honor that student and senior rate for overseas people.
Mark: Excellent. So the best place I guess to learn more about you is www.westonaprice.org?
Mark: And your books ""Nourishing Traditions" and "Eat Fat, Lose Fat can be purchased on Amazon?
Sally: "Eat Fat, Lose Fat" you can get from Amazon, "Nourishing Traditions" you can as well, but I would also invite you to visit my website www.newtrendspublishing.com which has not only "Nourishing Traditions" but the other books that I published and my two DVDs. I have a DVD of my five and a half hour seminar on traditional diet and the DVD called "The Oiling of America" which is about cholesterol and saturated fats and the cholesterol theory of heart disease.
Mark: Excellent. That sounds really interesting.
What's on the cards for the future?
Mark: At this point of the game, do you think raw milk will become a commercially available food?
Sally: Yes I do. I think eventually this movement to get raw milk will be irresistible.
Mark: Did you form a consumer demand point of view or you just think?
Sally: A consumer demand's point of view and the children getting raw milk a day will grow up to be healthy and in charge, it's what we call the aristocracy of the healthy and if the changes aren't made now they'll be made in the next generation.
Mark: Excellent. Any final thoughts or things to sum up?
Sally: If you're new to all these ideas go to our website and click on "Beginner's Tour". The website is just enormous there's so much information, the Beginner's Tour will take you through some important articles.
Mark: Fantastic. Well, really want to thank you for taking your time out today, coming on and answering these questions. Thank you very much and we wish you all the best with your campaign for raw milk. You're doing the world a great deal of good, much appreciated.
Sally: Thank you so much. It's a pleasure to be in your show.
Mark: Thank you Sally. Bye, have a good day.
Hey folk it's Maximus Mark. Hope you guys enjoyed that interview just a reminder, you guys can find more great podcasts just like this one by going to www.maximusmark.com/radio or searching Maximus Mark on iTunes.
Remember we got podcasts on Jonny Bowden, Randy Roach, Mark Schauss talking about toxins. I did an interview talking about a lot of hot topics, Aajonus Vonderplantiz on raw food, Lierre Keith about The Vegetarian Myth, Dr. Art De Vany talking about the caveman's diet as well as many, many more fantastic guests. Their all at maximusmark.com/radio and again they're on iTunes as well.
Do feel free to share this with your friends on Facebook and remember to Tweet them as well. I'll speak to you guys next time. Train hard, supplement smart and eat well.


This is Emma's story...what's yours? What's the story for your children? What's the story for the children in your school?
Once upon a time there was Thumbelina, there was a bird who couldn't fly and there were 3 stories AND a diary of Scotland all to be written, read and enjoyed....and here they are at the beginnings. Ooh plus a rather gory story, in picture form, about a man eating shark with a kinder looking jelly fish on the page you're looking at. But what brilliant ideas and how heartening to see children do write, they write when they're enjoying the moment and can become absorbed in it. Don't we all?


text:
World Trade Center (2006)
Watch World Trade Center (2006) Online
After the terrorist attack on the World Trade Center on September 11, 2001, the building collapses over the rescue team from the Port Authority Police Department. Will Jimeno and his sergeant John McLoughlin are found alive trapped under the wreckage while the rescue teams fight to save them.
Director: Oliver Stone
Actors: Danny Nucci, Jay Hernandez, Maggie Gyllenhaal, Maria Bello, Michael Peña, Michael Shannon, Nicolas Cage
Spirit: Stallion of the Cimarron (2002)
As a wild stallion travels across the frontiers of the Old West, he befriends a young human and finds true love with a mare.
Genre: Adventure, Animation, Drama, Family, Western
The Transfiguration (2016)
When troubled teen Milo, who has a fascination with vampire lore, meets the equally alienated Sophie, the two form a bond that begins to blur Milo's fantasy into reality.
The Beaver (2011)
Suffering from a severe case of depression, toy company CEO Walter Black (Mel Gibson) begins using a beaver hand puppet to help him open up to his family. With his…
Pearl (2020)
After her mother is murdered by her stepfather, gifted 15 year old student Pearl goes to live with an ex-lover of her mother, a grumpy unemployed film director who, pending…
The Last Thing He Wanted (2020)
Tells the story of Nobel Prize winner Marie Curie and her extraordinary scientific discoveries — through the prism of her marriage to husband Pierre — and the seismic and transformative…
Genre: Biography, Drama, Romance
Rent (2005)
This rock opera tells the story of one year in the life of a group of bohemians struggling in modern day East Village, New York, USA. The story centers around…
Genre: Drama, Musical, Romance
Genre: Adventure, Crime, Drama, Mystery
The Standoff at Sparrow Creek (2018)
After a mass shooting at a police funeral, reclusive ex-cop Gannon finds himself unwittingly forced out of retirement when he realizes that the killer belongs to the same militia he…
The Astronaut's Wife (1999)
When astronaut Spencer Armacost returns to Earth after a mission that nearly cost him his life, he decides to take a desk job in order to see his beautiful wife,…
A computer specialist is sued for sexual harassment by a former lover turned boss who initiated the act forcefully, which threatens both his career and his personal life.
The life of George Falconer, a British college professor, is reeling with the recent and sudden loss of his longtime partner. This traumatic event makes George challenge his own will…
Trailer: World Trade Center (2006)

redpajama_set_name: RedPajamaCommonCrawl


Our Little Miss Heart Breaker Raglan T-Shirt is the cutest top for this season! It is a jersey style top with stripes sleeves for that girly touch. Made from a super soft stretch cotton blend that is comfy enough for all day wear. Machine wash cold. Lay flat to dry.


text:
Scared teen pilot makes emergency landing after plane loses wheel
Teen pilot makes successful landing after losing wheel
BEVERLY, Massachusetts -- A 17-year-old student pilot from Massachusetts who successfully made an emergency landing after losing a wheel during her first solo flight plans to return to the cockpit soon.
Maggie Taraska, a high school senior from Gloucester, said Monday she was "scared" and "stressed" when she learned she had lost a wheel after takeoff from Beverly Regional Airport on Sunday.
She pulled herself together, and with help from instructor John Singleton on the ground, landed without a scratch although the single-engine Piper PA28 suffered significant damage.
After the plane came to a bumpy halt on the grass, she got out into the waiting arms of her father, Walt.
Singleton said some pilots with more experience than Maggie would have panicked, but she remained calm and "did it by the book."
massachusettsflight emergencyteenu.s. & worldemergency landing


I'm in Santa Fe, New Mexico for the long Labor Day weekend, spending time with my mom, brother, and sister-in-law. Jeff and Paco are holding down the fort at home - I'm sure Paco is not missing me at all (sarcasm - he's living in my closet, even with Jeff in the house).
I can't believe he didn't buy this.
Oh, Santa Fe! Have fun!
Have fun! Baylee hides under the kitchen table when I'm not home. I hope Paco is coping well!
Have a good time! That shouldn't be hard in Santa Fe!
Enjoy. Can't wait for pics.
OMG Jeff! Ha ha! Have a great trip!
Hope you had a wonderful weekend. Look forward to your pics.
I hope you guys had a great time! Can't wait to hear about it! That picture is hysterical!


text:
Pattern: Missing use of `save_changes`

Issue: -

## Description

Promotes the use of `save_changes`.

## Further Reading

* [RuboCop - Sequel/SaveChanges](https://github.com/rubocop/rubocop-sequel/blob/master/lib/rubocop/cop/sequel/save_changes.rb)

redpajama_set_name: RedPajamaGithub


text:
The Infrastructure Act and Forestry
Skip to The Infrastructure Act and Forestry
President Biden recently signed the historic $1.2 trillion Infrastructure Investment and Jobs Act (IIJA) into law as a part of the Build Back Better (BBB) framework. The IIJA will be the nation's largest investment in infrastructure constructions, renovations, and innovations. As such, the IIJA includes several provisions that have major implications for the forestry agencies and communities including the forest product industry and landowners. In this note, we explored the key provisions and funding allocations affecting forestry, wildfire management, and workforce development.
The legislation is scheduled to be primarily funded utilizing unused appropriations from COVID-19 relief measures. The IIJA is set to provide over $550 billion from FY 2022 through FY 2026 in new investments to the following sectors:
Infrastructure bill funding by sector.
Source: naco.org
Key Provisions Related to Forestry
Skip to Key Provisions Related to Forestry
Table 1 below summarizes some of the key provisions related to forestry.
Provisions Affecting Forestry
Weight limits of state roads that are set to become interstate highways remain at 90,000 pounds as opposed to decreasing to 80,000 pounds.
Enhancements to workforce development to encourage creation of new educational programs for workers in the transportation sector. Similarly, a pilot program to allow drivers of 21 years of age or less to operate trucks across states following training. This could be beneficial for loggers and timber haulers.
Forestry and forest product industry
Federal subsidy system for sawmills and wood processing facilities, including $400 million in financial assistance, that would consider proximity to sawmills when funding federal land restoration projects.
The Repairing Existing Public Land by Adding Necessary Trees (REPLANT) Act will increase reforestation investment four-fold on national forestlands to support the USDA Forest Service in planting 1.2 billion trees, creating almost 49,000 jobs over the next 10 years.
$200 million appropriated to reforest abandoned mine land and additional $200 million aligned for funding the country's national seed/seedling strategy.
$490 million to fund natural infrastructure resilience through urban forest management and tree planting.
Creation of the Healthy Streets program to provide grants to governments to expand tree cover and deploy cool, porous pavements ($100 million each fiscal year from 2022 to 2026).
$1.5 billion for state and private forestry (wildfire risk reduction and ecosystem restoration)
Wildland Fire
$3.3 billion designated for wildland fire issues including the creation of the federal Wildland Firefighter occupational series, which also increases the salary of wildland firefighters employed by federal agencies, and management of personnel to increase the number of full-time wildland firefighters and improve the health and safety of members of the workforce. Funding has also been designated for fire science research and communication, as well as land management practices such as prescribed fires, construction of fuel breaks, and thinning/removal operations and programs to aid communities and tribal nations with forest restoration. For instance, $20 million is specifically allocated for the Joint Fire Science Program to fund fire science research.
$2.1 billion for improvements, with specific provisions for small- and medium-scale operations, in energy, water, and material efficiency, waste reduction, pollution control, and load management without decreasing net returns. More specifically, the Office of Energy Efficiency and Renewable Energy will perform onsite technical assessments to identify opportunities for manufacturers to conserve natural resources and expand their usage of sustainable materials, potentially reducing pressure on the Nation's forests and creating new markets for sustainable products.
For more information on the IIJA, please visit the official bill.
Daley J. 2021, November 5. Celebrating the infrastructure bill – A win for America's forests. American Forests.
Forest2Market. 2021, November 9. House Passes $1.2 Trillion Infrastructure Bill; What's in it for Forestry? Forest2Market.
Gabbert B. 2021, November 6. Congress appropriates $3.3 billion for wildland fire. Wildfire Today.
National Association of Counties [NACo]. 2021, November 7. Legislative Analysis for Counties: The Infrastructure Investment and Jobs Act. NACo.
Stephanie Chizmar
Rajan Parajuli
Assistant Professor and Extension Specialist, Forest Economics
Laurel Kays
Extension Assistant
Extension Forestry
Publication date: Nov. 22, 2021


What a nice wife I have. A Yashica MF-2 Super is on it's way home to me via GoodWill.
Take that 'Merica! I lost a pound yesterday.
@danielpunkass immediately on the heals of the day we give thanks. It's an abomination.
Epic morning so far. Greatful to still have power.
@toddfilm @DrShitlord rain here ended around noon. We're looking at at least 8? of quite heavy snow.
Cooking my dinner with the electrics… I expect to lose power any moment now.
@sidceaser We've been getting a lot of flickers up here too.. losing power would be less than ideal. Though, worse for the line workers!


What we love about these earrings: BOLD look with lightweight feel (and price). Everything comes full circle, yes? We dig the radial style of these wood earrings. Add a longer length silver ear wire and you've got a standout style. Handmade with salvaged wood and sterling silver ear wires, these mesmerizing earrings measure 3.5" long including wire. These are the blonde wood color. Check out the Medium and dark wood versions as well! All of our jewelry comes boxed and ribboned, ready for giving (or keeping)!


How Much Does It Cost To Resurface A Bathtub is clear HD wallpaper. This wallpaper was upload by Aura in Bathtubs .
Starting around $300 to $400 for a standard-sized tub, a bathtub refinishing company can add a brand-new coating to the bathtub in a day, allowing it to be used again in two to four days without the additional delays and mess caused by replacement.
Learn all about bathroom resurfacing costs. Read general bathroom resurfacing prices, tips and get free bathroom resurface estimates. CostOwl.com.
See typical tasks and time to reglaze a bathtub, along with per unit costs and material requirements.. The Homewyse bathtub reglazing calculator uses industry-standard methods and. Average Cost per Glazing, $438.02, $983.14 .
How Much Does It Cost To Resurface A Bathtub is tall definition wallpaper and size this wallpaper is 800x534. You can make How Much Does It Cost To Resurface A Bathtub For your Desktop Wallpaper, Tablet, Android or iPhone and another Smartphone device for free. To download and come by the How Much Does It Cost To Resurface A Bathtub pictures by click the download button below to acquire complex high-resversions.


text:
Danielson leads Volvo's manufacturing operations in China
Gothenburg, Sweden – Lars Danielson has been appointed manager of Volvo's manufacturing operations in China. Danielson was previously manager at Volvo Cars Torslanda.
He will report to Freeman Shen, recently appointed as Senior Vice President, China Operations, and Magnus Hellsten, Volvo Cars's Senior Vice President, Manufacturing.
Danielson, 61, joined Volvo in June 2006 after having been with Saab and General Motors.
Electrifying Europe: new EU 'Fit for 55' legislation effectively bans petrol and diesel engines by 2035
The EU's latest salvo against the automotive industry to mitigate against climate change will eliminate ICEs and transform automotive manufacturing
Volvo and Northvolt form JV for battery development and production
The joint venture will develop and produce sustainable batteries, tailored to pure electric Volvo and Polestar cars, and establish an R&D centre
VW to have 240 GWh of battery plants in Europe by 2030
Volkswagen Group plans to significantly increase battery cell production capacity and reshape the EV battery supply chain in Europe, with plans to have six 'gigafactories' by the end of the decade – including an expansion of its partnership with Sweden's Northvolt.


Harmony baby carriers are a step up from our Elementary range and feature the addition of a padded waist band with a buckle closure and a choice of pixie, flat or adjustable flat hood. Featuring our standard, 2.1m wrap straps, these carriers are a harmonic blend of convenience and the comfort our woven cloth has to offer.
Panel sizes are consistent with our standard sizes; baby, inbetween and toddler.


Acute kidney failure occurs when your kidneys become unable to filter waste products from your blood. When your kidneys lose their filtering ability, dangerous levels of wastes may accumulate and your blood's chemical makeup may get out of balance.
Acute kidney failure – also called acute renal failure or acute kidney injury – can develop rapidly over a few hours or a few days. Acute kidney failure can be fatal and requires intensive treatment. However, acute kidney failure may be reversible. If you're otherwise in good health, you may recover normal or nearly normal kidney function.
How common is acute renal failure?
Acute kidney failure is most common in people who are already hospitalized, particularly in critically ill people who need intensive care.
Acute renal failure can affect patients at any age. It can be managed by reducing your risk factors. Please discuss with your doctor for further information.
What increases my risk for acute renal failure?
How is acute renal failure diagnosed?
Blood tests. A sample of your blood may reveal rapidly rising levels of urea and creatinine – two substances used to measure kidney function.
Dialysis to remove toxins from your blood. If toxins build up in your blood, you may need temporary hemodialysis – often referred to simply as dialysis – to help remove toxins and excess fluids from your body while your kidneys heal. Dialysis may also help remove excess potassium from your body. During dialysis, a machine pumps blood out of your body through an artificial kidney (dialyzer) that filters out waste. The blood is then returned to your body.
What are some lifestyle changes or home remedies that can help me manage acute renal failure?
Acute Kidney Failure. http://www.mayoclinic.org/diseases-conditions/kidney-failure/basics/definition/con-20024029. Accessed 19 Mar 2017.
Acute Kidney Failure. http://www.healthline.com/health/acute-kidney-failure. Accessed 19 Mar 2017.


text:
Bobby Hebb, né Robert Von Hebb à Nashville (Tennessee, États-Unis), le  et mort le  dans la même ville, est un auteur et chanteur américain, célèbre pour son enregistrement de Sunny en 1966.

Le , le lendemain de l'assassinat de John F. Kennedy, le frère de Bobby Hebb est poignardé mortellement lors d'un combat à l'extérieur d'un night club de Nashville.  Hebb est anéanti par les deux évènements et cherche le réconfort dans l'écriture. La chanson qu'il écrit est l'optimiste Sunny.

Sunny a été enregistré par, entre autres, Marvin Gaye, Boney M, Cher, Georgie Fame, Johnny Rivers, Frank Sinatra avec Duke Ellington, Ella Fitzgerald (1970), the Electric Flag, James Brown avec Marva Whitney, The Four Seasons, Christophe Willem, the Four Tops, Richard Anthony, Wilson Pickett, Les McCann, Stanley Turrentine (1966), Johnny "Hammond" Smith (1966) Henry Cain (1967), The Young Holt Trio (1966), Jerome Richardson (1968), Jack McDuff avec David "Fathead" Newman (1968), Jose Feliciano (1968), Stevie Wonder (1968), Dusty Springfield, Harry Manx & Kevin Breit (2011).

Anecdotes
 Le couplet et refrain de Sunny se termine avec un motif de quatre notes tiré du thème de James Bond dans James Bond 007 contre  No.

Liens externes

Notes et références

Chanteur américain du XXe siècle
Naissance en juillet 1938
Naissance à Nashville
Décès en août 2010
Décès à Nashville
Décès à 72 ans
Artiste de Philips Records
Artiste de Smash Records

redpajama_set_name: RedPajamaWikipedia