text:
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.execution.buffer;

import com.facebook.presto.OutputBuffers;
import com.facebook.presto.OutputBuffers.OutputBufferId;
import com.facebook.presto.block.BlockAssertions;
import com.facebook.presto.execution.StateMachine;
import com.facebook.presto.memory.context.SimpleLocalMemoryContext;
import com.facebook.presto.spi.Page;
import com.facebook.presto.spi.type.BigintType;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ListenableFuture;
import io.airlift.units.DataSize;
import io.airlift.units.Duration;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;

import static com.facebook.presto.OutputBuffers.BROADCAST_PARTITION_ID;
import static com.facebook.presto.OutputBuffers.BufferType.BROADCAST;
import static com.facebook.presto.OutputBuffers.createInitialEmptyOutputBuffers;
import static com.facebook.presto.execution.buffer.BufferResult.emptyResults;
import static com.facebook.presto.execution.buffer.BufferState.OPEN;
import static com.facebook.presto.execution.buffer.BufferState.TERMINAL_BUFFER_STATES;
import static com.facebook.presto.execution.buffer.TestClientBuffer.assertBufferResultEquals;
import static com.facebook.presto.execution.buffer.TestClientBuffer.getFuture;
import static com.facebook.presto.execution.buffer.TestingPagesSerdeFactory.testingPagesSerde;
import static com.facebook.presto.memory.context.AggregatedMemoryContext.newSimpleAggregatedMemoryContext;
import static com.facebook.presto.spi.type.BigintType.BIGINT;
import static com.google.common.base.Preconditions.checkArgument;
import static io.airlift.concurrent.MoreFutures.tryGetFutureValue;
import static io.airlift.concurrent.Threads.daemonThreadsNamed;
import static io.airlift.units.DataSize.Unit.BYTE;
import static java.util.concurrent.Executors.newScheduledThreadPool;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;

public class TestBroadcastOutputBuffer
{
    private static final PagesSerde PAGES_SERDE = testingPagesSerde();

    private static final Duration NO_WAIT = new Duration(0, MILLISECONDS);
    private static final Duration MAX_WAIT = new Duration(1, SECONDS);
    private static final DataSize BUFFERED_PAGE_SIZE = new DataSize(PAGES_SERDE.serialize(createPage(42)).getRetainedSizeInBytes(), BYTE);
    private static final String TASK_INSTANCE_ID = "task-instance-id";

    private static final ImmutableList<BigintType> TYPES = ImmutableList.of(BIGINT);
    private static final OutputBufferId FIRST = new OutputBufferId(0);
    private static final OutputBufferId SECOND = new OutputBufferId(1);

    private ScheduledExecutorService stateNotificationExecutor;

    @BeforeClass
    public void setUp()
    {
        stateNotificationExecutor = newScheduledThreadPool(5, daemonThreadsNamed("test-%s"));
    }

    @AfterClass(alwaysRun = true)
    public void tearDown()
    {
        if (stateNotificationExecutor != null) {
            stateNotificationExecutor.shutdownNow();
            stateNotificationExecutor = null;
        }
    }

    @Test
    public void testInvalidConstructorArg()
    {
        try {
            createBroadcastBuffer(createInitialEmptyOutputBuffers(BROADCAST).withBuffer(FIRST, BROADCAST_PARTITION_ID).withNoMoreBufferIds(), new DataSize(0, BYTE));
            fail("Expected IllegalStateException");
        }
        catch (IllegalArgumentException ignored) {
        }
        try {
            createBroadcastBuffer(createInitialEmptyOutputBuffers(BROADCAST), new DataSize(0, BYTE));
            fail("Expected IllegalStateException");
        }
        catch (IllegalArgumentException ignored) {
        }
    }

    @Test
    public void testSimple()
    {
        OutputBuffers outputBuffers = createInitialEmptyOutputBuffers(BROADCAST);
        BroadcastOutputBuffer buffer = createBroadcastBuffer(outputBuffers, sizeOfPages(10));

        // add three items
        for (int i = 0; i < 3; i++) {
            addPage(buffer, createPage(i));
        }

        outputBuffers = createInitialEmptyOutputBuffers(BROADCAST).withBuffer(FIRST, BROADCAST_PARTITION_ID);

        // add a queue
        buffer.setOutputBuffers(outputBuffers);
        assertQueueState(buffer, FIRST, 3, 0);

        // get the three elements
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 0, sizeOfPages(10), NO_WAIT), bufferResult(0, createPage(0), createPage(1), createPage(2)));
        // pages not acknowledged yet so state is the same
        assertQueueState(buffer, FIRST, 3, 0);

        // acknowledge first three pages
        buffer.get(FIRST, 3, sizeOfPages(10)).cancel(true);
        // pages now acknowledged
        assertQueueState(buffer, FIRST, 0, 3);

        // fill the buffer (we already added 3 pages)
        for (int i = 3; i < 10; i++) {
            addPage(buffer, createPage(i));
        }
        assertQueueState(buffer, FIRST, 7, 3);

        // try to add one more page, which should block
        ListenableFuture<?> future = enqueuePage(buffer, createPage(10));
        assertFalse(future.isDone());
        assertQueueState(buffer, FIRST, 8, 3);

        // remove a page
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 3, sizeOfPages(1), NO_WAIT), bufferResult(3, createPage(3)));
        // page not acknowledged yet so sent count is the same
        assertQueueState(buffer, FIRST, 8, 3);

        // we should still be blocked
        assertFalse(future.isDone());

        //
        // add another buffer and verify it sees all pages
        outputBuffers = outputBuffers.withBuffer(SECOND, BROADCAST_PARTITION_ID);
        buffer.setOutputBuffers(outputBuffers);
        assertQueueState(buffer, SECOND, 11, 0);
        assertBufferResultEquals(TYPES, getBufferResult(buffer, SECOND, 0, sizeOfPages(10), NO_WAIT), bufferResult(0, createPage(0),
                createPage(1),
                createPage(2),
                createPage(3),
                createPage(4),
                createPage(5),
                createPage(6),
                createPage(7),
                createPage(8),
                createPage(9)));
        // page not acknowledged yet so sent count is still zero
        assertQueueState(buffer, SECOND, 11, 0);
        // acknowledge the 10 pages
        buffer.get(SECOND, 10, sizeOfPages(10)).cancel(true);
        assertQueueState(buffer, SECOND, 1, 10);

        //
        // tell shared buffer there will be no more queues
        outputBuffers = outputBuffers.withNoMoreBufferIds();
        buffer.setOutputBuffers(outputBuffers);

        // queues consumed the first three pages, so they should be dropped now and the blocked page future from above should be done
        assertQueueState(buffer, FIRST, 8, 3);
        assertQueueState(buffer, SECOND, 1, 10);
        assertFutureIsDone(future);

        // we should be able to add 3 more pages (the third will be queued)
        // although the first queue fetched the 4th page, the page has not been acknowledged yet
        addPage(buffer, createPage(11));
        addPage(buffer, createPage(12));
        future = enqueuePage(buffer, createPage(13));
        assertFalse(future.isDone());
        assertQueueState(buffer, FIRST, 11, 3);
        assertQueueState(buffer, SECOND, 4, 10);

        // acknowledge the receipt of the 3rd page and try to remove the 4th page from the first queue
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 4, sizeOfPages(1), NO_WAIT), bufferResult(4, createPage(4)));

        // the blocked page future above should be done
        assertFutureIsDone(future);
        assertQueueState(buffer, FIRST, 10, 4);
        assertQueueState(buffer, SECOND, 4, 10);

        //
        // finish the buffer
        assertFalse(buffer.isFinished());
        buffer.setNoMorePages();
        assertQueueState(buffer, FIRST, 10, 4);
        assertQueueState(buffer, SECOND, 4, 10);

        // not fully finished until all pages are consumed
        assertFalse(buffer.isFinished());

        // remove a page, not finished
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 5, sizeOfPages(1), NO_WAIT), bufferResult(5, createPage(5)));
        assertQueueState(buffer, FIRST, 9, 5);
        assertQueueState(buffer, SECOND, 4, 10);
        assertFalse(buffer.isFinished());

        // remove all remaining pages from first queue, should not be finished
        BufferResult x = getBufferResult(buffer, FIRST, 6, sizeOfPages(10), NO_WAIT);
        assertBufferResultEquals(TYPES, x, bufferResult(6, createPage(6),
                createPage(7),
                createPage(8),
                createPage(9),
                createPage(10),
                createPage(11),
                createPage(12),
                createPage(13)));
        assertQueueState(buffer, FIRST, 8, 6);
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 14, sizeOfPages(10), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 14, true));

        // finish first queue
        buffer.abort(FIRST);
        assertQueueClosed(buffer, FIRST, 14);
        assertQueueState(buffer, SECOND, 4, 10);
        assertFalse(buffer.isFinished());

        // remove all remaining pages from second queue, should be finished
        assertBufferResultEquals(TYPES, getBufferResult(buffer, SECOND, 10, sizeOfPages(10), NO_WAIT), bufferResult(10, createPage(10),
                createPage(11),
                createPage(12),
                createPage(13)));
        assertQueueState(buffer, SECOND, 4, 10);
        assertBufferResultEquals(TYPES, getBufferResult(buffer, SECOND, 14, sizeOfPages(10), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 14, true));
        buffer.abort(SECOND);
        assertQueueClosed(buffer, FIRST, 14);
        assertQueueClosed(buffer, SECOND, 14);
        assertFinished(buffer);

        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 14, sizeOfPages(10), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 14, true));
        assertBufferResultEquals(TYPES, getBufferResult(buffer, SECOND, 14, sizeOfPages(10), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 14, true));
    }

    @Test
    public void testSharedBufferFull()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(createInitialEmptyOutputBuffers(BROADCAST), sizeOfPages(2));

        // Add two pages, buffer is full
        addPage(buffer, createPage(1));
        addPage(buffer, createPage(2));

        // third page is blocked
        enqueuePage(buffer, createPage(3));
    }

    @Test
    public void testDuplicateRequests()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(10));

        // add three items
        for (int i = 0; i < 3; i++) {
            addPage(buffer, createPage(i));
        }

        // add a queue
        assertQueueState(buffer, FIRST, 3, 0);

        // get the three elements
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 0, sizeOfPages(10), NO_WAIT), bufferResult(0, createPage(0), createPage(1), createPage(2)));
        // pages not acknowledged yet so state is the same
        assertQueueState(buffer, FIRST, 3, 0);

        // get the three elements again
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 0, sizeOfPages(10), NO_WAIT), bufferResult(0, createPage(0), createPage(1), createPage(2)));
        // pages not acknowledged yet so state is the same
        assertQueueState(buffer, FIRST, 3, 0);

        // acknowledge the pages
        buffer.get(FIRST, 3, sizeOfPages(10)).cancel(true);

        // attempt to get the three elements again
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 0, sizeOfPages(10), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 0, false));
        // pages not acknowledged yet so state is the same
        assertQueueState(buffer, FIRST, 0, 3);
    }

    @Test
    public void testAddQueueAfterCreation()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(10));

        assertFalse(buffer.isFinished());

        try {
            buffer.setOutputBuffers(createInitialEmptyOutputBuffers(BROADCAST)
                    .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                    .withBuffer(SECOND, BROADCAST_PARTITION_ID)
                    .withNoMoreBufferIds());
            fail("Expected IllegalStateException from addQueue after noMoreQueues has been called");
        }
        catch (IllegalArgumentException ignored) {
        }
    }

    @Test
    public void testAddAfterFinish()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(10));
        buffer.setNoMorePages();
        addPage(buffer, createPage(0));
        addPage(buffer, createPage(0));
        assertEquals(buffer.getInfo().getTotalPagesSent(), 0);
    }

    @Test
    public void testAddQueueAfterNoMoreQueues()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(createInitialEmptyOutputBuffers(BROADCAST), sizeOfPages(10));
        assertFalse(buffer.isFinished());

        // tell buffer no more queues will be added
        buffer.setOutputBuffers(createInitialEmptyOutputBuffers(BROADCAST).withNoMoreBufferIds());
        assertFalse(buffer.isFinished());

        // set no more queues a second time to assure that we don't get an exception or such
        buffer.setOutputBuffers(createInitialEmptyOutputBuffers(BROADCAST).withNoMoreBufferIds());
        assertFalse(buffer.isFinished());

        // set no more queues a third time to assure that we don't get an exception or such
        buffer.setOutputBuffers(createInitialEmptyOutputBuffers(BROADCAST).withNoMoreBufferIds());
        assertFalse(buffer.isFinished());

        try {
            OutputBuffers outputBuffers = createInitialEmptyOutputBuffers(BROADCAST)
                    .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                    .withNoMoreBufferIds();

            buffer.setOutputBuffers(outputBuffers);
            fail("Expected IllegalStateException from addQueue after noMoreQueues has been called");
        }
        catch (IllegalArgumentException ignored) {
        }
    }

    @Test
    public void testAddAfterDestroy()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(10));
        buffer.destroy();
        addPage(buffer, createPage(0));
        addPage(buffer, createPage(0));
        assertEquals(buffer.getInfo().getTotalPagesSent(), 0);
    }

    @Test
    public void testGetBeforeCreate()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(createInitialEmptyOutputBuffers(BROADCAST), sizeOfPages(10));
        assertFalse(buffer.isFinished());

        // get a page from a buffer that doesn't exist yet
        ListenableFuture<BufferResult> future = buffer.get(FIRST, 0L, sizeOfPages(1));
        assertFalse(future.isDone());

        // add a page and verify the future is complete
        addPage(buffer, createPage(33));
        assertTrue(future.isDone());
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), bufferResult(0, createPage(33)));
    }

    @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = ".*does not contain.*\\[0]")
    public void testSetFinalBuffersWihtoutDeclaringUsedBuffer()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(createInitialEmptyOutputBuffers(BROADCAST), sizeOfPages(10));
        assertFalse(buffer.isFinished());

        // get a page from a buffer that doesn't exist yet
        ListenableFuture<BufferResult> future = buffer.get(FIRST, 0L, sizeOfPages(1));
        assertFalse(future.isDone());

        // add a page and set no more pages
        addPage(buffer, createPage(33));
        buffer.setNoMorePages();

        // read the page
        assertTrue(future.isDone());
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), bufferResult(0, createPage(33)));

        // acknowledge the page and verify we are finished
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 1, sizeOfPages(10), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 1, true));
        buffer.abort(FIRST);

        // set final buffers to a set that does not contain the buffer, which will fail
        buffer.setOutputBuffers(createInitialEmptyOutputBuffers(BROADCAST).withNoMoreBufferIds());
    }

    @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "No more buffers already set")
    public void testUseUndeclaredBufferAfterFinalBuffersSet()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(10));
        assertFalse(buffer.isFinished());

        // get a page from a buffer that was not declared, which will fail
        buffer.get(SECOND, 0L, sizeOfPages(1));
    }

    @Test
    public void testAbortBeforeCreate()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(createInitialEmptyOutputBuffers(BROADCAST), sizeOfPages(2));
        assertFalse(buffer.isFinished());

        // get a page from a buffer that doesn't exist yet
        ListenableFuture<BufferResult> future = buffer.get(FIRST, 0, sizeOfPages(1));
        assertFalse(future.isDone());

        // abort that buffer, and verify the future is complete and buffer is finished
        buffer.abort(FIRST);
        assertTrue(future.isDone());
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 0, sizeOfPages(10), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 0, true));
    }

    @Test
    public void testFullBufferBlocksWriter()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withBuffer(SECOND, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(2));

        // Add two pages, buffer is full
        addPage(buffer, createPage(1));
        addPage(buffer, createPage(2));

        // third page is blocked
        enqueuePage(buffer, createPage(3));
    }

    @Test
    public void testAcknowledgementFreesWriters()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withBuffer(SECOND, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(2));

        // Add two pages, buffer is full
        addPage(buffer, createPage(1));
        addPage(buffer, createPage(2));
        assertQueueState(buffer, FIRST, 2, 0);

        // third page is blocked
        ListenableFuture<?> future = enqueuePage(buffer, createPage(3));

        // we should be blocked
        assertFalse(future.isDone());
        assertQueueState(buffer, FIRST, 3, 0);
        assertQueueState(buffer, SECOND, 3, 0);

        // acknowledge pages for first buffer, no space is freed
        buffer.get(FIRST, 2, sizeOfPages(10)).cancel(true);
        assertFalse(future.isDone());

        // acknowledge pages for second buffer, which makes space in the buffer
        buffer.get(SECOND, 2, sizeOfPages(10)).cancel(true);

        // writer should not be blocked
        assertFutureIsDone(future);
        assertQueueState(buffer, SECOND, 1, 2);
    }

    @Test
    public void testAbort()
    {
        BroadcastOutputBuffer bufferedBuffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withBuffer(SECOND, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(10));

        // fill the buffer
        for (int i = 0; i < 10; i++) {
            addPage(bufferedBuffer, createPage(i));
        }
        bufferedBuffer.setNoMorePages();

        assertBufferResultEquals(TYPES, getBufferResult(bufferedBuffer, FIRST, 0, sizeOfPages(1), NO_WAIT), bufferResult(0, createPage(0)));
        bufferedBuffer.abort(FIRST);
        assertQueueClosed(bufferedBuffer, FIRST, 0);
        assertBufferResultEquals(TYPES, getBufferResult(bufferedBuffer, FIRST, 1, sizeOfPages(1), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 0, true));

        assertBufferResultEquals(TYPES, getBufferResult(bufferedBuffer, SECOND, 0, sizeOfPages(1), NO_WAIT), bufferResult(0, createPage(0)));
        bufferedBuffer.abort(SECOND);
        assertQueueClosed(bufferedBuffer, SECOND, 0);
        assertFinished(bufferedBuffer);
        assertBufferResultEquals(TYPES, getBufferResult(bufferedBuffer, SECOND, 1, sizeOfPages(1), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 0, true));
    }

    @Test
    public void testFinishClosesEmptyQueues()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withBuffer(SECOND, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(10));

        // finish while queues are empty
        buffer.setNoMorePages();

        assertQueueState(buffer, FIRST, 0, 0);
        assertQueueState(buffer, SECOND, 0, 0);

        buffer.abort(FIRST);
        buffer.abort(SECOND);

        assertQueueClosed(buffer, FIRST, 0);
        assertQueueClosed(buffer, SECOND, 0);
    }

    @Test
    public void testAbortFreesReader()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withBuffer(SECOND, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(5));
        assertFalse(buffer.isFinished());

        // attempt to get a page
        ListenableFuture<BufferResult> future = buffer.get(FIRST, 0, sizeOfPages(10));

        // verify we are waiting for a page
        assertFalse(future.isDone());

        // add one item
        addPage(buffer, createPage(0));
        assertTrue(future.isDone());

        // verify we got one page
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), bufferResult(0, createPage(0)));

        // attempt to get another page, and verify we are blocked
        future = buffer.get(FIRST, 1, sizeOfPages(10));
        assertFalse(future.isDone());

        // abort the buffer
        buffer.abort(FIRST);

        // verify the future completed
        // broadcast buffer does not return a "complete" result in this case, but it doesn't mapper
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), emptyResults(TASK_INSTANCE_ID, 1, false));

        // further requests will see a completed result
        assertQueueClosed(buffer, FIRST, 1);
    }

    @Test
    public void testFinishFreesReader()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(5));
        assertFalse(buffer.isFinished());

        // attempt to get a page
        ListenableFuture<BufferResult> future = buffer.get(FIRST, 0, sizeOfPages(10));

        // verify we are waiting for a page
        assertFalse(future.isDone());

        // add one item
        addPage(buffer, createPage(0));

        // verify we got one page
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), bufferResult(0, createPage(0)));

        // attempt to get another page, and verify we are blocked
        future = buffer.get(FIRST, 1, sizeOfPages(10));
        assertFalse(future.isDone());

        // finish the buffer
        buffer.setNoMorePages();
        assertQueueState(buffer, FIRST, 0, 1);

        // verify the future completed
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), emptyResults(TASK_INSTANCE_ID, 1, true));
    }

    @Test
    public void testFinishFreesWriter()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(5));
        assertFalse(buffer.isFinished());

        // fill the buffer
        for (int i = 0; i < 5; i++) {
            addPage(buffer, createPage(i));
        }

        // enqueue the addition two pages more pages
        ListenableFuture<?> firstEnqueuePage = enqueuePage(buffer, createPage(5));
        ListenableFuture<?> secondEnqueuePage = enqueuePage(buffer, createPage(6));

        // get and acknowledge one page
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 0, sizeOfPages(1), MAX_WAIT), bufferResult(0, createPage(0)));
        buffer.get(FIRST, 1, sizeOfPages(1)).cancel(true);

        // verify we are still blocked because the buffer is full
        assertFalse(firstEnqueuePage.isDone());
        assertFalse(secondEnqueuePage.isDone());

        // finish the query
        buffer.setNoMorePages();
        assertFalse(buffer.isFinished());

        // verify futures are complete
        assertFutureIsDone(firstEnqueuePage);
        assertFutureIsDone(secondEnqueuePage);

        // get and acknowledge the last 6 pages
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 1, sizeOfPages(100), NO_WAIT),
                bufferResult(1, createPage(1), createPage(2), createPage(3), createPage(4), createPage(5), createPage(6)));
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 7, sizeOfPages(100), NO_WAIT), emptyResults(TASK_INSTANCE_ID, 7, true));

        buffer.abort(FIRST);

        // verify finished
        assertFinished(buffer);
    }

    @Test
    public void testDestroyFreesReader()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(5));
        assertFalse(buffer.isFinished());

        // attempt to get a page
        ListenableFuture<BufferResult> future = buffer.get(FIRST, 0, sizeOfPages(10));

        // verify we are waiting for a page
        assertFalse(future.isDone());

        // add one page
        addPage(buffer, createPage(0));

        // verify we got one page
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), bufferResult(0, createPage(0)));

        // attempt to get another page, and verify we are blocked
        future = buffer.get(FIRST, 1, sizeOfPages(10));
        assertFalse(future.isDone());

        // destroy the buffer
        buffer.destroy();
        assertQueueClosed(buffer, FIRST, 1);

        // verify the future completed
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), emptyResults(TASK_INSTANCE_ID, 1, false));
    }

    @Test
    public void testDestroyFreesWriter()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(5));
        assertFalse(buffer.isFinished());

        // fill the buffer
        for (int i = 0; i < 5; i++) {
            addPage(buffer, createPage(i));
        }

        // add two pages to the buffer queue
        ListenableFuture<?> firstEnqueuePage = enqueuePage(buffer, createPage(5));
        ListenableFuture<?> secondEnqueuePage = enqueuePage(buffer, createPage(6));

        // get and acknowledge one page
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 0, sizeOfPages(1), MAX_WAIT), bufferResult(0, createPage(0)));
        buffer.get(FIRST, 1, sizeOfPages(1)).cancel(true);

        // verify we are still blocked because the buffer is full
        assertFalse(firstEnqueuePage.isDone());
        assertFalse(secondEnqueuePage.isDone());

        // destroy the buffer (i.e., cancel the query)
        buffer.destroy();
        assertFinished(buffer);

        // verify the futures are completed
        assertFutureIsDone(firstEnqueuePage);
        assertFutureIsDone(secondEnqueuePage);
    }

    @Test
    public void testFailDoesNotFreeReader()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(5));
        assertFalse(buffer.isFinished());

        // attempt to get a page
        ListenableFuture<BufferResult> future = buffer.get(FIRST, 0, sizeOfPages(10));

        // verify we are waiting for a page
        assertFalse(future.isDone());

        // add one page
        addPage(buffer, createPage(0));

        // verify we got one page
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), bufferResult(0, createPage(0)));

        // attempt to get another page, and verify we are blocked
        future = buffer.get(FIRST, 1, sizeOfPages(10));
        assertFalse(future.isDone());

        // fail the buffer
        buffer.fail();

        // future should have not finished
        assertFalse(future.isDone());

        // attempt to get another page, and verify we are blocked
        future = buffer.get(FIRST, 1, sizeOfPages(10));
        assertFalse(future.isDone());
    }

    @Test
    public void testFailFreesWriter()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(5));
        assertFalse(buffer.isFinished());

        // fill the buffer
        for (int i = 0; i < 5; i++) {
            addPage(buffer, createPage(i));
        }

        // add two pages to the buffer queue
        ListenableFuture<?> firstEnqueuePage = enqueuePage(buffer, createPage(5));
        ListenableFuture<?> secondEnqueuePage = enqueuePage(buffer, createPage(6));

        // get and acknowledge one page
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 0, sizeOfPages(1), MAX_WAIT), bufferResult(0, createPage(0)));
        buffer.get(FIRST, 1, sizeOfPages(1)).cancel(true);

        // verify we are still blocked because the buffer is full
        assertFalse(firstEnqueuePage.isDone());
        assertFalse(secondEnqueuePage.isDone());

        // fail the buffer (i.e., cancel the query)
        buffer.fail();
        assertFalse(buffer.isFinished());

        // verify the futures are completed
        assertFutureIsDone(firstEnqueuePage);
        assertFutureIsDone(secondEnqueuePage);
    }

    @Test
    public void testAddBufferAfterFail()
    {
        OutputBuffers outputBuffers = createInitialEmptyOutputBuffers(BROADCAST)
                .withBuffer(FIRST, BROADCAST_PARTITION_ID);
        BroadcastOutputBuffer buffer = createBroadcastBuffer(outputBuffers, sizeOfPages(5));
        assertFalse(buffer.isFinished());

        // attempt to get a page
        ListenableFuture<BufferResult> future = buffer.get(FIRST, 0, sizeOfPages(10));

        // verify we are waiting for a page
        assertFalse(future.isDone());

        // add one page
        addPage(buffer, createPage(0));

        // verify we got one page
        assertBufferResultEquals(TYPES, getFuture(future, NO_WAIT), bufferResult(0, createPage(0)));

        // fail the buffer
        buffer.fail();

        // add a buffer
        outputBuffers = outputBuffers.withBuffer(SECOND, BROADCAST_PARTITION_ID);
        buffer.setOutputBuffers(outputBuffers);

        // attempt to get page, and verify we are blocked
        future = buffer.get(FIRST, 1, sizeOfPages(10));
        assertFalse(future.isDone());
        future = buffer.get(SECOND, 0, sizeOfPages(10));
        assertFalse(future.isDone());

        // set no more buffers
        outputBuffers = outputBuffers.withNoMoreBufferIds();
        buffer.setOutputBuffers(outputBuffers);

        // attempt to get page, and verify we are blocked
        future = buffer.get(FIRST, 1, sizeOfPages(10));
        assertFalse(future.isDone());
        future = buffer.get(SECOND, 0, sizeOfPages(10));
        assertFalse(future.isDone());
    }

    @Test
    public void testBufferCompletion()
    {
        BroadcastOutputBuffer buffer = createBroadcastBuffer(
                createInitialEmptyOutputBuffers(BROADCAST)
                        .withBuffer(FIRST, BROADCAST_PARTITION_ID)
                        .withNoMoreBufferIds(),
                sizeOfPages(5));

        assertFalse(buffer.isFinished());

        // fill the buffer
        List<Page> pages = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Page page = createPage(i);
            addPage(buffer, page);
            pages.add(page);
        }

        buffer.setNoMorePages();

        // get and acknowledge 5 pages
        assertBufferResultEquals(TYPES, getBufferResult(buffer, FIRST, 0, sizeOfPages(5), MAX_WAIT), bufferResult(0, pages));

        // buffer is not finished
        assertFalse(buffer.isFinished());

        // there are no more pages and no more buffers, but buffer is not finished because it didn't receive an acknowledgement yet
        assertFalse(buffer.isFinished());

        // ask the buffer to finish
        buffer.abort(FIRST);

        // verify that the buffer is finished
        assertTrue(buffer.isFinished());
    }

    public static BufferResult getBufferResult(BroadcastOutputBuffer buffer, OutputBufferId bufferId, long sequenceId, DataSize maxSize, Duration maxWait)
    {
        ListenableFuture<BufferResult> future = buffer.get(bufferId, sequenceId, maxSize);
        return getFuture(future, maxWait);
    }

    private static ListenableFuture<?> enqueuePage(BroadcastOutputBuffer buffer, Page page)
    {
        ListenableFuture<?> future = buffer.enqueue(ImmutableList.of(PAGES_SERDE.serialize(page)));
        assertFalse(future.isDone());
        return future;
    }

    private static void addPage(BroadcastOutputBuffer buffer, Page page)
    {
        assertTrue(buffer.enqueue(ImmutableList.of(PAGES_SERDE.serialize(page))).isDone(), "Expected add page to not block");
    }

    private static void assertQueueState(
            BroadcastOutputBuffer buffer,
            OutputBufferId bufferId,
            int bufferedPages,
            int pagesSent)
    {
        assertEquals(
                getBufferInfo(buffer, bufferId),
                new BufferInfo(
                        bufferId,
                        false,
                        bufferedPages,
                        pagesSent,
                        new PageBufferInfo(
                                bufferId.getId(),
                                bufferedPages,
                                sizeOfPages(bufferedPages).toBytes(),
                                bufferedPages + pagesSent, // every page has one row
                                bufferedPages + pagesSent)));
    }

    @SuppressWarnings("ConstantConditions")
    private static void assertQueueClosed(BroadcastOutputBuffer buffer, OutputBufferId bufferId, int pagesSent)
    {
        BufferInfo bufferInfo = getBufferInfo(buffer, bufferId);
        assertEquals(bufferInfo.getBufferedPages(), 0);
        assertEquals(bufferInfo.getPagesSent(), pagesSent);
        assertTrue(bufferInfo.isFinished());
    }

    private BroadcastOutputBuffer createBroadcastBuffer(OutputBuffers outputBuffers, DataSize dataSize)
    {
        BroadcastOutputBuffer buffer = new BroadcastOutputBuffer(
                TASK_INSTANCE_ID,
                new StateMachine<>("bufferState", stateNotificationExecutor, OPEN, TERMINAL_BUFFER_STATES),
                dataSize,
                () -> new SimpleLocalMemoryContext(newSimpleAggregatedMemoryContext()),
                stateNotificationExecutor);
        buffer.setOutputBuffers(outputBuffers);
        return buffer;
    }

    private static BufferInfo getBufferInfo(BroadcastOutputBuffer buffer, OutputBufferId bufferId)
    {
        for (BufferInfo bufferInfo : buffer.getInfo().getBuffers()) {
            if (bufferInfo.getBufferId().equals(bufferId)) {
                return bufferInfo;
            }
        }
        return null;
    }

    private static void assertFinished(BroadcastOutputBuffer buffer)
    {
        assertTrue(buffer.isFinished());
        for (BufferInfo bufferInfo : buffer.getInfo().getBuffers()) {
            assertTrue(bufferInfo.isFinished());
            assertEquals(bufferInfo.getBufferedPages(), 0);
        }
    }

    private static void assertFutureIsDone(Future<?> future)
    {
        tryGetFutureValue(future, 5, SECONDS);
        assertTrue(future.isDone());
    }

    public static BufferResult bufferResult(long token, Page firstPage, Page... otherPages)
    {
        List<Page> pages = ImmutableList.<Page>builder().add(firstPage).add(otherPages).build();
        return bufferResult(token, pages);
    }

    public static BufferResult bufferResult(long token, List<Page> pages)
    {
        checkArgument(!pages.isEmpty(), "pages is empty");
        return new BufferResult(
                TASK_INSTANCE_ID,
                token,
                token + pages.size(),
                false,
                pages.stream()
                        .map(PAGES_SERDE::serialize)
                        .collect(Collectors.toList()));
    }

    private static Page createPage(int i)
    {
        return new Page(BlockAssertions.createLongsBlock(i));
    }

    public static DataSize sizeOfPages(int count)
    {
        return new DataSize(BUFFERED_PAGE_SIZE.toBytes() * count, BYTE);
    }
}

redpajama_set_name: RedPajamaGithub


"Primary mechanical damage to spinal cord tissue kills a certain amount of neuronal cells. But there's secondary damage due to the release of excess glutamates, which are responsible for additional functional disability," Dr. Goldshmit says. "The main idea is to reduce the secondary damage as soon as possible -- to block the body's natural reaction to spinal cord trauma. This is the role of the enzyme injection we devised."


text:
A North Korean defector flees to freedom under a barrage of gunfire
Warning: Some viewers might find the above video disturbing.
It's the stuff of action movie climaxes, but IRL.
A new video captured by the United Nations Command depicts a North Korean soldier defecting by crossing the "Joint Security Area" (JSA) of the Korean Demilitarized Zone (DMZ). The gunfire that the escape attempt drew is a violation of the truce between North and South Korea, the first such violation since a similar escape attempt in 1984.
In the video, the former soldier flees by military jeep. But when he gets stuck in a ditch right on the border, the soldier — whose last name is Oh, according to Stars and Stripes — sprints from the driver's seat and attempts to run. His former fellow soldiers rain bullets on him, and he gets shot multiple times. South Korean soldiers eventually crawl through the JSA and drag him to safety. Read more...
More about Video, South Korea, North Korea, Defects, and Dmz
http://ift.tt/2B46lSa
Labels: A North Korean defector flees to freedom under a barrage of gunfire

redpajama_set_name: RedPajamaCommonCrawl


Take up to 20% off on antique and furniture at the Whispering Raven Clearance Sale.
Find great deals on books at the Scholastic Book Fairs Holiday Warehouse Sale.
Find great deals on collectibles, handbags, store fixtures, rugs, home accessories, and furniture at Angela Adams Warehouse Sale.
is bringing the featuring gift items and stationery at reduced prices.


text:
Fredrikson & Byron Hires Seven New Associates
Fredrikson & Byron announces the addition of seven associates to the firm's Minneapolis office.
Lukas S. Boehning is an associate in the Employment & Labor Group. Boehning represents clients in employment, labor and business litigation. He gained experience working with Fredrikson & Byron as a summer associate. Boehning earned his J.D. from Mitchell Hamline School of Law, where he was a legal extern for the Minnesota ACLU. He was also an editor of the Mitchell Hamline Law Review, during which he organized an event for the legal community on the challenges facing at-risk children of Minnesota. While attending law school, Boehning worked full-time in education advocacy and policy to improve education laws around the country.
Tash S. Bottum is an associate in the Mergers & Acquisitions Group. Bottum's practice focuses on assisting clients with mergers, acquisitions and general corporate needs. She helps businesses with a variety of matters, including business combination, business and general counsel services, and corporate governance. Bottum attended the University of Minnesota Law School, where she graduated summa cum laude. During law school, she served as a law clerk at an agricultural Fortune 500 cooperative and externed with the honorable Magistrate Judge Hildy Bowbeer.
Olivia E. Cares is an associate in the Energy Group. Cares works with clients in the renewable energy industry on their regulatory and commercial law matters. Her practice focuses on commercial transactions related to the energy industry, project finance and mergers and acquisitions. Cares received her law degree from the University of Michigan Law School, where she was a student researcher for the Environmental Crimes Project and co-chaired the Environmental Law Society. She has also served as a legal intern in the Office of the Solicitor for the Intermountain Region for the U.S. Department of the Interior in Salt Lake City, Utah.
Rachel Leitschuck Dougherty is an associate in the Litigation Group. Dougherty is a problem solver who uses her experience working for Minnesota judges to help her clients win cases. Dougherty represents clients involved in a wide range of business disputes. She is committed to using her written and oral advocacy skills to meet her clients' goals in every stage of their cases. Before joining Fredrikson, Dougherty worked as a judicial clerk to the Honorable Chief Justice Lorie S. Gildea of the Minnesota Supreme Court and as a judicial extern to the Honorable Kate M. Menendez in the United States District Court of Minnesota. She also represented clients in the University of Minnesota's Insurance Law Clinic as a certified student attorney and served as a law clerk in the Hennepin County Attorney's Office.
Erin M. Edgerton is an associate in the Employment & Labor Group. Edgerton provides clients with legal guidance for navigating employment and labor laws. Her employment and labor practice focuses on advising employers on a variety of day-to-day employment and business matters. She represents clients during everyday disputes both in and out of the court room. Edgerton also prepares and reviews a variety of employment agreement policies, including separation agreements, employee handbooks and non-competition and confidentiality agreements.
Jacob D. Levine is an associate in the Mergers & Acquisitions Group. Jake is a corporate attorney who represents private and public companies in all types of business transactions. Prior to joining Fredrikson & Byron, Jake served as a judicial intern to Chief Justice Shirley S. Abrahamson of the Wisconsin Supreme Court. He also worked as a student attorney for the Law & Entrepreneurship Clinic in Madison, Wisconsin. In that role, he provided transactional services for a variety of early-stage entrepreneurs and startup companies as well as drafted contracts for operating agreements, service agreements, terms of use and privacy policies.
Charles J. Urena is an associate in the Energy Group. Urena assists utilities, transmission and independent power producers with energy law matters. Urena assists clients in the energy industry on regulatory and energy law matters. He is part of a team advising utilities, independent power producers and transmission companies on siting, routing, permitting and other regulatory matters before the Minnesota Public Utilities Commission and other federal, state and local agencies. Prior to joining Fredrikson, Urena clerked in the Appellate Practice Group of a Madison, Wisconsin, law firm, interned for Chief Justice Shirley Abrahamson of the Wisconsin Supreme Court and provided research assistance to a professor focusing on administrative and constitutional law.
Fredrikson & Byron is a 300-attorney law firm based in Minneapolis, with offices in Bismarck, Des Moines, Fargo, Mankato, St. Paul, Saltillo, Mexico, and Shanghai, China. Fredrikson & Byron has a reputation as the firm "where law and business meet." Our attorneys bring business acumen and entrepreneurial thinking to work with clients, and operate as business advisors and strategic partners, as well as legal counselors. More information about the firm is available at www.fredlaw.com. Follow us on LinkedIn and on Twitter @FredriksonLaw.
Lukas Boehning
lboehning@fredlaw.com
Tash Bottum
tbottum@fredlaw.com
Olivia Cares
ocares@fredlaw.com
Rachel Dougherty
rdougherty@fredlaw.com
Erin Edgerton Hall, AWI-CH
eedgertonhall@fredlaw.com
Jacob Levine
jlevine@fredlaw.com


text:
Punch Historical Archive 1841-1992
Various source media, Punch Historical Archive 1841-1992
JOAN BAKEWELL
LESLIE GILBERT ILLINGWORTH
MAY KENDALL
JOHN TENNIEL
A cultural figurehead in the 1960s and one of the longest-surviving female interviewers on British television, Joan Bakewell (1933-) has earned her place in the history of the UK medium. Following Cambridge, she started with the BBC as a trainee studio manager for radio and moved to television in the early 1960s. Making her first appearance on the arts discussion/review series Late Night Line-Up (BBC, 1964-72) in early 1965, she soon became the programme's leading lady, as presenter and interviewer, and remained a fixture for six years. She was appointed arts correspondent for the BBC in 1982, returning her to more 'serious' pursuits, until the John Birt (1944-) revolution in the late 1980s, which removed the arts from under the news and current affairs umbrella. Switching from arts to morals, she presented the religious debate series Heart of the Matter (BBC, 1979-2000) for 12 years. She was awarded a CBE in 1999 and DBE in 2008; also held the post of BFI Chair, 1999-2002. (Adapted from: http://www.screenonline.org.uk/people/id/1359918/index.html).
Bakewell, Joan. "Why Can't a Woman . . ." Punch, 20 June 1973
Bakewell, Joan, and Jack Emery. "Australia, His and Hers . . ." Punch, 5 June 1974
Bakewell, Joan. "Daughters of the Revolution." Punch, 12 Feb. 1975
Bakewell, Joan. "Winter Olympics." Punch, 20 Jan. 1982
John Betjeman (1906-1984) is a unique figure in 20th century English poetry, enjoying a degree of fame and success unequaled by any poet since Byron. His Collected Poems of 1958 reputedly sold more than 100,000 copies, and they are read by millions of people who normally never read poetry, while he has become a household name through his many appearances on television panels and on programs about architecture. He is also quintessentially English, a pillar of the so-called establishment and he has, during a long and diverse career, accumulated several honorary doctorates, a CBE, and a knighthood before being created the Poet Laureate in 1972. Despite such public recognition (or perhaps partly because of it) Betjeman's stature as a poet has remained singularly hard to assess. Some critics have always maintained that he is a poet of mediocre talents, a competent versifier whose adroit exploitation of the television medium in its early years enabled him to carve out for himself a reputation he does not deserve. (Adapted from: Clarke, John. "John Betjeman." British Poets, 1914-1945, edited by Donald E. Stanford, Gale, 1983).
Betjeman, John. "The Metropolitan Railway." Punch, 28 Jan. 1953
Betjeman, John. "The Fabric of our Faith." Punch, 23 Dec. 1953
Betjeman, John. "The Lecture." Punch, 17 Mar. 1954
Betjeman, John. "Imaginary Conversations." Punch, 7 July 1954
Three-time winner of the Hans Christian Andersen Award for illustration, the "Nobel" of such prizes, British author-illustrator Quentin Blake (1932-) is regarded by many critics as a master artist whose line drawings and watercolors are touched with genius. Blake has written and illustrated numerous well-received books for children and has provided the pictures for over two hundred titles by other authors for children and adults. Considered an especially inventive and adaptable illustrator, he has created a highly recognizable style--called "calligraphic"--that ranges from the childlike to the highly sophisticated. Blake studied for three years at Cambridge, where he drew for their undergraduate magazines as well as for Punch. Becoming a freelance artist, Blake was hired to do a drawing a week for Punch and also began working for the literary magazine Spectator. (Adapted from: "Quentin (Saxby) Blake." Major Authors and Illustrators for Children and Young Adults, Gale, 2002).
Blake, Quentin. "Educational Visits." Punch, 15 Sept. 1965
Blake, Quentin. "Punch." Punch, 12 Apr. 1967
Blake, Quentin. "And what's more, m'lud, we have reason to believe the jury has been interfered with." Punch, 30 Aug. 1967
Blake, Quentin. "Punch." Punch, 3 Apr. 1968
Penelope Fitzgerald (1916-2000) published her first novel when she was fifty-nine years old. Some two decades and a Booker Prize later, she had established a reputation as an ironic, spare, and richly comic author. Even when the settings for her novels range as far afield as Florence, pre-revolutionary Moscow, and Germany in the 1790s, she is praised for her sense of detail and her clear observations of human nature. Some of Fitzgerald's early novels are loosely based upon her own work experiences. Born of a "writing family," she was educated at Oxford and was employed by the British Broadcasting Corporation during World War II. After her marriage in 1953, she worked as a clerk in a bookstore in rural East Suffolk; later she and her family lived on a barge on the Thames. (Adapted from: "Penelope Fitzgerald." Contemporary Authors Online, Gale, 2004).
Fitzgerald, Penelope. "At the Play." Punch, 5 Jan. 1944
Fitzgerald, Penelope. "At the Play." Punch, 19 Jan. 1944
W. L., and Penelope Fitzgerald. "At the Play." Punch, 16 Feb. 1944
Fitzgerald, Penelope, et al. "Our Booking-Office." Punch, 10 Oct. 1945
Leslie Illingworth (1902-1979) was born in South Wales, and in 1917 won a scholarship to study at the Cardiff Art School. A successful student, he won a gold medal for drawing and had four topical cartoons published in the college's magazine, studying in the morning and working in the lithographic departments of the Western Mail. In 1921 Illingworth won a three-year scholarship to the Slade Art School. Illingworth left the Western Mail in 1927. He moved to Paris for a year before moving to New Jersey. His first cartoon for Punch magazine was published on 27th May 1931. He shared responsibility for producing the main political cartoon for the magazine with E. H. Shepard (1979-1976) and Bernard Partridge (1861-1945). On the outbreak of the Second World War he was offered £650 a year to become an official war artist. He refused the offer and instead accepted a job with the Daily Mail, that paid £2,000 a year, where he drew four cartoons a week. Illingworth's drawings continued to appear throughout the war, despite the fact that by the end of 1940 paper rationing had reduced the newspaper to six pages. On the death of Bernard Partridge in 1945, Illingworth became the main political cartoonist on Punch magazine. On 22nd December, 1969, Illingworth published his last cartoon for the Daily Mail and retired to his smallholding in Robertsbridge, East Sussex. (Adapted from: http://spartacus-educational.com/ARTillingworth.html).
Illingworth, Leslie. "The Novice." Punch, 1 Jan. 1940
Illingworth, Leslie. "Buzz!" Punch, 20 May 1953
Illingworth, Leslie. "In Nehru-land what Avatar?" Punch, 11 Aug. 1954
Illingworth, Leslie. "United Nations Organization." Punch, 9 Dec. 1964
May Kendall (1861-1943) was a poet whose work was a vehicle for her social commentary, particularly on the subjects of science, evolution, and feminism. Kendall was born in Yorkshire, England, lived in Liverpool and Birmingham, and spent most of her life in York. In Dreams to Sell, her poems explore evolution, some of the theories of which were not particularly favorable to women, presuming that they were more associated with "mother" nature and men with things spiritual. Charles Darwin (1809-1882) challenged these roles, and women poets used his theories as a tool in their opposition to Victorian presumptions about gender. In several of the poems in this collection, Kendall portrays males who acknowledge female equality. She became affiliated with the Rountrees, a philanthropic family that supported social research. Kendall died poor, alone, but surrounded by her many cats. The Rountree family paid for her funeral, and she was buried in an unmarked grave. (Adapted from: "May Kendall." Contemporary Authors Online, Gale, 2002).
[May Kendall]. "An Astral Complication." Punch, 8 Mar. 1890
[May Kendall]. "The Original Aryan to the Professor." Punch, 23 Mar. 1895
[May Kendall]. "The Introspective Bard." Punch, 30 Mar. 1895
[May Kendall]. "The Dilemma of the Headless Spectre." Punch, 3 Nov. 1894
Sir John Tenniel (1820-1914) is remembered chiefly for his illustration of Lewis Carroll's (1832-1898) Alice's Adventures in Wonderland and Through the Looking-Glass, works that have won near universal approval from critics and from readers of all ages around the world. The Tenniel images of Alice and her friends are nearly as important to the lasting success of the works as Carroll's stories, and few subsequent illustrators of Alice's Adventures in Wonderland and Through the Looking-Glass have measured up to the master artist who came before. In his own time, though, Tenniel enjoyed more attention for his work as a political cartoonist for the magazine Punch, where more than two thousand of his cartoons were published between 1850 and his retirement in 1901. Tenniel was also a life-long artist and art lover who staged his first exhibition when he was sixteen. By the time he took the commission from Carroll he had already illustrated nearly thirty books either in whole or in part. (Adapted from: "John Tenniel." Major Authors and Illustrators for Children and Young Adults, Gale, 2002).
Tenniel, John. "Poland's Chain-Shot." Punch, 28 Mar. 1863
Tenniel, John. "The Zulu Bride." Punch, 8 Feb. 1868
Tenniel, John. "Urgency!" Punch, 12 Feb. 1881
Tenniel, John. "A Friend in Need—." Punch, 21 July 1894
William Makepeace Thackeray (1811-1863) created unrivaled panoramas of English upper-middle-class life, crowded with memorable characters displaying realistic mixtures of virtue, vanity, and vice. When William Makepeace Thackeray began his literary career, English prose fiction was dominated by Charles Dickens (1812-1870). Thackeray formed his style in conscious reaction against Dickens's programmatic indictment of social evils and against the artificial style and sentimental falsification of life and moral values of the popular historical romances. The familiar, moralizing commentaries of Thackeray's narrators, as integral a part of his novels as the characters themselves, expressed their author's detached moral disillusionment--usually touched with sentimentality. Although critical of society, Thackeray was never a radical intellectual, remaining basically conservative. As a regular contributor to the satiric magazine Punch between 1844 and 1851, Thackeray finally achieved widespread recognition. His most famous contribution was 'The Snobs of England, by One of Themselves' (1846-1847). Through a series of satiric character sketches, it made a critical survey of the manners of a period in which old standards of behavior and social relationships had been shaken by the redistribution of wealth and power effected by industrialism. (Adapted from: "William Makepeace Thackeray." Encyclopedia of World Biography, Gale, 1998).
[William Thackeray]. "Soldiering." Punch, 26 July 1845
One of Themselves [William Thackeray]. "The Snobs of England." Punch, 31 Oct. 1846
[William Thackeray]. "The Balmoral Gazette." Punch, 16 Sept. 1848
[William Thackeray]. "An Ingleez Family." Punch, 4 Oct. 1851


text:
Tag Archives: Westport
Last week, fire gutted the former Convent of Mercy in Skibbereen, County Cork. Its original occupants had long since vacated the building, left to stand empty and falling into dereliction for the past 15 years: the police have since requested forensic experts to investigate the cause of the blaze. All across Ireland there are similar sites, substantial complexes built in the 19th century for religious orders which, with the decline in vocations and the need for better facilities, have become redundant and too often allowed to become ruinous. A similar series of buildings can be found in Westport, County Mayo, again a former convent formerly belonging to the Sisters of Mercy. Dating from the early 1840s and built on a site provided by the then-Marquess of Sligo, the place was vacated in 2008 after which it was bought by the local authority for €4 million, with assurances that the buildings would find new purpose by 2011 as the town's civic centre. Twelve years later, although still owned by Mayo County Council nothing has been done and the old place is now a blight on the town. Westport rightly enjoys a reputation for its fine architectural heritage: the present state of the old Convent of Mercy does nothing to help that reputation. In 2017 local newspaper The Mayo News wrote about the condition of the property and quoted a council official's assurances that there was 'a masterplan for the whole site and the council will be putting parts of the project to tender in the next couple of weeks'. That was three years ago; those tenders seem to be awfully slow in arrival. Twelve months ago, the council posted a planning notice for work to be carried out on the site, including the construction of two new blocks, one to house a civic office, the other a library. Again, nothing has yet happened. Meanwhile the condition of the buildings grows steadily worse. Two points need to be made here. The first is that Mayo County Council was itself responsible for listing the buildings in question as protected structures. What kind of example does it give to anyone else when the authority so signally fails to protect property in its own possession? Secondly, €4 million of public money has already been spent on the purchase of the former convent: the longer it is left neglected, the more eventual restoration will cost. Everyone – especially members of the council – should remember this will be public money, provided by the Irish tax payer.
10 Comments Posted in Architectural History, Convent, Heritage at Risk, Mayo Tagged Architectural History, Convent, County Mayo, Heritage at Risk, Westport
Last November the Department of Arts, Heritage and the Gaeltacht launched a document called An Action Plan for the Sustainable Future of the Irish Historic House in Private Ownership. In her Introduction Minister Heather Humphreys observed that these properties 'are an important part of our social, cultural and architectural heritage,' as well as being 'an essential thread of our national story and a great source of local community pride.' Furthermore historic houses are 'a vital attraction for both local and foreign visitors and they play an important role in stimulating economic development, particularly at community level.'
Last Thursday members of the Browne family announced that Westport House, County Mayo where they and their forebears have lived for almost 350 years, is to be placed on the open market. The financial difficulties faced by the Brownes, arising from a bank loan (and its attendant guarantees) taken out in 2006 by the late Jeremy Sligo, have been well known for some time. (Incidentally, they demonstrate yet again how in this country while a borrower can be penalised for making an ill-advised decision, the relevant lender suffers no such retribution). Westport's predicament demonstrates how fragile is Ireland's remaining stock of historic properties, how vulnerable to the vagaries of shifting circumstance, precisely because so few safeguards or supports exist to ensure they can weather past and future storms.
Westport House perfectly conforms to Minister Humphreys' designation of the Irish historic property being a source of local pride, an attraction for domestic and overseas visitors and a key player in stimulating regional economic development. A report commissioned last year by Mayo County Council found the house and grounds attracted 162,000 visitors annually and contributed €1.7 million to the fiscal purse and local economy, with 60 per cent of respondents citing the Browne family home as their main reason for visiting Mayo. It is vital to the well being of the area, and the Brownes deserve applause for making this so.
Over the past year there have been plenty of reports, meetings, analyses and consultations over Westport's plight. The time for talk has now come to a close. Decisive action needs to take place, the estate and house ought to be preserved, and the values espoused in its recent document by the Department of Arts, Heritage and the Gaeltacht made manifest. Otherwise, yet again, we will witness the diminution of Ireland's heritage, and the loss of another 'essential thread of our national story.'
9 Comments Posted in Architectural History, Country House, Heritage at Risk, Mayo Tagged Architectural History, County Mayo, Georgian Architecture, Heritage at Risk, Irish Country House, Stately Home, The Big House, Westport
Misplaced Priorities
This weekend the grounds of Westport House, County Mayo play host to a music festival. Revellers of sensitive disposition are advised not to venture into the adjacent town as the neglect of its historic core can only lead to feelings of disgust. In the closing decades of the 18th century, the centre of Westport town was laid out by John Browne, third Earl of Altamont (and later first Marquess of Sligo); its design is often attributed to James Wyatt – who was certainly responsible for some of the house's interiors – but there is no direct evidence to support this.
In any case what cannot be questioned is that Westport has the potential to be one of the most attractive towns in Ireland, a potential which at present is being squandered as the photograph above shows. This is a former coaching inn standing on the North Mall and overlooking the canalised Carrowbeg river. In 1835 John Barrow described it as being a hostelry 'where the most fastidious could scarcely fail to be pleased' and seven years later Thackeray called 'one of the prettiest, comfortablest inns in Ireland.' The hotel continued in business for over two centuries until 2006 when plans were announced for its refurbishment: since then this crucial site has remained shut, despite Westport being heavily dependant on tourism.
If only this were an isolated case, but worse can be found towards the eastern end of the North Mall where the hotel's equivalent can be seen below. Of similar date, five bays and two storeys, and originally created as a private residence the building served for many years as a bank until that closed in 2007 since when it has likewise been permitted to fall into the present state of decay. Furthermore the same is true of several other properties along the mall, their roofs sagging, their window frames decaying, the whole spectacle a sad testament to on-going neglect.
Almost 180 years ago John Barrow regarded the North Mall as 'bearing a close resemblance to a street in a Dutch town' although it is unlikely any local authority in Holland would allow such dereliction to occur. Mayo County Council's current development plan for Westport states 'It is the policy of the Council to maintain, conserve and protect the architectural quality, character and scale of the town.' Looking at these pictures, it is hard to find evidence of the policy being put into practice. Westport even has a town architect who as recently as last November could be found lecturing the burghers of Fermoy, County Cork on how to improve their historic centre. He would do better to stay at home and ensure the place where he is employed, officially designated a Heritage Town of Ireland, holds onto its heritage before this is lost forever.
7 Comments Posted in Architectural History, Heritage at Risk, Mayo Tagged Architectural History, County Mayo, Dublin, Heritage at Risk, Westport


Hi, my name is John Nicholl and I am an Independent Researcher, Leather Finds Specialist and Experimental Archaeologist. As a researcher, my area of interest focuses on all aspects of Leather-working in Ireland from the Early Medieval to the Post-Medieval periods. Brogues and Shoes is a new venture through which I intend to try and share with a wider audience the results of the last twenty years of my research and experiment on the History and Archaeology of Leatherworking in Ireland.
As a Finds Specialist I have written reports on leather finds from sites all over Ireland including Caherduggan Castle in Co. Cork for Rubicon Heritage, Rathfarnham Castle in Dublin for Archaeology Plan and, more recently, Drumclay Crannog in Co. Fermanagh for the Northern Ireland Environment Agency. Every collection of finds can be familiar but different at the same time. The familiar is reassuring. It highlights links between sites and cultures and it places finds in a context. The difference though is exciting. The thrill of opening a finds-bag of mud encased pieces of leather which are not familiar. The gradual teasing out of the puzzle which then drives research to discover and confirm new links not previously known.
Sometimes it is necessary to replicate a find. As an Experimental Archaeologist I have been inspired by the work of the late Olaf Goubitz (1934-2007) who believed "it is impossible to understand historical technology unless you have tried it, and equally impossible to understand ancient footwear unless you have used it" (Goubitz 2007, 8). With this in mind I have made numerous replicas of artefacts as a way of exploring the original method of manufacture and this knowledge and experience feeds into the process of examining a find.
Replica Lucas Type 1 shoes as seen on figures on the Cross of Muiredeach at Monasterboice, Co. Louth.
I have also spent a great deal of time talking about shoes and other leather artefacts to visitors at museums and heritage sites and more formally to students of archaeology. All of these talks, whether informally on a heritage site or more formally in a classroom have been illustrated by my efforts at reproducing the artefacts of which I speak. This can range from shoes, to bottles, slings, quivers, scabbards and so on – in fact anything made from leather and particularly from an Irish context. The shoes I make, I wear at re-enacting events. They are invariably talking points as people are curious as to how they feel, are they comfortable, how long would a pair last for – all practical questions which can only be answered by making and testing.
Leatherworking display at the Irish National Heritage Park in Co. Wexford.
And it is the making and testing which I think is the crucial part of the whole activity. As an archaeologist, it teaches me how the materials behave – their strengths and weaknesses. It teaches me to recognize stitching and other tell-tale signs which might indicate what a fragment of leather originally formed a part of. It helps me to tease out a sodden and crumpled piece of leather and to reshape it as it once appeared.
Brogues and Shoes is my attempt at sharing this knowledge and experience with a wider audience beyond the gates of the heritage site or the classroom door. If I encourage anyone else to take up some basic tools and begin to work with leather I will consider the venture a success. For any students of archaeology who may read this – don't expect to find all the answers – just a trail to follow in your own research and lots of encouragement to experiment for yourself. And for the real heroes and heroines, the archaeologists digging in the mud and dirt of a medieval ditch or well, perhaps a better insight into the potential of that sodden lump of leather which you tease from the ground.


According to The Springfield Journal and Register, a Michigan truck driver has been cited for negligent driving for a Chicago truck accident that killed two people and left twenty-one people injured.
The Chicago truck accident occurred when the driver drove his semi-trailer into a Chicago Transit Authority elevated train station. The truck driver was briefly hospitalized following the Illinois auto accident.
The two women were killed, and most of the twenty-one injured were in the bus shelter underneath the train when the Chicago truck accident happened.
Police are still examining footage captured by a CTA surveillance camera to determine what events led to the Chicago truck accident.