text:
import requests as _requests
from goldsberry.apiconvertor import *

class team_info:
    def __init__(self, teamid, season='2015',league='NBA', seasontype=1):
        self._url = "http://stats.nba.com/stats/teaminfocommon?"
        self._api_param = {'TeamID':teamid,
                            'LeagueID': nba_league(league),
                            'SeasonType':season_type(seasontype),
                            'Season': nba_season(season)
                            }
        self._pull = _requests.get(self._url, params=self._api_param)
    def info(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def season_ranks(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class roster:
    def __init__(self, teamid, season='2015',league='NBA'):
        self._url = "http://stats.nba.com/stats/commonteamroster?"
        self._api_param = {'TeamID':teamid,
                            'Season': nba_season(season),
                            'LeagueID': nba_league(league)
                            }
        self._pull = _requests.get(self._url, params=self._api_param)
    def players(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def coaches(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class history:
    def __init__(self, teamid):
        self._url = "".join(["http://stats.nba.com/feeds/teams/profile/",str(teamid),"_TeamProfile.js"])
        self._pull = _requests.get(self._url)
    def details(self):
        return self._pull.json()['TeamDetails'][0]['Details']
    def history(self):
        return self._pull.json()['TeamDetails'][1]['History']
    def social_sites(self):
        return self._pull.json()['TeamDetails'][2]['SocialSites']
    def championships(self):
        if self._pull.json()['TeamDetails'][3]['Awards'][0]['Championships'] == []:
            return ["None"]
        else: return self._pull.json()['TeamDetails'][3]['Awards'][0]['Championships']
    def conference_titles(self):
        if self._pull.json()['TeamDetails'][3]['Awards'][1]['ConferenceTitles'] == []:
            return ["None"]
        else: return self._pull.json()['TeamDetails'][3]['Awards'][1]['ConferenceTitles']
    def divisional_titles(self):
        if self._pull.json()['TeamDetails'][3]['Awards'][2]['DivitionalTitles'] == []:
            return ['None']
        else: return self._pull.json()['TeamDetails'][3]['Awards'][2]['DivitionalTitles']
    def hof_inductees(self):
        return self._pull.json()['TeamDetails'][4]['HallOfFameInductees']
    def retired_members(self):
        return self._pull.json()['TeamDetails'][5]['RetiredMembers']
class splits:
    def __init__(self, teamid, season='2015',league='NBA', datefrom='',
        dateto='', gamesegment=1, lastngames='0', location=1, measuretype=1,
        month='0', opponentteamid='0', outcome=1, paceadjust=1, permode=1,
        period='0', plusminus=1, seasonsegment=1, seasontype=1,
        vsconf=1, vsdiv=1, rank=1):
        self._url = "http://stats.nba.com/stats/teamdashboardbygeneralsplits?"
        self._api_param = {'TeamID':teamid,
                            'Season': nba_season(season),
                            'LeagueID': nba_league(league),
                            'DateFrom':valid_date(datefrom),
                            'DateTo':valid_date(dateto),
                            'GameSegment':game_segment(gamesegment),
                            'LastNGames':lastngames,
                            'Location':location(location),
                            'MeasureType': measure_type(measuretype),
                            'Month':month,
                            'OpponentTeamID':opponentteamid,
                            'Outcome':outcome(outcome),
                            'PaceAdjust':pace_adjust(paceadjust),
                            'PerMode':per_mode_large(permode),
                            'Period':period,
                            'PlusMinus':plus_minus(plusminus),
                            'Rank':rank(rank),
                            'SeasonSegment':season_segment(seasonsegment),
                            'SeasonType':season_type(seasontype),
                            'VsConference':vs_conference(vsconf),
                            'VsDivision':vs_division(vsdiv)
                            }
        self._pull = _requests.get(self._url, params=self._api_param)
    def overall(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def location(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def wins_losses(self):
        _headers = self._pull.json()['resultSets'][2]['headers']
        _values = self._pull.json()['resultSets'][2]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def month(self):
        _headers = self._pull.json()['resultSets'][3]['headers']
        _values = self._pull.json()['resultSets'][3]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def pre_post_allstar(self):
        _headers = self._pull.json()['resultSets'][4]['headers']
        _values = self._pull.json()['resultSets'][4]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def days_rest(self):
        _headers = self._pull.json()['resultSets'][5]['headers']
        _values = self._pull.json()['resultSets'][5]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class season_stats:
    def __init__(self, teamid, season='2015',league='NBA', datefrom='',
        dateto='', gamesegment=1, lastngames='0', location=1, measuretype=1,
        month='0', opponentteamid='0', outcome=1, paceadjust=1, permode=1,
        period='0', plusminus=1, seasonsegment=1, seasontype=1,
        vsconf=1, vsdiv=1, rank=1):
        self._url = "http://stats.nba.com/stats/teamplayerdashboard?"
        self._api_param = {'TeamID':teamid,
                            'Season': nba_season(season),
                            'LeagueID': nba_league(league),
                            'DateFrom': valid_date(datefrom),
                            'DateTo': valid_date(dateto),
                            'GameSegment': game_segment(gamesegment),
                            'LastNGames': lastngames,
                            'Location': location(location),
                            'MeasureType': measure_type(measuretype),
                            'Month': month,
                            'OpponentTeamID': opponentteamid,
                            'Outcome': outcome(outcome),
                            'PaceAdjust': pace_adjust(paceadjust),
                            'PerMode': per_mode_large(permode),
                            'Period': period,
                            'PlusMinus': plus_minus(plusminus),
                            'Rank': rank(rank),
                            'SeasonSegment': season_segment(seasonsegment),
                            'SeasonType': season_type(seasontype),
                            'VsConference': vs_conference(vsconf),
                            'VsDivision': vs_division(vsdiv)
                            }
        self._pull = _requests.get(self._url, params=self._api_param)
    def overall(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def player_totals(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class on_off_court:
    def __init__(self, teamid, season='2015',league='NBA', datefrom='',
        dateto='', gamesegment=1, lastngames='0', location=1, measuretype=1,
        month='0', opponentteamid='0', outcome=1, paceadjust=1, permode=1,
        period='0', plusminus=1, seasonsegment=1, seasontype=1,
        vsconf=1, vsdiv=1, rank='N'):
        self._url = "http://stats.nba.com/stats/teamplayeronoffdetails?"
        self._api_param = {'TeamID':teamid,
                            'Season': nba_season(season),
                            'LeagueID': nba_league(league),
                            'DateFrom': valid_date(datefrom),
                            'DateTo': valid_date(dateto),
                            'GameSegment':game_segment(gamesegment),
                            'LastNGames':lastngames,
                            'Location':location(location),
                            'MeasureType': measure_type(measuretype),
                            'Month':month,
                            'OpponentTeamID':opponentteamid,
                            'Outcome':outcome(outcome),
                            'PaceAdjust':pace_adjust(paceadjust),
                            'PerMode':per_mode_large(permode),
                            'Period':period,
                            'PlusMinus':plus_minus(plusminus),
                            'Rank':rank(rank),
                            'SeasonSegment':season_segment(seasonsegment),
                            'SeasonType':season_type(seasontype),
                            'VsConference':vs_conference(vsconf),
                            'VsDivision':vs_division(vsdiv)
                            }
        self._pull = _requests.get(self._url, params=self._api_param)
        self._url2 = "http://stats.nba.com/stats/teamdashboardbyshootingsplits?"
        self._pull2 = _requests.get(self._url2, params=self._api_param)

    def overall(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def on_court(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def off_court(self):
        _headers = self._pull.json()['resultSets'][2]['headers']
        _values = self._pull.json()['resultSets'][2]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def overall_summary(self):
        _headers = self._pull2.json()['resultSets'][0]['headers']
        _values = self._pull2.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def on_court_summary(self):
        _headers = self._pull2.json()['resultSets'][1]['headers']
        _values = self._pull2.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def off_court_summary(self):
        _headers = self._pull2.json()['resultSets'][2]['headers']
        _values = self._pull2.json()['resultSets'][2]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class on_off_court:
    def __init__(self, teamid, permode=1,league='NBA', seasontype=1):
        self._url = "http://stats.nba.com/stats/teamyearbyyearstats?"
        self._api_param = {'TeamID':teamid,
                            'PerMode': per_mode_mini(permode),
                            'LeagueID': nba_league(league),
                            'SeasonType':season_type(seasontype)
                            }
        self._pull = _requests.get(self._url, params=self._api_param)
    def team_stats(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class game_logs:
    def __init__(self, teamid, season='2015',seasontype=1):
        self._url = "http://stats.nba.com/stats/teamgamelog?"
        self._api_param = {'TeamID':teamid,
                            'SeasonType':season_type(seasontype),
                            'Season': nba_season(season)
                            }
        self._pull = _requests.get(self._url, params=self._api_param)
    def logs(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class lineups:
    def __init__(self, teamid, groupsize=5, measure=1, gameid='',season=2015, league="NBA", datefrom='',
        dateto='', month=0, opponentteamid=0, paceadjust=1, permode=1, period=0, plusminus=1, rank=1,
        seasonsegment=1, seasontype=1, vsconf=1, vsdiv=1, lastngames=0, location=1, outcome=1):
        self._url = "http://stats.nba.com/stats/teamdashlineups?"
        self._api_param = {
                'DateFrom':valid_date(datefrom),
                'DateTo':valid_date(dateto),
                'GameID':gameid,
                'GameSegment':game_segment(gamesegment),
                'GroupQuantity':groupsize,
                'LastNGames':lastngames,
                'LeagueID':nba_league(league),
                'Location':location(location),
                'MeasureType':measure_type(measure),
                'Month':month,
                'OpponentTeamID':opponentteamid,
                'Outcome':outcome(outcome),
                'PaceAdjust':pace_adjust(paceadjust),
                'PerMode':per_mode_large(permode),
                'Period':period,
                'PlusMinus':plus_minus(plusminus),
                'Rank':rank(rank),
                'Season':nba_season(season),
                'SeasonSegment':season_segment(seasonsegment),
                'SeasonType':season_type(seasontype),
                'TeamID':teamid,
                'VsConference':vs_conference(vsconf),
                'VsDivision':vs_division(vsdiv)
        }
        self._pull = _requests.get(self._url, params=self._api_param)
    def overall(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def lineups(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class shooting_splits:
    def __init__(self, teamid, measure=1, season=2015, league="NBA", datefrom='',
        dateto='', month=0, opponentteamid=0, paceadjust=1, permode=1, period=0, plusminus=1, rank=1,
        seasonsegment=1, seasontype=1, vsconf=1, vsdiv=1, lastngames=0, location=1, outcome=1):
        self._url = "http://stats.nba.com/stats/teamdashboardbyshootingsplits?"
        self._api_param = {
                'DateFrom':valid_date(datefrom),
                'DateTo':valid_date(dateto),
                'GameSegment':game_segment(gamesegment),
                'LastNGames':lastngames,
                'LeagueID':nba_league(league),
                'Location':location(location),
                'MeasureType':measure_type(measure),
                'Month':month,
                'OpponentTeamID':opponentteamid,
                'Outcome':outcome(outcome),
                'PaceAdjust':pace_adjust(paceadjust),
                'PerMode':per_mode_large(permode),
                'Period':period,
                'PlusMinus':plus_minus(plusminus),
                'Rank':rank(rank),
                'Season':nba_season(season),
                'SeasonSegment':season_segment(seasonsegment),
                'SeasonType':season_type(seasontype),
                'TeamID':teamid,
                'VsConference':vs_conference(vsconf),
                'VsDivision':vs_division(vsdiv)
        }
    def overall(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def shot_5ft(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def shot_8ft(self):
        _headers = self._pull.json()['resultSets'][2]['headers']
        _values = self._pull.json()['resultSets'][2]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def shot_area(self):
        _headers = self._pull.json()['resultSets'][3]['headers']
        _values = self._pull.json()['resultSets'][3]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def assisted_shot(self):
        _headers = self._pull.json()['resultSets'][4]['headers']
        _values = self._pull.json()['resultSets'][4]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def shot_type(self):
        _headers = self._pull.json()['resultSets'][5]['headers']
        _values = self._pull.json()['resultSets'][5]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def assisted_by(self):
        _headers = self._pull.json()['resultSets'][6]['headers']
        _values = self._pull.json()['resultSets'][6]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class passing_dashboard:
    def __init__(self,teamid,league='NBA',season='2015', seasontype=1,outcome=1,location=1,month=0,
                seasonsegment=1,datefrom='',dateto='',opponentteamid=0,vsconf=1,vsdiv=1,gamesegment=1,
                period=0,lastngames=0, permode=1):
        self._url = "http://stats.nba.com/stats/teamdashptpass?"
        self._api_param = {
                        'TeamID' : teamid,
                        'LeagueID': nba_league(league),
                        'Season' :  nba_season(season),
                        'SeasonType' : season_type(seasontype),
                        'Outcome' : outcome(outcome),
                        'Location' : location(location),
                        'Month' : month,
                        'SeasonSegment' : season_segment(seasonsegment),
                        'DateFrom' :  valid_date(datefrom),
                        'DateTo' : valid_date(dateto),
                        'OpponentTeamID' : opponentteamid,
                        'VsConference' : vs_conference(vsconf),
                        'VsDivision' : vs_division(vsdiv),
                        'GameSegment' : game_segment(gamesegment),
                        'Period' :  period,
                        'LastNGames' : lastngames,
                        'PerMode' : per_mode_mini(permode)
                        }
        self._pull = _requests.get(self._url, params=self._api_param)
    def PassesMade(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def PassesReceived(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class rebound_dashboard:
    def __init__(self,teamid,league='NBA',season='2015', seasontype=1,outcome=1,location=1,month=0,
                seasonsegment=1,datefrom='',dateto='',opponentteamid=0,vsconf=1,vsdiv=1,gamesegment=1,
                period=0,lastngames=0, permode=1):
        self._url = "http://stats.nba.com/stats/teamdashptreb?"
        self._api_param = {
                        'TeamID' : teamid,
                        'LeagueID': nba_league(league),
                        'Season' :  nba_season(season),
                        'SeasonType' : season_type(seasontype),
                        'Outcome' : outcome(outcome),
                        'Location' : location(location),
                        'Month' : month,
                        'SeasonSegment' : season_segment(seasonsegment),
                        'DateFrom' :  valid_date(datefrom),
                        'DateTo' : valid_date(dateto),
                        'OpponentTeamID' : opponentteamid,
                        'VsConference' : vs_conference(vsconf),
                        'VsDivision' : vs_division(vsdiv),
                        'GameSegment' : game_segment(gamesegment),
                        'Period' :  period,
                        'LastNGames' : lastngames,
                        'PerMode' : per_mode_mini(permode)
                        }
        self._pull = _requests.get(self._url, params=self._api_param)
    def overall(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def shot_type(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def contesting_rebounders(self):
        _headers = self._pull.json()['resultSets'][2]['headers']
        _values = self._pull.json()['resultSets'][2]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def shot_distance(self):
        _headers = self._pull.json()['resultSets'][3]['headers']
        _values = self._pull.json()['resultSets'][3]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def rebound_distance(self):
        _headers = self._pull.json()['resultSets'][4]['headers']
        _values = self._pull.json()['resultSets'][4]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
class shot_dashboard:
    def __init__(self,teamid,league='NBA',season='2015', seasontype=1,outcome=1,location=1,month=0,
        seasonsegment=1,datefrom='',dateto='',opponentteamid=0,vsconf=1,vsdiv=1,gamesegment=1,period=0,
        lastngames=0, permode=1):
        self._url = "http://stats.nba.com/stats/teamdashptshots?"
        self._api_param = {
                        'TeamID' : teamid,
                        'LeagueID': nba_league(league),
                        'Season' :  nba_season(season),
                        'SeasonType' : season_type(seasontype),
                        'Outcome' : outcome(outcome),
                        'Location' : location(location),
                        'Month' : month,
                        'SeasonSegment' : season_segment(seasonsegment),
                        'DateFrom' :  valid_date(datefrom),
                        'DateTo' : valid_date(dateto),
                        'OpponentTeamID' : opponentteamid,
                        'VsConference' : vs_conference(vsconf),
                        'VsDivision' : vs_division(vsdiv),
                        'GameSegment' : game_segment(gamesegment),
                        'Period' : period,
                        'LastNGames' : lastngames,
                        'PerMode' : per_mode_mini(permode)
                        }
        self._pull = _requests.get(self._url, params=self._api_param)
    def general(self):
        _headers = self._pull.json()['resultSets'][0]['headers']
        _values = self._pull.json()['resultSets'][0]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def shot_clock(self):
        _headers = self._pull.json()['resultSets'][1]['headers']
        _values = self._pull.json()['resultSets'][1]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def dribble(self):
        _headers = self._pull.json()['resultSets'][2]['headers']
        _values = self._pull.json()['resultSets'][2]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def closest_defender(self):
        _headers = self._pull.json()['resultSets'][3]['headers']
        _values = self._pull.json()['resultSets'][3]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def closest_defender_10ft(self):
        _headers = self._pull.json()['resultSets'][4]['headers']
        _values = self._pull.json()['resultSets'][4]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]
    def touch_time(self):
        _headers = self._pull.json()['resultSets'][5]['headers']
        _values = self._pull.json()['resultSets'][5]['rowSet']
        return [dict(zip(_headers, value)) for value in _values]

__all__ = ['team_info', 'roster', 'history', 'splits','season_stats', 'on_off_court',
           'on_off_court', 'game_logs', 'lineups', 'shooting_splits', 'passing_dashboard',
           'passing_dashboard', 'shot_dashboard']


text:
//  Copyright (c) 2018-2019
//  Cem Bassoy
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
//  The authors gratefully acknowledge the support of
//  Fraunhofer and Google in producing this work
//  which started as a Google Summer of Code project.
//

/// \file tensor.hpp Definition for the tensor template class

#ifndef BOOST_UBLAS_TENSOR_IMPL_HPP
#define BOOST_UBLAS_TENSOR_IMPL_HPP

#include <boost/config.hpp>

#include <initializer_list>

#include "algorithms.hpp"
#include "expression.hpp"
#include "expression_evaluation.hpp"
#include "extents.hpp"
#include "strides.hpp"
#include "index.hpp"

namespace boost { namespace numeric { namespace ublas {

template<class T, class F, class A>
class tensor;

template<class T, class F, class A>
class matrix;

template<class T, class A>
class vector;

///** \brief Base class for Tensor container models
// *
// * it does not model the Tensor concept but all derived types should.
// * The class defines a common base type and some common interface for all
// * statically derived Tensor classes
// * We implement the casts to the statically derived type.
// */
//template<class C>
//class tensor_container:
//		public detail::tensor_expression<C>
//{
//public:
//	static const unsigned complexity = 0;
//	typedef C container_type;
//	typedef tensor_tag type_category;

//	BOOST_UBLAS_INLINE
//	const container_type &operator () () const {
//			return *static_cast<const container_type *> (this);
//	}
//	BOOST_UBLAS_INLINE
//	container_type &operator () () {
//			return *static_cast<container_type *> (this);
//	}
//};

/** @brief A dense tensor of values of type \c T.
		*
		* For a \f$n\f$-dimensional tensor \f$v\f$ and \f$0\leq i < n\f$ every element \f$v_i\f$ is mapped
		* to the \f$i\f$-th element of the container. A storage type \c A can be specified which defaults to \c unbounded_array.
		* Elements are constructed by \c A, which need not initialise their value.
		*
		* @tparam T type of the objects stored in the tensor (like int, double, complex,...)
		* @tparam A The type of the storage array of the tensor. Default is \c unbounded_array<T>. \c <bounded_array<T> and \c std::vector<T> can also be used
		*/
template<class T, class F = first_order, class A = std::vector<T,std::allocator<T>> >
class tensor:
		public detail::tensor_expression<tensor<T, F, A>,tensor<T, F, A>>
{

	static_assert( std::is_same<F,first_order>::value ||
								 std::is_same<F,last_order >::value, "boost::numeric::tensor template class only supports first- or last-order storage formats.");

	using self_type  = tensor<T, F, A>;
public:

	template<class derived_type>
	using tensor_expression_type = detail::tensor_expression<self_type,derived_type>;

	template<class derived_type>
	using matrix_expression_type = matrix_expression<derived_type>;

	template<class derived_type>
	using vector_expression_type = vector_expression<derived_type>;

	using super_type = tensor_expression_type<self_type>;

//	static_assert(std::is_same_v<tensor_expression_type<self_type>, detail::tensor_expression<tensor<T,F,A>,tensor<T,F,A>>>, "tensor_expression_type<self_type>");

	using array_type  = A;
	using layout_type = F;

	using size_type       = typename array_type::size_type;
	using difference_type = typename array_type::difference_type;
	using value_type      = typename array_type::value_type;

	using reference       = typename array_type::reference;
	using const_reference = typename array_type::const_reference;

	using pointer         = typename array_type::pointer;
	using const_pointer   = typename array_type::const_pointer;

	using iterator        = typename array_type::iterator;
	using const_iterator  = typename array_type::const_iterator;

	using reverse_iterator        = typename array_type::reverse_iterator;
	using const_reverse_iterator  = typename array_type::const_reverse_iterator;

	using tensor_temporary_type = self_type;
	using storage_category = dense_tag;

	using strides_type = basic_strides<std::size_t,layout_type>;
	using extents_type = shape;

	using matrix_type     = matrix<value_type,layout_type,array_type>;
	using vector_type     = vector<value_type,array_type>;

	/** @brief Constructs a tensor.
	 *
	 * @note the tensor is empty.
	 * @note the tensor needs to reshaped for further use.
	 *
	 */
	BOOST_UBLAS_INLINE
	constexpr tensor ()
		: tensor_expression_type<self_type>() // container_type
		, extents_()
		, strides_()
		, data_()
	{
	}

	/** @brief Constructs a tensor with an initializer list
	 *
	 * By default, its elements are initialized to 0.
	 *
	 * @code tensor<float> A{4,2,3}; @endcode
	 *
	 * @param l initializer list for setting the dimension extents of the tensor
	 */
	explicit BOOST_UBLAS_INLINE
	tensor (std::initializer_list<size_type> l)
		: tensor_expression_type<self_type>()
		, extents_ (std::move(l))
		, strides_ (extents_)
		, data_    (extents_.product())
	{
	}

	/** @brief Constructs a tensor with a \c shape
	 *
	 * By default, its elements are initialized to 0.
	 *
	 * @code tensor<float> A{extents{4,2,3}}; @endcode
	 *
	 * @param s initial tensor dimension extents
	 */
	explicit BOOST_UBLAS_INLINE
	tensor (extents_type const& s)
		: tensor_expression_type<self_type>() //tensor_container<self_type>()
		, extents_ (s)
		, strides_ (extents_)
		, data_    (extents_.product())
	{}

	/** @brief Constructs a tensor with a \c shape and initiates it with one-dimensional data
	 *
	 * @code tensor<float> A{extents{4,2,3}, array }; @endcode
	 *
	 *
	 *  @param s initial tensor dimension extents
	 *  @param a container of \c array_type that is copied according to the storage layout
	 */
	BOOST_UBLAS_INLINE
	tensor (extents_type const& s, const array_type &a)
		: tensor_expression_type<self_type>() //tensor_container<self_type>()
		, extents_ (s)
		, strides_ (extents_)
		, data_    (a)
	{
		if(this->extents_.product() != this->data_.size())
			throw std::runtime_error("Error in boost::numeric::ublas::tensor: size of provided data and specified extents do not match.");
	}

	/** @brief Constructs a tensor using a shape tuple and initiates it with a value.
	 *
	 *  @code tensor<float> A{extents{4,2,3}, 1 }; @endcode
	 *
	 *  @param e initial tensor dimension extents
	 *  @param i initial value of all elements of type \c value_type
	 */
	BOOST_UBLAS_INLINE
	tensor (extents_type const& e, const value_type &i)
		: tensor_expression_type<self_type>() //tensor_container<self_type> ()
		, extents_ (e)
		, strides_ (extents_)
		, data_    (extents_.product(), i)
	{}

	/** @brief Constructs a tensor from another tensor
	 *
	 *  @param v tensor to be copied.
	 */
	BOOST_UBLAS_INLINE
	tensor (const tensor &v)
		: tensor_expression_type<self_type>()
		, extents_ (v.extents_)
		, strides_ (v.strides_)
		, data_    (v.data_   )
	{}

	/** @brief Constructs a tensor from another tensor
	 *
	 *  @param v tensor to be moved.
	 */
	BOOST_UBLAS_INLINE
	tensor (tensor &&v)
		: tensor_expression_type<self_type>() //tensor_container<self_type> ()
		, extents_ (std::move(v.extents_))
		, strides_ (std::move(v.strides_))
		, data_    (std::move(v.data_   ))
	{}

	/** @brief Constructs a tensor with a matrix
	 *
	 * \note Initially the tensor will be two-dimensional.
	 *
	 *  @param v matrix to be copied.
	 */
	BOOST_UBLAS_INLINE
	tensor (const matrix_type &v)
		: tensor_expression_type<self_type>()
		, extents_ ()
		, strides_ ()
		, data_    (v.data())
	{
		if(!data_.empty()){
			extents_ = extents_type{v.size1(),v.size2()};
			strides_ = strides_type(extents_);
		}
	}

	/** @brief Constructs a tensor with a matrix
	 *
	 * \note Initially the tensor will be two-dimensional.
	 *
	 *  @param v matrix to be moved.
	 */
	BOOST_UBLAS_INLINE
	tensor (matrix_type &&v)
		: tensor_expression_type<self_type>()
		, extents_ {}
		, strides_ {}
		, data_    {}
	{
		if(v.size1()*v.size2() != 0){
			extents_ = extents_type{v.size1(),v.size2()};
			strides_ = strides_type(extents_);
			data_    = std::move(v.data());
		}
	}

	/** @brief Constructs a tensor using a \c vector
	 *
	 * @note It is assumed that vector is column vector
	 * @note Initially the tensor will be one-dimensional.
	 *
	 *  @param v vector to be copied.
	 */
	BOOST_UBLAS_INLINE
	tensor (const vector_type &v)
		: tensor_expression_type<self_type>()
		, extents_ ()
		, strides_ ()
		, data_    (v.data())
	{
		if(!data_.empty()){
			extents_ = extents_type{data_.size(),1};
			strides_ = strides_type(extents_);
		}
	}

	/** @brief Constructs a tensor using a \c vector
	 *
	 *  @param v vector to be moved.
	 */
	BOOST_UBLAS_INLINE
	tensor (vector_type &&v)
		: tensor_expression_type<self_type>()
		, extents_ {}
		, strides_ {}
		, data_    {}
	{
		if(v.size() != 0){
			extents_ = extents_type{v.size(),1};
			strides_ = strides_type(extents_);
			data_    = std::move(v.data());
		}
	}

	/** @brief Constructs a tensor with another tensor with a different layout
	 *
	 * @param other tensor with a different layout to be copied.
	 */
	BOOST_UBLAS_INLINE
	template<class other_layout>
	tensor (const tensor<value_type, other_layout> &other)
		: tensor_expression_type<self_type> ()
		, extents_ (other.extents())
		, strides_ (other.extents())
		, data_    (other.extents().product())
	{
		copy(this->rank(), this->extents().data(),
				 this->data(), this->strides().data(),
				 other.data(), other.strides().data());
	}

	/** @brief Constructs a tensor with an tensor expression
	 *
	 * @code tensor<float> A = B + 3 * C; @endcode
	 *
	 * @note type must be specified of tensor must be specified.
	 * @note dimension extents are extracted from tensors within the expression.
	 *
	 * @param expr tensor expression
	 */
	BOOST_UBLAS_INLINE
	template<class derived_type>
	tensor (const tensor_expression_type<derived_type> &expr)
		: tensor_expression_type<self_type> ()
		, extents_ ( detail::retrieve_extents(expr) )
		, strides_ ( extents_ )
		, data_    ( extents_.product() )
	{
		static_assert( detail::has_tensor_types<self_type, tensor_expression_type<derived_type>>::value,
									 "Error in boost::numeric::ublas::tensor: expression does not contain a tensor. cannot retrieve shape.");
		detail::eval( *this, expr );
	}

	/** @brief Constructs a tensor with a matrix expression
	 *
	 * @code tensor<float> A = B + 3 * C; @endcode
	 *
	 * @note matrix expression is evaluated and pushed into a temporary matrix before assignment.
	 * @note extents are automatically extracted from the temporary matrix
	 *
	 * @param expr matrix expression
	 */
	BOOST_UBLAS_INLINE
	template<class derived_type>
	tensor (const matrix_expression_type<derived_type> &expr)
		: tensor(  matrix_type ( expr )  )
	{
	}

	/** @brief Constructs a tensor with a vector expression
	 *
	 * @code tensor<float> A = b + 3 * b; @endcode
	 *
	 * @note matrix expression is evaluated and pushed into a temporary matrix before assignment.
	 * @note extents are automatically extracted from the temporary matrix
	 *
	 * @param expr vector expression
	 */
	BOOST_UBLAS_INLINE
	template<class derived_type>
	tensor (const vector_expression_type<derived_type> &expr)
		: tensor(  vector_type ( expr )  )
	{
	}

	/** @brief Evaluates the tensor_expression and assigns the results to the tensor
	 *
	 * @code A = B + C * 2;  @endcode
	 *
	 * @note rank and dimension extents of the tensors in the expressions must conform with this tensor.
	 *
	 * @param expr expression that is evaluated.
	 */
	BOOST_UBLAS_INLINE
	template<class derived_type>
	tensor &operator = (const tensor_expression_type<derived_type> &expr)
	{
		detail::eval(*this, expr);
		return *this;
	}

	tensor& operator=(tensor other)
	{
		swap (*this, other);
		return *this;
	}

	tensor& operator=(const_reference v)
	{
		std::fill(this->begin(), this->end(), v);
		return *this;
	}

	/** @brief Returns true if the tensor is empty (\c size==0) */
	BOOST_UBLAS_INLINE
	bool empty () const {
		return this->data_.empty();
	}

	/** @brief Returns the size of the tensor */
	BOOST_UBLAS_INLINE
	size_type size () const {
		return this->data_.size ();
	}

	/** @brief Returns the size of the tensor */
	BOOST_UBLAS_INLINE
	size_type size (size_type r) const {
		return this->extents_.at(r);
	}

	/** @brief Returns the number of dimensions/modes of the tensor */
	BOOST_UBLAS_INLINE
	size_type rank () const {
		return this->extents_.size();
	}

	/** @brief Returns the number of dimensions/modes of the tensor */
	BOOST_UBLAS_INLINE
	size_type order () const {
		return this->extents_.size();
	}

	/** @brief Returns the strides of the tensor */
	BOOST_UBLAS_INLINE
	strides_type const& strides () const {
		return this->strides_;
	}

	/** @brief Returns the extents of the tensor */
	BOOST_UBLAS_INLINE
	extents_type const& extents () const {
		return this->extents_;
	}

	/** @brief Returns a \c const reference to the container. */
	BOOST_UBLAS_INLINE
	const_pointer data () const {
		return this->data_.data();
	}

	/** @brief Returns a \c const reference to the container. */
	BOOST_UBLAS_INLINE
	pointer data () {
		return this->data_.data();
	}

	/** @brief Element access using a single index.
	 *
	 *  @code auto a = A[i]; @endcode
	 *
	 *  @param i zero-based index where 0 <= i < this->size()
	 */
	BOOST_UBLAS_INLINE
	const_reference operator [] (size_type i) const {
		return this->data_[i];
	}

	/** @brief Element access using a single index.
	 *
	 *
	 *  @code A[i] = a; @endcode
	 *
	 *  @param i zero-based index where 0 <= i < this->size()
	 */
	BOOST_UBLAS_INLINE
	reference operator [] (size_type i)
	{
		return this->data_[i];
	}

	/** @brief Element access using a multi-index or single-index.
	 *
	 *
	 *  @code auto a = A.at(i,j,k); @endcode or
	 *  @code auto a = A.at(i);     @endcode
	 *
	 *  @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0)
	 *  @param is zero-based indices where 0 <= is[r] < this->size(r) where  0 < r < this->rank()
	 */
	template<class ... size_types>
	BOOST_UBLAS_INLINE
	const_reference at (size_type i, size_types ... is) const {
		if constexpr (sizeof...(is) == 0)
			return this->data_[i];
		else
			return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward<size_types>(is)...)];
	}

	/** @brief Element access using a multi-index or single-index.
	 *
	 *
	 *  @code A.at(i,j,k) = a; @endcode or
	 *  @code A.at(i) = a;     @endcode
	 *
	 *  @param i zero-based index where 0 <= i < this->size() if sizeof...(is) == 0, else 0<= i < this->size(0)
	 *  @param is zero-based indices where 0 <= is[r] < this->size(r) where  0 < r < this->rank()
	 */
	BOOST_UBLAS_INLINE
	template<class ... size_types>
	reference at (size_type i, size_types ... is) {
		if constexpr (sizeof...(is) == 0)
			return this->data_[i];
		else
			return this->data_[detail::access<0ul>(size_type(0),this->strides_,i,std::forward<size_types>(is)...)];
	}

	/** @brief Element access using a single index.
	 *
	 *
	 *  @code A(i) = a; @endcode
	 *
	 *  @param i zero-based index where 0 <= i < this->size()
	 */
	BOOST_UBLAS_INLINE
	const_reference operator()(size_type i) const {
		return this->data_[i];
	}

	/** @brief Element access using a single index.
	 *
	 *  @code A(i) = a; @endcode
	 *
	 *  @param i zero-based index where 0 <= i < this->size()
	 */
	BOOST_UBLAS_INLINE
	reference operator()(size_type i){
		return this->data_[i];
	}

	/** @brief Generates a tensor index for tensor contraction
	 *
	 *
	 *  @code auto Ai = A(_i,_j,k); @endcode
	 *
	 *  @param i placeholder
	 *  @param is zero-based indices where 0 <= is[r] < this->size(r) where  0 < r < this->rank()
	 */
	BOOST_UBLAS_INLINE
	template<std::size_t I, class ... index_types>
	decltype(auto) operator() (index::index_type<I> p, index_types ... ps) const
	{
		constexpr auto N = sizeof...(ps)+1;
		if( N != this->rank() )
			throw std::runtime_error("Error in boost::numeric::ublas::operator(): size of provided index_types does not match with the rank.");

		return std::make_pair( std::cref(*this),  std::make_tuple( p, std::forward<index_types>(ps)... ) );
	}

	/** @brief Reshapes the tensor
	 *
	 *
	 * (1) @code A.reshape(extents{m,n,o});     @endcode or
	 * (2) @code A.reshape(extents{m,n,o},4);   @endcode
	 *
	 * If the size of this smaller than the specified extents than
	 * default constructed (1) or specified (2) value is appended.
	 *
	 * @note rank of the tensor might also change.
	 *
	 * @param e extents with which the tensor is reshaped.
	 * @param v value which is appended if the tensor is enlarged.
	 */
	BOOST_UBLAS_INLINE
	void reshape (extents_type const& e, value_type v = value_type{})
	{
		this->extents_ = e;
		this->strides_ = strides_type(this->extents_);

		if(e.product() != this->size())
			this->data_.resize (this->extents_.product(), v);
	}

	friend void swap(tensor& lhs, tensor& rhs) {
		std::swap(lhs.data_   , rhs.data_   );
		std::swap(lhs.extents_, rhs.extents_);
		std::swap(lhs.strides_, rhs.strides_);
	}

	/// \brief return an iterator on the first element of the tensor
	BOOST_UBLAS_INLINE
	const_iterator begin () const {
		return data_.begin ();
	}

	/// \brief return an iterator on the first element of the tensor
	BOOST_UBLAS_INLINE
	const_iterator cbegin () const {
		return data_.cbegin ();
	}

	/// \brief return an iterator after the last element of the tensor
	BOOST_UBLAS_INLINE
	const_iterator end () const {
		return data_.end();
	}

	/// \brief return an iterator after the last element of the tensor
	BOOST_UBLAS_INLINE
	const_iterator cend () const {
		return data_.cend ();
	}

	/// \brief Return an iterator on the first element of the tensor
	BOOST_UBLAS_INLINE
	iterator begin () {
		return data_.begin();
	}

	/// \brief Return an iterator at the end of the tensor
	BOOST_UBLAS_INLINE
	iterator end () {
		return data_.end();
	}

	/// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor)
	BOOST_UBLAS_INLINE
	const_reverse_iterator rbegin () const {
		return data_.rbegin();
	}

	/// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor)
	BOOST_UBLAS_INLINE
	const_reverse_iterator crbegin () const {
		return data_.crbegin();
	}

	/// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor)
	BOOST_UBLAS_INLINE
	const_reverse_iterator rend () const {
		return data_.rend();
	}

	/// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor)
	BOOST_UBLAS_INLINE
	const_reverse_iterator crend () const {
		return data_.crend();
	}

	/// \brief Return a const reverse iterator before the first element of the reversed tensor (i.e. end() of normal tensor)
	BOOST_UBLAS_INLINE
	reverse_iterator rbegin () {
		return data_.rbegin();
	}

	/// \brief Return a const reverse iterator on the end of the reverse tensor (i.e. first element of the normal tensor)
	BOOST_UBLAS_INLINE
	reverse_iterator rend () {
		return data_.rend();
	}

#if 0
	// -------------
	// Serialization
	// -------------

	/// Serialize a tensor into and archive as defined in Boost
	/// \param ar Archive object. Can be a flat file, an XML file or any other stream
	/// \param file_version Optional file version (not yet used)
	template<class Archive>
	void serialize(Archive & ar, const unsigned int /* file_version */){
		ar & serialization::make_nvp("data",data_);
	}
#endif

private:

	extents_type extents_;
	strides_type strides_;
	array_type data_;
};

}}} // namespaces

#endif

redpajama_set_name: RedPajamaGithub


text:
// Copyright 2017 The Ray Authors.
//
// 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.

#include "ray/util/logging.h"

#include <cstdlib>
#ifdef _WIN32
#include <process.h>
#else
#include <execinfo.h>
#endif
#include <signal.h>
#ifndef _WIN32
#include <unistd.h>
#endif

#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>

#include "absl/debugging/failure_signal_handler.h"
#include "absl/debugging/stacktrace.h"
#include "absl/debugging/symbolize.h"
#include "ray/util/event_label.h"
#include "ray/util/filesystem.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"

namespace ray {

RayLogLevel RayLog::severity_threshold_ = RayLogLevel::INFO;
std::string RayLog::app_name_ = "";
std::string RayLog::log_dir_ = "";
// Format pattern is 2020-08-21 17:00:00,000 I 100 1001 msg.
// %L is loglevel, %P is process id, %t for thread id.
std::string RayLog::log_format_pattern_ = "[%Y-%m-%d %H:%M:%S,%e %L %P %t] %v";
std::string RayLog::logger_name_ = "ray_log_sink";
long RayLog::log_rotation_max_size_ = 1 << 29;
long RayLog::log_rotation_file_num_ = 10;
bool RayLog::is_failure_signal_handler_installed_ = false;
std::atomic<bool> RayLog::initialized_ = false;

std::ostream &operator<<(std::ostream &os, const StackTrace &stack_trace) {
  static constexpr int MAX_NUM_FRAMES = 64;
  char buf[16 * 1024];
  void *frames[MAX_NUM_FRAMES];

#ifndef _WIN32
  const int num_frames = backtrace(frames, MAX_NUM_FRAMES);
  char **frame_symbols = backtrace_symbols(frames, num_frames);
  for (int i = 0; i < num_frames; ++i) {
    os << frame_symbols[i];

    if (absl::Symbolize(frames[i], buf, sizeof(buf))) {
      os << " " << buf;
    }

    os << "\n";
  }
  free(frame_symbols);
#else
  const int num_frames = absl::GetStackTrace(frames, MAX_NUM_FRAMES, 0);
  for (int i = 0; i < num_frames; ++i) {
    if (absl::Symbolize(frames[i], buf, sizeof(buf))) {
      os << buf;
    } else {
      os << "unknown";
    }
    os << "\n";
  }
#endif

  return os;
}

void TerminateHandler() {
  // Print the exception info, if any.
  if (auto e_ptr = std::current_exception()) {
    try {
      std::rethrow_exception(e_ptr);
    } catch (std::exception &e) {
      RAY_LOG(ERROR) << "Unhandled exception: " << typeid(e).name()
                     << ". what(): " << e.what();
    } catch (...) {
      RAY_LOG(ERROR) << "Unhandled unknown exception.";
    }
  }

  RAY_LOG(ERROR) << "Stack trace: \n " << ray::StackTrace();

  std::abort();
}

inline const char *ConstBasename(const char *filepath) {
  const char *base = strrchr(filepath, '/');
#ifdef OS_WINDOWS  // Look for either path separator in Windows
  if (!base) base = strrchr(filepath, '\\');
#endif
  return base ? (base + 1) : filepath;
}

/// A logger that prints logs to stderr.
/// This is the default logger if logging is not initialized.
/// NOTE(lingxuan.zlx): Default stderr logger must be singleton and global
/// variable so core worker process can invoke `RAY_LOG` in its whole lifecyle.
class DefaultStdErrLogger final {
 public:
  std::shared_ptr<spdlog::logger> GetDefaultLogger() { return default_stderr_logger_; }

  static DefaultStdErrLogger &Instance() {
    static DefaultStdErrLogger instance;
    return instance;
  }

 private:
  DefaultStdErrLogger() {
    default_stderr_logger_ = spdlog::stderr_color_mt("stderr");
    default_stderr_logger_->set_pattern(RayLog::GetLogFormatPattern());
  }
  ~DefaultStdErrLogger() = default;
  DefaultStdErrLogger(DefaultStdErrLogger const &) = delete;
  DefaultStdErrLogger(DefaultStdErrLogger &&) = delete;
  std::shared_ptr<spdlog::logger> default_stderr_logger_;
};

class SpdLogMessage final {
 public:
  explicit SpdLogMessage(const char *file,
                         int line,
                         int loglevel,
                         std::shared_ptr<std::ostringstream> expose_osstream)
      : loglevel_(loglevel), expose_osstream_(expose_osstream) {
    stream() << ConstBasename(file) << ":" << line << ": ";
  }

  inline void Flush() {
    auto logger = spdlog::get(RayLog::GetLoggerName());
    if (!logger) {
      logger = DefaultStdErrLogger::Instance().GetDefaultLogger();
    }

    if (loglevel_ == static_cast<int>(spdlog::level::critical)) {
      stream() << "\n*** StackTrace Information ***\n" << ray::StackTrace();
    }
    if (expose_osstream_) {
      *expose_osstream_ << "\n*** StackTrace Information ***\n" << ray::StackTrace();
    }
    // NOTE(lingxuan.zlx): See more fmt by visiting https://github.com/fmtlib/fmt.
    logger->log(
        static_cast<spdlog::level::level_enum>(loglevel_), /*fmt*/ "{}", str_.str());
    logger->flush();
  }

  ~SpdLogMessage() { Flush(); }
  inline std::ostream &stream() { return str_; }

 private:
  SpdLogMessage(const SpdLogMessage &) = delete;
  SpdLogMessage &operator=(const SpdLogMessage &) = delete;

 private:
  std::ostringstream str_;
  int loglevel_;
  std::shared_ptr<std::ostringstream> expose_osstream_;
};

typedef ray::SpdLogMessage LoggingProvider;

// Spdlog's severity map.
static int GetMappedSeverity(RayLogLevel severity) {
  switch (severity) {
  case RayLogLevel::TRACE:
    return spdlog::level::trace;
  case RayLogLevel::DEBUG:
    return spdlog::level::debug;
  case RayLogLevel::INFO:
    return spdlog::level::info;
  case RayLogLevel::WARNING:
    return spdlog::level::warn;
  case RayLogLevel::ERROR:
    return spdlog::level::err;
  case RayLogLevel::FATAL:
    return spdlog::level::critical;
  default:
    RAY_LOG(FATAL) << "Unsupported logging level: " << static_cast<int>(severity);
    // This return won't be hit but compiler needs it.
    return spdlog::level::off;
  }
}

std::vector<FatalLogCallback> RayLog::fatal_log_callbacks_;

void RayLog::StartRayLog(const std::string &app_name,
                         RayLogLevel severity_threshold,
                         const std::string &log_dir) {
  const char *var_value = std::getenv("RAY_BACKEND_LOG_LEVEL");
  if (var_value != nullptr) {
    std::string data = var_value;
    std::transform(data.begin(), data.end(), data.begin(), ::tolower);
    if (data == "trace") {
      severity_threshold = RayLogLevel::TRACE;
    } else if (data == "debug") {
      severity_threshold = RayLogLevel::DEBUG;
    } else if (data == "info") {
      severity_threshold = RayLogLevel::INFO;
    } else if (data == "warning") {
      severity_threshold = RayLogLevel::WARNING;
    } else if (data == "error") {
      severity_threshold = RayLogLevel::ERROR;
    } else if (data == "fatal") {
      severity_threshold = RayLogLevel::FATAL;
    } else {
      RAY_LOG(WARNING) << "Unrecognized setting of RAY_BACKEND_LOG_LEVEL=" << var_value;
    }
    RAY_LOG(INFO) << "Set ray log level from environment variable RAY_BACKEND_LOG_LEVEL"
                  << " to " << static_cast<int>(severity_threshold);
  }
  severity_threshold_ = severity_threshold;
  app_name_ = app_name;
  log_dir_ = log_dir;

  // All the logging sinks to add.
  std::vector<spdlog::sink_ptr> sinks;
  auto level = static_cast<spdlog::level::level_enum>(severity_threshold_);
  std::string app_name_without_path = app_name;
  if (app_name.empty()) {
    app_name_without_path = "DefaultApp";
  } else {
    // Find the app name without the path.
    std::string app_file_name = ray::GetFileName(app_name);
    if (!app_file_name.empty()) {
      app_name_without_path = app_file_name;
    }
  }

  if (!log_dir_.empty()) {
    // Enable log file if log_dir_ is not empty.
#ifdef _WIN32
    int pid = _getpid();
#else
    pid_t pid = getpid();
#endif
    // Reset log pattern and level and we assume a log file can be rotated with
    // 10 files in max size 512M by default.
    if (std::getenv("RAY_ROTATION_MAX_BYTES")) {
      long max_size = std::atol(std::getenv("RAY_ROTATION_MAX_BYTES"));
      // 0 means no log rotation in python, but not in spdlog. We just use the default
      // value here.
      if (max_size != 0) {
        log_rotation_max_size_ = max_size;
      }
    }
    if (std::getenv("RAY_ROTATION_BACKUP_COUNT")) {
      long file_num = std::atol(std::getenv("RAY_ROTATION_BACKUP_COUNT"));
      if (file_num != 0) {
        log_rotation_file_num_ = file_num;
      }
    }
    spdlog::set_pattern(log_format_pattern_);
    spdlog::set_level(static_cast<spdlog::level::level_enum>(severity_threshold_));
    // Sink all log stuff to default file logger we defined here. We may need
    // multiple sinks for different files or loglevel.
    auto file_logger = spdlog::get(RayLog::GetLoggerName());
    if (file_logger) {
      // Drop this old logger first if we need reset filename or reconfig
      // logger.
      spdlog::drop(RayLog::GetLoggerName());
    }
    auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
        JoinPaths(log_dir_, app_name_without_path + "_" + std::to_string(pid) + ".log"),
        log_rotation_max_size_,
        log_rotation_file_num_);
    sinks.push_back(file_sink);
  } else {
    // Format pattern is 2020-08-21 17:00:00,000 I 100 1001 msg.
    // %L is loglevel, %P is process id, %t for thread id.
    log_format_pattern_ =
        "[%Y-%m-%d %H:%M:%S,%e %L %P %t] (" + app_name_without_path + ") %v";
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_pattern(log_format_pattern_);
    console_sink->set_level(level);
    sinks.push_back(console_sink);
  }

  // In all cases, log errors to the console log so they are in driver logs.
  // https://github.com/ray-project/ray/issues/12893
  auto err_sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
  err_sink->set_pattern(log_format_pattern_);
  err_sink->set_level(spdlog::level::err);
  sinks.push_back(err_sink);

  // Set the combined logger.
  auto logger = std::make_shared<spdlog::logger>(
      RayLog::GetLoggerName(), sinks.begin(), sinks.end());
  logger->set_level(level);
  logger->set_pattern(log_format_pattern_);
  spdlog::set_level(static_cast<spdlog::level::level_enum>(severity_threshold_));
  spdlog::set_pattern(log_format_pattern_);
  spdlog::set_default_logger(logger);

  initialized_ = true;
}

void RayLog::UninstallSignalAction() {
  if (!is_failure_signal_handler_installed_) {
    return;
  }
  RAY_LOG(DEBUG) << "Uninstall signal handlers.";
  std::vector<int> installed_signals({SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM});
#ifdef _WIN32  // Do NOT use WIN32 (without the underscore); we want _WIN32 here
  for (int signal_num : installed_signals) {
    RAY_CHECK(signal(signal_num, SIG_DFL) != SIG_ERR);
  }
#else
  struct sigaction sig_action;
  memset(&sig_action, 0, sizeof(sig_action));
  sigemptyset(&sig_action.sa_mask);
  sig_action.sa_handler = SIG_DFL;
  for (int signal_num : installed_signals) {
    RAY_CHECK(sigaction(signal_num, &sig_action, NULL) == 0);
  }
#endif
  is_failure_signal_handler_installed_ = false;
}

void RayLog::ShutDownRayLog() {
  if (!initialized_) {
    // If the log wasn't initialized, make it no-op.
    RAY_LOG(INFO) << "The log wasn't initialized. ShutdownRayLog requests are ignored";
    return;
  }
  UninstallSignalAction();
  if (spdlog::default_logger()) {
    spdlog::default_logger()->flush();
  }
  // NOTE(lingxuan.zlx) All loggers will be closed in shutdown but we don't need drop
  // console logger out because of some console logging might be used after shutdown ray
  // log. spdlog::shutdown();
}

void WriteFailureMessage(const char *data) {
  // The data & size represent one line failure message.
  // The second parameter `size-1` means we should strip last char `\n`
  // for pretty printing.
  if (nullptr != data) {
    RAY_LOG(ERROR) << std::string(data, strlen(data) - 1);
  }

  // If logger writes logs to files, logs are fully-buffered, which is different from
  // stdout (line-buffered) and stderr (unbuffered). So always flush here in case logs are
  // lost when logger writes logs to files.
  if (spdlog::default_logger()) {
    spdlog::default_logger()->flush();
  }
}

bool RayLog::IsFailureSignalHandlerEnabled() {
  return is_failure_signal_handler_installed_;
}

void RayLog::InstallFailureSignalHandler(const char *argv0, bool call_previous_handler) {
#ifdef _WIN32
  // If process fails to initialize, don't display an error window.
  SetErrorMode(GetErrorMode() | SEM_FAILCRITICALERRORS);
  // If process crashes, don't display an error window.
  SetErrorMode(GetErrorMode() | SEM_NOGPFAULTERRORBOX);
#endif
  if (is_failure_signal_handler_installed_) {
    return;
  }
  absl::InitializeSymbolizer(argv0);
  absl::FailureSignalHandlerOptions options;
  options.call_previous_handler = call_previous_handler;
  options.writerfn = WriteFailureMessage;
  absl::InstallFailureSignalHandler(options);
  is_failure_signal_handler_installed_ = true;
}

void RayLog::InstallTerminateHandler() { std::set_terminate(TerminateHandler); }

bool RayLog::IsLevelEnabled(RayLogLevel log_level) {
  return log_level >= severity_threshold_;
}

std::string RayLog::GetLogFormatPattern() { return log_format_pattern_; }

std::string RayLog::GetLoggerName() { return logger_name_; }

void RayLog::AddFatalLogCallbacks(
    const std::vector<FatalLogCallback> &expose_log_callbacks) {
  fatal_log_callbacks_.insert(fatal_log_callbacks_.end(),
                              expose_log_callbacks.begin(),
                              expose_log_callbacks.end());
}

RayLog::RayLog(const char *file_name, int line_number, RayLogLevel severity)
    : logging_provider_(nullptr),
      is_enabled_(severity >= severity_threshold_),
      severity_(severity),
      is_fatal_(severity == RayLogLevel::FATAL) {
  if (is_fatal_) {
    expose_osstream_ = std::make_shared<std::ostringstream>();
    *expose_osstream_ << file_name << ":" << line_number << ":";
  }
  if (is_enabled_) {
    logging_provider_ = new LoggingProvider(
        file_name, line_number, GetMappedSeverity(severity), expose_osstream_);
  }
}

std::ostream &RayLog::Stream() {
  auto logging_provider = reinterpret_cast<LoggingProvider *>(logging_provider_);
  // Before calling this function, user should check IsEnabled.
  // When IsEnabled == false, logging_provider_ will be empty.
  return logging_provider->stream();
}

bool RayLog::IsEnabled() const { return is_enabled_; }

bool RayLog::IsFatal() const { return is_fatal_; }

std::ostream &RayLog::ExposeStream() { return *expose_osstream_; }

RayLog::~RayLog() {
  if (logging_provider_ != nullptr) {
    delete reinterpret_cast<LoggingProvider *>(logging_provider_);
    logging_provider_ = nullptr;
  }
  if (expose_osstream_ != nullptr) {
    for (const auto &callback : fatal_log_callbacks_) {
      callback(EL_RAY_FATAL_CHECK_FAILED, expose_osstream_->str());
    }
  }
  if (severity_ == RayLogLevel::FATAL) {
    std::_Exit(EXIT_FAILURE);
  }
}

}  // namespace ray


text:
package org.apache.cassandra.db;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;

import org.apache.cassandra.io.SerDeUtils;
import org.apache.cassandra.locator.OldNetworkTopologyStrategy;
import org.apache.cassandra.thrift.CfDef;
import org.apache.cassandra.thrift.ColumnDef;
import org.junit.Test;

import org.apache.cassandra.CleanupHelper;
import org.apache.cassandra.Util;
import org.apache.cassandra.config.*;
import org.apache.cassandra.db.clock.TimestampReconciler;
import org.apache.cassandra.db.filter.QueryFilter;
import org.apache.cassandra.db.filter.QueryPath;
import org.apache.cassandra.db.marshal.BytesType;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.db.migration.*;
import org.apache.cassandra.locator.SimpleStrategy;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.UUIDGen;

public class DefsTest extends CleanupHelper
{
    @Test
    public void ensureStaticCFMIdsAreLessThan1000()
    {
        assert CFMetaData.StatusCf.cfId == 0;
        assert CFMetaData.HintsCf.cfId == 1;
        assert CFMetaData.MigrationsCf.cfId == 2;
        assert CFMetaData.SchemaCf.cfId == 3;
    }

    @Test
    public void testInvalidNames() throws IOException
    {
        String[] valid = {"1", "a", "_1", "b_", "__", "1_a"};
        for (String s : valid)
            assert Migration.isLegalName(s);

        String[] invalid = {"b@t", "dash-y", "", " ", "dot.s", ".hidden"};
        for (String s : invalid)
            assert !Migration.isLegalName(s);
    }

    @Test
    public void saveAndRestore() throws IOException
    {
        // verify dump and reload.
        UUID first = UUIDGen.makeType1UUIDFromHost(FBUtilities.getLocalAddress());
        DefsTable.dumpToStorage(first);
        List<KSMetaData> defs = new ArrayList<KSMetaData>(DefsTable.loadFromStorage(first));

        assert defs.size() > 0;
        assert defs.size() == DatabaseDescriptor.getNonSystemTables().size();
        for (KSMetaData loaded : defs)
        {
            KSMetaData defined = DatabaseDescriptor.getTableDefinition(loaded.name);
            assert defined.equals(loaded);
        }
    }

    @Test
    public void addNewCfToBogusTable() throws InterruptedException
    {
        CFMetaData newCf = addTestCF("MadeUpKeyspace", "NewCF", "new cf");
        try
        {
            new AddColumnFamily(newCf).apply();
            throw new AssertionError("You shouldn't be able to do anything to a keyspace that doesn't exist.");
        }
        catch (ConfigurationException expected)
        {
        }
        catch (IOException unexpected)
        {
            throw new AssertionError("Unexpected exception.");
        }
    }

    @Test
    public void testMigrations() throws IOException, ConfigurationException
    {
        // do a save. make sure it doesn't mess with the defs version.
        UUID prior = DatabaseDescriptor.getDefsVersion();
        UUID ver0 = UUIDGen.makeType1UUIDFromHost(FBUtilities.getLocalAddress());
        DefsTable.dumpToStorage(ver0);
        assert DatabaseDescriptor.getDefsVersion().equals(prior);

        // add a cf.
        CFMetaData newCf1 = addTestCF("Keyspace1", "MigrationCf_1", "Migration CF");

        Migration m1 = new AddColumnFamily(newCf1);
        m1.apply();
        UUID ver1 = m1.getVersion();
        assert DatabaseDescriptor.getDefsVersion().equals(ver1);

        // rename it.
        Migration m2 = new RenameColumnFamily("Keyspace1", "MigrationCf_1", "MigrationCf_2");
        m2.apply();
        UUID ver2 = m2.getVersion();
        assert DatabaseDescriptor.getDefsVersion().equals(ver2);

        // drop it.
        Migration m3 = new DropColumnFamily("Keyspace1", "MigrationCf_2", true);
        m3.apply();
        UUID ver3 = m3.getVersion();
        assert DatabaseDescriptor.getDefsVersion().equals(ver3);

        // now lets load the older migrations to see if that code works.
        Collection<IColumn> serializedMigrations = Migration.getLocalMigrations(ver1, ver3);
        assert serializedMigrations.size() == 3;

        // test deserialization of the migrations.
        Migration[] reconstituded = new Migration[3];
        int i = 0;
        for (IColumn col : serializedMigrations)
        {
            UUID version = UUIDGen.makeType1UUID(col.name());
            reconstituded[i] = Migration.deserialize(col.value());
            assert version.equals(reconstituded[i].getVersion());
            i++;
        }

        assert m1.getClass().equals(reconstituded[0].getClass());
        assert m2.getClass().equals(reconstituded[1].getClass());
        assert m3.getClass().equals(reconstituded[2].getClass());

        // verify that the row mutations are the same. rather than exposing the private fields, serialize and verify.
        assert Arrays.equals(m1.serialize(), reconstituded[0].serialize());
        assert Arrays.equals(m2.serialize(), reconstituded[1].serialize());
        assert Arrays.equals(m3.serialize(), reconstituded[2].serialize());
    }

    @Test
    public void addNewCF() throws ConfigurationException, IOException, ExecutionException, InterruptedException
    {
        final String ks = "Keyspace1";
        final String cf = "BrandNewCf";
        KSMetaData original = DatabaseDescriptor.getTableDefinition(ks);

        CFMetaData newCf = addTestCF(original.name, cf, "A New Column Family");

        assert !DatabaseDescriptor.getTableDefinition(ks).cfMetaData().containsKey(newCf.cfName);
        new AddColumnFamily(newCf).apply();

        assert DatabaseDescriptor.getTableDefinition(ks).cfMetaData().containsKey(newCf.cfName);
        assert DatabaseDescriptor.getTableDefinition(ks).cfMetaData().get(newCf.cfName).equals(newCf);

        // now read and write to it.
        DecoratedKey dk = Util.dk("key0");
        RowMutation rm = new RowMutation(ks, dk.key);
        rm.add(new QueryPath(cf, null, "col0".getBytes()), "value0".getBytes(), new TimestampClock(1L));
        rm.apply();
        ColumnFamilyStore store = Table.open(ks).getColumnFamilyStore(cf);
        assert store != null;
        store.forceBlockingFlush();

        ColumnFamily cfam = store.getColumnFamily(QueryFilter.getNamesFilter(dk, new QueryPath(cf), "col0".getBytes()));
        assert cfam.getColumn("col0".getBytes()) != null;
        IColumn col = cfam.getColumn("col0".getBytes());
        assert Arrays.equals("value0".getBytes(), col.value());
    }

    @Test
    public void dropCf() throws ConfigurationException, IOException, ExecutionException, InterruptedException
    {
        DecoratedKey dk = Util.dk("dropCf");
        // sanity
        final KSMetaData ks = DatabaseDescriptor.getTableDefinition("Keyspace1");
        assert ks != null;
        final CFMetaData cfm = ks.cfMetaData().get("Standard1");
        assert cfm != null;

        // write some data, force a flush, then verify that files exist on disk.
        RowMutation rm = new RowMutation(ks.name, dk.key);
        for (int i = 0; i < 100; i++)
            rm.add(new QueryPath(cfm.cfName, null, ("col" + i).getBytes()), "anyvalue".getBytes(), new TimestampClock(1L));
        rm.apply();
        ColumnFamilyStore store = Table.open(cfm.tableName).getColumnFamilyStore(cfm.cfName);
        assert store != null;
        store.forceBlockingFlush();
        store.getFlushPath();
        assert DefsTable.getFiles(cfm.tableName, cfm.cfName).size() > 0;

        new DropColumnFamily(ks.name, cfm.cfName, true).apply();

        assert !DatabaseDescriptor.getTableDefinition(ks.name).cfMetaData().containsKey(cfm.cfName);

        // any write should fail.
        rm = new RowMutation(ks.name, dk.key);
        boolean success = true;
        try
        {
            rm.add(new QueryPath("Standard1", null, "col0".getBytes()), "value0".getBytes(), new TimestampClock(1L));
            rm.apply();
        }
        catch (Throwable th)
        {
            success = false;
        }
        assert !success : "This mutation should have failed since the CF no longer exists.";

        // verify that the files are gone.
        for (File file : DefsTable.getFiles(cfm.tableName, cfm.cfName))
        {
            if (file.getPath().endsWith("Data.db") && !new File(file.getPath().replace("Data.db", "Compacted")).exists())
                throw new AssertionError("undeleted file " + file);
        }
    }

    @Test
    public void renameCf() throws ConfigurationException, IOException, ExecutionException, InterruptedException
    {
        DecoratedKey dk = Util.dk("key0");
        final KSMetaData ks = DatabaseDescriptor.getTableDefinition("Keyspace2");
        assert ks != null;
        final CFMetaData oldCfm = ks.cfMetaData().get("Standard1");
        assert oldCfm != null;

        // write some data, force a flush, then verify that files exist on disk.
        RowMutation rm = new RowMutation(ks.name, dk.key);
        for (int i = 0; i < 100; i++)
            rm.add(new QueryPath(oldCfm.cfName, null, ("col" + i).getBytes()), "anyvalue".getBytes(), new TimestampClock(1L));
        rm.apply();
        ColumnFamilyStore store = Table.open(oldCfm.tableName).getColumnFamilyStore(oldCfm.cfName);
        assert store != null;
        store.forceBlockingFlush();
        int fileCount = DefsTable.getFiles(oldCfm.tableName, oldCfm.cfName).size();
        assert fileCount > 0;

        final String cfName = "St4ndard1Replacement";
        new RenameColumnFamily(oldCfm.tableName, oldCfm.cfName, cfName).apply();

        assert !DatabaseDescriptor.getTableDefinition(ks.name).cfMetaData().containsKey(oldCfm.cfName);
        assert DatabaseDescriptor.getTableDefinition(ks.name).cfMetaData().containsKey(cfName);

        // verify that new files are there.
        assert DefsTable.getFiles(oldCfm.tableName, cfName).size() == fileCount;

        // do some reads.
        store = Table.open(oldCfm.tableName).getColumnFamilyStore(cfName);
        assert store != null;
        ColumnFamily cfam = store.getColumnFamily(QueryFilter.getSliceFilter(dk, new QueryPath(cfName), "".getBytes(), "".getBytes(), false, 1000));
        assert cfam.getSortedColumns().size() == 100; // should be good enough?

        // do some writes
        rm = new RowMutation(ks.name, dk.key);
        rm.add(new QueryPath(cfName, null, "col5".getBytes()), "updated".getBytes(), new TimestampClock(2L));
        rm.apply();
        store.forceBlockingFlush();

        cfam = store.getColumnFamily(QueryFilter.getNamesFilter(dk, new QueryPath(cfName), "col5".getBytes()));
        assert cfam.getColumnCount() == 1;
        assert Arrays.equals(cfam.getColumn("col5".getBytes()).value(), "updated".getBytes());
    }

    @Test
    public void addNewKS() throws ConfigurationException, IOException, ExecutionException, InterruptedException
    {
        DecoratedKey dk = Util.dk("key0");
        CFMetaData newCf = addTestCF("NewKeyspace1", "AddedStandard1", "A new cf for a new ks");

        KSMetaData newKs = new KSMetaData(newCf.tableName, SimpleStrategy.class, null, 5, newCf);

        new AddKeyspace(newKs).apply();

        assert DatabaseDescriptor.getTableDefinition(newCf.tableName) != null;
        assert DatabaseDescriptor.getTableDefinition(newCf.tableName) == newKs;

        // test reads and writes.
        RowMutation rm = new RowMutation(newCf.tableName, dk.key);
        rm.add(new QueryPath(newCf.cfName, null, "col0".getBytes()), "value0".getBytes(), new TimestampClock(1L));
        rm.apply();
        ColumnFamilyStore store = Table.open(newCf.tableName).getColumnFamilyStore(newCf.cfName);
        assert store != null;
        store.forceBlockingFlush();

        ColumnFamily cfam = store.getColumnFamily(QueryFilter.getNamesFilter(dk, new QueryPath(newCf.cfName), "col0".getBytes()));
        assert cfam.getColumn("col0".getBytes()) != null;
        IColumn col = cfam.getColumn("col0".getBytes());
        assert Arrays.equals("value0".getBytes(), col.value());
    }

    @Test
    public void dropKS() throws ConfigurationException, IOException, ExecutionException, InterruptedException
    {
        DecoratedKey dk = Util.dk("dropKs");
        // sanity
        final KSMetaData ks = DatabaseDescriptor.getTableDefinition("Keyspace1");
        assert ks != null;
        final CFMetaData cfm = ks.cfMetaData().get("Standard2");
        assert cfm != null;

        // write some data, force a flush, then verify that files exist on disk.
        RowMutation rm = new RowMutation(ks.name, dk.key);
        for (int i = 0; i < 100; i++)
            rm.add(new QueryPath(cfm.cfName, null, ("col" + i).getBytes()), "anyvalue".getBytes(), new TimestampClock(1L));
        rm.apply();
        ColumnFamilyStore store = Table.open(cfm.tableName).getColumnFamilyStore(cfm.cfName);
        assert store != null;
        store.forceBlockingFlush();
        assert DefsTable.getFiles(cfm.tableName, cfm.cfName).size() > 0;

        new DropKeyspace(ks.name, true).apply();

        assert DatabaseDescriptor.getTableDefinition(ks.name) == null;

        // write should fail.
        rm = new RowMutation(ks.name, dk.key);
        boolean success = true;
        try
        {
            rm.add(new QueryPath("Standard1", null, "col0".getBytes()), "value0".getBytes(), new TimestampClock(1L));
            rm.apply();
        }
        catch (Throwable th)
        {
            success = false;
        }
        assert !success : "This mutation should have failed since the CF no longer exists.";

        // reads should fail too.
        try
        {
            Table.open(ks.name);
        }
        catch (Throwable th)
        {
            // this is what has historically happened when you try to open a table that doesn't exist.
            assert th instanceof NullPointerException;
        }
    }

    @Test
    public void renameKs() throws ConfigurationException, IOException, ExecutionException, InterruptedException
    {
        DecoratedKey dk = Util.dk("renameKs");
        final KSMetaData oldKs = DatabaseDescriptor.getTableDefinition("Keyspace2");
        assert oldKs != null;
        final String cfName = "Standard3";
        assert oldKs.cfMetaData().containsKey(cfName);
        assert oldKs.cfMetaData().get(cfName).tableName.equals(oldKs.name);

        // write some data that we hope to read back later.
        RowMutation rm = new RowMutation(oldKs.name, dk.key);
        for (int i = 0; i < 10; i++)
            rm.add(new QueryPath(cfName, null, ("col" + i).getBytes()), "value".getBytes(), new TimestampClock(1L));
        rm.apply();
        ColumnFamilyStore store = Table.open(oldKs.name).getColumnFamilyStore(cfName);
        assert store != null;
        store.forceBlockingFlush();
        assert DefsTable.getFiles(oldKs.name, cfName).size() > 0;

        final String newKsName = "RenamedKeyspace2";
        new RenameKeyspace(oldKs.name, newKsName).apply();
        KSMetaData newKs = DatabaseDescriptor.getTableDefinition(newKsName);

        assert DatabaseDescriptor.getTableDefinition(oldKs.name) == null;
        assert newKs != null;
        assert newKs.name.equals(newKsName);
        assert newKs.cfMetaData().containsKey(cfName);
        assert newKs.cfMetaData().get(cfName).tableName.equals(newKsName);
        assert DefsTable.getFiles(newKs.name, cfName).size() > 0;

        // read on old should fail.
        try
        {
            Table.open(oldKs.name);
        }
        catch (Throwable th)
        {
            assert th instanceof NullPointerException;
        }

        // write on old should fail.
        rm = new RowMutation(oldKs.name, "any key will do".getBytes());
        boolean success = true;
        try
        {
            rm.add(new QueryPath(cfName, null, "col0".getBytes()), "value0".getBytes(), new TimestampClock(1L));
            rm.apply();
        }
        catch (Throwable th)
        {
            success = false;
        }
        assert !success : "This mutation should have failed since the CF/Table no longer exists.";

        // write on new should work.
        rm = new RowMutation(newKsName, dk.key);
        rm.add(new QueryPath(cfName, null, "col0".getBytes()), "newvalue".getBytes(), new TimestampClock(2L));
        rm.apply();
        store = Table.open(newKs.name).getColumnFamilyStore(cfName);
        assert store != null;
        store.forceBlockingFlush();

        // read on new should work.
        SortedSet<byte[]> cols = new TreeSet<byte[]>(BytesType.instance);
        cols.add("col0".getBytes());
        cols.add("col1".getBytes());
        ColumnFamily cfam = store.getColumnFamily(QueryFilter.getNamesFilter(dk, new QueryPath(cfName), cols));
        assert cfam.getColumnCount() == cols.size();
        // tests new write.
        assert Arrays.equals(cfam.getColumn("col0".getBytes()).value(), "newvalue".getBytes());
        // tests old write.
        assert Arrays.equals(cfam.getColumn("col1".getBytes()).value(), "value".getBytes());
    }

    @Test
    public void createEmptyKsAddNewCf() throws ConfigurationException, IOException, ExecutionException, InterruptedException
    {
        assert DatabaseDescriptor.getTableDefinition("EmptyKeyspace") == null;

        KSMetaData newKs = new KSMetaData("EmptyKeyspace", SimpleStrategy.class, null, 5);

        new AddKeyspace(newKs).apply();
        assert DatabaseDescriptor.getTableDefinition("EmptyKeyspace") != null;

        CFMetaData newCf = addTestCF("EmptyKeyspace", "AddedLater", "A new CF to add to an empty KS");

        //should not exist until apply
        assert !DatabaseDescriptor.getTableDefinition(newKs.name).cfMetaData().containsKey(newCf.cfName);

        //add the new CF to the empty space
        new AddColumnFamily(newCf).apply();

        assert DatabaseDescriptor.getTableDefinition(newKs.name).cfMetaData().containsKey(newCf.cfName);
        assert DatabaseDescriptor.getTableDefinition(newKs.name).cfMetaData().get(newCf.cfName).equals(newCf);

        // now read and write to it.
        DecoratedKey dk = Util.dk("key0");
        RowMutation rm = new RowMutation(newKs.name, dk.key);
        rm.add(new QueryPath(newCf.cfName, null, "col0".getBytes()), "value0".getBytes(), new TimestampClock(1L));
        rm.apply();
        ColumnFamilyStore store = Table.open(newKs.name).getColumnFamilyStore(newCf.cfName);
        assert store != null;
        store.forceBlockingFlush();

        ColumnFamily cfam = store.getColumnFamily(QueryFilter.getNamesFilter(dk, new QueryPath(newCf.cfName), "col0".getBytes()));
        assert cfam.getColumn("col0".getBytes()) != null;
        IColumn col = cfam.getColumn("col0".getBytes());
        assert Arrays.equals("value0".getBytes(), col.value());
    }

    @Test
    public void testUpdateKeyspace() throws ConfigurationException, IOException, ExecutionException, InterruptedException
    {
        // create a keyspace to serve as existing.
        CFMetaData cf = addTestCF("UpdatedKeyspace", "AddedStandard1", "A new cf for a new ks");
        KSMetaData oldKs = new KSMetaData(cf.tableName, SimpleStrategy.class, null, 5, cf);

        new AddKeyspace(oldKs).apply();

        assert DatabaseDescriptor.getTableDefinition(cf.tableName) != null;
        assert DatabaseDescriptor.getTableDefinition(cf.tableName) == oldKs;

        // anything with cf defs should fail.
        CFMetaData cf2 = addTestCF(cf.tableName, "AddedStandard2", "A new cf for a new ks");
        KSMetaData newBadKs = new KSMetaData(cf.tableName, SimpleStrategy.class, null, 4, cf2);
        try
        {
            new UpdateKeyspace(newBadKs).apply();
            throw new AssertionError("Should not have been able to update a KS with a KS that described column families.");
        }
        catch (ConfigurationException ex)
        {
            // expected.
        }

        // names should match.
        KSMetaData newBadKs2 = new KSMetaData(cf.tableName + "trash", SimpleStrategy.class, null, 4);
        try
        {
            new UpdateKeyspace(newBadKs2).apply();
            throw new AssertionError("Should not have been able to update a KS with an invalid KS name.");
        }
        catch (ConfigurationException ex)
        {
            // expected.
        }

        KSMetaData newKs = new KSMetaData(cf.tableName, OldNetworkTopologyStrategy.class, null, 1);
        new UpdateKeyspace(newKs).apply();

        KSMetaData newFetchedKs = DatabaseDescriptor.getKSMetaData(newKs.name);
        assert newFetchedKs.replicationFactor == newKs.replicationFactor;
        assert newFetchedKs.replicationFactor != oldKs.replicationFactor;
        assert newFetchedKs.strategyClass.equals(newKs.strategyClass);
        assert !newFetchedKs.strategyClass.equals(oldKs.strategyClass);
    }

    @Test
    public void testUpdateColumnFamilyNoIndexes() throws ConfigurationException, IOException, ExecutionException, InterruptedException
    {
        // create a keyspace with a cf to update.
        CFMetaData cf = addTestCF("UpdatedCfKs", "Standard1added", "A new cf that will be updated");
        KSMetaData ksm = new KSMetaData(cf.tableName, SimpleStrategy.class, null, 1, cf);
        new AddKeyspace(ksm).apply();

        assert DatabaseDescriptor.getTableDefinition(cf.tableName) != null;
        assert DatabaseDescriptor.getTableDefinition(cf.tableName) == ksm;

        // updating certain fields should fail.
        CfDef cf_def = new CfDef();
        cf_def.setId(cf.cfId);
        cf_def.setKeyspace(cf.tableName);
        cf_def.setName(cf.cfName);
        cf_def.setColumn_type(cf.cfType.name());
        cf_def.setComment(cf.comment);
        cf_def.setComparator_type(cf.comparator.getClass().getName());
        cf_def.setSubcomparator_type(null);
        cf_def.setGc_grace_seconds(cf.gcGraceSeconds);
        cf_def.setKey_cache_size(cf.keyCacheSize);
        cf_def.setPreload_row_cache(cf.preloadRowCache);
        cf_def.setRead_repair_chance(cf.readRepairChance);
        cf_def.setRow_cache_size(43.3);
        cf_def.setColumn_metadata(new ArrayList<ColumnDef>());
        cf_def.setDefault_validation_class("BytesType");
        cf_def.setMin_compaction_threshold(5);
        cf_def.setMax_compaction_threshold(31);

        // test valid operations.
        cf_def.setComment("Modified comment");
        CFMetaData updateCfm = cf.apply(cf_def);
        new UpdateColumnFamily(cf, updateCfm).apply();
        cf = updateCfm;

        cf_def.setRow_cache_size(2d);
        updateCfm = cf.apply(cf_def);
        new UpdateColumnFamily(cf, updateCfm).apply();
        cf = updateCfm;

        cf_def.setKey_cache_size(3d);
        updateCfm = cf.apply(cf_def);
        new UpdateColumnFamily(cf, updateCfm).apply();
        cf = updateCfm;

        cf_def.setRead_repair_chance(0.23);
        updateCfm = cf.apply(cf_def);
        new UpdateColumnFamily(cf, updateCfm).apply();
        cf = updateCfm;

        cf_def.setGc_grace_seconds(12);
        updateCfm = cf.apply(cf_def);
        new UpdateColumnFamily(cf, updateCfm).apply();
        cf = updateCfm;

        cf_def.setPreload_row_cache(!cf_def.preload_row_cache);
        updateCfm = cf.apply(cf_def);
        new UpdateColumnFamily(cf, updateCfm).apply();
        cf = updateCfm;

        cf_def.setDefault_validation_class("UTF8Type");
        updateCfm = cf.apply(cf_def);
        new UpdateColumnFamily(cf, updateCfm).apply();
        cf = updateCfm;

        cf_def.setMin_compaction_threshold(3);
        updateCfm = cf.apply(cf_def);
        new UpdateColumnFamily(cf, updateCfm).apply();
        cf = updateCfm;

        cf_def.setMax_compaction_threshold(33);
        updateCfm = cf.apply(cf_def);
        new UpdateColumnFamily(cf, updateCfm).apply();
        cf = updateCfm;

        // can't test changing the reconciler because there is only one impl.

        // check the cumulative affect.
        assert DatabaseDescriptor.getCFMetaData(cf.tableName, cf.cfName).comment.equals(cf_def.comment);
        assert DatabaseDescriptor.getCFMetaData(cf.tableName, cf.cfName).rowCacheSize == cf_def.row_cache_size;
        assert DatabaseDescriptor.getCFMetaData(cf.tableName, cf.cfName).keyCacheSize == cf_def.key_cache_size;
        assert DatabaseDescriptor.getCFMetaData(cf.tableName, cf.cfName).readRepairChance == cf_def.read_repair_chance;
        assert DatabaseDescriptor.getCFMetaData(cf.tableName, cf.cfName).gcGraceSeconds == cf_def.gc_grace_seconds;
        assert DatabaseDescriptor.getCFMetaData(cf.tableName, cf.cfName).preloadRowCache == cf_def.preload_row_cache;
        assert DatabaseDescriptor.getCFMetaData(cf.tableName, cf.cfName).defaultValidator == UTF8Type.instance;

        // make sure some invalid operations fail.
        int oldId = cf_def.id;
        try
        {
            cf_def.setId(cf_def.getId() + 1);
            updateCfm = cf.apply(cf_def);
            throw new AssertionError("Should have blown up when you used a different id.");
        }
        catch (ConfigurationException expected)
        {
            cf_def.setId(oldId);
        }

        String oldStr = cf_def.getName();
        try
        {
            cf_def.setName(cf_def.getName() + "_renamed");
            updateCfm = cf.apply(cf_def);
            throw new AssertionError("Should have blown up when you used a different name.");
        }
        catch (ConfigurationException expected)
        {
            cf_def.setName(oldStr);
        }

        oldStr = cf_def.getKeyspace();
        try
        {
            cf_def.setKeyspace(oldStr + "_renamed");
            updateCfm = cf.apply(cf_def);
            throw new AssertionError("Should have blown up when you used a different keyspace.");
        }
        catch (ConfigurationException expected)
        {
            cf_def.setKeyspace(oldStr);
        }

        try
        {
            cf_def.setColumn_type(ColumnFamilyType.Super.name());
            updateCfm = cf.apply(cf_def);
            throw new AssertionError("Should have blwon up when you used a different cf type.");
        }
        catch (ConfigurationException expected)
        {
            cf_def.setColumn_type(ColumnFamilyType.Standard.name());
        }

        oldStr = cf_def.getComparator_type();
        try
        {
            cf_def.setComparator_type(BytesType.class.getSimpleName());
            updateCfm = cf.apply(cf_def);
            throw new AssertionError("Should have blown up when you used a different comparator.");
        }
        catch (ConfigurationException expected)
        {
            cf_def.setComparator_type(UTF8Type.class.getSimpleName());
        }

        try
        {
            cf_def.setMin_compaction_threshold(34);
            updateCfm = cf.apply(cf_def);
            throw new AssertionError("Should have blown up when min > max.");
        }
        catch (ConfigurationException expected)
        {
            cf_def.setMin_compaction_threshold(3);
        }

        try
        {
            cf_def.setMax_compaction_threshold(2);
            updateCfm = cf.apply(cf_def);
            throw new AssertionError("Should have blown up when max > min.");
        }
        catch (ConfigurationException expected)
        {
            cf_def.setMax_compaction_threshold(33);
        }
    }

    private CFMetaData addTestCF(String ks, String cf, String comment)
    {
        return new CFMetaData(ks,
                              cf,
                              ColumnFamilyType.Standard,
                              ClockType.Timestamp,
                              UTF8Type.instance,
                              null,
                              TimestampReconciler.instance,
                              comment,
                              0,
                              false,
                              1.0,
                              0,
                              864000,
                              BytesType.instance,
                              4,
                              32,
                              Collections.<byte[], ColumnDefinition>emptyMap());
    }

}


text:
/*
 *
 *
 *
 */
package com.yhy.core.search;

import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;

import com.yhy.core.constants.SYMBOL;
import com.google.common.collect.Maps;

/**
 * 查询过滤类.
 *
 * @author YHY
 * @version 2014-08-08
 * @----------------------------------------------------------------------------------------
 * @updated 修改描述.
 * @updated by YHY
 * @updated at 2014-08-08
 */
public class Filter {

	public static final String DELETION = "EQ_deletion"; // 逻辑删除查询条件名
	public static final String GENRE = "EQ_genre"; // 类型查询条件名
	public static final String PARENT_ID = "EQ_parentId"; // 父节点查询条件名
	public static final String ORDINAL = "AC_ordinal"; // 父节点查询条件名

	private static final String NULL = "_filter_nil_"; // 默认零值

	/**
	 * EQ : equal( = ) NE : not equal( <> ) GT : greater than( > ) LT : less
	 * than( < ) GE : greater than or equal( >= ) LE : less than or equal( <= )
	 * LI : like '?' LK : like '%?%' LL : like '%?' LR : like '?%' BE : between
	 * 'a,b' IN : in 'a,b,c,d' NU : is null NN : is not null AC : asc(order by)
	 * DC : desc(order by)
	 */
	public enum Operator {
		EQ, NE, GT, LT, GE, LE, LI, LK, LL, LR, BE, IN, NU, NN, AC, DC
	}

	public String fieldName;
	public Object value;
	public Operator operator;

	/**
	 * 只用于 NU : is null NN : is not null AC : asc(order by) DC : desc(order by)
	 *
	 * @param fieldName
	 * @param operator
	 */
	public Filter(String fieldName, Operator operator) {
		this.fieldName = fieldName;
		this.value = Filter.NULL;
		this.operator = operator;
	}

	public Filter(String fieldName, Operator operator, Object value) {
		this.fieldName = fieldName;
		this.value = value;
		this.operator = operator;
	}

	/**
	 * searchParams中key的格式为OPERATOR_FIELDNAME
	 */
	public static Map<String, Filter> parse(Map<String, Object> searchParams) {
		Map<String, Filter> filters = Maps.newHashMap();

		for (Entry<String, Object> entry : searchParams.entrySet()) {
			// 过滤掉空值
			String key = entry.getKey();
			Object value = entry.getValue();
			if (value == null || StringUtils.isBlank(value.toString())) {
				continue;
			}

			// 拆分operator与filedAttribute
			String[] names = StringUtils.split(key, SYMBOL.UNDERLINE);
			if (names.length != 2) {
				throw new IllegalArgumentException(key + " is not a valid search filter name");
			}
			String filedName = names[1];
			Operator operator = Operator.valueOf(names[0]);

			// 创建Filter
			Filter filter = new Filter(filedName, operator, value);
			filters.put(key, filter);
		}

		return filters;
	}

}


text:
<?xml version="1.0" encoding="utf-8"?>
<project name="LTE" default="deploy">
  <!--
  Build.xml file for CakePHP

  Uses phing to create releases, and pear packages.
  Based off of build.xml in doctrine.

  Requires the d51PearPkg2 to be installed:

  pear channel-discover pear.domain51.com
  pear install domain51/Phing_d51PearPkg2Task

  Use the `release` task to update VERSION.txt, and create a new tag.
  Use the `build` task to create a pear package based on the current working copy.
  Use the `clean` task to clean up packaging artifacts.
  -->

    <property name="domain" value="ng-book.oppoin.com" override="true" />

    <property name="repository-uri" value="git@github.com:simkimsia/ng-book.git" override="true" />

    <property name="server-user" value="www-data" override="true" />
    <property name="server-ip" value="166.78.124.182" override="true" />
    <property name="host-used" value="${server-user}@${server-ip}" override="true" />

    <property name="production.branch" value="master" override="true" />
    <property name="production.sitedir" value="/var/virtual/${domain}/" override="true" />

    <tstamp>
        <format property="build.time" pattern="%Y_%m_%d_%H_%M_%S" />
    </tstamp>

    <target name="deploy" depends="gitclone,update-symlink-current">
        <echo msg="Preparing deploy on rackspace server for ng-book environment" />

    </target>

    <target name="gitclone">
        <echo msg="gitclone ${production.branch} branch code to ${production} environment" />

        <exec command="ssh -A ${host-used} 'git clone -b ${production.branch} ${repository-uri} ${production.sitedir}${build.time}'"
         outputProperty="result" escape="false"/>
        <echo msg="${result}" />

    </target>

    <target name="update-symlink-current">
        <echo msg="Updating symlink at current to latest cloned files for ${environment} deployment" />

        <!-- remove the symlink if it is already there -->
        <exec command="ssh -A ${host-used} 'rm ${production.sitedir}current'" outputProperty="result" />

        <!-- <delete dir="${environment.sitedir}current" quiet='true' /> -->
        <exec command="ssh -A ${host-used} 'ln -s ${production.sitedir}${build.time} ${production.sitedir}current'" outputProperty="result" />
        <echo msg="${result}" />
    </target>

</project>


text:
package endtoend

import (
	"io"
	"reflect"
	"runtime"
	"strconv"
	"testing"
	"time"

	"github.com/youtube/vitess/go/sqltypes"
	"github.com/youtube/vitess/go/vt/tabletserver/endtoend/framework"

	querypb "github.com/youtube/vitess/go/vt/proto/query"
)

var createMessage = `create table vitess_message(
	time_scheduled bigint,
	id bigint,
	time_next bigint,
	epoch bigint,
	time_created bigint,
	time_acked bigint,
	message varchar(128),
	primary key(time_scheduled, id),
	unique index id_idx(id),
	index next_idx(time_next, epoch))
comment 'vitess_message,vt_ack_wait=1,vt_purge_after=3,vt_batch_size=2,vt_cache_size=10,vt_poller_interval=1'`

func TestMessage(t *testing.T) {
	ch := make(chan *sqltypes.Result)
	done := make(chan struct{})
	client := framework.NewClient()
	if _, err := client.Execute(createMessage, nil); err != nil {
		t.Fatal(err)
	}
	defer client.Execute("drop table vitess_message", nil)

	go func() {
		if err := client.MessageStream("vitess_message", func(qr *sqltypes.Result) error {
			select {
			case <-done:
				return io.EOF
			default:
			}
			ch <- qr
			return nil
		}); err != nil {
			t.Fatal(err)
		}
	}()
	got := <-ch
	want := &sqltypes.Result{
		Fields: []*querypb.Field{{
			Name: "id",
			Type: sqltypes.Int64,
		}, {
			Name: "message",
			Type: sqltypes.VarChar,
		}},
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("message(field) received:\n%v, want\n%v", got, want)
	}
	runtime.Gosched()
	defer func() { close(done) }()
	err := client.Begin()
	if err != nil {
		t.Error(err)
		return
	}
	_, err = client.Execute("insert into vitess_message(id, message) values(1, 'hello world')", nil)
	if err != nil {
		t.Error(err)
		return
	}
	err = client.Commit()
	if err != nil {
		t.Error(err)
		return
	}
	start := time.Now().UnixNano()
	got = <-ch
	want = &sqltypes.Result{
		Rows: [][]sqltypes.Value{{
			sqltypes.MakeTrusted(sqltypes.Int64, []byte("1")),
			sqltypes.MakeTrusted(sqltypes.VarChar, []byte("hello world")),
		}},
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("message received:\n%v, want\n%v", got, want)
	}
	qr, err := client.Execute("select time_next, epoch from vitess_message where id = 1", nil)
	if err != nil {
		t.Fatal(err)
	}
	next, epoch := getTimeEpoch(qr)
	// epoch could be 0 or 1, depending on how fast the row is updated
	switch epoch {
	case 0:
		if !(start-1e9 < next && next < start) {
			t.Errorf("next: %d. must be within 1s of start: %d", next/1e9, start/1e9)
		}
	case 1:
		if !(start < next && next < start+3e9) {
			t.Errorf("next: %d. must be about 1s after start: %d", next/1e9, start/1e9)
		}
	default:
		t.Errorf("epoch: %d, must be 0 or 1", epoch)
	}
	<-ch
	qr, err = client.Execute("select time_next, epoch from vitess_message where id = 1", nil)
	if err != nil {
		t.Fatal(err)
	}
	next, epoch = getTimeEpoch(qr)
	// epoch could be 1 or 2, depending on how fast the row is updated
	switch epoch {
	case 1:
		if !(start < next && next < start+3e9) {
			t.Errorf("next: %d. must be about 1s after start: %d", next/1e9, start/1e9)
		}
	case 2:
		if !(start+2e9 < next && next < start+6e9) {
			t.Errorf("next: %d. must be about 3s after start: %d", next/1e9, start/1e9)
		}
	default:
		t.Errorf("epoch: %d, must be 1 or 2", epoch)
	}
	count, err := client.MessageAck("vitess_message", []string{"1"})
	if err != nil {
		t.Error(err)
	}
	if count != 1 {
		t.Errorf("count: %d, want 1", count)
	}
	qr, err = client.Execute("select time_acked, epoch from vitess_message where id = 1", nil)
	if err != nil {
		t.Fatal(err)
	}
	end := time.Now().UnixNano()
	ack, _ := getTimeEpoch(qr)
	if !(end-1e9 < ack && ack < end) {
		t.Errorf("ack: %d. must be within 1s of end: %d", ack/1e9, end/1e9)
	}
	// Within 3+1 seconds, the row should be deleted.
	time.Sleep(4 * time.Second)
	qr, err = client.Execute("select time_acked, epoch from vitess_message where id = 1", nil)
	if err != nil {
		t.Fatal(err)
	}
	if qr.RowsAffected != 0 {
		t.Error("The row has not been purged yet")
	}
}

func getTimeEpoch(qr *sqltypes.Result) (int64, int64) {
	if len(qr.Rows) != 1 {
		return 0, 0
	}
	t, _ := strconv.Atoi(qr.Rows[0][0].String())
	e, _ := strconv.Atoi(qr.Rows[0][1].String())
	return int64(t), int64(e)
}


text:
module SimpleSpark
  VERSION = "1.0.12"
end


text:
package conex

import (
	"context"
	"fmt"
	"testing"
	"time"

	docker "github.com/fsouza/go-dockerclient"
)

func init() {
	var _ Container = (*container)(nil)
}

type container struct {
	j *docker.Container
	c *docker.Client

	t testing.TB
}

func (c *container) ID() string {
	return c.j.ID
}

func (c *container) Image() string {
	return c.j.Image
}

func (c *container) Name() string {
	return c.j.Name
}

func (c *container) Address() string {
	return c.j.NetworkSettings.IPAddress
}

func (c *container) Ports() []string {
	// return c.j.NetworkSettings.Ports
	return nil
}

func (c *container) Drop() {
	err := c.c.StopContainer(c.j.ID, 10)

	if err != nil {
		fmt.Println("failed ", c.j.ID)
		c.t.Fatal(err)
	}

	err = c.c.RemoveContainer(docker.RemoveContainerOptions{
		ID:            c.j.ID,
		RemoveVolumes: true,
		Force:         true,
		Context:       context.Background(),
	})
	if err != nil {
		c.t.Fatal(err)
	}

}

func (c *container) Wait(port string, timeout time.Duration) error {
	return wait(c.Address(), port, timeout)
}