from ._compat import ord_byte

import math
import string
from logging import getLogger

_logger = getLogger('pwm.encoding')

# 'full' repeats digits twice, to increase the probablity of a digit appearing in a default 16
# character password, for sites that suck at estimating entropy and requires digits to be present
PRESETS = {
    'full': string.ascii_letters + 2 * string.digits + '!#$%&()*+,-./:;=?@[]^_|~',
    'alpha': string.ascii_letters,
    'numeric': string.digits,
    'alphanumeric': string.ascii_letters + string.digits,
}

def ceildiv(dividend, divisor):
    ''' integer ceiling division '''
    return (dividend + divisor - 1) // divisor

def calc_chunklen(alph_len):
    '''
    computes the ideal conversion ratio for the given alphabet.
    A ratio is considered ideal when the number of bits in one output
    encoding chunk that don't add up to one input encoding chunk is minimal.
    '''
    binlen, enclen = min([
                          (i, i*8 / math.log(alph_len, 2))
                          for i in range(1, 7)
                         ], key=lambda k: k[1] % 1)

    return binlen, int(enclen)

class Encoder(object):
    '''
    general-purpose encoder. Encodes arbitrary binary data with a given
    specific base ("alphabet").
    '''

    def __init__(self, alphabet):
        self.alphabet = alphabet
        self.chunklen = calc_chunklen(len(alphabet))

    def encode(self, digest, total_len):
        nchunks = ceildiv(len(digest), self.chunklen[0])
        binstr = digest.ljust(nchunks * self.chunklen[0], b'\0')

        return ''.join([
                self._encode_chunk(binstr, i) for i in range(0, nchunks)
            ])[:total_len]

    def _encode_chunk(self, data, index):
        '''
        gets a chunk from the input data, converts it to a number and
        encodes that number
        '''
        chunk = self._get_chunk(data, index)
        return self._encode_long(self._chunk_to_long(chunk))

    def _encode_long(self, val):
        '''
        encodes an integer of 8*self.chunklen[0] bits using the specified
        alphabet
        '''
        return ''.join([
                self.alphabet[(val//len(self.alphabet)**i) % len(self.alphabet)]
                for i in reversed(range(self.chunklen[1]))
            ])

    def _chunk_to_long(self, chunk):
        '''
        parses a chunk of bytes to integer using big-endian representation
        '''
        return sum([
                256**(self.chunklen[0]-1-i) * ord_byte(chunk[i])
                for i in range(self.chunklen[0])
            ])

    def _get_chunk(self, data, index):
        '''
        partition the data into chunks and retrieve the chunk at the given index
        '''
        return data[index*self.chunklen[0]:(index+1)*self.chunklen[0]]

def lookup_alphabet(charset):
    '''
    retrieves a named charset or treats the input as a custom alphabet and use that
    '''
    if charset in PRESETS:
        return PRESETS[charset]
    if len(charset) < 16:
        _logger.warning('very small alphabet in use, possibly a failed lookup?')
    return charset


# -*- coding: utf-8 -*-
#
# This file is part of COUNTER-Robots.
# Copyright (C) 2018 CERN.
#
# COUNTER-Robots is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""Library for COUNTER-compliant detection of machines and robots."""

from __future__ import absolute_import, print_function

import re
from functools import wraps
from os.path import join

import pkg_resources

from .version import __version__

def _get_resource_content(filename):
    """Retrieve content from a file in this Python package."""
    return pkg_resources.resource_string(__name__, join('data', filename))

def memoize(func):
    """Cache result of function call."""
    cache = {}

    @wraps(func)
    def inner(filename):
        if filename not in cache:
            cache[filename] = func(filename)
        return cache[filename]
    return inner

@memoize
def _regexp(filename):
    """Get a list of patterns from a file and make a regular expression."""
    lines = _get_resource_content(filename).decode('utf-8').splitlines()
    return re.compile('|'.join(lines))

def _match_useragent(user_agent, filename):
    return bool(_regexp(filename).search(user_agent))

def is_robot(user_agent):
    """Determine if user agent is a robot/crawler/spider.

    Determined according to the *Code of Practice for Research Data*.
    """
    return _match_useragent(user_agent, 'robot.txt')

def is_machine(user_agent):
    """Determine if user agent is a machine (e.g. script).

    Determined according to the *Code of Practice for Research Data*.
    """
    return _match_useragent(user_agent, 'machine.txt')

def is_robot_or_machine(user_agent):
    """Determine if a user agent is a machine/robot or human.

    Determined according to the *COUNTER Code of Practice*.
    """
    return is_robot(user_agent) or is_machine(user_agent)

__all__ = (
    '__version__',
    'is_machine',
    'is_robot',
    'is_robot_or_machine',
)


# -*- coding: utf-8 -*-
# vim:fenc=utf-8

'''
  :copyright (c) 2014 Hive Tech, SAS.
  :license: Apache 2.0, see LICENSE for more details.
'''

import pandas as pd
import time
import datetime as dt
import pytz
import calendar
import locale
import dateutil.parser

# TODO Handle in-day dates, with hours and minutes
def normalize_date_format(date):
    '''
    Dates can be defined in many ways, but zipline use
    aware datetime objects only. Plus, the software work
    with utc timezone so we convert it.
    '''
    if isinstance(date, int):
        # This is probably epoch time
        date = time.strftime('%Y-%m-%d %H:%M:%S',
                             time.localtime(date))

    # assert isinstance(date, str) or isinstance(date, unicode)
    if isinstance(date, str) or isinstance(date, unicode):
        date = dateutil.parser.parse(date)
    if not date.tzinfo:
        local_tz = pytz.timezone(_detect_timezone())
        local_dt = local_tz.localize(date, is_dst=None)
        # TODO I'm not sure why and when I need to add a date to make it right
        date = local_dt.astimezone(pytz.utc) + pd.datetools.day

    return date

def _detect_timezone():
    '''
    Get timezone as set by the system
    '''
    default_timezone = 'America/New_York'
    locale_code = locale.getdefaultlocale()
    return default_timezone if not locale_code[0] else \
        str(pytz.country_timezones[locale_code[0][-2:]][0])

def UTC_date_to_epoch(utc_date):
    return calendar.timegm(utc_date.timetuple())

def epoch_to_date(epoch, tz=pytz.utc):
    tm = time.gmtime(epoch)
    return(dt.datetime(tm.tm_year, tm.tm_mon, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, 0, tz))


# -*- coding: utf-8 -*-
# vim:fenc=utf-8

'''
  :copyright (c) 2014 Xavier Bruhiere.
  :license: MIT, see LICENSE for more details.
'''

import flask
import functools
import datetime as dt
import dna.utils

def api_url(full_version, resource):
    '''
    >>> # Harmonize api endpoints
    >>> # __version__ should be like major.minor.fix
    >>> from my_app import __version__
    >>> api_url(__version__, '/some/endpoint')
    /v0/some/endpoint
    '''
    return '/v{}/{}'.format(dna.utils.Version(full_version).major, resource)

def api_doc(full_version, resource, method='GET', **kwargs):
    '''
    >>> # Wrap api endpoints with more details
    >>> api_doc('/resource', secure=True, key='value')
    GET /resource?secure=true&key=value
    '''
    doc = '{} {}'.format(method, api_url(full_version, resource))
    params = '&'.join(['{}={}'.format(k, v) for k, v in kwargs.iteritems()])
    if params:
        doc = '?'.join([doc, params])
    return doc

# NOTE See also https://github.com/wcdolphin/flask-cors
# NOTE ALready included into flask-api, about to be removed
def crossdomain(origin=None, methods=None, headers=None,
                max_age=21600, attach_to_all=True,
                automatic_options=True):
    if methods is not None:
        methods = ', '.join(sorted(x.upper() for x in methods))
    if headers is not None and not isinstance(headers, basestring):
        headers = ', '.join(x.upper() for x in headers)
    if not isinstance(origin, basestring):
        origin = ', '.join(origin)
    if isinstance(max_age, dt.timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        if methods is not None:
            return methods

        options_resp = flask.current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        def wrapped_function(*args, **kwargs):
            if automatic_options and flask.request.method == 'OPTIONS':
                resp = flask.current_app.make_default_options_response()
            else:
                resp = flask.make_response(f(*args, **kwargs))
            if not attach_to_all and flask.request.method != 'OPTIONS':
                return resp

            h = resp.headers

            h['Access-Control-Allow-Origin'] = origin
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)
            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        return functools.update_wrapper(wrapped_function, f)
    return decorator


# coding: utf-8

"""
Copyright 2015 SmartBear Software

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    Ref: https://github.com/swagger-api/swagger-codegen
"""

from pprint import pformat
from six import iteritems

class FinancialDataStatusDatastatus(object):
    """
    NOTE: This class is auto generated by the swagger code generator program.
    Do not edit the class manually.
    """
    def __init__(self):
        """
        FinancialDataStatusDatastatus - a model defined in Swagger

        :param dict swaggerTypes: The key is attribute name
                                  and the value is attribute type.
        :param dict attributeMap: The key is attribute name
                                  and the value is json key in definition.
        """
        self.swagger_types = {
            'last_updated': 'date',
            'last_fin_year_end': 'date'
        }

        self.attribute_map = {
            'last_updated': 'last_updated',
            'last_fin_year_end': 'last_fin_year_end'
        }

        self._last_updated = None
        self._last_fin_year_end = None

    @property
    def last_updated(self):
        """
        Gets the last_updated of this FinancialDataStatusDatastatus.
        Date when the company was last probed

        :return: The last_updated of this FinancialDataStatusDatastatus.
        :rtype: date
        """
        return self._last_updated

    @last_updated.setter
    def last_updated(self, last_updated):
        """
        Sets the last_updated of this FinancialDataStatusDatastatus.
        Date when the company was last probed

        :param last_updated: The last_updated of this FinancialDataStatusDatastatus.
        :type: date
        """
        self._last_updated = last_updated

    @property
    def last_fin_year_end(self):
        """
        Gets the last_fin_year_end of this FinancialDataStatusDatastatus.
        Date of the last balance sheet year-end available

        :return: The last_fin_year_end of this FinancialDataStatusDatastatus.
        :rtype: date
        """
        return self._last_fin_year_end

    @last_fin_year_end.setter
    def last_fin_year_end(self, last_fin_year_end):
        """
        Sets the last_fin_year_end of this FinancialDataStatusDatastatus.
        Date of the last balance sheet year-end available

        :param last_fin_year_end: The last_fin_year_end of this FinancialDataStatusDatastatus.
        :type: date
        """
        self._last_fin_year_end = last_fin_year_end

    def to_dict(self):
        """
        Returns the model properties as a dict
        """
        result = {}

        for attr, _ in iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            else:
                result[attr] = value

        return result

    def to_str(self):
        """
        Returns the string representation of the model
        """
        return pformat(self.to_dict())

    def __repr__(self):
        """
        For `print` and `pprint`
        """
        return self.to_str()

    def __eq__(self, other):
        """
        Returns true if both objects are equal
        """
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        """
        Returns true if both objects are not equal
        """
        return not self == other


#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8

'''
  dna debug helpers
  -----------------

  :copyright (c) 2014 Xavier Bruhiere.
  :license: %LICENCE%, see LICENSE for more details.
'''

import os
import json

def activate_pdb_hook():
    ''' Catch exceptions with a prompt for post-mortem analyzis'''
    def debug_exception(type_exception, value, tb):
        import pdb
        pdb.post_mortem(tb)

    import sys
    sys.excepthook = debug_exception

#NOTE Could use pprint module
def emphasis(obj, align=True):
    ''' Clearer data printing '''
    if isinstance(obj, dict):
        if align:
            pretty_msg = os.linesep.join(
                ["%25s: %s" % (k, obj[k]) for k in sorted(obj.keys())])
        else:
            pretty_msg = json.dumps(obj, indent=4, sort_keys=True)
    else:
        return obj
    return pretty_msg


'''
Created on 24.01.2014

@author: Dirk Rother
@contact: dirrot.dev@gmail.com
@license: GPL
@version: 0.2

'''

from urllib2 import Request, urlopen, URLError, HTTPError
from urllib import urlencode
from Models import Coin, TradingPair
import json

class API(object):
    '''
    This class is a wrapper class for the CryptoCoinCharts api.
    '''

    API_PATH = "http://api.cryptocoincharts.info/"

    def listcoins(self):
        '''
        Use this function to list all coins with their data which are available on cryptocoincharts.
        Usage: http://api.cryptocoincharts.info/listCoins
        '''
        url = self.API_PATH + 'listCoins'

        json_data = json.loads(self._getdata(url))

        coins = []
        for entry in json_data:
            coin = Coin()
            coin.id = entry['id']
            coin.name = entry['name']
            coin.website = entry['website']
            coin.price_btc = entry['price_btc']
            coin.volume_btc = entry['volume_btc']
            coins.append(coin)

        return coins

    def tradingpair(self, pair):
        '''
        Use this function to query price and volume data for ONE trading pair.
        A list with all coin currencies can be found by using the listcoins method.
        A example pair: currency1_currency2 = "doge_btc"
        Usage: http://api.cryptocoincharts.info/tradingPair/[currency1_currency2]
        '''
        url = self.API_PATH + 'tradingPair/' + pair

        json_data = json.loads(self._getdata(url))

        tradingpair = TradingPair()
        tradingpair.id = json_data['id']
        tradingpair.price = json_data['price']
        tradingpair.price_before_24h = json_data['price_before_24h']
        tradingpair.volume_first = json_data['volume_first']
        tradingpair.volume_second = json_data['volume_second']
        tradingpair.volume_btc = json_data['volume_btc']
        tradingpair.best_market = json_data['best_market']
        tradingpair.latest_trade = json_data['latest_trade']

        return tradingpair

    def tradingpairs(self, pairs):
        '''
        Use this function to query price and volume data for MANY trading pairs.
        Usage: http://api.cryptocoincharts.info/tradingPairs/[currency1_currency2,currency2_currency3,...]
               A example pair: currency1_currency2 = "doge_btc"
                               currency2_currency3 = "btc_eur"
               http://api.cryptocoincharts.info/tradingPairs/"doge_btc,btc_eur"
        '''
        url = self.API_PATH + 'tradingPairs/'
        data = { 'pairs':pairs }

        json_data = json.loads(self._getdata(url, data))

        tradingpairs = []
        for entry in json_data:
            tradingpair = TradingPair()
            tradingpair.id = entry['id']
            tradingpair.price = entry['price']
            tradingpair.price_before_24h = entry['price_before_24h']
            tradingpair.volume_first = entry['volume_first']
            tradingpair.volume_second = entry['volume_second']
            tradingpair.volume_btc = entry['volume_btc']
            tradingpair.best_market = entry['best_market']
            tradingpair.latest_trade = entry['latest_trade']
            tradingpairs.append(tradingpair)

        return tradingpairs

    def listofpairs(self):
        pass

    def _getdata(self, url, data = ""):
        '''
        Wrapper method
        '''
        request = Request(url)

        if data != "":
            request = Request(url, urlencode(data))

        try:
            response = urlopen(request)
        except HTTPError as e:
            print('The Server couldn\'t fulfill the request.')
            print('Error code: ', e.code)
        except URLError as e:
            print('We failed to reach a server.')
            print('Reason: ', e.code)
        else:
            # Everything is fine.
            return response.read()


import asyncio
import multiprocessing
import json
import logging

logger = logging.getLogger(__name__)

async def handle_jobs(job_handler, host, port, *, loop):
    """
    Connects to the remote master and continuously receives calls, executes
    them, then returns a response until interrupted.
    """

    try:

        try:
            reader, writer = await asyncio.open_connection(host, port, loop=loop)
        except OSError:
            logging.error("worker could not connect to server")
            return

        while True:

            try:
                call_encoded = await reader.readuntil(b"\n")
            except (asyncio.IncompleteReadError, ConnectionResetError):
                break
            logging.debug("worker got call")
            call_json = call_encoded.decode("utf-8")
            call = json.loads(call_json)

            response = job_handler(call)

            response_json = json.dumps(response) + "\n"
            response_encoded = response_json.encode("utf-8")
            writer.write(response_encoded)
            logging.debug("worker returned response")

    except KeyboardInterrupt:

        pass

def worker_main(job_handler, host, port):
    """
    Starts an asyncio event loop to connect to the master and run jobs.
    """

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(None)
    loop.run_until_complete(handle_jobs(job_handler, host, port, loop=loop))
    loop.close()

def run_worker_pool(job_handler, host="localhost", port=48484,
                      *, max_workers=None):
    """
    Runs a pool of workers which connect to a remote HighFive master and begin
    executing calls.
    """

    if max_workers is None:
        max_workers = multiprocessing.cpu_count()

    processes = []
    for _ in range(max_workers):
        p = multiprocessing.Process(target=worker_main,
                args=(job_handler, host, port))
        p.start()
        processes.append(p)

    logger.debug("workers started")

    for p in processes:
        p.join()

    logger.debug("all workers completed")


# coding: utf-8

"""
Copyright 2015 SmartBear Software

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    Ref: https://github.com/swagger-api/swagger-codegen
"""

from pprint import pformat
from six import iteritems

class CompanyDetailCompany(object):
    """
    NOTE: This class is auto generated by the swagger code generator program.
    Do not edit the class manually.
    """
    def __init__(self):
        """
        CompanyDetailCompany - a model defined in Swagger

        :param dict swaggerTypes: The key is attribute name
                                  and the value is attribute type.
        :param dict attributeMap: The key is attribute name
                                  and the value is json key in definition.
        """
        self.swagger_types = {
            'legal_name': 'str',
            'status': 'str',
            'incorporation_date': 'str',
            'next_cin': 'str',
            'classification': 'str',
            'paid_up_capital': 'int',
            'authorized_capital': 'float',
            'registered_address': 'Address',
            'efiling_status': 'str',
            'cin': 'str'
        }

        self.attribute_map = {
            'legal_name': 'legal_name',
            'status': 'status',
            'incorporation_date': 'incorporation_date',
            'next_cin': 'next_cin',
            'classification': 'classification',
            'paid_up_capital': 'paid_up_capital',
            'authorized_capital': 'authorized_capital',
            'registered_address': 'registered_address',
            'efiling_status': 'efiling_status',
            'cin': 'cin'
        }

        self._legal_name = None
        self._status = None
        self._incorporation_date = None
        self._next_cin = None
        self._classification = None
        self._paid_up_capital = None
        self._authorized_capital = None
        self._registered_address = None
        self._efiling_status = None
        self._cin = None

    @property
    def legal_name(self):
        """
        Gets the legal_name of this CompanyDetailCompany.
        Legal name of the company

        :return: The legal_name of this CompanyDetailCompany.
        :rtype: str
        """
        return self._legal_name

    @legal_name.setter
    def legal_name(self, legal_name):
        """
        Sets the legal_name of this CompanyDetailCompany.
        Legal name of the company

        :param legal_name: The legal_name of this CompanyDetailCompany.
        :type: str
        """
        self._legal_name = legal_name

    @property
    def status(self):
        """
        Gets the status of this CompanyDetailCompany.
        Listing status

        :return: The status of this CompanyDetailCompany.
        :rtype: str
        """
        return self._status

    @status.setter
    def status(self, status):
        """
        Sets the status of this CompanyDetailCompany.
        Listing status

        :param status: The status of this CompanyDetailCompany.
        :type: str
        """
        allowed_values = ["Listed", "Unlisted", "Undefined"]
        if status not in allowed_values:
            raise ValueError(
                "Invalid value for `status`, must be one of {0}"
                .format(allowed_values)
            )
        self._status = status

    @property
    def incorporation_date(self):
        """
        Gets the incorporation_date of this CompanyDetailCompany.
        Date of incorporation of the company.

        :return: The incorporation_date of this CompanyDetailCompany.
        :rtype: str
        """
        return self._incorporation_date

    @incorporation_date.setter
    def incorporation_date(self, incorporation_date):
        """
        Sets the incorporation_date of this CompanyDetailCompany.
        Date of incorporation of the company.

        :param incorporation_date: The incorporation_date of this CompanyDetailCompany.
        :type: str
        """
        self._incorporation_date = incorporation_date

    @property
    def next_cin(self):
        """
        Gets the next_cin of this CompanyDetailCompany.
        Changed CIN

        :return: The next_cin of this CompanyDetailCompany.
        :rtype: str
        """
        return self._next_cin

    @next_cin.setter
    def next_cin(self, next_cin):
        """
        Sets the next_cin of this CompanyDetailCompany.
        Changed CIN

        :param next_cin: The next_cin of this CompanyDetailCompany.
        :type: str
        """
        self._next_cin = next_cin

    @property
    def classification(self):
        """
        Gets the classification of this CompanyDetailCompany.
        Classification of Company

        :return: The classification of this CompanyDetailCompany.
        :rtype: str
        """
        return self._classification

    @classification.setter
    def classification(self, classification):
        """
        Sets the classification of this CompanyDetailCompany.
        Classification of Company

        :param classification: The classification of this CompanyDetailCompany.
        :type: str
        """
        allowed_values = ["Public Limited Indian Non-Government Company", "Private Limited Indian Non-Government Company", "One Person Company", "Private Limited Foreign Company Incorporated in India", "Public Limited Foreign Company Incorporated in India", "Union Government Company", "State Government Company", "Guarantee & Association Public", "Guarantee & Association Private", "Not For Profit Company", "Unlimited Liabilities Public", "Unlimited Liabilities Private", "Undefined"]
        if classification not in allowed_values:
            raise ValueError(
                "Invalid value for `classification`, must be one of {0}"
                .format(allowed_values)
            )
        self._classification = classification

    @property
    def paid_up_capital(self):
        """
        Gets the paid_up_capital of this CompanyDetailCompany.
        Paid up capital

        :return: The paid_up_capital of this CompanyDetailCompany.
        :rtype: int
        """
        return self._paid_up_capital

    @paid_up_capital.setter
    def paid_up_capital(self, paid_up_capital):
        """
        Sets the paid_up_capital of this CompanyDetailCompany.
        Paid up capital

        :param paid_up_capital: The paid_up_capital of this CompanyDetailCompany.
        :type: int
        """
        self._paid_up_capital = paid_up_capital

    @property
    def authorized_capital(self):
        """
        Gets the authorized_capital of this CompanyDetailCompany.
        Authorized Capital for the company.

        :return: The authorized_capital of this CompanyDetailCompany.
        :rtype: float
        """
        return self._authorized_capital

    @authorized_capital.setter
    def authorized_capital(self, authorized_capital):
        """
        Sets the authorized_capital of this CompanyDetailCompany.
        Authorized Capital for the company.

        :param authorized_capital: The authorized_capital of this CompanyDetailCompany.
        :type: float
        """
        self._authorized_capital = authorized_capital

    @property
    def registered_address(self):
        """
        Gets the registered_address of this CompanyDetailCompany.

        :return: The registered_address of this CompanyDetailCompany.
        :rtype: Address
        """
        return self._registered_address

    @registered_address.setter
    def registered_address(self, registered_address):
        """
        Sets the registered_address of this CompanyDetailCompany.

        :param registered_address: The registered_address of this CompanyDetailCompany.
        :type: Address
        """
        self._registered_address = registered_address

    @property
    def efiling_status(self):
        """
        Gets the efiling_status of this CompanyDetailCompany.
        Status of EFiling.

        :return: The efiling_status of this CompanyDetailCompany.
        :rtype: str
        """
        return self._efiling_status

    @efiling_status.setter
    def efiling_status(self, efiling_status):
        """
        Sets the efiling_status of this CompanyDetailCompany.
        Status of EFiling.

        :param efiling_status: The efiling_status of this CompanyDetailCompany.
        :type: str
        """
        self._efiling_status = efiling_status

    @property
    def cin(self):
        """
        Gets the cin of this CompanyDetailCompany.
        Unique identifier representing the Company - Company Identification number.

        :return: The cin of this CompanyDetailCompany.
        :rtype: str
        """
        return self._cin

    @cin.setter
    def cin(self, cin):
        """
        Sets the cin of this CompanyDetailCompany.
        Unique identifier representing the Company - Company Identification number.

        :param cin: The cin of this CompanyDetailCompany.
        :type: str
        """
        self._cin = cin

    def to_dict(self):
        """
        Returns the model properties as a dict
        """
        result = {}

        for attr, _ in iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            else:
                result[attr] = value

        return result

    def to_str(self):
        """
        Returns the string representation of the model
        """
        return pformat(self.to_dict())

    def __repr__(self):
        """
        For `print` and `pprint`
        """
        return self.to_str()

    def __eq__(self, other):
        """
        Returns true if both objects are equal
        """
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        """
        Returns true if both objects are not equal
        """
        return not self == other


"""Python library to provide reliable communication link with LightWaveRF lights and switches."""
import logging
import socket
import time
from itertools import cycle
from queue import Queue
from threading import Thread

_LOGGER = logging.getLogger(__name__)

class LWLink():
    """LWLink provides a communication link with the LightwaveRF hub."""

    SOCKET_TIMEOUT = 2.0
    RX_PORT = 9761
    TX_PORT = 9760

    link_ip = None
    transaction_id = cycle(range(1, 1000))
    the_queue = Queue()
    thread = None

    def __init__(self, link_ip=None):
        """Initialise the component."""
        if link_ip is not None:
            LWLink.link_ip = link_ip

    def _send_message(self, msg):
        """Add message to queue and start processing the queue."""
        LWLink.the_queue.put_nowait(msg)
        if LWLink.thread is None or not LWLink.thread.isAlive():
            LWLink.thread = Thread(target=self._send_queue)
            LWLink.thread.start()

    def register(self):
        """Create the message to register client."""
        msg = '!F*p'
        self._send_message(msg)

    def deregister_all(self):
        """Create the message to deregister all clients."""
        msg = '!F*xP'
        self._send_message(msg)

    def turn_on_light(self, device_id, name):
        """Create the message to turn light on."""
        msg = "!%sFdP32|Turn On|%s" % (device_id, name)
        self._send_message(msg)

    def turn_on_switch(self, device_id, name):
        """Create the message to turn switch on."""
        msg = "!%sF1|Turn On|%s" % (device_id, name)
        self._send_message(msg)

    def turn_on_with_brightness(self, device_id, name, brightness):
        """Scale brightness from 0..255 to 1..32."""
        brightness_value = round((brightness * 31) / 255) + 1
        # F1 = Light on and F0 = light off. FdP[0..32] is brightness. 32 is
        # full. We want that when turning the light on.
        msg = "!%sFdP%d|Lights %d|%s" % (
            device_id, brightness_value, brightness_value, name)
        self._send_message(msg)

    def turn_off(self, device_id, name):
        """Create the message to turn light or switch off."""
        msg = "!%sF0|Turn Off|%s" % (device_id, name)
        self._send_message(msg)

    def _send_queue(self):
        """If the queue is not empty, process the queue."""
        while not LWLink.the_queue.empty():
            self._send_reliable_message(LWLink.the_queue.get_nowait())

    def _send_reliable_message(self, msg):
        """Send msg to LightwaveRF hub."""
        result = False
        max_retries = 15
        trans_id = next(LWLink.transaction_id)
        msg = "%d,%s" % (trans_id, msg)
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) \
                    as write_sock, \
                    socket.socket(socket.AF_INET, socket.SOCK_DGRAM) \
                    as read_sock:
                write_sock.setsockopt(
                    socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                read_sock.setsockopt(socket.SOL_SOCKET,
                                     socket.SO_BROADCAST, 1)
                read_sock.settimeout(self.SOCKET_TIMEOUT)
                read_sock.bind(('0.0.0.0', self.RX_PORT))
                while max_retries:
                    max_retries -= 1
                    write_sock.sendto(msg.encode(
                        'UTF-8'), (LWLink.link_ip, self.TX_PORT))
                    result = False
                    while True:
                        response, dummy = read_sock.recvfrom(1024)
                        response = response.decode('UTF-8')
                        if "Not yet registered." in response:
                            _LOGGER.error("Not yet registered")
                            self.register()
                            result = True
                            break

                        if response.startswith("%d,OK" % trans_id):
                            result = True
                            break
                        if response.startswith("%d,ERR" % trans_id):
                            _LOGGER.error(response)
                            break

                        _LOGGER.info(response)

                    if result:
                        break

                    time.sleep(0.25)

        except socket.timeout:
            _LOGGER.error("LW broker timeout!")
            return result

        except Exception as ex:
            _LOGGER.error(ex)
            raise

        if result:
            _LOGGER.info("LW broker OK!")
        else:
            _LOGGER.error("LW broker fail!")
        return result


# coding: utf-8

"""
Copyright 2015 SmartBear Software

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

    Ref: https://github.com/swagger-api/swagger-codegen
"""

from pprint import pformat
from six import iteritems

class YearlyFinancials(object):
    """
    NOTE: This class is auto generated by the swagger code generator program.
    Do not edit the class manually.
    """
    def __init__(self):
        """
        YearlyFinancials - a model defined in Swagger

        :param dict swaggerTypes: The key is attribute name
                                  and the value is attribute type.
        :param dict attributeMap: The key is attribute name
                                  and the value is json key in definition.
        """
        self.swagger_types = {
            'year': 'date',
            'nature': 'str',
            'stated_on': 'date',
            'capital_wip': 'float',
            'cash_and_bank_balances': 'float',
            'investments': 'float',
            'inventories': 'float',
            'net_fixed_assets': 'float',
            'other_assets': 'float',
            'total_assets': 'float',
            'trade_receivables': 'float',
            'share_capital': 'float',
            'reserves_and_surplus': 'float',
            'others': 'float',
            'long_term_borrowings': 'float',
            'other_current_liabilities_and_provisions': 'float',
            'other_long_term_liabilities_and_provisions': 'float',
            'trade_payables': 'float',
            'short_term_borrowings': 'float',
            'total_equity': 'float',
            'total_equity_and_liabilities': 'float',
            'depreciation': 'float',
            'exceptional_item_before_tax': 'float',
            'income_tax': 'float',
            'interest': 'float',
            'net_income': 'float',
            'operating_cost': 'float',
            'operating_profit': 'float',
            'other_income': 'float',
            'profit_before_interest_and_tax': 'float',
            'profit_before_tax': 'float',
            'revenue': 'float'
        }

        self.attribute_map = {
            'year': 'year',
            'nature': 'nature',
            'stated_on': 'stated_on',
            'capital_wip': 'capital_wip',
            'cash_and_bank_balances': 'cash_and_bank_balances',
            'investments': 'investments',
            'inventories': 'inventories',
            'net_fixed_assets': 'net_fixed_assets',
            'other_assets': 'other_assets',
            'total_assets': 'total_assets',
            'trade_receivables': 'trade_receivables',
            'share_capital': 'share_capital',
            'reserves_and_surplus': 'reserves_and_surplus',
            'others': 'others',
            'long_term_borrowings': 'long_term_borrowings',
            'other_current_liabilities_and_provisions': 'other_current_liabilities_and_provisions',
            'other_long_term_liabilities_and_provisions': 'other_long_term_liabilities_and_provisions',
            'trade_payables': 'trade_payables',
            'short_term_borrowings': 'short_term_borrowings',
            'total_equity': 'total_equity',
            'total_equity_and_liabilities': 'total_equity_and_liabilities',
            'depreciation': 'depreciation',
            'exceptional_item_before_tax': 'exceptional_item_before_tax',
            'income_tax': 'income_tax',
            'interest': 'interest',
            'net_income': 'net_income',
            'operating_cost': 'operating_cost',
            'operating_profit': 'operating_profit',
            'other_income': 'other_income',
            'profit_before_interest_and_tax': 'profit_before_interest_and_tax',
            'profit_before_tax': 'profit_before_tax',
            'revenue': 'revenue'
        }

        self._year = None
        self._nature = None
        self._stated_on = None
        self._capital_wip = None
        self._cash_and_bank_balances = None
        self._investments = None
        self._inventories = None
        self._net_fixed_assets = None
        self._other_assets = None
        self._total_assets = None
        self._trade_receivables = None
        self._share_capital = None
        self._reserves_and_surplus = None
        self._others = None
        self._long_term_borrowings = None
        self._other_current_liabilities_and_provisions = None
        self._other_long_term_liabilities_and_provisions = None
        self._trade_payables = None
        self._short_term_borrowings = None
        self._total_equity = None
        self._total_equity_and_liabilities = None
        self._depreciation = None
        self._exceptional_item_before_tax = None
        self._income_tax = None
        self._interest = None
        self._net_income = None
        self._operating_cost = None
        self._operating_profit = None
        self._other_income = None
        self._profit_before_interest_and_tax = None
        self._profit_before_tax = None
        self._revenue = None

    @property
    def year(self):
        """
        Gets the year of this YearlyFinancials.
        Year-end of the balancesheet

        :return: The year of this YearlyFinancials.
        :rtype: date
        """
        return self._year

    @year.setter
    def year(self, year):
        """
        Sets the year of this YearlyFinancials.
        Year-end of the balancesheet

        :param year: The year of this YearlyFinancials.
        :type: date
        """
        self._year = year

    @property
    def nature(self):
        """
        Gets the nature of this YearlyFinancials.
        Nature of the balancesheet

        :return: The nature of this YearlyFinancials.
        :rtype: str
        """
        return self._nature

    @nature.setter
    def nature(self, nature):
        """
        Sets the nature of this YearlyFinancials.
        Nature of the balancesheet

        :param nature: The nature of this YearlyFinancials.
        :type: str
        """
        allowed_values = ["STANDALONE"]
        if nature not in allowed_values:
            raise ValueError(
                "Invalid value for `nature`, must be one of {0}"
                .format(allowed_values)
            )
        self._nature = nature

    @property
    def stated_on(self):
        """
        Gets the stated_on of this YearlyFinancials.
        Balancesheet stated on date

        :return: The stated_on of this YearlyFinancials.
        :rtype: date
        """
        return self._stated_on

    @stated_on.setter
    def stated_on(self, stated_on):
        """
        Sets the stated_on of this YearlyFinancials.
        Balancesheet stated on date

        :param stated_on: The stated_on of this YearlyFinancials.
        :type: date
        """
        self._stated_on = stated_on

    @property
    def capital_wip(self):
        """
        Gets the capital_wip of this YearlyFinancials.
        Capital work in progress

        :return: The capital_wip of this YearlyFinancials.
        :rtype: float
        """
        return self._capital_wip

    @capital_wip.setter
    def capital_wip(self, capital_wip):
        """
        Sets the capital_wip of this YearlyFinancials.
        Capital work in progress

        :param capital_wip: The capital_wip of this YearlyFinancials.
        :type: float
        """
        self._capital_wip = capital_wip

    @property
    def cash_and_bank_balances(self):
        """
        Gets the cash_and_bank_balances of this YearlyFinancials.

        :return: The cash_and_bank_balances of this YearlyFinancials.
        :rtype: float
        """
        return self._cash_and_bank_balances

    @cash_and_bank_balances.setter
    def cash_and_bank_balances(self, cash_and_bank_balances):
        """
        Sets the cash_and_bank_balances of this YearlyFinancials.

        :param cash_and_bank_balances: The cash_and_bank_balances of this YearlyFinancials.
        :type: float
        """
        self._cash_and_bank_balances = cash_and_bank_balances

    @property
    def investments(self):
        """
        Gets the investments of this YearlyFinancials.

        :return: The investments of this YearlyFinancials.
        :rtype: float
        """
        return self._investments

    @investments.setter
    def investments(self, investments):
        """
        Sets the investments of this YearlyFinancials.

        :param investments: The investments of this YearlyFinancials.
        :type: float
        """
        self._investments = investments

    @property
    def inventories(self):
        """
        Gets the inventories of this YearlyFinancials.

        :return: The inventories of this YearlyFinancials.
        :rtype: float
        """
        return self._inventories

    @inventories.setter
    def inventories(self, inventories):
        """
        Sets the inventories of this YearlyFinancials.

        :param inventories: The inventories of this YearlyFinancials.
        :type: float
        """
        self._inventories = inventories

    @property
    def net_fixed_assets(self):
        """
        Gets the net_fixed_assets of this YearlyFinancials.

        :return: The net_fixed_assets of this YearlyFinancials.
        :rtype: float
        """
        return self._net_fixed_assets

    @net_fixed_assets.setter
    def net_fixed_assets(self, net_fixed_assets):
        """
        Sets the net_fixed_assets of this YearlyFinancials.

        :param net_fixed_assets: The net_fixed_assets of this YearlyFinancials.
        :type: float
        """
        self._net_fixed_assets = net_fixed_assets

    @property
    def other_assets(self):
        """
        Gets the other_assets of this YearlyFinancials.

        :return: The other_assets of this YearlyFinancials.
        :rtype: float
        """
        return self._other_assets

    @other_assets.setter
    def other_assets(self, other_assets):
        """
        Sets the other_assets of this YearlyFinancials.

        :param other_assets: The other_assets of this YearlyFinancials.
        :type: float
        """
        self._other_assets = other_assets

    @property
    def total_assets(self):
        """
        Gets the total_assets of this YearlyFinancials.

        :return: The total_assets of this YearlyFinancials.
        :rtype: float
        """
        return self._total_assets

    @total_assets.setter
    def total_assets(self, total_assets):
        """
        Sets the total_assets of this YearlyFinancials.

        :param total_assets: The total_assets of this YearlyFinancials.
        :type: float
        """
        self._total_assets = total_assets

    @property
    def trade_receivables(self):
        """
        Gets the trade_receivables of this YearlyFinancials.

        :return: The trade_receivables of this YearlyFinancials.
        :rtype: float
        """
        return self._trade_receivables

    @trade_receivables.setter
    def trade_receivables(self, trade_receivables):
        """
        Sets the trade_receivables of this YearlyFinancials.

        :param trade_receivables: The trade_receivables of this YearlyFinancials.
        :type: float
        """
        self._trade_receivables = trade_receivables

    @property
    def share_capital(self):
        """
        Gets the share_capital of this YearlyFinancials.

        :return: The share_capital of this YearlyFinancials.
        :rtype: float
        """
        return self._share_capital

    @share_capital.setter
    def share_capital(self, share_capital):
        """
        Sets the share_capital of this YearlyFinancials.

        :param share_capital: The share_capital of this YearlyFinancials.
        :type: float
        """
        self._share_capital = share_capital

    @property
    def reserves_and_surplus(self):
        """
        Gets the reserves_and_surplus of this YearlyFinancials.

        :return: The reserves_and_surplus of this YearlyFinancials.
        :rtype: float
        """
        return self._reserves_and_surplus

    @reserves_and_surplus.setter
    def reserves_and_surplus(self, reserves_and_surplus):
        """
        Sets the reserves_and_surplus of this YearlyFinancials.

        :param reserves_and_surplus: The reserves_and_surplus of this YearlyFinancials.
        :type: float
        """
        self._reserves_and_surplus = reserves_and_surplus

    @property
    def others(self):
        """
        Gets the others of this YearlyFinancials.

        :return: The others of this YearlyFinancials.
        :rtype: float
        """
        return self._others

    @others.setter
    def others(self, others):
        """
        Sets the others of this YearlyFinancials.

        :param others: The others of this YearlyFinancials.
        :type: float
        """
        self._others = others

    @property
    def long_term_borrowings(self):
        """
        Gets the long_term_borrowings of this YearlyFinancials.

        :return: The long_term_borrowings of this YearlyFinancials.
        :rtype: float
        """
        return self._long_term_borrowings

    @long_term_borrowings.setter
    def long_term_borrowings(self, long_term_borrowings):
        """
        Sets the long_term_borrowings of this YearlyFinancials.

        :param long_term_borrowings: The long_term_borrowings of this YearlyFinancials.
        :type: float
        """
        self._long_term_borrowings = long_term_borrowings

    @property
    def other_current_liabilities_and_provisions(self):
        """
        Gets the other_current_liabilities_and_provisions of this YearlyFinancials.

        :return: The other_current_liabilities_and_provisions of this YearlyFinancials.
        :rtype: float
        """
        return self._other_current_liabilities_and_provisions

    @other_current_liabilities_and_provisions.setter
    def other_current_liabilities_and_provisions(self, other_current_liabilities_and_provisions):
        """
        Sets the other_current_liabilities_and_provisions of this YearlyFinancials.

        :param other_current_liabilities_and_provisions: The other_current_liabilities_and_provisions of this YearlyFinancials.
        :type: float
        """
        self._other_current_liabilities_and_provisions = other_current_liabilities_and_provisions

    @property
    def other_long_term_liabilities_and_provisions(self):
        """
        Gets the other_long_term_liabilities_and_provisions of this YearlyFinancials.

        :return: The other_long_term_liabilities_and_provisions of this YearlyFinancials.
        :rtype: float
        """
        return self._other_long_term_liabilities_and_provisions

    @other_long_term_liabilities_and_provisions.setter
    def other_long_term_liabilities_and_provisions(self, other_long_term_liabilities_and_provisions):
        """
        Sets the other_long_term_liabilities_and_provisions of this YearlyFinancials.

        :param other_long_term_liabilities_and_provisions: The other_long_term_liabilities_and_provisions of this YearlyFinancials.
        :type: float
        """
        self._other_long_term_liabilities_and_provisions = other_long_term_liabilities_and_provisions

    @property
    def trade_payables(self):
        """
        Gets the trade_payables of this YearlyFinancials.

        :return: The trade_payables of this YearlyFinancials.
        :rtype: float
        """
        return self._trade_payables

    @trade_payables.setter
    def trade_payables(self, trade_payables):
        """
        Sets the trade_payables of this YearlyFinancials.

        :param trade_payables: The trade_payables of this YearlyFinancials.
        :type: float
        """
        self._trade_payables = trade_payables

    @property
    def short_term_borrowings(self):
        """
        Gets the short_term_borrowings of this YearlyFinancials.

        :return: The short_term_borrowings of this YearlyFinancials.
        :rtype: float
        """
        return self._short_term_borrowings

    @short_term_borrowings.setter
    def short_term_borrowings(self, short_term_borrowings):
        """
        Sets the short_term_borrowings of this YearlyFinancials.

        :param short_term_borrowings: The short_term_borrowings of this YearlyFinancials.
        :type: float
        """
        self._short_term_borrowings = short_term_borrowings

    @property
    def total_equity(self):
        """
        Gets the total_equity of this YearlyFinancials.

        :return: The total_equity of this YearlyFinancials.
        :rtype: float
        """
        return self._total_equity

    @total_equity.setter
    def total_equity(self, total_equity):
        """
        Sets the total_equity of this YearlyFinancials.

        :param total_equity: The total_equity of this YearlyFinancials.
        :type: float
        """
        self._total_equity = total_equity

    @property
    def total_equity_and_liabilities(self):
        """
        Gets the total_equity_and_liabilities of this YearlyFinancials.

        :return: The total_equity_and_liabilities of this YearlyFinancials.
        :rtype: float
        """
        return self._total_equity_and_liabilities

    @total_equity_and_liabilities.setter
    def total_equity_and_liabilities(self, total_equity_and_liabilities):
        """
        Sets the total_equity_and_liabilities of this YearlyFinancials.

        :param total_equity_and_liabilities: The total_equity_and_liabilities of this YearlyFinancials.
        :type: float
        """
        self._total_equity_and_liabilities = total_equity_and_liabilities

    @property
    def depreciation(self):
        """
        Gets the depreciation of this YearlyFinancials.

        :return: The depreciation of this YearlyFinancials.
        :rtype: float
        """
        return self._depreciation

    @depreciation.setter
    def depreciation(self, depreciation):
        """
        Sets the depreciation of this YearlyFinancials.

        :param depreciation: The depreciation of this YearlyFinancials.
        :type: float
        """
        self._depreciation = depreciation

    @property
    def exceptional_item_before_tax(self):
        """
        Gets the exceptional_item_before_tax of this YearlyFinancials.

        :return: The exceptional_item_before_tax of this YearlyFinancials.
        :rtype: float
        """
        return self._exceptional_item_before_tax

    @exceptional_item_before_tax.setter
    def exceptional_item_before_tax(self, exceptional_item_before_tax):
        """
        Sets the exceptional_item_before_tax of this YearlyFinancials.

        :param exceptional_item_before_tax: The exceptional_item_before_tax of this YearlyFinancials.
        :type: float
        """
        self._exceptional_item_before_tax = exceptional_item_before_tax

    @property
    def income_tax(self):
        """
        Gets the income_tax of this YearlyFinancials.

        :return: The income_tax of this YearlyFinancials.
        :rtype: float
        """
        return self._income_tax

    @income_tax.setter
    def income_tax(self, income_tax):
        """
        Sets the income_tax of this YearlyFinancials.

        :param income_tax: The income_tax of this YearlyFinancials.
        :type: float
        """
        self._income_tax = income_tax

    @property
    def interest(self):
        """
        Gets the interest of this YearlyFinancials.

        :return: The interest of this YearlyFinancials.
        :rtype: float
        """
        return self._interest

    @interest.setter
    def interest(self, interest):
        """
        Sets the interest of this YearlyFinancials.

        :param interest: The interest of this YearlyFinancials.
        :type: float
        """
        self._interest = interest

    @property
    def net_income(self):
        """
        Gets the net_income of this YearlyFinancials.

        :return: The net_income of this YearlyFinancials.
        :rtype: float
        """
        return self._net_income

    @net_income.setter
    def net_income(self, net_income):
        """
        Sets the net_income of this YearlyFinancials.

        :param net_income: The net_income of this YearlyFinancials.
        :type: float
        """
        self._net_income = net_income

    @property
    def operating_cost(self):
        """
        Gets the operating_cost of this YearlyFinancials.

        :return: The operating_cost of this YearlyFinancials.
        :rtype: float
        """
        return self._operating_cost

    @operating_cost.setter
    def operating_cost(self, operating_cost):
        """
        Sets the operating_cost of this YearlyFinancials.

        :param operating_cost: The operating_cost of this YearlyFinancials.
        :type: float
        """
        self._operating_cost = operating_cost

    @property
    def operating_profit(self):
        """
        Gets the operating_profit of this YearlyFinancials.

        :return: The operating_profit of this YearlyFinancials.
        :rtype: float
        """
        return self._operating_profit

    @operating_profit.setter
    def operating_profit(self, operating_profit):
        """
        Sets the operating_profit of this YearlyFinancials.

        :param operating_profit: The operating_profit of this YearlyFinancials.
        :type: float
        """
        self._operating_profit = operating_profit

    @property
    def other_income(self):
        """
        Gets the other_income of this YearlyFinancials.

        :return: The other_income of this YearlyFinancials.
        :rtype: float
        """
        return self._other_income

    @other_income.setter
    def other_income(self, other_income):
        """
        Sets the other_income of this YearlyFinancials.

        :param other_income: The other_income of this YearlyFinancials.
        :type: float
        """
        self._other_income = other_income

    @property
    def profit_before_interest_and_tax(self):
        """
        Gets the profit_before_interest_and_tax of this YearlyFinancials.

        :return: The profit_before_interest_and_tax of this YearlyFinancials.
        :rtype: float
        """
        return self._profit_before_interest_and_tax

    @profit_before_interest_and_tax.setter
    def profit_before_interest_and_tax(self, profit_before_interest_and_tax):
        """
        Sets the profit_before_interest_and_tax of this YearlyFinancials.

        :param profit_before_interest_and_tax: The profit_before_interest_and_tax of this YearlyFinancials.
        :type: float
        """
        self._profit_before_interest_and_tax = profit_before_interest_and_tax

    @property
    def profit_before_tax(self):
        """
        Gets the profit_before_tax of this YearlyFinancials.

        :return: The profit_before_tax of this YearlyFinancials.
        :rtype: float
        """
        return self._profit_before_tax

    @profit_before_tax.setter
    def profit_before_tax(self, profit_before_tax):
        """
        Sets the profit_before_tax of this YearlyFinancials.

        :param profit_before_tax: The profit_before_tax of this YearlyFinancials.
        :type: float
        """
        self._profit_before_tax = profit_before_tax

    @property
    def revenue(self):
        """
        Gets the revenue of this YearlyFinancials.

        :return: The revenue of this YearlyFinancials.
        :rtype: float
        """
        return self._revenue

    @revenue.setter
    def revenue(self, revenue):
        """
        Sets the revenue of this YearlyFinancials.

        :param revenue: The revenue of this YearlyFinancials.
        :type: float
        """
        self._revenue = revenue

    def to_dict(self):
        """
        Returns the model properties as a dict
        """
        result = {}

        for attr, _ in iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            else:
                result[attr] = value

        return result

    def to_str(self):
        """
        Returns the string representation of the model
        """
        return pformat(self.to_dict())

    def __repr__(self):
        """
        For `print` and `pprint`
        """
        return self.to_str()

    def __eq__(self, other):
        """
        Returns true if both objects are equal
        """
        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        """
        Returns true if both objects are not equal
        """
        return not self == other


# -*- coding: utf-8 -*-
"""Return compact set of columns as a string with newlines for an
array of strings.

Adapted from the routine of the same name inside cmd.py"""

import os
try:
    from shutil import get_terminal_size  # Python >= 3.3
except ImportError:
    from backports.shutil_get_terminal_size import get_terminal_size

def computed_displaywidth():
    '''Figure out a reasonable default with. Use os.environ['COLUMNS'] if possible,
    and failing that use 80.
    '''
    try:
        width = int(os.environ['COLUMNS'])
    except (KeyError, ValueError):
        width = get_terminal_size().columns

    return width or 80

default_opts = {
    'arrange_array'    : False,  # Check if file has changed since last time
    'arrange_vertical' : True,
    'array_prefix'     : '',
    'array_suffix'     : '',
    'colfmt'           : None,
    'colsep'           : '  ',
    'displaywidth'     : computed_displaywidth(),
    'lineprefix'       : '',
    'linesuffix'       : "\n",
    'ljust'            : None,
    'term_adjust'      : False
    }

def get_option(key, options):
    return options.get(key, default_opts.get(key))

def columnize(array, displaywidth=80, colsep = '  ',
              arrange_vertical=True, ljust=True, lineprefix='',
              opts={}):
    """Return a list of strings as a compact set of columns arranged
    horizontally or vertically.

    For example, for a line width of 4 characters (arranged vertically):
        ['1', '2,', '3', '4'] => '1  3\n2  4\n'

    or arranged horizontally:
        ['1', '2,', '3', '4'] => '1  2\n3  4\n'

    Each column is only as wide as necessary.  By default, columns are
    separated by two spaces - one was not legible enough. Set "colsep"
    to adjust the string separate columns. Set `displaywidth' to set
    the line width.

    Normally, consecutive items go down from the top to bottom from
    the left-most column to the right-most. If "arrange_vertical" is
    set false, consecutive items will go across, left to right, top to
    bottom."""
    if not isinstance(array, (list, tuple)):
        raise TypeError((
            'array needs to be an instance of a list or a tuple'))

    o = {}
    if len(opts.keys()) > 0:
        for key in default_opts.keys():
            o[key] = get_option(key, opts)
            pass
        if o['arrange_array']:
            o['array_prefix'] = '['
            o['lineprefix']   = ' '
            o['linesuffix']   = ",\n"
            o['array_suffix'] = "]\n"
            o['colsep']       = ', '
            o['arrange_vertical'] = False
            pass

    else:
        o = default_opts.copy()
        o['displaywidth']     = displaywidth
        o['colsep']           = colsep
        o['arrange_vertical'] = arrange_vertical
        o['ljust']            = ljust
        o['lineprefix']       = lineprefix
        pass

    # if o['ljust'] is None:
    #     o['ljust'] = !(list.all?{|datum| datum.kind_of?(Numeric)})
    #     pass

    if o['colfmt']:
        array = [(o['colfmt'] % i) for i in array]
    else:
        array = [str(i) for i in array]
        pass

    # Some degenerate cases
    size = len(array)
    if 0 == size:
        return "<empty>\n"
    elif size == 1:
        return '%s%s%s\n' % (o['array_prefix'], str(array[0]),
                             o['array_suffix'])

    o['displaywidth'] = max(4, o['displaywidth'] - len(o['lineprefix']))
    if o['arrange_vertical']:
        array_index = lambda nrows, row, col: nrows*col + row
        # Try every row count from 1 upwards
        for nrows in range(1, size+1):
            ncols = (size+nrows-1) // nrows
            colwidths = []
            totwidth = -len(o['colsep'])
            for col in range(ncols):
                # get max column width for this column
                colwidth = 0
                for row in range(nrows):
                    i = array_index(nrows, row, col)
                    if i >= size: break
                    x = array[i]
                    colwidth = max(colwidth, len(x))
                    pass
                colwidths.append(colwidth)
                totwidth += colwidth + len(o['colsep'])
                if totwidth > o['displaywidth']:
                    break
                pass
            if totwidth <= o['displaywidth']:
                break
            pass
        # The smallest number of rows computed and the
        # max widths for each column has been obtained.
        # Now we just have to format each of the
        # rows.
        s = ''
        for row in range(nrows):
            texts = []
            for col in range(ncols):
                i = row + nrows*col
                if i >= size:
                    x = ""
                else:
                    x = array[i]
                texts.append(x)
            while texts and not texts[-1]:
                del texts[-1]
            for col in range(len(texts)):
                if o['ljust']:
                    texts[col] = texts[col].ljust(colwidths[col])
                else:
                    texts[col] = texts[col].rjust(colwidths[col])
                    pass
                pass
            s += "%s%s%s" % (o['lineprefix'], str(o['colsep'].join(texts)),
                             o['linesuffix'])
            pass
        return s
    else:
        array_index = lambda ncols, row, col: ncols*(row-1) + col
        # Try every column count from size downwards
        colwidths = []
        for ncols in range(size, 0, -1):
            # Try every row count from 1 upwards
            min_rows = (size+ncols-1) // ncols
            nrows = min_rows -1
            while nrows < size:
                nrows += 1
                rounded_size = nrows * ncols
                colwidths = []
                totwidth  = -len(o['colsep'])
                for col in range(ncols):
                    # get max column width for this column
                    colwidth  = 0
                    for row in range(1, nrows+1):
                        i = array_index(ncols, row, col)
                        if i >= rounded_size: break
                        elif i < size:
                            x = array[i]
                            colwidth = max(colwidth, len(x))
                            pass
                        pass
                    colwidths.append(colwidth)
                    totwidth += colwidth + len(o['colsep'])
                    if totwidth >= o['displaywidth']:
                        break
                    pass
                if totwidth <= o['displaywidth'] and i >= rounded_size-1:
                    # Found the right nrows and ncols
                    # print "right nrows and ncols"
                    nrows  = row
                    break
                elif totwidth >= o['displaywidth']:
                    # print "reduce ncols", ncols
                    # Need to reduce ncols
                    break
                pass
            if totwidth <= o['displaywidth'] and i >= rounded_size-1:
                break
            pass
        # The smallest number of rows computed and the
        # max widths for each column has been obtained.
        # Now we just have to format each of the
        # rows.
        s = ''
        if len(o['array_prefix']) != 0:
            prefix = o['array_prefix']
        else:
            prefix = o['lineprefix']
            pass
        for row in range(1, nrows+1):
            texts = []
            for col in range(ncols):
                i = array_index(ncols, row, col)
                if i >= size:
                    break
                else: x = array[i]
                texts.append(x)
                pass
            for col in range(len(texts)):
                if o['ljust']:
                    texts[col] = texts[col].ljust(colwidths[col])
                else:
                    texts[col] = texts[col].rjust(colwidths[col])
                    pass
                pass
            s += "%s%s%s" % (prefix, str(o['colsep'].join(texts)),
                             o['linesuffix'])
            prefix = o['lineprefix']
            pass
        if o['arrange_array']:
            colsep = o['colsep'].rstrip()
            colsep_pos = -(len(colsep)+1)
            if s[colsep_pos:] == colsep + "\n":
                s = s[:colsep_pos] + o['array_suffix'] + "\n"
                pass
            pass
        else:
            s += o['array_suffix']
            pass
        return s
    pass

# Demo it
if __name__=='__main__':
    # from trepan.api import debug
    # debug()
    print(columnize(list(range(12)),
                      opts={'displaywidth':6, 'arrange_array':True}))
    print(columnize(list(range(12)),
                      opts={'displaywidth':10, 'arrange_array':True}))
    for t in ((4, 4,), (4, 7), (100, 80)):
        width = t[1]
        data = [str(i) for i in range(t[0])]
        options = {}
        for t2 in ((False, 'horizontal',), (True, 'vertical',)):
            print("Width: %d, direction: %s" % (width, t2[1]))
            options['displaywidth'] = width
            options['arrange_vertical'] = t2[0]
            print(columnize(data, opts=options))
            pass
        pass
    print(columnize([]))
    print(columnize(["a", '2', "c"], 10, ', '))
    print(columnize(["oneitem"]))
    print(columnize(("one", "two", "three",)))
    data = (
        "one",       "two",         "three",
        "for",       "five",        "six",
        "seven",     "eight",       "nine",
        "ten",       "eleven",      "twelve",
        "thirteen",  "fourteen",    "fifteen",
        "sixteen",   "seventeen",   "eightteen",
        "nineteen",  "twenty",      "twentyone",
        "twentytwo", "twentythree", "twentyfour",
        "twentyfive","twentysix",   "twentyseven",)
    print(columnize(data))
    print(columnize(data, arrange_vertical=False))
    data = [str(i) for i in range(55)]
    print(columnize(data, opts={'displaywidth':39, 'arrange_array':True}))
    print(columnize(data, displaywidth=39, ljust=False,
                    colsep=', ', lineprefix='    '))
    print(columnize(data, displaywidth=39, ljust=False,
                    arrange_vertical=False,
                    colsep = ', '))

    print(columnize(data, displaywidth=39, ljust=False,
                    arrange_vertical=False,
                    colsep = ', ', lineprefix='    '))

    import sys
    try:
        print(columnize(5))
    except TypeError:
        _, err, _ = sys.exc_info()
        print(err)
        pass

    print(columnize(list(range(4))))


"""Definition of configuration manager classes.

Note:
    All methods and attributes are postfixed with an underscore to minimize the
    risk of collision with the names of your configuration sections and
    options.
"""
import pathlib
from types import MappingProxyType

import toml

from . import error

def _is_valid(name):
    """Check if a section or option name is valid."""
    return name.isidentifier() and name != 'loam_sub_name'

class ConfOpt:

    """Metadata of configuration options.

    Attributes:
        default: the default value of the configuration option.
        cmd_arg (bool): whether the option is a command line argument.
        shortname (str): short version of the command line argument.
        cmd_kwargs (dict): keyword arguments fed to
            :meth:`argparse.ArgumentParser.add_argument` during the
            construction of the command line arguments parser.
        conf_arg (bool): whether the option can be set in the config file.
        help (str): short description of the option.
        comprule (str): completion rule for ZSH shell.

    """

    def __init__(self, default, cmd_arg=False, shortname=None, cmd_kwargs=None,
                 conf_arg=False, help_msg='', comprule=''):
        self.default = default
        self.cmd_arg = cmd_arg
        self.shortname = shortname
        self.cmd_kwargs = {} if cmd_kwargs is None else cmd_kwargs
        self.conf_arg = conf_arg
        self.help = help_msg
        self.comprule = comprule

class Section:

    """Hold options for a single section."""

    def __init__(self, **options):
        """Initialization of instances.

        Args:
            options (:class:`ConfOpt`): option metadata. The name of each
                *option* is the name of the keyword argument passed on to this
                function. Option names should be valid identifiers, otherwise
                an :class:`~loam.error.OptionError` is raised.
        """
        self._def = {}
        for opt_name, opt_meta in options.items():
            if _is_valid(opt_name):
                self._def[opt_name] = opt_meta
                self[opt_name] = opt_meta.default
            else:
                raise error.OptionError(opt_name)

    @property
    def def_(self):
        return MappingProxyType(self._def)

    def __getitem__(self, opt):
        return getattr(self, opt)

    def __setitem__(self, opt, value):
        setattr(self, opt, value)

    def __delitem__(self, opt):
        delattr(self, opt)

    def __delattr__(self, opt):
        if opt not in self:
            raise error.OptionError(opt)
        self[opt] = self.def_[opt].default

    def __getattr__(self, opt):
        raise error.OptionError(opt)

    def __iter__(self):
        return iter(self.def_.keys())

    def __contains__(self, opt):
        return opt in self.def_

    def options_(self):
        """Iterator over configuration option names.

        Yields:
            option names.
        """
        return iter(self)

    def opt_vals_(self):
        """Iterator over option names and option values.

        Yields:
            tuples with option names, and option values.
        """
        for opt in self.options_():
            yield opt, self[opt]

    def defaults_(self):
        """Iterator over option names, and option metadata.

        Yields:
            tuples with option names, and :class:`Conf` instances holding
            option metadata.
        """
        return self.def_.items()

    def update_(self, sct_dict, conf_arg=True):
        """Update values of configuration section with dict.

        Args:
            sct_dict (dict): dict indexed with option names. Undefined
                options are discarded.
            conf_arg (bool): if True, only options that can be set in a config
                file are updated.
        """
        for opt, val in sct_dict.items():
            if opt not in self.def_:
                continue
            if not conf_arg or self.def_[opt].conf_arg:
                self[opt] = val

    def reset_(self):
        """Restore default values of options in this section."""
        for opt, meta in self.defaults_():
            self[opt] = meta.default

class ConfigurationManager:

    """Configuration manager.

    Configuration options are organized in sections. A configuration option can
    be accessed both with attribute and item access notations, these two lines
    access the same option value::

        conf.some_section.some_option
        conf['some_section']['some_option']

    To reset a configuration option (or an entire section) to its default
    value, simply delete it (with item or attribute notation)::

        del conf['some_section']  # reset all options in 'some_section'
        del conf.some_section.some_option  # reset a particular option

    It will be set to its default value the next time you access it.
    """

    def __init__(self, **sections):
        """Initialization of instances.

        Args:
            sections (:class:`~loam.manager.Section`): section metadata. The
                name of each *section* is the name of the keyword argument
                passed on to this function. Section names should be valid
                identifiers, otherwise a :class:`~loam.error.SectionError` is
                raised.
        """
        self._sections = []
        for sct_name, sct_meta in sections.items():
            if _is_valid(sct_name):
                setattr(self, sct_name, Section(**sct_meta.def_))
                self._sections.append(sct_name)
            else:
                raise error.SectionError(sct_name)
        self._parser = None
        self._nosub_valid = False
        self._subcmds = {}
        self._config_files = ()

    @classmethod
    def from_dict_(cls, conf_dict):
        """Use a dictionary to create a :class:`ConfigurationManager`.

        Args:
            conf_dict (dict of dict of :class:`ConfOpt`): the first level of
                keys should be the section names. The second level should be
                the option names. The values are the options metadata.

        Returns:
            :class:`ConfigurationManager`: a configuration manager with the
            requested sections and options.
        """
        return cls(**{name: Section(**opts)
                      for name, opts in conf_dict.items()})

    @property
    def config_files_(self):
        """Path of config files.

        Tuple of pathlib.Path instances. The config files are in the order of
        reading. This means the most global config file is the first one on
        this list while the most local config file is the last one.
        """
        return self._config_files

    def set_config_files_(self, *config_files):
        """Set the list of config files.

        Args:
            config_files (pathlike): path of config files, given in the order
                of reading.
        """
        self._config_files = tuple(pathlib.Path(path) for path in config_files)

    def __getitem__(self, sct):
        return getattr(self, sct)

    def __delitem__(self, sct):
        delattr(self, sct)

    def __delattr__(self, sct):
        self[sct].reset_()

    def __getattr__(self, sct):
        raise error.SectionError(sct)

    def __iter__(self):
        return iter(self._sections)

    def __contains__(self, sct):
        return sct in self._sections

    def sections_(self):
        """Iterator over configuration section names.

        Yields:
            section names.
        """
        return iter(self)

    def options_(self):
        """Iterator over section and option names.

        This iterator is also implemented at the section level. The two loops
        produce the same output::

            for sct, opt in conf.options_():
                print(sct, opt)

            for sct in conf.sections_():
                for opt in conf[sct].options_():
                    print(sct, opt)

        Yields:
            tuples with subsection and options names.
        """
        for sct in self:
            for opt in self[sct]:
                yield sct, opt

    def opt_vals_(self):
        """Iterator over sections, option names, and option values.

        This iterator is also implemented at the section level. The two loops
        produce the same output::

            for sct, opt, val in conf.opt_vals_():
                print(sct, opt, val)

            for sct in conf.sections_():
                for opt, val in conf[sct].opt_vals_():
                    print(sct, opt, val)

        Yields:
            tuples with sections, option names, and option values.
        """
        for sct, opt in self.options_():
            yield sct, opt, self[sct][opt]

    def defaults_(self):
        """Iterator over sections, option names, and option metadata.

        This iterator is also implemented at the section level. The two loops
        produce the same output::

            for sct, opt, meta in conf.defaults_():
                print(sct, opt, meta.default)

            for sct in conf.sections_():
                for opt, meta in conf[sct].defaults_():
                    print(sct, opt, meta.default)

        Yields:
            tuples with sections, option names, and :class:`Conf` instances
            holding option metadata.
        """
        for sct, opt in self.options_():
            yield sct, opt, self[sct].def_[opt]

    def reset_(self):
        """Restore default values of all options."""
        for sct, opt, meta in self.defaults_():
            self[sct][opt] = meta.default

    def create_config_(self, index=0, update=False):
        """Create config file.

        Create config file in :attr:`config_files_[index]`.

        Parameters:
            index(int): index of config file.
            update (bool): if set to True and :attr:`config_files_` already
                exists, its content is read and all the options it sets are
                kept in the produced config file.
        """
        if not self.config_files_[index:]:
            return
        path = self.config_files_[index]
        if not path.parent.exists():
            path.parent.mkdir(parents=True)
        conf_dict = {}
        for section in self.sections_():
            conf_opts = [o for o, m in self[section].defaults_() if m.conf_arg]
            if not conf_opts:
                continue
            conf_dict[section] = {}
            for opt in conf_opts:
                conf_dict[section][opt] = (self[section][opt] if update else
                                           self[section].def_[opt].default)
        with path.open('w') as cfile:
            toml.dump(conf_dict, cfile)

    def update_(self, conf_dict, conf_arg=True):
        """Update values of configuration options with dict.

        Args:
            conf_dict (dict): dict of dict indexed with section and option
                names.
            conf_arg (bool): if True, only options that can be set in a config
                file are updated.
        """
        for section, secdict in conf_dict.items():
            self[section].update_(secdict, conf_arg)

    def read_config_(self, cfile):
        """Read a config file and set config values accordingly.

        Returns:
            dict: content of config file.
        """
        if not cfile.exists():
            return {}
        try:
            conf_dict = toml.load(str(cfile))
        except toml.TomlDecodeError:
            return None
        self.update_(conf_dict)
        return conf_dict

    def read_configs_(self):
        """Read config files and set config values accordingly.

        Returns:
            (dict, list, list): respectively content of files, list of
            missing/empty files and list of files for which a parsing error
            arised.
        """
        if not self.config_files_:
            return {}, [], []
        content = {section: {} for section in self}
        empty_files = []
        faulty_files = []
        for cfile in self.config_files_:
            conf_dict = self.read_config_(cfile)
            if conf_dict is None:
                faulty_files.append(cfile)
                continue
            elif not conf_dict:
                empty_files.append(cfile)
                continue
            for section, secdict in conf_dict.items():
                content[section].update(secdict)
        return content, empty_files, faulty_files


# -*- coding: utf-8 -*-
# Author: Douglas Creager <dcreager@dcreager.net>
# This file is placed into the public domain.

# Calculates the current version number.  If possible, this is the
# output of “git describe”, modified to conform to the versioning
# scheme that setuptools uses.  If “git describe” returns an error
# (most likely because we're in an unpacked copy of a release tarball,
# rather than in a git working copy), then we fall back on reading the
# contents of the RELEASE-VERSION file.
#
# To use this script, simply import it your setup.py file, and use the
# results of get_git_version() as your package version:
#
# from version import *
#
# setup(
#     version=get_git_version(),
#     .
#     .
#     .
# )
#
# This will automatically update the RELEASE-VERSION file, if
# necessary.  Note that the RELEASE-VERSION file should *not* be
# checked into git; please add it to your top-level .gitignore file.
#
# You'll probably want to distribute the RELEASE-VERSION file in your
# sdist tarballs; to do this, just create a MANIFEST.in file that
# contains the following line:
#
#   include RELEASE-VERSION

from __future__ import absolute_import
from __future__ import print_function
from yaclifw import __file__ as module_file
from subprocess import Popen, PIPE
from os import path, getcwd, chdir
from .framework import Command
import re

__all__ = ("get_git_version")

def _lookup_version(module_file):
    """
    For the given module file (usually found by:

        from package import __file__ as module_file

    in the caller, return the location of
    the current RELEASE-VERSION file and the file
    itself.
    """
    version_dir = path.abspath(path.dirname(module_file))
    version_file = path.join(version_dir, "RELEASE-VERSION")
    return version_dir, version_file

def call_git_describe(abbrev=4):
    try:
        p = Popen(['git', 'describe', '--match=[v0-9][.0-9]*',
                   '--abbrev=%d' % abbrev], stdout=PIPE, stderr=PIPE)
        p.stderr.close()
        line = p.stdout.readlines()[0]
        return line.strip().decode("utf-8")

    except Exception:
        return None

def read_release_version(module_file):
    try:
        version_dir, version_file = _lookup_version(module_file)
        with open(version_file, "r") as f:
            version = f.readlines()[0]
            return version.strip()
    except Exception:
        return None

def write_release_version(module_file, version):
    version_dir, version_file = _lookup_version(module_file)
    with open(version_file, "w") as f:
        f.write("%s\n" % version)

version_pattern = '^(v)?(?P<version>[0-9]+[\.][0-9]+[\.][0-9]+(\-.+)*)$'
version_pattern = re.compile(version_pattern)

def get_git_version(module_file, abbrev=4):
    # Read in the version that's currently in RELEASE-VERSION.
    release_version = read_release_version(module_file)

    # First try to get the current version using “git describe”.
    cwd = getcwd()
    version_dir, version_file = _lookup_version(module_file)
    git_version = None
    try:
        chdir(version_dir)
        git_version = call_git_describe(abbrev)
    finally:
        chdir(cwd)

    # Extract version number
    version = None
    if git_version:
        m = version_pattern.match(git_version)
        if m:
            version = m.group('version')

    # If that doesn't work, fall back on the value that's in
    # RELEASE-VERSION.

    if version is None:
        version = release_version

    # If we still don't have anything, that's an error.

    if version is None:
        import logging
        logger = logging.getLogger("yaclifw.version")
        logger.warn((
            "Cannot find the version number! Looking "
            "in %s while in %s"), version_dir, cwd)
        version = "UNKNOWN"

    # If the current version is different from what's in the
    # RELEASE-VERSION file, update the file to be current.

    if version != release_version:
        write_release_version(module_file, version)

    # Finally, return the current version.

    return version

class Version(Command):
    """Find which version of this library is being used"""

    NAME = "version"
    FILE = module_file

    def __init__(self, sub_parsers):
        super(Version, self).__init__(sub_parsers)
        # No token args

    def __call__(self, args):
        super(Version, self).__call__(args)

        try:
            # If this file has been downloaded in isolation,
            # then scc_version will not be present.
            version = get_git_version(self.FILE)
        except Exception:
            version = "unknown"
        print(version)