`L i>^ddlZddlZddlZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z ddlmZmZmZmZmZmZmZddlmZmZddlmZdd lmZmZdd lmZddl Z!d d l"m#Z#d d l$m%Z%d dl&m'Z'm(Z(m)Z)m*Z*m+Z+ddl,m-Z-ddl.m/Z/dgZ0dZ1dZ2dZ3dZ4eee5e5fZ6eee5e5fZ7de5de5de5fdZ8 dSde5dee5dee9defdZ: dTde;d eGd$d%e?Z@ dUd!e5d&ee5dee5de;d eee5d6eee;e;fd7e5de;d e.decorator..wrapper=s $~"~% &$~"~%  &%1j+78.I,[)D 77>>*-IIj)$~"~% &sBA&B BBr)r7r8r"r*r!s` r' decoratorz*_retry_with_clean_cache..decorator<s q &  &$r))r!r"r*r9s``` r'_retry_with_clean_cacher;1s, r)? n_retriesdelayurlcfd}|S)aUIf the function call results in a network error, call the function again up to ``n_retries`` times with a ``delay`` between each call. If the error has a 412 status code, don't call the function again as this is a specific OpenML error. The url parameter is used to give more information to the user about the error. c6tfd}|S)Nc4} |i|S#ttf$ry}t|tr|jdk(r|dk(rt ddt|tr|j |dz}tjYd}~nd}~wwxYw)Nrz+A network error occurred while downloading z . Retrying...r) r TimeoutErrorr/rcoderclosetimesleep)r3kwargs retry_counterer?r7r>r@s r'r8z;_retry_on_network_error..decorator..wrapperas%M&d-f-- ,/&!!Y/AFFcM$)EcU-X"!Y/ !Q&MJJu%%&sBA/BBr)r7r8r?r>r@s` r'r9z*_retry_on_network_error..decorator`s q &  &*r)r:)r>r?r@r9s``` r'_retry_on_network_errorrMUs2 r)c d}t|}|jdd|Ht|||jt|}||rt j |dS|St|jjd}t||}tjj|\} } tjj|stj| d  t| 5} t!t|||jt|5}||rt"} nt j } | tjj%| | d 5} t'j(|| ddddddt'j* j,|dddt j |dS#1swYOxYw#1swYSxYw#1swY7xYw#t.$r6tjj|rtj0|wxYw) a Returns a resource from OpenML.org. Caches it to data_home if required. Parameters ---------- url : str OpenML URL that will be downloaded and cached locally. The path component of the URL is used to replicate the tree structure as sub-folders of the local cache folder. data_home : str Directory to which the files will be cached. If None, no caching will be applied. n_retries : int, default=3 Number of retries when HTTP errors are encountered. Error with status code 412 won't be retried as they represent OpenML generic errors. delay : float, default=1.0 Number of seconds between retries. Returns ------- result : stream A stream to the OpenML resource. cH|jjdddk(S)NzContent-Encodinggzip)infoget)_fsrcs r'is_gzip_encodedz)_open_openml_url..is_gzip_encodeds!zz| 2B76AAr)zAccept-encodingrQNrb)fileobjmode/T)exist_ok)dirwb)r add_headerrMfull_urlrrQGzipFilerr&lstripr(r%splitr1makedirsrropenrshutil copyfileobjmovenamer.r2)r@r"r>r?rUreqfsrcr!r6dir_name file_nametmpdiropenerfdsts r'_open_openml_urlro|s<B #,CNN$f-OF&y%FwOPST 4 ==D9 9 3-$$++C0K i8J''-- 3Hi 77>>* % Ht,  $1 3VTK+IucllKGT 7&t,!%!% VY ?F7$**467 7 DIIz2 3* ==T **77 7 7 3 3 ww~~j) *%  sU4 H1G51AG)8GG)(G5?HG& "G))G2 .G55G>:H?IceZdZdZy) OpenMLErrorzDHTTP 412 is a specific OpenML error code, indicating a generic errorN)__name__ __module__ __qualname____doc__r:r)r'rqrqsNr)rq error_messagectfd} |S#t$r%}|jdk7r|Yd}~t|d}~wwxYw)a Loads json data from the openml api. Parameters ---------- url : str The URL to load from. Should be an official OpenML endpoint. error_message : str or None The error message to raise if an acceptable OpenML error is thrown (acceptable error is, e.g., data id not found. Other errors, like 404's will throw the native error message). data_home : str or None Location to cache the response. None if no cache is required. n_retries : int, default=3 Number of retries when HTTP errors are encountered. Error with status code 412 won't be retried as they represent OpenML generic errors. delay : float, default=1.0 Number of seconds between retries. Returns ------- json_data : json the json result from the OpenML server if the call was successful. An exception otherwise. r"ctt5}tj|j j dcdddS#1swYyxYw)Nr>r?zutf-8)rrojsonloadsreaddecode)responser"r?r>r@s r' _load_jsonz5_get_json_content_from_openml_api.._load_jsonsN  S)y N  ? ::hmmo44W=> ? ? ?s 2AArDN)r;rrFrq)r@rvr"r>r?rerrors` ``` r'!_get_json_content_from_openml_apirsaJSI6?7? |  :: K  m $$s% AAArgversionc|dk(rtj|dz}dj|}t|||||}|dd}t|dkDrC|dd x} }d |d | d } |D] } | d | d d| ddz } | d| ddz } "t | |dStdzj||} t|d|||}|dddS#t $r*|dz }dj||}t|||||}Y=wxYw)a? Utilizes the openml dataset listing api to find a dataset by name/version OpenML api function: https://www.openml.org/api_docs#!/data/get_data_list_data_name_data_name Parameters ---------- name : str name of the dataset version : int or str If version is an integer, the exact name/version will be obtained from OpenML. If version is a string (value: "active") it will take the first version from OpenML that is annotated as active. Any other string values except "active" are treated as integer. data_home : str or None Location to cache the response. None if no cache is required. n_retries : int, default=3 Number of retries when HTTP errors are encountered. Error with status code 412 won't be retried as they represent OpenML generic errors. delay : float, default=1.0 Number of seconds between retries. Returns ------- first_dataset : json json representation of the first dataset object that adhired to the search criteria activez/status/active/zNo active dataset {} found.r"r>r?datadatasetrrrz:Multiple active versions of the dataset matching the name zC exist. Versions may be fundamentally different, returning version z. Available versions: z - version z , status: status z2 url: https://www.openml.org/search?type=data&id=didz/data_version/{}N)rvr"r>r?z/status/deactivatedz%Dataset {} with version {} not found.) _SEARCH_NAMEformatrlenrrq) rgrr"r>r?r@ error_msg json_datares first_version warning_msgrs r'_get_data_info_by_namersR(!!$'*;;188> 5     * s8a<&)!fY&7 7MG6%%2O4((   AiL>AhK=PRSS H5 RTU    1v  , , 4 4T7 CC 5   , V Y ' **   $$;BB4Q 5      s7C0DDdata_idcxtj|}dj|}t|||||}|dS)N"Dataset with data_id {} not found.rdata_set_description) _DATA_INFOrrrr"r>r?r@rvrs r'_get_data_description_by_idrgsK   G $C8??HM1  I + ,,r)c~tj|}dj|}t|||||}|ddS)Nrr data_featuresfeature)_DATA_FEATURESrrrs r'_get_data_featuresrzsO    (C8??HM1  I _ %i 00r)ctj|}dj|}t|||||}|jdijdgS)Nrrdata_qualitiesquality)_DATA_QUALITIESrrrSrs r'_get_data_qualitiesrs^   )C8??HM1  I ==)2 . 2 29b AAr)rcd}|Dcic] }|d|d }}tt|jd|Scc}w)aJGet the number of samples from data qualities. Parameters ---------- data_qualities : list of dict Used to retrieve the number of instances (samples) in the dataset. Returns ------- n_samples : int The number of samples in the dataset or -1 if data qualities are unavailable. rgvalueNumberOfInstances)intfloatrS)rdefault_n_samplesd qualitiess r'_get_num_samplesrsM0>?16AgJ&?I? uY]]#68IJK LL@s=parser output_typeopenml_columns_infofeature_names_to_selecttarget_names_to_selectshape md5_checksumread_csv_kwargsc 4t||| | t5tj} t fddD]} | j | | j }ddd|k7rtd|d|d|dd }t||||||| xsi } |||| | |\}}}}||||fS#1swYTxYw#t$rI}|d k7rd d l m }t||s|dj d|||| | |\}}}}Yd}~_d}~wwxYw)aLoad the ARFF data associated with the OpenML URL. In addition of loading the data, this function will also check the integrity of the downloaded file from OpenML using MD5 checksum. Parameters ---------- url : str The URL of the ARFF file on OpenML. data_home : str The location where to cache the data. parser : {"liac-arff", "pandas"} The parser used to parse the ARFF file. output_type : {"numpy", "pandas", "sparse"} The type of the arrays that will be returned. The possibilities are: - `"numpy"`: both `X` and `y` will be NumPy arrays; - `"sparse"`: `X` will be sparse matrix and `y` will be a NumPy array; - `"pandas"`: `X` will be a pandas DataFrame and `y` will be either a pandas Series or DataFrame. openml_columns_info : dict The information provided by OpenML regarding the columns of the ARFF file. feature_names_to_select : list of str The list of the features to be selected. target_names_to_select : list of str The list of the target variables to be selected. shape : tuple or None With `parser="liac-arff"`, when using a generator to load the data, one needs to provide the shape of the data beforehand. md5_checksum : str The MD5 checksum provided by OpenML to check the data integrity. n_retries : int, default=3 The number of times to retry downloading the data if it fails. delay : float, default=1.0 The delay between two consecutive downloads in seconds. read_csv_kwargs : dict, default=None Keyword arguments to pass to `pandas.read_csv` when using the pandas parser. It allows to overwrite the default options. .. versionadded:: 1.3 Returns ------- X : {ndarray, sparse matrix, dataframe} The data matrix. y : {ndarray, dataframe, series} The target. frame : dataframe or None A dataframe containing both `X` and `y`. `None` if `output_array_type != "pandas"`. categories : list of str or None The names of the features that are categorical. `None` if `output_array_type == "pandas"`. rzc&jdS)Ni)r}) gzip_filesr'z%_load_arff_response..s).."6r)r)Nzmd5 checksum of local file for z' does not match description: expected: z but got zP. Downloaded file could have been modified / corrupted, clean cache and retry...czt||||}t|5t|fi|cdddS#1swYyxYw)Nrz)rorr)r@r"r>r? arff_paramsrs r'_open_url_and_load_gzip_filez9_load_arff_response.._open_url_and_load_gzip_filesA$S)yPUV Y  F+IEE F F Fs 1:)rrrrrrrpandasr ParserErrorr') quotechar) rorhashlibmd5iterupdate hexdigest ValueErrordictr. pandas.errorsrr/)r@r"rrrrrrrr>r?rrchunkactual_md5_checksumrrXyframe categoriesr5rrs @r'_load_arff_responsersmf!i9ERI  .kkm6< E JJu  !mmo . l*-cU3%i0C/DE   F / 75'-2K "> Iuk# 1eZ( a ""c..@  X  -#{+  %&---<"> Iuk# 1eZ s$A B9"C9C D?DD)r>r?rsparseas_frame data_columnstarget_columnsc f|D cic]} | d|  }} |rd}n|rd}nd}t|||D]/}||}t|d}|dkDstd|dd|d d }| dk(rdd lm}|}t |||t ||| ||||||| | | \}}}}t|||||| Scc} w)aDownload ARFF data, load it to a specific container and create to Bunch. This function has a mechanism to retry/cache/clean the data. Parameters ---------- url : str The URL of the ARFF file on OpenML. sparse : bool Whether the dataset is expected to use the sparse ARFF format. data_home : str The location where to cache the data. as_frame : bool Whether or not to return the data into a pandas DataFrame. openml_columns_info : list of dict The information regarding the columns provided by OpenML for the ARFF dataset. The information is stored as a list of dictionaries. data_columns : list of str The list of the features to be selected. target_columns : list of str The list of the target variables to be selected. shape : tuple or None With `parser="liac-arff"`, when using a generator to load the data, one needs to provide the shape of the data beforehand. md5_checksum : str The MD5 checksum provided by OpenML to check the data integrity. n_retries : int, default=3 Number of retries when HTTP errors are encountered. Error with status code 412 won't be retried as they represent OpenML generic errors. delay : float, default=1.0 Number of seconds between retries. parser : {"liac-arff", "pandas"} The parser used to parse the ARFF file. read_csv_kwargs : dict, default=None Keyword arguments to pass to `pandas.read_csv` when using the pandas parser. It allows to overwrite the default options. .. versionadded:: 1.3 Returns ------- data : :class:`~sklearn.utils.Bunch` Dictionary-like object, with the following attributes. X : {ndarray, sparse matrix, dataframe} The data matrix. y : {ndarray, dataframe, series} The target. frame : dataframe or None A dataframe containing both `X` and `y`. `None` if `output_array_type != "pandas"`. categories : list of str or None The names of the features that are categorical. `None` if `output_array_type == "pandas"`. rgrrnumpynumber_of_missing_valuesrzTarget column 'z' has zE missing values. Missing values are not supported for target columns.Nr) rrrrrrrr>r?r)rtargetrr feature_names target_names)_verify_target_data_typerrrrr;rr)r@rr"rrrrrrr>r?rrr features_dictrrg column_infon_missing_valuesr*rrrrrs r'_download_data_to_bunchrAs?h>QQ'WV_g-QMQ    ]N;#D) {+EFG a !+f"5!6f=M ?=/1FG H  '(; < F ?=/1NO P Q ;!   r)ctg}|D]0}|d|vs |ddk7s|ddk7s|j|d2|S)Nrgrrr)append) features_listrvalid_data_column_namesrs r'_valid_data_column_namesrsZ ! < FO> 1 $.+,6 # * *76? ; < #"r)left)closedrautogneither>rr liac-arff) rgrrr"rcache return_X_yrr>r?rrT)prefer_skip_nested_validationdefault-targetF) rrr"rrrrr>r?rrrrrc |durd}n!t|}tt|d}|C|j}|t dj ||t ||||| } | d}n-| |dk7r&t d j ||t d t||} | d dk7r%td j | d | d| dd| vrtdj | dd| vrtdj | d| djdk(}|dk(r| n|}| dk(r|rdnd}n| }|dk(r td|r!|r t d|dk(rt d| dt||}|s'|D]"}d |d!|d"fvr|d#d$k(st d%|d&k(r|Dcgc]}|d'd k(r|d}}nt|tr|g}n|g}n|}t||}|s#t||}t|t!|f}nd}| d}t#|||t%|||||| d(|| || ) }|r|j&|j(fSd*j | j+d+}|j-|| d,j |-|S#t$r}|rd}nd| d}t||d}~wwxYwcc}w).a$Fetch dataset from openml by name or dataset id. Datasets are uniquely identified by either an integer ID or by a combination of name and version (i.e. there might be multiple versions of the 'iris' dataset). Please give either name or data_id (not both). In case a name is given, a version can also be provided. Read more in the :ref:`User Guide `. .. versionadded:: 0.20 .. note:: EXPERIMENTAL The API is experimental (particularly the return value structure), and might have small backward-incompatible changes without notice or warning in future releases. Parameters ---------- name : str, default=None String identifier of the dataset. Note that OpenML can have multiple datasets with the same name. version : int or 'active', default='active' Version of the dataset. Can only be provided if also ``name`` is given. If 'active' the oldest version that's still active is used. Since there may be more than one active version of a dataset, and those versions may fundamentally be different from one another, setting an exact version is highly recommended. data_id : int, default=None OpenML ID of the dataset. The most specific way of retrieving a dataset. If data_id is not given, name (and potential version) are used to obtain a dataset. data_home : str or path-like, default=None Specify another download and cache folder for the data sets. By default all scikit-learn data is stored in '~/scikit_learn_data' subfolders. target_column : str, list or None, default='default-target' Specify the column name in the data to use as target. If 'default-target', the standard target column a stored on the server is used. If ``None``, all columns are returned as data and the target is ``None``. If list (of strings), all columns with these names are returned as multi-target (Note: not all scikit-learn classifiers can handle all types of multi-output combinations). cache : bool, default=True Whether to cache the downloaded datasets into `data_home`. return_X_y : bool, default=False If True, returns ``(data, target)`` instead of a Bunch object. See below for more information about the `data` and `target` objects. as_frame : bool or 'auto', default='auto' If True, the data is a pandas DataFrame including columns with appropriate dtypes (numeric, string or categorical). The target is a pandas DataFrame or Series depending on the number of target_columns. The Bunch will contain a ``frame`` attribute with the target and the data. If ``return_X_y`` is True, then ``(data, target)`` will be pandas DataFrames or Series as describe above. If `as_frame` is 'auto', the data and target will be converted to DataFrame or Series as if `as_frame` is set to True, unless the dataset is stored in sparse format. If `as_frame` is False, the data and target will be NumPy arrays and the `data` will only contain numerical values when `parser="liac-arff"` where the categories are provided in the attribute `categories` of the `Bunch` instance. When `parser="pandas"`, no ordinal encoding is made. .. versionchanged:: 0.24 The default value of `as_frame` changed from `False` to `'auto'` in 0.24. n_retries : int, default=3 Number of retries when HTTP errors or network timeouts are encountered. Error with status code 412 won't be retried as they represent OpenML generic errors. delay : float, default=1.0 Number of seconds between retries. parser : {"auto", "pandas", "liac-arff"}, default="auto" Parser used to load the ARFF file. Two parsers are implemented: - `"pandas"`: this is the most efficient parser. However, it requires pandas to be installed and can only open dense datasets. - `"liac-arff"`: this is a pure Python ARFF parser that is much less memory- and CPU-efficient. It deals with sparse ARFF datasets. If `"auto"`, the parser is chosen automatically such that `"liac-arff"` is selected for sparse ARFF datasets, otherwise `"pandas"` is selected. .. versionadded:: 1.2 .. versionchanged:: 1.4 The default value of `parser` changes from `"liac-arff"` to `"auto"`. read_csv_kwargs : dict, default=None Keyword arguments passed to :func:`pandas.read_csv` when loading the data from a ARFF file and using the pandas parser. It can allow to overwrite some default parameters. .. versionadded:: 1.3 Returns ------- data : :class:`~sklearn.utils.Bunch` Dictionary-like object, with the following attributes. data : np.array, scipy.sparse.csr_matrix of floats, or pandas DataFrame The feature matrix. Categorical features are encoded as ordinals. target : np.array, pandas Series or DataFrame The regression target or classification labels, if applicable. Dtype is float if numeric, and object if categorical. If ``as_frame`` is True, ``target`` is a pandas object. DESCR : str The full description of the dataset. feature_names : list The names of the dataset columns. target_names: list The names of the target columns. .. versionadded:: 0.22 categories : dict or None Maps each categorical feature name to a list of values, such that the value encoded as i is ith in the list. If ``as_frame`` is True, this is None. details : dict More metadata from OpenML. frame : pandas DataFrame Only present when `as_frame=True`. DataFrame with ``data`` and ``target``. (data, target) : tuple if ``return_X_y`` is True .. note:: EXPERIMENTAL This interface is **experimental** and subsequent releases may change attributes without notice (although there should only be minor changes to ``data`` and ``target``). Missing values in the 'data' are represented as NaN's. Missing values in 'target' are represented as NaN's (numerical target) or None (categorical target). Notes ----- The `"pandas"` and `"liac-arff"` parsers can lead to different data types in the output. The notable differences are the following: - The `"liac-arff"` parser always encodes categorical features as `str` objects. To the contrary, the `"pandas"` parser instead infers the type while reading and numerical categories will be casted into integers whenever possible. - The `"liac-arff"` parser uses float64 to encode numerical features tagged as 'REAL' and 'NUMERICAL' in the metadata. The `"pandas"` parser instead infers if these numerical features corresponds to integers and uses panda's Integer extension dtype. - In particular, classification datasets with integer categories are typically loaded as such `(0, 1, ...)` with the `"pandas"` parser while `"liac-arff"` will force the use of string encoded class labels such as `"0"`, `"1"` and so on. - The `"pandas"` parser will not strip single quotes - i.e. `'` - from string columns. For instance, a string `'my string'` will be kept as is while the `"liac-arff"` parser will strip the single quotes. For categorical columns, the single quotes are stripped from the values. In addition, when `as_frame=False` is used, the `"liac-arff"` parser returns ordinally encoded data where the categories are provided in the attribute `categories` of the `Bunch` instance. Instead, `"pandas"` returns a NumPy array were the categories are not encoded. Examples -------- >>> from sklearn.datasets import fetch_openml >>> adult = fetch_openml("adult", version=2) # doctest: +SKIP >>> adult.frame.info() # doctest: +SKIP RangeIndex: 48842 entries, 0 to 48841 Data columns (total 15 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 age 48842 non-null int64 1 workclass 46043 non-null category 2 fnlwgt 48842 non-null int64 3 education 48842 non-null category 4 education-num 48842 non-null int64 5 marital-status 48842 non-null category 6 occupation 46033 non-null category 7 relationship 48842 non-null category 8 race 48842 non-null category 9 sex 48842 non-null category 10 capital-gain 48842 non-null int64 11 capital-loss 48842 non-null int64 12 hours-per-week 48842 non-null int64 13 native-country 47985 non-null category 14 class 48842 non-null category dtypes: category(9), int64(6) memory usage: 2.7 MB FNrxopenmlzfDataset data_id={} and name={} passed, but you can only specify a numeric data_id or a name, not both.rzrrzlDataset data_id={} and version={} passed, but you can only specify a numeric data_id or a version, not both.zFNeither name nor data_id are provided. Please provide name or data_id.rzVersion {} of dataset {} is inactive, meaning that issues have been found in the dataset. Try using a newer version from this URL: {}rrgr@rzMOpenML registered a problem with the dataset. It might be unusable. Error: {}warningzIOpenML raised a warning on the dataset. It might be unusable. Warning: {}r sparse_arffrrrz`fetch_openml`zReturning pandas objects requires pandas to be installed. Alternatively, explicitly set `as_frame=False` and `parser='liac-arff'`.zUsing `parser=zf` with dense data requires pandas to be installed. Alternatively, explicitly set `parser='liac-arff'`.zhSparse ARFF datasets cannot be loaded with as_frame=True. Use as_frame=False or as_frame='auto' instead.z2Sparse ARFF datasets cannot be loaded with parser=z2. Use parser='liac-arff' or parser='auto' instead.rrrrstringzOSTRING attributes are not supported for array representation. Try as_frame=Truer is_targetr) rrrrrrr>r?rrz{} Downloaded from openml.org. descriptionzhttps://www.openml.org/d/{})DESCRdetailsr@)rrstrlowerrrrrrr ImportErrorrr/rrrrrboolrrpopr)rgrrr"rrrrr>r?rr data_infodata_description return_sparseparser_r5err_msgrrrrrrr@bunchrs r'r r s\ ~ !I6 Y2  zz|  w-  + '9  E"   h w0   T  37IF!X-  !6 + ( ' ""  ""(&)9')B"C $$  $$*F+;I+F$G %X.446-GM$,$6= HH !.+H( 0 !1 2 A  h DVJOCC  'w :M $ G'+.8K0LMM{#x/ >  (( ) {#v- FO  M3 ''  '+M>JL -Wi@ 0#m2DD 5 !C # h)%!%n5' E zz5<<''5<<]+K LL ) 0 0 9 LG 0,%VJ/UUg&C / 0V s J#6K # K,KK)N)r<r=rP)r<r=)r<r=N)PrQrr{r%rdrH contextlibr functoolsros.pathrtempfilertypingrr r r r r r urllib.errorrr urllib.parserurllib.requestrrwarningsrrrutilsrutils._optional_dependenciesrutils._param_validationrrrrrrPr _arff_parserr__all__rrrrr OpenmlQualitiesTypeOpenmlFeaturesTyper(r.r;rrrMrorrqrrrrrrrrr rrrPathLikerr r:r)r'r&s  'DDD,!+?2  R 9 FH4S>*$sCx.)FFFF/3!!}!!+! !J8:$$$$14$ $PLOI+ I+!#I+36I+CHI+X *  5% 5%C=5%}5% 5%  5%  5%x ^+ ^+ 38_^+}^+ ^+  ^+H - -}--  -  #s(^ -, 1 1}11  1  1. B B}BB  B  B,M%8MSM>&*E# E#}E# E# E#  E# "#Y E#!IE# E#s(O $E#E#E# E#d^E#f&*H H H}H  H d Hs)HIH E#s(O $HHH H Hd^HV 6 # d Xq$v> H:@VWXq$v>E2;;-tT*f:vh/0xD@A4d9=> 6 7 !$< #'#(B (!370@!'&*B 3-B38_Bc] B c2;;./0 B E#t),- B BBCIBB B Bd^B'&Br)