text:
Panamint City is a ghost town in the Panamint Range, near Death Valley, in Inyo County, California, US. It is also known by the official Board of Geographic Names as Panamint. Panamint was a boom town founded after silver and copper were found there in 1872. By 1874, the town had a population of about 2,000. Its main street was one mile (1.6 km) long. Panamint had its own newspaper, the Panamint News. Silver was the principal product mined in the area. The town is located about three miles northwest of Sentinel Peak. According to the National Geographic Names Database, NAD27 latitude and longitude for the locale are , and the feature ID number is 1661185. The elevation of this location is identified as being 6,280 feet AMSL. The similar-sounding Panamint Springs, California, is located about 25.8 miles at 306.4 degrees off true north near Panamint Junction.

History
Panamint City is the site of the largest and most elaborate group of Coso Painted Style pictographs. The presence of these pictographs indicates that Surprise Canyon was inhabited by Shoshone and/or Kawaiisu not long before the town was founded.

Silver was discovered by Prospectors William Ledlie Kennedy, Robert Polk Stewart, and Richard C. Jacobs, who were forced to form a partnership with a gang of six stage robbers who had followed them when they returned to stake their claim. EP Raines, an early investor in Panamint mining, convinced a group of Los Angeles businessmen to build a wagon road and then moved on to San Francisco, where he met Nevada Senator John P. Jones. Jones and the other Nevada Senator, William M. Stewart, created the Panamint Mining Company and bought up the larger mines. The two were quite famous for their heavy involvement in silver mining in Nevada, and their interest in Panamint started the boom.

Founded in 1873–74, the town grew to include many mills, saloons, stores, a red light district, and a cemetery – all built along the uppermost end of Surprise Canyon. Panamint City was regarded as a "bad and wicked" town. Because of Panamint City's lawless reputation, Wells Fargo refused to open an office there. The senators solved the question of how to transport the silver bullion from the mines by casting it into 450-pound cannonballs, which were hauled to Los Angeles in an unguarded wagon.

On July 24, 1876, a flash flood roared down the canyon and washed out most of the town. The County of Inyo maintained a graded road to Panamint City until about 1983, when a terrific series of cloudbursts completely washed the canyon out to bedrock. This road permitted large vehicles, such as house trailers and trucks with mining equipment, to access Panamint City (some of these vehicles are abandoned there). The California Desert Protection Act in 1994 placed the upper portion of Surprise in Death Valley National Park and designated the Bureau of Land Management portion below as wilderness. Congress excluded a narrow strip of land around the washed-out road and remaining private property in Panamint City. Surprise Canyon Road was hard-closed with a locked gate by the Bureau of Land Management in May 2001 as a result of a lawsuit brought about by the Center for Biological Diversity, the Sierra Club, and Public Employees for Environmental Responsibility. In the closure order there was an exemption to owners of private property, allowing them to access their property as had been done in the past. A "Stipulation Agreement" written into the terms of the closure stated that the BLM must complete an "Environmental Impact Statement" (EIS) to determine further allowed use of the road. To date, private property owners' requests for access have gone un-answered as the agencies feel many of the issues they have surrounding access will be answered by the yet-to-be released findings of the "EIS".

A post office operated at Panamint from 1874 to 1877, from 1882 to 1883, and from 1887 to 1895.

Much of Panamint City and Surprise Canyon were added to Death Valley National Park in 1994, with the exception of the land, buildings, and road that are still private property. Surprise Canyon Road and Panamint City are in a non-wilderness "cherry stem" created by an act of Congress, surrounded by Surprise Canyon Wilderness and Death Valley National Park. A "cherry stem" means that these areas were specifically excluded from wilderness because they did not meet the wilderness criteria. The cherry stem of Surprise Canyon Road and Panamint City was created by Congress to insure future public access to this historic town, and private property in the area. In May 2001 the BLM erected a gate to block vehicular access road. Today, Panamint City is accessible only by a 7.5 mile hike, strenuous for even experienced hikers.

Nearby features
 Sentinel Peak is plotted on the 1988, Panamint, California topographic map at NAD83 latitude and longitude .
 Thompson Camp is plotted near NAD83 latitude and longitude  on the 1988, Panamint, California topographic map.
 Hemlock Mine is plotted on the 1988, Panamint, California topographic map at NAD83 latitude and longitude .

See also
 List of ghost towns in California

Notes

External links
National Park Service
GhostTowns.com
Historical Society of the Upper Mojave Desert newsletter containing excerpts from the Panamint News

Ghost towns in Inyo County, California
Panamint Range
Mining communities in California
Death Valley National Park
Populated places in the Mojave Desert
History of the Mojave Desert region
Former settlements in Inyo County, California
Unincorporated communities in California
Populated places established in 1872
1872 establishments in California


Saudi Arabia's ministry of media has issued a strong rebuttal of claims made by tennis' leading bodies about the beoutQ pirate network active in the Middle East and North Africa.
The demand for Arabsat to "stop facilitating the mass-scale piracy and for decisive action to be taken to stamp out beoutQ" has been met with a fiery riposte from Saudi Arabia's General Commission for Audiovisual Media.
Claims that beoutQ is based in Saudi Arabia and that the country is "somehow complicit in beoutQ's broadcasts" are "inaccurate and irresponsible," the ministry has boldly claimed.
The ministry's stance is set against the backdrop of the bitter dispute between Qatar and other Gulf nations and the campaign led by BeIN Sports, the Qatar-backed international pay-TV sports broadcaster, against beoutQ. Other leading rights-holders that have publicly criticised beoutQ in recent weeks include Formula 1 and soccer's Uefa, Fifa and CAF (plus broadcasters Telemundo and Eleven Sports).
Qatar has repeatedly and vehemently denied the allegations that it supports terrorism in the region.
The ministry stated: "Wimbledon and the various tennis associations know or should know that beginning in June 2017, the Saudi government banned all broadcasts by Al Jazeera and its affiliates because Al Jazeera is a media platform for terrorists to propagate their violent messages and to promote instability in the region.
However, matches from the Fifa World Cup on beoutQ are reported to have been played on big screens at a government-sponsored event in Riyadh, and the service regularly broadcasts in homes, cafes and restaurants. The beoutQ set-top boxes are also said to be readily available across shops in Saudi Arabia, costing as much as SAR400 ($107), including a year-long subscription.
BeIN told the New York Times in May that it had traced the beoutQ signal to Arabsat, and that is has spent over $200,000 investigating the piracy.


Amsterdam, NL – While human genetic mutations are involved in a small number of Parkinson's disease (PD) cases, the vast majority of cases are of unknown environmental causes, prompting enormous interest in identifying environmental risk factors involved.
The link between Helicobacter pylori (H. pylori) and gastric ulcers has been known for several decades, but new evidence suggests that this harmful bacterium may play a role in PD as well. A new open access review in the Journal of Parkinson's Disease summarizes the current literature regarding the link between H. pylori and PD and explores the possible mechanisms behind the association.
The bacteria might interfere with the absorption properties of levodopa, the medication commonly used to treat the symptoms of Parkinson's disease.
The onset of PD is often preceded by gastrointestinal dysfunction, suggesting that the condition might originate in the gut and spread to the brain along the brain–gut axis. In the review, investigators note that this has been documented in rats.
Full open access study: "Stomaching the Possibility of a Pathogenic Role for Helicobacter pylori in Parkinson's Disease," by David J. McGee, Xiao-Hong Lu and Elizabeth A. Disbrow (DOI 10.3233/JPD-181327) published in the Journal of Parkinson's Disease, Volume 8, Issue 3 (August 2018) by IOS Press. It is available open access at: https://content.iospress.com/articles/journal-of-parkinsons-disease/jpd181327.
For additional information, contact Diana Murray, IOS Press (+1 718 640-5678; d.murray@iospress.com). Journalists wishing to interview the study's authors should contact Dr. David McGee, LSU Health Sciences Center-Shreveport (+1 318-675-8138; dmcgee@lsuhsc.edu).


The term 'Connectably Ltd' or 'us' or 'we' refers to the owner of the website whose registered office is 46 Dragon Avenue, Harrogate, North Yorkshire, HG1 5DT, United Kingdom. Our company registration number is 10835177, a Private Limited company with share capital, registered in England. The term 'you' refers to the user or viewer of our website or our services.


alga marghen proudly presents the new edition of two sublime pieces by Eliane Radigue, "Jouet Electronique" (1967) for feedback on magnetic tape and "Elemental I" (1968) for feedback of natural sounds on magnetic tape. This LP was first issued in 2010 on the occasion of an alga marghen presentation at Centre Pompidou in Paris and included in the series of publications connected to the Oeuvres Sonores events. We thought, after a long time this wonderful record was sold out, it's time now to have it available again, presenting it for the first time with it's own specific artwork and layout.
Both works were recorded at Pierre Henry's Studio Apsome in Paris. Between 1967 and 1968, Eliane Radigue was the assistant of Pierre Henry in his studio, mainly for the editing of "L'Apocalypse de Jean". He also put her in charge of organizing his sound archive according to different criteria. It was endless work – there were incredible sounds, a true sound library! Eliane Radigue really enjoyed doing this work, even if it took a long time. So, sometimes she decided to set the machines of the studio to do some little work on her own. "Jouet Electronique" and "Elemental I" were born this way as a kind of recreation during her time as a studio assistant.
Working with feedback is something that Eliane Radigue learned through Pierre Henry. Do you remember "Voyage"? There's that fluid part which is made of feedback constructed with a microphone. Everything had to be set at a precise distance from the loudspeakers because that is the specific problem with feedback – you have to be at the right distance. Afterwards, these high tone recordings were slowed down in order to discover the deeper character of their color. This work with feedback was in the end quite limited and the composer preferred working with two reel tape machines to produce sounds. The first was set on the recording mode while the other was playing and it was the accidents happening in this phase that made the feedback richer. With some fine-tuning you could reach very beautiful results: low pulsations, very high-pitched sounds – sometimes both at the same time – or long sounds. All of these sounds could be slowed down or accelerated, which gave her a beautiful material to work with.
With "Jouet Electronique" Eliane Radigue had a lot of fun, hence the title. As far as "Elemental I" is concerned, it was the first attempt at something which was very important to her based on the theme of the basic elements: water, fire, air and earth. Eliane had the chance to record in open air thanks to a small Stella Vox that Arman gave her in the beginning of the 1960s. At the time she was still living in Nice and every now and then she went for a walk to do some recordings of the sea, the wind, the rain, the fire – Eliane Radigue continued this way to build her very minimal sound library, consisting of not more than ten reel tapes. This was the starting point and in 1968 she used these recordings for her work with two reel tape machines.
New edition of 200 copies, with liner notes by Eliane Radigue and portrait photos by Arman.


Bedroom Colors With Wood Furniture - Hello there, thanks for visit here and this is a collections about Bedroom Colors With Wood Furniture, was posted under Bedroom Furniture Collections. Just click one of picture to view large image.
Bedroom Colors With Wood Furniture Posted by admin on February 14, 2018 at 11:17 pm . If you found any images copyrighted to yours, please contact us and we will remove it. We don't intend to display any copyright protected images.


This summer season, plan out a family trip or a honeymoon at Tajawal. Plan your trip to any of the exotic locations. Tajawal is offering Flat 100 AED OFF for your flight tickets along with the discount on Hotel Bookings on a minimum of 1,000 AED transaction value. This is the best offer you can have. So book your winter holiday immediately using available Tajawal Coupon Code. Just take care that payment must be made by a valid Visa card.
Minimum booking amount must be worth AED 1000 or more.
Book your International Flight now on Rehlat and Enjoy 80 AED OFF and 80 AED Karam Cash.
This offer is Applicable to International flights only.
Use Rehlat Coupon code to grab this amazing offer.
This offer is valid for all users on the web & mobile platform.
Discount can be redeemed with net banking, COD & other payment methods.
Available for UAE region only.
This festive season, celebrate Holi with your friends & family. Book your flight at Rehlat using Rehlat Coupon Code & get instant 40 AED Off and use Karam cash equal to 3% of base fare (upto a maximum of 40 AED). After booking, you will also earn flat 80 AED Karam cashback which can be used for your next booking. No minimum booking amount required to enjoy the discount benefits. Coupon Code can be redeemed multiple times. No use restriction. Applicable on all international routes. Coupon doesn't apply on Jazeera Airways, Spicejet, flydubai, flynas, Air Arabia, Pegasus, SalamAir, & Air India Express.
Wanna meet & greet your relatives living in Pakistan? This is the perfect time to book your flight tickets. Tajawal is offering SalamAir flights to Pakistan on the special fare for as low as 541* AED only. Your travel ticket would be in economy class with meals included. Make your journey comfortable & happy with this exceptional flight offer. Book now. The offer is valid until 3o April 2019 to book the air tickets.
How about making a family trip to Prague? Excited! This season, witness the beauty of historical monuments & awesome tourist spots. Book your flight ticket or holiday package at Tajawal and get the lowest flight fare: AED 1,399 onwards. The offer is open for all registered Tajawal users.
Eligible airlines are Air Arabia for the offered trip.
valid on Tajawal web + mobile.
all payments methods are accepted for the offer.
valid until 31st April 2019.
Explore the greatest iconic destinations like Kiev, Barcelona, Istanbul, Berlin and more with Turkish Airlines. The airline travels across several countries covering many hottest destination popular globally. Now let's talk about the deal. Tajawal is offering a great fare for these routes and that starts from AED 1,499 onward. The fares are much lower than the regular ones. You hardly may get such a good deal. So, Book now.
Turkish Airlines offers top flights from AED 1,499 onward.
The offer available for UAE users only.
Booking must be made with Turkish Airlines & before 28 Feb 2019.
Travel should be commenced before 28 Feb 2019.
Almosafer is offering you the best flight deal for London. Book your flight for London using the available Almosafer Coupon and get your ticket done at just AED 2,399 only. The best thing is that all taxes and charges are inclusive.
Travelling under the sale must be commenced before 31 March 2019.
Fares are applicable for Economy class return trips.
Fares are applicable to Etihad Airways.
Riyadh is Saudi Arabia's capital city & and main financial hub of the country. It is famous for both modern architecture and historical monuments. If you are planning to make a trip to Riyadh this is the perfect time to explore the place. To make your trip easy & cost effective, Saudi Gulf Airlines is offering the flight for as low as 885* onward from Dubai with some top onboard services. To place your booking you just have to Login at Tajawal and proceed by filling the journey details. The fare flights are available until 3o April 2019. So book your flight as soon as possible.
The flight fares are subject to modification at the time of booking.
Travel can be commenced until 28 Feb 2019.
No coupon code is mandatory to avail the offer benefits.
Make your weekend getaway plans to Moscow, Baku, Yerevan, Nairobi, Istanbul, Tbilisi, Prague & Beirut and enjoy Flat 60 AED OFF on Air Arabia flights. Just apply the coupon code at the checkout while booking and redeem the instant discount. Neither minimum booking amount restrictions nor the minimum passengers. So what are you waiting for? Book now.
Discount does not apply to infant booking.
New one way direct flights between Dammam & Karachi at Just SAR 396*. Book now.
Plan your best trip of recent times with Almosafer. Book your flight ticket on Gulf Air for as low as AED 982 only. Hurry up! This is a limited period offer.
No code required to get the deal benefits. Offer expires on 31 Jan 2019.
Planning to visit Manila? Explore the charm of Manila with Rehlat. Your flights for Manila starts from AED 1,299* only.
Get your tickets done with Oman Air at Ejazah and avail a flat discount of 10% by applying the coupon code. Hurry up! Offer valid for a very limited period only.
The users must apply the valid coupon code to get the discount.
A discount of 10% can be availed on Oman Air flights for up to a maximum amount of SAR 500.
Discount is available on the base fare with a minimum purchase value of SAR 1,000.
The offer is valid from now until 28 Feb 2019.
Book your flight from Riyadh to New Delhi at very special fare - AED 670* Only.
Book a package for London with Flat 20% OFF on fare. With 4* Days and 4 Nights, you can book at SAR 2,000 only.
The coupon is applicable for London Holiday Package.
Maximum 20% can be availed on base fare as the discount.
Coupon can be used by all users (new & existing both).
Discount expires on 3o April 2019.
It's not mandatory to apply the coupon code to get the discount.
Here is an amazing flight offer to book the Nile Air flight tickets at a discounted fare. Ejazah is offering flat SAR 75 OFF on air tickets. Just apply the coupon code NP75 at the checkout and enjoy the discount benefits. Hurry up! Offer valid for a very limited period only.
Minimum transaction value should be worth SAR 1,000.
Bookings must be done until 28 Feb 2019 to avail the discount.
How about exploring the coolest Indian destinations this summer. It's a monsoon going on in India and this is the perfect time to chill up after summer. Book your roundtrip flight from Riyadh to New Delhi at SAR 2,495* only. This is a limited period offer so hurry up!
The users do not require any coupon code to get the benefits of this deal.
This Diwali travel to greet your family & friends with special flight fare. Air Arabia is offering return flights for India at just USD 440* only. You can visit India and come back with such lowest price. So pack your bag and get ready to fly.
Travel must be commenced before 25 Nov 2018 and return to be completed by 15 Dec 2018.
Enjoy super deals on our Economy Business and First Class to some of our most popular destinations. So book your seat and take advantage of this fantastic offer Book by 31 Jan 2019 and for travel until 5 April 2019.


text:
Thu, 23 May 2019 04:22:21 GMT
12.0: Organic Chemistry - Alkanes & Halogenated Hydrocarbons
[ "article:topic", "showtoc:no", "license:ccbyncsa" ]
Introductory & GOB Chemistry
Book: The Basics of GOB Chemistry (Ball et al.)
12: Organic Chemistry - Alkanes & Halogenated Hydrocarbons
Hydrocarbons are the simplest organic compounds, but they have interesting physiological effects. These effects depend on the size of the hydrocarbon molecules and where on or in the body they are applied. Alkanes of low molar mass—those with from 1 to approximately 10 or so carbon atoms—are gases or light liquids that act as anesthetics. Inhaling ("sniffing") these hydrocarbons in gasoline or aerosol propellants for their intoxicating effect is a major health problem that can lead to liver, kidney, or brain damage or to immediate death by asphyxiation by excluding oxygen.
Swallowed, liquid alkanes do little harm while in the stomach. In the lungs, however, they cause "chemical" pneumonia by dissolving fatlike molecules from cell membranes in the tiny air sacs (alveoli). The lungs become unable to expel fluids, just as in pneumonia caused by bacteria or viruses. People who swallow gasoline or other liquid alkane mixtures should not be made to vomit, as this would increase the chance of getting alkanes into the lungs. (There is no home-treatment antidote for gasoline poisoning; call a poison control center.)
Figure \(\PageIndex{1}\): Butane is a hydrocarbon with the formula \(\ce{C4H10}\) and is a gas at room temperature and atmospheric pressure. Under excess pressures, it can be liquidized like the fuel shown in this butane lighters. Image used with permission (CC BY 3.0Unported; Frank Vincentz)
Liquid alkanes with approximately 5–16 carbon atoms per molecule wash away natural skin oils and cause drying and chapping of the skin, while heavier liquid alkanes (those with approximately 17 or more carbon atoms per molecule) act as emollients (skin softeners). Such alkane mixtures as mineral oil and petroleum jelly can be applied as a protective film. Water and aqueous solutions such as urine will not dissolve such a film, which explains why petroleum jelly protects a baby's tender skin from diaper rash.
12.1: Organic Chemistry

redpajama_set_name: RedPajamaCommonCrawl


text:
package uk.gov.register.store.postgres;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import io.dropwizard.jdbi.OptionalContainerFactory;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import uk.gov.register.core.Entry;
import uk.gov.register.core.EntryType;
import uk.gov.register.core.Item;
import uk.gov.register.core.Record;
import uk.gov.register.db.EntryDAO;
import uk.gov.register.db.EntryQueryDAO;
import uk.gov.register.db.ItemDAO;
import uk.gov.register.db.ItemQueryDAO;
import uk.gov.register.db.RecordQueryDAO;
import uk.gov.register.functional.app.RegisterRule;
import uk.gov.register.functional.app.TestRegister;
import uk.gov.register.functional.app.WipeDatabaseRule;
import uk.gov.register.util.HashValue;

import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Optional;

import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static uk.gov.register.core.HashingAlgorithm.SHA256;

public class BatchedPostgresDataAccessLayerTest {
    private BatchedPostgresDataAccessLayer batchedPostgresDataAccessLayer;
    private PostgresDataAccessLayer postgresDataAccessLayer;
    private ObjectMapper objectMapper = new ObjectMapper();

    @ClassRule
    public static RegisterRule register = new RegisterRule();
    private DBI dbi;
    private Handle handle;

    @BeforeClass
    public static void wipe() {
        register.wipe();
    }

    @Before
    public void setup() {
        TestRegister register = TestRegister.address;
        dbi = new DBI(register.getDatabaseConnectionString("BatchedPostgresDataAccessLayerTest"));
        dbi.registerContainerFactory(new OptionalContainerFactory());
        handle = dbi.open();

        postgresDataAccessLayer = new PostgresDataAccessLayer(
                handle.attach(EntryDAO.class),
                handle.attach(EntryQueryDAO.class),
                handle.attach(ItemDAO.class),
                handle.attach(ItemQueryDAO.class),
                handle.attach(RecordQueryDAO.class),
                register.getSchema());
        batchedPostgresDataAccessLayer = new BatchedPostgresDataAccessLayer(postgresDataAccessLayer);
    }

    @After
    public void tearDown() {
        dbi.close(handle);
        register.wipe();
    }

    @Test
    public void canAppendAndGetEntry() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry entry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(entry1);
        batchedPostgresDataAccessLayer.appendEntry(entry2);
        assertThat(batchedPostgresDataAccessLayer.getEntry(1), is(Optional.of(entry1)));
        assertThat(batchedPostgresDataAccessLayer.getEntry(2), is(Optional.of(entry2)));
        assertThat(batchedPostgresDataAccessLayer.getEntry(3), is(Optional.empty()));
    }

    @Test(expected = IllegalArgumentException.class)
    public void appendUserEntriesThatSkipEntryNumberThrowsException() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry entry2 = new Entry(3, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(entry1);
        batchedPostgresDataAccessLayer.appendEntry(entry2);
    }

    @Test(expected = IllegalArgumentException.class)
    public void appendUserEntriesWithDuplicateEntryNumberThrowsException() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry entry2 = new Entry(1, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(entry1);
        batchedPostgresDataAccessLayer.appendEntry(entry2);
    }

    @Test(expected = IllegalArgumentException.class)
    public void appendSystemEntriesThatSkipEntryNumberThrowsException() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry2 = new Entry(3, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.system);

        batchedPostgresDataAccessLayer.appendEntry(entry1);
        batchedPostgresDataAccessLayer.appendEntry(entry2);
    }

    @Test(expected = IllegalArgumentException.class)
    public void appendSystemEntriesWithDuplicateEntryNumberThrowsException() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry2 = new Entry(1, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.system);

        batchedPostgresDataAccessLayer.appendEntry(entry1);
        batchedPostgresDataAccessLayer.appendEntry(entry2);
    }

    @Test
    public void canGetMultipleEntries() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry entry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry entry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key3", EntryType.user);
        Entry entry4 = new Entry(4, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key3", EntryType.user);

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(entry1);
        batchedPostgresDataAccessLayer.appendEntry(entry2);
        batchedPostgresDataAccessLayer.appendEntry(entry3);
        batchedPostgresDataAccessLayer.appendEntry(entry4);

        assertThat(batchedPostgresDataAccessLayer.getAllEntries().size(), is(4));
        assertThat(batchedPostgresDataAccessLayer.getAllEntries(), contains(entry4, entry3, entry2, entry1));
        assertThat(batchedPostgresDataAccessLayer.getEntries(1, 10).size(), is(4));
        assertThat(batchedPostgresDataAccessLayer.getEntries(1, 10), contains(entry1, entry2, entry3, entry4));
        assertThat(batchedPostgresDataAccessLayer.getEntries(2, 2).size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.getEntries(2, 2), contains(entry2, entry3));
    }

    @Test
    public void canGetEntryIterator() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry userEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry userEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry userEntry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key3", EntryType.user);
        Entry userEntry4 = new Entry(4, new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "blobhash4"), timestamp, "key4", EntryType.user);
        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry systemEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.system);
        Entry systemEntry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key3", EntryType.system);
        Entry systemEntry4 = new Entry(4, new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "blobhash4"), timestamp, "key4", EntryType.system);

        batchedPostgresDataAccessLayer.appendEntry(userEntry1);
        batchedPostgresDataAccessLayer.appendEntry(userEntry2);
        batchedPostgresDataAccessLayer.appendEntry(userEntry3);
        batchedPostgresDataAccessLayer.appendEntry(userEntry4);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry2);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry3);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry4);

        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.user)).size(), is(4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.user)), contains(userEntry1, userEntry2, userEntry3, userEntry4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.user, 0, 10)).size(), is(4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.user, 0, 10)), contains(userEntry1, userEntry2, userEntry3, userEntry4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.user, 1, 3)).size(), is(2));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.user, 1, 3)), contains(userEntry2, userEntry3));

        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.system)).size(), is(4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.system)), contains(systemEntry1, systemEntry2, systemEntry3, systemEntry4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.system, 0, 10)).size(), is(4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.system, 0, 10)), contains(systemEntry1, systemEntry2, systemEntry3, systemEntry4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.system, 1, 3)).size(), is(2));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getEntryIterator(EntryType.system, 1, 3)), contains(systemEntry2, systemEntry3));
    }

    @Test
    public void canGetEntriesByKey() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry entry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry entry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key3", EntryType.user);
        Entry entry4 = new Entry(4, new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "blobhash4"), timestamp, "key3", EntryType.user);

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(entry1);
        batchedPostgresDataAccessLayer.appendEntry(entry2);
        batchedPostgresDataAccessLayer.appendEntry(entry3);
        batchedPostgresDataAccessLayer.appendEntry(entry4);

        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key1").size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key1"), contains(entry1));
        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key2").size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key2"), contains(entry2));
        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key3").size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key3"), contains(entry3, entry4));
    }

    @Test
    public void canGetTotalEntries() {
        assertThat(batchedPostgresDataAccessLayer.getTotalEntries(EntryType.user), is(0));
        assertThat(batchedPostgresDataAccessLayer.getTotalEntries(EntryType.system), is(0));

        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry userEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry userEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry userEntry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key3", EntryType.user);
        Entry userEntry4 = new Entry(4, new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "blobhash4"), timestamp, "key4", EntryType.user);

        batchedPostgresDataAccessLayer.appendEntry(userEntry1);
        batchedPostgresDataAccessLayer.appendEntry(userEntry2);
        batchedPostgresDataAccessLayer.appendEntry(userEntry3);
        batchedPostgresDataAccessLayer.appendEntry(userEntry4);

        assertThat(batchedPostgresDataAccessLayer.getTotalEntries(EntryType.user), is(4));

        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry systemEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.system);

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry2);

        assertThat(batchedPostgresDataAccessLayer.getTotalEntries(EntryType.system), is(2));
    }

    @Test
    public void canGetLastUpdatedTime() {
        assertThat(batchedPostgresDataAccessLayer.getLastUpdatedTime(), is(Optional.empty()));

        Instant timestamp1 = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Instant timestamp2 = timestamp1.plus(Duration.ofDays(1));
        Instant timestamp3 = timestamp2.plus(Duration.ofDays(1));

        Entry userEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp1, "key1", EntryType.user);
        Entry userEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp2, "key2", EntryType.user);
        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp3, "key1", EntryType.system);

        batchedPostgresDataAccessLayer.appendEntry(userEntry1);
        batchedPostgresDataAccessLayer.appendEntry(userEntry2);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);

        assertThat(batchedPostgresDataAccessLayer.getLastUpdatedTime(), is(Optional.of(timestamp2)));
    }

    @Test
    public void canAddAndGetItem() throws IOException {
        Item item1 = new Item(new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "itemhash1-blob-hash"), objectMapper.readTree("{\"field\":\"foo\"}"));
        Item item2 = new Item(new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "itemhash2-blob-hash"), objectMapper.readTree("{\"field\":\"bar\"}"));

        batchedPostgresDataAccessLayer.addItem(item1);
        batchedPostgresDataAccessLayer.addItem(item2);

        assertThat(batchedPostgresDataAccessLayer.getItemByV1Hash(new HashValue(SHA256, "itemhash1")), is(Optional.of(item1)));
        assertThat(batchedPostgresDataAccessLayer.getItemByV1Hash(new HashValue(SHA256, "itemhash2")), is(Optional.of(item2)));
        assertThat(batchedPostgresDataAccessLayer.getItemByV1Hash(new HashValue(SHA256, "itemhash3")), is(Optional.empty()));
    }

    @Test
    public void doesNotDuplicateItems() throws IOException {
        Item item1 = new Item(new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "itemhash1-blob-hash"), objectMapper.readTree("{\"field\":\"foo\"}"));
        Item item2 = new Item(new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "itemhash2-blob-hash"), objectMapper.readTree("{\"field\":\"bar\"}"));

        batchedPostgresDataAccessLayer.addItem(item1);
        batchedPostgresDataAccessLayer.addItem(item2);
        batchedPostgresDataAccessLayer.addItem(item1);

        assertThat(batchedPostgresDataAccessLayer.getItemByV1Hash(new HashValue(SHA256, "itemhash1")), is(Optional.of(item1)));
        assertThat(batchedPostgresDataAccessLayer.getItemByV1Hash(new HashValue(SHA256, "itemhash2")), is(Optional.of(item2)));
        assertThat(batchedPostgresDataAccessLayer.getItemByV1Hash(new HashValue(SHA256, "itemhash3")), is(Optional.empty()));
    }

    @Test
    public void canGetMultipleItems() throws IOException {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);

        assertThat(batchedPostgresDataAccessLayer.getAllItems().size(), is(0));

        Item item1 = new Item(new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "itemhash1-blob-hash"), objectMapper.readTree("{\"field\":\"foo\"}"));
        Item item2 = new Item(new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "itemhash2-blob-hash"), objectMapper.readTree("{\"field\":\"bar\"}"));

        batchedPostgresDataAccessLayer.addItem(item1);
        batchedPostgresDataAccessLayer.addItem(item2);

        assertThat(batchedPostgresDataAccessLayer.getAllItems().size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.getAllItems(), containsInAnyOrder(item1, item2));
    }

    @Test
    public void canGetItemIterator() throws IOException {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry userEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry userEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry userEntry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key3", EntryType.user);
        Entry userEntry4 = new Entry(4, new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "blobhash4"), timestamp, "key4", EntryType.user);
        Item item1 = new Item(new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "itemhash1-blob-hash"), objectMapper.readTree("{\"field\":\"value1\"}"));
        Item item2 = new Item(new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "itemhash2-blob-hash"), objectMapper.readTree("{\"field\":\"value2\"}"));
        Item item3 = new Item(new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "itemhash3-blob-hash"), objectMapper.readTree("{\"field\":\"value3\"}"));
        Item item4 = new Item(new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "itemhash4-blob-hash"), objectMapper.readTree("{\"field\":\"value4\"}"));

        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "blobhash5"), timestamp, "key5", EntryType.system);
        Entry systemEntry2 = new Entry(2, new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "blobhash6") , timestamp, "key6", EntryType.system);
        Entry systemEntry3 = new Entry(3, new HashValue(SHA256, "itemhash7"), new HashValue(SHA256, "blobhash7"), timestamp, "key7", EntryType.system);
        Entry systemEntry4 = new Entry(4, new HashValue(SHA256, "itemhash8"), new HashValue(SHA256, "blobhash8"), timestamp, "key8", EntryType.system);
        Item item5 = new Item(new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "itemhash5-blob-hash"), objectMapper.readTree("{\"field\":\"value5\"}"));
        Item item6 = new Item(new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "itemhash6-blob-hash"), objectMapper.readTree("{\"field\":\"value6\"}"));
        Item item7 = new Item(new HashValue(SHA256, "itemhash7"), new HashValue(SHA256, "itemhash7-blob-hash"), objectMapper.readTree("{\"field\":\"value7\"}"));
        Item item8 = new Item(new HashValue(SHA256, "itemhash8"), new HashValue(SHA256, "itemhash8-blob-hash"), objectMapper.readTree("{\"field\":\"value8\"}"));

        batchedPostgresDataAccessLayer.appendEntry(userEntry1);
        batchedPostgresDataAccessLayer.appendEntry(userEntry2);
        batchedPostgresDataAccessLayer.appendEntry(userEntry3);
        batchedPostgresDataAccessLayer.appendEntry(userEntry4);
        batchedPostgresDataAccessLayer.addItem(item1);
        batchedPostgresDataAccessLayer.addItem(item2);
        batchedPostgresDataAccessLayer.addItem(item3);
        batchedPostgresDataAccessLayer.addItem(item4);

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry2);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry3);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry4);
        batchedPostgresDataAccessLayer.addItem(item5);
        batchedPostgresDataAccessLayer.addItem(item6);
        batchedPostgresDataAccessLayer.addItem(item7);
        batchedPostgresDataAccessLayer.addItem(item8);

        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getItemIterator(EntryType.user)).size(), is(4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getItemIterator(EntryType.user)), containsInAnyOrder(item1, item2, item3, item4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getItemIterator(0, 10)).size(), is(4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getItemIterator(0, 10)), containsInAnyOrder(item1, item2, item3, item4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getItemIterator(1, 3)).size(), is(2));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getItemIterator(1, 3)), containsInAnyOrder(item2, item3));

        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getItemIterator(EntryType.system)).size(), is(4));
        assertThat(Lists.newArrayList(batchedPostgresDataAccessLayer.getItemIterator(EntryType.system)), containsInAnyOrder(item5, item6, item7, item8));
    }

    @Test
    public void canGetRecordsAndTotalRecords() throws IOException {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry userEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry userEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry userEntry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key2", EntryType.user);
        Item item1 = new Item(new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "itemhash1-blob-hash"), objectMapper.readTree("{\"field\":\"value1\"}"));
        Item item2 = new Item(new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "itemhash2-blob-hash"), objectMapper.readTree("{\"field\":\"value2\"}"));
        Item item3 = new Item(new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "itemhash3-blob-hash"), objectMapper.readTree("{\"field\":\"value3\"}"));

        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "blobhash4"), timestamp, "key5", EntryType.system);
        Entry systemEntry2 = new Entry(2, new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "blobhash5"), timestamp, "key6", EntryType.system);
        Entry systemEntry3 = new Entry(3, new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "blobhash6"), timestamp, "key5", EntryType.system);
        Item item4 = new Item(new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "itemhash4-blob-hash"), objectMapper.readTree("{\"field\":\"value4\"}"));
        Item item5 = new Item(new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "itemhash5-blob-hash"), objectMapper.readTree("{\"field\":\"value5\"}"));
        Item item6 = new Item(new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "itemhash6-blob-hash"), objectMapper.readTree("{\"field\":\"value6\"}"));

        batchedPostgresDataAccessLayer.appendEntry(userEntry1);
        batchedPostgresDataAccessLayer.appendEntry(userEntry2);
        batchedPostgresDataAccessLayer.appendEntry(userEntry3);
        batchedPostgresDataAccessLayer.addItem(item1);
        batchedPostgresDataAccessLayer.addItem(item2);
        batchedPostgresDataAccessLayer.addItem(item3);

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry2);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry3);
        batchedPostgresDataAccessLayer.addItem(item4);
        batchedPostgresDataAccessLayer.addItem(item5);
        batchedPostgresDataAccessLayer.addItem(item6);

        Record userRecord1 = new Record(userEntry1, item1);
        Record userRecord2 = new Record(userEntry3, item3);
        Record systemRecord1 = new Record(systemEntry2, item5);
        Record systemRecord2 = new Record(systemEntry3, item6);

        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.user, "key1"), is(Optional.of(userRecord1)));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.user, "key2"), is(Optional.of(userRecord2)));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.user, "key3"), is(Optional.empty()));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.user, 10, 0).size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.user, 10, 0), contains(userRecord2, userRecord1));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.user, 10, 1).size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.user, 10, 1), contains(userRecord1));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.user, 1, 0).size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.user, 1, 0), contains(userRecord2));
        assertThat(batchedPostgresDataAccessLayer.getTotalRecords(EntryType.user), is(2));

        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.system, "key1"), is(Optional.empty()));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.system, "key5"), is(Optional.of(systemRecord2)));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.system, "key6"), is(Optional.of(systemRecord1)));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.system, 10, 0).size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.system, 10, 0), contains(systemRecord2, systemRecord1));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.system, 10, 1).size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.system, 10, 1), contains(systemRecord1));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.system, 1, 0).size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.getRecords(EntryType.system, 1, 0), contains(systemRecord2));
        assertThat(batchedPostgresDataAccessLayer.getTotalRecords(EntryType.system), is(2));
    }

    @Test
    public void canGetRecordsByKeyValue() throws IOException {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry userEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry userEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry userEntry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key2", EntryType.user);
        Entry userEntry4 = new Entry(4, new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "blobhash4"), timestamp, "key3", EntryType.user);
        Item item1 = new Item(new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "itemhash1-blob-hash"), objectMapper.readTree("{\"field\":\"value1\"}"));
        Item item2 = new Item(new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "itemhash2-blob-hash"), objectMapper.readTree("{\"field\":\"value1\"}"));
        Item item3 = new Item(new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "itemhash3-blob-hash"), objectMapper.readTree("{\"field\":\"value2\"}"));
        Item item4 = new Item(new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "itemhash4-blob-hash"), objectMapper.readTree("{\"field\":\"value2\"}"));

        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "blobhash5"), timestamp, "key5", EntryType.system);
        Entry systemEntry2 = new Entry(2, new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "blobhash6") , timestamp, "key6", EntryType.system);
        Entry systemEntry3 = new Entry(3, new HashValue(SHA256, "itemhash7"), new HashValue(SHA256, "blobhash7"), timestamp, "key5", EntryType.system);
        Item item5 = new Item(new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "itemhash5-blob-hash"), objectMapper.readTree("{\"field\":\"value3\"}"));
        Item item6 = new Item(new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "itemhash6-blob-hash"), objectMapper.readTree("{\"field\":\"value4\"}"));
        Item item7 = new Item(new HashValue(SHA256, "itemhash7"), new HashValue(SHA256, "itemhash7-blob-hash"), objectMapper.readTree("{\"field\":\"value4\"}"));

        batchedPostgresDataAccessLayer.appendEntry(userEntry1);
        batchedPostgresDataAccessLayer.appendEntry(userEntry2);
        batchedPostgresDataAccessLayer.appendEntry(userEntry3);
        batchedPostgresDataAccessLayer.appendEntry(userEntry4);
        batchedPostgresDataAccessLayer.addItem(item1);
        batchedPostgresDataAccessLayer.addItem(item2);
        batchedPostgresDataAccessLayer.addItem(item3);
        batchedPostgresDataAccessLayer.addItem(item4);

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry2);
        batchedPostgresDataAccessLayer.appendEntry(systemEntry3);
        batchedPostgresDataAccessLayer.addItem(item5);
        batchedPostgresDataAccessLayer.addItem(item6);
        batchedPostgresDataAccessLayer.addItem(item7);

        Record userRecord1 = new Record(userEntry1, item1);
        Record userRecord2 = new Record(userEntry3, item3);
        Record userRecord3 = new Record(userEntry4, item4);
        Record systemRecord1 = new Record(systemEntry2, item6);
        Record systemRecord2 = new Record(systemEntry3, item7);

        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.user, "field", "value1").size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.user, "field", "value1"), contains(userRecord1));
        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.user, "field", "value2").size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.user, "field", "value2"), contains(userRecord3, userRecord2));
        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.user, "field", "value3").size(), is(0));
        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.user, "invalid-field", "value").size(), is(0));

        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.system, "field", "value3").size(), is(0));
        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.system, "field", "value4").size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.system, "field", "value4"), contains(systemRecord2, systemRecord1));
        assertThat(batchedPostgresDataAccessLayer.findMax100RecordsByKeyValue(EntryType.system, "invalid-field", "value").size(), is(0));
    }

    @Test
    public void getEntryCanGetFromMemoryAndDB() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry entry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);

        postgresDataAccessLayer.appendEntry(entry1); // entry goes to database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(1)); // value in database

        batchedPostgresDataAccessLayer.appendEntry(entry2); // entry goes to memory
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(1)); // still only one value in database

        assertThat(batchedPostgresDataAccessLayer.getEntry(1), is(Optional.of(entry1)));
        assertThat(batchedPostgresDataAccessLayer.getEntry(2), is(Optional.of(entry2)));
        assertThat(batchedPostgresDataAccessLayer.getEntry(3), is(Optional.empty()));

        batchedPostgresDataAccessLayer.writeBatchesToDatabase();
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(2)); // both values in database
    }

    @Test
    public void getEntriesGetsFromMemoryIfAllEntriesInMemory() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry2 = new Entry(1, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry entry3 = new Entry(2, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "itemhash3"), timestamp, "key3", EntryType.user);

        batchedPostgresDataAccessLayer.appendEntry(entry1); // entry goes to memory
        batchedPostgresDataAccessLayer.appendEntry(entry2); // entry goes to memory
        batchedPostgresDataAccessLayer.appendEntry(entry3); // entry goes to memory
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(0)); // nothing in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database

        assertThat(batchedPostgresDataAccessLayer.getAllEntries().size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.getAllEntries(), contains(entry3, entry2));
        assertThat(batchedPostgresDataAccessLayer.getEntries(2, 1).size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.getEntries(2, 1), contains(entry3));
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(0)); // nothing in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database
    }

    @Test
    public void getEntriesGetsFromDBIfEntriesAreNotInMemory() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry2 = new Entry(1, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry entry3 = new Entry(2, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "itemhash3"), timestamp, "key3", EntryType.user);

        postgresDataAccessLayer.appendEntry(entry1); // entry goes to database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(1)); // value in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database

        batchedPostgresDataAccessLayer.appendEntry(entry2); // entry goes to memory
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(1)); // value in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database

        assertThat(batchedPostgresDataAccessLayer.getAllEntries().size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.getAllEntries(), contains(entry2));

        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(1)); // value in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(1)); // value in database

        batchedPostgresDataAccessLayer.appendEntry(entry3); // entry goes to memory
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(1)); // value in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(1)); // value in database

        assertThat(batchedPostgresDataAccessLayer.getEntries(2, 1).size(), is(1));
        assertThat(batchedPostgresDataAccessLayer.getEntries(2, 1), contains(entry3));
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(1)); // value in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(1)); // values in database
    }

    @Test
    public void getEntriesByKeyGetsFromMemoryIfAllEntriesInMemory() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry2 = new Entry(1, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry entry3 = new Entry(2, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "itemhash3"), timestamp, "key2", EntryType.user);

        batchedPostgresDataAccessLayer.appendEntry(entry1); // entry goes to memory
        batchedPostgresDataAccessLayer.appendEntry(entry2); // entry goes to memory
        batchedPostgresDataAccessLayer.appendEntry(entry3); // entry goes to memory
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(0)); // nothing in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database

        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key2").size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key2"), contains(entry2, entry3));
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(0)); // nothing in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database
    }

    @Test
    public void getEntriesByKeyGetsFromDBIfEntriesAreNotInMemory() {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry entry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.system);
        Entry entry2 = new Entry(1, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry entry3 = new Entry(2, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "itemhash3"), timestamp, "key2", EntryType.user);

        postgresDataAccessLayer.appendEntry(entry1); // entry goes to database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(1)); // value in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database

        batchedPostgresDataAccessLayer.appendEntry(entry2); // entry goes to memory
        batchedPostgresDataAccessLayer.appendEntry(entry3); // entry goes to memory
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(1)); // value in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database

        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key2").size(), is(2));
        assertThat(batchedPostgresDataAccessLayer.getAllEntriesByKey("key2"), contains(entry2, entry3));
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(1)); // value in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(2)); // values in database
    }

    @Test
    public void getRecordGetsFromMemoryIfAllDataInMemory() throws IOException {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry userEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry userEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry userEntry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key2", EntryType.user);
        Item item1 = new Item(new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "itemhash1-blob-hash"), objectMapper.readTree("{\"field\":\"value1\"}"));
        Item item2 = new Item(new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "itemhash2-blob-hash"), objectMapper.readTree("{\"field\":\"value2\"}"));
        Item item3 = new Item(new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "itemhash3-blob-hash"), objectMapper.readTree("{\"field\":\"value3\"}"));

        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "blobhash4"), timestamp, "key5", EntryType.system);
        Entry systemEntry2 = new Entry(2, new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "blobhash5"), timestamp, "key6", EntryType.system);
        Entry systemEntry3 = new Entry(3, new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "blobhash6"), timestamp, "key5", EntryType.system);
        Item item4 = new Item(new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "itemhash4-blob-hash"), objectMapper.readTree("{\"field\":\"value4\"}"));
        Item item5 = new Item(new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "itemhash5-blob-hash"), objectMapper.readTree("{\"field\":\"value5\"}"));
        Item item6 = new Item(new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "itemhash6-blob-hash"), objectMapper.readTree("{\"field\":\"value6\"}"));

        batchedPostgresDataAccessLayer.appendEntry(userEntry1); // entry goes to memory
        batchedPostgresDataAccessLayer.appendEntry(userEntry2); // entry goes to memory
        batchedPostgresDataAccessLayer.appendEntry(userEntry3); // entry goes to memory
        batchedPostgresDataAccessLayer.addItem(item1); // item goes to memory
        batchedPostgresDataAccessLayer.addItem(item2); // item goes to memory
        batchedPostgresDataAccessLayer.addItem(item3); // item goes to memory

        batchedPostgresDataAccessLayer.appendEntry(systemEntry1); // entry goes to memory
        batchedPostgresDataAccessLayer.appendEntry(systemEntry2); // entry goes to memory
        batchedPostgresDataAccessLayer.appendEntry(systemEntry3); // entry goes to memory
        batchedPostgresDataAccessLayer.addItem(item4); // item goes to memory
        batchedPostgresDataAccessLayer.addItem(item5); // item goes to memory
        batchedPostgresDataAccessLayer.addItem(item6); // item goes to memory

        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(0));// nothing in database

        Record userRecord1 = new Record(userEntry1, item1);
        Record userRecord2 = new Record(userEntry3, item3);
        Record systemRecord1 = new Record(systemEntry2, item5);
        Record systemRecord2 = new Record(systemEntry3, item6);

        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.user, "key1"), is(Optional.of(userRecord1)));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.user, "key2"), is(Optional.of(userRecord2)));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.user, "key3"), is(Optional.empty()));

        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.system, "key1"), is(Optional.empty()));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.system, "key5"), is(Optional.of(systemRecord2)));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.system, "key6"), is(Optional.of(systemRecord1)));

        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(0)); // nothing in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(0)); // nothing in database
    }

    @Test
    public void getRecordGetsFromDBIfDataNotInMemory() throws IOException {
        Instant timestamp = Instant.now().truncatedTo(ChronoUnit.SECONDS);
        Entry userEntry1 = new Entry(1, new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "blobhash1"), timestamp, "key1", EntryType.user);
        Entry userEntry2 = new Entry(2, new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "blobhash2"), timestamp, "key2", EntryType.user);
        Entry userEntry3 = new Entry(3, new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "blobhash3"), timestamp, "key2", EntryType.user);
        Item item1 = new Item(new HashValue(SHA256, "itemhash1"), new HashValue(SHA256, "itemhash1-blob-hash"), objectMapper.readTree("{\"field\":\"value1\"}"));
        Item item2 = new Item(new HashValue(SHA256, "itemhash2"), new HashValue(SHA256, "itemhash2-blob-hash"), objectMapper.readTree("{\"field\":\"value2\"}"));
        Item item3 = new Item(new HashValue(SHA256, "itemhash3"), new HashValue(SHA256, "itemhash3-blob-hash"), objectMapper.readTree("{\"field\":\"value3\"}"));

        Entry systemEntry1 = new Entry(1, new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "blobhash4"), timestamp, "key5", EntryType.system);
        Entry systemEntry2 = new Entry(2, new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "blobhash5"), timestamp, "key6", EntryType.system);
        Entry systemEntry3 = new Entry(3, new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "blobhash6"), timestamp, "key5", EntryType.system);
        Item item4 = new Item(new HashValue(SHA256, "itemhash4"), new HashValue(SHA256, "itemhash4-blob-hash"), objectMapper.readTree("{\"field\":\"value4\"}"));
        Item item5 = new Item(new HashValue(SHA256, "itemhash5"), new HashValue(SHA256, "itemhash5-blob-hash"), objectMapper.readTree("{\"field\":\"value5\"}"));
        Item item6 = new Item(new HashValue(SHA256, "itemhash6"), new HashValue(SHA256, "itemhash6-blob-hash"), objectMapper.readTree("{\"field\":\"value6\"}"));

        postgresDataAccessLayer.appendEntry(userEntry1); // entry goes to database
        postgresDataAccessLayer.appendEntry(userEntry2); // entry goes to database
        batchedPostgresDataAccessLayer.appendEntry(userEntry3); // entry goes to memory
        postgresDataAccessLayer.addItem(item1); // item goes to database
        postgresDataAccessLayer.addItem(item2); // item goes to database
        batchedPostgresDataAccessLayer.addItem(item3); // item goes to memory

        postgresDataAccessLayer.appendEntry(systemEntry1); // entry goes to database
        postgresDataAccessLayer.appendEntry(systemEntry2); // entry goes to database
        batchedPostgresDataAccessLayer.appendEntry(systemEntry3); // entry goes to memory
        postgresDataAccessLayer.addItem(item4); // item goes to database
        postgresDataAccessLayer.addItem(item5); // item goes to database
        batchedPostgresDataAccessLayer.addItem(item6); // item goes to memory

        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(2)); // nothing in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(2));// nothing in database

        Record userRecord1 = new Record(userEntry1, item1);
        Record userRecord2 = new Record(userEntry3, item3);
        Record systemRecord1 = new Record(systemEntry2, item5);
        Record systemRecord2 = new Record(systemEntry3, item6);

        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.user, "key1"), is(Optional.of(userRecord1)));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.user, "key2"), is(Optional.of(userRecord2)));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.user, "key3"), is(Optional.empty()));

        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.system, "key1"), is(Optional.empty()));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.system, "key5"), is(Optional.of(systemRecord2)));
        assertThat(batchedPostgresDataAccessLayer.getRecord(EntryType.system, "key6"), is(Optional.of(systemRecord1)));

        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.user), is(2)); // nothing in database
        assertThat(postgresDataAccessLayer.getTotalEntries(EntryType.system), is(2));// nothing in database
    }
}

redpajama_set_name: RedPajamaGithub


text:
Il futuro modello dominante di mediazione | Dal corrispondente ISCT Dan Simon (USA)
I estimate it took me 5 years of trying until I fully embraced the transformative perspective. I had started out mediating by assuming my job was to uncover underlying interests, then help both sides figure out how to get as much of what they wanted as possible, and help them accept that they couldn't get everything they wanted. When I started mediating, I saw hostility and distrust between the parties as impediments to a solution, but they didn't hold much interest beyond that. Now that I see things from the transformative perspective, that hostility and distrust are where the action is.
To help clarify this change of focus, I'll walk through how we explore it in transformative mediation trainings. In our basic mediation courses, we start by asking participants to think back to the worst conflict they've been involved in, to focus on the worst moment of that conflict, and to describe what was so bad about that worst moment. Common answers include that they felt powerless, out-of-control, overwhelmed, less competent than usual, as if they were talking to a brick wall, misunderstood, and shocked that the other person could act this way.
From there we distill those experiences down to their essences. We say that many of the words used, such as powerless, out-of-control, overwhelmed, and less competent, can be understood as variations on a sense of relative "weakness" – and we say that such concepts as brick wall, misunderstood, and shocked at the other's behavior can be distilled down to "self-absorption". (Self-absorption is always hard for people to cop to – so we point out that when one is feeling weak and vulnerable it's entirely understandable that one would be less able to empathize, less understanding, and less compassionate. It's natural that, compared to our usual state, we're self-absorbed at those worst moments.).
Next we describe the vicious cycle that these experiences create within us. We notice that in those worst conflict moments we don't know what to do, so we focus intensely on that, as we focus on that, we remain less able to pay attention to or understand the other person, as we continue to deal with this person we don't understand, we feel weaker than ever, and so on. And when you add to the mix that the other person may be caught in the same vicious cycle, a vivid picture emerges of what we call the "Destructive Conflict Cycle". I suggest that we're all familiar with examples of the Destructive Cycle in our own lives, and we're aware of extreme examples in stories of litigation that costs far more than either side can hope to gain, in suicide bombings, and in murder-suicides. In all of these stories, the desperate efforts to regain a sense of power can destroy both the other party and oneself.
From there we talk about what an improvement to that Destructive Cycle would look like. We say that a sense of strength would be an improvement over a sense of weakness. And, on the other side of the equation, the ability to be responsive to the other party would be an improvement over being self-absorbed (sometimes participants object, saying that when the other party is pure evil, responsiveness is not an improvement – to which we reply that, at the very least, it's preferable to be able to deal with evil effectively, as opposed to in a way that only hurts ourselves – in extreme cases, responsiveness may mean clarity that we need to end our dealings with the other party – in other cases it may turn out that the other side wasn't quite as evil as they seemed). We call the movement from weakness to strength the Empowerment Shift; and we call the progress from self-absorption to responsiveness the Recognition Shift.
The next step in the training is to gain a deeper grasp of what empowerment shifts and recognition shifts look like. Often by observing a transformative mediation demonstration, we see parties become calmer and clearer (Empowerment Shift) and we see them turn toward each other and genuinely listen (Recognition Shift). We notice that Empowerment Shifts can manifest themselves in clearer articulation of needs, in a new idea emerging, or in focusing on a new topic that seems important. We see that Recognition Shifts take the form of acknowledging some truth in the other party's perspective, in offering suggestions that address the other party's concerns, in expressing appreciation of the other party, and in proposing viable solutions.
Once we've become clear about what these shifts look like; and once we've gained confidence that these sorts of shifts can and do happen, we turn our attention to how a mediator can be most helpful in facilitating them.
For many who study transformative mediation, it's hard to focus on clients' interaction (which, as discussed in Part I, is characterized by a sense of weakness and self-absorption in relation to each other)- we're so accustomed to thinking ahead to possible solutions to their problem. So transformative mediation trainings give participants opportunities to experience empowerment and recognition shifts themselves. In one exercise, we have pairs of participants take turns talking to each other about a real life dilemma they're facing. We instruct the listening partner to help the talking partner gain clarity but without the listening partner being directive. In 15 minutes of talking, the participants report that talking caused them to see their dilemma differently. The dilemma was put in perspective, either it became less troubling, or the opposite, it became clearer just what a big deal the dilemma was. Or sometimes the talker realizes that they actually already know how to handle their dilemma. Other times they realize that they had been focused on the wrong part of the problem and they get clearer about what aspect of it really matters. Nearly always, they report some sort of progress. That progress is an empowerment shift.
Training participants experience recognition shifts later in the training, when they role play a conflict scenario. When they play the role of a disputant, they notice that during the mediation they have insights into where the other side is coming from, or they realize that the other person isn't quite as bad as they seemed, or they feel genuine empathy for the other person.
So with some understanding of what empowerment and recognition shifts look like and feel like, we can turn our attention to what the transformative mediator does to facilitate those shifts.
There are three core activities that we transformative mediators do constantly while mediating. (1) Attend to the parties with a microfocus on their interaction (2) Monitor ourselves to make sure we're remaining true to our intention to support the parties in their efforts and (3) Respond to opportunities for empowerment and recognition shifts in ways that support the parties' efforts.
Attending to the Parties
It's almost a cliché that pure listening is hard and happens very rarely. But it's true. There are so many distractions that a listener contends with that come from the listener's own mind: planning what to say next, noticing the flaws in the talker's logic, thinking about how to solve the talker's problem, thinking about what information would help the talker, thinking about what we want for lunch, etc. So the skill of purely listening to what the talker is saying and how they're saying it is not easily mastered. And it's a skill that many professionals aren't accustomed to practicing, since we're used to feeling like we need to analyze and evaluate, so we can offer a helpful opinion. But in the transformative model our intention is to purely listen.
Attending to the parties is, itself, helpful at supporting parties' efforts at making shifts. To focus our attention on the parties is to behave consistently with the reality that empowerment and recognition shifts happen within and between the parties – we mediators aren't the point – the parties are. Our attention to the parties supports the parties' efforts at paying attention to themselves and each other. As the participants in our earlier training exercise discovered, just being listened to can be empowering.
Monitoring Our Own Intentions
Many good intentions, other than pure support of the parties' efforts, naturally arise in us as we listen to the parties. We want to solve their problem, to protect potential victims, to help them avoid a mistake, to share our knowledge that seems very relevant, even to tell a timely joke. So vigilance about our own intentions is necessary to make sure that whatever we do in the mediation is consistent with our purpose, to support the parties' own efforts at making empowerment and recognition shifts. In the trainings, we spend time exploring the sources of these other intentions, so we can recognize them when they arise.
Responding to Opportunities
Mindful of our intention, we do and say things that are consistent with it. The specific moves we make (things we say or don't say) depend entirely on the context of the conversation. We make every effort to enhance the conversation by acknowledging what the parties have said, giving them additional opportunities to clarify what's been said, and giving them the opportunity to decide what comes next. It would be misleading to name those skills outside of the context of a training, because it might appear that doing a certain skill, say reflecting, would be doing transformative mediation. But each skill is only transformative mediation if it's done consistently with the pure intention to support the parties in their efforts at deliberation and perspective-taking.
The Biggest Challenges
For me, the biggest challenge to adopting the transformative approach was my ego. I like everyone to know how smart, wise, funny and cool I am. I don't get to show off much of that while I'm doing transformative mediation. (Come to think of it, maybe I do seem cool to clients, because I'm so non-judgmental and supportive). Also, especially when mediation has gone very well, I'd like some credit for it. But often, after a particularly powerful mediation session, the parties are understandably focused on how much better they feel about the situation, about themselves, and about each other – they aren't so focused on how masterful the mediator was.
For others who explore practicing transformative mediation, the big challenge seems to be difficulty believing that parties have the desire and capacity to move toward strength and responsiveness. Especially if one comes from the world of litigation, where clients are assumed to be purely self-interested, it's an extreme shift to start to see the relational aspects of conflict. Litigators see hostility as either an attempt to maximize one's own gain, or when it's too extreme, they see it as an irrational part of human nature that clients should be advised to overcome. Transformative mediators assume that same hostility is a natural part of human conflict, a manifestation of weakness and self-absorption. And we see the distress that accompanies the hostility as evidence that the client would rather be in a state of strength and responsiveness. And we know we can help with that.
Source: Dan Simon


Well, this is an interesting sight to come home to!
The last thing you're expecting to see when you hop off of the school bus at the end of the day is a family of dinosaurs waiting for you, but that's exactly the surprise that was in store for one young girl. Her entire family, aside from one person holding the camera, dressed up in dinosaur costumes and waited to greet her as the school bus rolled in to the bus stop.
That means four giant T-Rexs are what she saw as soon as she stepped off the bus. She didn't seem to be expecting the dinosaurs, but she was the only kid to get off at the stop, so she must have known it was her family. We can't imagine what she was thinking as she saw this sight out of the bus windows!
As soon as she was able to, she took off running, making this a game of chase. Most people probably wouldn't react much differently to seeing a clan of T-Rex.
This silly family prank will make you smile, and potentially even give you some ideas to surprise your kids, too. Halloween is right around the corner, after all.
Apparently, this isn't the first time a parent has used the dinosaur costume trick at the bus stop, either. One mom was very emotional while sending her daughter off to kindergarten, so she decided to use the costume as a way to get a laugh and hide any tears that did escape.
It worked out great because her daughter is also a huge dinosaur fan. Win-win!
You can find inflatable unisex dinosaur costumes on Amazon, just in case you're interested in dressing the entire family up as dinosaurs this Halloween. Or you know, anytime, really.
Dinosaur costumes come in sizes for adults and kids and range from $38 to $112. Where you decide to wear it is up to you!


The search for the fountain of youth has been a quest for many years. Consumers pay millions of dollars every year in hopes of finding the magic solution or remedy to aging. Some people resort to surgery to remain having a youthful appearance. Instead of spending money on the painful and expensive surgery, you can age gracefully with some attention to the needs of your body so you can age naturally and beautifully.
Start using sunblock with SPF everyday to prevent sun damage and skin peeling. Use formulated sunblock for your face that allows you to apply makeup over the lotion.
Moisturize your skin on daily. The benefits of moisturizers help to hydrate the skin, replenish the skin cells, reduce wrinkles, and create softer skin. There are quality moisturizers on the market that work effectively without the high price associated with many moisturizers.
Exercise regularly to improve your health. Base your exercise regimen on your health conditions as you may have limitations. Use stretching exercises if you have difficulties with other forms of exercise. Use yoga and Pilates to increase your joint pliability.
Add meditation, yoga, or another stress relieving exercise to your life. When you learn to relax and reduce the stress in your life, you remove the risks of heart disease and stroke. This increases your chances of living longer.
Add walking to your exercise program. Walk for thirty minutes four times a week. Buy walking shoes for proper support of your feet and back to lessen the risks of damages and possible injuries.
Eat a balance low fat low calorie diet filled with nutrients and antioxidants to help your body keep the youthful skin and buoyancy. Eat foods that contain acai and dark green leafy vegetables that aid the body's natural ability to age gracefully while they help to build your immunity.
Limit your intake of fats and sugars with your foods and beverages. Drink water to keep your body hydrated. Eight 8-ounce glasses of water a day is the medical recommendation for optimal water intake. Reduce your consumption of coffee with added creams and sugar, sodas, teas with the sugars, and other drinks high in sugar contents.
Add a multi-vitamin and supplement to your daily regimen. As you age, your body needs different levels of essential vitamins and minerals. The age appropriate vitamins and supplements will help you have the right amounts daily so you can age gracefully with your healthy body and immune system.
Visit your physician for a regular checkup. Have your cholesterol, blood pressure, and blood sugars checked. You doctor will have blood work done to monitor the level of your health and to help prevent any possible medical conditions. Discuss with your doctor any health issues you may be experiencing so they can be treated.


text:
The Pontiff of No Return
The most important thing about Pope Francis: He's blowing up the Catholic Church's bridge back to medieval pomp, purity, and authority.
Benjamin J. Dueholm
Pope Francis among the people at St. Peter's Square. (PHOTO: EDGAR JIMENEZ/WIKIMEDIA COMMONS)
"I am a really, really undisciplined person:" This confession, coming from the spiritual leader of the world's 1.2 billion Catholics in a much-discussed, lengthy, and gripping interview last week, was not especially surprising to those who have followed the young papacy of Francis closely. From the moment of his election, stories have bubbled up about the unscripted papacy—about phone calls out of the blue to ordinary Catholics, about a mass being moved at the last minute to a juvenile detention center, about a member of the Swiss Guard being ordered to have a seat while protecting the new pontiff. In early statements, he rather mockingly disparaged both Catholic traditionalists ("restorationist") and Catholic radicals ("pantheist") and made a remark about salvation and atheists that Vatican spokesmen, like characters in a palace comedy, later had to clarify with a "what the Czar meant to say" sort of statement. "It's just Francis being Francis," I found myself starting to think, with a mixture of delight and suspense for what his papacy might entail.
From the beginning, the contrast with his predecessor could not have been more stark: Benedict was meticulous in his public statements, austere in demeanor, and took a rococo approach to vestments. Francis is improvisational, intimate, and dons more basic wear. He has famously eschewed the papal apartment for a room in the Vatican guest house. He drives an old Renault.*
It's true that these early departures were—as many progressives who were reluctant to place their faith in the new pontiff pointed out—mostly matters of style. But with the papacy as with few other offices, style truly is substance. The pope plays a uniquely visible function: representing Christ (and the church) to the world. And it was clear early on that the Christ represented by the Archbishop of Buenos Aires would cut a different figure than the Christ represented by the man formerly known as Joseph Ratzinger.
If the next pope drives an old Renault, no one will care; and if he brings back all the medieval trappings he'll look foolish.
It was less obvious where the new pope stood on doctrinal issues. Until this week it was still possible to imagine Francis wrapping conventional theological views in a charmingly chaotic pastoral style. But the 12,000-word interview, conducted over three sessions and approved in its Italian text by the Vatican, closes that possibility definitively. It is a document that may fairly be called unprecedented. In discussing topics that range from doctrine and spirituality to art and music, Francis gives clear and fulsome voice to the long-muted tradition of theologically progressive Catholicism. On homosexuality, the role of women, and the collegial relationship between the pope and other bishops, Francis spoke carefully but encouragingly for the possibility of development. Doubt and the openness of faith are celebrated; the pope, himself a Jesuit, says that a Jesuit "must be a person whose thought is incomplete." That there are turns ahead in Catholic faith and life, turns ardently hoped and worked for by some and resisted by others, is a possibility Francis leaves pointedly open.
But more striking than anything he has said about hot-button issues was the way in which he depicted the development of teaching and thought within the church. In facing the world, the church can't let itself retreat into a "small chapel" for "a small group of selected people"—a clear rebuke to the many advocates for a "smaller, purer church." "We must not reduce the bosom of the universal church to a nest protecting our mediocrity." In an interview full of startling moments, this one stands out for what will likely become a rhetorical trademark of the Francis papacy: he identifies the impulse to separate from and reject the secularized society not with an admirable if misguided holiness, but with mediocrity. This mediocrity seeks only to discipline and correct a "barbarian" world, and to put the church into a posture of defense. But this, Francis insists, is exactly wrong. "There are ecclesiastical rules and precepts that were once effective, but now they have lost value or meaning." There is a difference between the genius of Thomas Aquinas and the "bankrupt" commentators who imitated him. "Even the forms for expressing truth can be multiform," Francis says, citing the Winged Victory of Samothrace, Caravaggio, Chagall, and Dali, "and this is indeed necessary for the transmission of the Gospel in its timeless meaning." "In thinking of the human being, therefore, the church should strive for genius and not for decadence."
The interview met with a thunderous cheer from many quarters, believing, unbelieving, differently-believing, and estranged, and took a variety of forms. The New Yorker's Alex Ross singled out a comment about Wagner's Parsifal. A friend of mine who hasn't been to mass in years confessed a desire to go "old-school Irish Catholic and hang a picture of the Pope in my living room." It is easy to exaggerate the radicalism of his statements; the very next day he condemned abortion as an extension of the "indifference and solitude" to which we condemn the world's poor. The ideas expressed in the interview are not new or unorthodox. They are thrilling to theological progressives and discouraging to church traditionalists less on their own account than because of the person giving them voice.
Francis inspires admiration or anger because he is supposed to inspire awe. The pope who began his papacy threatening to become a cassocked version of Warren Beatty's Senator Bulworth has emerged quickly as a more classical, solid figure of reversal. A pope is not expected to wash the feet of female Muslim prisoners, to drive a beater, to live in a guest house, or to compare the church's doctrine of humanity to the movement from classical sculpture to Dali. The irony of Francis' young tenure in the chair of Peter is that he has become a hero (or a villain) by subverting the expectations of the very role that makes his utterances significant.
This subversion is unrepeatable. "I feel sorry for whoever has to be pope after Francis," a theologian friend remarked to me. Having shown that a pope can perfectly well break down the hallowed distance between himself and the people, speak candidly and publicly about his own failings, and fearlessly push his church toward embracing "the freshness and fragrance of the gospel" over a "disjointed multitude of doctrines to be imposed insistently," Francis will leave his successor accountable either to continue doing so or to revert to a fustian papal model that will appear not so much grand and ancient as nostalgic and, to borrow Francis' word, mediocre. If the next pope drives an old Renault, no one will care; and if he brings back all the medieval trappings he'll look foolish.
In that sense, Francis has already made himself a pivotal figure. In answering his predecessor's departing challenge to lead the church into a complex modern world, Francis has changed his office and his church. What remains to be seen is whether this modestly-styled, thrilling, frustrating papacy will retain enough awe to effect the renovation it promises.
*UPDATE 09/25/2013: This post originally stated that Pope Francis drives a Peugeot. In fact, he drives a Renault.
Catholic ChurchPope FrancisVaticanCulture
The One About the Pope's Mother
What Pope Francis' off-the-cuff comments about punching the murdered Charlie Hebdo cartoonists can tell us about the long history of the Catholic Church's relationship with secularism.
Why Pope Francis' Recent Acceptance of Gay Priests Shouldn't Surprise You
The Catholic Church changes its teachings all the time.
New, Chill Pope Still Hasn't Convinced You to Go to Mass
The "Pope Francis Effect" hasn't caught on in the U.S., according to a Pew study.
Pope Francis Addresses Immigration Issues During World Youth Day in Panama (in Photos)
The Catholic Church's youth rally has drawn 200,000 pilgrims from around the world to Panama City.
Was Retiring Pope Benedict a Liberal?
Pope Benedict XVI was typecast in American eyes as 'God's Rottweiler,' an unyielding champion of the Catholic Church's conservative side. But the real Benedict had more dimensions, some of them at odds with with his North American stereotype.
Pope Francis Takes on Wall Street
In a new essay, the pope calls for intensified regulation of the "sophisticated technologies" of financial markets.


Custom Log Home Design Services from Footprint Log Homes will take you through the process of designing your home, so that you will be ready to start construction.
There are many different ways to communicate your ideas, wishes and dreams of the perfect home be it Log, Timber Frame, Swedish Cope or Hybrid (a mixture of different materials). Check out our Product Line to find the right one for you.
You may have a sketch showing the rough layout of rooms with dimensions and the square footage of the home. You may even just have a concept drawn on a napkin. One of our clients had a scrap book filled with ideas from when she was a child. You may choose to pick a floor plan from our web site or a concept you may have seen somewhere and then customize it to your liking.
Whatever stage you are at, the Footprint Log Homes design service will help you to achieve your goal.
You will receive views in both 2 and 3D of the log/timber work and the elevations. Customizing a home does not mean more money! Contact us to find out more.