text:
"""Tests for backend.api.device_api."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import datetime

from absl.testing import parameterized
import mock

from protorpc import message_types
from google.appengine.api import datastore_errors

import endpoints

from loaner.web_app import constants
from loaner.web_app.backend.api import device_api
from loaner.web_app.backend.api import root_api
from loaner.web_app.backend.api.messages import device_messages
from loaner.web_app.backend.api.messages import shared_messages
from loaner.web_app.backend.api.messages import shelf_messages
from loaner.web_app.backend.clients import bigquery
from loaner.web_app.backend.clients import directory
from loaner.web_app.backend.lib import api_utils
from loaner.web_app.backend.lib import search_utils
from loaner.web_app.backend.models import config_model
from loaner.web_app.backend.models import device_model
from loaner.web_app.backend.models import shelf_model
from loaner.web_app.backend.testing import loanertest

class DeviceApiTest(parameterized.TestCase, loanertest.EndpointsTestCase):
  """Tests for the Device API."""

  def setUp(self):
    super(DeviceApiTest, self).setUp()
    self.service = device_api.DeviceApi()
    self.login_admin_endpoints_user()

    # Set bootstrap to completed so that maintenance mode will not be invoked.
    config_model.Config.set('bootstrap_completed', True)
    self.shelf = shelf_model.Shelf.enroll(
        user_email=loanertest.USER_EMAIL,
        location='NYC',
        capacity=10,
        friendly_name='GnG',
        latitude=40.6892534,
        longitude=-74.0466891,
        altitude=1.0)

    self.device = device_model.Device()
    self.device.serial_number = '123ABC'
    self.device.asset_tag = '12345'
    self.device.enrolled = True
    self.device.device_model = 'Google Pixelbook'
    self.device.due_date = datetime.datetime(2017, 11, 15)
    self.device.last_known_healthy = datetime.datetime(2017, 11, 1)
    self.device.shelf = self.shelf.key
    self.device.assigned_user = loanertest.USER_EMAIL
    self.device.assignment_date = datetime.datetime(2017, 11, 1)
    self.device.current_ou = '/'
    self.device.ou_changed_date = datetime.datetime(2017, 11, 1)
    self.device.locked = False
    self.device.lost = False
    self.device.chrome_device_id = 'unique_id_1'
    self.device.last_heartbeat = datetime.datetime(2017, 11, 1)
    self.device.damaged = False
    self.device.damaged_reason = None
    self.device.put()
    self.device.set_last_reminder(0)
    self.device.set_next_reminder(1, datetime.timedelta(hours=2))
    device_model.Device(
        serial_number='6789',
        enrolled=True,
        device_model='HP Chromebook 13 G1',
        current_ou='/',
        chrome_device_id='unique_id_2',
        shelf=self.shelf.key,
        damaged=False,
    ).put()
    self.unenrolled_device = device_model.Device(
        serial_number='4567',
        enrolled=False,
        device_model='HP Chromebook 13 G1',
        current_ou='/',
        chrome_device_id='unique_id_3',
        damaged=False,
    )
    self.unenrolled_device.put()
    self.unenrolled_device_directory = {
        'deviceId': 'unique_id',
        'serialNumber': '4567',
        'status': 'ACTIVE',
        'lastSync': datetime.datetime.utcnow(),
        'model': 'HP Chromebook 13 G1',
        'orgUnitPath': constants.ORG_UNIT_DICT['DEFAULT'],
    }

  def tearDown(self):
    super(DeviceApiTest, self).tearDown()
    self.service = None

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  def test_enroll(self, mock_directoryclass):
    """Tests Enroll with mock methods."""
    mock_directoryclient = mock_directoryclass.return_value
    mock_directoryclient.get_chrome_device.return_value = (
        self.unenrolled_device)
    mock_directoryclient.get_chrome_device_by_serial.return_value = (
        self.unenrolled_device_directory)
    retrieved_device = device_model.Device.get(
        serial_number=self.unenrolled_device.serial_number)
    self.assertFalse(retrieved_device.enrolled)

    request = device_messages.DeviceRequest(
        serial_number=self.unenrolled_device.serial_number)
    with mock.patch.object(
        self.service, 'check_xsrf_token', autospec=True) as mock_xsrf_token:
      response = self.service.enroll(request)
      self.assertIsInstance(response, message_types.VoidMessage)
      retrieved_device = device_model.Device.get(
          serial_number=self.unenrolled_device.serial_number)
      self.assertTrue(retrieved_device.enrolled)
      self.assertEqual(mock_xsrf_token.call_count, 1)

  @parameterized.parameters((datastore_errors.BadValueError,),
                            (device_model.DeviceCreationError,))
  @mock.patch.object(device_model, 'Device', autospec=True)
  def test_enroll_error(self, test_error, mock_device_cls):
    mock_device_cls.enroll.side_effect = test_error
    request = device_messages.DeviceRequest(
        serial_number=self.unenrolled_device.serial_number)
    with self.assertRaises(endpoints.BadRequestException):
      self.service.enroll(request)

  @mock.patch.object(device_model, 'Device', autospec=True)
  def test_unenroll_error(self, mock_device_cls):
    mock_device_cls.get.return_value.unenroll.side_effect = (
        device_model.FailedToUnenrollError())
    request = device_messages.DeviceRequest(
        serial_number=self.unenrolled_device.serial_number)
    with self.assertRaises(endpoints.BadRequestException):
      self.service.unenroll(request)

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_unenroll(self, mock_xsrf_token, mock_directoryclass):
    mock_directoryclient = mock_directoryclass.return_value
    mock_directoryclient.move_chrome_device_org_unit.return_value = (
        loanertest.TEST_DIR_DEVICE_DEFAULT)
    request = device_messages.DeviceRequest(
        serial_number=self.device.serial_number)
    self.assertTrue(self.device.enrolled)
    response = self.service.unenroll(request)
    self.assertFalse(self.device.enrolled)
    self.assertIsNone(self.device.assigned_user)
    self.assertIsNone(self.device.due_date)
    self.assertIsInstance(response, message_types.VoidMessage)
    self.assertEqual(mock_xsrf_token.call_count, 1)

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_unlock(self, mock_xsrf_token, mock_directoryclass):
    self.device.lost = True
    self.device.locked = True
    self.device.put()
    mock_directoryclient = mock_directoryclass.return_value
    mock_directoryclient.move_chrome_device_org_unit.return_value = (
        loanertest.TEST_DIR_DEVICE_DEFAULT)
    request = device_messages.DeviceRequest(
        serial_number=self.device.serial_number)
    response = self.service.unlock(request)
    self.assertFalse(self.device.locked)
    self.assertFalse(self.device.lost)
    self.assertIsInstance(response, message_types.VoidMessage)
    self.assertEqual(mock_xsrf_token.call_count, 1)

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  def test_unlock_directory_error(self, mock_directory_class):
    mock_directory_client = mock_directory_class.return_value
    mock_directory_client.reenable_chrome_device.side_effect = (
        directory.DirectoryRPCError)
    with self.assertRaises(endpoints.BadRequestException):
      self.service.unlock(device_messages.DeviceRequest(asset_tag='12345'))

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  def test_unlock_move_ou_error(self, mock_directory_class):
    del mock_directory_class  # Unused.
    with mock.patch.object(
        self.device,
        'move_to_default_ou',
        side_effect=device_model.UnableToMoveToDefaultOUError):
      with self.assertRaises(endpoints.BadRequestException):
        self.service.unlock(device_messages.DeviceRequest(asset_tag='12345'))

  @mock.patch('__main__.device_model.Device.device_audit_check')
  def test_device_audit_check(self, mock_device_audit_check):
    request = device_messages.DeviceRequest(identifier='6765')
    self.assertRaisesRegexp(device_api.endpoints.NotFoundException,
                           device_api._NO_DEVICE_MSG % '6765',
                           self.service.device_audit_check, request)

    device_model.Device(
        serial_number='12345',
        enrolled=True,
        device_model='HP Chromebook 13 G1',
        current_ou='/',
        chrome_device_id='unique_id_1',
        damaged=False).put()
    request = device_messages.DeviceRequest(identifier='12345')
    response = self.service.device_audit_check(request)
    self.assertEqual(mock_device_audit_check.call_count, 1)
    self.assertIsInstance(response, message_types.VoidMessage)

  def test_device_audit_check_device_not_enrolled(self):
    request = device_messages.DeviceRequest(
        identifier=self.device.serial_number)
    self.device.enrolled = False
    with self.assertRaises(device_api.endpoints.BadRequestException):
      self.service.device_audit_check(request)

  def test_device_audit_check_device_damaged(self):
    request = device_messages.DeviceRequest(
        identifier=self.device.serial_number)
    self.device.damaged = True
    with self.assertRaises(device_api.endpoints.BadRequestException):
      self.service.device_audit_check(request)

  def test_device_audit_check_audit_error(self):
    request = device_messages.DeviceRequest(
        identifier=self.device.serial_number)
    self.testbed.mock_raiseevent.side_effect = device_model.DeviceAuditEventError
    with self.assertRaises(device_api.endpoints.BadRequestException):
      self.service.device_audit_check(request)

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  def test_get_device_not_found(self, mock_directory_class):
    mock_directory_client = mock_directory_class.return_value
    mock_directory_client.given_name.return_value = 'given name value'
    request = device_messages.DeviceRequest(identifier='not-found')
    with self.assertRaises(device_api.endpoints.NotFoundException):
      self.service.get_device(request)

  def test_get_device_unenrolled(self):
    request = device_messages.DeviceRequest(
        identifier=self.device.serial_number)
    self.device.enrolled = False
    with self.assertRaises(device_api.endpoints.BadRequestException):
      self.service.get_device(request)

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  def test_get_device(self, mock_directory_class):
    mock_directory_client = mock_directory_class.return_value
    mock_directory_client.given_name.return_value = 'given name value'
    asset_tag_response = self.service.get_device(
        device_messages.DeviceRequest(asset_tag='12345'))
    chrome_device_id_response = self.service.get_device(
        device_messages.DeviceRequest(chrome_device_id='unique_id_1'))
    serial_number_response = self.service.get_device(
        device_messages.DeviceRequest(serial_number='123ABC'))
    urlkey_response = self.service.get_device(
        device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))
    identifier_response = self.service.get_device(
        device_messages.DeviceRequest(identifier='123ABC'))

    self.assertIsInstance(asset_tag_response, device_messages.Device)
    self.assertIsInstance(chrome_device_id_response, device_messages.Device)
    self.assertIsInstance(serial_number_response, device_messages.Device)
    self.assertIsInstance(urlkey_response, device_messages.Device)
    self.assertIsInstance(identifier_response, device_messages.Device)
    self.assertEqual(self.device.serial_number,
                     asset_tag_response.serial_number)
    self.assertEqual(self.device.device_model, urlkey_response.device_model)

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  def test_get_device_no_permission(self, mock_directory_class):
    mock_directory_client = mock_directory_class.return_value
    mock_directory_client.given_name.return_value = 'given name value'
    email = 'random@{}'.format(loanertest.USER_DOMAIN)
    self.login_endpoints_user(email=email)
    with self.assertRaises(endpoints.UnauthorizedException):
      self.service.get_device(
          device_messages.DeviceRequest(
              serial_number=self.device.serial_number))

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  def test_get_device_has_permission(self, mock_directory_class):
    mock_directory_client = mock_directory_class.return_value
    mock_directory_client.given_name.return_value = 'given name value'
    device = self.service.get_device(
        device_messages.DeviceRequest(serial_number=self.device.serial_number))
    self.assertIsInstance(device, device_messages.Device)
    self.assertEqual(device.serial_number, self.device.serial_number)

  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  def test_get_device_assigned_user(self, mock_directory_class):
    mock_directory_client = mock_directory_class.return_value
    mock_directory_client.given_name.return_value = 'given name value'
    email = 'random@{}'.format(loanertest.USER_DOMAIN)
    self.login_endpoints_user(email=email)
    self.device.assigned_user = email
    self.device.put()
    device = self.service.get_device(
        device_messages.DeviceRequest(serial_number=self.device.serial_number))
    self.assertIsInstance(device, device_messages.Device)
    self.assertEqual(device.serial_number, self.device.serial_number)

  @parameterized.parameters(directory.DirectoryRPCError,
                            directory.GivenNameDoesNotExistError)
  @mock.patch.object(directory, 'DirectoryApiClient', autospec=True)
  def test_get_device_directory_errors(self, test_error, mock_directory_class):
    request = device_messages.DeviceRequest(asset_tag='12345')
    mock_directory_client = mock_directory_class.return_value
    mock_directory_client.given_name.side_effect = test_error
    self.assertIsNone(self.service.get_device(request).given_name)

  @parameterized.parameters((
      device_messages.Device(enrolled=True),
      2,
  ), (
      device_messages.Device(current_ou='/'),
      2,
  ), (
      device_messages.Device(enrolled=False),
      1,
  ), (
      device_messages.Device(
          query=shared_messages.SearchRequest(query_string='sn:6789')),
      1,
  ), (
      device_messages.Device(
          query=shared_messages.SearchRequest(query_string='at:12345')),
      1,
  ))
  def test_list_devices(self, request, response_length):
    response = self.service.list_devices(request)
    self.assertLen(response.devices, response_length)

  def test_list_devices_with_search_constraints(self):
    expressions = shared_messages.SearchExpression(expression='serial_number')
    expected_response = device_messages.ListDevicesResponse(
        devices=[device_messages.Device(serial_number='6789')],
        has_additional_results=False)
    request = device_messages.Device(
        query=shared_messages.SearchRequest(
            query_string='sn:6789',
            expressions=[expressions],
            returned_fields=['serial_number']))
    response = self.service.list_devices(request)
    self.assertEqual(response.devices[0].serial_number,
                     expected_response.devices[0].serial_number)
    self.assertFalse(response.has_additional_results)

  def test_list_devices_with_filter_message(self):
    message = device_messages.Device(
        enrolled=True, device_model='HP Chromebook 13 G1', current_ou='/')
    filters = api_utils.to_dict(message, device_model.Device)
    request = device_messages.Device(**filters)
    response = self.service.list_devices(request)
    expected_response = device_messages.ListDevicesResponse(
        devices=[
            device_messages.Device(
                serial_number='6789',
                identifier='6789',
                enrolled=True,
                device_model='HP Chromebook 13 G1',
                current_ou='/',
                locked=False,
                lost=False,
                chrome_device_id='unique_id_2',
                damaged=False,
                guest_permitted=True,
                onboarded=False)
        ],
        has_additional_results=False)
    self.assertEqual(response, expected_response)

  @mock.patch('__main__.device_api.shelf_api.get_shelf')
  def test_list_devices_with_shelf_filter(self, mock_get_shelf):
    # Test for shelf location as filter.
    mock_get_shelf.return_value = self.shelf
    shelf_request_message = shelf_messages.ShelfRequest(
        location=self.shelf.location)
    message = shelf_messages.Shelf(shelf_request=shelf_request_message)
    request = device_messages.Device(shelf=message)
    response = self.service.list_devices(request)
    mock_get_shelf.assert_called_once_with(shelf_request_message)
    self.assertLen(response.devices, 2)

  def test_list_devices_with_page_token(self):
    request = device_messages.Device(enrolled=True, page_size=1)
    response_devices = []
    while True:
      response = self.service.list_devices(request)
      for device in response.devices:
        response_devices.append(device)
      request = device_messages.Device(
          enrolled=True, page_size=1, page_token=response.page_token)
      if not response.has_additional_results:
        break
    self.assertLen(response_devices, 2)

  @mock.patch.object(
      search_utils, 'to_query', return_value='enrolled:enrolled', autospec=True)
  def test_list_devices_with_malformed_page_token(self, mock_to_query):
    """Test list devices with a fake token, raises BadRequestException."""
    request = device_messages.Device(page_token='malformedtoken')
    with self.assertRaises(endpoints.BadRequestException):
      self.service.list_devices(request)

  def test_list_devices_inactive_no_shelf(self):
    request = device_messages.Device(enrolled=False, page_size=1)
    response = self.service.list_devices(request)
    expected_response = device_messages.ListDevicesResponse(
        devices=[
            device_messages.Device(
                serial_number=self.unenrolled_device.serial_number,
                identifier=self.unenrolled_device.serial_number,
                enrolled=self.unenrolled_device.enrolled,
                device_model=self.unenrolled_device.device_model,
                current_ou=self.unenrolled_device.current_ou,
                locked=self.unenrolled_device.locked,
                lost=self.unenrolled_device.lost,
                chrome_device_id=self.unenrolled_device.chrome_device_id,
                damaged=self.unenrolled_device.damaged,
                guest_permitted=True,
                onboarded=False)
        ],
        has_additional_results=False)
    self.assertEqual(expected_response, response)

  @mock.patch('__main__.device_model.Device.list_by_user')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_list_user_devices(self, mock_xsrf_token, mock_list_by_user):
    self.login_endpoints_user()
    device2 = device_model.Device()
    device2.serial_number = '123ABC'
    device2.assigned_user = loanertest.USER_EMAIL
    device2.assignment_date = datetime.datetime(2017, 11, 1)
    device2.due_date = datetime.datetime(2017, 11, 4)
    device2.put()

    request = message_types.VoidMessage()
    mock_list_by_user.return_value = [self.device, device2]
    response = self.service.list_user_devices(request)
    self.assertEqual(response.devices[0].serial_number,
                     self.device.serial_number)
    self.assertLen(response.devices, 2)
    self.assertEqual(mock_xsrf_token.call_count, 1)
    mock_list_by_user.assert_called_once_with(loanertest.USER_EMAIL)

  @mock.patch('__main__.device_model.Device.enable_guest_mode')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_enable_guest_mode(self, mock_xsrf_token, mock_enableguest):
    config_model.Config.set('allow_guest_mode', True)
    self.login_endpoints_user()
    self.service.enable_guest_mode(
        device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))
    self.assertTrue(mock_enableguest.called)
    self.assertEqual(mock_xsrf_token.call_count, 1)

    mock_xsrf_token.reset_mock()
    mock_enableguest.reset_mock()
    self.service.enable_guest_mode(
        device_messages.DeviceRequest(
            chrome_device_id=self.device.chrome_device_id))
    self.assertTrue(mock_enableguest.called)
    self.assertEqual(mock_xsrf_token.call_count, 1)

    def guest_disabled_error(*args, **kwargs):
      del args, kwargs  # Unused.
      raise device_model.GuestNotAllowedError(
          device_model._GUEST_MODE_DISABLED_MSG)

    def directory_error(*args, **kwargs):
      del args, kwargs  # Unused.
      raise device_model.EnableGuestError('Directory broke, all your fault.')

    mock_enableguest.side_effect = guest_disabled_error
    with self.assertRaises(endpoints.UnauthorizedException):
      self.service.enable_guest_mode(
          device_messages.DeviceRequest(
              chrome_device_id=self.device.chrome_device_id))

    mock_enableguest.side_effect = directory_error
    with self.assertRaises(endpoints.InternalServerErrorException):
      self.service.enable_guest_mode(
          device_messages.DeviceRequest(
              chrome_device_id=self.device.chrome_device_id))

  def test_enable_guest_unassigned(self):
    config_model.Config.set('allow_guest_mode', True)
    self.device.assigned_user = None
    self.device.put()
    with self.assertRaisesRegexp(
        endpoints.UnauthorizedException,
        device_model._UNASSIGNED_DEVICE % self.device.identifier):
      self.service.enable_guest_mode(
          device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))

  @mock.patch('__main__.device_model.Device.loan_extend')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_extend_loan(self, mock_xsrf_token, mock_loanextend):
    tomorrow = datetime.datetime.utcnow() + datetime.timedelta(days=1)
    self.login_endpoints_user()
    self.service.extend_loan(
        device_messages.ExtendLoanRequest(
            device=device_messages.DeviceRequest(
                urlkey=self.device.key.urlsafe()),
            extend_date=tomorrow))
    mock_loanextend.assert_called_once_with(
        user_email=loanertest.USER_EMAIL, extend_date_time=tomorrow)
    self.assertEqual(mock_xsrf_token.call_count, 1)

    mock_xsrf_token.reset_mock()
    mock_loanextend.reset_mock()
    self.service.extend_loan(
        device_messages.ExtendLoanRequest(
            device=device_messages.DeviceRequest(
                chrome_device_id=self.device.chrome_device_id),
            extend_date=tomorrow))
    mock_loanextend.assert_called_once_with(
        user_email=loanertest.USER_EMAIL, extend_date_time=tomorrow)
    self.assertEqual(mock_xsrf_token.call_count, 1)

    mock_loanextend.side_effect = device_model.ExtendError
    self.assertRaises(
        device_api.endpoints.BadRequestException, self.service.extend_loan,
        device_messages.ExtendLoanRequest(
            device=device_messages.DeviceRequest(
                chrome_device_id=self.device.chrome_device_id),
            extend_date=tomorrow))

  def test_extend_loan_unassigned(self):
    self.device.assigned_user = None
    self.device.put()
    with self.assertRaisesRegexp(
        endpoints.UnauthorizedException,
        device_model._UNASSIGNED_DEVICE % self.device.identifier):
      self.service.extend_loan(
          device_messages.ExtendLoanRequest(
              device=device_messages.DeviceRequest(
                  chrome_device_id=self.device.chrome_device_id)))

  @mock.patch('__main__.device_model.Device.mark_damaged')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_mark_damaged(self, mock_xsrf_token, mock_markdamaged):
    self.login_endpoints_user()
    self.service.mark_damaged(
        device_messages.DamagedRequest(
            device=device_messages.DeviceRequest(
                urlkey=self.device.key.urlsafe()),
            damaged_reason='Foo'))
    mock_markdamaged.assert_called_once_with(
        user_email=loanertest.USER_EMAIL, damaged_reason='Foo')
    self.assertEqual(mock_xsrf_token.call_count, 1)

    mock_xsrf_token.reset_mock()
    mock_markdamaged.reset_mock()
    self.service.mark_damaged(
        device_messages.DamagedRequest(  # No reason given.
            device=device_messages.DeviceRequest(
                urlkey=self.device.key.urlsafe())))
    mock_markdamaged.assert_called_once_with(
        user_email=loanertest.USER_EMAIL, damaged_reason=None)
    self.assertEqual(mock_xsrf_token.call_count, 1)

  @mock.patch.object(device_model.Device, 'mark_damaged')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_mark_damaged__unauthorized(self, mock_xsrf, mock_markdamaged):
    del mock_xsrf  # Unused.
    self.login_endpoints_user()
    mock_markdamaged.side_effect = device_model.UnauthorizedError()
    with self.assertRaises(endpoints.UnauthorizedException):
      self.service.mark_damaged(
          device_messages.DamagedRequest(
              device=device_messages.DeviceRequest(
                  urlkey=self.device.key.urlsafe()),
              damaged_reason='Foo'))

  def test_mark_undamaged(self):
    with mock.patch.object(self.device, 'mark_undamaged') as mock_markundamaged:
      self.service.mark_undamaged(
          device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))
      mock_markundamaged.assert_called_once_with(
          user_email=loanertest.SUPER_ADMIN_EMAIL)

  @mock.patch.object(device_model.Device, 'mark_undamaged')
  def test_mark_undamaged__unauthorized(self, mock_markundamaged):
    self.login_endpoints_user()
    with mock.patch.object(self.service, 'check_xsrf_token') as mock_xsrf_token:
      mock_markundamaged.side_effect = device_model.UnauthorizedError()
      with self.assertRaises(endpoints.UnauthorizedException):
        self.service.mark_undamaged(
            device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))
      self.assertEqual(mock_xsrf_token.call_count, 1)

  @mock.patch('__main__.device_model.Device.mark_lost')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_mark_lost(self, mock_xsrf_token, mock_marklost):
    self.service.mark_lost(
        device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))
    mock_marklost.assert_called_once_with(
        user_email=loanertest.SUPER_ADMIN_EMAIL)
    self.assertEqual(mock_xsrf_token.call_count, 1)

  @mock.patch.object(device_model.Device, 'mark_lost')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_mark_lost__unauthorized(self, mock_xsrf_token, mock_marklost):
    del mock_xsrf_token  # Unused.
    mock_marklost.side_effect = device_model.UnauthorizedError()
    with self.assertRaises(endpoints.UnauthorizedException):
      self.service.mark_lost(
          device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))

  @mock.patch('__main__.device_model.Device.mark_pending_return')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_mark_pending_return(self, mock_xsrf_token, mock_markreturned):
    self.login_endpoints_user()
    self.service.mark_pending_return(
        device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))
    mock_markreturned.assert_called_once_with(user_email=loanertest.USER_EMAIL)
    self.assertEqual(mock_xsrf_token.call_count, 1)

  def test_mark_pending_return_unassigned(self):
    self.device.assigned_user = None
    self.device.put()
    with self.assertRaisesRegexp(
        endpoints.UnauthorizedException,
        device_model._UNASSIGNED_DEVICE % self.device.identifier):
      self.service.mark_pending_return(
          device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))

  @mock.patch.object(device_model.Device, 'complete_onboard')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_complete_onboard(self, mock_xsrf_token, mock_completeonboard):
    self.login_endpoints_user()
    self.service.complete_onboard(
        device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))
    mock_completeonboard.assert_called_once_with(
        user_email=loanertest.USER_EMAIL)
    self.assertEqual(mock_xsrf_token.call_count, 1)

  @mock.patch('__main__.device_model.Device.resume_loan')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_resume_loan(self, mock_xsrf_token, mock_resume_loan):
    self.login_endpoints_user()
    self.service.resume_loan(
        device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))
    self.assertEqual(mock_resume_loan.call_count, 1)
    self.assertEqual(mock_xsrf_token.call_count, 1)

  @mock.patch.object(device_model.Device, 'resume_loan')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_resume_loan__unauthorized(self, mock_xsrf_token, mock_resume_loan):
    del mock_xsrf_token  # Unused.
    self.login_endpoints_user()
    mock_resume_loan.side_effect = device_model.UnauthorizedError()
    with self.assertRaises(endpoints.UnauthorizedException):
      self.service.resume_loan(
          device_messages.DeviceRequest(urlkey=self.device.key.urlsafe()))

  @mock.patch.object(bigquery, 'BigQueryClient')
  @mock.patch.object(root_api.Service, 'check_xsrf_token', autospec=True)
  def test_get_history(self, mock_xsrf_token, mock_bigquery):
    device_request = device_messages.DeviceRequest()
    device_request.asset_tag = '12345'
    request = device_messages.HistoryRequest(device=device_request)

    device_response = device_messages.Device()
    device_response.asset_tag = '12345'

    expected_response = device_messages.HistoryResponse()
    for _ in range(2):
      expected_response.devices.append(device_response)
      expected_response.timestamp.append(
          datetime.datetime(2019, 10, 22, 20, 43, 37))
      expected_response.actor.append('testuser@google.com')
      expected_response.summary.append(
          'Beginning new loan for user testuser@google.com with device 12345.')

    bigquery_response = [
        (u"Key('Device', 5158133238333440)",
         datetime.datetime(2019, 10, 22, 20, 43,
                           37), u'testuser@google.com', u'enable_guest_mode',
         u'Beginning new loan for user testuser@google.com with device 12345.',
         {
             u'ou_changed_date': datetime.datetime(2019, 10, 22, 20, 43, 37),
             u'current_ou': u'/',
             u'shelf': None,
             u'due_date': datetime.datetime(2019, 10, 22, 20, 43, 37),
             u'chrome_device_id': u'unique_id_1',
             u'mark_pending_return_date': None,
             u'asset_tag': u'12345',
             u'last_known_healthy': datetime.datetime(2019, 10, 22, 20, 43, 37),
             u'locked': False,
             u'last_reminder': {
                 u'count': 1,
                 u'time': datetime.datetime(2019, 10, 22, 20, 43, 37),
                 u'level': 1
             },
             u'next_reminder': None,
             u'device_model': u'Chromebook',
             u'enrolled': True,
             u'serial_number': u'123ABC',
             u'damaged': False,
             u'onboarded': True,
             u'assignment_date': datetime.datetime(2019, 10, 22, 20, 43, 37),
             u'damaged_reason': None,
             u'assigned_user': u'testuser@google.com',
             u'lost': False,
             u'last_heartbeat': datetime.datetime(2019, 10, 22, 20, 43, 37)
         }),
        (u"Key('Device', 5158133238333440)",
         datetime.datetime(2019, 10, 22, 20, 43,
                           37), u'testuser@google.com', u'enable_guest_mode',
         u'Beginning new loan for user testuser@google.com with device 12345.',
         {
             u'ou_changed_date': datetime.datetime(2019, 10, 22, 20, 43, 37),
             u'current_ou': u'/',
             u'shelf': None,
             u'due_date': datetime.datetime(2019, 10, 22, 20, 43, 37),
             u'chrome_device_id': u'unique_id_1',
             u'mark_pending_return_date': None,
             u'asset_tag': u'12345',
             u'last_known_healthy': datetime.datetime(2019, 10, 22, 20, 43, 37),
             u'locked': False,
             u'last_reminder': {
                 u'count': 1,
                 u'time': datetime.datetime(2019, 10, 22, 20, 43, 37),
                 u'level': 1
             },
             u'next_reminder': None,
             u'device_model': u'Chromebook',
             u'enrolled': True,
             u'serial_number': u'123ABC',
             u'damaged': False,
             u'onboarded': True,
             u'assignment_date': datetime.datetime(2019, 10, 22, 20, 43, 37),
             u'damaged_reason': None,
             u'assigned_user': u'testuser@google.com',
             u'lost': False,
             u'last_heartbeat': datetime.datetime(2019, 10, 22, 20, 43, 37)
         }),
    ]
    mock_bigquery_client = mock.Mock()
    mock_bigquery_client.get_device_info.return_value = bigquery_response
    mock_bigquery.return_value = mock_bigquery_client

    actual_response = self.service.get_history(request)

    self.assertEqual(actual_response, expected_response)

  def test_get_device_errors(self):
    # No identifiers.
    with self.assertRaises(endpoints.BadRequestException):
      device_api._get_device(device_messages.DeviceRequest())

    # URL-safe key that is still URL-safe, but technically not a key.
    with self.assertRaises(device_api.endpoints.BadRequestException):
      device_api._get_device(device_messages.DeviceRequest(urlkey='bad-key'))

if __name__ == '__main__':
  loanertest.main()

redpajama_set_name: RedPajamaGithub


text:
Homes & Land for Sale in Center Point, Alabama
Center Point Homes for Sale > Standard Real Estate Search
Search by Street Number or/and Name
Street Number or/and Name
Listing Inventory Trend
Move Mouse over Graph
Any $10,000 $20,000 $30,000 $40,000 $45,000 $50,000 $55,000 $60,000 $70,000 $75,000 $100,000 $125,000 $150,000 $175,000 $200,000 $225,000 $250,000 $275,000 $300,000 $325,000 $350,000 $400,000 $450,000 $500,000 $550,000 $600,000 $650,000 $700,000 $750,000 $800,000 $850,000 $900,000 $1,000,000 $1,500,000 $2,000,000 $2,500,000 $3,000,000 $3,500,000 $4,000,000 $4,500,000 $5,000,000 $6,000,000 $8,000,000 $10,000,000 No Maximum
Any $0 $10,000 $20,000 $30,000 $40,000 $45,000 $50,000 $55,000 $60,000 $70,000 $75,000 $100,000 $125,000 $150,000 $175,000 $200,000 $225,000 $250,000 $275,000 $300,000 $325,000 $350,000 $400,000 $450,000 $500,000 $550,000 $600,000 $650,000 $700,000 $750,000 $800,000 $850,000 $900,000 $1,000,000 $1,500,000 $2,000,000 $2,500,000 $3,000,000 $3,500,000 $4,000,000 $4,500,000 $5,000,000 $6,000,000 $8,000,000 $10,000,000
Min Baths
Min Size
No Min 500 sqft 1000 sqft 1500 sqft 2000 sqft 2500 sqft 3000 sqft 4000 sqft 5000 sqft
Max Size
500 sqft 1000 sqft 1500 sqft 2000 sqft 2500 sqft 3000 sqft 4000 sqft 5000 sqft 6000 sqft 7000 sqft 8000 sqft No Max
Any Sizes 0 - 1/4 Arces 1/4 - 1/2 Arces 1/2 - 1 Arces 1 - 2 Arces 2 - 5 Arces 5 - 10 Arces 10+ Arces
Earliest Year Built
Show only New & Price Reduced Listings
Click to View / Hide Home and Community Features: 3 Car Garage, Gated, Single Story, Swimming Pool, . . .
Boat Dockage
Bonus/Game Rm
Den/Study/Office
Enc Patio/Sun Rm
Family/Great Rm
Guest Qtr/House
Tile Roof
Two+ Story
City Light View
Mountain/Hills View
Home Owner Fee
View New Search Results below
Center Point Real Estate Listings
Sort By price (high to low) price (low to high) beds baths footage
Found 48 homes
Select desired properties for listing details and photos. All selections are removed by clicking 'Search' button above.
City Type Beds Baths Ga Sq.Ft. Price
Center Point Single Family Home 4 2 0 $189,900 Reduced by $10,000 (5%) on 01/08/20
Center Point Single Family Home 7 2.5 0 $160,000 Added on 1/21/20
Center Point Single Family Home 3 2 0 $160,000 Added on 1/20/20
Center Point Single Family Home 4 3.5 0 $159,900
Center Point Single Family Home 4 2 0 $152,900
Center Point Single Family Home 3 2 0 $137,500 Reduced by $7,400 (5.11%) on 11/21/19
Center Point Single Family Home 4 2 0 $129,500 Reduced by $400 (0.31%) on 11/19/19
You select 0 listing(s)
Select & Visit another City in AL > > > >
By completing and sending the form above you are giving permission for the sponsoring real estate agent to contact you by email and/or telephone. The data presented are deemed reliable as of the date provided and may or may not be listed by the participating agent/broker. Due to the nature of markets, properties may not still be available at the time of your search. Please proceed and/or contact the participating agent/broker for current availability of Alabama listed properties and the most recently updated information. Sponsored by Alabama Real Estate Agent: Alabama Real Estate, a local broker, .
Alabama Real Estate, Realtor® serving & specialized in Center Point
Contact by Email Home Page: centerpointalabama.househunt.com
© Copyright 1995-2020 HouseHunt, Inc. for www.centerpointalabama.househunt.com

redpajama_set_name: RedPajamaCommonCrawl


Passenger and aircraft security are a vital part of what Biggin Hill provides for its customers.
The Airport has been a participant in the National Aviation Security Program (NASP) for many years and has over 40 people available and trained in house to carry out the security procedures. To complement this, the airport has separate hold and hand baggage screening areas in order that multiple flights can be processed at the same time.
Biggin Hill operates 24 hour security patrols around the entire Airport site with restricted access to the Terminal. In addition the Airport has CCTV and other security measures in place. The patrols include the car park, which is locked at night.


Remember when I posted my favorite diet foods for 2008 and I mentioned that despite loving all the foods/recipes I post to my blog, there are times when I wish I could add a special mark to make sure you don't miss them? Well, today is one of those times, as these chocolate covered wafer rolls are the new found love of my food life. They are beyond delicious and if they sound remotely interesting you definitely should seek them out and try them!
What are they exactly? Well, they are basically like pirouline rolls (round crispy/flaky wafers), except these are different in that they are coated inside with a thin layer of chocolate and then covered with an even more perfect layer of dark chocolate around the outside. The outer layer of chocolate is deliciously thick (*much* thicker than you'd imagine) -- in fact it is so thick, that it is hard to believe that two of these dark chocolate covered wafers are only 120 calories!!
The full nutritionals for the dark chocolate flavor are 120 calories, 6 grams of fat, 1 gram of protein, and 1 gram of fiber -- so they 3 weight watchers points for both or 1 weight watchers point for just one (which is quite satisfying and filling on its own).
I ADORE dark chocolate, since it not only fulfills my chocolate cravings, but it is also known to be more healthy than milk chocolate, since it has antioxidants in it, which are believed to help lower blood pressure and protect against heart disease.
The wafer rolls also come in milk chocolate and peanut butter for 10 more calories. All of the flavors are all natural, and do not contain hydrogenated oils, artificial flavors or colors, high fructose corn syrup, or preservatives.
I found these QBel wafer rolls hiding amongst all the giant chocolate bars at whole foods, and I'm so glad I did!!
Do they have any flavor besides chocolate? I'm allegic!
They sound delicious. But how can you eat just one?!
The peanut butter flavor sounds good!Are they vegan??I used to love wafer rolls filled with chocolate!
You should start posting the food items' picture so users can see the siz of the wafers, say, compared to a dollar bill or pencil. It would help many of us gauge the portion size! Thanks for a great blog!
Thanks for the suggestion -- the wafers are about 4.5 inches long.
I know this is an older post but I tried these on your recommendation....yummy! I'm on WW too and the only problem I have is eating just one package. It's totally worth it for 3 points as long as I can stick to the one package. I wish they were sold on Amazon!
Thank you, thank you, thank you!!! I LOVE these! Is it cheating if I have one in the morning and one in the evening so that I can count it as two points instead of three?
What's so cool is that this company is right here in Nyack, NY! We're practically neighbors! I bough a whole box of these from my local Back to Earth. Totally yummy!


It is always a daunting experience turning up to a gig and being greeted by an empty room, but unfortunately with ten minutes to go until the first support took to the stage, that is exactly what lay before me. Much to my relief a steady trickle of fans began to filter through the doors of East Village Arts Club (EVAC) and with moments to spare a respectable gathering had formed.
Almost unannounced, Highfields began their set, a jovial yet impeccably executed roster of original songs, heralding a comically large amount of instruments (kudos to the xylophone, triangle, bongo etc. player). Placing their best foot forward, the LIPA collectives glee-inducing set was received rapturously by the ever increasing crowd who almost unanimously were left wanting more. Cattle and Cane were the next on stage, immediately endearing me due to their Northeast accents. Highfields' upbeat jive was replaced with warm folky tones and atmospheric crescendos achieved through dual vocals between male and female members. This was indeed another tremendous attempt to steal the show from the headline act, although since watching Highfields, I can't seem to help but feel most, if not all, music could do with more xylophone.
So now it was time for the headline act, my limbs, had been teased with goosebumps throughout the previous two sets and the expectation for the headline act was tangible. Goldheart Assembly arrived to the loudest applause of the night; on the back of recent summer album release 'Long Distance Song Effects'. Delving straight into that new album, they opened with "Sunday Morning", a harmony based haze of delicate guitars and impressively crafted vocals. This theme endured throughout the whole set, every musician playing their part in creating the experimental folk sound that has earned them acclaim over both albums.
There was, unfortunately, something missing. For all their raw ability and stunning vocal work, the repetition of that same formula meant the set suffered a distinct feeling of 'De Ja Vu'. Don't get me wrong, I enjoy knee-weakening, romanticism-heavy experimental-folk ballads as much as the next guy, but there's only so much an individual can take before their knees begin to buckle, somewhat. Due to this, the standout moments of the night came through the transitions between melodious organic verse to riff-heavy pop rock bridges, seen in "Hope Hung High" and "So Long St Christopher".


text:
Your pillar of strength in the legal community.
Special Counsel on Facebook
Special Counsel on Twitter Follow
Special Counsel on Google+
Special Counsel on LinkedIn
Technology and eDiscovery
Attorney Recruiting
Legal Talent
Legal Job Opportunities
Top 10 Legal Jobs
Collateral Library
About Special Counsel
Concise® Deposition Summary Service
Alderson® Court Reporting
How to Reduce Your Threat of Cyber Attacks in Wake of China Hack Allegations
With all the news coming out of Washington last week as part of the confirmation process for Supreme Court Justice nominee Brett Kavanaugh, and the disclosure by Facebook of a breach that affected at least 50 million users, it would be easy to miss the equally significant story about the latest variant of nation-state cyberwarfare.
On Thursday, October 4, Bloomberg Businessweek reported that agents of the Chinese government may have inserted rouge computer chips into hardware used by "30 companies and multiple U.S. government agencies." Regardless of if this story proves to be true, it represents a dangerous actual or potential escalation of the cyber battles waged between nation states.
Advanced Persistent Threats Definition
Typically, government supported, or condoned cyber attackers use a method known as advanced persistent threats (APT). University of Maryland computer networks and cybersecurity professor, Dr. Sam Musa, defined APT as "a set of stealthy and continuous hacking processes often orchestrated by humans targeting a specific entity."
Do you have a response plan in place for potential litigation? Download this eBook to develop your resources in advance to prevent the headaches that arise from the need to scramble and the bottlenecks that accompany it.
APTs are typically used for business or political motives. By definition, advanced persistent threats consist of three major elements. First, advanced methods such as malware are used to exploit vulnerabilities in a system. Second, a persistent process must exist. Persistence can refer to continuous monitoring of the system, or the continued presence of the underlying threat. The last element, obviously, is a threat, often a human or group who is involved in orchestrating the attack.
History Behind Current Allegations
Before discussing why the present allegations denote a dangerous escalation in a decades long "cold" war between the U.S. and China, we need to step back and discuss where the accusations originate.
In 2015, as part of the due diligence conducted for a possible acquisition, global tech company Amazon conducted an evaluation of the security of the company that was being considered for acquisition. A first pass review of Elemental Technologies caused Amazon Web Services (AWS), the department tasked with completing the due diligence, to discover an alarming fact. The motherboard for the servers that Elemental sold to customers contained a small microchip that was not part of the original designs of the boards sold by Super Micro Computers Inc. to Elemental.
An investigation was conducted by U.S. government officials after Amazon informed them of the discovery. The investigation found that servers sold by Elemental were present in data centers for the U.S. Department of Defense, the Central Intelligence Agency's drone operations center, and onboard several Naval warships. More alarming is that Elemental is only one of Supermicro's customers. Finally, the investigation found that the chips appear to have been inserted on the motherboards while they were being manufactured at subcontractor sites in China.
APT attacks, like other malware and cyberattacks can typically be discovered by trained forensic investigators using specialized analysis techniques, indicators of compromise (IOCs), and automated tools that scan for abnormalities. A hardware vulnerability, such as the Supermicro issue, is largely immune from these types of investigative techniques. Further, a chip by chip, granular, manual review of each part of every desktop, laptop, or server in most organizations would require a specialized team of skilled experts that most organizations cannot support.
If U.S companies have learned anything in the wake of the Sony hack, the Target data breach, and the recent Facebook hack, it is that information is power.
With 75 percent of the world's mobile phones, and 90 percent of PCs manufactured in China , the revelation that state sanctioned insertion of malicious computer chips occurred is a problem that must be addressed. It seems rather fortuitous that at the same time that California passed and has begun the process of preparing to enforce its new Consumer Privacy Protection Act, the discovery of a massive threat to U.S. consumer and national security data was made public.
If U.S companies have learned anything in the wake of the Sony hack, the Target data breach, and the recent Facebook hack, it is that information is power. According to a 2017 report from IBM , the equivalent of 2,273,736 terabytes of data are created each day. In the same year, cyberattacks cost US companies an average of $1.3 million. As early as 2012, when the famed Stuxnet attack on Iranian nuclear facilities took place, governments were characterizing cyberattacks in militaristic terms.
In a 2012 article , Edward Snowden journalist Glenn Greenwald noted that the Pentagon went on record to say: "If any cyber-attack is directed at the U.S. –rather than by the U.S.–it will be instantly depicted as an act of unparalleled aggression and evil." The Pentagon decreed that any cyberattack on the U.S. would be deemed "an act of war."
What Companies Can Do to Improve Cybersecurity
In 2008, as a response to massive data losses experienced by organizations, the SANS institute, a private for-profit company in the U.S., created the Critical Security Controls for Effective Cyber Defense (known colloquially as "CSCs" or "Critical Security Controls"). The Critical Security Controls are a list of twenty key actions that an organization can and should take to prevent or mitigate cyberattacks.
The underlying principle of the CSCs is the Pareto Principle. Commonly known as the 80/20 rule, the Pareto Principle and the application of the CSCs significantly reduces attack success. The Center for Internet Security, the organization that now maintains the CSCs, states on their website, "Organizations that apply just the first 5 CIS Controls can reduce their risk of cyberattack by around 85 percent. Implementing all 20 CIS Controls increases the risk reduction to around 94 percent."
To ensure that the information technology and cybersecurity program of any organization is as robust as possible, a combination of internal and external risk assessment must occur. Additionally, the need for continuous monitoring of the supply chain and third-parties, and analysis and testing of items provided or tasks completed as they move through the chain must occur.
This undertaking cannot and should not be completed alone. Leveraging the expertise of an outside security consultant will ensure that an organization benefits from information sharing and vulnerabilities from the wider ecosystem. If, for example, the previously discussed vulnerability had not been shared in mainstream media, it would be likely that most companies would never have gone looking for it.
Categories: Cybersecurity
Attract & Retain Top Talent
With a rapidly changing industry, it's vital to offer the right compensation and set the right expectation. With our Salary Guide, get detailed job descriptions, industry insights and local salary data to equip your managers with hiring confidence and expertise.
Get your copy »
Get email updates about more content like this.
I'm a job seeker I'm an employer
| Next articles in The Column blog |
Legal Staffing
Jobs Reports
Transactional eDiscovery Pricing: Death of the IN/OUT Cost Model
Learn how the shift to the cloud solutions, and more explicitly RelativityOne, is shaping the future of transactional eDiscovery pricing models.
Read Post »
How to Write an Effective Thank You Letter
Here are 5 steps for to following-up after an interview with a thank you letter to make the best impression on employers.
Get the foundation you need to hire the best legal talent.
Request your copy of our 2019 Salary Guide »
3 Ways Managed Document Review Can Benefit Your Next Case
Here are the 3 reasons conducting a managed document review will benefit your next case.
How to Research a Law Firm for An Interview: 4 Questions to Get You Started
When you're facing an important interview, knowledge is your best friend. Take a look at these tips on how to research a law firm before an interview.
Why You Need to Restructure Your Organization's Innovation Goals
CEO of FutureThink, Lisa Bodell, explains why you should rethink your organization's innovation goals in this ILTACON recap.
3 Reasons Why You Shouldn't Ghost Your Recruiter in the Legal Industry
Here are 3 reasons why not to ghost your recruiter by cutting off contact during the interview process in the legal industry.
How to Network at a Conference: 5 Tips to Help You Succeed
These 5 tips will help you learn how to network at a conference in order to expand your professional circle and improve your career.
Being a 2018 Adecco Win4Youth Ambassador
Sharon A. McLaughlin details her experience as a 2018 Win4Youth Ambassador, while highlighting the effort put into training for the upcoming triathlon.
Basic eDiscovery Early Case Assessment Checklist
Here is a basic look at what ECA is, why it should be implemented in your workflow, and a quick Early Case Assessment Checklist for your next case.
Writing Samples for Legal Jobs: 5 Things You Need to Know for Your Interview
To help you put your best foot forward, here are 5 things to know about writing samples for legal jobs.
Get to Know Our Partner Group: Change is Good
Change is good for many reasons, others believe it will have a negative impact on their life or career. Learn why some reasons why change is good for you.
Data Reuse in eDiscovery: 4 Questions to Help Start Your Policy
The subject of reusing data by organizations that are involved in serial litigation is a popular topic of discussion, and often is seen as ideal, if not often practiced.
6 Best Practices for Managing Your Online Persona After Law School
Here are some best practices for managing your online profiles to be more appealing to potential law firms.
Negotiating Your Salary 101
You've successfully navigated the interview process and your dream job is within your reach. But it's not over yet because now it is time to negotiate the offer. But, if you prepare, and take into consideration a few important factors when you enter "the room", you can leave the negotiation knowing you represented yourself well. Learn more about how to negotiate your salary.
5 Things To Do to Help You Get a Job After the Bar Exam
The actions you take after the bar exam will help you succeed in finding legal employment. These 5 tips will help you get a job after the bar exam.
5 Life Lessons Learned from Completing a Triathlon
As Win4Youth 2018 quickly approaches, take a look at the training insight and advice given by our 2017 ambassador that competed in the Win4Youth triathlon in Spain last September.
How eDiscovery Managed Services Can Benefit Any Team
There is a common misconception in the legal industry that eDiscovery managed services are only a feasible option for larger law firms and corporations.
X1 Discovery's Insight & Collection Shows Promise to Close the Gaps in the EDRM
This week I participated in a webinar and live demo of X1 Discovery's Insight & Collection and its integration with Relativity One. What we saw from that demonstration was truly impressive.
Q&A with a Legal HR Professional
We recently sat down with Heather and asked her a few questions about D4, our Culture and why having an HR professional is such an important part of every organization today.
What is the GDPR? 4 Basic Facts Experts Want You to Know
It has been nearly 2 months since updates to the General Data Protection Rules (GDPR)have taken effect.
What an Experienced Project Manager Wants You to Know About Legal Document Review
Project manager from Special Counsel, Kalyn Johnson, answered questions about the legal document review process and specifically how the managed review workflow can help you.
How to Prepare For In-House Legal Interviews
These 4 tips can help candidates effectively and thoroughly prepare for in-house legal interviews.
Social Media Law Update: Your Tweets, Tom Brady, and Violating Copyright?
This blog was originally published by our partners at Relativity.
Why It's Important to Understand Paralegal Qualifications in Your State
This blog explains the role of paralegals under the California Business and Professions Code – and the result of insufficient paralegal qualifications when called into question.
Why It is Crucial to Have a Litigation Response Plan
When does the destruction of email messages of a named plaintiff by the defendant's IT department lead to sanctions?
3 Tips from Document Review Project Managers
Here are 3 tips from document review project managers that will help make your next review more efficient.
On-the-Spot Job Offers
One trend that Parker + Lynch legal is noticing is that firms are making offers on-the-spot to candidates at the conclusion of their interviews. As recruiters, we have seen both sides of this play out; here are some reasons why your firm may want to consider this approach.
A Quick Look at the In-House Staffing Trends in 2018
Presented here are the "big picture" in-house staffing trends trends we're seeing on hiring and staffing solutions for America's corporate legal departments.
7 Factors to Consider Before Creating an Email Retention Policy
These 7 considerations will help you create and implement a corporate email retention policy that is defensible and meets the needs of your organization.
5 Things You Need to Know About the Managed Review Process
Despite variation in managed review projects, these 5 guidelines will help you strategically plan a defensible workflow for your next managed review process.
7 Steps to Create Positive Work Environments for Attorneys
Employers play a significant role in helping to manage the effects of the immense stress and pressure that attorneys' face. Use these steps to help you create a positive work environment for attorneys' to increase their overall job performance.
Burdensome eDiscovery Requests: How to Manage the Cost of Review
How do you respond when opposing counsel argues that it is not possible to cull a large, collected data set with potentially responsive data by applying keywords because of the…
My Special Counsel #CEO1Month Journey
Yolian Ogbu, Special Counsel's CEO For One Month candidate, shares what she's learned about business and entrepreneurship as she shadows the Special Counsel President in Washington, DC.
Motherhood: A Performance Review
A woman's work is never done. According to the 2018 Mother's Day Index, mom's overall "annual wage" increased 1.
National Law Day
National Law Day is held on May 1st every year to celebrate the role of law in our society and to cultivate a deeper understanding of the legal profession.
Intellectual Property Lateral Trends – The Not So Obvious
Happy World IP (Intellectual Property) Day, and welcome to the first installment of Parker + Lynch's "Lateral IP Trends" series.
Administrative Professionals Day: How Administrative Support Can Help New Lawyers
Starting a position as a new lawyer is both exciting and overwhelming. However, there are many day-to-day tasks that need to be completed which are not taught in law school. Learn more about how the legal administrative support professionals at their job can help.
Lateral Gracefully: How to Leave Your Current Firm
Have you ever "ghosted" at a social gathering? You know, just left a party or a bar without telling anyone you were going to leave?
Understanding Patent Law and the Role of a Patent Attorney
A patent is a legal protection for inventions, designs, products and processes that are novel, "non- obvious," and useful. Consider the patent law practice in three functional areas: patent preparation, patent protection and patent administration.
Recent Accolades Reinforce Why D4's Powered by People
When you think of an eDiscovery company, the first things that might come to mind are along the lines of specific software, data workflows, document review or data productions.
Understanding the Role of Tax Attorneys
Attorneys working specifically on tax-related matters may serve in government bodies, nonprofit organizations, corporations or law firms. Whatever the context for their work, however, these professionals all help clients manage issues related to tax law. And with the recent tax revisions, 2018 is proving to be an interesting time for legal professionals dealing with tax law.
What is Intellectual Property Law?
The U.S. Constitution authorizes Congress to protect intellectual property—the fruits of mental labor. Article One includes this statement of purpose: "…To promote the Progress of Science and the useful Arts, by securing for limited Times to Authors and Inventors the exclusive Right to their respective Writings and Discoveries." As a new lawyer, what career opportunities might intellectual property law present for you?
Checking Out Batches in Relativity
Everyone who's been involved with a Relativity review has either used, or at the very least heard of batch review. But, what does that mean and how does it affect you as a reviewer?
Control the Cost of eDiscovery: Do You Know What to Outsource?
When looking to reduce litigation and eDiscovery costs, the first step is to evaluate your current spending.
How to Write a Cover Letter: Junior Associate
As a candidate, you must present an accurate and compelling value proposition when applying for a Junior Associate position. When you do, you'll increase the chances of making a solid step towards your professional goals. That's where the cover letter comes into play.
How to Write a Cover Letter: Legal Assistant
The second in our "cover letter" series, we've examined the Legal Assistant position. We'll tell you how it differs from a Legal Secretary and how can you stand out during the application process. The cover letter is your chance to set yourself apart during the application process - so read on!
How to Write a Cover Letter: Legal Secretary
When applying for a Legal Secretary position, your application itself is a crucially important work product. Yes, the recipient will scour your work history, your academic background, etc.—but this "screener" also will be looking at how well you present yourself when it comes to important correspondence. The cover letter is your chance to shine.
Helpful Tips and Tricks for Searching in Relativity
Here are some helpful tips, tricks and minor updates when searching in Relativity to help you plan for a more efficient process.
IT & Cybersecurity
Litigation & Trial Consultants
Technology & eDiscovery
Software & Training
Office 365 eDiscovery
Forensic & Collections
Paper Operations
Law Firm Associate Recruiting
Partner Placement
In-House Counsel Recruiting
Contract Attorneys
Contract Legal Support
Direct Hire Legal Support
Legal Technology Recruiting
© 2018 Special Counsel
Shaping solutions together:
Concise Deposition Summary Service
Alderson Court Reporting


text:
Renowned Art School at Risk of Closure
Malmö Art Academy has been given notice to vacate its premises in one year. According to Dean Gertrud Sandqvist, this could imply that the school is will be forced to close.
By Frida Sandström	 17.06.16 News	Artikel på svenska
The Art Academy in Malmö.
Over the course of the past week, Malmö Art Academy has been subject to a lively debate in social and national media. The reason is that the school has been given notice to vacate its premises located in a former elementary school in west Malmö.
Presently, 4,918 signatures have been collected by the petition "Save Malmö Art Academy", which has circulated online since Monday. In the appeal, the termination of the institution's lease is described as definite, but in fact such a decision can be made only when the municipal board convene next in August and September. In order for the academy to vacate by the summer 2017, the lease has to be cancelled before October 1, 2016. The purpose is to make room for renovations during 2017–18, after which a planned elementary school could move into the premises in the fall of 2018.
Malmö Art Academy is part of Lund University, and since the beginning of the year there has been a plan in place that would merge the university's faculty of the arts, which includes institutions for music, theatre and fine arts,together into a larger campus. Until the inauguration in 2023 at the earliest, Malmö Art Academy has been promised that it can remain in the building where it has been located since 1995, or that it will be offered a comparable facility.
During a meeting on June 9, dean Solfrid Söderlind of The Faculty of Fine and Performing Arts was notified that the Malmö Art Academy must vacate its premises. She calls attention to the fact that a university operation does not relocate painlessly. The regulations that have to be followed are many, while time is short.
– It takes planning more in advance, and it is futile to refer to the new campus planned ten years from now, Söderlind tells Kunstkritikk, and stresses that Lund University will not shut down the art academy, and that the City of Malmö, too, wants the institution to stay in the city.
– The sudden turn implied by a notice to vacate without any alternative has however forced the university into crisis planning, she says.
In an article titled "Rethink, Malmö!", the directors of the region's contemporary art spaces and museums raise the fact that Malmö Art Academy was the only school in the country to have all its educational programs, including bachelor's, master's, and doctoral levels, given the highest estimation by the Swedish Higher Education Authority, in their review of Swedish art education in 2014. Furthermore, it was at Malmö Art Academy that the first doctoral theses in fine arts in the Nordic countries were presented by Matts Leiderstam, Sopawan Boonnimitra and Miya Yoshida Iwasaki in 2006.
Anders Rubin.
Now, ten years later, the social democratic municipal commissioner of education in Malmö, Anders Rubin, claims that it is easier to find new premises for a school of 60 adults than for young people in Malmö, where the population is growing at a fast rate. He therfore sees no alternative than giving notice to the art academy and instead housing a new elementary school in the premises. He stresses that the City of Malmö is responsible for the young students, while Lund University is responsible for the Malmö Art Academy.
– Usually we do not offer spaces as favourably as in the case of the Art Academy. This is about prioritizing the property that we have, and as a landlord giving notice to the Art Academy. Our ambition is not to shut down the school, Rubin tells Kunstkritikk.
Director of Malmö's city planning office, Christer Larsson, emphasizes that the relocation of the art academy will be done in consultation with Lund University, and will be discussed in a meeting with the university's vice-chancellor, Torbjörn von Schantz, on June 28. Larsson, too, stresses the importance of the art academy to Malmö and the Skåne region.
– That is why the city of Malmö has collaborated with Lund University for some time, in order to find new ways forward, says Larsson, who stresses that the art academy will not be tossed out without being offered a satisfactory alternative.
The Dean at Malmö Art Academy, Gertrud Sandqvist, is worried by the fact that the school's management has not yet been notified about any such alternatives. According to her, it is difficult to imagine how a satisfactory alternative could be provided by the fall semester of 2017, and she stresses that a possible alternative space must meet the institution's criteria for studios and workshops.
Gertrud Sandqvist.
– We cannot conduct an art education without adequate facilities, which is why a relocation could force us to close the school and phase out current students, Sandqvist tells Kunstkritikk.
Sandqvist notes that the City of Malmö had the school renovated in the 90s, when it was threatened with demolition, into what is now the fully functional study environment of the Malmö Art Academy. This includes workshops for many artistic media, as well as separate studios with natural light. Sandqvist stresses the importance of these places for individual study, claiming that this is primarily where the students develop their artistic practice.
– The studio provides the student with an environment that resembles, to the greatest extent possible, the professional art world. A substantial part of artistic practice is individual work, but it is up to the student how to use it, she says and draws attention to the school's fundamental premise: that the student invites visitors to their space, not the other way around.
Viktor Rosdahl.
Viktor Rosdahl is one of many alumni who, after graduating from Malmö Art Academy, have received prestigious awards such as the Maria Bonnier Dahlin grant. He is shocked by the news about the notice to vacate, and is among those who have returned to the school building this week to help with the work that is done now to emphasize the school's importance.
– The art academy regards you as a professional artist and this makes it possible for you treat your own work as such. This possibility distinguishes the school from other art academies in the Nordic countries that I have visited or taught at since I was a student in Malmö, says Rosdahl. He stresses the benefit of studio practice to the students' development at the art academy, which has resulted in several internationally active artists as well as locally based studio collectives and galleries such as Galleri CC, CEO, Woodpecker Projects and MFK (The Malmö Free University for Women).
– In another environment, this development would not be possible, says Rosdahl.
Failing to see the consequences of such a well functioning school risking having to close is ominous, according to Gertrud Sandqvist, and all too similar to the planned reconstruction of Lund's Konsthall six months ago. Similar to the konsthall, the Malmö Art Academy has received great international support that reminds how important the school is to contemporary art. Yet Sandqvist wishes to emphasize the school's influence locally.
– It would be catastrophic for both the city and the region if the school disappeared, she says.
On Friday Malmö Art Academy is open to all from 7pm. Besides exhibitions and the present petition, two tours of the school will be given.
Norsk kunstscene i Art Review
For et par uker siden skrev vi om ryktene om et Norge-bilag i den kommende utgaven av Art Review. Nå er nummeret ute.
By Ketil Nergaard 23.11.06 News
Art Criticsm
Comment Share Print
By Tegneklubben 23.05.11 Tegneklubben


text:
module ("bin", package.seeall)

--- Turn a little-endian word into a number
function le_to_number (s)
  local res = 0
  for i = #s, 1, -1 do
    res = res * 256 + string.byte (s, i)
  end
  return res
end

--- Turn a little-endian word into a hex string
function le_to_hex (s)
  local res = ""
  for i = 1, #s do
    res = res .. string.format ("%.2x", string.byte (s, i))
  end
  return res
end


text:
Category archive: Obituaries
William B. Booker
September 28, 2012tdomf_b2d59Obituariesno comments
ST. GEORGE — William B. Booker, 85, of Rangeley, passed away peacefully on Sept. 27, surrounded by his loving family. He was born June 28, 1927, in Boston, Mass. He grew up in Bangor, and attended local schools. During his high school years, he left school and joined the U.S. Navy du…
George "Wes" Weston Brooks
September 24, 2012Rangeley News HoundObituariesno comments
OTISFIELD — George "Wes" Weston Brooks left this world peacefully in his home of Otisfield, on Sept. 21. A native of Rangeley, born to Merle and Rachel Huntoon Brooks on Feb. 25, 1936, a Class of '53 graduate of Rangeley High School, he went on to serve his …
George Gatling Long
September 12, 2012Rangeley News HoundCommunity News, Obituariesno comments
AUBURN — George Gatling Long, 62, of Rangeley, formerly of Greenport, Long Island, N.Y., sadly passed away Wednesday, Aug. 29, at Androscoggin Hospice House, surrounded by his loving family and great friends. He was born May 18, 1950, in Greenport, Long Island, N.Y., a son of Robert Jennings and Winifred (Gatling) Long.read more
Azel I. Campbell
FARMINGTON — Azel Irving Campbell, 86, died on Sept. 6, at the Sandy River Center for Health Care. He was born Jan. 3, 1926, in Phillips, the son of Clarence and Ezma (Springer) Campbell. He was educated in the schools of Phillips. During World War II, he served in the U.S. Marine Co…
George G. Long
September 2, 2012Rangeley News HoundObituaries1 comment
AUBURN — George Gatling Long, 62, of Rangeley, formerly of Greenport, Long Island, N.Y., sadly, passed away Wednesday, Aug. 29, at Androscoggin Hospice House in Auburn, surrounded by his loving family and great friends.
George A. Roth Sr.
September 1, 2012Rangeley News HoundObituariesno comments
WESTBROOK — George Arthur Roth Sr., 76, of Rangeley, passed comfortably Monday, Aug. 27, at the Springbrook Center, after a short, but intense battle with cancer. He was born Dec. 5, 1935, in Brooklyn, N.Y., to George and Grace (Lawless) Roth. George graduated from St. John's P…
Janice G. Rand
August 31, 2012tdomf_b2d59Obituariesno comments
AUBURN — Janice Gertrude Pillsbury Rand, 81, passed away Aug. 28, at Clover Health Care Facility surrounded by her loving family, due to complications of Alzheimer's disease. She was born in Rangeley, Jan. 2, 1931, the daughter of Vern G. Pillsbury and Annie Stewart Morton Pill…
Agnes M. 'Aggie' Morin
August 22, 2012Rangeley News HoundCommunity News, Obituariesno comments
FARMINGTON — Agnes M. "Aggie" Doyen Morin, 72, of Farmington, formerly of Rangeley, died Wednesday, Aug. 15, 2012, at the Franklin Memorial Hospital, with her loving family at her side.read more
Margaret " Peg" Callahan Stinchfield (1916-2012)
August 13, 2012Rangeley News HoundObituariesno comments
PHILLIPS – Margaret " Peg" Callahan Stinchfield, 95, died on Sunday, August 12, 2012 at the Maplecrest Rehab and Living Center in Madison. She was born on December 22, 1916 in Farmington, the daughter of John A. And Maude E. (Foley) Callahan
Lee R. White
July 28, 2012Rangeley News HoundObituariesno comments
PHILLIPS — Lee R.
Page 23 of 24‹‹››


Condensing gas boiler for central heating and hot water in a boiler - ZSB (with the connection of a ..
Hot water tank for use with all JUNKERS boilers. | Description:Made of enamelle..
Gas fired boiler for central heating up to 280 m2 and hot water heating for flow-through. Flue-gas d..
CeraclassExcellence - atmospheric gas boilers. Heating and warm water-preparatory power 24kW. Hot wa..
Condensing gas heating boiler for central heating and hot water preparation according to the flow pr..
CeraclassExcellence - atmospheric gas boilers. Heating and warm water-preparatory power 28kW. Hot wa..
Condensing gas boiler with connection to the boiler. Designed for premises up to 140 m2.The grea..
Condensation gas boiler with boiler connection. Designed for areas up to 220m2.The greatest adva..
Condensing gas boiler with built-in heat exchanger for the preparation of sanitary water. Designed f..
Hot water tanks are designed for use with CERAPUR COMFORT, CERAPUR MAXX boilers. | Des..
Condensing gas boiler with flowing function of hot water. Designed for premises up to 350 m2.The..
Tanks for hot water are designed for use with all Junkers wall-mounted boilers. | Desc..
Gas condensing boiler for heating and hot water preparation in flow mode. | Description..


text:
Tag: science fiction
Rage: A Review of Iron Widow, by Xiran Jay Zhao
On October 30, 2021 October 29, 2021 By Michael CostanzoIn Book ReviewLeave a comment
Revolution has always been a major theme across literature, and nearly every young adult novel features the concept in some way. Stories are full of characters challenging the status quo and pushing back against injustice. However, there is usually a limit, a disconnect, which separates the injustices on the page from the injustices in the real world. Mainstream readers can enjoy a series such as The Hunger Games without connecting the dots between the world in the novels to the real world. Whenever a book comes along that does challenge its readers to think critically about our own reality and history, there can be hesitancy. Publishers do not think it would sell well, publicists worry about potential backlash, and more. Yet, there is an audience for literature such as that, literature that combines entertainment with real revolution, and that audience is getting larger and more vocal every year, hungry for more.
Continue reading "Rage: A Review of Iron Widow, by Xiran Jay Zhao" →
Practical Villainy: A Review of Hench, by Natalie Zina Walschots
On February 18, 2021 February 17, 2021 By Michael CostanzoIn Book ReviewLeave a comment
This is no longer the Golden Age of Superheroes. We are long passed the silver and bronze ages as well. In the world of comic books, and superheroes in particular, we currently find ourselves the Modern Age. A literary and creative time period where superheroes cannot be taken at face value anymore, where the implications of people with extraordinary powers must be considered and no longer ignored. We have seen this trend in both comic books and film, where a certain practicality has been applied to thinking about superheroes and their effects on the world. Readers and consumers of superhero fiction are not content with just watching Superman demolish buildings in order to stop the latest villain's world-ending plot. We need creators to consider the people in those buildings. There are generations of people today—like millennials and gen Z—who have been raised on tragedy and destruction. Terrorist attacks, never ending school shootings, and plagues were out childhood. Like these disasters, literature cannot ignore the destruction and death caused just off-page when superheroes and supervillains clash. Because, when you truly think about it, the idea of a superman in real life is horrifying.
Continue reading "Practical Villainy: A Review of Hench, by Natalie Zina Walschots" →
Removing the Mask: A Review of Chaos Reigning, by Jessie Mihalik
On September 30, 2020 September 30, 2020 By Michael CostanzoIn Book ReviewLeave a comment
There are times when you pick up a book expecting to be surprised. You look forward to twists and turns to keep you on your toes. Insurmountable odds that the main characters must struggle to overcome, coupled with prose posing philosophical debates about the characters actions. These are books that are meant to bring you out of your comfort zone. However, especially in this day and age, we could use a bit of comfort. Jessie Mihalik's Consortium Rebellion trilogy, culminating in Chaos Reigning, is the comfort food of science-fiction. You go into the third novel knowing what you want and what you expect from this series. A cool heroine who learns to embrace her abilities and find her confidence, a steamy romance with a considerate and strong man, and a healthy dose of sci-fi adventure.
Continue reading "Removing the Mask: A Review of Chaos Reigning, by Jessie Mihalik" →
The Omnipotence Paradox: A Review of The God Game, by Danny Tobey
On May 15, 2020 May 14, 2020 By Michael CostanzoIn Book Review1 Comment
Artificial intelligence has become one of the most common staples in science-fiction, the embodiment of human concerns with being replaced. Our collective worry about creating machines smarter and stronger than us crystallized into its own genre. Artificial intelligence, or A.I., is all over fiction, yet very difficult to get just right. For every successful A.I. story, there are piles of unsuccessful ones. Isaac Asimov's I, Robot, William Gibson's Neuromancer, Alex Garland's Ex Machina, and Masamune Shirow's Ghost in the Shell all come to mind as stories about A.I. done right. Unfortunately, The God Game by Danny Tobey never quite reaches the heights its predecessors achieved.
Read the Rest!
The Power Dynamics of Identity: A Review of Splintegrate, by Deborah Teramis Christian
Every story has a theme, a focus running side-by-side with the plot that thoroughly defines the very nature of the book. When a person asks what a book is about, there are always two answers; the plot, and the themes. For example, The Lord of the Rings is about the battle between good and evil, and the nature of heroism. It is also the story of a hobbit crossing the world to throw an evil ring into a volcano. In a similar vein, Splintegrate, by Deborah Teramis Christian, is a story about bodily autonomy and the nature of identity. It is about what happens when outside machinations violate one's body and personality without consent. It is also an engaging science-fiction thriller about a professional dominatrix charged with assassinating a mob boss. The high level of technology present in a science-fiction setting allows for a practical examination of identity outside of the thought experiments of today.
Immortal Cavalier: A Review of Gideon the Ninth, by Tamsyn Muir
On January 8, 2020 January 7, 2020 By Michael CostanzoIn Book Review1 Comment
Science-fiction and fantasy may appear to be very different genres at first glance. Once is full of advanced technologies, with a focus on scientific progress and how that works within the setting. Fantasy focuses on magic and oftentimes breaking the rules of the physical world in the pursuit of power. However, the two are full of more similarities than differences. Both can take place on Earth, or on another world. The world can have creatures other than humans, be they aliens or elves. Fantasy can sometimes show technology powered by magic, while highly advanced technology can sometimes appear indistinguishable from magic depending on who witnesses it. Popular franchises such as Warhammer, Isaac Asimov's Foundation series, and even Star Wars, all find compelling ways to blend genres. Gideon the Ninth, by Tamsyn Muir, blends science-fiction and fantasy in a wonderfully gruesome way.
Mapping the Stars: A Review of The Forbidden Stars, by Tim Pratt
On November 14, 2019 November 13, 2019 By Michael CostanzoIn Book ReviewLeave a comment
Science-fiction is one of the most versatile genres of fiction around, capable of combining settings with any other tale. Science-fiction as a genre is also a bit of a misnomer. The average science-fiction story is not just science-fiction. Tales can be action films, adventure stories, romance, horror, and more. From Blade Runner to Black Mirror, from Polaris Rising to Foundation. Science-fiction can be defined by both fun and thoughtfulness, and there is always a place for a fun adventure that does not require readers to analyze every paragraph. Books like The Forbidden Stars, Tim Pratt's third novel in the Axiom trilogy, show the importance of such escapism while also taking the opportunity to define a possible future. While entertaining, the novels also take some time to normalize behaviors and lifestyles, sexual orientations and body modifications. Science-fiction lets us see all futures and revel in them.
Never a Hindrance: A Review of Aurora Blazing, by Jessie Mihalik
On November 6, 2019 November 5, 2019 By Michael CostanzoIn Book Review1 Comment
There is a certain amount of joy gained in reading some fiction. Fiction meant to entertain, to transport the readers to fantastical worlds and witness the deeds of heroic peoples. Where literary fiction tends to prioritize specific word choice and meaning over plot and character, many authors realize that there can be greater value in drawing in and entertaining your audience. Sometimes the best books are the ones that make you forget that you are reading words on a page, instead conjuring images in your imagination. These are the kinds of books that are hard to put down, and you wonder how you managed to read through them so quickly. These types of books thrive in science-fiction, where most things, if not all things, are possible. The only barrier is the author's imagination.
Time travel is one of the best travelled staples of science-fiction, from books to television shows to movies, it is the ultimate form of exploration. The concept of time travel is almost as old as the history of writing, with the first known written example dating to around 400 BCE. In the Sanskrit epic, Mahabharata, King Raivata Kakudmi journeys to heaven to meet Brahma, the Hindu creator god. When he returns to the moral world, centuries have passed. Time travel in fiction, from this ancient epic to Stargate and Doctor Who, usually involves physically transporting one-self through time, bringing your body and memories with you. Threats include meeting your past self, or encountering the grandfather paradox, or making changes to the past which may affect the future. Very rarely do we get a novel in a similar vein to Kurt Vonnegut's Slaughterhouse Five, where time travel is a person journey into your own memories.
Insurrection: A Review of Tiamat's Wrath, by James S. A. Corey
On July 22, 2019 July 22, 2019 By Michael CostanzoIn Book ReviewLeave a comment
This month we celebrate the 50th anniversary of the Apollo 11 mission, where the first humans in history stepped foot on the Moon. The first steps a human took on a celestial body other than the Earth. For all of known history, we have looked to the stars and wondered what was out there. Today, we know more than we ever have about the worlds beyond our own, but that has does nothing to stop people's imaginations from filling in the blanks. Tiamat's Wrath is the latest novel in James S. A. Corey's ground-breaking science fiction series, The Expanse. Beginning in 2011 with Leviathan Wakes, these books have taken a realistic approach to fictional space travel, using the technology of today to extrapolate and imagine what space exploration may look like in the future. It is not an exaggeration to say that The Expanse is one of the greatest works of modern science-fiction.


It was the first quarter of 2019. RB Builders was aiming – once again – to extend its reputation as a builder that thrives on both the margin and velocity sides of Return on Assets, by expanding into a new geographical market, via the late-2018 acquisition of its sixth existing homebuilding operation.
In terms of market segment, this newly-acquired division was in-line with all but one of the previously acquired operations. Like its predecessors, it had historically generated operating results and business outcomes that are lower than what RB Builders considers acceptable. And, like its predecessors, this new building operation had acceptable current land/lot positions.
Early-on, RB Builders had completed the newly-acquired division's conversion to the enterprise management technology system and started the conversion of its business and operating processes; With this latest acquisition, RB Builders was confident that it could continue its record for unifying, developing, and improving the capabilities of existing teams at the builders it had acquired, transforming them into teams that reflected its own savvy, motivated, and mutually-accountable homebuilding team.
This road had become a familiar path for RB Builders.
HISTORY OF RB BUILDERS: Just over a decade earlier, at the start of 2008, and shortly after the end of the halcyon period known as the Age of Homebuilder Entitlement®, RB Builders had begun its own transformation process, with the objective of extracting itself from what it self-described as "the tar pits of averageness".
Along the way, there had been a number of initiatives, some dealing with workflow, one dealing with scheduling, some dealing the value stream and trade partnering, others dealing with product.
As a result of this program, RB Builders had made massive strides.
During the ensuing five-year period (2008-2012), figured on a same company basis, annual Revenue had grown from $50 million to more than $121 million, an increase of almost 250%. During the same period, the number of closings had increased more than 225%, from 200 to 453 houses per year. Despite margin pressure, overall Gross Margin had increased slightly, from 22% to 24%; as a result, RB Builders' Gross Income had out-paced Revenue, growing by more than 250%, from $11 million to almost $30 million.
During this five-year period, Operating Expense had increased 30% (from $8.5 million to $11 million), far less than the same-period increase in Revenue. As a result, RB Builder's Net Income had risen from $2.5 million to $16.5 million, more than six times what it had been before the company began its transformation; Net Margin had almost tripled, from 5% to 14%.
In 2008, RB Builder's cycle time had been 180 days; by the end of 2012, cycle time had been reduced to 65 days. In 2008, the average amount of work-in-process had been 100 houses under construction; by the end of 2012, the company been able to reduce its average work-in-process to 80 houses under construction, despite closing more than twice as many houses.
In 2008, RB Builders had targeted an inventory turn of 2.5x, which was actually an improvement from 2007; in 2012, by keeping its work-in-process at 80 houses and closing 453 houses, RB Builders had been able to more than double its physical inventory turn, from 2.5x to 5.7x.
In 2008, RB Builders had been able to turn the value of its financial assets twice; in 2012, it turned the value of its assets almost five times. Because it had managed to maintain margins while improving velocity, RB Builders saw its main barometer of economic return (Return on Invested Assets) increase almost six-fold during the five-year period, from 11% in 2008 to 64% in 2012.
In 2013, RB Builders moved all of its raw land holdings and developed lot inventory off of its balance sheet and into subsidiaries, a move which would have further increased Asset Turn – and ROIA – had those two measures been restated to reflect the remaining assets.
By any measure, it had been a remarkable transformation.
The five divisions that RB Builders had previously acquired have all met – or remain solidly on-track towards meeting – their own multi-year plans for significantly increasing closings and Revenue, all without incurring any increase in Operating Expense, all the while maintaining lower levels of work-in-process and operating under reduced construction lines of credit.
NEWLY-ACQUIRED DIVISION: Near the end of 2018, RB Builders acquired this, its sixth homebuilding operation. Unlike the preceding year's acquisition, this acquisition was considered very much in-line with RB Builders' M&A pattern, because of similar product offerings, in the same price range.
For managerial accounting purposes, RB Builders had insisted that this new division (like all of its acquisitions) convert to a Contribution Income Statement format based on a variable costing approach to cost allocation.
In its final year of independent operation, the division had closed 66 houses, and generated $16.5 million in Revenue; with the little more than $13.5 million in restated Cost of Sales now reflecting only its direct, variable costs, the operation had generated just under $3.0 million in Gross Income, producing an 18% Gross Margin. With its $1.8 million in restated Operating Expense now reflecting only its indirect, non-variable costs, the operation had produced almost $1.2 million in Net Income, resulting in a 7.1% Net Income Margin.
Since it carried an average work-in-process of 33 houses under construction throughout 2018, the division had a calculated cycle time of 180 days (despite job schedules that typically called for 120 day completions); 66 closings with an average work-in-process of 33 houses under construction also meant that the division had turned its physical inventory twice (2.0x) in 2018.
Adopting what had become another of RB Builders' mandates, and moving all of its raw land holdings and developed lot inventory off its balance sheet and into subsidiaries, the newly-acquired building operation showed a restated average work-in-process of $4.62 million (the average per-unit LIP balance of $140,000 consisted of a $75,000 average lot takedown and a $205,000 fully-funded LIP balance (100% of cost, 82% of the $250,000 average sales price).
Revenue of $16.5 million gave it an asset turnover ratio of just under 3.6x. For 2018, with its Net Margin of 7.1% and its restated asset turn of 3.6x, the new operation had achieved an ROIA of just over 25%.
Q; How will you address a mandate that your newly-acquired division increase its annual closings by close to 25% over a two-year period, with less work-in-process, a smaller line of credit, and the same amount of overhead?
Q: How will you use Building Information Modeling (BIM) to improve both the margin and velocity sides of economic return? What will your ROBIMI (Return on Building Information Modeling Investment) be?
Q: What cost accounting practices will need to change in order for you to the type of operating decisions that drive the targeted economic outcomes?
Q: How will you create a savvy, motivated, mutually-accountable homebuilding team? A team that understands the business of homebuilding as much as it understands the homebuilding business? How will you give every teammate a significant financial stake in the outcome? What is the baseline, target, and payout reserve?
Q: How will you answer RB Builders' contention that variation – evidenced solely by your 2018 calculated cycle time – is costing your division almost $1.5 million per year in lost Net Income, an outcome that will persist each and every year, until it is addressed. A fact to keep in mind: in 2018, your division had Net Income of less than $1.2 million. Is what they are asserting even possible?
Q: As you analyze it, are you willing to consider replacing, over time, your fully-outsourced building model (requiring a larger, shallower geographic footprint) with a fully-integrated building model (which requires a narrower, deeper footprint)?
Q: How will you use Business Process Improvement (BPI) to remove non-value-adding work and make the remaining value-adding work flow faster, more evenly, more smoothly, with fewer mistakes and rework? How will you build a shorter, straighter pipe?
Q: Can you use Critical Chain Project Management to reduce your job schedules from 150 days to 121 days, while also assuring more reliable job completion dates?
You can always ask us to send you the business case. You can complete it, grade it, and figure out how well – or how poorly – you did. Were you able to answer the questions? Were you able to solve the problems?
If you find as unacceptable – what we'll call it your "degree of attunement" – you should come to the upcoming Pipeline workshop™.
RB Builders: Lessons from the Pipeline© is the underlying business case study used at every Pipeline workshop™. The next workshop is being held March 20-21, 2019, at the Ponte Vedra Inn and Club, in Ponte Vedra Beach, Florida.
This change continues to pay-off. But – we don't ever stop trying to improve the learning; as a result, the Pipeline game™ keeps getting better and better.
For example, at a recent Pipeline workshop™, we introduced a scenario that contrasts the currently accepted growth and operations strategy (a completely outsourced building model) with a radically different growth and operations strategy (a completely integrated building model), in order to explore the difference between a strategy based on a broader, shallower footprint and one based on a narrower, deeper footprint.
The next Pipeline workshop™ will be held March 20-21, 2019 at the Ponte Vedra Inn and Club, in Ponte Vedra Beach, Florida. Cost is $895.00; for team pricing, inquire here: flgroves@saiconsulting.com).


You won't want to miss these must-see area attractions.
It's a new year and that means new adventures. Where are the best places to create new memories this year in northwest Louisiana?
We asked around and found seven places sure to offer a good time.
A short drive to Benton offers a lot to do. Just past the entrance gate is the zoo with beautiful exotic animals. The sandy beaches by the lake allow for sunbathing and just chilling out. There is also camping, fishing, area for games like disc golf and volleyball, barbecues and more. Each year it is home to the triathlon if you are feeling brave.
Part of the New Deal's Public Works projects, this doughnut-shaped building opened to the public in 1939.
Not to miss: The four panel fresco by Conrad Albrizio, the dioramas in the rotunda or the Caddo dugout in the West Wing.
This historic spot has obtained an impressive array of concerts and shows in recent years. Seeing one of your favorites in this incredible historic building will be a memory you won't forget.
"The recently renovated Shreveport Municipal Auditorium is rich in music history from the legendary Louisiana Hayride, Elvis Presley to the Blues musician Huddie "Leadbelly" Ledbetter, as well as Johnny Cash, and many more. The music and eclectic style of performers still rings to this day. It continues to host an array of performers such as Diana Ross, Peter Frampton, Tyler Perry, Boston, ZZ Top, Harry Connick Jr. and most recently three sold out Kevin Hart shows," said Sam Voisin, SMG regional vice president.
More than 150 years old, this cemetery is home to several notable people. From a Shreveport Madame to Martha Bowie Street, sister of Jim Bowie who invented the Bowie knife, as well as confederate soldier's graves. Don't miss the mass grave of about 800 victims of the great yellow fever epidemic of 1873.
"Oakland offers visitors a chance to actually walk through the unique and varied history of downtown Shreveport. Stand where one-quarter of the population was buried in a Yellow Fever outbreak in 1873, ponder the life and times of Shreveport Madam Annie McCune," said Liz Swaine, executive director of the Downtown Development Authority. "When I walk through, it always makes me want to learn more...about a person, an event, or that particular time in history,"
When the doors opened in 1966, Shreveport got a crowning jewel. Its ever-expanding landscape has grown to encompass the surrounding 40 acres. It is a must-see when the azaleas bloom in the spring but has a unique beauty in every season. The museum includes many noteworthy works, including those of western artists, Frederic Remington and Charles M. Russell.
"Sometimes, you just owe it to yourself to dive, or at the least stick a toe, into the river of creativity that flows through centuries of art. It's dramatic, it's lyrical, it's chaotic, it's divine, it's us...humanity," said Lewis Norton, Director of the R. W. Norton Art Gallery.
Hours: 10 a.m.–5 p.m.Wed.-Thurs., 10 a.m.–7 p.m. Fri.-Sat. and 1-5 p.m. Sun.
A self-proclaimed 'hole-in-the-wall' joint, this is a must for locals and tourists. Since it has opened in 1936, it has been delivering delicious food. Food that manager Charlie Lee says has not changed in quality. No wonder locals still flock.
Not to miss: The eclectic front room.
One of the best ways to learn about a city's history is to tour its oldest homes. And Shreveport has plenty of options. Call each to find out about tours and pricing.
The Austen Place B&B, known as the Ogilvie-Wiener Mansion, is still being remodeled. Filled with antiques it is a home tour unlike all others. Not to miss is the doll collection in the attic. Address: 728 Austen Place, Shreveport Phone: (318) 393-0668.