text:
package com.thoughtworks.go.server.scheduling;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.thoughtworks.go.config.BasicCruiseConfig;
import com.thoughtworks.go.config.CaseInsensitiveString;
import com.thoughtworks.go.config.PipelineConfig;
import com.thoughtworks.go.config.materials.MaterialConfigs;
import com.thoughtworks.go.config.materials.Materials;
import com.thoughtworks.go.config.materials.dependency.DependencyMaterial;
import com.thoughtworks.go.config.materials.mercurial.HgMaterial;
import com.thoughtworks.go.config.materials.mercurial.HgMaterialConfig;
import com.thoughtworks.go.config.materials.svn.SvnMaterial;
import com.thoughtworks.go.config.materials.svn.SvnMaterialConfig;
import com.thoughtworks.go.config.remote.ConfigRepoConfig;
import com.thoughtworks.go.config.remote.RepoConfigOrigin;
import com.thoughtworks.go.domain.MaterialRevision;
import com.thoughtworks.go.domain.MaterialRevisions;
import com.thoughtworks.go.domain.buildcause.BuildCause;
import com.thoughtworks.go.domain.materials.Material;
import com.thoughtworks.go.domain.materials.Modification;
import com.thoughtworks.go.helper.MaterialsMother;
import com.thoughtworks.go.helper.ModificationsMother;
import com.thoughtworks.go.helper.PipelineConfigMother;
import com.thoughtworks.go.server.domain.PipelineConfigDependencyGraph;
import com.thoughtworks.go.server.domain.PipelineTimeline;
import com.thoughtworks.go.server.domain.Username;
import com.thoughtworks.go.server.materials.MaterialUpdateCompletedTopic;
import com.thoughtworks.go.server.materials.MaterialUpdateFailedMessage;
import com.thoughtworks.go.server.materials.MaterialUpdateService;
import com.thoughtworks.go.server.materials.MaterialUpdateStatusListener;
import com.thoughtworks.go.server.materials.MaterialUpdateStatusNotifier;
import com.thoughtworks.go.server.materials.MaterialUpdateSuccessfulMessage;
import com.thoughtworks.go.server.materials.SpecificMaterialRevisionFactory;
import com.thoughtworks.go.server.perf.SchedulingPerformanceLogger;
import com.thoughtworks.go.server.persistence.MaterialRepository;
import com.thoughtworks.go.server.service.AutoBuild;
import com.thoughtworks.go.server.service.GoConfigService;
import com.thoughtworks.go.server.service.ManualBuild;
import com.thoughtworks.go.server.service.MaterialConfigConverter;
import com.thoughtworks.go.server.service.MaterialExpansionService;
import com.thoughtworks.go.server.service.NoModificationsPresentForDependentMaterialException;
import com.thoughtworks.go.server.service.PipelineScheduleQueue;
import com.thoughtworks.go.server.service.PipelineService;
import com.thoughtworks.go.server.service.SchedulingCheckerService;
import com.thoughtworks.go.server.service.result.HttpOperationResult;
import com.thoughtworks.go.server.service.result.OperationResult;
import com.thoughtworks.go.server.service.result.ServerHealthStateOperationResult;
import com.thoughtworks.go.serverhealth.HealthStateScope;
import com.thoughtworks.go.serverhealth.HealthStateType;
import com.thoughtworks.go.serverhealth.ServerHealthService;
import com.thoughtworks.go.serverhealth.ServerHealthState;
import com.thoughtworks.go.util.SystemEnvironment;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import static com.thoughtworks.go.serverhealth.HealthStateScope.GLOBAL;
import static com.thoughtworks.go.serverhealth.ServerHealthState.error;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;

public class BuildCauseProducerServiceTest {
    private static final ServerHealthState SERVER_ERROR = error("something", "else", HealthStateType.general(GLOBAL));

    private PipelineConfig pipelineConfig = new PipelineConfig(new CaseInsensitiveString("pipeline"), new MaterialConfigs());
    @Mock private ServerHealthService mockServerHealthService;
    @Mock private SchedulingCheckerService mockSchedulingCheckerService;
    @Mock private MaterialUpdateStatusNotifier mockMaterialUpdateStatusNotifier;
    @Mock private MaterialUpdateService mockMaterialUpdateService;
    @Mock private OperationResult operationResult;
    @Mock private PipelineScheduleQueue pipelineScheduleQueue;
    @Mock private MaterialRepository materialRepository;
    @Mock private SpecificMaterialRevisionFactory specificMaterialRevisionFactory;
    @Mock private PipelineService pipelineService;
    @Mock private PipelineTimeline pipelineTimeline;
    @Mock private GoConfigService goConfigService;
    @Mock private MaterialConfigConverter materialConfigConverter;
    @Mock private MaterialExpansionService materialExpansionService;
    @Mock private SchedulingPerformanceLogger schedulingPerformanceLogger;

    private final Map<String, String> EMPTY_REVISIONS = new HashMap<>();
    private HealthStateType healthStateType;
    private TriggerMonitor triggerMonitor;
    private BuildCauseProducerService buildCauseProducerService;

    @Before
    public void setUp() throws Exception {
        initMocks(this);

        triggerMonitor = new TriggerMonitor();
        healthStateType = HealthStateType.general(HealthStateScope.forPipeline(CaseInsensitiveString.str(pipelineConfig.name())));
        when(goConfigService.pipelineConfigNamed(pipelineConfig.name())).thenReturn(pipelineConfig);

        buildCauseProducerService = createBuildCauseProducerService(mockMaterialUpdateStatusNotifier);
    }

    private BuildCauseProducerService createBuildCauseProducerService(MaterialUpdateStatusNotifier materialUpdateStatusNotifier) {
        return new BuildCauseProducerService(mockSchedulingCheckerService, mockServerHealthService,
                pipelineScheduleQueue, goConfigService, materialRepository, materialUpdateStatusNotifier,
                mockMaterialUpdateService, specificMaterialRevisionFactory, triggerMonitor, pipelineService, new SystemEnvironment(), materialConfigConverter,
                materialExpansionService, schedulingPerformanceLogger);
    }

    @Test
    public void onErrorShouldUpdateServerHealthWhenUpdateServerHealthStatusByDefault() throws Exception {
        buildCauseProducerService.manualSchedulePipeline(Username.CRUISE_TIMER, pipelineConfig.name(), new ScheduleOptions(), errorResult());
        verify(mockServerHealthService).update(SERVER_ERROR);
    }

    @Test
    public void shouldAllowRetriggeringIfThePreviousTriggerFailed() throws Exception {

        buildCauseProducerService.manualSchedulePipeline(Username.CRUISE_TIMER, pipelineConfig.name(), new ScheduleOptions(), errorResult());

        HttpOperationResult result = new HttpOperationResult();
        buildCauseProducerService.manualSchedulePipeline(Username.CRUISE_TIMER, pipelineConfig.name(), new ScheduleOptions(), result);
        assertThat(result.httpCode(), is(202));

    }

    @Test
    public void shouldCheckForModificationsWhenManuallyScheduling() throws Exception {
        HgMaterialConfig hgMaterialConfig = new HgMaterialConfig("url", null);
        HgMaterial hgMaterial = new HgMaterial("url", null);
        SvnMaterial svnMaterial = new SvnMaterial("url", null, null, false);
        SvnMaterialConfig svnMaterialConfig = new SvnMaterialConfig("url", null, null, false);
        pipelineConfig.addMaterialConfig(hgMaterialConfig);
        pipelineConfig.addMaterialConfig(svnMaterialConfig);

        when(materialConfigConverter.toMaterial(hgMaterialConfig)).thenReturn(hgMaterial);
        when(materialConfigConverter.toMaterial(svnMaterialConfig)).thenReturn(svnMaterial);

        ServerHealthStateOperationResult result = new ServerHealthStateOperationResult();
        buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(), new ScheduleOptions(), result);
        assertThat(result.getServerHealthState().isSuccess(), is(true));

        verify(mockMaterialUpdateService, times(2)).updateMaterial(any(Material.class));
        verify(mockMaterialUpdateStatusNotifier).registerListenerFor(eq(pipelineConfig),
                any(MaterialUpdateStatusListener.class));
    }

    @Test
    public void shouldNotCheckForModificationsIfAlreadyChecking() throws Exception {
        Username user = Username.ANONYMOUS;
        final HttpOperationResult result = new HttpOperationResult();

        when(mockSchedulingCheckerService.canTriggerManualPipeline(pipelineConfig, CaseInsensitiveString.str(user.getUsername()), operationResult)).thenAnswer(new Answer<Boolean>() {
            public Boolean answer(InvocationOnMock invocationOnMock) throws Throwable {
                result.accepted("junk", "junk", healthStateType);
                return true;
            }
        });

        buildCauseProducerService.markPipelineAsAlreadyTriggered(pipelineConfig);
        buildCauseProducerService.manualSchedulePipeline(user, pipelineConfig.name(), new ScheduleOptions(), result);

        assertThat(result.canContinue(), is(false));
        assertThat(result.message(), is("Failed to force pipeline: pipeline"));

        verify(mockMaterialUpdateService, never()).updateMaterial(any(Material.class));
        verify(mockMaterialUpdateStatusNotifier, never()).registerListenerFor(eq(pipelineConfig),
                any(MaterialUpdateStatusListener.class));
    }

    @Test
    public void shouldAllowTriggeringOfPipelineWhenThereIsAnErrorAfterPipelineIsMarkedAsTriggeredAndBeforeTheMaterialUpdateIsScheduled()
            throws Exception {
        try {
            when(operationResult.canContinue()).thenThrow(new RuntimeException("force a failure"));
            buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(), new ScheduleOptions(), operationResult);
            fail("expected exception, got none");
        } catch (Exception e) {
            assertThat(triggerMonitor.isAlreadyTriggered(CaseInsensitiveString.str(pipelineConfig.name())), is(false));
        }
    }

    @Test
    public void shouldAllowTriggeringOfPipelineAfterMaterialUpdate() throws Exception {
        HgMaterial hgMaterial = new HgMaterial("url", null);
        HgMaterialConfig hgMaterialConfig = new HgMaterialConfig("url", null);

        pipelineConfig.addMaterialConfig(hgMaterialConfig);

        when(materialConfigConverter.toMaterial(hgMaterialConfig)).thenReturn(hgMaterial);
        when(specificMaterialRevisionFactory.create("pipeline", new HashMap<>())).thenReturn(new MaterialRevisions());
        when(pipelineScheduleQueue.mostRecentScheduled(CaseInsensitiveString.str(pipelineConfig.name()))).thenReturn(BuildCause.createNeverRun());
        when(materialRepository.findLatestModification(hgMaterial)).thenReturn(new MaterialRevisions(new MaterialRevision(hgMaterial, new ArrayList<>())));

        buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(), new ScheduleOptions(), new ServerHealthStateOperationResult());
        assertThat(triggerMonitor.isAlreadyTriggered(CaseInsensitiveString.str(pipelineConfig.name())), is(true));
        sendMaterialUpdateCompleteMessage(extractMaterialListenerInstanceFromRegisterCall(), hgMaterial);
        assertThat(triggerMonitor.isAlreadyTriggered(CaseInsensitiveString.str(pipelineConfig.name())), is(false));
    }

    @Test
    public void manualTriggerShouldNotTriggerThePipelineIfMaterialUpdateFailed() throws Exception {
        HgMaterialConfig hgMaterialConfig = new HgMaterialConfig("url", null);
        HgMaterial hgMaterial = new HgMaterial("url", null);

        pipelineConfig.addMaterialConfig(hgMaterialConfig);
        when(materialConfigConverter.toMaterial(hgMaterialConfig)).thenReturn(hgMaterial);

        buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(), new ScheduleOptions(), new ServerHealthStateOperationResult());
        sendMaterialUpdateFailedMessage(extractMaterialListenerInstanceFromRegisterCall(), hgMaterial);
        assertThat(triggerMonitor.isAlreadyTriggered(CaseInsensitiveString.str(pipelineConfig.name())), is(false));
    }

    private void sendMaterialUpdateCompleteMessage(MaterialUpdateStatusListener materialUpdateStatusListener, HgMaterial material) {
        materialUpdateStatusListener.onMaterialUpdate(new MaterialUpdateSuccessfulMessage(material, 0));
    }

    private void sendMaterialUpdateFailedMessage(MaterialUpdateStatusListener materialUpdateStatusListener, HgMaterial material) {
        materialUpdateStatusListener.onMaterialUpdate(new MaterialUpdateFailedMessage(material, 0, new RuntimeException("Seven Nation Army")));
    }

    private MaterialUpdateStatusListener extractMaterialListenerInstanceFromRegisterCall() {
        final MaterialUpdateStatusListener[] listener = new MaterialUpdateStatusListener[1];
        verify(mockMaterialUpdateStatusNotifier).registerListenerFor(any(PipelineConfig.class),
                argThat(new BaseMatcher<MaterialUpdateStatusListener>() {
                    public boolean matches(Object o) {
                        listener[0] = (MaterialUpdateStatusListener) o;
                        return true;
                    }

                    public void describeTo(Description description) {
                    }
                }));
        return listener[0];
    }

    @Test
    public void shouldNotCheckForModificationsUnableToTriggerManualPipeline() throws Exception {
        buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(), new ScheduleOptions(), errorResult());
        verify(mockMaterialUpdateService, never()).updateMaterial(any(Material.class));
        verify(mockMaterialUpdateStatusNotifier, never()).registerListenerFor(eq(pipelineConfig),
                any(MaterialUpdateStatusListener.class));
    }

    @Test
    public void shouldScheduleAfterAllMaterialsAreUpdated() throws Exception {
        HgMaterial hgMaterial = new HgMaterial("url", null);
        HgMaterialConfig hgMaterialConfig = new HgMaterialConfig("url", null);
        SvnMaterial svnMaterial = new SvnMaterial("url", null, null, false);
        SvnMaterialConfig svnMaterialConfig = new SvnMaterialConfig("url", null, null, false);
        pipelineConfig.addMaterialConfig(hgMaterialConfig);
        pipelineConfig.addMaterialConfig(svnMaterialConfig);

        GoConfigService service = mock(GoConfigService.class);
        when(service.pipelineConfigNamed(pipelineConfig.name())).thenReturn(pipelineConfig);
        when(materialConfigConverter.toMaterial(hgMaterialConfig)).thenReturn(hgMaterial);
        when(materialConfigConverter.toMaterial(svnMaterialConfig)).thenReturn(svnMaterial);

        MaterialUpdateStatusNotifier notifier = new MaterialUpdateStatusNotifier(mock(MaterialUpdateCompletedTopic.class));
        buildCauseProducerService = spy(createBuildCauseProducerService(notifier));
        buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(), new ScheduleOptions(), new ServerHealthStateOperationResult());
        final HashMap<String, String> stringStringHashMap = new HashMap<>();
        doReturn(ServerHealthState.success(healthStateType)).when(buildCauseProducerService).newProduceBuildCause(
                eq(pipelineConfig), any(ManualBuild.class),
                new ScheduleOptions(eq(EMPTY_REVISIONS), stringStringHashMap, new HashMap<>()), any(ServerHealthStateOperationResult.class), eq(12345L));

        assertThat(notifier.hasListenerFor(pipelineConfig), is(true));
        notifier.onMessage(new MaterialUpdateSuccessfulMessage(hgMaterial, 1111L));

        assertThat(notifier.hasListenerFor(pipelineConfig), is(true));
        notifier.onMessage(new MaterialUpdateSuccessfulMessage(svnMaterial, 2222L));

        assertThat(notifier.hasListenerFor(pipelineConfig), is(false));
        verify(buildCauseProducerService).newProduceBuildCause(eq(pipelineConfig), any(ManualBuild.class), eq(new ScheduleOptions()), any(ServerHealthStateOperationResult.class), eq(2222L));
    }

    @Test
    public void shouldUpdateResultAsAcceptedOnSuccess() throws Exception {
        when(mockMaterialUpdateStatusNotifier.hasListenerFor(pipelineConfig)).thenReturn(false);
        when(operationResult.canContinue()).thenReturn(true);
        buildCauseProducerService.manualSchedulePipeline(Username.BLANK, pipelineConfig.name(), new ScheduleOptions(), operationResult);
        verify(operationResult).accepted(eq("Request to schedule pipeline pipeline accepted"), any(String.class),
                any(HealthStateType.class));
    }

    @Test
    public void shouldBeAbleToPassInSpecificRevisionForMaterialsAndScheduleABuild() throws Exception {
        DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("upstream-pipeline"), new CaseInsensitiveString("stage"));
        SvnMaterial svnMaterial = new SvnMaterial("url", null, null, false);
        pipelineConfig.addMaterialConfig(dependencyMaterial.config());
        pipelineConfig.addMaterialConfig(svnMaterial.config());

        List<Modification> svnModifications = ModificationsMother.multipleModificationList();
        MaterialConfigs knownMaterialConfigs = new MaterialConfigs(pipelineConfig.materialConfigs());

        MaterialRevision specificMaterialRevision = new MaterialRevision(dependencyMaterial, new Modification(new Date(), "upstream-pipeline/2/stage/1", "MOCK_LABEL-12", null));
        when(specificMaterialRevisionFactory.create(eq("pipeline"), eq(Collections.singletonMap(dependencyMaterial.getPipelineUniqueFingerprint(), "upstream-pipeline/2/stage/1"))))
                .thenReturn(new MaterialRevisions(specificMaterialRevision));
        when(pipelineScheduleQueue.mostRecentScheduled("pipeline")).thenReturn(BuildCause.createNeverRun());
        when(materialRepository.findLatestModification(svnMaterial)).thenReturn(new MaterialRevisions(new MaterialRevision(svnMaterial, svnModifications)));

        when(materialConfigConverter.toMaterials(pipelineConfig.materialConfigs())).thenReturn(new Materials(dependencyMaterial, svnMaterial));
        when(materialExpansionService.expandMaterialConfigsForScheduling(pipelineConfig.materialConfigs())).thenReturn(knownMaterialConfigs);
        when(materialConfigConverter.toMaterials(knownMaterialConfigs)).thenReturn(new Materials(dependencyMaterial, svnMaterial));

        ManualBuild buildType = new ManualBuild(Username.ANONYMOUS);
        final HashMap<String, String> stringStringHashMap = new HashMap<>();
        buildCauseProducerService.newProduceBuildCause(pipelineConfig, buildType,
                new ScheduleOptions(Collections.singletonMap(dependencyMaterial.getPipelineUniqueFingerprint(), "upstream-pipeline/2/stage/1"),
                        stringStringHashMap, new HashMap<>()), new ServerHealthStateOperationResult(), 12345);

        verify(pipelineScheduleQueue).schedule(eq("pipeline"), argThat(containsRevisions(new MaterialRevision(svnMaterial, svnModifications), specificMaterialRevision)));
    }

    @Test
    public void shouldHandleCaseWhereSpecifiedRevisionDoesNotExist() throws Exception {
        DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("upstream-pipeline"), new CaseInsensitiveString("stage"));
        when(specificMaterialRevisionFactory.create(eq("pipeline"), eq(Collections.singletonMap(dependencyMaterial.getPipelineUniqueFingerprint(), "upstream-pipeline/200/stage/1"))))
                .thenThrow(new RuntimeException("Invalid specified revision"));
        ManualBuild buildType = new ManualBuild(Username.ANONYMOUS);
        final HashMap<String, String> stringStringHashMap = new HashMap<>();
        buildCauseProducerService.newProduceBuildCause(pipelineConfig, buildType,
                new ScheduleOptions(Collections.singletonMap(dependencyMaterial.getPipelineUniqueFingerprint(), "upstream-pipeline/200/stage/1"),
                        stringStringHashMap, new HashMap<>()), new ServerHealthStateOperationResult(), 12345);
        verify(mockServerHealthService).update(argThat(hasErrorHealthState("Error while scheduling pipeline: pipeline", "Invalid specified revision")));
    }

    @Test
    public void shouldHandleCaseWhenExceptionWithoutMessageIsRaised() throws Exception {
        DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("upstream-pipeline"), new CaseInsensitiveString("stage"));
        when(specificMaterialRevisionFactory.create(eq("pipeline"), eq(Collections.singletonMap(dependencyMaterial.getPipelineUniqueFingerprint(), "upstream-pipeline/200/stage/1"))))
                .thenThrow(new NullPointerException());
        ManualBuild buildType = new ManualBuild(Username.ANONYMOUS);
        final HashMap<String, String> stringStringHashMap = new HashMap<>();
        buildCauseProducerService.newProduceBuildCause(pipelineConfig, buildType,
                new ScheduleOptions(Collections.singletonMap(dependencyMaterial.getPipelineUniqueFingerprint(), "upstream-pipeline/200/stage/1"), stringStringHashMap, new HashMap<>()),
                new ServerHealthStateOperationResult(), 12345);
        verify(mockServerHealthService).update(argThat(hasErrorHealthState("Error while scheduling pipeline: pipeline", "Details not available, please check server logs.")));
    }

    @Test
    public void shouldUpdateOnlyOnceIfThereAreTwoMaterialsWithSameFingerPrintButDifferentDest() {
        HgMaterial material1 = new HgMaterial("url", null);
        HgMaterial material2 = new HgMaterial("url", null);
        HgMaterialConfig materialConfig1 = new HgMaterialConfig("url", null);
        HgMaterialConfig materialConfig2 = new HgMaterialConfig("url", null);
        material1.setFolder("folder1");
        material2.setFolder("folder2");

        assertThat(material1.getFingerprint(), is(material2.getFingerprint()));

        pipelineConfig.addMaterialConfig(materialConfig1);
        pipelineConfig.addMaterialConfig(materialConfig2);
        Material[] materials = new Material[]{material1, material2};

        when(materialConfigConverter.toMaterial(materialConfig1)).thenReturn(material1);
        when(materialConfigConverter.toMaterial(materialConfig2)).thenReturn(material2);

        buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(),
                new ScheduleOptions(new HashMap<>(), new HashMap<>(), new HashMap<>()),
                new ServerHealthStateOperationResult());
        verify(mockMaterialUpdateService, times(1)).updateMaterial(any(Material.class));
        MaterialUpdateStatusListener statusListener = extractMaterialListenerInstanceFromRegisterCall();
        statusListener.onMaterialUpdate(new MaterialUpdateFailedMessage(materials[0], 0, new Exception("Cannot connect to repo")));
        verify(mockMaterialUpdateStatusNotifier).removeListenerFor(pipelineConfig);

    }

    @Test
    public void manualTrigger_shouldUpdatePipelineConfigWhenMaterialIsConfigRepo() {
        HgMaterial material1 = new HgMaterial("url", null);
        HgMaterialConfig materialConfig1 = new HgMaterialConfig("url", null);

        pipelineConfig.addMaterialConfig(materialConfig1);
        pipelineConfig.setOrigin(new RepoConfigOrigin(new ConfigRepoConfig(materialConfig1,"plug"),"revision1"));

        when(materialConfigConverter.toMaterial(materialConfig1)).thenReturn(material1);
        when(goConfigService.hasPipelineNamed(pipelineConfig.name())).thenReturn(true);

        buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(),
                new ScheduleOptions(new HashMap<>(), new HashMap<>(), new HashMap<>()),
                new ServerHealthStateOperationResult());
        verify(goConfigService, times(1)).pipelineConfigNamed(pipelineConfig.name());

        MaterialUpdateStatusListener statusListener = extractMaterialListenerInstanceFromRegisterCall();
        statusListener.onMaterialUpdate(new MaterialUpdateSuccessfulMessage(material1, 0));
        verify(mockMaterialUpdateStatusNotifier).removeListenerFor(pipelineConfig);

        verify(goConfigService, times(2)).pipelineConfigNamed(pipelineConfig.name());
    }

    @Test
    public void manualTrigger_shouldNotUpdatePipelineConfigWhenConfigRepoIsNotInMaterials() {
        HgMaterial material1 = new HgMaterial("url", null);
        HgMaterialConfig materialConfig1 = new HgMaterialConfig("url", null);
        HgMaterialConfig materialConfig2 = new HgMaterialConfig("url2", null);

        pipelineConfig.addMaterialConfig(materialConfig1);
        pipelineConfig.setOrigin(new RepoConfigOrigin(new ConfigRepoConfig(materialConfig2,"plug"),"revision1"));

        when(materialConfigConverter.toMaterial(materialConfig1)).thenReturn(material1);

        buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(),
                new ScheduleOptions(new HashMap<>(), new HashMap<>(), new HashMap<>()),
                new ServerHealthStateOperationResult());
        verify(goConfigService, times(1)).pipelineConfigNamed(pipelineConfig.name());

        MaterialUpdateStatusListener statusListener = extractMaterialListenerInstanceFromRegisterCall();
        statusListener.onMaterialUpdate(new MaterialUpdateSuccessfulMessage(material1, 0));
        verify(mockMaterialUpdateStatusNotifier).removeListenerFor(pipelineConfig);

        verify(goConfigService, times(1)).pipelineConfigNamed(pipelineConfig.name());
    }

    @Test
    public void manualTrigger_shouldRequestUpdateOfNewMaterials_WhenPipelineConfigInConfigRepo() {
        HgMaterial material1 = new HgMaterial("url", null);
        HgMaterial material2 = new HgMaterial("url2", null);
        HgMaterialConfig materialConfig1 = new HgMaterialConfig("url", null);
        HgMaterialConfig materialConfig2 = new HgMaterialConfig("url2", null);

        pipelineConfig.addMaterialConfig(materialConfig1);
        pipelineConfig.setOrigin(new RepoConfigOrigin(new ConfigRepoConfig(materialConfig1,"plug"),"revision1"));

        when(materialConfigConverter.toMaterial(materialConfig1)).thenReturn(material1);
        when(materialConfigConverter.toMaterial(materialConfig2)).thenReturn(material2);

        buildCauseProducerService.manualSchedulePipeline(Username.ANONYMOUS, pipelineConfig.name(),
                new ScheduleOptions(new HashMap<>(), new HashMap<>(), new HashMap<>()),
                new ServerHealthStateOperationResult());
        verify(goConfigService, times(1)).pipelineConfigNamed(pipelineConfig.name());

        // updated pipeline config
        PipelineConfig pipelineConfig1 = new PipelineConfig(new CaseInsensitiveString("pipeline"), new MaterialConfigs());
        pipelineConfig1.addMaterialConfig(materialConfig1);
        pipelineConfig1.addMaterialConfig(materialConfig2);
        when(goConfigService.pipelineConfigNamed(pipelineConfig.name())).thenReturn(pipelineConfig1);
        when(goConfigService.hasPipelineNamed(pipelineConfig.name())).thenReturn(true);

        MaterialUpdateStatusListener statusListener = extractMaterialListenerInstanceFromRegisterCall();
        statusListener.onMaterialUpdate(new MaterialUpdateSuccessfulMessage(material1, 0));

        verify(goConfigService, times(2)).pipelineConfigNamed(pipelineConfig.name());

        verify(mockMaterialUpdateService,times(1)).updateMaterial(material1);
        verify(mockMaterialUpdateService,times(1)).updateMaterial(material2);

        statusListener.onMaterialUpdate(new MaterialUpdateSuccessfulMessage(material2, 0));

        verify(mockMaterialUpdateStatusNotifier).removeListenerFor(pipelineConfig1);
    }

    @Test
    public void shouldHandleNoModificationExceptionThrownByAutoBuild() {
        String pipelineName = "pipeline";
        ServerHealthStateOperationResult result = new ServerHealthStateOperationResult();
        PipelineConfig config = PipelineConfigMother.pipelineConfig(pipelineName);

        Material svnMaterial = MaterialsMother.defaultMaterials().get(0);
        DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("up"), new CaseInsensitiveString("s1"));

        config.materialConfigs().clear();
        config.addMaterialConfig(svnMaterial.config());
        config.addMaterialConfig(dependencyMaterial.config());

        when(pipelineService.getRevisionsBasedOnDependencies(Matchers.<MaterialRevisions>any(), Matchers.<BasicCruiseConfig>any(), Matchers.<CaseInsensitiveString>any())).thenThrow(
                new NoModificationsPresentForDependentMaterialException("P/1/S/1"));
        when(pipelineScheduleQueue.mostRecentScheduled(pipelineName)).thenReturn(BuildCause.createNeverRun());
        Modification modification = ModificationsMother.checkinWithComment("r", "c", new Date(), "f1");
        when(materialRepository.findLatestModification(svnMaterial)).thenReturn(ModificationsMother.createSvnMaterialWithMultipleRevisions(1, modification));
        when(materialRepository.findLatestModification(dependencyMaterial)).thenReturn(new MaterialRevisions(ModificationsMother.changedDependencyMaterialRevision("up", 1, "1", "s", 1, new Date())));
        when(specificMaterialRevisionFactory.create(Matchers.<String>any(), Matchers.<Map<String, String>>any())).thenReturn(MaterialRevisions.EMPTY);
        when(goConfigService.upstreamDependencyGraphOf(Matchers.<String>any(), Matchers.<BasicCruiseConfig>any())).thenReturn(new PipelineConfigDependencyGraph(config));

        MaterialConfigs knownMaterialConfigs = new MaterialConfigs(svnMaterial.config(), dependencyMaterial.config());
        Materials materials = new Materials(svnMaterial, dependencyMaterial);
        when(materialConfigConverter.toMaterials(config.materialConfigs())).thenReturn(materials);
        when(materialExpansionService.expandMaterialConfigsForScheduling(config.materialConfigs())).thenReturn(knownMaterialConfigs);
        when(materialConfigConverter.toMaterials(knownMaterialConfigs)).thenReturn(materials);

        AutoBuild autoBuild = new AutoBuild(goConfigService, pipelineService, pipelineName, new SystemEnvironment(), null, mockServerHealthService);
        ServerHealthState serverHealthState = buildCauseProducerService.newProduceBuildCause(config, autoBuild, result, 12345);

        assertThat(serverHealthState.isSuccess(), is(true));
    }

    private TypeSafeMatcher<ServerHealthState> hasErrorHealthState(final String message, final String description) {
        return new TypeSafeMatcher<ServerHealthState>() {
            @Override
            public boolean matchesSafely(ServerHealthState item) {
                assertThat("isSuccess", item.isSuccess(), is(false));
                assertThat("message", item.getMessage(), is(message));
                assertThat("description", item.getDescription(), is(description));
                return true;
            }
            public void describeTo(Description description) {
                description.appendText("message = [" + message + "] and description = [" + description + "]");
            }
        };
    }

    private TypeSafeMatcher<BuildCause> containsRevisions(final MaterialRevision... revisions) {
        return new TypeSafeMatcher<BuildCause>() {
            @Override
            public boolean matchesSafely(BuildCause item) {
                for (MaterialRevision revision : revisions) {
                    if (!item.getMaterialRevisions().getRevisions().contains(revision)) {
                        return false;
                    }
                }
                return true;
            }

            public void describeTo(Description description) {
                description.appendText("should contain revisions " + Arrays.toString(revisions));
            }
        };
    }

    private OperationResult errorResult() {
        HttpOperationResult operationResult1 = new HttpOperationResult();
        operationResult1.error("something", "else", HealthStateType.general(GLOBAL));
        return operationResult1;
    }
}


text:
# RabbitMQ tutorial - Reliable Publishing with Publisher Confirms SUPPRESS-RHS

## Publisher Confirms

<xi:include href="site/tutorials/tutorials-help.xml.inc"/>

[Publisher confirms](../confirms.html#publisher-confirms)
are a RabbitMQ extension to implement reliable
publishing. When publisher confirms are enabled on a channel,
messages the client publishes are confirmed asynchronously
by the broker, meaning they have been taken care of on the server
side.

### (using the Java client)

### Overview

In this tutorial we're going to use publisher confirms to make
sure published messages have safely reached the broker. We will
cover several strategies to using publisher confirms and explain
their pros and cons.

### Enabling Publisher Confirms on a Channel

Publisher confirms are a RabbitMQ extension to the AMQP 0.9.1 protocol,
so they are not enabled by default. Publisher confirms are
enabled at the channel level with the `confirmSelect` method:

Channel channel = connection.createChannel();
channel.confirmSelect();

This method must be called on every channel that you expect to use publisher
confirms. Confirms should be enabled just once, not for every message published.

### Strategy #1: Publishing Messages Individually

Let's start with the simplest approach to publishing with confirms,
that is, publishing a message and waiting synchronously for its confirmation:

while (thereAreMessagesToPublish()) {
    byte[] body = ...;
    BasicProperties properties = ...;
    channel.basicPublish(exchange, queue, properties, body);
    // uses a 5 second timeout
    channel.waitForConfirmsOrDie(5_000);
}

In the previous example we publish a message as usual and wait for its
confirmation with the `Channel#waitForConfirmsOrDie(long)` method.
The method returns as soon as the message has been confirmed. If the
message is not confirmed within the timeout or if it is nack-ed (meaning
the broker could not take care of it for some reason), the method will
throw an exception. The handling of the exception usually consists
in logging an error message and/or retrying to send the message.

Different client libraries have different ways to synchronously deal with publisher confirms,
so make sure to read carefully the documentation of the client you are using.

This technique is very straightforward but also has a major drawback:
it **significantly slows down publishing**, as the confirmation of a message blocks the publishing
of all subsequent messages. This approach is not going to deliver throughput of
more than a few hundreds of published messages per second. Nevertheless, this can be
good enough for some applications.

> #### Are Publisher Confirms Asynchronous?
>
> We mentioned at the beginning that the broker confirms published
> messages asynchronously but in the first example the code waits
> synchronously until the message is confirmed. The client actually
> receives confirms asynchronously and unblocks the call to `waitForConfirmsOrDie`
> accordingly. Think of `waitForConfirmsOrDie` as a synchronous helper
> which relies on asynchronous notifications under the hood.

### Strategy #2: Publishing Messages in Batches

To improve upon our previous example, we can publish a batch
of messages and wait for this whole batch to be confirmed.
The following example uses a batch of 100:

int batchSize = 100;
int outstandingMessageCount = 0;
while (thereAreMessagesToPublish()) {
    byte[] body = ...;
    BasicProperties properties = ...;
    channel.basicPublish(exchange, queue, properties, body);
    outstandingMessageCount++;
    if (outstandingMessageCount == batchSize) {
        channel.waitForConfirmsOrDie(5_000);
        outstandingMessageCount = 0;
    }
}
if (outstandingMessageCount > 0) {
    channel.waitForConfirmsOrDie(5_000);
}

Waiting for a batch of messages to be confirmed improves throughput drastically over
waiting for a confirm for individual message (up to 20-30 times with a remote RabbitMQ node).
One drawback is that we do not know exactly what went wrong in case of failure,
so we may have to keep a whole batch in memory to log something meaningful or
to re-publish the messages. And this solution is still synchronous, so it
blocks the publishing of messages.

### Strategy #3: Handling Publisher Confirms Asynchronously

The broker confirms published messages asynchronously, one just needs
to register a callback on the client to be notified of these confirms:

Channel channel = connection.createChannel();
channel.confirmSelect();
channel.addConfirmListener((sequenceNumber, multiple) -> {
    // code when message is confirmed
}, (sequenceNumber, multiple) -> {
    // code when message is nack-ed
});

There are 2 callbacks: one for confirmed messages and one for nack-ed messages
(messages that can be considered lost by the broker). Each callback has
2 parameters:

 * sequence number: a number that identifies the confirmed
 or nack-ed message. We will see shortly how to correlate it with the published message.
 * multiple: this is a boolean value. If false, only one message is confirmed/nack-ed, if
 true, all messages with a lower or equal sequence number are confirmed/nack-ed.

The sequence number can be obtained with `Channel#getNextPublishSeqNo()`
before publishing:

int sequenceNumber = channel.getNextPublishSeqNo());
ch.basicPublish(exchange, queue, properties, body);

A simple way to correlate messages with sequence number consists in using a
map. Let's assume we want to publish strings because they are easy to turn into
an array of bytes for publishing. Here is a code sample that uses a map to
correlate the publishing sequence number with the string body of the message:

ConcurrentNavigableMap<Long, String> outstandingConfirms = new ConcurrentSkipListMap<>();
// ... code for confirm callbacks will come later
String body = "...";
outstandingConfirms.put(channel.getNextPublishSeqNo(), body);
channel.basicPublish(exchange, queue, properties, body.getBytes());

The publishing code now tracks outbound messages with a map. We need
to clean this map when confirms arrive and do something like logging a warning
when messages are nack-ed:

ConcurrentNavigableMap<Long, String> outstandingConfirms = new ConcurrentSkipListMap<>();
ConfirmCallback cleanOutstandingConfirms = (sequenceNumber, multiple) -> {
    if (multiple) {
        ConcurrentNavigableMap<Long, String> confirmed = outstandingConfirms.headMap(
          sequenceNumber, true
        );
        confirmed.clear();
    } else {
        outstandingConfirms.remove(sequenceNumber);
    }
};

channel.addConfirmListener(cleanOutstandingConfirms, (sequenceNumber, multiple) -> {
    String body = outstandingConfirms.get(sequenceNumber);
    System.err.format(
      "Message with body %s has been nack-ed. Sequence number: %d, multiple: %b%n",
      body, sequenceNumber, multiple
    );
    cleanOutstandingConfirms.handle(sequenceNumber, multiple);
});
// ... publishing code

The previous sample contains a callback that cleans the map when
confirms arrive. Note this callback handles both single and multiple
confirms. This callback is used when confirms arrive (as the first argument of
`Channel#addConfirmListener`). The callback for nack-ed messages
retrieves the message body and issues a warning. It then re-uses the
previous callback to clean the map of outstanding confirms (whether
messages are confirmed or nack-ed, their corresponding entries in the map
must be removed.)

> #### How to Track Outstanding Confirms?
>
> Our samples use a `ConcurrentNavigableMap` to track outstanding confirms.
> This data structure is convenient for several reasons. It allows to
> easily correlate a sequence number with a message (whatever the message data
> is) and to easily clean the entries up to a given sequence id (to handle
> multiple confirms/nacks). At last, it supports concurrent access, because
> confirm callbacks are called in a thread owned by the client library, which
> should be kept different from the publishing thread.
>
> There are other ways to track outstanding confirms than with
> a sophisticated map implementation, like using a simple concurrent hash map
> and a variable to track the lower bound of the publishing sequence, but
> they are usually more involved and do not belong to a tutorial.

To sum up, handling publisher confirms asynchronously usually requires the
following steps:

 * provide a way to correlate the publishing sequence number with a message.
 * register a confirm listener on the channel to be notified when
 publisher acks/nacks arrive to perform the appropriate actions, like
 logging or re-publishing a nack-ed message. The sequence-number-to-message
 correlation mechanism may also require some cleaning during this step.
 * track the publishing sequence number before publishing a message.

> #### Re-publishing nack-ed Messages?
>
> It can be tempting to re-publish a nack-ed message from the corresponding
> callback but this should be avoided, as confirm callbacks are
> dispatched in an I/O thread where channels are not supposed
> to do operations. A better solution consists in enqueuing the message in an in-memory
> queue which is polled by a publishing thread. A class like `ConcurrentLinkedQueue`
> would be a good candidate to transmit messages between the confirm callbacks
> and a publishing thread.

### Summary

Making sure published messages made it to the broker can be essential in some applications.
Publisher confirms are a RabbitMQ feature that helps to meet this requirement. Publisher
confirms are asynchronous in nature but it is also possible to handle them synchronously.
There is no definitive way to implement publisher confirms, this usually comes down
to the constraints in the application and in the overall system. Typical techniques are:

 * publishing messages individually, waiting for the confirmation synchronously: simple, but very
 limited throughput.
 * publishing messages in batch, waiting for the confirmation synchronously for a batch: simple, reasonable
 throughput, but hard to reason about when something goes wrong.
 * asynchronous handling: best performance and use of resources, good control in case of error, but
 can be involved to implement correctly.

## Putting It All Together

The [`PublisherConfirms.java`](https://github.com/rabbitmq/rabbitmq-tutorials/blob/main/java/PublisherConfirms.java)
class contains code for the techniques we covered. We can compile it, execute it as-is and
see how they each perform:

javac -cp $CP PublisherConfirms.java
java -cp $CP PublisherConfirms

The output will look like the following:

Published 50,000 messages individually in 5,549 ms
Published 50,000 messages in batch in 2,331 ms
Published 50,000 messages and handled confirms asynchronously in 4,054 ms

The output on your computer should look similar if the
client and the server sit on the same machine. Publishing messages individually
performs poorly as expected, but the results for asynchronously handling
are a bit disappointing compared to batch publishing.

Publisher confirms are very network-dependent, so we'd better off
trying with a remote node, which is more realistic as clients
and servers are usually not on the same machine in production.
`PublisherConfirms.java` can easily be changed to use a non-local node:

static Connection createConnection() throws Exception {
    ConnectionFactory cf = new ConnectionFactory();
    cf.setHost("remote-host");
    cf.setUsername("remote-user");
    cf.setPassword("remote-password");
    return cf.newConnection();
}

Recompile the class, execute it again, and wait for the results:

Published 50,000 messages individually in 231,541 ms
Published 50,000 messages in batch in 7,232 ms
Published 50,000 messages and handled confirms asynchronously in 6,332 ms

We see publishing individually now performs terribly. But
with the network between the client and the server, batch publishing and asynchronous handling
now perform similarly, with a small advantage for asynchronous handling of the publisher confirms.

Remember that batch publishing is simple to implement, but does not make it easy to know
which message(s) could not make it to the broker in case of negative publisher acknowledgment.
Handling publisher confirms asynchronously is more involved to implement but provide
better granularity and better control over actions to perform when published messages
are nack-ed.

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace Sabberworm\CSS\RuleSet;

use Sabberworm\CSS\Rule\Rule;
use Sabberworm\CSS\Renderable;

/**
 * RuleSet is a generic superclass denoting rules. The typical example for rule sets are declaration block.
 * However, unknown At-Rules (like @font-face) are also rule sets.
 */
abstract class RuleSet implements Renderable {

	private $aRules;

	public function __construct() {
		$this->aRules = array();
	}

	public function addRule(Rule $oRule) {
		$sRule = $oRule->getRule();
		if(!isset($this->aRules[$sRule])) {
			$this->aRules[$sRule] = array();
		}
		$this->aRules[$sRule][] = $oRule;
	}

	/**
	 * Returns all rules matching the given rule name
	 * @param (null|string|Rule) $mRule pattern to search for. If null, returns all rules. if the pattern ends with a dash, all rules starting with the pattern are returned as well as one matching the pattern with the dash excluded. passing a Rule behaves like calling getRules($mRule->getRule()).
	 * @example $oRuleSet->getRules('font-') //returns an array of all rules either beginning with font- or matching font.
	 * @example $oRuleSet->getRules('font') //returns array(0 => $oRule, …) or array().
	 */
	public function getRules($mRule = null) {
		if ($mRule instanceof Rule) {
			$mRule = $mRule->getRule();
		}
		$aResult = array();
		foreach($this->aRules as $sName => $aRules) {
			// Either no search rule is given or the search rule matches the found rule exactly or the search rule ends in "-" and the found rule starts with the search rule.
			if(!$mRule || $sName === $mRule || (strrpos($mRule, '-') === strlen($mRule) - strlen('-') && (strpos($sName, $mRule) === 0 || $sName === substr($mRule, 0, -1)))) {
				$aResult = array_merge($aResult, $aRules);
			}
		}
		return $aResult;
	}

	/**
	 * Returns all rules matching the given pattern and returns them in an associative array with the rule's name as keys. This method exists mainly for backwards-compatibility and is really only partially useful.
	 * @param (string) $mRule pattern to search for. If null, returns all rules. if the pattern ends with a dash, all rules starting with the pattern are returned as well as one matching the pattern with the dash excluded. passing a Rule behaves like calling getRules($mRule->getRule()).
	 * Note: This method loses some information: Calling this (with an argument of 'background-') on a declaration block like { background-color: green; background-color; rgba(0, 127, 0, 0.7); } will only yield an associative array containing the rgba-valued rule while @link{getRules()} would yield an indexed array containing both.
	 */
	public function getRulesAssoc($mRule = null) {
		$aResult = array();
		foreach($this->getRules($mRule) as $oRule) {
			$aResult[$oRule->getRule()] = $oRule;
		}
		return $aResult;
	}

	/**
	* Remove a rule from this RuleSet. This accepts all the possible values that @link{getRules()} accepts. If given a Rule, it will only remove this particular rule (by identity). If given a name, it will remove all rules by that name. Note: this is different from pre-v.2.0 behaviour of PHP-CSS-Parser, where passing a Rule instance would remove all rules with the same name. To get the old behvaiour, use removeRule($oRule->getRule()).
 * @param (null|string|Rule) $mRule pattern to remove. If $mRule is null, all rules are removed. If the pattern ends in a dash, all rules starting with the pattern are removed as well as one matching the pattern with the dash excluded. Passing a Rule behaves matches by identity.
	*/
	public function removeRule($mRule) {
		if($mRule instanceof Rule) {
			$sRule = $mRule->getRule();
			if(!isset($this->aRules[$sRule])) {
				return;
			}
			foreach($this->aRules[$sRule] as $iKey => $oRule) {
				if($oRule === $mRule) {
					unset($this->aRules[$sRule][$iKey]);
				}
			}
		} else {
			foreach($this->aRules as $sName => $aRules) {
				// Either no search rule is given or the search rule matches the found rule exactly or the search rule ends in "-" and the found rule starts with the search rule or equals it (without the trailing dash).
				if(!$mRule || $sName === $mRule || (strrpos($mRule, '-') === strlen($mRule) - strlen('-') && (strpos($sName, $mRule) === 0 || $sName === substr($mRule, 0, -1)))) {
					unset($this->aRules[$sName]);
				}
			}
		}
	}

	public function __toString() {
		return $this->render(new \Sabberworm\CSS\OutputFormat());
	}

	public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
		$sResult = '';
		$bIsFirst = true;
		foreach ($this->aRules as $aRules) {
			foreach($aRules as $oRule) {
				$sRendered = $oOutputFormat->safely(function() use ($oRule, $oOutputFormat) {
					return $oRule->render($oOutputFormat->nextLevel());
				});
				if($sRendered === null) {
					continue;
				}
				if($bIsFirst) {
					$bIsFirst = false;
					$sResult .= $oOutputFormat->nextLevel()->spaceBeforeRules();
				} else {
					$sResult .= $oOutputFormat->nextLevel()->spaceBetweenRules();
				}
				$sResult .= $sRendered;
			}
		}

		if(!$bIsFirst) {
			// Had some output
			$sResult .= $oOutputFormat->spaceAfterRules();
		}

		return $oOutputFormat->removeLastSemicolon($sResult);
	}

}


text:
enum {VALUEMODIFY=200, VALUEDELETE, VALUERENAME};

BEGIN_EVENT_TABLE(ValueListCtrl, wxListCtrl)
  EVT_RIGHT_DOWN(ValueListCtrl::OnRightDown)
  EVT_MENU(VALUEMODIFY, ValueListCtrl::OnModify)
  EVT_MENU(VALUEDELETE, ValueListCtrl::OnDelete)
  EVT_MENU(VALUERENAME, ValueListCtrl::OnRename)
END_EVENT_TABLE()

ValueListCtrl::ValueListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, const wxString& name)
: wxListCtrl(parent, id, pos, size, style | wxLC_REPORT | wxLC_SINGLE_SEL, validator, name)
{
  InsertColumn(0, "Name");
  InsertColumn(1, "Type");
  InsertColumn(2, "Data");
}

ValueListCtrl::~ValueListCtrl()
{
}

void ValueListCtrl::DisplaySection(const ACE_Configuration_Section_Key& Key)
{
  m_Key = Key;
  DeleteAllItems();
  m_pConfig = MainFrame::Instance()->GetpConfig();
  ACE_TString Name;
  int Index = 0;
  ACE_Configuration::VALUETYPE Type;
  ACE_TString StringValue;
  u_int UINTValue;
  while(!m_pConfig->enumerate_values(Key, Index, Name, Type))
  {
    int Row = InsertItem(0, Name.fast_rep());
    switch(Type)
    {
    case ACE_Configuration::STRING:
      SetItem(Row, 1, "String");
      m_pConfig->get_string_value(Key, Name.fast_rep(), StringValue);
      SetItem(Row, 2, StringValue.fast_rep());
      break;
    case ACE_Configuration::INTEGER:
      {
        SetItem(Row, 1, "Integer");
        m_pConfig->get_integer_value(Key, Name.fast_rep(), UINTValue);
        wxString Text;
        Text.sprintf("%d", UINTValue);
        SetItem(Row, 2, Text);
      }
      break;
    case ACE_Configuration::BINARY:
      SetItem(Row, 1, "Binary");
      break;
    }
    SetItemData(Row, Type);
    ++Index;
  }
}

long ValueListCtrl::GetSelectedItem()
{
  return GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
}

void ValueListCtrl::SelectItem(long ItemID)
{
  // XXX Something isn't right here...  When I use a mask it doesn't work at
  // all someone explain..
  long State = wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED;
  SetItemState(ItemID, State, State);
}

void ValueListCtrl::OnRightDown(wxMouseEvent& event)
{
  int Flags = wxLIST_HITTEST_ONITEM;
  long ItemID = HitTest(wxPoint(event.m_x, event.m_y), Flags);
  if(ItemID < 0)
  {
    return;
  }
  SelectItem(ItemID);

  wxMenu* pMenu = new wxMenu;
  pMenu->Append(VALUEMODIFY, "Modify");
  pMenu->AppendSeparator();
  pMenu->Append(VALUEDELETE, "Delete");
  pMenu->Append(VALUERENAME, "Rename");
  PopupMenu(pMenu, event.m_x, event.m_y);
  delete pMenu;
}

void ValueListCtrl::OnModify(wxCommandEvent& event)
{
  long Item = GetSelectedItem();
  if(Item == -1)
  {
    return ;
  }
  wxListItem ListItem;
  ACE_Configuration::VALUETYPE Type = (ACE_Configuration::VALUETYPE)GetItemData(Item);
  wxString Name = GetItemText(Item);

  switch(Type)
  {
    case ACE_Configuration::STRING:
      {
        ACE_TString Value;
        m_pConfig->get_string_value(m_Key, Name, Value);
        wxString ValueText(Value.fast_rep());
        ValueDlg Dlg(this, Name, ValueText);
        if(Dlg.ShowModal() != wxID_OK)
        {
          return;
        }

        Value = (const char*)Dlg.GetStringValue();
        m_pConfig->set_string_value(m_Key, Name, Value);
      }
      break;
    case ACE_Configuration::INTEGER:
      {
        u_int Value;
        m_pConfig->get_integer_value(m_Key, Name, Value);
        ValueDlg Dlg(this, Name, Value);
        if(Dlg.ShowModal() != wxID_OK)
        {
          return;
        }

        Value = Dlg.GetUINTValue();
        m_pConfig->set_integer_value(m_Key, Name, Value);

      }
      break;
    case ACE_Configuration::BINARY:
      {
        wxMessageBox("Binary modification not supported (why don't you implement it?)");
        //assert(0);
      }
      break;
  }
  DisplaySection(m_Key);
}

void ValueListCtrl::OnDelete(wxCommandEvent& event)
{
  wxMessageDialog Dlg(this, "Are you sure you want to delete this value?", "Confirm Value Delete", wxYES_NO | wxICON_EXCLAMATION );
  if(Dlg.ShowModal() != wxID_YES)
  {
    return;
  }
  long Item = GetSelectedItem();
  if(Item == -1)
  {
    return ;
  }
  wxString Text = GetItemText(Item);
  m_pConfig->remove_value(m_Key, Text);
  DeleteItem(Item);
}

void ValueListCtrl::OnRename(wxCommandEvent& event)
{
  long Item = GetSelectedItem();
  if(Item == -1)
  {
    return ;
  }
  wxListItem ListItem;
  ACE_Configuration::VALUETYPE Type = (ACE_Configuration::VALUETYPE)GetItemData(Item);
  wxString Name = GetItemText(Item);
  wxString Message;
  Message.sprintf("Enter new name for '%s'", Name);
  wxTextEntryDialog Dlg(this, Message, "Please enter text", Name);
  if(Dlg.ShowModal() != wxID_OK)
  {
    return;
  }
  wxString NewName = Dlg.GetValue();
  if(NewName == Name)
  {
    return;
  }

  // XXX Check to see if an entry with this new name already exists

  switch(Type)
  {
    case ACE_Configuration::STRING:
      {
        ACE_TString Value;
        m_pConfig->get_string_value(m_Key, Name, Value);
        m_pConfig->set_string_value(m_Key, NewName, Value);
      }
      break;
    case ACE_Configuration::INTEGER:
      {
        u_int Value;
        m_pConfig->get_integer_value(m_Key, Name, Value);
        m_pConfig->set_integer_value(m_Key, NewName, Value);
      }
      break;
    case ACE_Configuration::BINARY:
      {
        wxMessageBox("Rename binary not supported (Why don't you implement it?)");
        assert(0);
      }
  }
  m_pConfig->remove_value(m_Key, Name);
  DisplaySection(m_Key);
}

void ValueListCtrl::ChangeConfig(ACE_Configuration* pConfig)
{
  m_pConfig = pConfig;
  DisplaySection(pConfig->root_section());
}


text:
var args = arguments[0] || {};
COMMON.construct($);
var postModel = Alloy.createCollection('post');
var searchKey = "";
var post_counter = 0;
var loadLimit = 0;
var count = 1;
if(OS_IOS){
	var viewTolerance = 250;
}else{
	var viewTolerance = 400;
}
var lastDistance = 0;
var nextDistance = viewTolerance;
init();

function init(){
	COMMON.showLoading();

	setTimeout(function(){
		syncData();
	},500);
	if(Ti.App.Properties.getString('roles') == "teacher"){
		COMMON.removeAllChildren($.addView);
	}
}

function syncData(){
	var param = {
		"e_id"	  : Ti.App.Properties.getString('e_id'),
		"session" : Ti.App.Properties.getString('session')
	};
	API.callByPost({url:"getSchoolPost", params: param}, function(responseText){

		var res = JSON.parse(responseText);
		if(res.status == "success"){
			var postData = res.data;
			 if(postData != ""){
			 	 var post = res.data.post;
				 postModel.addPost(post);
				 var post_element_model = Alloy.createCollection('post_element');
				 post_element_model.addElement(post);
			 }
			COMMON.removeAllChildren($.announcementSv);
			post_counter = 0;
			loadLimit = 0;
			showList();
		}else{
			$.win.close();
			Alloy.Globals.Navigator.open("login");
			COMMON.resultPopUp("Session Expired", res.data);
		}
		COMMON.hideLoading();
	}, function(){
		//on error
		showList();
	});

}

function showList(){
	var latestPost = postModel.getPostByEducation( Ti.App.Properties.getString('e_id'),1,searchKey);
	//COMMON.hideLoading();
 	//COMMON.removeAllChildren($.announcementSv);
 	console.log(latestPost);
	if(latestPost.length > 0){

		loadLimit = latestPost.length;
		if(latestPost.length > post_counter ){
			loadLimit = post_counter +10;
		}

		for(i=post_counter; i < loadLimit ; i++){
			if(i < latestPost.length  ){
			//latestPost.forEach(function(entry) {
				var entry = latestPost[i];
				var view0 = $.UI.create('View',{
					classes :['hsize' ],
					source :entry.id,
					selectedBackgroundColor : "#ffffff",
				});

				var view1 = $.UI.create('View',{
					classes :['hsize', 'vert'],
					source :entry.id,
					selectedBackgroundColor : "#ffffff",
				});

				var title = entry.title;
				if(title.trim() != "" &&  title.trim() != null){
					title = title.replace(""", "'");
				}

				var label1 = $.UI.create('Label',{
					classes :['h5','hsize' ,'themeColor', 'padding-left' ],
					top:12,
					width: "80%",
					source :entry.id,
					text: title
				});

				var label2 = $.UI.create('Label',{
					classes :['h6', 'hsize','wfill','font_light_grey', 'padding-left','padding-bottom' ],
					top:5,
					source :entry.id,
					text: entry.publisher_position + " at "+ timeFormat(entry.publish_date)
				});

				var imgView1 = $.UI.create('ImageView',{
					image : "/images/btn-forward.png",
					source :entry.id,
					width : 20,
					height : 20,
					right: 10
				});

				view1.add(label1);
				view1.add(label2);
				view0.add(view1);
				view0.add(imgView1);
				view0.addEventListener('click', goDetails);
				$.announcementSv.add(view0);

				if(latestPost.length != count){
					var viewLine = $.UI.create('View',{
						classes :['gray-line']
					});
					$.announcementSv.add(viewLine);
				}
				count++;
			}
		}

		post_counter += 10;
		COMMON.hideLoading();
	}
}

function separateHozLine(){
	return seperatorLine = Titanium.UI.createView({
		backgroundColor: "#D5D5D5",
		height:1,
		top:5,
		width:Ti.UI.FILL
	});
}

function goDetails(e){
	var elbl = JSON.stringify(e.source);
	var res = JSON.parse(elbl);
	Alloy.Globals.Navigator.open('announcementDetails',{id: res.source, isCurriculum :""});
}

function closeWindow(){
	Ti.App.removeEventListener('refreshPostList', refreshPostList);
	$.win.close();
}

/***SEARCH FUNCTION***/
function searchResult(){
	$.searchItem.blur();
	COMMON.showLoading();
	searchKey = $.searchItem.getValue();
	console.log("searchKey : "+searchKey);
	showList();
}

$.searchItem.addEventListener("return", searchResult);

$.searchItem.addEventListener('focus', function f(e){
	$.searchItem.removeEventListener('focus', f);
});

$.searchItem.addEventListener('cancel', function(e){
	$.searchItem.blur();
	searchKey = "";
	showList();
});

$.searchItem.addEventListener('blur', function(e){

});

$.refresh.addEventListener('click', function(){
	console.log("refresh click");
	post_counter = 0;
	loadLimit = 0;
	COMMON.showLoading();
	syncData();
});

$.add.addEventListener('click', function(){
	Alloy.Globals.Navigator.open('form',{id: "", isCurriculum : "", formType: "1"});
});

$.search.addEventListener('click', function(){
	var isVis=  $.searchItem.getVisible();
	if(isVis === true){
		$.searchItem.visible = false;
		$.searchItem.height = 0;

	}else{
		$.searchItem.visible = true;
		$.searchItem.height = 50;
	}
});

$.announcementSv.addEventListener("scroll", function(e){
	lastDistance = e.y;
	if(lastDistance >= nextDistance){
		nextDistance += viewTolerance;
		showList();
	}

});

function refreshPostList(){
	post_counter = 0;
	loadLimit = 0;
	console.log("refreshPostList");
	syncData();
	//COMMON.removeAllChildren($.announcementSv);
 	//showList();
}

Ti.App.addEventListener('postlayout', refreshPostList);
Ti.App.addEventListener('refreshPostList', refreshPostList);


text:
#ifndef itkPreOrderTreeIterator_h
#define itkPreOrderTreeIterator_h

#include "itkTreeIteratorBase.h"

namespace itk
{
// Forward reference because of circular dependencies
template< typename TTreeType >
class ITK_TEMPLATE_EXPORT LeafTreeIterator;

template< typename TTreeType >
class PreOrderTreeIterator:public TreeIteratorBase< TTreeType >
{
public:

  /** Typedefs */
  typedef typename TTreeType::ValueType     ValueType;
  typedef TreeIteratorBase< TTreeType >     Superclass;
  typedef typename Superclass::TreeNodeType TreeNodeType;
  typedef typename Superclass::NodeType     NodeType;

  /** Constructor */
  PreOrderTreeIterator(const TTreeType *tree, const TreeNodeType *start = ITK_NULLPTR);

  /** Get the type of the iterator */
  NodeType GetType() const;

  /** Clone function */
  TreeIteratorBase< TTreeType > * Clone();

protected:
  /** Return the next node */
  const ValueType & Next();

  /** Return true if the next node exists */
  bool HasNext() const;

private:

  /** Find the next node */
  const TreeNodeType * FindNextNode() const;

  /** LeafTreeIterator uses PreOrderTreeIterator in its implementation, but it
   * needs to adjust its root.  A friend designation is added to correct
   * behavior and retain backwards compatible behavior. */
  friend class LeafTreeIterator< TTreeType >;
};

/** Constructor */
template< typename TTreeType >
PreOrderTreeIterator< TTreeType >::PreOrderTreeIterator(const TTreeType *tree, const TreeNodeType *start):
  TreeIteratorBase< TTreeType >(tree, start)
{}

/** Return the type of the iterator */
template< typename TTreeType >
typename PreOrderTreeIterator< TTreeType >::NodeType
PreOrderTreeIterator< TTreeType >::GetType() const
{
  return TreeIteratorBase< TTreeType >::PREORDER;
}

/** Return true if the next node exists */
template< typename TTreeType >
bool
PreOrderTreeIterator< TTreeType >::HasNext() const
{
  if ( const_cast< TreeNodeType * >( FindNextNode() ) != ITK_NULLPTR )
    {
    return true;
    }
  return false;
}

/** Return the next node */
template< typename TTreeType >
const typename PreOrderTreeIterator< TTreeType >::ValueType &
PreOrderTreeIterator< TTreeType >::Next()
{
  this->m_Position = const_cast< TreeNodeType * >( FindNextNode() );
  return this->m_Position->Get();
}

/** Find the next node */
template< typename TTreeType >
const typename PreOrderTreeIterator< TTreeType >::TreeNodeType *
PreOrderTreeIterator< TTreeType >::FindNextNode() const
{
  if ( this->m_Position == ITK_NULLPTR )
    {
    return ITK_NULLPTR;
    }
  if ( this->m_Position->HasChildren() )
    {
    return dynamic_cast< const TreeNodeType * >( this->m_Position->GetChild(0) );
    }

  if ( !this->m_Position->HasParent() )
    {
    return ITK_NULLPTR;
    }

  TreeNodeType *child = this->m_Position;
  TreeNodeType *parent = dynamic_cast< TreeNodeType * >( this->m_Position->GetParent() );

  // Are we a subtree? Then we are done.
  if ( parent && parent->ChildPosition(this->m_Root) >= 0 )
    {
    return ITK_NULLPTR;
    }

  int childPosition = parent->ChildPosition(child);
  int lastChildPosition = parent->CountChildren() - 1;

  while ( childPosition < lastChildPosition )
    {
    TreeNodeType *help = dynamic_cast< TreeNodeType * >( parent->GetChild(childPosition + 1) );

    if ( help != ITK_NULLPTR )
      {
      return help;
      }
    childPosition++;
    }

  while ( parent->HasParent() )
    {
    child = parent;
    parent = dynamic_cast< TreeNodeType * >( parent->GetParent() );

    // Subtree
    if ( parent->ChildPosition(this->m_Root) >= 0 )
      {
      return ITK_NULLPTR;
      }

    childPosition = parent->ChildPosition(child);
    lastChildPosition = parent->CountChildren() - 1;

    while ( childPosition < lastChildPosition )
      {
      TreeNodeType *help = dynamic_cast< TreeNodeType * >( parent->GetChild(childPosition + 1) );

      if ( help != ITK_NULLPTR )
        {
        return help;
        }
      }
    }
  return ITK_NULLPTR;
}

/** Clone function */
template< typename TTreeType >
TreeIteratorBase< TTreeType > *PreOrderTreeIterator< TTreeType >::Clone()
{
  PreOrderTreeIterator< TTreeType > *clone = new PreOrderTreeIterator< TTreeType >(this->m_Tree, this->m_Position);
  *clone = *this;
  return clone;
}
} // end namespace itk

#endif


text:
@interface StandardLibrary : NSObject

+(llvm::Constant *) getFunction:(NSString *)functionName withBuilder:(llvm::IRBuilder<>)Builder andModule:(llvm::Module *)theModule;

@end


text:
<?php

namespace ThisData\Api\RequestHandler;

use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use ThisData\Api\Event\EventDispatcher;

class AsynchronousRequestHandlerTest extends \PHPUnit_Framework_TestCase
{
    const API_KEY = 'apikey';

    /**
     * @var \PHPUnit_Framework_MockObject_MockObject
     */
    private $dispatcher;

    /**
     * @var AsynchronousRequestHandler
     */
    private $handler;

    public function setUp()
    {
        $this->dispatcher = $this->getMockBuilder(EventDispatcher::class)
            ->getMock();

        $this->handler = new AsynchronousRequestHandler($this->dispatcher);
    }

    public function testHandle()
    {
        $client = $this->getMockClient();
        $request = new Request('GET', '/');

        $this->handler->handle($client, $request);
        $this->assertAttributeCount(1, 'promises', $this->handler);
    }

    public function testWaitForResponses()
    {
        $promise = $this->getMockBuilder(Promise::class)
            ->setMethods(['wait'])
            ->getMock();

        $promise->expects($this->once())
            ->method('wait');

        $property = new \ReflectionProperty($this->handler, 'promises');
        $property->setAccessible(true);
        $property->setValue($this->handler, [$promise]);

        $this->handler->waitForResponses();
    }

    protected function getMockClient()
    {
        $mock = new MockHandler([
            new Response(200),
        ]);

        $handler = HandlerStack::create($mock);

        return new \ThisData\Api\Client(self::API_KEY, 1, [
            'handler' => $handler,
        ]);
    }
}