text:
import abc
import datetime
import json
import re
import socket
import tempfile
import time
import uuid

import brkt_cli.util
from brkt_cli.util import (
    append_suffix,
    BracketError,
    make_nonce
)
from googleapiclient import discovery, errors
from oauth2client.client import GoogleCredentials

from brkt_cli.validation import ValidationError

GCP_NAME_MAX_LENGTH = 63
LATEST_IMAGE = 'latest.image.tar.gz'

brkt_image_buckets = {
    'prod': 'brkt-prod-images',
    'stage': 'brkt-stage-images',
    'shared': 'brkt-shared-images'
}

def retry(function, timeout=15.0):
    return brkt_cli.util.retry(
        function, on=[socket.error, errors.HttpError], timeout=timeout)

def execute_gcp_api_call(gcp_object):
    return gcp_object.execute()

class InstanceError(BracketError):
    pass

class BaseGCPService(object):
    __metaclass__ = abc.ABCMeta

    def __init__(self, project, session_id, logger):
        self.log = logger
        self.project = project
        self.session_id = session_id
        self.gcp_res_uri = "https://www.googleapis.com/compute/v1/"
        self.disks = []
        self.instances = []

    @abc.abstractmethod
    def list_zones(self):
        pass

    @abc.abstractmethod
    def get_session_id(self):
        pass

    @abc.abstractmethod
    def disk_from_image(self, zone, image, name, image_project):
        pass

    @abc.abstractmethod
    def get_snapshot(self, name):
        pass

    @abc.abstractmethod
    def wait_snapshot(self, snapshot):
        pass

    @abc.abstractmethod
    def get_image(self, image):
        pass

    @abc.abstractmethod
    def get_network(self, nw):
        pass

    @abc.abstractmethod
    def image_exists(self, image):
        pass

    @abc.abstractmethod
    def project_exists(self, project):
        pass

    @abc.abstractmethod
    def delete_instance(self, zone, instance):
        pass

    @abc.abstractmethod
    def delete_image(self, image):
        pass

    @abc.abstractmethod
    def delete_disk(self, zone, disk):
        pass

    @abc.abstractmethod
    def wait_instance(self, name, zone):
        pass

    @abc.abstractmethod
    def get_instance_ip(self, name, zone):
        pass

    @abc.abstractmethod
    def get_private_ip(self, name, zone):
        pass

    @abc.abstractmethod
    def detach_disk(self, zone, instance, diskName):
        pass

    @abc.abstractmethod
    def wait_for_disk(self, zone, diskName):
        pass

    @abc.abstractmethod
    def get_disk_size(self, zone, diskName):
        pass

    @abc.abstractmethod
    def wait_for_detach(self, zone, diskName):
        pass

    @abc.abstractmethod
    def disk_exists(self, zone, name):
        pass

    @abc.abstractmethod
    def create_snapshot(self, zone, disk, snapshot_name):
        pass

    @abc.abstractmethod
    def delete_snapshot(self, snapshot_name):
        pass

    @abc.abstractmethod
    def disk_from_snapshot(self, zone, snapshot, name):
        pass

    @abc.abstractmethod
    def create_disk(self, zone, name, size):
        pass

    @abc.abstractmethod
    def create_gcp_image_from_disk(self, zone, image_name, disk_name):
        pass

    @abc.abstractmethod
    def create_gcp_image_from_file(self, zone, image_name, file_name, bucket):
        pass

    @abc.abstractmethod
    def wait_image(self, image_name):
        pass

    @abc.abstractmethod
    def get_younger(self, new, old):
        pass

    @abc.abstractmethod
    def get_image_file(self, bucket):
        pass

    @abc.abstractmethod
    def set_tags(self, zone, instance, tags):
        pass

    @abc.abstractmethod
    def get_tags_fingerprint(self, name, zone):
        pass

    @abc.abstractmethod
    def get_latest_encryptor_image(self,
                                   zone,
                                   image_name,
                                   bucket,
                                   image_file=None):
        pass

    @abc.abstractmethod
    def run_instance(self,
                     zone,
                     name,
                     image,
                     network,
                     disks,
                     metadata,
                     delete_boot,
                     block_project_ssh_keys,
                     instance_type,
                     image_project,
                     subnet=None,
                     tags=None):
        pass

    @abc.abstractmethod
    def get_disk(self, zone, disk_name):
        pass

    @abc.abstractmethod
    def cleanup(self, zone, encryptor_image, keep_encryptor=False):
        pass

class GCPService(BaseGCPService):
    def __init__(self, project, session_id, logger):
        super(GCPService, self).__init__(project, session_id, logger)
        self.credentials = GoogleCredentials.get_application_default()
        self.compute = discovery.build(
            'compute', 'v1', credentials=self.credentials)

        self.storage = discovery.build(
            'storage', 'v1', credentials=self.credentials)

    # Create bucket/check permissions
    def check_bucket_name(self, bucket, project):
        try:
            body = {'name' : bucket}
            self.storage.buckets().insert(
                project=project, body=body).execute()

            return
        except errors.HttpError as e:
            # Parse error message and return if user owns bucket
            # Error codes are not unique so message is used
            message = json.loads(e.content)["error"]["message"]
            if 'You already own this bucket' in message:
                return
            else:
                self.log.error("Bucket must be in project: %s", project)
                raise

    # Check if the file name uses valid syntax
    def validate_file_name(self, file):
        m = re.search(r'[*\[\]?#]', file)
        if m:
            raise ValidationError("File name can't contain '[',']','*','?' or '#'")
        return

    def check_bucket_file(self, bucket, file):
        try:
            existing_file = self.storage.objects().get(
                    bucket=bucket,
                    object=file).execute()
            if existing_file:
                raise ValidationError("File already exists")
        except errors.HttpError as e:
            code = e.resp.status
            if code == 404:
                return self.validate_file_name(file)
            else:
                raise ValidationError(e)

    def wait_bucket_file(self, bucket, file):
        for i in range(48):
            try:
                self.storage.objects().get(
                   bucket=bucket,
                   object=file).execute()
                return True
            except errors.HttpError as e:
                self.log.debug(e)
                code = e.resp.status
                if code == 404:
                    time.sleep(5)
                else:
                    self.log.warn("Failed uploading tar file")
                    self.log.debug("Failed uploading tar file: %s", e)
                    return False
        return False

    def get_public_image(self):
        # guest_os is a family
        self.log.info("Trying to get from image family...")
        request = self.compute.images().getFromFamily(
            project='ubuntu-os-cloud',
            family='ubuntu-1404-lts')
        public_image = request.execute(num_retries=5)
        return public_image['name']

    def cleanup(self, zone, encryptor_image, keep_encryptor=False):
        try:
            for instance in self.instances[:]:
                self.log.info('deleting instance %s' % instance)
                self.delete_instance(zone, instance)
            for disk in self.disks[:]:
                self.log.info('deleting disk %s' % disk)
                if self.disk_exists(zone, disk):
                    self.wait_for_detach(zone, disk)
                    self.delete_disk(zone, disk)
            if not keep_encryptor and encryptor_image:
                self.log.info('Deleting encryptor image %s' % encryptor_image)
                self.delete_image(encryptor_image)
        except:
            self.log.exception('Cleanup failed')

    def list_zones(self):
        zones = []
        zones_resp = self.compute.zones().list(project=self.project).execute()
        for item in zones_resp['items']:
            zones.append(item['name'])

        return zones

    def get_session_id(self):
        return self.session_id

    def get_snapshot(self, name):
        snap_req = self.compute.snapshots().get(
            project=self.project, snapshot=name)
        return retry(execute_gcp_api_call)(snap_req)

    def wait_snapshot(self, snapshot):
        while True:
            if self.get_snapshot(snapshot)['status'] == 'READY':
                return
            time.sleep(5)

    def get_network(self, nw):
        return self.compute.networks().get(project=self.project,
            network=nw).execute()

    def network_exists(self, nw):
        try:
            self.get_network(nw)
        except:
            return False
        return True

    def get_image(self, image, image_project=None):
        if image_project:
            return self.compute.images().get(project=image_project,
                image=image).execute()
        else:
            return self.compute.images().get(project=self.project,
               image=image).execute()

    def image_exists(self, image, image_project=None):
        try:
            self.get_image(image, image_project)
        except:
            return False
        return True

    def get_project(self, project):
        return self.compute.projects().get(project=project).execute()

    def project_exists(self, project=None):
        try:
            self.get_project(project)
        except errors.HttpError as e:
            code = json.loads(e.content)['error']['code']
            if code == 400 or code == 403 or code == 404:
                return False
            raise
        return True

    def delete_instance(self, zone, instance):
        if instance in self.instances:
            self.instances.remove(instance)
        return self.compute.instances().delete(project=self.project,
               zone=zone, instance=instance).execute()

    def delete_image(self, image):
        return self.compute.images().delete(project=self.project,
               image=image).execute()

    def delete_disk(self, zone, disk):
        # remove disk if we're tracking it
        if disk in self.disks:
            self.disks.remove(disk)
        return self.compute.disks().delete(project=self.project,
               zone=zone, disk=disk).execute()

    def wait_instance(self, name, zone):
        instance = self.compute.instances().list(project=self.project,
                zone=zone)
        while True:
            instance_data = retry(execute_gcp_api_call)(instance)
            if 'items' in instance_data:
                for i in instance_data['items']:
                    if name == i['name'] and i['status'] == 'RUNNING':
                        return
            self.log.info('Waiting for ' + name + ' to become ready')
            time.sleep(5)

    def get_instance_ip(self, name, zone):
        for i in range(60):
            time.sleep(5)
            instance_req = self.compute.instances().get(project=self.project,
                    zone=zone, instance=name)
            try:
                nw = 'networkInterfaces'
                instance = retry(execute_gcp_api_call)(instance_req)
                if instance[nw][0]['accessConfigs'][0]['natIP']:
                    return instance[nw][0]['accessConfigs'][0]['natIP']
            except:
                pass
        self.log.info("Couldn't find an IP address for this instance.")

    def get_private_ip(self, name, zone):
        nw = 'networkInterfaces'
        instance_req = self.compute.instances().get(project=self.project,
                zone=zone, instance=name)
        instance = retry(execute_gcp_api_call)(instance_req)
        if instance[nw][0]['networkIP']:
            return instance[nw][0]['networkIP']
        self.log.info("Couldn't find private IP address for this instance.")

    def write_serial_console_file(self, zone, instance):
        try:
            serial_port_out = self.compute.instances().getSerialPortOutput(
                    project=self.project,
                    instance=instance,
                    zone=zone).execute()
            if 'contents' in serial_port_out:
                with tempfile.NamedTemporaryFile(prefix='serial-console-',
                                                 suffix='-%s.out' % self.session_id,
                                                 delete=False) as t:
                    t.write(serial_port_out['contents'])
                return t.name
        except:
            self.log.exception('Unable to write serial console contents')

        return None

    def detach_disk(self, zone, instance, diskName):
        detach_req = self.compute.instances().detachDisk(project=self.project,
                instance=instance, zone=zone, deviceName=diskName)
        retry(execute_gcp_api_call)(detach_req)
        # wait for disk ready
        return self.wait_for_detach(zone, diskName)

    def wait_for_disk(self, zone, diskName):
        disk_req = self.compute.disks().get(zone=zone,
                                            project=self.project,
                                            disk=diskName)
        while True:
            self.log.info("Waiting for disk to become ready")
            if 'READY' == retry(execute_gcp_api_call)(disk_req)['status']:
                return
            time.sleep(10)

    def get_disk_size(self, zone, diskName):
        disk_info = self.compute.disks().get(zone=zone, project=self.project, disk=diskName).execute()
        return int(disk_info['sizeGb'])

    def wait_for_detach(self, zone, diskName):
        detach_req = self.compute.disks().get(zone=zone,
                                              project=self.project,
                                              disk=diskName)
        while True:
            resp = retry(execute_gcp_api_call)(detach_req)
            if "users" not in resp and resp != {}:
                self.log.info("Disk detach successful")
                return
            time.sleep(10)

    def disk_exists(self, zone, name):
        try:
            self.compute.disks().get(zone=zone, project=self.project,
                    disk=name).execute()
            return True
        except:
            return False

    def create_snapshot(self, zone, disk, snapshot_name):
        disk_url = "projects/%s/zones/%s/disks/%s" % (self.project, zone, disk)
        body = {'sourceDisk': disk_url, 'name': snapshot_name}
        self.compute.disks().createSnapshot(project=self.project, disk=disk, body=body, zone=zone).execute()

    def delete_snapshot(self, snapshot_name):
        self.compute.snapshots().delete(project=self.project, snapshot=snapshot_name).execute()

    def disk_from_image(self, zone, image, name, image_project=None):
        if self.disk_exists(zone, name):
            return
        project = self.project
        if image_project:
            project = image_project

        image_info = self.compute.images().get(project=project,
                                                 image=image).execute()
        base = "projects/%s/zones/%s" % (self.project, zone)
        body = {
                "name": name,
                "zone": base,
                "type": base + "/diskTypes/pd-ssd",
                "sourceImage": "projects/%s/global/images/%s" % (project, image),
                "sizeGb": image_info['diskSizeGb']
        }
        self.compute.disks().insert(project=self.project,
                zone=zone, body=body).execute()
        self.disks.append(name)

    def disk_from_snapshot(self, zone, snapshot, name):
        if self.disk_exists(zone, name):
            return
        snap_info = self.compute.snapshots().get(project=self.project,
                                                 snapshot=snapshot).execute()
        base = "projects/%s/zones/%s" % (self.project, zone)
        body = {
                "name": name,
                "zone": base,
                "type": base + "/diskTypes/pd-ssd",
                "sourceSnapshot": "projects/%s/global/snapshots/%s" % (self.project, snapshot),
                "sizeGb": snap_info['diskSizeGb']
        }
        self.compute.disks().insert(project=self.project,
                zone=zone, body=body).execute()
        self.disks.append(name)

    def create_disk(self, zone, name, size=25):
        if name not in self.disks:
            self.disks.append(name)
        if self.disk_exists(zone, name):
            return

        base = "projects/%s/zones/%s" % (self.project, zone)
        body = {
            "name": name,
            "zone": base,
            "type": base + "/diskTypes/pd-ssd",
            "sizeGb": str(size)
        }
        self.compute.disks().insert(project=self.project,
                zone=zone, body=body).execute()
        self.wait_for_disk(zone, name)

    def create_ssd_disk(self, zone):
        name = 'scratch-' + str(uuid.uuid4().hex)
        base = "projects/%s/zones/%s" % (self.project, zone)
        body = {
            "deviceName": name,
            "type": "SCRATCH",
            "autoDelete": True,
            "initializeParams": {
                "diskType": base + "/diskTypes/local-ssd"
            }
        }
        return body

    def create_gcp_image_from_disk(self, zone, image_name, disk_name):
        build_disk = "projects/%s/zones/%s/disks/%s" % (self.project,
                zone, disk_name)
        self.compute.images().insert(body={"rawdisk": {},
            "name": image_name,
            "sourceDisk": build_disk},
            project=self.project).execute()

    def create_gcp_image_from_file(self, zone, image_name, file_name, bucket):
        source = "https://storage.googleapis.com/%s/%s" % (bucket, file_name)
        self.compute.images().insert(
            body={
                "rawDisk": {
                    "source": source
                },
                "name": image_name,
            },
            project=self.project).execute()

    def wait_image(self, image_name):
        image_req = self.compute.images().get(image=image_name, project=self.project)
        while True:
            if retry(execute_gcp_api_call, timeout=30.0)(image_req)['status'] == 'READY':
                return
            time.sleep(10)

    def get_younger(self, new, old):
        new_time = datetime.datetime.strptime(new['timeCreated'],
                                              "%Y-%m-%dT%H:%M:%S.%fZ")
        old_time = datetime.datetime.strptime(old['timeCreated'],
                                              "%Y-%m-%dT%H:%M:%S.%fZ")
        if new_time > old_time:
            return new
        else:
            return old

    def get_image_file(self, bucket):
        files = []
        request = self.storage.objects().list(bucket=bucket)
        # Paginate thru' the list of files in the bucket
        while request:
            resp = request.execute()
            files += resp['items']
            request = self.storage.objects().list_next(request, resp)
        # if LATEST_IMAGE exists return that
        for f in files:
            if f['name'] == LATEST_IMAGE:
                return LATEST_IMAGE

        # else return the newest file that ends in .image.tar.gz
        youngest = {'timeCreated': '1992-10-01T01:50:02.942Z'}
        for f in files:
            if 'image.tar.gz' in f['name']:
                youngest = self.get_younger(f, youngest)

        return youngest['name']

    def get_latest_encryptor_image(self,
                                   zone,
                                   bucket,
                                   image_file=None):
        if bucket in brkt_image_buckets:
            bucket = brkt_image_buckets[bucket]

        image_name = 'encryptor-%s' % self.get_session_id()
        # if image_file is not provided try to get latest.image.tar.gz
        # if latest.image.tar.gz doesnt exist return the newest image
        if not image_file:
            image_file = self.get_image_file(bucket)
        self.create_gcp_image_from_file(zone,
                                        image_name,
                                        image_file,
                                        bucket)
        self.wait_image(image_name)
        self.encryptor_image = image_name
        return image_name

    def run_instance(self,
                     zone,
                     name,
                     image,
                     network='default',
                     disks=[],
                     metadata={},
                     delete_boot=True,
                     block_project_ssh_keys=False,
                     instance_type='n1-standard-4',
                     image_project=None,
                     subnet=None,
                     tags=None):

        if block_project_ssh_keys:
            if 'items' not in metadata:
                metadata['items'] = []
            metadata['items'].append({"key": "block-project-ssh-keys", 'value': 'true'})

        # if boot disk doesn't autodelete we need to track it
        if not delete_boot:
            self.disks.append(name)
        if image_project:
            source_disk_image = "projects/%s/global/images/%s" % (image_project,
                image)
        else:
            source_disk_image = "projects/%s/global/images/%s" % (self.project,
                image)
        machine_type = "zones/%s/machineTypes/%s" % (zone, instance_type)

        config = {
            'name': name,
            'machineType': machine_type,

            # Specify the boot disk and the image to use as a source.
            'disks': [
                {
                    'boot': True,
                    'autoDelete': delete_boot,
                    'initializeParams': {
                        'sourceImage': self.gcp_res_uri + source_disk_image,
                    },
                },
            ] + disks,

            # Specify a network interface with NAT to access the public
            # internet.
            'networkInterfaces': [{
                'network': 'global/networks/%s' % network,
                'accessConfigs': [
                    {'type': 'ONE_TO_ONE_NAT', 'name': 'External NAT'}
                ]
            }],

            # Allow the instance to access cloud storage and logging.
            'serviceAccounts': [{
                'email': 'default',
                'scopes': [
                    'https://www.googleapis.com/auth/devstorage.read_write',
                    'https://www.googleapis.com/auth/logging.write'
                ]
            }],

            # Metadata is readable from the instance and allows you to
            # pass configuration from deployment scripts to instances.
            'metadata': metadata
        }

        if subnet:
            subnetwork = "projects/%s/regions/%s/subnetworks/%s" % (
                self.project, zone[:-2], subnet)
            config['networkInterfaces'][0]['subnetwork'] = subnetwork

        instance_req = self.compute.instances().insert(
            project=self.project,
            zone=zone,
            body=config)
        retry(execute_gcp_api_call, timeout=30.0)(instance_req)
        if tags:
            self.log.info("Setting instance tags %s", tags)
            self.set_tags(zone, name, tags)
        self.wait_instance(name, zone)
        self.get_disk_size(zone, name)
        self.instances.append(name)

    def get_disk(self, zone, disk_name):
        source_disk = "projects/%s/zones/%s/disks/%s" % (self.project,
                            zone, disk_name)
        return {
            'boot': False,
            'autoDelete': False,
            'source': self.gcp_res_uri + source_disk,
        }

    def set_tags(self, zone, instance, tags):
        """
        Takes a list of tags (strings) as input, will override existing
        tags on the instance
        """
        fingerprint = self.get_tags_fingerprint(instance, zone)
        body = {"items": tags, "fingerprint": fingerprint}
        request = self.compute.instances().setTags(project=self.project,
                                                   zone=zone,
                                                   instance=instance,
                                                   body=body)
        retry(execute_gcp_api_call)(request)
        return

    def get_tags_fingerprint(self, name, zone):
        """
        Returns the fingerprint of the instance, this is used for all
        requests which modify or update metadata on the instance
        """
        request = self.compute.instances().get(project=self.project,
                                                instance=name,
                                                zone=zone)
        instance = execute_gcp_api_call(request)
        if instance['tags']['fingerprint']:
            return instance['tags']['fingerprint']

def gcp_metadata_from_userdata(brkt_data, extra_items=None):
    """ brkt_data is a JSON blob containing the brkt-config """
    items_list = [{'key': 'brkt', 'value': brkt_data}]
    if extra_items:
        items_list.extend(extra_items)
    return { 'items': items_list }

def get_image_name(encrypted_image_name, name):
    if encrypted_image_name:
        return encrypted_image_name

    nonce = make_nonce()
    # Replace nonce in image name
    m = re.match('(.+)\-encrypted\-', name)
    if m:
        encrypted_image_name = append_suffix(
                m.group(1),
                '-encrypted-%s' % (nonce,),
                GCP_NAME_MAX_LENGTH)
    else:
        encrypted_image_name = append_suffix(
                name,
                '-encrypted-%s' % (nonce,),
                GCP_NAME_MAX_LENGTH)
    return encrypted_image_name

def validate_images(gcp_svc, encrypted_image_name, encryptor, guest_image, image_project=None):
    # check that image to be updated exists
    if not gcp_svc.image_exists(guest_image, image_project):
        raise ValidationError('Guest image or image project invalid')

    # check that encryptor exists
    if encryptor and not gcp_svc.image_exists(encryptor):
        raise ValidationError('Encryptor image %s does not exist. Encryption failed.' % encryptor)

    # check that there is no existing image named encrypted_image_name
    if gcp_svc.image_exists(encrypted_image_name):
        raise ValidationError('An image already exists with name %s. Encryption Failed.' % encrypted_image_name)

def validate_image_name(name):
    """ Verify that the name is a valid GCP image name. Return the name
        if it is valid.

    : raises ValidationError if name is invalid
    """
    if not (name and len(name) <= 64):
        raise ValidationError(
            'Image or instance name may be at most 64 characters')

    m = re.match(r'[a-z0-9\-]*[a-z0-9]$', name)
    if not m:
        raise ValidationError(
            "Image or instance name must be lower case letters, numbers "
            "and hyphens and must end with a lower case letter or a number"
        )
    return name


text:
from __future__ import print_function, absolute_import, division

import contextlib
import warnings
from copy import deepcopy

try:
    import builtins
except ImportError:
    # python2
    import __builtin__ as builtins

import dask.array as da
import numpy as np
from astropy.wcs.utils import proj_plane_pixel_area
from astropy.wcs import (WCSSUB_SPECTRAL, WCSSUB_LONGITUDE, WCSSUB_LATITUDE)
from . import wcs_utils
from .utils import FITSWarning, AstropyUserWarning, WCSCelestialError
from astropy import log
from astropy.io import fits
from astropy.wcs.utils import is_proj_plane_distorted
from astropy.io.fits import BinTableHDU, Column
from astropy import units as u
import itertools
import re
from radio_beam import Beam

def _fix_spectral(wcs):
    """
    Attempt to fix a cube with an invalid spectral axis definition.  Only uses
    well-known exceptions, e.g. CTYPE = 'VELOCITY'.  For the rest, it will try
    to raise a helpful error.
    """

    axtypes = wcs.get_axis_types()

    types = [a['coordinate_type'] for a in axtypes]

    if wcs.naxis not in (3, 4):
        raise TypeError("The WCS has {0} axes of types {1}".format(len(types),
                                                                   types))

    # sanitize noncompliant headers
    if 'spectral' not in types:
        log.warning("No spectral axis found; header may be non-compliant.")
        for ind,tp in enumerate(types):
            if tp not in ('celestial','stokes'):
                if wcs.wcs.ctype[ind] in wcs_utils.bad_spectypes_mapping:
                    wcs.wcs.ctype[ind] = wcs_utils.bad_spectypes_mapping[wcs.wcs.ctype[ind]]

    return wcs

def _split_stokes(array, wcs, beam_table=None):
    """
    Given a 4-d data cube with 4-d WCS (spectral cube + stokes) return a
    dictionary of data and WCS objects for each Stokes component

    Parameters
    ----------
    array : `~numpy.ndarray`
        The input 3-d array with two position dimensions, one spectral
        dimension, and a Stokes dimension.
    wcs : `~astropy.wcs.WCS`
        The input 3-d WCS with two position dimensions, one spectral
        dimension, and a Stokes dimension.
    beam_table : `~astropy.io.fits.hdu.table.BinTableHDU`
        When multiple beams are present, a FITS table with the beam information
        can be given to be split into the polarization components, consistent with
        `array`.
    """

    if array.ndim not in (3,4):
        raise ValueError("Input array must be 3- or 4-dimensional for a"
                         " STOKES cube")

    if wcs.wcs.naxis != 4:
        raise ValueError("Input WCS must be 4-dimensional for a STOKES cube")

    wcs = _fix_spectral(wcs)

    # reverse from wcs -> numpy convention
    axtypes = wcs.get_axis_types()[::-1]

    types = [a['coordinate_type'] for a in axtypes]

    try:
        # Find stokes dimension
        stokes_index = types.index('stokes')
    except ValueError:
        # stokes not in list, but we are 4d
        if types.count('celestial') == 2 and types.count('spectral') == 1:
            if None in types:
                stokes_index = types.index(None)
                log.warning("FITS file has no STOKES axis, but it has a blank"
                            " axis type at index {0} that is assumed to be "
                            "stokes.".format(4-stokes_index))
            else:
                for ii,tp in enumerate(types):
                    if tp not in ('celestial', 'spectral'):
                        stokes_index = ii
                        stokes_type = tp

                log.warning("FITS file has no STOKES axis, but it has an axis"
                            " of type {1} at index {0} that is assumed to be "
                            "stokes.".format(4-stokes_index, stokes_type))
        else:
            raise IOError("There are 4 axes in the data cube but no STOKES "
                          "axis could be identified")

    # TODO: make the stokes names more general
    stokes_names = ["I", "Q", "U", "V"]

    stokes_arrays = {}

    if beam_table is not None:
        beam_tables = {}

    wcs_slice = wcs_utils.drop_axis(wcs, wcs.naxis - 1 - stokes_index)

    if array.ndim == 4:
        for i_stokes in range(array.shape[stokes_index]):

            array_slice = [i_stokes if idim == stokes_index else slice(None)
                           for idim in range(array.ndim)]

            stokes_arrays[stokes_names[i_stokes]] = array[tuple(array_slice)]

            if beam_table is not None:
                beam_pol_idx = beam_table['POL'] == i_stokes
                beam_tables[stokes_names[i_stokes]] = beam_table[beam_pol_idx]

    else:
        # 3D array with STOKES as a 4th header parameter
        stokes_arrays['I'] = array

        if beam_table is not None:
            beam_tables['I'] = beam_table

    if beam_table is not None:
        return stokes_arrays, wcs_slice, beam_tables
    else:
        return stokes_arrays, wcs_slice

def _orient(array, wcs):
    """
    Given a 3-d spectral cube and WCS, swap around the axes so that the
    spectral axis cube is the first in Numpy notation, and the last in WCS
    notation.

    Parameters
    ----------
    array : `~numpy.ndarray`
        The input 3-d array with two position dimensions and one spectral
        dimension.
    wcs : `~astropy.wcs.WCS`
        The input 3-d WCS with two position dimensions and one spectral
        dimension.
    """

    if array.ndim != 3:
        raise ValueError("Input array must be 3-dimensional")

    if wcs.wcs.naxis != 3:
        raise ValueError("Input WCS must be 3-dimensional")

    wcs = wcs_utils.diagonal_wcs_to_cdelt(_fix_spectral(wcs))

    # reverse from wcs -> numpy convention
    axtypes = wcs.get_axis_types()[::-1]

    types = [a['coordinate_type'] for a in axtypes]

    n_celestial = types.count('celestial')

    if n_celestial == 0:
        raise ValueError('No celestial axes found in WCS')
    elif n_celestial != 2:
        raise ValueError('WCS should contain 2 celestial dimensions but '
                         'contains {0}'.format(n_celestial))

    n_spectral = types.count('spectral')

    if n_spectral == 0:
        raise ValueError('No spectral axes found in WCS')
    elif n_spectral != 1:
        raise ValueError('WCS should contain one spectral dimension but '
                         'contains {0}'.format(n_spectral))

    nums = [None if a['coordinate_type'] != 'celestial' else a['number']
            for a in axtypes]

    if 'stokes' in types:
        raise ValueError("Input WCS should not contain stokes")

    t = [types.index('spectral'), nums.index(1), nums.index(0)]
    if t == [0, 1, 2]:
        result_array = array
    else:
        result_array = array.transpose(t)

    result_wcs = wcs.sub([WCSSUB_LONGITUDE, WCSSUB_LATITUDE, WCSSUB_SPECTRAL])

    return result_array, result_wcs

def slice_syntax(f):
    """
    This decorator wraps a function that accepts a tuple of slices.

    After wrapping, the function acts like a property that accepts
    bracket syntax (e.g., p[1:3, :, :])

    Parameters
    ----------
    f : function
    """

    def wrapper(self):
        result = SliceIndexer(f, self)
        result.__doc__ = f.__doc__
        return result

    wrapper.__doc__ = slice_doc.format(f.__doc__ or '',
                                       f.__name__)

    result = property(wrapper)

    return result

slice_doc = """
{0}

Notes
-----
Supports efficient Numpy slice notation,
like ``{1}[0:3, :, 2:4]``
"""

class SliceIndexer(object):

    def __init__(self, func, _other):
        self._func = func
        self._other = _other

    def __getitem__(self, view):
        result = self._func(self._other, view)
        if isinstance(result, da.Array):
            result = result.compute()
        return result

    @property
    def size(self):
        return self._other.size

    @property
    def ndim(self):
        return self._other.ndim

    @property
    def shape(self):
        return self._other.shape

    def __iter__(self):
        raise Exception("You need to specify a slice (e.g. ``[:]`` or "
                        "``[0,:,:]`` in order to access this property.")

# TODO: make this into a proper configuration item
# TODO: make threshold depend on memory?
MEMORY_THRESHOLD=1e8

def is_huge(cube):
    if cube.size < MEMORY_THRESHOLD:  # smallish
        return False
    else:
        return True

def iterator_strategy(cube, axis=None):
    """
    Guess the most efficient iteration strategy
    for iterating over a cube, given its size and layout

    Parameters
    ----------
    cube : SpectralCube instance
        The cube to iterate over
    axis : [0, 1, 2]
        For reduction methods, the axis that is
        being collapsed

    Returns
    -------
    strategy : ['cube' | 'ray' | 'slice']
        The recommended iteration strategy.
        *cube* recommends working with the entire array in memory
        *slice* recommends working with one slice at a time
        *ray*  recommends working with one ray at a time
    """
    # pretty simple for now
    if cube.size < 1e8:  # smallish
        return 'cube'
    return 'slice'

def try_load_beam(header):
    '''
    Try loading a beam from a FITS header.
    '''

    try:
        beam = Beam.from_fits_header(header)
        return beam
    except Exception as ex:
        # We don't emit a warning if no beam was found since it's ok for
        # cubes to not have beams
        # if 'No BMAJ' not in str(ex):
        #     warnings.warn("Could not parse beam information from header."
        #                   "  Exception was: {0}".format(ex.__repr__()),
        #                   FITSWarning
        #                  )

        # Avoid warning since cubes don't have a beam
        # Warning now provided when `SpectralCube.beam` is None
        beam = None

    return beam

def try_load_beams(data):
    '''
    Try loading a beam table from a FITS HDU list.
    '''
    try:
        from radio_beam import Beam
    except ImportError:
        warnings.warn("radio_beam is not installed. No beam "
                      "can be created.",
                      ImportError
                     )

    if isinstance(data, fits.BinTableHDU):
        if 'BPA' in data.data.names:
            beam_table = data.data
            return beam_table
        else:
            raise ValueError("No beam table found")
    elif isinstance(data, fits.HDUList):

        for ihdu, hdu_item in enumerate(data):
            if isinstance(hdu_item, (fits.PrimaryHDU, fits.ImageHDU)):
                beam = try_load_beams(hdu_item.header)
            elif isinstance(hdu_item, fits.BinTableHDU):
                if 'BPA' in hdu_item.data.names:
                    beam_table = hdu_item.data
                    return beam_table

        try:
            # if there was a beam in a header, but not a beam table
            return beam
        except NameError:
            # if the for loop has completed, we didn't find a beam table
            raise ValueError("No beam table found")
    elif isinstance(data, (fits.PrimaryHDU, fits.ImageHDU)):
        return try_load_beams(data.header)
    elif isinstance(data, fits.Header):
        try:
            beam = Beam.from_fits_header(data)
            return beam
        except Exception as ex:
            # warnings.warn("Could not parse beam information from header."
            #               "  Exception was: {0}".format(ex.__repr__()),
            #               FITSWarning
            #              )

            # Avoid warning since cubes don't have a beam
            # Warning now provided when `SpectralCube.beam` is None
            beam = None
    else:
        raise ValueError("How did you get here?  This is some sort of error.")

def beams_to_bintable(beams):
    """
    Convert a list of beams to a CASA-style BinTableHDU
    """

    c1 = Column(name='BMAJ', format='1E', array=[bm.major.to(u.arcsec).value for bm in beams], unit=u.arcsec.to_string('FITS'))
    c2 = Column(name='BMIN', format='1E', array=[bm.minor.to(u.arcsec).value for bm in beams], unit=u.arcsec.to_string('FITS'))
    c3 = Column(name='BPA', format='1E', array=[bm.pa.to(u.deg).value for bm in beams], unit=u.deg.to_string('FITS'))
    #c4 = Column(name='CHAN', format='1J', array=[bm.meta['CHAN'] if 'CHAN' in bm.meta else 0 for bm in beams])
    c4 = Column(name='CHAN', format='1J', array=np.arange(len(beams)))
    c5 = Column(name='POL', format='1J', array=[bm.meta['POL'] if 'POL' in bm.meta else 0 for bm in beams])

    bmhdu = BinTableHDU.from_columns([c1, c2, c3, c4, c5])
    bmhdu.header['EXTNAME'] = 'BEAMS'
    bmhdu.header['EXTVER'] = 1
    bmhdu.header['XTENSION'] = 'BINTABLE'
    bmhdu.header['NCHAN'] = len(beams)
    bmhdu.header['NPOL'] = len(set([bm.meta['POL'] for bm in beams if 'POL' in bm.meta]))
    return bmhdu

def beam_props(beams, includemask=None):
    '''
    Returns separate quantities for the major, minor, and PA of a list of
    beams.
    '''
    if includemask is None:
        includemask = itertools.cycle([True])

    major = u.Quantity([bm.major for bm, incl in zip(beams, includemask)
                        if incl], u.deg)
    minor = u.Quantity([bm.minor for bm, incl in zip(beams, includemask)
                        if incl], u.deg)
    pa = u.Quantity([bm.pa for bm, incl in zip(beams, includemask)
                     if incl], u.deg)

    return major, minor, pa

def largest_beam(beams, includemask=None):
    """
    Returns the largest beam (by area) in a list of beams.
    """

    from radio_beam import Beam

    major, minor, pa = beam_props(beams, includemask)
    largest_idx = (major * minor).argmax()
    new_beam = Beam(major=major[largest_idx], minor=minor[largest_idx],
                    pa=pa[largest_idx])

    return new_beam

def smallest_beam(beams, includemask=None):
    """
    Returns the smallest beam (by area) in a list of beams.
    """

    from radio_beam import Beam

    major, minor, pa = beam_props(beams, includemask)
    smallest_idx = (major * minor).argmin()
    new_beam = Beam(major=major[smallest_idx], minor=minor[smallest_idx],
                    pa=pa[smallest_idx])

    return new_beam

@contextlib.contextmanager
def _map_context(numcores):
    """
    Mapping context manager to allow parallel mapping or regular mapping
    depending on the number of cores specified.

    The builtin map is overloaded to handle python3 problems: python3 returns a
    generator, while ``multiprocessing.Pool.map`` actually runs the whole thing
    """
    if numcores is not None and numcores > 1:
        try:
            from joblib import Parallel, delayed
            from joblib.pool import has_shareable_memory
            map = lambda x,y: Parallel(n_jobs=numcores)(delayed(has_shareable_memory)(x))(y)
            parallel = True
        except ImportError:
            map = lambda x,y: list(builtins.map(x,y))
            warnings.warn("Could not import joblib.  "
                          "map will be non-parallel.",
                          ImportError
                         )
            parallel = False
    else:
        parallel = False
        map = lambda x,y: list(builtins.map(x,y))

    yield map

def convert_bunit(bunit):
    '''
    Convert a BUNIT string to a quantity

    Parameters
    ----------
    bunit : str
        String to convert to an `~astropy.units.Unit`

    Returns
    -------
    unit : `~astropy.unit.Unit`
        Corresponding unit.
    '''

    # special case: CASA (sometimes) makes non-FITS-compliant jy/beam headers
    bunit_lower = re.sub(r"\s", "", bunit.lower())
    if bunit_lower == 'jy/beam':
        unit = u.Jy / u.beam
    else:
        try:
            unit = u.Unit(bunit)
        except ValueError:
            warnings.warn("Could not parse unit {0}".format(bunit),
                          AstropyUserWarning)
            unit = None

    return unit

def world_take_along_axis(cube, position_plane, axis):
    '''
    Convert a 2D plane of pixel positions to the equivalent WCS coordinates.
    For example, this will convert `argmax`
    along the spectral axis to the equivalent spectral value (e.g., velocity at
    peak intensity).

    Parameters
    ----------
    cube : SpectralCube
        A spectral cube.
    position_plane : 2D numpy.ndarray
        2D array of pixel positions along `axis`. For example, `position_plane` can
        be the output of `argmax` or `argmin` along an axis.
    axis : int
        The axis that `position_plane` is collapsed along.

    Returns
    -------
    out : astropy.units.Quantity
        2D array of WCS coordinates.
    '''

    if wcs_utils.is_pixel_axis_to_wcs_correlated(cube.wcs, axis):
        raise WCSCelestialError("world_take_along_axis requires the celestial axes"
                                " to be aligned along image axes.")

    # Get 1D slice along that axis.
    world_slice = [0, 0]
    world_slice.insert(axis, slice(None))

    world_coords = cube.world[tuple(world_slice)][axis]

    world_newaxis = [np.newaxis] * 2
    world_newaxis.insert(axis, slice(None))
    world_newaxis = tuple(world_newaxis)

    plane_newaxis = [slice(None), slice(None)]
    plane_newaxis.insert(axis, np.newaxis)
    plane_newaxis = tuple(plane_newaxis)

    out = np.take_along_axis(world_coords[world_newaxis],
                             position_plane[plane_newaxis], axis=axis)
    out = out.squeeze()

    return out

def _has_beam(obj):
    if hasattr(obj, '_beam'):
        return obj._beam is not None
    else:
        return False

def _has_beams(obj):
    if hasattr(obj, '_beams'):
        return obj._beams is not None
    else:
        return False

def bunit_converters(obj, unit, equivalencies=(), freq=None):
    '''
    Handler for all brightness unit conversions, including: K, Jy/beam, Jy/pix, Jy/sr.
    This also includes varying resolution spectral cubes, where the beam size varies along
    the frequency axis.

    Parameters
    ----------
    obj : {SpectralCube, LowerDimensionalObject}
        A spectral cube or any other lower dimensional object.
    unit : `~astropy.units.Unit`
        Unit to convert `obj` to.
    equivalencies : tuple, optional
        Initial list of equivalencies.
    freq : `~astropy.unit.Quantity`, optional
        Frequency to use for spectral conversions. If the spectral axis is available, the
        frequencies will already be defined.

    Outputs
    -------
    factor : `~numpy.ndarray`
        Array of factors for the unit conversion.

    '''

    # Add a simple check it the new unit is already equivalent, and so we don't need
    # any additional unit equivalencies
    if obj.unit.is_equivalent(unit):
        # return equivalencies
        factor = obj.unit.to(unit, equivalencies=equivalencies)
        return np.array([factor])

    # Determine the bunit "type". This will determine what information we need for the unit conversion.
    has_btemp = obj.unit.is_equivalent(u.K) or unit.is_equivalent(u.K)
    has_perbeam = obj.unit.is_equivalent(u.Jy/u.beam) or unit.is_equivalent(u.Jy/u.beam)
    has_perangarea = obj.unit.is_equivalent(u.Jy/u.sr) or unit.is_equivalent(u.Jy/u.sr)
    has_perpix = obj.unit.is_equivalent(u.Jy/u.pix) or unit.is_equivalent(u.Jy/u.pix)

    # Is there any beam object defined?
    has_beam = _has_beam(obj) or _has_beams(obj)

    # Set if this is a varying resolution object
    has_beams = _has_beams(obj)

    # Define freq, if needed:
    if any([has_perangarea, has_perbeam, has_btemp]):
        # Create a beam equivalency for brightness temperature
        # This requires knowing the frequency along the spectral axis.
        if freq is None:
            try:
                freq = obj.with_spectral_unit(u.Hz).spectral_axis
            except AttributeError:
                raise TypeError("Object of type {0} has no spectral "
                                "information. `freq` must be provided for"
                                " unit conversion from Jy/beam"
                                .format(type(obj)))
        else:
            if not freq.unit.is_equivalent(u.Hz):
                raise u.UnitsError("freq must be given in equivalent "
                                   "frequency units.")

            freq = freq.reshape((-1,))

    else:
        freq = [None]

    # To handle varying resolution objects, loop through "channels"
    # Default to a single iteration for a 2D spatial object or when a beam is not defined
    # This allows handling all 1D, 2D, and 3D data products.
    if has_beams:
        iter = range(len(obj.beams))
        beams = obj.beams
    elif has_beam:
        iter = range(0, 1)
        beams = [obj.beam]
    else:
        iter = range(0, 1)
        beams = [None]

    # Append the unit conversion factors
    factors = []

    # Iterate through spectral channels.
    for ii in iter:

        beam = beams[ii]

        # Use the range of frequencies when the beam does not change. Otherwise, select the
        # frequency corresponding to this beam.
        if has_beams:
            thisfreq = freq[ii]
        else:
            thisfreq = freq

        # Changes in beam require a new equivalency for each.
        this_equivalencies = deepcopy(equivalencies)

        # Equivalencies for Jy per ang area.
        if has_perangarea:
            bmequiv_angarea = u.brightness_temperature(thisfreq)

            this_equivalencies = list(this_equivalencies) + bmequiv_angarea

        # Beam area equivalencies for Jy per beam and/or Jy per ang area
        if has_perbeam:

            # create a beam equivalency for brightness temperature
            bmequiv = beam.jtok_equiv(thisfreq)

            # NOTE: `beamarea_equiv` was included in the radio-beam v0.3.3 release
            # The if/else here handles potential cases where earlier releases are installed.
            if hasattr(beam, 'beamarea_equiv'):
                bmarea_equiv = beam.beamarea_equiv
            else:
                bmarea_equiv = u.beam_angular_area(beam.sr)

            this_equivalencies = list(this_equivalencies) + bmequiv + bmarea_equiv

        # Equivalencies for Jy per pixel area.
        if has_perpix:

            if not obj.wcs.has_celestial:
                raise ValueError("Spatial WCS information is required for unit conversions"
                                " involving spatial areas (e.g., Jy/pix, Jy/sr)")

            pix_area = (proj_plane_pixel_area(obj.wcs.celestial) * u.deg**2).to(u.sr)

            pix_area_equiv = [(u.Jy / u.pix, u.Jy / u.sr,
                            lambda x: x / pix_area.value,
                            lambda x: x * pix_area.value)]

            this_equivalencies = list(this_equivalencies) + pix_area_equiv

            # Define full from brightness temp to Jy / pix.
            # Otherwise isn't working in 1 step
            if has_btemp:
                if not has_beam:
                    raise ValueError("Conversions between K and Jy/beam or Jy/pix"
                                    "requires the cube to have a beam defined.")

                jtok_factor = beam.jtok(thisfreq) / (u.Jy / u.beam)

                # We're going to do this piecemeal because it's easier to conceptualize
                # We specifically anchor these conversions based on the beam area. So from
                # beam to pix, this is beam -> angular area -> area per pixel
                # Altogether:
                # K ->  Jy/beam -> Jy /sr - > Jy / pix
                forward_factor = 1 / (jtok_factor * (beam.sr / u.beam) / (pix_area / u.pix))
                reverse_factor = jtok_factor * (beam.sr / u.beam) / (pix_area / u.pix)

                pix_area_btemp_equiv = [(u.K, u.Jy / u.pix,
                                        lambda x: x * forward_factor.value,
                                        lambda x: x * reverse_factor.value)]

                this_equivalencies = list(this_equivalencies) + pix_area_btemp_equiv

            # Equivalencies between pixel and angular areas.
            if has_perbeam:
                if not has_beam:
                    raise ValueError("Conversions between Jy/beam or Jy/pix"
                                    "requires the cube to have a beam defined.")

                beam_area = beam.sr

                pix_area_btemp_equiv = [(u.Jy / u.pix, u.Jy / u.beam,
                                        lambda x: x * (beam_area / pix_area).value,
                                        lambda x: x * (pix_area / beam_area).value)]

                this_equivalencies = list(this_equivalencies) + pix_area_btemp_equiv

        factor = obj.unit.to(unit, equivalencies=this_equivalencies)
        factors.append(factor)

    if has_beams:
        return factors
    else:
        # Slice along first axis to return a 1D array.
        return factors[0]

redpajama_set_name: RedPajamaGithub


text:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="edu.buffalo.cse.cse486586.simplemessenger.test">

    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />

    <application>
        <uses-library android:name="android.test.runner" />
    </application>

    <instrumentation android:name="android.test.InstrumentationTestRunner"
                     android:targetPackage="edu.buffalo.cse.cse486586.simplemessenger"
                     android:handleProfiling="false"
                     android:functionalTest="false"
                     android:label="Tests for edu.buffalo.cse.cse486586.simplemessenger"/>
</manifest>


text:
package aQute.bnd.ant;

import java.io.File;
import java.io.IOException;

import org.apache.tools.ant.BuildException;

import aQute.bnd.build.Project;
import aQute.bnd.build.Workspace;
import aQute.lib.io.IO;

public class RunBundlesTask extends BaseTask {

	private File	rootDir;
	private String	outputDir;
	private File	bndFile	= new File(Project.BNDFILE);

	@Override
	public void execute() throws BuildException {
		try {
			createReleaseDir();
			Workspace workspace;
			if (rootDir != null) {
				workspace = new Workspace(rootDir);
			} else {
				workspace = Workspace.findWorkspace(bndFile);
				log("Workspace not specified, using " + workspace.getBase()
					.getAbsolutePath());
			}
			// 2nd arg is not used, so no use trying to set it
			Project bndProject = new Project(workspace, null, bndFile);

			bndProject.exportRunbundles(bndFile.getName(), new File(outputDir));

			bndProject.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new BuildException(e);
		}
	}

	private File createReleaseDir() {
		File releaseDir = new File(outputDir);
		try {
			IO.deleteWithException(releaseDir);
			log("Deleted directory " + outputDir);
		} catch (IOException e1) {
			// ignore
		}

		try {
			IO.mkdirs(releaseDir);
			log("Created directory " + outputDir);
		} catch (IOException e) {
			throw new BuildException("Output directory '" + outputDir + "' could not be created", e);
		}

		return releaseDir;
	}

	public void setRootDir(File rootDir) {
		this.rootDir = rootDir;
	}

	public void setOutputDir(String outputDir) {
		this.outputDir = outputDir;
	}

	public void setBndFile(File bndFile) {
		this.bndFile = bndFile;
	}
}


text: self.addEventListener('fetch', () => { });