text:
"""Tests for vumi_message_store.migrators."""

from twisted.internet.defer import inlineCallbacks

from vumi.message import format_vumi_date
from vumi.tests.helpers import VumiTestCase, MessageHelper, PersistenceHelper

from vumi_message_store.tests.old_models import (
    OutboundMessageVNone, InboundMessageVNone, EventVNone, BatchVNone,
    OutboundMessageV1, InboundMessageV1, OutboundMessageV2,
    InboundMessageV2, OutboundMessageV3, InboundMessageV3, EventV1,
    OutboundMessageV4, InboundMessageV4)
from vumi_message_store.memory_backend_manager import (
    FakeRiakState, FakeMemoryRiakManager)
from vumi_message_store.models import (
    to_reverse_timestamp,
    InboundMessage as InboundMessageV5,
    OutboundMessage as OutboundMessageV5,
    Event as EventV2)

def mws_value(msg_id, event, status):
    return "%s$%s$%s" % (msg_id, event['timestamp'], status)

def bwsr_value(batch_id, event, status):
    reverse_ts = to_reverse_timestamp(format_vumi_date(event['timestamp']))
    return "%s$%s$%s" % (batch_id, reverse_ts, status)

def bwt_value(batch_id, msg):
    return "%s$%s" % (batch_id, msg['timestamp'])

def bwa_in_value(batch_id, msg):
    return "%s$%s$%s" % (batch_id, msg['timestamp'], msg['from_addr'])

def bwa_out_value(batch_id, msg):
    return "%s$%s$%s" % (batch_id, msg['timestamp'], msg['to_addr'])

def bwar_in_value(batch_id, msg):
    reverse_ts = to_reverse_timestamp(format_vumi_date(msg['timestamp']))
    return "%s$%s$%s" % (batch_id, reverse_ts, msg['from_addr'])

def bwar_out_value(batch_id, msg):
    reverse_ts = to_reverse_timestamp(format_vumi_date(msg['timestamp']))
    return "%s$%s$%s" % (batch_id, reverse_ts, msg['to_addr'])

def batch_index(value):
    return ("batches_bin", value)

def bwt_index(value):
    return ("batches_with_timestamps_bin", value)

def bwa_index(value):
    return ("batches_with_addresses_bin", value)

def bwar_index(value):
    return ("batches_with_addresses_reverse_bin", value)

class EventMigratorTestMixin(object):

    def set_up_proxies(self):
        self.event_vnone = self.manager.proxy(EventVNone)
        self.event_v1 = self.manager.proxy(EventV1)
        self.event_v2 = self.manager.proxy(EventV2)

    @inlineCallbacks
    def test_migrate_vnone_to_v1(self):
        """
        A vNone model can be migrated to v1.
        """
        msg = self.msg_helper.make_outbound("outbound")
        msg_id = msg["message_id"]
        event = self.msg_helper.make_ack(msg)
        old_record = self.event_vnone(
            event["event_id"], event=event, message=msg_id)
        yield old_record.save()

        new_record = yield self.event_v1.load(old_record.key)
        self.assertEqual(new_record.event, event)
        self.assertEqual(new_record.message.key, msg_id)

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(new_record.message_with_status, None)
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            ("message_bin", msg_id),
        ]))

        yield new_record.save()
        self.assertEqual(
            new_record.message_with_status, mws_value(msg_id, event, "ack"))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            ("message_bin", msg_id),
            ("message_with_status_bin", mws_value(msg_id, event, "ack")),
        ]))

    @inlineCallbacks
    def test_reverse_migrate_v1_vnone(self):
        """
        A v1 model can be stored in a vNone-compatible way.
        """
        # Configure the manager to save the older message version.
        modelcls = self.event_v1._modelcls
        model_name = "%s.%s" % (modelcls.__module__, modelcls.__name__)
        self.manager.store_versions[model_name] = None

        msg = self.msg_helper.make_outbound("outbound")
        msg_id = msg["message_id"]
        event = self.msg_helper.make_ack(msg)
        new_record = self.event_v1(
            event["event_id"], event=event, message=msg_id)
        yield new_record.save()

        old_record = yield self.event_vnone.load(new_record.key)
        self.assertEqual(old_record.event, event)
        self.assertEqual(old_record.message.key, msg_id)

    @inlineCallbacks
    def test_migrate_vnone_to_v1_index_only_foreign_key(self):
        """
        A vNone model can be migrated to v1 even if it's old enough to still
        have index-only foreign keys.
        """
        msg = self.msg_helper.make_outbound("outbound")
        msg_id = msg["message_id"]
        event = self.msg_helper.make_ack(msg)
        old_record = self.event_vnone(
            event["event_id"], event=event, message=msg_id)

        # Remove the foreign key field from the data before saving it.
        old_record._riak_object.delete_data_field("message")
        yield old_record.save()

        new_record = yield self.event_v1.load(old_record.key)
        self.assertEqual(new_record.event, event)
        self.assertEqual(new_record.message.key, msg_id)

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(new_record.message_with_status, None)
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            ("message_bin", msg_id),
        ]))

        yield new_record.save()
        self.assertEqual(
            new_record.message_with_status, mws_value(msg_id, event, "ack"))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            ("message_bin", msg_id),
            ("message_with_status_bin", mws_value(msg_id, event, "ack")),
        ]))

    @inlineCallbacks
    def test_migrate_v1_to_v2(self):
        """
        A v1 model can be migrated to v2, but the batches field will be empty.
        """
        msg = self.msg_helper.make_outbound("outbound")
        msg_id = msg["message_id"]
        event = self.msg_helper.make_ack(msg)
        old_record = self.event_v1(
            event["event_id"], event=event, message=msg_id)
        yield old_record.save()

        new_record = yield self.event_v2.load(old_record.key)
        self.assertEqual(new_record.event, event)
        self.assertEqual(new_record.message.key, msg_id)
        self.assertEqual(new_record.batches.keys(), [])
        self.assertEqual(new_record.message_with_status, None)
        self.assertEqual(set(new_record.batches_with_statuses_reverse), set())
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            ("message_bin", msg_id),
            ("message_with_status_bin", mws_value(msg_id, event, "ack")),
        ]))

        # Some indexes are only added at save time.
        yield new_record.save()
        self.assertEqual(
            new_record.message_with_status, mws_value(msg_id, event, "ack"))
        self.assertEqual(set(new_record.batches_with_statuses_reverse), set())
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            ("message_bin", msg_id),
            ("message_with_status_bin", mws_value(msg_id, event, "ack")),
        ]))

    @inlineCallbacks
    def test_reverse_migrate_v2_v1(self):
        """
        A v2 model can be stored in a v1-compatible way, but batch information
        is preserved.
        """
        # Configure the manager to save the older message version.
        modelcls = self.event_v2._modelcls
        model_name = "%s.%s" % (modelcls.__module__, modelcls.__name__)
        self.manager.store_versions[model_name] = 1

        msg = self.msg_helper.make_outbound("outbound")
        msg_id = msg["message_id"]
        event = self.msg_helper.make_ack(msg)
        new_record = self.event_v2(
            event["event_id"], event=event, message=msg_id)
        new_record.batches.add_key(u"batch-1")
        yield new_record.save()

        old_record = yield self.event_v1.load(new_record.key)
        self.assertEqual(old_record.event, event)
        self.assertEqual(old_record.message.key, msg_id)
        self.assertEqual(new_record.message_with_status, None)
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            ("message_bin", msg_id),
            ("batches_bin", "batch-1"),
            ("message_with_status_bin", mws_value(msg_id, event, "ack")),
            ("batches_with_statuses_reverse_bin",
             bwsr_value("batch-1", event, "ack")),
        ]))

        # Some indexes are only added at save time.
        yield old_record.save()
        self.assertEqual(
            old_record.message_with_status, mws_value(msg_id, event, "ack"))
        self.assertEqual(old_record._riak_object.get_indexes(), set([
            ("message_bin", msg_id),
            ("batches_bin", "batch-1"),
            ("message_with_status_bin", mws_value(msg_id, event, "ack")),
            ("batches_with_statuses_reverse_bin",
             bwsr_value("batch-1", event, "ack")),
        ]))

        new2_record = yield self.event_v2.load(old_record.key)
        self.assertEqual(new2_record.event, event)
        self.assertEqual(new2_record.message.key, msg_id)
        self.assertEqual(new2_record.batches.keys(), [u"batch-1"])
        self.assertEqual(new2_record.message_with_status, None)
        self.assertEqual(set(new2_record.batches_with_statuses_reverse), set())

class OutboundMessageMigratorTestMixin(object):
    def set_up_proxies(self):
        self.outbound_vnone = self.manager.proxy(OutboundMessageVNone)
        self.outbound_v1 = self.manager.proxy(OutboundMessageV1)
        self.outbound_v2 = self.manager.proxy(OutboundMessageV2)
        self.outbound_v3 = self.manager.proxy(OutboundMessageV3)
        self.outbound_v4 = self.manager.proxy(OutboundMessageV4)
        self.outbound_v5 = self.manager.proxy(OutboundMessageV5)
        self.batch_vnone = self.manager.proxy(BatchVNone)

    @inlineCallbacks
    def test_migrate_vnone_to_v1(self):
        msg = self.msg_helper.make_outbound("outbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.outbound_vnone(
            msg["message_id"], msg=msg, batch=old_batch)
        yield old_record.save()
        new_record = yield self.outbound_v1.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

    @inlineCallbacks
    def test_migrate_vnone_to_v1_without_batch(self):
        msg = self.msg_helper.make_outbound("outbound")
        old_record = self.outbound_vnone(
            msg["message_id"], msg=msg, batch=None)
        yield old_record.save()
        new_record = yield self.outbound_v1.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

    @inlineCallbacks
    def test_migrate_v1_to_v2_no_batches(self):
        msg = self.msg_helper.make_outbound("outbound")
        old_record = self.outbound_v1(msg["message_id"], msg=msg)
        yield old_record.save()
        new_record = yield self.outbound_v2.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

        yield new_record.save()
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

    @inlineCallbacks
    def test_migrate_v1_to_v2_one_batch(self):
        msg = self.msg_helper.make_outbound("outbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.outbound_v1(msg["message_id"], msg=msg)
        old_record.batches.add_key(old_batch.key)
        yield old_record.save()
        new_record = yield self.outbound_v2.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(
            new_record._riak_object.get_indexes(),
            set([batch_index("batch-1")]))

        yield new_record.save()
        self.assertEqual(
            set(new_record.batches_with_timestamps),
            set([bwt_value("batch-1", msg)]))
        self.assertEqual(new_record._riak_object.get_indexes(), set(
            [batch_index("batch-1"), bwt_index(bwt_value("batch-1", msg))]))

    @inlineCallbacks
    def test_migrate_v1_to_v2_two_batches(self):
        msg = self.msg_helper.make_outbound("outbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        old_record = self.outbound_v1(msg["message_id"], msg=msg)
        old_record.batches.add_key(batch_1.key)
        old_record.batches.add_key(batch_2.key)
        yield old_record.save()
        new_record = yield self.outbound_v2.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [batch_1.key, batch_2.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"), batch_index("batch-2")]))

        yield new_record.save()
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
        ]))

    @inlineCallbacks
    def test_migrate_v2_to_v3_no_batches(self):
        msg = self.msg_helper.make_outbound("outbound")
        old_record = self.outbound_v2(msg["message_id"], msg=msg)
        yield old_record.save()
        new_record = yield self.outbound_v3.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

        yield new_record.save()
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

    @inlineCallbacks
    def test_migrate_v2_to_v3_one_batch(self):
        msg = self.msg_helper.make_outbound("outbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.outbound_v2(msg["message_id"], msg=msg)
        old_record.batches.add_key(old_batch.key)
        yield old_record.save()
        new_record = yield self.outbound_v3.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwt_index(bwt_value("batch-1", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(
            set(new_record.batches_with_timestamps),
            set([bwt_value("batch-1", msg)]))
        self.assertEqual(
            set(new_record.batches_with_addresses),
            set([bwa_out_value("batch-1", msg)]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwt_index(bwt_value("batch-1", msg)),
            bwa_index(bwa_out_value("batch-1", msg)),
        ]))

    @inlineCallbacks
    def test_migrate_v2_to_v3_two_batches(self):
        msg = self.msg_helper.make_outbound("outbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        old_record = self.outbound_v2(msg["message_id"], msg=msg)
        old_record.batches.add_key(batch_1.key)
        old_record.batches.add_key(batch_2.key)
        yield old_record.save()
        new_record = yield self.outbound_v3.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [batch_1.key, batch_2.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
            bwa_index(bwa_out_value("batch-1", msg)),
            bwa_index(bwa_out_value("batch-2", msg)),
        ]))

    @inlineCallbacks
    def test_reverse_migrate_v3_to_v2(self):
        """
        A v3 model can be stored in a v2-compatible way.
        """
        # Configure the manager to save the older message version.
        modelcls = self.outbound_v3._modelcls
        model_name = "%s.%s" % (modelcls.__module__, modelcls.__name__)
        self.manager.store_versions[model_name] = 2

        msg = self.msg_helper.make_outbound("outbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        new_record = self.outbound_v3(msg["message_id"], msg=msg)
        new_record.batches.add_key(batch_1.key)
        new_record.batches.add_key(batch_2.key)
        yield new_record.save()

        old_record = yield self.outbound_v2.load(new_record.key)
        self.assertEqual(old_record.msg, msg)
        self.assertEqual(old_record.batches.keys(), [batch_1.key, batch_2.key])

    @inlineCallbacks
    def test_migrate_v3_to_v4_no_batches(self):
        """
        A v3 model with no batches has no extra indexes when migrated to v4.
        """
        msg = self.msg_helper.make_outbound("outbound")
        old_record = self.outbound_v3(msg["message_id"], msg=msg)
        yield old_record.save()
        new_record = yield self.outbound_v4.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

        yield new_record.save()
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

    @inlineCallbacks
    def test_migrate_v3_to_v4_one_batch(self):
        """
        A v3 model with one batch gets one extra index when migrated to v4.
        """
        msg = self.msg_helper.make_outbound("outbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.outbound_v3(msg["message_id"], msg=msg)
        old_record.batches.add_key(old_batch.key)
        yield old_record.save()
        new_record = yield self.outbound_v4.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwt_index(bwt_value("batch-1", msg)),
            bwa_index(bwa_out_value("batch-1", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(
            set(new_record.batches_with_timestamps),
            set([bwt_value("batch-1", msg)]))
        self.assertEqual(
            set(new_record.batches_with_addresses),
            set([bwa_out_value("batch-1", msg)]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse),
            set([bwar_out_value("batch-1", msg)]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwt_index(bwt_value("batch-1", msg)),
            bwa_index(bwa_out_value("batch-1", msg)),
            bwar_index(bwar_out_value("batch-1", msg)),
        ]))

    @inlineCallbacks
    def test_migrate_v3_to_v4_two_batches(self):
        """
        A v3 model with two batches gets two extra indexes when migrated to v4.
        """
        msg = self.msg_helper.make_outbound("outbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        old_record = self.outbound_v3(msg["message_id"], msg=msg)
        old_record.batches.add_key(batch_1.key)
        old_record.batches.add_key(batch_2.key)
        yield old_record.save()
        new_record = yield self.outbound_v4.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [batch_1.key, batch_2.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
            bwa_index(bwa_out_value("batch-1", msg)),
            bwa_index(bwa_out_value("batch-2", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
            bwa_index(bwa_out_value("batch-1", msg)),
            bwa_index(bwa_out_value("batch-2", msg)),
            bwar_index(bwar_out_value("batch-1", msg)),
            bwar_index(bwar_out_value("batch-2", msg)),
        ]))

    @inlineCallbacks
    def test_reverse_migrate_v4_to_v3(self):
        """
        A v4 model can be stored in a v3-compatible way.
        """
        # Configure the manager to save the older message version.
        modelcls = self.outbound_v4._modelcls
        model_name = "%s.%s" % (modelcls.__module__, modelcls.__name__)
        self.manager.store_versions[model_name] = 3

        msg = self.msg_helper.make_outbound("outbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        new_record = self.outbound_v4(msg["message_id"], msg=msg)
        new_record.batches.add_key(batch_1.key)
        new_record.batches.add_key(batch_2.key)
        yield new_record.save()

        old_record = yield self.outbound_v3.load(new_record.key)
        self.assertEqual(old_record.msg, msg)
        self.assertEqual(old_record.batches.keys(), [batch_1.key, batch_2.key])

    @inlineCallbacks
    def test_migrate_v4_to_v5_no_batches(self):
        """
        A v4 model with no batches has no fewer indexes when migrated to v5.
        """
        msg = self.msg_helper.make_outbound("outbound")
        old_record = self.outbound_v4(msg["message_id"], msg=msg)
        yield old_record.save()
        new_record = yield self.outbound_v5.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

        yield new_record.save()
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

    @inlineCallbacks
    def test_migrate_v4_to_v5_one_batch(self):
        """
        A v4 model with one batch gets one fewer index when migrated to v5.
        """
        msg = self.msg_helper.make_outbound("outbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.outbound_v4(msg["message_id"], msg=msg)
        old_record.batches.add_key(old_batch.key)
        yield old_record.save()
        new_record = yield self.outbound_v5.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwa_index(bwa_out_value("batch-1", msg)),
            bwar_index(bwar_out_value("batch-1", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(
            set(new_record.batches_with_addresses),
            set([bwa_out_value("batch-1", msg)]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse),
            set([bwar_out_value("batch-1", msg)]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwa_index(bwa_out_value("batch-1", msg)),
            bwar_index(bwar_out_value("batch-1", msg)),
        ]))

    @inlineCallbacks
    def test_migrate_v4_to_v5_two_batches(self):
        """
        A v4 model with two batches gets two fewer indexes when migrated to v5.
        """
        msg = self.msg_helper.make_outbound("outbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        old_record = self.outbound_v4(msg["message_id"], msg=msg)
        old_record.batches.add_key(batch_1.key)
        old_record.batches.add_key(batch_2.key)
        yield old_record.save()
        new_record = yield self.outbound_v5.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [batch_1.key, batch_2.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwa_index(bwa_out_value("batch-1", msg)),
            bwa_index(bwa_out_value("batch-2", msg)),
            bwar_index(bwar_out_value("batch-1", msg)),
            bwar_index(bwar_out_value("batch-2", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwa_index(bwa_out_value("batch-1", msg)),
            bwa_index(bwa_out_value("batch-2", msg)),
            bwar_index(bwar_out_value("batch-1", msg)),
            bwar_index(bwar_out_value("batch-2", msg)),
        ]))

    @inlineCallbacks
    def test_reverse_migrate_v5_to_v4(self):
        """
        A v5 model can be stored in a v4-compatible way.
        """
        # Configure the manager to save the older message version.
        modelcls = self.outbound_v5._modelcls
        model_name = "%s.%s" % (modelcls.__module__, modelcls.__name__)
        self.manager.store_versions[model_name] = 4

        msg = self.msg_helper.make_outbound("outbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        new_record = self.outbound_v5(msg["message_id"], msg=msg)
        new_record.batches.add_key(batch_1.key)
        new_record.batches.add_key(batch_2.key)
        yield new_record.save()

        old_record = yield self.outbound_v4.load(new_record.key)
        self.assertEqual(old_record.msg, msg)
        self.assertEqual(old_record.batches.keys(), [batch_1.key, batch_2.key])

class InboundMessageMigratorTestMixin(object):

    def set_up_proxies(self):
        self.inbound_vnone = self.manager.proxy(InboundMessageVNone)
        self.inbound_v1 = self.manager.proxy(InboundMessageV1)
        self.inbound_v2 = self.manager.proxy(InboundMessageV2)
        self.inbound_v3 = self.manager.proxy(InboundMessageV3)
        self.inbound_v4 = self.manager.proxy(InboundMessageV4)
        self.inbound_v5 = self.manager.proxy(InboundMessageV5)
        self.batch_vnone = self.manager.proxy(BatchVNone)

    @inlineCallbacks
    def test_migrate_vnone_to_v1(self):
        msg = self.msg_helper.make_inbound("inbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.inbound_vnone(
            msg["message_id"], msg=msg, batch=old_batch)
        yield old_record.save()
        new_record = yield self.inbound_v1.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

    @inlineCallbacks
    def test_migrate_vnone_to_v1_without_batch(self):
        msg = self.msg_helper.make_inbound("inbound")
        old_record = self.inbound_vnone(
            msg["message_id"], msg=msg, batch=None)
        yield old_record.save()
        new_record = yield self.inbound_v1.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

    @inlineCallbacks
    def test_migrate_v1_to_v2_no_batches(self):
        msg = self.msg_helper.make_inbound("inbound")
        old_record = self.inbound_v1(msg["message_id"], msg=msg)
        yield old_record.save()
        new_record = yield self.inbound_v2.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

        yield new_record.save()
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

    @inlineCallbacks
    def test_migrate_v1_to_v2_one_batch(self):
        msg = self.msg_helper.make_inbound("inbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.inbound_v1(msg["message_id"], msg=msg)
        old_record.batches.add_key(old_batch.key)
        yield old_record.save()
        new_record = yield self.inbound_v2.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(
            new_record._riak_object.get_indexes(),
            set([batch_index("batch-1")]))

        yield new_record.save()
        self.assertEqual(
            set(new_record.batches_with_timestamps),
            set([bwt_value("batch-1", msg)]))
        self.assertEqual(new_record._riak_object.get_indexes(), set(
            [batch_index("batch-1"), bwt_index(bwt_value("batch-1", msg))]))

    @inlineCallbacks
    def test_migrate_v1_to_v2_two_batches(self):
        msg = self.msg_helper.make_inbound("inbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        old_record = self.inbound_v1(msg["message_id"], msg=msg)
        old_record.batches.add_key(batch_1.key)
        old_record.batches.add_key(batch_2.key)
        yield old_record.save()
        new_record = yield self.inbound_v2.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [batch_1.key, batch_2.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"), batch_index("batch-2")]))

        yield new_record.save()
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
        ]))

    @inlineCallbacks
    def test_migrate_v2_to_v3_no_batches(self):
        msg = self.msg_helper.make_inbound("inbound")
        old_record = self.inbound_v2(msg["message_id"], msg=msg)
        yield old_record.save()
        new_record = yield self.inbound_v3.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

        yield new_record.save()
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

    @inlineCallbacks
    def test_migrate_v2_to_v3_one_batch(self):
        msg = self.msg_helper.make_inbound("inbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.inbound_v2(msg["message_id"], msg=msg)
        old_record.batches.add_key(old_batch.key)
        yield old_record.save()
        new_record = yield self.inbound_v3.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwt_index(bwt_value("batch-1", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(
            set(new_record.batches_with_timestamps),
            set([bwt_value("batch-1", msg)]))
        self.assertEqual(
            set(new_record.batches_with_addresses),
            set([bwa_in_value("batch-1", msg)]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwt_index(bwt_value("batch-1", msg)),
            bwa_index(bwa_in_value("batch-1", msg)),
        ]))

    @inlineCallbacks
    def test_migrate_v2_to_v3_two_batches(self):
        msg = self.msg_helper.make_inbound("inbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        old_record = self.inbound_v2(msg["message_id"], msg=msg)
        old_record.batches.add_key(batch_1.key)
        old_record.batches.add_key(batch_2.key)
        yield old_record.save()
        new_record = yield self.inbound_v3.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [batch_1.key, batch_2.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
            bwa_index(bwa_in_value("batch-1", msg)),
            bwa_index(bwa_in_value("batch-2", msg)),
        ]))

    @inlineCallbacks
    def test_reverse_migrate_v3_to_v2(self):
        """
        A v3 model can be stored in a v2-compatible way.
        """
        # Configure the manager to save the older message version.
        modelcls = self.inbound_v3._modelcls
        model_name = "%s.%s" % (modelcls.__module__, modelcls.__name__)
        self.manager.store_versions[model_name] = 2

        msg = self.msg_helper.make_inbound("inbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        new_record = self.inbound_v3(msg["message_id"], msg=msg)
        new_record.batches.add_key(batch_1.key)
        new_record.batches.add_key(batch_2.key)
        yield new_record.save()

        old_record = yield self.inbound_v2.load(new_record.key)
        self.assertEqual(old_record.msg, msg)
        self.assertEqual(old_record.batches.keys(), [batch_1.key, batch_2.key])

    @inlineCallbacks
    def test_migrate_v3_to_v4_no_batches(self):
        """
        A v3 model with no batches gets no extra indexes when migrated to v4.
        """
        msg = self.msg_helper.make_inbound("inbound")
        old_record = self.inbound_v3(msg["message_id"], msg=msg)
        yield old_record.save()
        new_record = yield self.inbound_v4.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

        yield new_record.save()
        self.assertEqual(set(new_record.batches_with_timestamps), set([]))
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

    @inlineCallbacks
    def test_migrate_v3_to_v4_one_batch(self):
        """
        A v3 model with one batche gets one extra index when migrated to v4.
        """
        msg = self.msg_helper.make_inbound("inbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.inbound_v3(msg["message_id"], msg=msg)
        old_record.batches.add_key(old_batch.key)
        yield old_record.save()
        new_record = yield self.inbound_v4.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwt_index(bwt_value("batch-1", msg)),
            bwa_index(bwa_in_value("batch-1", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(
            set(new_record.batches_with_timestamps),
            set([bwt_value("batch-1", msg)]))
        self.assertEqual(
            set(new_record.batches_with_addresses),
            set([bwa_in_value("batch-1", msg)]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse),
            set([bwar_in_value("batch-1", msg)]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwt_index(bwt_value("batch-1", msg)),
            bwa_index(bwa_in_value("batch-1", msg)),
            bwar_index(bwar_in_value("batch-1", msg)),
        ]))

    @inlineCallbacks
    def test_migrate_v3_to_v4_two_batches(self):
        """
        A v3 model with two batches gets two extra indexes when migrated to v4.
        """
        msg = self.msg_helper.make_inbound("inbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        old_record = self.inbound_v3(msg["message_id"], msg=msg)
        old_record.batches.add_key(batch_1.key)
        old_record.batches.add_key(batch_2.key)
        yield old_record.save()
        new_record = yield self.inbound_v4.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [batch_1.key, batch_2.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
            bwa_index(bwa_in_value("batch-1", msg)),
            bwa_index(bwa_in_value("batch-2", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwt_index(bwt_value("batch-1", msg)),
            bwt_index(bwt_value("batch-2", msg)),
            bwa_index(bwa_in_value("batch-1", msg)),
            bwa_index(bwa_in_value("batch-2", msg)),
            bwar_index(bwar_in_value("batch-1", msg)),
            bwar_index(bwar_in_value("batch-2", msg)),
        ]))

    @inlineCallbacks
    def test_reverse_migrate_v4_to_v3(self):
        """
        A v4 model can be stored in a v3-compatible way.
        """
        # Configure the manager to save the older message version.
        modelcls = self.inbound_v4._modelcls
        model_name = "%s.%s" % (modelcls.__module__, modelcls.__name__)
        self.manager.store_versions[model_name] = 3

        msg = self.msg_helper.make_inbound("inbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        new_record = self.inbound_v4(msg["message_id"], msg=msg)
        new_record.batches.add_key(batch_1.key)
        new_record.batches.add_key(batch_2.key)
        yield new_record.save()

        old_record = yield self.inbound_v3.load(new_record.key)
        self.assertEqual(old_record.msg, msg)
        self.assertEqual(old_record.batches.keys(), [batch_1.key, batch_2.key])

    @inlineCallbacks
    def test_migrate_v4_to_v5_no_batches(self):
        """
        A v4 model with no batches gets no fewer indexes when migrated to v5.
        """
        msg = self.msg_helper.make_inbound("inbound")
        old_record = self.inbound_v4(msg["message_id"], msg=msg)
        yield old_record.save()
        new_record = yield self.inbound_v5.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

        yield new_record.save()
        self.assertEqual(set(new_record.batches_with_addresses), set([]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([]))

    @inlineCallbacks
    def test_migrate_v4_to_v5_one_batch(self):
        """
        A v4 model with one batch gets one fewer index when migrated to v5.
        """
        msg = self.msg_helper.make_inbound("inbound")
        old_batch = self.batch_vnone(key=u"batch-1")
        old_record = self.inbound_v4(msg["message_id"], msg=msg)
        old_record.batches.add_key(old_batch.key)
        yield old_record.save()
        new_record = yield self.inbound_v5.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [old_batch.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.

        self.assertEqual(
            set(new_record.batches_with_addresses_reverse), set([]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwa_index(bwa_in_value("batch-1", msg)),
            bwar_index(bwar_in_value("batch-1", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(
            set(new_record.batches_with_addresses),
            set([bwa_in_value("batch-1", msg)]))
        self.assertEqual(
            set(new_record.batches_with_addresses_reverse),
            set([bwar_in_value("batch-1", msg)]))
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            bwa_index(bwa_in_value("batch-1", msg)),
            bwar_index(bwar_in_value("batch-1", msg)),
        ]))

    @inlineCallbacks
    def test_migrate_v4_to_v5_two_batches(self):
        """
        A v4 model with two batches gets two fewer indexes when migrated to v5.
        """
        msg = self.msg_helper.make_inbound("inbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        old_record = self.inbound_v4(msg["message_id"], msg=msg)
        old_record.batches.add_key(batch_1.key)
        old_record.batches.add_key(batch_2.key)
        yield old_record.save()
        new_record = yield self.inbound_v5.load(old_record.key)
        self.assertEqual(new_record.msg, msg)
        self.assertEqual(new_record.batches.keys(), [batch_1.key, batch_2.key])

        # The migration doesn't set the new fields and indexes, that only
        # happens at save time.
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwa_index(bwa_in_value("batch-1", msg)),
            bwa_index(bwa_in_value("batch-2", msg)),
            bwar_index(bwar_in_value("batch-1", msg)),
            bwar_index(bwar_in_value("batch-2", msg)),
        ]))

        yield new_record.save()
        self.assertEqual(new_record._riak_object.get_indexes(), set([
            batch_index("batch-1"),
            batch_index("batch-2"),
            bwa_index(bwa_in_value("batch-1", msg)),
            bwa_index(bwa_in_value("batch-2", msg)),
            bwar_index(bwar_in_value("batch-1", msg)),
            bwar_index(bwar_in_value("batch-2", msg)),
        ]))

    @inlineCallbacks
    def test_reverse_migrate_v5_to_v4(self):
        """
        A v5 model can be stored in a v4-compatible way.
        """
        # Configure the manager to save the older message version.
        modelcls = self.inbound_v5._modelcls
        model_name = "%s.%s" % (modelcls.__module__, modelcls.__name__)
        self.manager.store_versions[model_name] = 4

        msg = self.msg_helper.make_inbound("inbound")
        batch_1 = self.batch_vnone(key=u"batch-1")
        batch_2 = self.batch_vnone(key=u"batch-2")
        new_record = self.inbound_v5(msg["message_id"], msg=msg)
        new_record.batches.add_key(batch_1.key)
        new_record.batches.add_key(batch_2.key)
        yield new_record.save()

        old_record = yield self.inbound_v4.load(new_record.key)
        self.assertEqual(old_record.msg, msg)
        self.assertEqual(old_record.batches.keys(), [batch_1.key, batch_2.key])

class TestEventMigrator(EventMigratorTestMixin, VumiTestCase):
    def setUp(self):
        self.persistence_helper = self.add_helper(
            PersistenceHelper(use_riak=True))
        self.manager = self.persistence_helper.get_riak_manager()
        self.add_cleanup(self.manager.close_manager)
        self.msg_helper = self.add_helper(MessageHelper())
        self.set_up_proxies()

class TestOutboundMessageMigrator(OutboundMessageMigratorTestMixin,
                                  VumiTestCase):
    def setUp(self):
        self.persistence_helper = self.add_helper(
            PersistenceHelper(use_riak=True))
        self.manager = self.persistence_helper.get_riak_manager()
        self.add_cleanup(self.manager.close_manager)
        self.msg_helper = self.add_helper(MessageHelper())
        self.set_up_proxies()

class TestInboundMessageMigrator(InboundMessageMigratorTestMixin,
                                 VumiTestCase):
    def setUp(self):
        self.persistence_helper = self.add_helper(
            PersistenceHelper(use_riak=True))
        self.manager = self.persistence_helper.get_riak_manager()
        self.add_cleanup(self.manager.close_manager)
        self.msg_helper = self.add_helper(MessageHelper())
        self.set_up_proxies()

class TestEventMigratorInMemory(EventMigratorTestMixin, VumiTestCase):
    def setUp(self):
        self.state = FakeRiakState(is_sync=False)
        self.add_cleanup(self.state.teardown)
        self.manager = FakeMemoryRiakManager(self.state)
        self.msg_helper = self.add_helper(MessageHelper())
        self.set_up_proxies()

class TestOutboundMessageMigratorInMemory(OutboundMessageMigratorTestMixin,
                                          VumiTestCase):
    def setUp(self):
        self.state = FakeRiakState(is_sync=False)
        self.add_cleanup(self.state.teardown)
        self.manager = FakeMemoryRiakManager(self.state)
        self.msg_helper = self.add_helper(MessageHelper())
        self.set_up_proxies()

class TestInboundMessageMigratorInMemory(InboundMessageMigratorTestMixin,
                                         VumiTestCase):
    def setUp(self):
        self.state = FakeRiakState(is_sync=False)
        self.add_cleanup(self.state.teardown)
        self.manager = FakeMemoryRiakManager(self.state)
        self.msg_helper = self.add_helper(MessageHelper())
        self.set_up_proxies()

redpajama_set_name: RedPajamaGithub


text:
Last Updated: Tuesday, 5 April, 2005, 10:24 GMT 11:24 UK
UK funding for anti-HIV gel trial
HIV is a massive problem among African women
The UK government is to provide £24m to fund a trial to assess how well a microbicide gel can prevent HIV infection in women.
Aids is the biggest killer in Africa, and most new HIV infections occur among young African women.
Research has shown an effective gel, applied before sex, could prevent up to 2.5m HIV infections world-wide over three years.
An extra £2m will be provided by the Medical Research Council.
These are long term strategies that will take many years to reach the people that need them
Nick Partridge
It is thought that many women in Africa have little control over sexual relations.
Women are also biologically more susceptible to HIV infection than men.
Hilary Benn, International Development Secretary, said: "Women vulnerable to infection are frequently unable to refuse sex or to insist on the use of a condom.
"The £26m announced today will fund a final stage trial of a microbicide gel that, if effective, could help women to protect themselves against HIV infection and help reverse the spread of the disease globally."
Key step
Professor Janet Darbyshire, Director of the MRC's Clinical Trials Unit, said: "The funding will take us one step further towards identifying an effective microbicide - a crucial element of our effort to reduce HIV transmission."
The microbicide gel being trialled is called PRO2000.
The MRC's Clinical Trials Unit will test its effectiveness and safety, starting in four African countries: Uganda, South Africa, Tanzania and Zambia.
The trial is expected to begin within 4 months and will run for 39 months.
A further six months will be needed to finalise analyses and report on findings.
Figures show that 57% of the 25m adults in sub-Sahara Africa infected with HIV are women.
Microbicides work in one of three ways - by killing the virus before it enters the body; by preventing it from taking hold once inside the body; or by creating a barrier to stop it from entering the body in the first place.
PRO2000 prevents HIV from binding onto cells and infecting them.
Long-term strategy
Nick Partridge, director of the HIV charity Terrence Higgins Trust said: "The development of a microbicide would be a significant step forward in the fight against HIV, as would the discovery of an effective vaccine.
"But it is important to remember that these are long term strategies that will take many years to reach the people that need them and may never be successfully developed.
"In the short term, promoting condom use and good sex education are essential if we are to prevent more unnecessary deaths from HIV."
Michael Carter, of NAM, an HIV information service, said: "The announcement of extra government funding for research into this microbicide is extremely welcome.
"Results from earlier studies involving PRO 2000 have been encouraging, but we'll have to await the results of this larger study to know if it is a safe and effective way of preventing HIV."
Achmat Dangor, of UNAIDS, said microbicides were one of the most promising new prevention options on the horizon.
"The development of an effective microbicide would be a breakthrough in giving women a real choice when it comes to protecting themselves from HIV and prevent the further spread of the Aids epidemic."
Trials to begin on anti-HIV gel
27 Mar 04 | Health
Gels 'could protect against HIV'
STD treatment could prevent HIV
19 Sep 03 | Health
Terrence Higgins Trust
News Front Page | Africa | Americas | Asia-Pacific | Europe | Middle East | South Asia
UK | Business | Entertainment | Science/Nature | Technology | Health
Have Your Say | In Pictures | Week at a Glance | Country Profiles | In Depth | Programmes

redpajama_set_name: RedPajamaCommonCrawl


2015 Distinguished Hospital Award for Clinical Excellence,ranking BMC among the Top 5% of Hospitals in the Nation for Clinical Excellence - the third year in a row and fourth time since 2009 that BMC has earned this honor.
In 2017, Fairview was honored with the Healthgrades Outstanding Patient Experience Award, ranking it among the Top 10% of Hospitals for patient satisfaction. Fairview was also honored in 2013, 2014, 2015 and 2016 with the Outstanding Patient Experience honor.
2017 & 2018: Healthgrades awards BMC with its 2017 & 2018 Patient Safety Excellence Award, placing BMC among the Top 5% of Hospitals in the Nation for Patient Safety for 2018.
2012 - 2017: The Leapfrog Group rates BMC with another Straight "A" grade for Patient Safety - BMC, as of Spring 2018, is one of only 49 hospitals nationwide to achieve this Straight "A" grade since the inception of the program in 2012.
2001 - 2017:Berkshire Medical Center leads the nation in Get with the Guidelines honors and is one of an elite group of hospitals nationally to achieve Triple Gold honors. BMC has been recognized with over a dozen consecutive Gold Performance Achievement awards for outstanding performance in the care of patients with Coronary Artery Disease. BMC was also the first hospital in the United States to be honored with a Performance Achievement Award for stroke, and holds ten consecutive honors. In addition, BMC has several consecutive yearly Performance Achievement awards for care of patients with heart failure.
2014 - 2017: BMC received the Get With the Guidelines Resuscitation Silver Quality Achievement Award for implementing specific quality improvement measures outlined by the American Heart Association for the treatment of patients who suffer cardiac arrests in the hospital.
2007 - 2018: Berkshire Medical Center's Women's Imaging Center - Breast Imaging Center of Excellence from the American College of Radiology's Commission on Quality and Safety and the Commission on Breast Imaging. Awarded only to centers that have achieved accreditation by the ACR in stereotactic breast biopsy, breast ultrasound, ultrasound-guided biopsy and mammography.
BMC's Weight Loss Surgery Program is a fully accredited center of the Metab olic and Bariatric Surgery Accreditation and Quality Improvement Program.
2017: The Cancer Program at BMC was named a Lung Cancer Screening Center of Excellence by the Lung Cancer Alliance.
Berkshire Medical Center's Cancer Center is the inaugural member of the Dana Farber Cancer Care Collaborative, signifying Berkshire Medical Center's commitment to excellence in cancer care by meeting a wide array of standards and best practices.
2010 - 2018: Berkshire Medical Center - Accredited by the Commission on Cancer of the American College of Surgeons.
2013 - 2018: BMC's Joint Replacement Program has achieved Joint Commission Disease Specific Certification for Hip and Knee Replacement, recognized with a Gold Seal, signifying that it is a Center of Excellence.
2009 - 2018: BMC - End Stage Renal Disease Network of New England has awarded the BMC Dialysis Centers its 5-Diamond designation as part of its 5-Diamond Patient Safety Program. BMC's Units, in both Pittsfield and Great Barrington have achieved 5-Diamond status.
The BMC Sleep Disorders Center is accredited by the American Academy of Sleep Medicine. The Sleep Disorders Center, based at the Hillcrest Campus of BMC, was granted accreditation, which, according to the AASM, is awarded to programs that "meet or exceed all standards for professional healthcare."
2007 - 2018: BMC - American College of Surgeons has verified Berkshire Medical Center as a Trauma Center.
2017: Berkshire Health Systems' Wellness at Work Program has been named a WorkWell Massachusetts Award Program Gold Level winner for exemplary worksite health promotion. The award recognizes Berkshire Health System's achievements developing, implementing, and participating in corporate health improvement and wellness programs. BHS is one out of four Gold Level award recipients for 2017.


We are investing in excess of £3m at both Dewsbury Moor and Huddersfield and Crematoria as part of a modernisation programme. Work began at Huddersfield Crematorium in October with 'front of house' refurbishment.
Works have now commenced at Dewsbury to replace the existing cremator equipment and work will be planned at a future date for the 'front of house' refurbishment at Dewsbury Moor. The cremator replacement works will take approximately 20 weeks to complete. Huddersfield Crematorium will also have state-of-the-art equipment installed which will replace the quarter of a century old cremators for which parts are no longer available.
The crematoria will be operating on a reduced capacity of four services per day whilst the major replacement programme is taking place. During the 20 week programme there will need to be a full closure of 1 week at Dewsbury Moor and Funeral Directors will be notified in advance.
How will Funeral directors know the impact of the renovations?
Funeral directors and providers can speak to their nominated contacts for specific details relating to each crematorium.


text:
Thuraya and Elcome partnership takes UAE maritime comms know-how to the world
This strategic agreement is a key milestone in Thuraya's strategy to drive growth in its maritime business. The partnership will further expand market potential by offering customized solutions for this market segment.
Sun 05 May 2019 11:11 AM
Thuraya Telecommunications Company, a subsidiary of the Al Yah Satellite Communications Company (Yahsat) has signed a Service Partner agreement with Elcome to provide Thuraya's products and services worldwide across key vertical markets.
Headquartered in Dubai and operating out of 23 offices across 11 countries, Elcome has developed a diversified portfolio of technologies and solutions since its founding in 1969.
Emirates Airline flies UAE's first satellite to South Korea for launch
The company's first-class integration capabilities complement Thuraya's renowned satellites, robust global network, best-in-class products and 20+ years record of outstanding resilience, availability and innovation, the companies said in a joint statement.
"Thuraya is pleased to welcome Elcome as a Service Partner. This partnership will further enhance our commitment to key sectors, including maritime, government, energy and leisure," said Ali Al Hashemi, CEO of Thuraya. "Nowadays, these sectors and their customers demand solutions that go beyond the standard connectivity. This partnership will meet those needs on all fronts, including products, network, integration and support."
"The demand for innovative and flexible data solutions for the maritime industry is growing exponentially," said Jimmy Grewal, executive director of Elcome. "We are proud to partner with Thuraya to deliver such integrated services to our regional defence, government and commercial customers."
British Telecom to transform Panalpina communications
Elcome is the largest satellite communications and systems integration provider in the Middle East, supporting all major shipyards in the region.
Its in-house team is fully competent and factory trained to deliver SOLAS compliant integrated communication solutions for vessel owners.
Elcome provides 24/7 support for over 1,200 terminals under the connectivity services program for the world's leading container and LNG carriers. It also supports a wide range of vessel owners and managers with tailor-made cyber security solutions.
"This is an important step towards an extensive and exciting long term collaboration," said Shawkat Ahmed, chief commercial officer of Thuraya. "Elcome covers a wide customer base who truly need comprehensive connectivity at all times beyond terrestrial reach."
"Our capabilities are complementary, and we will be able to give end users far greater flexibility than they have now. This agreement delivers reliable communication wherever and whenever it is needed," he added.
ELCOME
UAE confirms oil tanker missing in Iranian waters, UK sends additional warships


text:
what was lincoln's goal for reconstruction
1 What Was Lincoln's Goal For Reconstruction?
2 What were Lincoln's goals for Reconstruction?
3 What was Lincoln's goal for Reconstruction quizlet?
4 What were the 3 main goals of Reconstruction?
5 What were the three main points of Lincoln's Reconstruction plan?
6 Why did Congress object to Lincoln's wartime plan for Reconstruction?
7 What was the main goal of the Military Reconstruction Act?
8 What were Lincoln's goals quizlet?
9 What were the goals of the Reconstruction plan?
10 What were the two main goals of Reconstruction?
11 What were the goals and aims of the Reconstruction?
12 What was the original goal of Reconstruction quizlet?
13 How did Congress take control of Reconstruction?
14 What did the congressional plan for Reconstruction include?
15 What was the difference between Lincoln's and Johnson's Reconstruction plans?
16 What was the main goal of the military Reconstruction Act quizlet?
17 What was Abraham Lincoln's 10 percent plan?
18 What was the military Reconstruction Act?
19 What were the main goals of the Reconstruction of the South quizlet?
20 What was a main goal of reconstruction in South Carolina?
21 What were the primary goals of reconstruction and to what extent was reconstruction successful in achieving these goals?
22 What were the goals and achievements of the Reconstruction Era following the American Civil War?
23 How did Abraham Lincoln's death affect Reconstruction?
24 What was the goal of the Radical Republicans in Congress during Reconstruction?
25 What was the purpose of Lincoln's and Johnson's presidential Reconstruction plan quizlet?
26 What was Lincoln's Proclamation of Amnesty and Reconstruction?
27 What were three goals of the Radical Republicans during Reconstruction?
28 What was the military Reconstruction Act quizlet?
29 Why did Congress pass the military Reconstruction Acts quizlet?
30 What was the goal of Lincoln's Ten-Percent Plan of Reconstruction quizlet?
31 Which of the following was part of Lincoln's plan for Reconstruction?
32 What did the Reconstruction Act do?
33 What laws were passed during Reconstruction?
34 How did the Military Reconstruction Act divided the South?
35 Three Reconstruction Plans
36 Reconstruction and 1876: Crash Course US History #22
37 Reconstruction Period: Goals, Successes and Failures
38 MOOC | Andrew Johnson | The Civil War and Reconstruction, 1865-1890 | 3.3.1
What Was Lincoln's Goal For Reconstruction?
The aims, or goals of Reconstruction varied for different groups of Americans. Abraham Lincoln's aim was to preserve the Union and end the Civil War as quickly as possible. He promised an easy Reconstruction in order to persuade southern states to surrender.The aims, or goals of Reconstruction varied for different groups of Americans. Abraham Lincoln's aim was to preserve the Union and end the Civil War
The most common name for the American Civil War in modern American usage is simply "The Civil War". Although rarely used during the war, the term "War Between the States" became widespread afterward in the Southern United States.
What were Lincoln's goals for Reconstruction?
The Proclamation of Amnesty and Reconstruction was Lincoln's plan to reintegrate the Confederate states back into the Union, granting presidential pardons to all Southerners (except political leaders) who took an oath of future allegiance to the Union.
What was Lincoln's goal for Reconstruction quizlet?
Lincoln's primary goal of reconstruction was the restoration of national unity through a program of speedy, forgiving political reconciliation. Congress feared that the programs meant restoring the old southern ruling class to power. Congress wanted assurances of white loyalty and guarantees of black rights.
What were the 3 main goals of Reconstruction?
Reconstruction encompassed three major initiatives: restoration of the Union, transformation of southern society, and enactment of progressive legislation favoring the rights of freed slaves.
What were the three main points of Lincoln's Reconstruction plan?
1. A state must have a majority within its borders take the oath of loyalty 2. A state must formally abolish slavery 3. No Confederate officials could participate in the new governments.
Why did Congress object to Lincoln's wartime plan for Reconstruction?
Why did Congress object to Lincoln's wartime plan for reconstruction? "Congress thought Lincoln was being too soft on the former Confederate states. … They also wanted to use a harsh Reconstruction program to seize political and economic control of these states for themselves."
What was the main goal of the Military Reconstruction Act?
The main goal of the Military reconstruction act is to divided the South into five military districts and put officers in charge of making sure states rewrote their constitutions.
What were Lincoln's goals quizlet?
Terms in this set (21) Lincoln's main goal was to preserve the union, and make sure the confederates didn't leave the union. His main goal at the end of the war was to abolish slavery throughout the United States.
What were the goals of the Reconstruction plan?
Well, the goal of Reconstruction was to restore the union and compromise with the Southern states that ceded before and during the war. In order for Lincoln to restore our union he had to allow some flexibility with new laws so that the South would be want to come back to the union peacefully.
What were the two main goals of Reconstruction?
The two main goals of Reconstruction were to bring the former Confederate states back into the Union and to ensure the equal citizenship and rights of former slaves.
What were the goals and aims of the Reconstruction?
The Reconstruction Era lasted from the end of the Civil War in 1865 to 1877. Its main focus was on bringing the southern states back into full political participation in the Union, guaranteeing rights to former slaves and defining new relationships between African Americans and whites.
What was the original goal of Reconstruction quizlet?
What was the original goal of Reconstruction? To reunite the nation and rebuild southern states without slavery. 2.
How did Congress take control of Reconstruction?
In early 1866, Congressional Republicans, appalled by mass killing of ex-slaves and adoption of restrictive black codes, seized control of Reconstruction from President Johnson. … The 14th Amendment also reduced representation in Congress of any southern state that deprived African Americans of the vote.
What did the congressional plan for Reconstruction include?
Congressional Reconstruction included the stipulation that to reenter the Union, former Confederate states had to ratify the 14th and 15th Amendments. Congress also passed the Military Reconstruction Act, which attempted to protect the voting rights and civil rights of African Americans.
What was the difference between Lincoln's and Johnson's Reconstruction plans?
Both Lincoln and Johnson's plan wanted a quick re-admission for the South. Johnson's plan wasn't as willing to give as much freedom to newly free slaves as Lincolns was. … Johnson's plan gave less protection to freed slaves then the Radical Republican's plan.
What was the main goal of the military Reconstruction Act quizlet?
One of the main goals of Military Reconstruction was to guarantee the voting rights of the freedmen. Military Reconstruction Act. longest in the Deep South, which had the largest African American population. Southern white opposition and a lack of congressional support prevented the Freedmen's Bureau from succeeding.
What was Abraham Lincoln's 10 percent plan?
A component of President Lincoln's plans for the postwar reconstruction of the South, this proclamation decreed that a state in rebellion against the U.S. federal government could be reintegrated into the Union when 10% of the 1860 vote count from that state had taken an oath of allegiance to the U.S. and pledged to …
What was the military Reconstruction Act?
In 1867, Congress passed the Military Reconstruction Acts of 1867, which divided the South into five military districts governed by previous Union generals. To be eligible for readmittance to the Union, each Confederate state was required to pass the 13th and 14th Amendments and hold new elections.
What were the main goals of the Reconstruction of the South quizlet?
The main goals of the reconstruction of the south were to rebuild the south's ruined economy, and promote the rights of former slaves.
What was a main goal of reconstruction in South Carolina?
After the Civil War, the North wanted to ensure the abolition of slavery, recognition of the rights of African Americans, and that the South would remain a part of the nation; these were the major goals of the Reconstruction policies.
What were the primary goals of reconstruction and to what extent was reconstruction successful in achieving these goals?
Explain. Reconstruction was a success in that it restored the United States as a unified nation: by 1877, all of the former Confederate states had drafted new constitutions, acknowledged the Thirteenth, Fourteenth, and Fifteenth Amendments, and pledged their loyalty to the U.S. government.
What were the goals and achievements of the Reconstruction Era following the American Civil War?
Among the other achievements of Reconstruction were the South's first state-funded public school systems, more equitable taxation legislation, laws against racial discrimination in public transport and accommodations and ambitious economic development programs (including aid to railroads and other enterprises).
How did Abraham Lincoln's death affect Reconstruction?
His death gave the Radical Republicans more freedom to punish the south. And it put Andrew Johnson in charge who also wanted to punish the south and had a very bad relationship with the Congressmen. Without President Lincoln, the process of reconstruction took 12 years.
What was the goal of the Radical Republicans in Congress during Reconstruction?
During Reconstruction, the Radical Republicans wanted to impeach President Andrew Johnson so they could control the course of reconstruction and pass the laws that they supported to give AA full equality and citizenship.
What was the purpose of Lincoln's and Johnson's presidential Reconstruction plan quizlet?
Radical plan wanted to punish the south, while Lincoln and Johnson wanted to reunite the union as quickly as possible.
What was Lincoln's Proclamation of Amnesty and Reconstruction?
On December 8, 1863, President Abraham Lincoln offers his conciliatory plan for reunification of the United States with his Proclamation of Amnesty and Reconstruction. … Second, it allowed for a new state government to be formed when 10 percent of the eligible voters had taken an oath of allegiance to the United States.
What were three goals of the Radical Republicans during Reconstruction?
They wanted to prevent the leaders of the confederacy from returning to power after the war, they wanted the republican party to become a powerful institution in the south, and they wanted the federal government to help african americans achieve political equality by guaranteeing their rights to vote in the south.
What was the military Reconstruction Act quizlet?
What was the Military Reconstruction Act? The Military Reconstruction Act stated that remaining Confederate states that had not been reconstructed would be divided into five military districts and put under martial law.
Why did Congress pass the military Reconstruction Acts quizlet?
Among the following, who was a radical republican? One of the main goals he Military Reconstruction Act was to ensure that voting rights were granted to African American men.
What was the goal of Lincoln's Ten-Percent Plan of Reconstruction quizlet?
Lincoln's blueprint for Reconstruction included the Ten-Percent Plan, which specified that a southern state could be readmitted into the Union once 10 percent of its voters (from the voter rolls for the election of 1860) swore an oath of allegiance to the Union.
Which of the following was part of Lincoln's plan for Reconstruction?
Which of the following was part of Lincoln's plan for Reconstruction? The presidency would direct Reconstruction, and 10 percent of the 1860 voters had to take an oath of allegiance to the Union in order for former Confederate states to re-create a Union government.
What did the Reconstruction Act do?
The Reconstruction Act of 1867 outlined the terms for readmission to representation of rebel states. The bill divided the former Confederate states, except for Tennessee, into five military districts. … The act became law on March 2, 1867, after Congress overrode a presidential veto.
What laws were passed during Reconstruction?
The Radical Republicans passed the Civil Rights Act of 1866, the First Reconstruction Act, the Second Reconstruction Act, the Ku Klux Klan Act of 1871, the Civil Rights Act of 1875, and the Thirteenth, Fourteenth, and Fifteenth Amendments.
How did the Military Reconstruction Act divided the South?
The South was divided into five military districts and governed by military governors until acceptable state constitutions could be written and approved by Congress. … New state constitutions were required to provide for universal manhood suffrage (voting rights for all men) without regard to race.
Three Reconstruction Plans
Reconstruction and 1876: Crash Course US History #22
Reconstruction Period: Goals, Successes and Failures
MOOC | Andrew Johnson | The Civil War and Reconstruction, 1865-1890 | 3.3.1
proclamation of amnesty and reconstruction
what was the wade-davis bill
radical republican plan for reconstruction
radical reconstruction plan
who opposed lincoln's plan and why?
presidential reconstruction
andrew johnson reconstruction plan
FAQLeave a Comment on what was lincoln's goal for reconstruction


Here's a three-part semi-serious, mostly anecdotal guide on how to be your own best cycling coach.
After a decade and a half of fine-tuning athletic prowess (mine and others), introspection and a genuine curiosity for wellbeing, I've devised the HPP, or the High-Performance Program.
First things first. By HPP, I mean maximizing your QOL. Athletic performance is human performance. And human performance, in a nutshell, is being alive. We all want to live a good life. This isn't about exercise science. It's about what we all share in common: a passion for cycling.
Secondly, with these suggestions, take what's helpful. Use what speaks to you. Then discard the rest. If you have any comments, as always, drop me an email.
It ain't rocket science, but as your own cycling coach, it's essential. Find out what you're good at and capitalized the bejesus out of it. Everybody's made up with a unique set of traits; no better, no worse than others. It's about knowing them and playing them to your advantage.
Cycling has a lot to do with body type and genetics. We have our parents to thank whether we're climbers or sprinters. Or neither. Yet I've found the mind and our willpower to be the most powerful tools we have. Ultimately your body channels what you want and tell it to do.
We're all managing and improving upon a certain set of limitations that become irrelevant when you understand what motivates you. What is it that makes your heart skip a beat? Be familiar with what gets you out of bed in the morning.
Social - finding other people like you or other people who you like! The bike lets you sit there for hours and talk. Or, not talk. No doubt, cycling funnels in some interesting people, lifelong friendships in my experience.
Performance Targets - ticking off boxes, striving for something you wonder is even possible for yourself.
Personal Space - accrue kilometers that quell the noise in our heads to instead generate ideas.
The way you're wired or motivated becomes the way you incorporate cycling into your lifestyle. I find myself jumping around between these three categories. The common thread is there's something to channel, an energy to burn, and someplace to go.
The food you eat literally turns your pedals round, or it doesn't turn them at all. Energy consumption comes hand-in-hand with cycling. Develop a self-awareness in how to best feed your body.
Running on low tank is about the worse thing you can do physically. It's going to throw your mental wellbeing into the pooper as well. If you find you're hungry while riding, just keep throwing them jam sandwiches back!
It's less about nutrition and more about common sense. Although, I'm biased toward real (natural) food. The single biggest mistake I see most people make is not eating after riding. If you've ridden hard, and you're running on empty, there's a 30-40 minute window where you can boost recovery.
When your body doesn't have any energy to ingest, it starts feeding off itself. And it's not fat that it's eating, it's chomping away at your sunny outlook on life. The body functions as intelligently as the mind inside it.
HPP rule of thumb: drink plenty of water and exalt the salt. Especially in the summer months when your internal sodium factory is on peak output. My favourite (as a complete mineral profile) is the grey sea salt from Guérand, France. Table salt doesn't hold a candle next to this grey salty substance raked in the plains of Bretagne.
While we're on the topic of recovery, it's good custom to roughly know your TSS, or Training Stress Score. In layman's terms, TSS is a combination of duration and intensity. So taking into consideration your total ride time and how hard you rode. Not all rides are equal. It's easy to underestimate just how hard you rode especially when that non-sweating twit dropped you like a sack of nails.
You don't need a power meter to know you've spent the entire climb (or ride) a tutta - in the hurt box. It's stress your body's going to have to recover from. Tough rides can throw you off equilibrium. Knowing this, you'll be able to cope better.
Going downhill well builds with experience. The more you do it, the more you get a feel for it. Look to expand your limits, yet know them intimately.
The 80-20 rule works well here. 80% of your comfort zone is where you'll gain momentum and speed. The last 20% is where the risk and diminishing returns lie. Like staying at the discoteca past 2 am.
Speaking of the dicoteca, descending is like dancing. The bike leads, but you have a big say in where it goes.
Control your bike rather than your bike controlling you. Corner using your body weight to maneuver the bike. Think about putting the majority of your weight on your outside leg and imagine that weight transferring equally through your front and back tires into the pavement. Doing this, you're going to shift where your body makes contact with your seat if it makes contact at all. You and the bike should be moving to the same beat. If you're battling your bike, you're off beat.
Scan the corner like you would the discoteca at midnight and evaluate how much you need to slow down (or speedup!). All the braking should be done before the corner. Not in the corner and after will surely be too late! It's a highly learnable skill. The important part is learning it.
Notice road surfaces. If you encounter gravel (the key is to avoid it) and you're headed straight for it like an Italian man approaches a woman, let your bike simply roll over it the straightest, most direct possible line. Breaking or cornering in gravel for most of us yields unpredictable results. Don't panic, straighten your line, then course correct once you're through it.
Know where to put your hands. The lower you put them, the more control you have. By that, I mean in the drops. The hoods are perfect for cruising, but when you start to pick up speed, there's always a chance you hit a bump and your hands slip and slide right off them.
Give the centre line plenty of space. Especially in blind corners. You never want to put yourself in a weak position to clowns that willingly cross the centre line. Keep to your side of the road as much as reasonably possible.
Whenever I want to improve at something, like descending, I follow people who are better than me. If any of this becomes a chore refer back to what makes your heart sing. Go and do that.
This is by no means an exhaustive HPP or cycling coach protocol. Ideally, it incorporates some upper body and core work. Maybe also a stretching regime. Probably a travel to Italy program. These are just the basics. If you have any Q's, you know where to find me. Somewhere raking salt in France.


Oh what fun! Give or get dazzling jewelry that changes color in a Snap! Giving a beautiful base piece - necklace, bracelet, earrings, pin - plus interchangeable Snaps to suit the season (and beyond). She'll thank you all year long.


text:
Share this Story: Ontario spending $765M to upgrade public safety radio network
Ontario spending $765M to upgrade public safety radio network
Premier Doug Ford meets with first responders in Kenora where he announced a a $765-million investment to rebuild Ontario's Public Safety Radio Network. (FordNation/Twitter)
Ontario will spend $765 million to rebuild and replace parts of the province's aging public safety radio network.
Premier Doug Ford says Bell Mobility has been awarded the contract to make the upgrades.
Ontario spending $765M to upgrade public safety radio network Back to video
The government announced the project last year, saying the system used by first responders is prone to daily outages and needs to be modernized.
The network covers 750,000 square kilometres — about three quarters of the province's total area — including areas in the north where cellphone service is not available.
LIVE: Premier Doug Ford and @GregRickford, Minister of Energy, Northern Development and Mines and Minister of Indigenous Affairs, make an announcement regarding Ontario's Public Safety Radio Network in Kenora. #onpoli https://t.co/cIorUdT0CX
— Doug Ford (@fordnation) October 17, 2019
It helps first responders communicate and co-ordinate during forest fires, police operations and medical emergencies.
Transition to the new network will begin in 2021, and it's expected to be fully operational by June 2023.


If you have ever thought about getting facial treatment for lines and wrinkles, you may have considered dermal fillers; this type of injection can not only get rid of unsightly lines, it can also build up sunken areas and add volume to the face where it has been lost over the years. Aging can be difficult for some people and facial injections are fast becoming the treatment of choice for patients looking to make their complexion look fresher and more youthful. Facial injections can be seen as a great alternative to invasive surgery, although they don't give a permanent result, and many people who would like to look and feel younger can do so without having to resort to costly surgical procedures.
Dermal fillers are made up primarily of hyaluronic acid – which is a substance that occurs naturally in the human body and is used to lubricate the joints and to keep the skin supple. Because the acid is already present in the system, the dermal filler that is injected will eventually start to break down into the body, leaving no trace behind. This will typically occur after 3 to 5 months, after which time you will need to get a repeat treatment if you would like to maintain the results long-term. There are some permanent filler injections available but most surgeons are reluctant to use them because it cannot be predicted what will happen to the liquid if it is injected permanently into the body. Some patients also use this sort of treatment as a trial run for a facelift, in which case the temporary nature of the results is a bonus. Most patients who request anti-ageing treatment will just be looking for a slight change here and there, rather than a complete overhaul; this is a good way to keep the complexion looking fresh, without it being obvious that some work has been carried out.
If this sounds like something that could benefit you, call the laser skin & vein clinic dermal fillers injections and speak to a member of the team about booking a consultation today; the sooner you make an appointment the sooner you will be able to get your treatment under way.


We certainly celebrated our milestone anniversary of 50 years in style.
Employees and their families spent all day and evening at Festi-Five-O in the idyllic setting in Droxford, enjoying food and drinks throughout the day, four amazing live bands, lawn games, sports days for both the children and adults! Face painting, a bouncy castle, and a lot of relaxing and socialising in the shade away from the hot summer sun.
Here's to the next 50….


living room wall colour ideas colors accent paint color wal.
westminster chime wall clock with pendulum chiming s.
ikea observator wall mount tv shelf unit under stand for mounted.
lowes 3 4 drywall screws 8 x plywood co inc.
computer monitor wall mount target kit.
target wall art au graphic up design super ideas new trends info set canvas stickers blue wood framed.
cheap wall mirrors walmart a of in the master bath.
bathroom bathtub tile ideas in x metro ash grey wall surround ca.
black and white horse canvas wall art wood print oil paint decor.
extra large contemporary wall clocks uk clock art modern cont.


Roleplay Haven is a chatroom designed specifically for roleplaying, as well as groups and forums. The rooms, the boards, all the content is created and managed by the users themselves.
Find RP - You can post and view adverts to more easily find a writing partner.
Tabs - Separated for both one-on-one interactions and multi-user rooms, you can quickly flip between them and even use your tab and enter to cycle through them.
Character management - You can have multiple names grouped under one account.
It is not restricted to any sort of RP; Adult, Fantasy, Medieval, Sci-Fi, Anime, Realistic, and so on are all welcome. You play the storylines that you want to! Given the existance of adult content, you must be 18 or older.
Fill out a simple form to join within minutes.
After confirming your account you can edit your profile, add more characters, and more.
Once you've registered, join others that are looking for role play.
The owners of this site are not, in any way, responsible for the materials that are posted, said, and/or downloaded within chat. Content on the site is managed by the users and RPH is not responsable for it. By entering RPH, it is assumed that you are at least 18 years of age or older.


text:
Tabriz (persiano: تبریز; azero: Təbriz) è la più grande città dell'Iran nord-occidentale, con una popolazione di quasi  abitanti.

È il capoluogo dell'Azerbaigian Orientale e dello shahrestān di Tabriz.

Geografia fisica

Topografia
Tabriz si trova nel nord-ovest dell'Iran, nella provincia dell'Azerbaigian orientale a nord dei monti Sahand, a , e a sud dei monti Eynali, in un'area fertile sulle rive del fiume Aji e del fiume Ghuri. La zona è soggetta a terremoti e nel corso della sua storia la città è stata più volte devastata e ricostruita.

Clima
Tabriz ha un clima continentale con stagioni regolari (Köppen Dsa) che confinano con un clima semi-arido freddo (Köppen BSk). La precipitazione annuale è di circa 320 millimetri, buona parte della quale cade a carattere nevoso durante i mesi invernali e come pioggia in primavera e autunno. La città gode di un clima mite in primavera, secco e semi-caldo in estate, umido e piovoso in autunno e freddo nevoso in inverno. La temperatura media annuale è di  (). I venti freddi soffiano da est a ovest principalmente in estate.

Etimologia
Secondo alcune fonti, tra cui l'Encyclopædia Britannica, il nome Tabriz deriverebbe da tap-riz, dalle numerose sorgenti termali della zona. Altre fonti affermano che nel 246 d.C., per vendicare la morte di suo fratello, il re Tiridate II di Armenia respinse Ardashir I dell'Impero sasanide e cambiò il nome della città da Shahistan a Tauris, derivante da "ta-vrezh "("questa vendetta" in armeno classico). Nel 297 d.C. divenne la capitale di Tiridate III, re di Armenia. Tuttavia, questa storia ha un'origine popolare e nessuna fonte antica ha registrato tale evento. Essa si basa sui racconti di Vardan Areveltsi, uno storico armeno del XIII secolo. La Cambridge History of Iran indica una connessione tra "l'antica roccaforte di Tarui-Tarmakisa" (o Tarwi-Tarwakisa), esistita nell'VIII secolo a.C., e la città di Tabriz, insieme anche alla pubblicazione Archaeological History of Iran di Ernst Herzfeld che identifica direttamente "Tarwakisa" con Tabriz. Alcuni ricercatori ritengono che Tabriz possa essere considerato un toponimo pre-iranico.

Storia
Non ci sono fonti storiche certe circa la fondazione della città. La maggior parte di esse la collocano nell'era sasanide, mentre altre affermano che i primi insediamenti risalgano ancora più indietro nella storia. Dopo l'occupazione turca selgiuchide dell'Asia centrale, in Iran, Tabriz divenne capitale dell'Impero ilkhanide dal 1270 al 1305, della dinastia degli Ak Koyunlu dal 1469 al 1502 e dei Safavidi dal 1502 al 1548. Atropat, comandante iraniano dei Medi nell'impero achemenide di Dario e poi di Alessandro Magno, trasferì la capitale dei Medi, nel 4 d. C., da Ekbatan a un'altra città vicino a Tabriz. Nel 1270 il bazar coperto di Tabriz, costruito dai selgiuchidi nell'XI secolo, divenne il centro commerciale di Tabriz e del mondo, nonché la capitale della dinastia Ikhanidi dell'impero di Changhiz Khan.
Marco Polo la nomina come Tauris, città nobile e grande.

La storia dei Medi (Mada) parla della conquista degli Assiri, con Sargon II nell'VIII secolo d. C., del grande castello (o fortezza) di Taurui (Tauris), dell'impero del popolo di manna (mannea), corrispondente alla Tabriz odierna. La città veniva chiamata, anche dagli Europei, Tauris e, in vari periodi, anche Tarmakis o Tarmis o Tarbiz.

Monumenti e luoghi d'interesse
Ben poco è rimasto a testimonianza della storia secolare della città, tuttavia Tabriz conserva alcuni luoghi ed edifici antichi di indubbio fascino ed interesse. Fra questi ricordiamo la Moschea Blu o "Moschea Kabud" costruita nel 1465, la Moschea del venerdì e il gran bazar, uno dei più estesi e antichi dell'area mediorientale, citato da Marco Polo nel suo libro Il Milione.

Note

Voci correlate
 Metropolitana di Tabriz
 Terremoto di Tabriz del 1721

Altri progetti

Collegamenti esterni

Luoghi di Marco Polo in Iran

redpajama_set_name: RedPajamaWikipedia


This topic has 2 voices, contains 9 replies, and was last updated by chrisoosting 108 days ago.
I have a problem with the customer checkout button, it is not showing.
Customers can check in but don't check out, how can i fix this.
Can you please provide some more information? For the moment we are not able to fully understand your request. If appropriate, you can attach some screenshots to better illustrate, what exactly you mean.
My fault, it must me customers can log in to their account but can not log out, logout is not showing.
And another thing, after the tb upgrade live search is not showing al the pictures of products, do i have to delete a cache file for that?
You can add a logout menu link from the Menu composer. The link will only be visible when you are logged.
The link for the logout menu is installed, but not showing at the frontend when a customer is logged in, that is the problem. see screenshot.
Logout is stil not working, and live search not showing al the pictures.
Have you revoked the latest admin access you gave us?
admin access was inactive, is active again.
Hope you can fix this for me, also the pictures in the live search.
The problem with the login/logout menu was a missing closing tag in your analytics code. We've added it and now everything works fine.
And why are not al the product pictures showing in the search bar, did you also look at that.
It still only shows some pictures.


Room Correction Event with Audio Engineer, Manny LaCarrubba.
Join us for a seminar with Manny La Currabba and learn about different methods and systems for achieving better sound through room correction.
Our second DAC Smackdown event was a great success! We had a full house of members, including those selected to bring their own DACs to participate in the fun.
What a year it has been! Just this past weekend, we broke all attendance records with over 100 SFAS members converging on Magico's new factory and headquarters in Hayward.