package org.estatio.module.task.dom.policy;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.inject.Inject;
import com.google.common.collect.Lists;
import com.google.common.eventbus.Subscribe;
import org.axonframework.eventhandling.annotation.EventHandler;
import org.apache.isis.applib.annotation.DomainService;
import org.apache.isis.applib.annotation.DomainServiceLayout;
import org.apache.isis.applib.annotation.NatureOfService;
import org.apache.isis.applib.services.metamodel.MetaModelService3;
import org.estatio.module.base.spiimpl.togglz.EstatioTogglzFeature;
import org.estatio.module.task.dom.state.State;
import org.estatio.module.task.dom.state.StateTransition;
import org.estatio.module.task.dom.state.StateTransitionService;
import org.estatio.module.task.dom.state.StateTransitionType;
import org.estatio.module.task.dom.task.Task;
import org.estatio.module.task.dom.task.Task_mixinActAbstract;
import org.estatio.module.task.dom.triggers.DomainObject_triggerAbstract;
import org.estatio.module.party.dom.Person;
import org.estatio.module.party.dom.PersonRepository;
import org.estatio.module.party.dom.role.PartyRole;
import org.estatio.module.party.dom.role.PartyRoleType;
import org.estatio.module.party.dom.role.PartyRoleTypeRepository;

@DomainService(nature = NatureOfService.DOMAIN)
@DomainServiceLayout(menuOrder = "1")
public class EnforceTaskAssignmentPolicySubscriber extends org.apache.isis.applib.AbstractSubscriber {

    public static interface WithStateTransitionClass {

        Class<?> getStateTransitionClass();
    }

    @EventHandler
    @Subscribe
    public void on(Task_mixinActAbstract.ActionDomainEvent ev) {
        if (ev.getSemantics().isSafeInNature()) {
            return;
        }
        final Class stateTransitionClass = ev.getStateTransitionClass();
        final Task task = (Task) ev.getMixedIn();
        final StateTransition transition = stateTransitionService.findFor(task);
        if (transition == null) {
            // shouldn't occur
            return;
        }
        final Class taskTransitionClass = stateTransitionService.transitionClassFor(transition.getTransitionType());
        if (stateTransitionClass != taskTransitionClass) {
            // just ignore; this mixin action on task doesn't apply to the domain object that the task applies to.
            // or, maybe should hide (and then we can delete code in the subtypes of the mixinAbstract
            return;
        }
        final Object domainObject = transition.getDomainObject();
        applyPolicy(stateTransitionClass, domainObject, ev);
    }

    @EventHandler
    @Subscribe
    public void on(DomainObject_triggerAbstract.ActionDomainEvent ev) {
        if (ev.getSemantics().isSafeInNature()) {
            return;
        }
        final Class stateTransitionClass = ev.getStateTransitionClass();
        final Object domainObject = ev.getMixedIn();
        applyPolicy(stateTransitionClass, domainObject, ev);
    }

    private void applyPolicy(final Class stateTransitionClass, final Object domainObject, final org.apache.isis.applib.services.eventbus.ActionDomainEvent<?> evv) {
        Optional<String> reasonIfAny = applyPolicy(stateTransitionClass, domainObject);
        reasonIfAny.ifPresent(evv::disable);
    }

    <DO, ST extends StateTransition<DO, ST, STT, S>, STT extends StateTransitionType<DO, ST, STT, S>, S extends State<S>> Optional<String> applyPolicy(final Class<ST> stateTransitionClass, final DO entityOrViewModel) {
        if (EstatioTogglzFeature.ApproveByProxy.isActive()) {
            return Optional.empty();
        }
        final DO entity = unwrapIfRequired(entityOrViewModel);
        final ST pendingTransition = stateTransitionService.pendingTransitionOf(entity, stateTransitionClass);
        if (pendingTransition == null) {
            return Optional.empty();
        }
        final Task task = pendingTransition.getTask();
        if (task == null) {
            return Optional.empty();
        }
        final Person meAsPerson = personRepository.me();
        if (meAsPerson == null) {
            return Optional.of("Could not locate Person for current user");
        }
        List<PartyRoleType> meAsPersonRoleTypes = Lists.newArrayList(meAsPerson.getRoles()).stream().map(PartyRole::getRoleType).collect(Collectors.toList());
        // // if meAsPerson is incoming invoice manager and was allowed to reject previous state, still allow for correction
        // first guard: meAsPerson always needs the PartyRoleType the task is assigned to
        if (!meAsPersonRoleTypes.contains(task.getAssignedTo())) {
            return Optional.of(String.format("Task assigned to '%s' role", task.getAssignedTo().getKey()));
        }
        // second guard: if the task is assigned to a specific person it needs to be meAsPerson
        final Person taskAssignedTo = task.getPersonAssignedTo();
        if (taskAssignedTo == null || taskAssignedTo == meAsPerson) {
            return Optional.empty();
        } else {
            return Optional.of(String.format("Task assigned to %s", taskAssignedTo.getReference()));
        }
    }

    private <DO> DO unwrapIfRequired(final DO entityOrViewModel) {
        final DO entity;
        if (entityOrViewModel instanceof ViewModelWrapper) {
            final ViewModelWrapper entityOrViewModel1 = (ViewModelWrapper) entityOrViewModel;
            entity = (DO) entityOrViewModel1.getDomainObject();
        } else {
            entity = entityOrViewModel;
        }
        return entity;
    }

@Inject
    MetaModelService3 metaModelService3;

    @Inject
    StateTransitionService stateTransitionService;

    @Inject
    PersonRepository personRepository;

    @Inject
    PartyRoleTypeRepository partyRoleTypeRepository;
}


/*
 * All rights reserved.
 *
 */
package org.openquark.cal.foreignsupport.module.Summary;

import java.util.Random;

/**
 * @author Jawright
 * The Math class provides access to standard Java mathmatics functions for the
 * Summary module.
 */
public final class Math {

    private static final Random rndGenerator = new Random();

{
        return rndGenerator.nextDouble();
    }
}


{
        return rndGenerator.nextDouble();
    }

/*
 * All rights reserved.
 *
 */
package org.openquark.cal.foreignsupport.module.Summary;

import java.util.Random;

/**
 * @author Jawright
 * The Math class provides access to standard Java mathmatics functions for the
 * Summary module.
 */
public final class Math {

    private static final Random rndGenerator = new Random();

    public static final double random()


/*
 * All rights reserved.
 *
 */
package org.openquark.cal.foreignsupport.module.Summary;

import java.util.Random;

/**
 * @author Jawright
 * The Math class provides access to standard Java mathmatics functions for the
 * Summary module.
 */
public final class Math {

    private static final Random rndGenerator = new Random();

    public static final double random() {
        return rndGen


/*
 * All rights reserved.
 *
 */
package org.openquark.cal.foreignsupport.module.Summary;

import java.uti

l.Random;

/**
 * @author Jawright
 * The Math class provides access to standard Java mathmatics functions for the
 * Summary module.
 */
public final class Math {

    private static final Random rndGenerator = new Random();

    public static final double random() {
        return rndGenerator.nextDouble();
    }
}


package com.ra4king.opengl.arcsynthesis.gl33.chapter5.example2;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.*;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.BufferUtils;
import com.ra4king.opengl.GLProgram;
import com.ra4king.opengl.util.ShaderProgram;

public class Example5_2 extends GLProgram {

{
        new Example5_2().run(true);
    }

    private final float RIGHT_EXTENT = 0.8f;

    private final float LEFT_EXTENT = -RIGHT_EXTENT;

    private final float TOP_EXTENT = 0.2f;

    private final float MIDDLE_EXTENT = 0;

    private final float BOTTOM_EXTENT = -TOP_EXTENT;

    private final float FRONT_EXTENT = -1.25f;

    private final float REAR_EXTENT = -1.75f;

    private final float[] GREEN_COLOR = { 0.75f, 0.75f, 1, 1 };

    private final float[] BLUE_COLOR = { 0, 0.5f, 0, 1 };

    private final float[] RED_COLOR = { 1, 0, 0, 1 };

    private final float[] GREY_COLOR = { 0.8f, 0.8f, 0.8f, 1 };

    private final float[] BROWN_COLOR = { 0.5f, 0.5f, 0, 1 };

    private float[] data = { // Object 1 positions
    LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, // Object 2 positions
    TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, // Object 1 colors
    GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], // Object 2 colors
    RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3] };

    private final short[] indices = { 0, 2, 1, 3, 2, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 11, 13, 12, 14, 16, 15, 17, 16, 14 };

    private ShaderProgram program;

    private int offsetUniform;

    private int vao;

    private FloatBuffer perspectiveMatrix;

    private int perspectiveMatrixUniform;

    private float frustumScale = 1;

    public Example5_2() {
        super("Example 5.2 - Base Vertex Overlap", 500, 500, true);
    }

    @Override
    public void init() {
        glClearColor(0, 0, 0, 0);
        program = new ShaderProgram(readFromFile("example5.2.vert"), readFromFile("example5.2.frag"));
        offsetUniform = program.getUniformLocation("offset");
        perspectiveMatrixUniform = program.getUniformLocation("perspectiveMatrix");
        float zNear = 1, zFar = 3;
        perspectiveMatrix = BufferUtils.createFloatBuffer(16);
        perspectiveMatrix.put(0, frustumScale);
        perspectiveMatrix.put(5, frustumScale);
        perspectiveMatrix.put(10, (zFar + zNear) / (zNear - zFar));
        perspectiveMatrix.put(14, (2 * zFar * zNear) / (zNear - zFar));
        perspectiveMatrix.put(11, -1);
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
        int vbo1 = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glBufferData(GL_ARRAY_BUFFER, (FloatBuffer) BufferUtils.createFloatBuffer(data.length).put(data).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        int vbo2 = glGenBuffers();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (ShortBuffer) BufferUtils.createShortBuffer(indices.length).put(indices).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        vao = glGenVertexArrays();
        glBindVertexArray(vao);
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 36 * 3 * 4);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBindVertexArray(0);
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glFrontFace(GL_CW);
    }

    @Override
    public void resized() {
        super.resized();
        perspectiveMatrix.put(0, frustumScale / ((float) getWidth() / getHeight()));
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
    }

    @Override
    public void render() {
        glClear(GL_COLOR_BUFFER_BIT);
        program.begin();
        glBindVertexArray(vao);
        glUniform3f(offsetUniform, 0, 0, 0);
        glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0);
        glUniform3f(offsetUniform, 0, 0, -1);
        glDrawElementsBaseVertex(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0, 36 / 2);
        glBindVertexArray(0);
        program.end();
    }
}


{
        super.resized();
        perspectiveMatrix.put(0, frustumScale / ((float) getWidth() / getHeight()));
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
    }

package com.ra4king.opengl.arcsynthesis.gl33.chapter5.example2;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.*;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.BufferUtils;
import com.ra4king.opengl.GLProgram;
import com.ra4king.opengl.util.ShaderProgram;

public class Example5_2 extends GLProgram {

    public static void main(String[] args) {
        new Example5_2().run(true);
    }

    private final float RIGHT_EXTENT = 0.8f;

    private final float LEFT_EXTENT = -RIGHT_EXTENT;

    private final float TOP_EXTENT = 0.2f;

    private final float MIDDLE_EXTENT = 0;

    private final float BOTTOM_EXTENT = -TOP_EXTENT;

    private final float FRONT_EXTENT = -1.25f;

    private final float REAR_EXTENT = -1.75f;

    private final float[] GREEN_COLOR = { 0.75f, 0.75f, 1, 1 };

    private final float[] BLUE_COLOR = { 0, 0.5f, 0, 1 };

    private final float[] RED_COLOR = { 1, 0, 0, 1 };

    private final float[] GREY_COLOR = { 0.8f, 0.8f, 0.8f, 1 };

    private final float[] BROWN_COLOR = { 0.5f, 0.5f, 0, 1 };

    private float[] data = { // Object 1 positions
    LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, // Object 2 positions
    TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, // Object 1 colors
    GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], // Object 2 colors
    RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3] };

    private final short[] indices = { 0, 2, 1, 3, 2, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 11, 13, 12, 14, 16, 15, 17, 16, 14 };

    private ShaderProgram program;

    private int offsetUniform;

    private int vao;

    private FloatBuffer perspectiveMatrix;

    private int perspectiveMatrixUniform;

    private float frustumScale = 1;

    public Example5_2() {
        super("Example 5.2 - Base Vertex Overlap", 500, 500, true);
    }

    @Override
    public void init() {
        glClearColor(0, 0, 0, 0);
        program = new ShaderProgram(readFromFile("example5.2.vert"), readFromFile("example5.2.frag"));
        offsetUniform = program.getUniformLocation("offset");
        perspectiveMatrixUniform = program.getUniformLocation("perspectiveMatrix");
        float zNear = 1, zFar = 3;
        perspectiveMatrix = BufferUtils.createFloatBuffer(16);
        perspectiveMatrix.put(0, frustumScale);
        perspectiveMatrix.put(5, frustumScale);
        perspectiveMatrix.put(10, (zFar + zNear) / (zNear - zFar));
        perspectiveMatrix.put(14, (2 * zFar * zNear) / (zNear - zFar));
        perspectiveMatrix.put(11, -1);
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
        int vbo1 = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glBufferData(GL_ARRAY_BUFFER, (FloatBuffer) BufferUtils.createFloatBuffer(data.length).put(data).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        int vbo2 = glGenBuffers();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (ShortBuffer) BufferUtils.createShortBuffer(indices.length).put(indices).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        vao = glGenVertexArrays();
        glBindVertexArray(vao);
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 36 * 3 * 4);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBindVertexArray(0);
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glFrontFace(GL_CW);
    }

    @Override
    public void resized()

    @Override
    public void render() {
        glClear(GL_COLOR_BUFFER_BIT);
        program.begin();
        glBindVertexArray(vao);
        glUniform3f(offsetUniform, 0, 0, 0);
        glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0);
        glUniform3f(offsetUniform, 0, 0, -1);
        glDrawElementsBaseVertex(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0, 36 / 2);
        glBindVertexArray(0);
        program.end();
    }
}


        super.resized();
        perspectiveMatrix.put(0, frustumScale / ((float) getWidth() / getHeight()));

package com.ra4king.opengl.arcsynthesis.gl33.chapter5.example2;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.*;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.BufferUtils;
import com.ra4king.opengl.GLProgram;
import com.ra4king.opengl.util.ShaderProgram;

public class Example5_2 extends GLProgram {

    public static void main(String[] args) {
        new Example5_2().run(true);
    }

    private final float RIGHT_EXTENT = 0.8f;

    private final float LEFT_EXTENT = -RIGHT_EXTENT;

    private final float TOP_EXTENT = 0.2f;

    private final float MIDDLE_EXTENT = 0;

    private final float BOTTOM_EXTENT = -TOP_EXTENT;

    private final float FRONT_EXTENT = -1.25f;

    private final float REAR_EXTENT = -1.75f;

    private final float[] GREEN_COLOR = { 0.75f, 0.75f, 1, 1 };

    private final float[] BLUE_COLOR = { 0, 0.5f, 0, 1 };

    private final float[] RED_COLOR = { 1, 0, 0, 1 };

    private final float[] GREY_COLOR = { 0.8f, 0.8f, 0.8f, 1 };

    private final float[] BROWN_COLOR = { 0.5f, 0.5f, 0, 1 };

    private float[] data = { // Object 1 positions
    LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, // Object 2 positions
    TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, // Object 1 colors
    GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], // Object 2 colors
    RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3] };

    private final short[] indices = { 0, 2, 1, 3, 2, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 11, 13, 12, 14, 16, 15, 17, 16, 14 };

    private ShaderProgram program;

    private int offsetUniform;

    private int vao;

    private FloatBuffer perspectiveMatrix;

    private int perspectiveMatrixUniform;

    private float frustumScale = 1;

    public Example5_2() {
        super("Example 5.2 - Base Vertex Overlap", 500, 500, true);
    }

    @Override
    public void init() {
        glClearColor(0, 0, 0, 0);
        program = new ShaderProgram(readFromFile("example5.2.vert"), readFromFile("example5.2.frag"));
        offsetUniform = program.getUniformLocation("offset");
        perspectiveMatrixUniform = program.getUniformLocation("perspectiveMatrix");
        float zNear = 1, zFar = 3;
        perspectiveMatrix = BufferUtils.createFloatBuffer(16);
        perspectiveMatrix.put(0, frustumScale);
        perspectiveMatrix.put(5, frustumScale);
        perspectiveMatrix.put(10, (zFar + zNear) / (zNear - zFar));
        perspectiveMatrix.put(14, (2 * zFar * zNear) / (zNear - zFar));
        perspectiveMatrix.put(11, -1);
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
        int vbo1 = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glBufferData(GL_ARRAY_BUFFER, (FloatBuffer) BufferUtils.createFloatBuffer(data.length).put(data).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        int vbo2 = glGenBuffers();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (ShortBuffer) BufferUtils.createShortBuffer(indices.length).put(indices).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        vao = glGenVertexArrays();
        glBindVertexArray(vao);
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 36 * 3 * 4);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBindVertexArray(0);
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glFrontFace(GL_CW);
    }

    @Override
    public void resized() {

        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
    }

    @Override
    public void render() {
        glClear(GL_COLOR_BUFFER_BIT);
        program.begin();
        glBindVertexArray(vao);
        glUniform3f(offsetUniform, 0, 0, 0);
        glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0);
        glUniform3f(offsetUniform, 0, 0, -1);
        glDrawElementsBaseVertex(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0, 36 / 2);
        glBindVertexArray(0);
        program.end();
    }
}


package com.ra4king.opengl.arcsynthesis.gl33.chapter5.example2;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.*;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.BufferUtils;
import com.ra4king.opengl.GLProgram;
import com.ra4king.opengl.util.ShaderProgram;

public class Example5_2 extends GLProgram {

    public static void main(String[] args) {
        new Example5_2().run(true);
    }

    private final float RIGHT_EXTENT = 0.8f;

    private final float LEFT_EXTENT = -RIGHT_EXTENT;

    private final float TOP_EXTENT = 0.2f;

    private final float MIDDLE_EXTENT = 0;

    private final float BOTTOM_EXTENT = -TOP_EXTENT;

    private final float FRONT_EXTENT = -1.25f;

    private final float REAR_EXTENT = -1.75f;

    private final float[] GREEN_COLOR = { 0.75f, 0.75f, 1, 1 };

    private final float[] BLUE_COLOR = { 0, 0.5f, 0, 1 };

    private final float[] RED_COLOR = { 1, 0, 0, 1 };

    private final float[] GREY_COLOR = { 0.8f, 0.8f, 0.8f, 1 };

    private final float[] BROWN_COLOR = { 0.5f, 0.5f, 0, 1 };

    private float[] data = { // Object 1 positions
    LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, // Object 2 positions
    TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, // Object 1 colors
    GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], // Object 2 colors
    RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3] };

    private final short[] indices = { 0, 2, 1, 3, 2, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 11, 13, 12, 14, 16, 15, 17, 16, 14 };

    private ShaderProgram program;

    private int offsetUniform;

    private int vao;

    private FloatBuffer perspectiveMatrix;

    private int perspectiveMatrixUniform;

    private float frustumScale = 1;

    public Example5_2() {
        super("Example 5.2 - Base Vertex Overlap", 500, 500, true);
    }

    @Override
    public void init() {
        glClearColor(0, 0, 0, 0);
        program = new ShaderProgram(readFromFile("example5.2.vert"), readFromFile("example5.2.frag"));
        offsetUniform = program.getUniformLocation("offset");
        perspectiveMatrixUniform = program.getUniformLocation("perspectiveMatrix");
        float zNear = 1, zFar = 3;
        perspectiveMatrix = BufferUtils.createFloatBuffer(16);
        perspectiveMatrix.put(0, frustumScale);
        perspectiveMatrix.put(5, frustumScale);
        perspectiveMatrix.put(10, (zFar + zNear) / (zNear - zFar));
        perspectiveMatrix.put(14, (2 * zFar * zNear) / (zNear - zFar));
        perspectiveMatrix.put(11, -1);
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
        int vbo1 = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glBufferData(GL_ARRAY_BUFFER, (FloatBuffer) BufferUtils.createFloatBuffer(data.length).put(data).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        int vbo2 = glGenBuffers();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (ShortBuffer) BufferUtils.createShortBuffer(indices.length).put(indices).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        vao = glGenVertexArrays();
        glBindVertexArray(vao);
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 36 * 3 * 4);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBindVertexArray(0);
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glFrontFace(GL_CW);
    }

    @Override
    public void resized() {
        super.resized();
        perspectiveMatrix.put(0, frustumScale / ((float) getWidth() / getHeight()));

        program.end();
    }

    @Override
    public void render() {
        glClear(GL_COLOR_BUFFER_BIT);
        program.begin();
        glBindVertexArray(vao);
        glUniform3f(offsetUniform, 0, 0, 0);
        glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0);
        glUniform3f(offsetUniform, 0, 0, -1);
        glDrawElementsBaseVertex(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0, 36 / 2);
        glBindVertexArray(0);
        program.end();
    }
}


package com.ra4king.opengl.arcsynthesis.gl33.chapter5.example2;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.*;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.BufferUtils;
import com.ra4king.opengl.GLProgram;
import com.ra4king.opengl.util.ShaderProgram;

public class Example5_2 extends GLProgram {

    public static void main(String[] args) {
        new Example5_2().run(true);
    }

    private final float RIGHT_EXTENT = 0.8f;

    private final float LEFT_EXTENT = -RIGHT_EXTENT;

    private final float TOP_EXTENT = 0.2f;

    private final float MIDDLE_EXTENT = 0;

    private final float BOTTOM_EXTENT = -TOP_EXTENT;

    private final float FRONT_EXTENT = -1.25f;

    private final float REAR_EXTENT = -1.75f;

    private final float[] GREEN_COLOR = { 0.75f, 0.75f, 1, 1 };

    private final float[] BLUE_COLOR = { 0, 0.5f, 0, 1 };

    private final float[] RED_COLOR = { 1, 0, 0, 1 };

    private final float[] GREY_COLOR = { 0.8f, 0.8f, 0.8f, 1 };

    private final float[] BROWN_COLOR = { 0.5f, 0.5f, 0, 1 };

    private float[] data = { // Object 1 positions
    LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, // Object 2 positions
    TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, // Object 1 colors
    GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], // Object 2 colors
    RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3] };

    private final short[] indices = { 0, 2, 1, 3, 2, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 11, 13, 12, 14, 16, 15, 17, 16, 14 };

    private ShaderProgram program;

    private int offsetUniform;

    private int vao;

    private FloatBuffer perspectiveMatrix;

    private int perspectiveMatrixUniform;

    private float frustumScale = 1;

    public Example5_2() {
        super("Example 5.2 - Base Vertex Overlap", 500, 500, true);
    }

    @Override
    public void init() {
        glClearColor(0, 0, 0, 0);
        program = new ShaderProgram(readFromFile("example5.2.vert"), readFromFile("example5.2.frag"));
        offsetUniform = program.getUniformLocation("offset");
        perspectiveMatrixUniform = program.getUniformLocation("perspectiveMatrix");
        float zNear = 1, zFar = 3;
        perspectiveMatrix = BufferUtils.createFloatBuffer(16);
        perspectiveMatrix.put(0, frustumScale);
        perspectiveMatrix.put(5, frustumScale);
        perspectiveMatrix.put(10, (zFar + zNear) / (zNear - zFar));
        perspectiveMatrix.put(14, (2 * zFar * zNear) / (zNear - zFar));
        perspectiveMatrix.put(11, -1);
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
        int vbo1 = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glBufferData(GL_ARRAY_BUFFER, (FloatBuffer) BufferUtils.createFloatBuffer(data.length).put(data).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        int vbo2 = glGenBuffers();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (ShortBuffer) BufferUtils.createShortBuffer(indices.length).put(indices).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        vao = glGenVertexArrays();
        glBindVertexArray(vao);
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 36 * 3 * 4);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBindVertexArray(0);
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glFrontFace(GL_CW);
    }

    @Override
    public void resized() {
        super.resized();
        perspectiveMatrix.put(0, frustumScale / ((float) getWidth() / getHeight()));
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);


package com.ra4king.opengl.arcsynthesis.gl33.chapter5.example2;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.*;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.BufferUtils;
import com.ra4king.opengl.GLProgram;
import com.ra4king.opengl.util.ShaderProgram;

public class Example5_2 extends GLProgram {

    public static void main(String[] args) {
        new Example5_2().run(true);
    }

    private final float RIGHT_EXTENT = 0.8f;

    private final float LEFT_EXTENT = -RIGHT_EXTENT;

    private final float TOP_EXTENT = 0.2f;

    private final float MIDDLE_EXTENT = 0;

    private final float BOTTOM_EXTENT = -TOP_EXTENT;

    private final float FRONT_EXTENT = -1.25f;

    private final float REAR_EXTENT = -1.75f;

    private final float[] GREEN_COLOR = { 0.75f, 0.75f, 1, 1 };

    private final float[] BLUE_COLOR = { 0, 0.5f, 0, 1 };

    private final float[] RED_COLOR = { 1, 0, 0, 1 };

    private final float[] GREY_COLOR = { 0.8f, 0.8f, 0.8f, 1 };

    private final float[] BROWN_COLOR = { 0.5f, 0.5f, 0, 1 };

    private float[] data = { // Object 1 positions
    LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, // Object 2 positions
    TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, // Object 1 colors
    GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], // Object 2 colors
    RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3] };

    private final short[] indices = { 0, 2, 1, 3, 2, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 11, 13, 12, 14, 16, 15, 17, 16, 14 };

    private ShaderProgram program;

    private int offsetUniform;

    private int vao;

    private FloatBuffer perspectiveMatrix;

    private int perspectiveMatrixUniform;

    private float frustumScale = 1;

    public Example5_2() {
        super("Example 5.2 - Base Vertex Overlap", 500, 500, true);
    }

    @Override
    public void init() {
        glClearColor(0, 0, 0, 0);
        program = new ShaderProgram(readFromFile("example5.2.vert"), readFromFile("example5.2.frag"));
        offsetUniform = program.getUniformLocation("offset");
        perspectiveMatrixUniform = program.getUniformLocation("perspectiveMatrix");
        float zNear = 1, zFar = 3;
        perspectiveMatrix = BufferUtils.createFloatBuffer(16);
        perspectiveMatrix.put(0, frustumScale);
        perspectiveMatrix.put(5, frustumScale);
        perspectiveMatrix.put(10, (zFar + zNear) / (zNear - zFar));
        perspectiveMatrix.put(14, (2 * zFar * zNear) / (zNear - zFar));
        perspectiveMatrix.put(11, -1);
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspective

        program.end();
        int vbo1 = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glBufferData(GL_ARRAY_BUFFER, (FloatBuffer) BufferUtils.createFloatBuffer(data.length).put(data).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        int vbo2 = glGenBuffers();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (ShortBuffer) BufferUtils.createShortBuffer(indices.length).put(indices).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        vao = glGenVertexArrays();
        glBindVertexArray(vao);
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 36 * 3 * 4);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBindVertexArray(0);
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glFrontFace(GL_CW);
    }

    @Override
    public void resized() {
        super.resized();
        perspectiveMatrix.put(0, frustumScale / ((float) getWidth() / getHeight()));
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
    }

    @Override
    public void render() {
        glClear(GL_COLOR_BUFFER_BIT);
        program.begin();
        glBindVertexArray(vao);
        glUniform3f(offsetUniform, 0, 0, 0);
        glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0);
        glUniform3f(offsetUniform, 0, 0, -1);
        glDrawElementsBaseVertex(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0, 36 / 2);
        glBindVertexArray(0);
        program.end();
    }
}


package com.ra4king.opengl.arcsynthesis.gl33.chapter5.example2;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.opengl.GL32.*;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.lwjgl.BufferUtils;
import com.ra4king.opengl.GLProgram;
import com.ra4king.opengl.util.ShaderProgram;

public class Example5_2 extends GLProgram {

    public static void main(String[] args) {
        new Example5_2().run(true);
    }

    private final float RIGHT_EXTENT = 0.8f;

    private final float LEFT_EXTENT = -RIGHT_EXTENT;

    private final float TOP_EXTENT = 0.2f;

    private final float MIDDLE_EXTENT = 0;

    private final float BOTTOM_EXTENT = -TOP_EXTENT;

    private final float FRONT_EXTENT = -1.25f;

    private final float REAR_EXTENT = -1.75f;

    private final float[] GREEN_COLOR = { 0.75f, 0.75f, 1, 1 };

    private final float[] BLUE_COLOR = { 0, 0.5f, 0, 1 };

    private final float[] RED_COLOR = { 1, 0, 0, 1 };

    private final float[] GREY_COLOR = { 0.8f, 0.8f, 0.8f, 1 };

    private final float[] BROWN_COLOR = { 0.5f, 0.5f, 0, 1 };

    private float[] data = { // Object 1 positions
    LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, LEFT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, MIDDLE_EXTENT, FRONT_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, LEFT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, TOP_EXTENT, REAR_EXTENT, RIGHT_EXTENT, BOTTOM_EXTENT, REAR_EXTENT, // Object 2 positions
    TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM

_EXTENT, LEFT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, RIGHT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, MIDDLE_EXTENT, LEFT_EXTENT, FRONT_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, RIGHT_EXTENT, REAR_EXTENT, TOP_EXTENT, LEFT_EXTENT, REAR_EXTENT, BOTTOM_EXTENT, LEFT_EXTENT, REAR_EXTENT, // Object 1 colors
    GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], // Object 2 colors
    RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], RED_COLOR[0], RED_COLOR[1], RED_COLOR[2], RED_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BROWN_COLOR[0], BROWN_COLOR[1], BROWN_COLOR[2], BROWN_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], BLUE_COLOR[0], BLUE_COLOR[1], BLUE_COLOR[2], BLUE_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREEN_COLOR[0], GREEN_COLOR[1], GREEN_COLOR[2], GREEN_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3], GREY_COLOR[0], GREY_COLOR[1], GREY_COLOR[2], GREY_COLOR[3] };

    private final short[] indices = { 0, 2, 1, 3, 2, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 11, 13, 12, 14, 16, 15, 17, 16, 14 };

    private ShaderProgram program;

    private int offsetUniform;

    private int vao;

    private FloatBuffer perspectiveMatrix;

    private int perspectiveMatrixUniform;

    private float frustumScale = 1;

    public Example5_2() {
        super("Example 5.2 - Base Vertex Overlap", 500, 500, true);
    }

    @Override
    public void init() {
        glClearColor(0, 0, 0, 0);
        program = new ShaderProgram(readFromFile("example5.2.vert"), readFromFile("example5.2.frag"));
        offsetUniform = program.getUniformLocation("offset");
        perspectiveMatrixUniform = program.getUniformLocation("perspectiveMatrix");
        float zNear = 1, zFar = 3;
        perspectiveMatrix = BufferUtils.createFloatBuffer(16);
        perspectiveMatrix.put(0, frustumScale);
        perspectiveMatrix.put(5, frustumScale);
        perspectiveMatrix.put(10, (zFar + zNear) / (zNear - zFar));
        perspectiveMatrix.put(14, (2 * zFar * zNear) / (zNear - zFar));
        perspectiveMatrix.put(11, -1);
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
        int vbo1 = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glBufferData(GL_ARRAY_BUFFER, (FloatBuffer) BufferUtils.createFloatBuffer(data.length).put(data).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        int vbo2 = glGenBuffers();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (ShortBuffer) BufferUtils.createShortBuffer(indices.length).put(indices).flip(), GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        vao = glGenVertexArrays();
        glBindVertexArray(vao);
        glBindBuffer(GL_ARRAY_BUFFER, vbo1);
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
        glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, 36 * 3 * 4);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo2);
        glBindVertexArray(0);
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glFrontFace(GL_CW);
    }

    @Override
    public void resized() {
        super.resized();
        perspectiveMatrix.put(0, frustumScale / ((float) getWidth() / getHeight()));
        program.begin();
        glUniformMatrix4(perspectiveMatrixUniform, false, perspectiveMatrix);
        program.end();
    }

    @Override
    public void render() {
        glClear(GL_COLOR_BUFFER_BIT);
        program.begin();
        glBindVertexArray(vao);
        glUniform3f(offsetUniform, 0, 0, 0);
        glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0);
        glUniform3f(offsetUniform, 0, 0, -1);
        glDrawElementsBaseVertex(GL_TRIANGLES, indices.length, GL_UNSIGNED_SHORT, 0, 36 / 2);
        glBindVertexArray(0);
        program.end();
    }
}


@Override
    @Nonnull
    public String getDescription()

/*
 *
 * This file is part of MZmine 2.
 *
 */
package net.sf.mzmine.modules.rawdatamethods.peakpicking.msms;

import java.util.Collection;
import javax.annotation.Nonnull;
import net.sf.mzmine.datamodel.MZmineProject;
import net.sf.mzmine.datamodel.RawDataFile;
import net.sf.mzmine.modules.MZmineModuleCategory;
import net.sf.mzmine.modules.MZmineProcessingModule;
import net.sf.mzmine.parameters.ParameterSet;
import net.sf.mzmine.taskcontrol.Task;
import net.sf.mzmine.util.ExitCode;

public class MsMsPeakPickerModule implements MZmineProcessingModule {

    private static final String MODULE_NAME = "MS/MS peaklist builder";

    private static final String MODULE_DESCRIPTION = "This module looks through the whole raw data for MS2 scans and makes a list of chromatographic peaks using the precursor mass.";

    @Override
    @Nonnull
    public String getName() {
        return MODULE_NAME;
    }

{
        return MODULE_DESCRIPTION;
    }

    @Override
    @Nonnull
    public ExitCode runModule(@Nonnull MZmineProject project, @Nonnull ParameterSet parameters, @Nonnull Collection<Task> tasks) {
        RawDataFile[] dataFiles = parameters.getParameter(MsMsPeakPickerParameters.dataFiles).getValue().getMatchingRawDataFiles();
        for (RawDataFile dataFile : dataFiles) {
            Task newTask = new MsMsPeakPickingTask(project, dataFile, parameters);
            tasks.add(newTask);
        }
        return ExitCode.OK;
    }

    @Override
    @Nonnull
    public MZmineModuleCategory getModuleCategory() {
        return MZmineModuleCategory.PEAKPICKING;
    }

    @Override
    @Nonnull
    public Class<? extends ParameterSet> getParameterSetClass() {
        return MsMsPeakPickerParameters.class;
    }
}


{
        return MZmineModuleCategory.PEAKPICKING;
    }

/*
 *
 * This file is part of MZmine 2.
 *
 */
package net.sf.mzmine.modules.rawdatamethods.peakpicking.msms;

import java.util.Collection;
import javax.annotation.Nonnull;
import net.sf.mzmine.datamodel.MZmineProject;
import net.sf.mzmine.datamodel.RawDataFile;
import net.sf.mzmine.modules.MZmineModuleCategory;
import net.sf.mzmine.modules.MZmineProcessingModule;
import net.sf.mzmine.parameters.ParameterSet;
import net.sf.mzmine.taskcontrol.Task;
import net.sf.mzmine.util.ExitCode;

public class MsMsPeakPickerModule implements MZmineProcessingModule {

    private static final String MODULE_NAME = "MS/MS peaklist builder";

    private static final String MODULE_DESCRIPTION = "This module looks through the whole raw data for MS2 scans and makes a list of chromatographic peaks using the precursor mass.";

    @Override
    @Nonnull
    public String getName() {
        return MODULE_NAME;
    }

    @Override
    @Nonnull
    public String getDescription() {
        return MODULE_DESCRIPTION;
    }

    @Override
    @Nonnull
    public ExitCode runModule(@Nonnull MZmineProject project, @Nonnull ParameterSet parameters, @Nonnull Collection<Task> tasks) {
        RawDataFile[] dataFiles = parameters.getParameter(MsMsPeakPickerParameters.dataFiles).getValue().getMatchingRawDataFiles();
        for (RawDataFile dataFile : dataFiles) {
            Task newTask = new MsMsPeakPickingTask(project, dataFile, parameters);
            tasks.add(newTask);
        }
        return ExitCode.OK;
    }

    @Override
    @Nonnull
    public MZmineModuleCategory getModuleCategory()

    @Override
    @Nonnull
    public Class<? extends ParameterSet> getParameterSetClass() {
        return MsMsPeakPickerParameters.class;
    }
}


/*
 *
 * This file is part of MZmine 2.
 *
 */
package net.sf.mzmine.modules.rawdatamethods.peakpicking.msms;

import java.util.Collection;
import javax.annotation.Nonnull;
import net.sf.mzmine.datamodel.MZmineProject;
import net.sf.mzmine.datamodel.RawDataFile;
import net.sf.mzmine.modules.MZmineModuleCategory;
import net.sf.mzmine.modules.MZmineProcessingModule;
import net.sf.mzmine.parameters.ParameterSet;
import net.sf.mzmine.taskcontrol.Task;
import net.sf.mzmine.util.ExitCode;

public class MsMsPeakPickerModule implements MZmineProcessingModule {

    private static final String MODULE_NAME = "MS/MS peaklist builder";

    private static final String MODULE_DESCRIPTION = "This module looks through the whole raw data for MS2 scans and makes a list of chromatographic peaks using the precursor mass.";

    @Override
    @Nonnull
    public String getName() {
        return MODULE_NAME;
    }

    @Override
    @Nonnull
    public String getDescription() {
        return MODULE_DESCRIPTION;
    }

    @Override
    @Nonnull
    public ExitCode runModule(@Nonnull MZmineProject project, @Nonnull ParameterSet parameters, @Nonnull Collection<Task> tasks) {

        for (RawDataFile dataFile : dataFiles) {
            Task newTask = new MsMsPeakPickingTask(project, dataFile, parameters);
            tasks.add(newTask);
        }
        return ExitCode.OK;
    }

    @Override
    @Nonnull
    public MZmineModuleCategory getModuleCategory() {
        return MZmineModuleCategory.PEAKPICKING;
    }

    @Override
    @Nonnull
    public Class<? extends ParameterSet> getParameterSetClass() {
        return MsMsPeakPickerParameters.class;
    }
}


for (RawDataFile dataFile : dataFiles) {
            Task newTask = new MsMsPeakPickingTask(project, dataFile, parameters);
            tasks.add(newTask);
        }

/*
 *
 * This file is part of MZmine 2.
 *
 */
package net.sf.mzmine.modules.rawdatamethods.peakpicking.msms;

import java.util.Collection;
import javax.annotation.Nonnull;
import net.sf.mzmine.datamodel.MZmineProject;
import net.sf.mzmine.datamodel.RawDataFile;
import net.sf.mzmine.modules.MZmineModuleCategory;
import net.sf.mzmine.modules.MZmineProcessingModule;
import net.sf.mzmine.parameters.ParameterSet;
import net.sf.mzmine.taskcontrol.Task;
import net.sf.mzmine.util.ExitCode;

public class MsMsPeakPickerModule implements MZmineProcessingModule {

    private static final String MODULE_NAME = "MS/MS peaklist builder";

    private static final String MODULE_DESCRIPTION = "This module looks through the whole raw data for MS2 scans and makes a list of chromatographic peaks using the precursor mass.";

    @Override
    @Nonnull
    public String getName() {
        return MODULE_NAME;
    }

    @Override
    @Nonnull
    public String getDescription() {
        return MODULE_DESCRIPTION;
    }

    @Override
    @Nonnull
    public ExitCode runModule(@Nonnull MZmineProject project, @Nonnull ParameterSet parameters, @Nonnull Collection<Task> tasks) {
        RawDataFile[] dataFiles = parameters.getParameter(MsMsPeakPickerParameters.dataFiles).getValue().getMatchingRawDataFiles();

        return ExitCode.OK;
    }

    @Override
    @Nonnull
    public MZmineModuleCategory getModuleCategory() {
        return MZmineModuleCategory.PEAKPICKING;
    }

    @Override
    @Nonnull
    public Class<? extends ParameterSet> getParameterSetClass() {
        return MsMsPeakPickerParameters.class;
    }
}


/*
 *
 * This file is part of MZmine 2.
 *
 */
package net.sf.mzmine.modules.rawdatamethods.peakpicking.msms;

import java.util.Collection;
import javax.annotation.Nonnull;
import net.sf.mzmine.datamodel.MZmineProject;
import net.sf.mzmine.datamodel.RawDataFile;
import net.sf.mzmine.modules.MZmineModuleCategory;
import net.sf.mzmine.modules.MZmineProcessingModule;
import net.sf.mzmine.parameters.ParameterSet;
import net.sf.mzmine.taskcontrol.Task;
import net.sf.mzmine.util.ExitCode;

public class MsMsPeakPickerModule implements MZmineProcessingModule {

    private static final String MODULE_NAME = "MS/MS peaklist builder";

    private static final String MODULE_DESCRIPTION = "This module looks through the whole raw data for MS2 scans and makes a list of chromatographic peaks using the precursor mass.";

    @Override
    @Nonnull
    public String getName() {
        return MODULE_NAME;
    }

    @Override
    @Nonnull
    public String getDescription() {
        return MODULE_DESCRIPTION;
    }

    @Override
    @Nonnull
    public ExitCode runModule(@Nonnull MZmineProject project, @Nonnull ParameterSet parameters, @Nonnull Collection<Task> tasks) {
        RawDataFile[] dataFiles = parameters.getParameter(MsMsPeakPickerParameters.dataFiles).getValue().getMatchingRawDataFiles();
        for (RawDataFile dataFile : dataFiles) {
            Task newTask = new MsMsPeakPickingTask(project, dataFile, parameters);
            tasks.add(newTask);
        }

    @Override
    @Nonnull
    public MZmineModuleCategory getModuleCategory() {
        return MZmineModuleCategory.PEAKPICKING;
    }

    @Override
    @Nonnull
    public Class<? extends ParameterSet> getParameterSetClass() {
        return MsMsPeakPickerParameters.class;
    }
}


/*
 *
 * This file is part of MZmine 2.
 *
 */
package net.sf.mzmine.modules.rawdatamethods.peakpicking.msms;

import java.util.Collection;
import javax.annotation.Nonnull;
import net.sf.mzmine.datamodel.MZmineProject;
import net.sf.mzmine.datamodel.RawDataFile;
import net.sf.mzmine.modules.MZmineModuleCategory;
import net.sf.mzmine.modules.MZmineProcessingModule;
import net.sf.mzmine.parameters.ParameterSet;
import net.sf.mzmine.taskcontrol.Task;
import net.sf.mzmine.util.ExitCode;

public class MsMsPeakPickerModule implements MZmineProcessingModule {

    private static final String MODULE_NAME = "MS/MS peaklist builder";

    private static final String MODULE_DESCRIPTION = "This module looks through the whole raw data for MS2 scans and makes a list of chromatographic peaks using the precursor mass.";

    @Override
    @Nonnull
    public String getName() {
        return MODULE_NAME;
    }

    @Override
    @Nonnull
    public String getDescription() {
        return MODULE_DESCRIPTION;
    }

    @Override
    @Nonnull
    public ExitCode runModule(@Nonnull MZmineProject project, @Nonnull ParameterSet parameters, @Nonnull Collection<Task> tasks) {
        RawDataFile[]


/*
 *
 * This file is part of MZmine 2.
 *
 */
package net.sf.mzmine.modules.rawdatamethods.peakpicking.msms;

import java.util.Collection;
import javax.an

notation.Nonnull;
import net.sf.mzmine.datamodel.MZmineProject;
import net.sf.mzmine.datamodel.RawDataFile;
import net.sf.mzmine.modules.MZmineModuleCategory;
import net.sf.mzmine.modules.MZmineProcessingModule;
import net.sf.mzmine.parameters.ParameterSet;
import net.sf.mzmine.taskcontrol.Task;
import net.sf.mzmine.util.ExitCode;

public class MsMsPeakPickerModule implements MZmineProcessingModule {

    private static final String MODULE_NAME = "MS/MS peaklist builder";

    private static final String MODULE_DESCRIPTION = "This module looks through the whole raw data for MS2 scans and makes a list of chromatographic peaks using the precursor mass.";

    @Override
    @Nonnull
    public String getName() {
        return MODULE_NAME;
    }

    @Override
    @Nonnull
    public String getDescription() {
        return MODULE_DESCRIPTION;
    }

    @Override
    @Nonnull
    public ExitCode runModule(@Nonnull MZmineProject project, @Nonnull ParameterSet parameters, @Nonnull Collection<Task> tasks) {
        RawDataFile[] dataFiles = parameters.getParameter(MsMsPeakPickerParameters.dataFiles).getValue().getMatchingRawDataFiles();
        for (RawDataFile dataFile : dataFiles) {
            Task newTask = new MsMsPeakPickingTask(project, dataFile, parameters);
            tasks.add(newTask);
        }
        return ExitCode.OK;
    }

    @Override
    @Nonnull
    public MZmineModuleCategory getModuleCategory() {
        return MZmineModuleCategory.PEAKPICKING;
    }

    @Override
    @Nonnull
    public Class<? extends ParameterSet> getParameterSetClass() {
        return MsMsPeakPickerParameters.class;
    }
}


public void addInterfaceToDaemon(IPAndPort interfaceIPAndPort, IPAndPort daemonIPAndPort)

package com.ms.silverking.cloud.dht.net;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import com.google.common.collect.ImmutableMap;
import com.ms.silverking.collection.CollectionUtil;
import com.ms.silverking.collection.HashedSetMap;
import com.ms.silverking.log.Log;
import com.ms.silverking.net.AddrAndPort;
import com.ms.silverking.net.IPAndPort;

/**
 * Background: Under "normal" operation, each SK daemon has a fixed port bound to a single IP address. The port
 * is the same for all daemons. This implies that only a single daemon may run per server. It also implies that all
 * traffic will go over a single interface.
 *

 * IP aliasing allows us to overcome these limitations. IP aliasing does this in two ways:
 * 1) The aliasing feature can be used to allow a daemon to be identified by a "fake" IPAndPort. This IPAndPort is
 * used in the topology and almost all of the rest of the code as if it were a real IP. This IPAliasMap class is
 * used by MessageGroupBase (and a few other classes) to translate this IPAndPort into an actual IPAndPort when
 * communication needs to take place. By design, most of the code is unaware of this translation.
 * 2) The aliasing feature allows traffic to be distributed across multiple interfaces. This is done by associating
 * multiple interfaces with an actual IPAndPort. In this case, MessageGroupBase will translate the usual IPAndPort
 * into one of the many remote interfaces in a round-robin fashion.
 *

 * Terminology: for consistency in the above two cases, this class calls the IP address used to identify a daemon
 * the "daemon IP" or "daemon" for short. Note that the port is fixed to the SK instance port for this case.
 * Each of the one or more IPAndPorts associated with a daemon IP is called an "interface IP and port" or
 * "interface" for short. The "interface IP and port" are always a real IP and port. The daemon IP is "fake"
 * for case 1, but an actual IP for case 2.
 *

 * For case (1) each daemon IP acts as an alias, and has a single interface IP and port to which it is associated.
 * For case (2) each daemon IP has several interface IPAndPorts with which it is associated.
 *

 * Colloquially, for case (1) we can call the daemon IP an "alias". We don't do that in this code to avoid confusion
 * with case (2) where we could call the interface IP and ports aliases. (The daemon IP is real in this case.)
 *

 * Notes on case (1) - setting up "aliases"/fake IP addresses for each daemon IP.
 * - the topology, host groups, etc, must be composed of these daemon IPs, not interface IPs
 * - the DHT config must have an ipAliasMap field in the form ipAliasMap={daemonIp=interfaceIp:port}
 * As mentioned previously, the vast majority of the code will use this daemon IP as if it were the actual IP.
 * In addition, users will only use the daemon IP.
 *

 * All translation between daemon IP and interface IP and ports will take place in this class.
 * Clients will select a daemon IP address from the topology as their preferredServer. This is dealiased in
 * DHTSessionImpl to an interface IP and port, to which the client communicates.
 * Aliasing also allows nodes to deviate from the fixed port in DHT config; such nodes would require an alias
 * map entry which maps a fake IP to the port actually in use for a given address. The node itself must be passed
 * -port N on the command line at start up in order to run on a port different to that specified in DHT config.
 * This also allows many nodes to run on the same machine; several daemon IP entries in the maps could exist,
 * which resolve to the same host, but with unique ports. Note that each daemon IP must be unique in this case
 *

 * It is not required that all nodes have an alias identity, so long as it is consistent between the topology
 * and host group files, and such nodes can be omitted from the alias map. The alias resolution, when it
 * does not find an entry for such a node, would leave the address unchanged and clients/servers would proceed
 * to try and connect directly
 *

 * Notes on case 2:
 * When aliasing is used to support multi-homing, each daemon IP will be associated with
 * several interface and ports, and the dht config will have an entry of the
 * form: ipAliasMap={daemonIp=interfaceIp:port,...}. Note that all ports must be the same for case 2.
 * The ports may also be omitted.
 */
public class IPAliasMap {

    // one-to-many
    private final Map<IPAndPort, IPAndPort[]> daemonToInterfaces;

    // many-to-one
    private final Map<IPAndPort, IPAndPort> interfaceToDaemon;

    private final HashedSetMap<String, IPAndPort> interfaceIPToDaemons;

    // used for round-robin between aliases
    private final AtomicInteger interfaceIndex;

    // (e.g. for distributing traffic across multi-homed interfaces)
    private static final boolean logDaemonToInterfaceMapping = true;

    private static final boolean logInterfaceToDaemonMapping = true;

    public IPAliasMap(Map<IPAndPort, IPAndPort[]> daemonToInterfaces) {
        interfaceToDaemon = new ConcurrentHashMap<>();
        interfaceIPToDaemons = new HashedSetMap<>();
        if (daemonToInterfaces == null) {
            this.daemonToInterfaces = ImmutableMap.of();
            interfaceIndex = null;
        } else {
            sanityCheckMap(daemonToInterfaces);
            this.daemonToInterfaces = new ConcurrentHashMap<>();
            interfaceIndex = new AtomicInteger();
            this.daemonToInterfaces.putAll(daemonToInterfaces);
            if (logDaemonToInterfaceMapping) {
                IPAliasingUtil.logAliasMap(daemonToInterfaces);
            }
            addReverseMappings(daemonToInterfaces);
        }
    }

    public static IPAliasMap identityMap() {
        return new IPAliasMap(null);
    }

    private void sanityCheckMap(Map<IPAndPort, IPAndPort[]> daemonToInterfaces) {
        ensureDaemonPortsMatch(daemonToInterfaces);
    }

    private void ensureDaemonPortsMatch(Map<IPAndPort, IPAndPort[]> daemonToInterfaces) {
        int daemonPort;
        daemonPort = -1;
        for (IPAndPort daemonIPAndPort : daemonToInterfaces.keySet()) {
            if (daemonPort < 0) {
                daemonPort = daemonIPAndPort.getPort();
            } else {
                if (daemonIPAndPort.getPort() != daemonPort) {
                    throw new RuntimeException("IPAliasMap daemon ports must all be the same");
                }
            }
        }
    }

    public Map<IPAndPort, IPAndPort[]> getDaemonToInterfacesMap() {
        return ImmutableMap.copyOf(daemonToInterfaces);
    }

    public Map<IPAndPort, IPAndPort> getInterfaceToDaemonMap() {
        return ImmutableMap.copyOf(interfaceToDaemon);
    }

    public AddrAndPort daemonToInterface(AddrAndPort daemon) {
        AddrAndPort[] interfaces;
        interfaces = daemonToInterfaces.get(daemon);
        if (interfaces != null) {
            // Below is random. For now we implement round robin instead
            // Round robin
            return interfaces[interfaceIndex.getAndIncrement() % interfaces.length];
        } else {
            return daemon;
        }
    }

    public IPAndPort interfaceToDaemon(InetSocketAddress interfaceIPAndPort) {
        return interfaceToDaemon(new IPAndPort(interfaceIPAndPort));
    }

    public IPAndPort interfaceToDaemon(IPAndPort interfaceIPAndPort) {
        IPAndPort daemon;
        daemon = interfaceToDaemon.get(interfaceIPAndPort);
        return daemon != null ? daemon : interfaceIPAndPort;
    }

    /**
     * For all entries in the daemonToInterfaces argument, update the
     * reverse map. That is, update the interfaceToDaemon map with
     * the corresponding mappings.
     *
     * @param daemonToInterfaces the forward map to reverse
     */
    private void addReverseMappings(Map<IPAndPort, IPAndPort[]> daemonToInterfaces) {
        for (Map.Entry<IPAndPort, IPAndPort[]> entry : daemonToInterfaces.entrySet()) {
            addInterfacesToDaemon(entry.getValue(), entry.getKey());
        }
    }

    // only used at startup
    private void addInterfacesToDaemon(IPAndPort[] interfaces, IPAndPort daemon) {
        for (IPAndPort interfaceIPAndPort : interfaces) {
            addInterfaceToDaemon(interfaceIPAndPort, daemon, false);
            addIPToDaemonMapping(interfaceIPAndPort.getIPAsString(), daemon);
        }
    }

    // used at runtime to map reverse connections

{
        addInterfaceToDaemon(interfaceIPAndPort, daemonIPAndPort, true);
    }

    private void addInterfaceToDaemon(IPAndPort interfaceIPAndPort, IPAndPort daemonIPAndPort, boolean allowRemapping) {
        IPAndPort prev;
        prev = interfaceToDaemon.put(interfaceIPAndPort, daemonIPAndPort);
        if (logInterfaceToDaemonMapping && (prev == null || !prev.equals(daemonIPAndPort))) {
            Log.infof("IPAliasMap adding interfaceIPAndPort=>daemonIPAndPort: %s=>%s", interfaceIPAndPort, daemonIPAndPort);
        }
        if (!allowRemapping && prev != null && !prev.equals(daemonIPAndPort)) {
            throw new RuntimeException("Interface maps to multiple daemons: " + interfaceIPAndPort);
        }
    }

    private void addIPToDaemonMapping(String ip, IPAndPort daemonIPAndPort) {
        interfaceIPToDaemons.addValue(ip, daemonIPAndPort);
    }

    /**
     * Given an interface ip, randomly select one of the possibly many associated daemons
     *
     * @param ip
     * @return
     */
    public IPAndPort interfaceIPToRandomDaemon(String ip) {
        return interfaceIPToDaemons.getAnyValue(ip);
    }

    /**
     * If an interface ip uniquely identifies a daemon ip, return that daemon
     *
     * @param ip
     * @return the uniquely associated daemon
     */
    public IPAndPort interfaceIPToDaemon_ifUnique(String ip) {
        Set<IPAndPort> daemonIPAndPorts;
        daemonIPAndPorts = interfaceIPToDaemons.getSet(ip);
        if (daemonIPAndPorts == null || daemonIPAndPorts.size() > 1) {
            return null;
        } else {
            return daemonIPAndPorts.iterator().next();
        }
    }

    @Override
    public String toString() {
        StringBuffer sb;
        sb = new StringBuffer();
        sb.append("{");
        for (Map.Entry<IPAndPort, IPAndPort[]> entry : daemonToInterfaces.entrySet()) {
            sb.append(String.format("%s -> [", entry.getKey()));
            for (IPAndPort _interface : entry.getValue()) {
                sb.append(_interface + " ");
            }
            sb.append("]\n");
        }
        sb.append("}");
        return sb.toString() + "\n" + CollectionUtil.mapToString(interfaceToDaemon);
    }
}


{
        ensureDaemonPortsMatch(daemonToInterfaces);
    }

package com.ms.silverking.cloud.dht.net;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import com.google.common.collect.ImmutableMap;
import com.ms.silverking.collection.CollectionUtil;
import com.ms.silverking.collection.HashedSetMap;
import com.ms.silverking.log.Log;
import com.ms.silverking.net.AddrAndPort;
import com.ms.silverking.net.IPAndPort;

/**
 * Background: Under "normal" operation, each SK daemon has a fixed port bound to a single IP address. The port
 * is the same for all daemons. This implies that only a single daemon may run per server. It also implies that all
 * traffic will go over a single interface.
 *

 * IP aliasing allows us to overcome these limitations. IP aliasing does this in two ways:
 * 1) The aliasing feature can be used to allow a daemon to be identified by a "fake" IPAndPort. This IPAndPort is
 * used in the topology and almost all of the rest of the code as if it were a real IP. This IPAliasMap class is
 * used by MessageGroupBase (and a few other classes) to translate this IPAndPort into an actual IPAndPort when
 * communication needs to take place. By design, most of the code is unaware of this translation.
 * 2) The aliasing feature allows traffic to be distributed across multiple interfaces. This is done by associating
 * multiple interfaces with an actual IPAndPort. In this case, MessageGroupBase will translate the usual IPAndPort
 * into one of the many remote interfaces in a round-robin fashion.
 *

 * Terminology: for consistency in the above two cases, this class calls the IP address used to identify a daemon
 * the "daemon IP" or "daemon" for short. Note that the port is fixed to the SK instance port for this case.
 * Each of the one or more IPAndPorts associated with a daemon IP is called an "interface IP and port" or
 * "interface" for short. The "interface IP and port" are always a real IP and port. The daemon IP is "fake"
 * for case 1, but an actual IP for case 2.
 *

 * For case (1) each daemon IP acts as an alias, and has a single interface IP and port to which it is associated.
 * For case (2) each daemon IP has several interface IPAndPorts with which it is associated.
 *

 * Colloquially, for case (1) we can call the daemon IP an "alias". We don't do that in this code to avoid confusion
 * with case (2) where we could call the interface IP and ports aliases. (The daemon IP is real in this case.)
 *

 * Notes on case (1) - setting up "aliases"/fake IP addresses for each daemon IP.
 * - the topology, host groups, etc, must be composed of these daemon IPs, not interface IPs
 * - the DHT config must have an ipAliasMap field in the form ipAliasMap={daemonIp=interfaceIp:port}
 * As mentioned previously, the vast majority of the code will use this daemon IP as if it were the actual IP.
 * In addition, users will only use the daemon IP.
 *

 * All translation between daemon IP and interface IP and ports will take place in this class.
 * Clients will select a daemon IP address from the topology as their preferredServer. This is dealiased in
 * DHTSessionImpl to an interface IP and port, to which the client communicates.
 * Aliasing also allows nodes to deviate from the fixed port in DHT config; such nodes would require an alias
 * map entry which maps a fake IP to the port actually in use for a given address. The node itself must be passed
 * -port N on the command line at start up in order to run on a port different to that specified in DHT config.
 * This also allows many nodes to run on the same machine; several daemon IP entries in the maps could exist,
 * which resolve to the same host, but with unique ports. Note that each daemon IP must be unique in this case
 *

 * It is not required that all nodes have an alias identity, so long as it is consistent between the topology
 * and host group files, and such nodes can be omitted from the alias map. The alias resolution, when it
 * does not find an entry for such a node, would leave the address unchanged and clients/servers would proceed
 * to try and connect directly
 *

 * Notes on case 2:
 * When aliasing is used to support multi-homing, each daemon IP will be associated with
 * several interface and ports, and the dht config will have an entry of the
 * form: ipAliasMap={daemonIp=interfaceIp:port,...}. Note that all ports must be the same for case 2.
 * The ports may also be omitted.
 */
public class IPAliasMap {

    // one-to-many
    private final Map<IPAndPort, IPAndPort[]> daemonToInterfaces;

    // many-to-one
    private final Map<IPAndPort, IPAndPort> interfaceToDaemon;

    private final HashedSetMap<String, IPAndPort> interfaceIPToDaemons;

    // used for round-robin between aliases
    private final AtomicInteger interfaceIndex;

    // (e.g. for distributing traffic across multi-homed interfaces)
    private static final boolean logDaemonToInterfaceMapping = true;

    private static final boolean logInterfaceToDaemonMapping = true;

    public IPAliasMap(Map<IPAndPort, IPAndPort[]> daemonToInterfaces) {
        interfaceToDaemon = new ConcurrentHashMap<>();
        interfaceIPToDaemons = new HashedSetMap<>();
        if (daemonToInterfaces == null) {
            this.daemonToInterfaces = ImmutableMap.of();
            interfaceIndex = null;
        } else {
            sanityCheckMap(daemonToInterfaces);
            this.daemonToInterfaces = new ConcurrentHashMap<>();
            interfaceIndex = new AtomicInteger();
            this.daemonToInterfaces.putAll(daemonToInterfaces);
            if (logDaemonToInterfaceMapping) {
                IPAliasingUtil.logAliasMap(daemonToInterfaces);
            }
            addReverseMappings(daemonToInterfaces);
        }
    }

    public static IPAliasMap identityMap() {
        return new IPAliasMap(null);
    }

    private void sanityCheckMap(Map<IPAndPort, IPAndPort[]> daemonToInterfaces)

    private void ensureDaemonPortsMatch(Map<IPAndPort, IPAndPort[]> daemonToInterfaces) {
        int daemonPort;
        daemonPort = -1;
        for (IPAndPort daemonIPAndPort : daemonToInterfaces.keySet()) {
            if (daemonPort < 0) {
                daemonPort = daemonIPAndPort.getPort();
            } else {
                if (daemonIPAndPort.getPort() != daemonPort) {
                    throw new RuntimeException("IPAliasMap daemon ports must all be the same");
                }
            }
        }
    }

    public Map<IPAndPort, IPAndPort[]> getDaemonToInterfacesMap() {
        return ImmutableMap.copyOf(daemonToInterfaces);
    }

    public Map<IPAndPort, IPAndPort> getInterfaceToDaemonMap() {
        return ImmutableMap.copyOf(interfaceToDaemon);
    }

    public AddrAndPort daemonToInterface(AddrAndPort daemon) {
        AddrAndPort[] interfaces;
        interfaces = daemonToInterfaces.get(daemon);
        if (interfaces != null) {
            // Below is random. For now we implement round robin instead
            // Round robin
            return interfaces[interfaceIndex.getAndIncrement() % interfaces.length];
        } else {
            return daemon;
        }
    }

    public IPAndPort interfaceToDaemon(InetSocketAddress interfaceIPAndPort) {
        return interfaceToDaemon(new IPAndPort(interfaceIPAndPort));
    }

    public IPAndPort interfaceToDaemon(IPAndPort interfaceIPAndPort) {
        IPAndPort daemon;
        daemon = interfaceToDaemon.get(interfaceIPAndPort);
        return daemon != null ? daemon : interfaceIPAndPort;
    }

    /**
     * For all entries in the daemonToInterfaces argument, update the
     * reverse map. That is, update the interfaceToDaemon map with
     * the corresponding mappings.
     *
     * @param daemonToInterfaces the forward map to reverse
     */
    private void addReverseMappings(Map<IPAndPort, IPAndPort[]> daemonToInterfaces) {
        for (Map.Entry<IPAndPort, IPAndPort[]> entry : daemonToInterfaces.entrySet()) {
            addInterfacesToDaemon(entry.getValue(), entry.getKey());
        }
    }

    // only used at startup
    private void addInterfacesToDaemon(IPAndPort[] interfaces, IPAndPort daemon) {
        for (IPAndPort interfaceIPAndPort : interfaces) {
            addInterfaceToDaemon(interfaceIPAndPort, daemon, false);
            addIPToDaemonMapping(interfaceIPAndPort.getIPAsString(), daemon);
        }
    }

    // used at runtime to map reverse connections
    public void addInterfaceToDaemon(IPAndPort interfaceIPAndPort, IPAndPort daemonIPAndPort) {
        addInterfaceToDaemon(interfaceIPAndPort, daemonIPAndPort, true);
    }

    private void addInterfaceToDaemon(IPAndPort interfaceIPAndPort, IPAndPort daemonIPAndPort, boolean allowRemapping) {
        IPAndPort prev;
        prev = interfaceToDaemon.put(interfaceIPAndPort, daemonIPAndPort);
        if (logInterfaceToDaemonMapping && (prev == null || !prev.equals(daemonIPAndPort))) {
            Log.infof("IPAliasMap adding interfaceIPAndPort=>daemonIPAndPort: %s=>%s", interfaceIPAndPort, daemonIPAndPort);
        }
        if (!allowRemapping && prev != null && !prev.equals(daemonIPAndPort)) {
            throw new RuntimeException("Interface maps to multiple daemons: " + interfaceIPAndPort);
        }
    }

    private void addIPToDaemonMapping(String ip, IPAndPort daemonIPAndPort) {
        interfaceIPToDaemons.addValue(ip, daemonIPAndPort);
    }

    /**
     * Given an interface ip, randomly select one of the possibly many associated daemons
     *
     * @param ip
     * @return
     */
    public IPAndPort interfaceIPToRandomDaemon(String ip) {
        return interfaceIPToDaemons.getAnyValue(ip);
    }

    /**
     * If an interface ip uniquely identifies a daemon ip, return that daemon
     *
     * @param ip
     * @return the uniquely associated daemon
     */
    public IPAndPort interfaceIPToDaemon_ifUnique(String ip) {
        Set<IPAndPort> daemonIPAndPorts;
        daemonIPAndPorts = interfaceIPToDaemons.getSet(ip);
        if (daemonIPAndPorts == null || daemonIPAndPorts.size() > 1) {
            return null;
        } else {
            return daemonIPAndPorts.iterator().next();
        }
    }

    @Override
    public String toString() {
        StringBuffer sb;
        sb = new StringBuffer();
        sb.append("{");
        for (Map.Entry<IPAndPort, IPAndPort[]> entry : daemonToInterfaces.entrySet()) {
            sb.append(String.format("%s -> [", entry.getKey()));
            for (IPAndPort _interface : entry.getValue()) {
                sb.append(_interface + " ");
            }
            sb.append("]\n");
        }
        sb.append("}");
        return sb.toString() + "\n" + CollectionUtil.mapToString(interfaceToDaemon);
    }
}