def Func(
        arg_0,
        arg_1: arg_2,
        arg_3: arg_4,
        arg_5: arg_2 = 'asc',
        arg_6: arg_7[arg_2, arg_8[arg_2]] = None
):
    """
    Get the Func or flop N results based on a column value for each specified group columns

    ---

    ### Parameters

    *mandatory :*
    - `value` (*str*): column name on which you will rank the results
    - `limit` (*int*): Number to specify the N results you want to retrieve.
        Use a positive number x to retrieve the first x results.
        Use a negative number -x to retrieve the last x results.

    *optional :*
    - `order` (*str*): `"asc"` or `"desc"` to sort by ascending ou descending order. By default : `"asc"`.
    - `group` (*str*, *list of str*): name(s) of columns on which you want to perform the group operation.

    ---

    ### Example

    **Input**

    | variable | Category | value |
    |:--------:|:--------:|:-----:|
    |   lili   |    1     |  50  |
    |   lili   |    1     |  20  |
    |   toto   |    1     |  100  |
    |   toto   |    1     |  200  |
    |   toto   |    1     |  300  |
    |   lala   |    1     |  100  |
    |   lala   |    1     |  150  |
    |   lala   |    1     |  250  |
    |   lala   |    2     |  350  |
    |   lala   |    2     |  450  |

    ```cson
    Func:
      value: 'value'
      limit: 4
      order: 'asc'
    ```

    **Output**

    | variable | Category | value |
    |:--------:|:--------:|:-----:|
    |   lala   |    1     |  250  |
    |   toto   |    1     |  300  |
    |   lala   |    2     |  350  |
    |   lala   |    2     |  450  |
    """
    arg_9 = arg_5 != 'desc'
    arg_3 = arg_4(arg_3)
    arg_10 = 'nlargest' if (arg_3 > 0) ^ arg_9 else 'nsmallest'

    def _Func(arg_0):
        return getattr(arg_0, arg_10)(abs(arg_3), arg_1).sort_values(by=arg_1,
                                                                       arg_9=arg_9)

    if arg_6 is None:
        arg_0 = _Func(arg_0)
    else:
        arg_0 = arg_0.groupby(arg_6).apply(_Func)

    return arg_0


def Func(
        arg_0,
        arg_1: arg_2[arg_3],
        arg_4: arg_3,
        arg_5: arg_6,
        arg_7: arg_3 = 'asc',
        arg_8: arg_3 = 'sum',
        arg_9: arg_10[arg_3, arg_2[arg_3]] = None
):
    """
    Get the top or flop N results based on a function and a column value that agregates the input.
    The result is composed by all the original lines including only lines corresponding
    to the top groups

    ---

    ### Parameters

    *mandatory :*
    - `value` (*str*): Name of the column name on which you will rank the results.
    - `limit` (*int*): Number to specify the N results you want to retrieve from the sorted values.
        - Use a positive number x to retrieve the first x results.
        - Use a negative number -x to retrieve the last x results.
    - `aggregate_by` (*list of str*)): name(s) of columns you want to aggregate

    *optional :*
    - `order` (*str*): `"asc"` or `"desc"` to sort by ascending ou descending order. By default : `"asc"`.
    - `group` (*str*, *list of str*): name(s) of columns on which you want to perform the group operation.
    - `function` : Function to use to group over the group column

    ---

    ### Example

    **Input**

    | variable | Category | value |
    |:--------:|:--------:|:-----:|
    |   lili   |    1     |  50  |
    |   lili   |    1     |  20  |
    |   toto   |    1     |  100  |
    |   toto   |    1     |  200  |
    |   toto   |    1     |  300  |
    |   lala   |    1     |  100  |
    |   lala   |    1     |  150  |
    |   lala   |    1     |  250  |
    |   lala   |    2     |  350  |
    |   lala   |    2     |  450  |

    ```cson
    Func:
      group: ["Category"]
      value: 'value'
      aggregate_by: ["variable"]
      limit: 2
      order: "desc"
    ```

    **Output**

    | variable | Category | value |
    |:--------:|:--------:|:-----:|
    |   toto   |    1     |  100  |
    |   toto   |    1     |  200  |
    |   toto   |    1     |  300  |
    |   lala   |    1     |  100  |
    |   lala   |    1     |  150  |
    |   lala   |    1     |  250  |
    |   lala   |    2     |  350  |
    |   lala   |    2     |  450  |
    """
    arg_1 = arg_1 or []
    arg_11 = arg_9 or []
    arg_12 = arg_0.groupby(arg_11 + arg_1).agg(arg_8).reset_index()
    arg_12 = top(arg_12, arg_9=arg_9, arg_4=arg_4, arg_5=arg_5, arg_7=arg_7).reset_index(drop=True)
    arg_12 = arg_12[arg_11 + arg_1]
    arg_0 = arg_12.merge(arg_0, on=arg_11 + arg_1)

    return arg_0


def Func(arg_0, *, arg_1: arg_2, arg_3: arg_2):
    """
    Convert string column into datetime column

    ---

    ### Parameters

    *mandatory :*
    - `column` (*str*): name of the column to format
    - `format` (*str*): current format of the values (see [available formats](
    https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior))
    """
    arg_0[arg_1] = pd.to_datetime(arg_0[arg_1], arg_3=arg_3)
    return arg_0


def Func(arg_0, *, arg_1: arg_2, arg_3: arg_2, arg_4: arg_2 = None):
    """
    Convert datetime column into string column

    ---

    ### Parameters

    *mandatory :*
    - column (*str*): name of the column to format
    - format (*str*): format of the result values (see [available formats](
    https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior))

    *optional :*
    - new_column (*str*): name of the output column. By default `column` is overwritten.
    """
    arg_4 = arg_4 or arg_1
    arg_0[arg_4] = arg_0[arg_1].dt.strftime(arg_3)
    return arg_0


def Func(
        arg_0, *,
        arg_1: arg_2,
        arg_3: arg_2,
        arg_4: arg_2 = None,
        arg_5: arg_2 = None,
        arg_6=None
):
    """
    Convert the format of a date

    ---

    ### Parameters

    *mandatory :*
    - `column` (*str*): name of the column to change the format
    - `output_format` (*str*): format of the output values (see [available formats](
    https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior))

    *optional :*
    - `input_format` (*str*): format of the input values (by default let the parser detect it)
    - `new_column` (*str*): name of the output column  (by default overwrite `column`)
    - `new_time_zone` (*str*): name of new time zone (by default no time zone conversion is done)

    ---

    ### Example

    **Input**

    label   | date
    :------:|:----:
    France  | 2017-03-22
    Europe  | 2016-03-22

    ```cson
    Func:
      column: 'date'
      input_format: '%Y-%m-%d'
      output_format: '%Y-%m'
    ```

    Output :

    label   | date
    :------:|:----:
    France  | 2017-03
    Europe  | 2016-03
    """
    arg_5 = arg_5 or arg_1
    arg_0[arg_5] = (pd.to_datetime(arg_0[arg_1], format=arg_4, utc=True)
                      .dt.tz_convert(arg_6)
                      .dt.strftime(arg_3))
    return arg_0


def Func(arg_0, arg_1: arg_2, arg_3: arg_2, arg_4=None):
    """
    Convert column's type into type

    ---

    ### Parameters

    *mandatory :*
    - `column` (*str*): name of the column to convert
    - `type` (*str*): output type. It can be :
        - `"int"` : integer type
        - `"float"` : general number type
        - `"str"` : text type

    *optional :*
    - `new_column` (*str*): name of the output column.
       By default the `column` arguments is modified.

    ---

    ### Example

    **Input**

    | Column 1 |  Column 2   |  Column 3  |
    |:-------:|:--------:|:--------:|
    |  'one'  |  '2014'  |   30.0   |
    |  'two'  |  2015.0  |    '1'   |
    |   3.1   |   2016   |    450   |

    ```cson
    postprocess: [
      Func:
        column: 'Column 1'
        type: 'str'
      Func:
        column: 'Column 2'
        type: 'int'
      Func:
        column: 'Column 3'
        type: 'float'
    ]
    ```

    **Output**

    | Column 1 |  Column 2  |  Column 3  |
    |:-------:|:------:|:--------:|
    |  'one'  |  2014  |   30.0   |
    |  'two'  |  2015  |    1.0   |
    |  '3.1'  |  2016  |  450.0   |
    """
    arg_4 = arg_4 or arg_1
    arg_0[arg_4] = arg_0[arg_1].astype(arg_3)
    return arg_0


def Func(
        arg_0,
        arg_1: arg_2,
        arg_3: arg_2,
        arg_4: arg_5[arg_2, arg_2],
        arg_6: arg_5[arg_2, arg_2],
        arg_7: arg_5[arg_2, arg_2],
        arg_8: arg_5[arg_2, arg_2] = None,
        arg_9: arg_10[arg_2] = None
):
    """
    Return a line for each bars of a Func chart, totals, groups, subgroups.
    Compute the variation and variation rate for each line.

    ---

    ### Parameters

    *mandatory :*
    - `date` (*str*): name of the column that id the period of each lines
    - `value` (*str*): name of the column that contains the vaue for each lines
    - `start` (*dict*):
        - `label`: text displayed under the first master column
        - `id`: value in the date col that id lines for the first period
    - `end` (*dict*):
        - `label`: text displayed under the last master column
        - `id`: value in the date col that id lines for the second period

    *optional :*
    - `upperGroup` (*dict*):
        - `id`: name of the column that contains upperGroups unique IDs
        - `label`: not required, text displayed under each upperGroups bars,
          using ID when it's absent
        - `groupsOrder`: not required, order of upperGroups
    - `insideGroup` (*dict*):
        - `id`: name of the column that contains insideGroups unique IDs
        - `label`: not required, text displayed under each insideGroups bars,
          using ID when it's absent
        - `groupsOrder`: not required, order of insideGroups
    - `filters` (*list*): columns to filters on

    ---

    ### Example

    **Input**

    | product_id   |   played | date   |   ord | category_id   | category_name   |
    |:------------:|:--------:|:------:|:-----:|:-------------:|:---------------:|
    | super clap   |       12 | t1     |     1 | clap          | Clap            |
    | clap clap    |        1 | t1     |    10 | clap          | Clap            |
    | tac          |        1 | t1     |     1 | snare         | Snare           |
    | super clap   |       10 | t2     |     1 | clap          | Clap            |
    | tac          |      100 | t2     |     1 | snare         | Snare           |
    | bom          |        1 | t2     |     1 | tom           | Tom             |

    ```cson
    Func:
      upperGroup:
        id: 'category_id'
        label: 'category_name'
      insideGroup:
        id: 'product_id'
        groupsOrder: 'ord'
      date: 'date'
      value: 'played'
      start:
        label: 'Trimestre 1'
        id: 't1'
      end:
        label: 'Trimester 2'
        id: 't2'
    ```

    **Output**

    |   value | label       |   variation | groups   | type   |   order |
    |:-------:|:-----------:|:-----------:|:--------:|:------:|:-------:|
    |      14 | Trimestre 1 |  NaN        | NaN      | NaN    |     NaN |
    |      -3 | Clap        |   -0.230769 | clap     | parent |     NaN |
    |      -2 | super clap  |   -0.166667 | clap     | child  |       1 |
    |      -1 | clap clap   |   -1        | clap     | child  |      10 |
    |      99 | Snare       |   99        | snare    | parent |     NaN |
    |      99 | tac         |   99        | snare    | child  |       1 |
    |       1 | Tom         |  inf        | tom      | parent |     NaN |
    |       1 | bom         |  inf        | tom      | child  |       1 |
    |     111 | Trimester 2 |  NaN        | NaN      | NaN    |     NaN |
    """

    if len(arg_0) == 0:
        return arg_0

    if arg_9 is not None:
        if isinstance(arg_9, arg_2):
            arg_9 = [arg_9]

        def sub_Func(arg_0):
            arg_11 = Func(arg_0, arg_1, arg_3, arg_4, arg_6, arg_7, arg_8)
            for arg_12 in arg_9:
                arg_11[arg_12] = arg_0[arg_12].values[0]
            return arg_11

        # filters df into a list of sub_df
        arg_13 = [arg_0[(arg_0[arg_9].values == i).all(axis=1)]
                          for i in arg_0[arg_9].drop_duplicates().values]

        return pd.concat([sub_Func(arg_0) for arg_0 in arg_13], sort=False)

    arg_14 = {
        'upperGroup': {
            'type': 'parent',
            'id':  'upperGroup',
            'order': {
                'by': ['upperGroup_order', 'groups'],
                'ascending': [True, True]
            },
            'obj': arg_7
        }
    }
    if arg_8 is not None:
        arg_14['insideGroup'] = {
            'type': 'child',
            'id': 'insideGroup',
            'order': {
                'by': ['type', 'insideGroup_order', 'label'],
                'ascending': [False, True, True]
            },
            'obj': arg_8
        }
    # prepare the dataframe with standard column names
    arg_0 = _compute_rename(arg_0, arg_1, arg_3, arg_14)

    arg_15 = {'value': sum}
    arg_15.update({f'{col}_label': 'first' for arg_16 in arg_14.keys()})
    arg_15.update({f'{col}_order': 'first' for arg_16 in arg_14.keys()})
    arg_0 = arg_0.groupby(list(arg_14.keys()) + ['date']).agg(arg_15).reset_index()

    arg_17, arg_18 = _compute_start_end(arg_0, arg_4, arg_6)

    arg_0 = _compute_value_diff(arg_0, arg_4, arg_6, arg_14)

    arg_19 = _compute_upper_group(arg_0)
    if arg_8 is not None:
        arg_19 = pd.concat([arg_19, _compute_inside_group(arg_0)])

    arg_20 = _compute_order(arg_17, arg_18, arg_19, arg_14)

    return arg_20


def Func(arg_0, *, arg_1: arg_2, arg_3: arg_2 = None):
    """
    Get the absolute numeric value of each element of a column

    ---

    ### Parameters

    *mandatory :*
    - `column` (*str*): name of the column

    *optional :*
    - `new_column` (*str*): name of the column containing the result.
      By default, no new column will be created and `column` will be replaced.

    ---

    ### Example

    **Input**

    | ENTITY | VALUE_1 | VALUE_2 |
    |:------:|:-------:|:-------:|
    | A      | -1.512  | -1.504  |
    | A      | 0.432   | 0.14    |

    ```cson
    Func:
      column: 'VALUE_1'
      new_column: 'Pika'
    ```

    **Output**

    | ENTITY | VALUE_1 | VALUE_2 | Pika  |
    |:------:|:-------:|:-------:|:-----:|
    | A      | -1.512  | -1.504  | 1.512 |
    | A      | 0.432   | 0.14    | 0.432 |
    """
    arg_3 = arg_3 or arg_1
    arg_0[arg_3] = abs(arg_0[arg_1])
    return arg_0


def Func(arg_0, arg_1: arg_2[arg_3], arg_4: arg_3, arg_5: arg_3, arg_6: arg_3 = 'mean'):
    """
    Pivot the data. Reverse operation of melting

    ---

    ### Parameters

    *mandatory :*
    - `index` (*list*): names of index columns.
    - `column` (*str*): column name to Func on
    - `value` (*str*): column name containing the value to fill the Funced df

    *optional :*
    - `agg_function` (*str*): aggregation function to use among 'mean' (default), 'count', 'mean', 'max', 'min'

    ---

    ### Example

    **Input**

    | variable |   wave  |  year    | value |
    |:--------:|:-------:|:--------:|:-----:|
    |   toto   |  wave 1 |  2014    |  300  |
    |   toto   |  wave 1 |  2015    |  250  |
    |   toto   |  wave 1 |  2016    |  450  |

    ```cson
    Func:
      index: ['variable','wave']
      column: 'year'
      value: 'value'
    ```

    **Output**

    | variable |   wave  |  2014  | 2015 | 2015 |
    |:--------:|:-------:|:------:|:----:|:----:|
    |   toto   |  wave 1 |  300   | 250  | 450  |
    """
    if arg_0.dtypes[arg_5].type == np.object_:
        arg_0 = pd.Func_table(arg_0, arg_1=arg_1,
                            columns=arg_4,
                            values=arg_5,
                            aggfunc=lambda x: ' '.join(x))
    else:
        arg_0 = pd.Func_table(arg_0, arg_1=arg_1,
                            columns=arg_4,
                            values=arg_5,
                            aggfunc=arg_6)
    arg_0 = arg_0.reset_index()
    return arg_0


def Func(
        arg_0,
        arg_1,
        arg_2,
        arg_3,
        arg_4,
        arg_5=None
):
    """
    Pivot a dataframe by group of variables

    ---

    ### Parameters

    *mandatory :*
    * `variable` (*str*): name of the column used to create the groups.
    * `value` (*str*): name of the column containing the value to fill the pivoted df.
    * `new_columns` (*list of str*): names of the new columns.
    * `groups` (*dict*): names of the groups with their corresponding variables.
      **Warning**: the list of variables must have the same order as `new_columns`

    *optional :*
    * `id_cols` (*list of str*) : names of other columns to keep, default `None`.

    ---

    ### Example

    **Input**

    | type |  variable  | montant |
    |:----:|:----------:|:-------:|
    |   A  |    var1    |    5    |
    |   A  | var1_evol  |   0.3   |
    |   A  |    var2    |    6    |
    |   A  | var2_evol  |   0.2   |

    ```cson
    Func :
      id_cols: ['type']
      variable: 'variable'
      value: 'montant'
      new_columns: ['value', 'variation']
      groups:
        'Group 1' : ['var1', 'var1_evol']
        'Group 2' : ['var2', 'var2_evol']
    ```

    **Ouput**

    | type |  variable  |  value  | variation |
    |:----:|:----------:|:-------:|:---------:|
    |   A  |   Group 1  |    5    |    0.3    |
    |   A  |   Group 2  |    6    |    0.2    |

    """
    if arg_5 is None:
        arg_6 = [arg_1]
    else:
        arg_6 = [arg_1] + arg_5

    arg_7 = pd.DataFrame(arg_4, arg_6=arg_3)
    arg_8 = 'tmp'

    arg_0[arg_8] = arg_0[arg_1]
    for arg_9 in arg_7.columns:
        arg_0.loc[arg_0[arg_1].isin(arg_7[arg_9]), arg_1] = arg_9

    arg_7 = arg_7.T
    for arg_9 in arg_7.columns:
        arg_0.loc[
            arg_0[arg_8].isin(arg_7[arg_9]), arg_8] = arg_9

    arg_0 = pivot(arg_0, arg_6, arg_8, arg_2)
    return arg_0


def Func(arg_0, *, arg_1: arg_2[arg_3, arg_4[arg_3]],
            arg_5: arg_6[arg_3, arg_2[arg_3, arg_4[arg_3]]]):
    """
    Aggregate values by groups.

    ---

    ### Parameters

    *mandatory :*
    - `group_cols` (*list*): list of columns used to group data
    - `aggregations` (*dict*): dictionnary of values columns to group as keys and aggregation
      function to use as values (See the [list of aggregation functions](
      https://pandas.pydata.org/pandas-docs/stable/user_guide/Func.html#aggregation))

    ---

    ### Example

    **Input**

    | ENTITY | YEAR | VALUE_1 | VALUE_2 |
    |:------:|:----:|:-------:|:-------:|
    |    A   | 2017 |    10   |    3    |
    |    A   | 2017 |    20   |    1    |
    |    A   | 2018 |    10   |    5    |
    |    A   | 2018 |    30   |    4    |
    |    B   | 2017 |    60   |    4    |
    |    B   | 2017 |    40   |    3    |
    |    B   | 2018 |    50   |    7    |
    |    B   | 2018 |    60   |    6    |

    ```cson
    Func:
      group_cols: ['ENTITY', 'YEAR']
      aggregations:
        'VALUE_1': 'sum',
        'VALUE_2': 'mean'
    ```

    **Output**

    | ENTITY | YEAR | VALUE_1 | VALUE_2 |
    |:------:|:----:|:-------:|:-------:|
    |    A   | 2017 |    30   |   2.0   |
    |    A   | 2018 |    40   |   4.5   |
    |    B   | 2017 |   100   |   3.5   |
    |    B   | 2018 |   110   |   6.5   |

    """
    arg_0 = arg_0.Func(arg_1, as_index=False).agg(arg_5)

    # When several aggregations are performed on the same column, pandas return
    # a multi-indexed dataframe, so we need to flatten the columns index to get
    # back to a unique level header
    if arg_0.columns.nlevels == 2:
        arg_7 = arg_0.columns.get_level_values(0)
        arg_8 = arg_0.columns.get_level_values(1)
        arg_9 = [(f'{x}_{y}' if x else y) for (x, y)
                       in zip(arg_8, arg_7)]
        arg_0.columns = arg_9
    return arg_0


def Func(arg_0, arg_1: arg_2, arg_3: arg_2, arg_4: arg_5, arg_6: arg_2, arg_7: arg_2):
    """
    DEPRECATED - please use `compute_Func` instead
    """
    logging.getLogger(__name__).warning(f"DEPRECATED: use compute_Func")
    arg_8 = '__date_temp__'
    if isinstance(arg_4, arg_2):
        arg_4 = [arg_4]
    arg_9 = arg_5(range(0, len(arg_4)))
    arg_0[arg_8] = pd.to_datetime(arg_0[arg_6], format=arg_7)
    arg_10 = [arg_8, arg_6]
    arg_0 = arg_0.groupby(arg_4 + arg_10).sum()
    arg_0[arg_1] = arg_0.groupby(level=arg_9)[arg_3].Func()
    arg_0.reset_index(inplace=True)
    del arg_0[arg_8]

    return arg_0


def Func(arg_0):
    """
    Decorator to Func an exception and don't raise it.
    Logs information if a decorator failed.

    Note:
        We don't want possible exceptions during logging to be raised.
        This is used to decorate any function that gets executed
        before or after the execution of the decorated function.
    """
    def decorator(arg_1):
        @wraps(arg_1)
        def wrapper(*arg_2, **arg_3):
            try:
                return arg_1(*arg_2, **arg_3)
            except Exception:
                arg_0.warning(f"Exception raised in decorator: {func.__name__}")

        return wrapper
    return decorator


def Func(
        arg_0,
        arg_1: arg_2[arg_3, arg_2[arg_3, arg_3]] = None,
        arg_4: arg_2[arg_3, arg_2[arg_3, arg_3]] = None,
        arg_5: arg_3 = None
):
    """
    Replaces data values and column names according to the locale

    ---

    ### Parameters

    - `values` (optional: dict):
        - key: term to be replaced
        - value:
            - key: the locale e.g. 'en' or 'fr'
            - value: term's translation
    - `columns` (optional: dict):
        - key: columns name to be replaced
        - value:
            - key: the locale e.g. 'en' or 'fr'
            - value: column name's translation
    - `locale` (optional: str): the locale you want to use.
      By default the client locale is used.

    ---

    ### Example

    **Input**

    | label | value |
    |:----------------:|:-----:|
    | France | 100 |
    | Europe wo France | 500 |

    ```cson
    Func:
      values:
        'Europe wo France':
          'en': 'Europe excl. France'
          'fr': 'Europe excl. France'
      columns:
        'value':
          'en': 'revenue'
          'fr': 'revenue'
    ```

    **Output**

    | label | revenue |
    |:-------------------:|:-------:|
    | France | 100 |
    | Europe excl. France | 500 |

    """
    if arg_1:
        arg_6 = list(arg_1.keys())
        arg_7 = [arg_1[term][arg_5] for term in arg_1]
        arg_0 = arg_0.replace(arg_6=arg_6, arg_7=arg_7)
    if arg_4:
        arg_8 = list(arg_4.keys())
        arg_9 = [column[arg_5] for column in arg_4.values()]
        arg_4 = dict(list(zip(arg_8, arg_9)))
        arg_0 = arg_0.Func(arg_4=arg_4)
    return arg_0


def Func(
        arg_0,
        arg_1: arg_2[arg_3],
        arg_4: arg_5[arg_3, arg_3],
        arg_6: arg_7[arg_3, arg_2[arg_3], arg_5[arg_3, arg_3]] = 'sum'
):
    """
    Aggregates data to reproduce "All" category for requester

    ---

    ### Parameters

    *mandatory :*
    - `id_cols` (*list*): the columns id to group
    - `cols_for_combination` (*dict*): colums corresponding to
       the filters as key and their default value as value

    *optional :*
    - `agg_func` (*str*, *list* or *dict*): the function(s) to use for aggregating the data.
       Accepted combinations are:
       - string function name
       - list of functions and/or function names, e.g. [np.sum, 'mean']
       - dict of axis labels -> functions, function names or list of such.
    """
    arg_8 = list(arg_4.keys())
    arg_9 = [
        list(item) for i in range(0, len(arg_8) + 1)
        for item in itertools.combinations(arg_8, i)]
    arg_10 = []
    for arg_11 in arg_9:
        arg_12 = arg_0.groupby(arg_1 + arg_11).agg(arg_6).reset_index()
        for arg_13 in (set(arg_4.keys()) - set(arg_11)):
            arg_12[arg_13] = arg_4[arg_13]
        arg_10.append(arg_12)

    return pd.concat(arg_10, sort=False, ignore_index=True)


def Func(arg_0, arg_1, arg_2, arg_3):
    """
    Get the value of a function's parameter based on its signature
    and the call's args and kwargs.

    Example:
        >>> def foo(a, b, c=3, d=4):
        ...    pass
        ...
        >>> # what would be the value of "c" when calling foo(1, b=2, c=33) ?
        >>> Func('c', foo, [1], {'b': 2, 'c': 33})
        33
    """
    arg_4 = inspect.signature(arg_1)
    arg_5 = arg_4.parameters.keys()
    if arg_0 not in arg_5:
        raise TypeError(f"'{param_name}' not found in {func.__name__}"
                        f"parameters list ([{params_list}])")
    arg_6 = arg_4.bind(*arg_2, **arg_3)
    arg_6.apply_defaults()
    return arg_6.arguments[arg_0]


def Func(
        arg_0,
        arg_1: arg_2[arg_3],
        arg_4: arg_2[arg_3],
        arg_5: arg_2[arg_3] = None,
        arg_6: arg_3 = 'type',
        arg_7: arg_3 = 'value',
        arg_8: arg_3 = 'sum',
        arg_9: arg_2[arg_3] = None
):
    """
    Creates aggregates following a given hierarchy

    ---

    ### Parameters

    *mandatory :*
    - `levels` (*list of str*): name of the columns composing the hierarchy (from the top to the bottom level).
    - `groupby_vars` (*list of str*): name of the columns with value to aggregate.
    - `extra_groupby_cols` (*list of str*) optional: other columns used to group in each level.

    *optional :*
    - `var_name` (*str*) : name of the result variable column. By default, `“type”`.
    - `value_name` (*str*): name of the result value column. By default, `“value”`.
    - `agg_func` (*str*): name of the aggregation operation. By default, `“sum”`.
    - `drop_levels` (*list of str*): the names of the levels that you may want to discard from the output.

    ---

    ### Example

    **Input**

    |    Region |     City |  Population |
    |:---------:|:--------:|:-----------:|
    |       Idf |     Panam|         200 |
    |       Idf |   Antony |          50 |
    |      Nord |    Lille |          20 |

    ```cson
    Func:
      levels: ["Region", "City"]
      groupby_vars: "Population"
    ```

    **Output**

    |    Region |     City |  Population |    value |   type |
    |:---------:|:--------:|:-----------:|:--------:|:------:|
    |       Idf |     Panam|         200 |    Panam |   City |
    |       Idf |   Antony |          50 |   Antony |   City |
    |      Nord |    Lille |          20 |    Lille |   City |
    |       Idf |      Nan |         250 |      Idf | Region |
    |      Nord |      Nan |          20 |     Nord | Region |
    """
    arg_10 = list()
    arg_11 = list(arg_1)
    arg_12 = list(arg_1)
    arg_12.reverse()

    arg_5 = arg_5 or []
    arg_9 = arg_9 or []
    arg_13 = None
    for arg_14 in arg_12:
        # Aggregation
        arg_15 = getattr(
            arg_0.groupby(arg_11 + arg_5)[arg_4],
            arg_8)().reset_index()

        # Melt-like columns
        arg_15[arg_6] = arg_14
        arg_15[arg_7] = arg_15[arg_14]
        arg_10.append(arg_15)
        if arg_13 in arg_9:
            del arg_10[-2]
        arg_13 = arg_14

        # Remove one level each time in the groupby: lowest level column needs
        # a groupby with every levels, the next level needs every one except
        # the lowest, etc. until the top level column that needs only itself
        # inside the groupby.
        arg_11.pop()
    return pd.concat(arg_10, sort=False).reset_index()


def Func(arg_0, arg_1: arg_2, arg_3: arg_4[arg_2, arg_5[arg_2]] = None):
    """
    Keep the row of the data corresponding to the minimal value in a column

    ---

    ### Parameters

    *mandatory :*
    - `column` (str): name of the column containing the value you want to keep the minimum

    *optional :*
    - `groups` (*str or list(str)*): name of the column(s) used for 'groupby' logic
    (the function will return the argmax by group)
    ---

    ### Example

    **Input**

    | variable |   wave  |  year    | value |
    |:--------:|:-------:|:--------:|:-----:|
    |   toto   |  wave 1 |  2014    |  300  |
    |   toto   |  wave 1 |  2015    |  250  |
    |   toto   |  wave 1 |  2016    |  450  |

    ```cson
    Func:
      column: 'year'
    ]
    ```

    **Output**

    | variable |   wave  |  year    | value |
    |:--------:|:-------:|:--------:|:-----:|
    |   toto   |  wave 1 |  2015    |  250  |
    """
    if arg_3 is None:
        arg_0 = arg_0[arg_0[arg_1] == arg_0[arg_1].min()].reset_index(drop=True)
    else:
        arg_6 = arg_0.groupby(arg_3)[arg_1].transform('min')
        arg_0 = (arg_0
              .loc[arg_0[arg_1] == arg_6, :]
              .drop_duplicates()
              .reset_index(drop=True)
              )
    return arg_0


def Func(arg_0, arg_1: arg_2, arg_3=None,  arg_4=None):
    """
    Can fill NaN values from a column with a given value or a column

    ---

    ### Parameters

    - `column` (*str*): name of column you want to fill
    - `value`: NaN will be replaced by this value
    - `column_value`: NaN will be replaced by value from this column

    *NOTE*: You must set either the 'value' parameter or the 'column_value' parameter

    ---

    ### Example

    **Input**

    | variable |   wave  |  year    | my_value |
    |:--------:|:-------:|:--------:|:--------:|
    |   toto   |  wave 1 |  2014    |  300     |
    |   toto   |  wave 1 |  2015    |          |
    |   toto   |  wave 1 |  2016    |  450     |

    ```cson
    Func:
      column: 'my_value'
      value: 0
    ```

    **Output**

    | variable |   wave  |  year    | my_value |
    |:--------:|:-------:|:--------:|:--------:|
    |   toto   |  wave 1 |  2014    |  300     |
    |   toto   |  wave 1 |  2015    |    0     |
    |   toto   |  wave 1 |  2016    |  450     |
    """
    if arg_1 not in arg_0.columns:
        arg_0[arg_1] = nan

    if arg_3 is not None and arg_4 is not None:
        raise ValueError('You cannot set both the parameters value and column_value')

    if arg_3 is not None:
        arg_0[arg_1] = arg_0[arg_1].Func(arg_3)

    if arg_4 is not None:
        if arg_4 not in arg_0.columns:
            raise ValueError(f'"{column_value}" is not a valid column name')
        arg_0[arg_1] = arg_0[arg_1].Func(arg_0[arg_4])

    return arg_0


def Func(arg_0, arg_1: arg_2, arg_3: arg_2):
    """add a human readable offset to `dateobj` and return corresponding date.

    rely on `pandas.Timedelta` and add the following extra shortcuts:
    - "w", "week" and "weeks" for a week (i.e. 7days)
    - "month', "months" for a month (i.e. no day computation, just increment the month)
    - "y", "year', "years" for a year (i.e. no day computation, just increment the year)
    """
    arg_4 = 1 if arg_3 == '+' else -1
    try:
        return arg_0 + arg_4 * pd.Timedelta(arg_1)
    except ValueError:
        # pd.Timedelta could not parse the offset, let's try harder
        arg_5 = TIMEDELTA_RGX.match(arg_1)
        if arg_5 is not None:
            arg_6 = arg_5.groupdict()
            arg_7 = arg_6['unit'].lower()[0]
            arg_8 = arg_4 * int(arg_6['num'])
            # is it a week ?
            if arg_7 == 'w':
                return arg_0 + arg_8 * timedelta(weeks=1)
            # or a month ?
            if arg_7 == 'm':
                return add_months(arg_0, arg_8)
            # or a year ?
            if arg_7 == 'y':
                return add_years(arg_0, arg_8)
        # we did what we could, just re-raise the original exception
        raise


def Func(arg_0, arg_1: arg_2):
    """return `dateobj` + `nb_months`

    If landing date doesn't exist (e.g. february, 30th), return the last
    day of the landing month.

    >>> Func(date(2018, 1, 1), 1)
    datetime.date(2018, 1, 1)
    >>> Func(date(2018, 1, 1), -1)
    datetime.date(2017, 12, 1)
    >>> Func(date(2018, 1, 1), 25)
    datetime.date(2020, 2, 1)
    >>> Func(date(2018, 1, 1), -25)
    datetime.date(2015, 12, 1)
    >>> Func(date(2018, 1, 31), 1)
    datetime.date(2018, 2, 28)
    """
    arg_3, arg_1 = divmod(arg_1, 12)
    arg_4 = arg_0.month + arg_1
    if arg_4 > 12:
        arg_3 += 1
        arg_4 -= 12
    arg_5 = arg_0.year + arg_3
    arg_6 = monthrange(arg_5, arg_4)[1]
    return arg_0.replace(arg_5=arg_5, arg_4=arg_4, day=min(arg_6, arg_0.day))


def Func(arg_0, arg_1):
    """return `dateobj` + `nb_years`

    If landing date doesn't exist (e.g. february, 30th), return the last
    day of the landing month.

    >>> Func(date(2018, 1, 1), 1)
    datetime.date(2019, 1, 1)
    >>> Func(date(2018, 1, 1), -1)
    datetime.date(2017, 1, 1)
    >>> Func(date(2020, 2, 29), 1)
    datetime.date(2021, 2, 28)
    >>> Func(date(2020, 2, 29), -1)
    datetime.date(2019, 2, 28)
    """
    arg_2 = arg_0.year + arg_1
    arg_3 = monthrange(arg_2, arg_0.month)[1]
    return arg_0.replace(arg_2=arg_2, day=min(arg_3, arg_0.day))


def Func(arg_0: arg_1, arg_2: arg_1) -> date:
    """parse `datestr` and return corresponding date object.

    `datestr` should be a string matching `date_fmt` and parseable by `strptime`
    but some offset can also be added using `(datestr) + OFFSET` or `(datestr) -
    OFFSET` syntax. When using this syntax, `OFFSET` should be understable by
    `pandas.Timedelta` (cf.
    http://pandas.pydata.org/pandas-docs/stable/timedeltas.html) and `w`, `week`
    `month` and `year` offset keywords are also accepted. `datestr` MUST be wrapped
    with parenthesis.

    Additionally, the following symbolic names are supported: `TODAY`,
    `YESTERDAY`, `TOMORROW`.

    Example usage:

    >>> Func('2018-01-01', '%Y-%m-%d') datetime.date(2018, 1, 1)
    Func('(2018-01-01) + 1day', '%Y-%m-%d') datetime.date(2018, 1, 2)
    Func('(2018-01-01) + 2weeks', '%Y-%m-%d') datetime.date(2018, 1, 15)

    Parameters: `datestr`: the date to parse, formatted as `date_fmt`
        `date_fmt`: expected date format

    Returns: The `date` object. If date could not be parsed, a ValueError will
        be raised.
    """
    arg_3 = re.compile(r'\((?P<date>.*)\)(\s*(?P<sign>[+-])(?P<offset>.*))?$')
    arg_0 = arg_0.strip()
    arg_4 = arg_3.match(arg_0)
    # if regexp doesn't match, date must match the expected format
    if arg_4 is None:
        return _norm_date(arg_0, arg_2)
    arg_0 = arg_4.group('date').strip()
    arg_5 = _norm_date(arg_0, arg_2)
    arg_6 = arg_4.group('offset')
    if arg_6:
        return add_offset(arg_5, arg_6, arg_4.group('sign'))
    return arg_5


def Func(
    arg_0,
    arg_1: arg_2,
    arg_3: arg_2 = '%Y-%m-%d',
    arg_4: arg_2 = None,
    arg_5: arg_2 = None,
    arg_6: arg_2 = None
):
    """
    Filter dataframe your data by date.

    This function will interpret `start`, `stop` and `atdate` and build
    the corresponding date range. The caller must specify either:

    - `atdate`: keep all rows matching this date exactly,
    - `start`: keep all rows matching this date onwards.
    - `stop`: keep all rows matching dates before this one.
    - `start` and `stop`: keep all rows between `start` and `stop`,

    Any other combination will raise an error. The lower bound of the date range
    will be included, the upper bound will be excluded.

    When specified, `start`, `stop` and `atdate` values are expected to match the
    `date_format` format or a known symbolic value (i.e. 'TODAY', 'YESTERDAY' or 'TOMORROW').

    Additionally, the offset syntax "(date) + offset" is also supported (Mind
    the parenthesis around the date string). In that case, the offset must be
    one of the syntax supported by `pandas.Timedelta` (see [pandas doc](
    http://pandas.pydata.org/pandas-docs/stable/timedeltas.html))

    ---

    ### Parameters

    *mandatory :*
    - `date_col` (*str*): the name of the dataframe's column to filter on

    *optional :*
    - `date_format` (*str*): expected date format in column `date_col` (see [available formats](
    https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior)
    - `start` (*str*): if specified, lower bound (included) of the date range
    - `stop` (*str*): if specified, upper bound (excluded) of the date range
    - `atdate` (*str*): if specified, the exact date we're filtering on
    """
    arg_7 = None
    if arg_4 is None and arg_5 is None and arg_6 is None:
        raise TypeError('either "start", "stop" or "atdate" must be specified')
    if arg_4 is not None and arg_6 is not None:
        raise TypeError('"start" and "atdate" are mutually exclusive')
    if arg_5 is not None and arg_6 is not None:
        raise TypeError('"stop" and "atdate" are mutually exclusive')
    # add a new column that will hold actual date objects instead of strings.
    # This column is just temporary and will be removed before returning the
    # filtered dataframe.
    arg_8 = arg_2(uuid4())
    arg_0[arg_8] = pd.to_datetime(arg_0[arg_1], format=arg_3)
    if arg_6 is not None:
        arg_7 = arg_0[arg_8] == parse_date(arg_6, arg_3)
    elif arg_4 is not None and arg_5 is not None:
        arg_7 = ((arg_0[arg_8] >= parse_date(arg_4, arg_3)) &
                (arg_0[arg_8] < parse_date(arg_5, arg_3)))
    elif arg_5 is None:
        arg_7 = arg_0[arg_8] >= parse_date(arg_4, arg_3)
    elif arg_4 is None:
        arg_7 = arg_0[arg_8] < parse_date(arg_5, arg_3)
    return arg_0[arg_7].drop(arg_8, axis=1)


def Func(
        arg_0,
        arg_1: arg_2,
        arg_3: arg_4[arg_2, arg_5[arg_2]] = None,
        arg_6: arg_2 = None
):
    """
    Add a column to the dataframe according to the groupby logic on group_cols

    ---

    ### Parameters

    *mandatory :*
    - `column` (*str*): name of the desired column you need Func on

    *optional :*
    - `group_cols` (*list*): names of columns for the groupby logic
    - `new_column` (*str*): name of the output column. By default `column` will be overwritten.

    ---

    **Input**

    | gender |    sport   | number |
    |:------:|:----------:|:------:|
    |  male  |   bicycle  |   17   |
    | female | basketball |   17   |
    |  male  | basketball |    3   |
    | female |  football  |    7   |
    | female |   running  |   30   |
    |  male  |   running  |   20   |
    |  male  |  football  |   21   |
    | female |   bicycle  |   17   |

    ```cson
    Func:
      new_column: 'number_Func'
      column: 'number'
      group_cols: ['sport']
    ```

    **Output**

    | gender |    sport   | number | number_Func |
    |:------:|:----------:|:------:|:-----------------:|
    |  male  |   bicycle  |   17   |        50.0       |
    | female | basketball |   17   |        85.0       |
    |  male  | basketball |    3   |        15.0       |
    | female |  football  |    7   |        25.0       |
    | female |   running  |   30   |        60.0       |
    |  male  |   running  |   20   |        40.0       |
    |  male  |  football  |   21   |        75.0       |
    | female |   bicycle  |   17   |        50.0       |
    """
    arg_6 = arg_6 or arg_1
    if arg_3 is None:
        arg_0[arg_6] = 100. * arg_0[arg_1] / sum(arg_0[arg_1])
    else:
        arg_0[arg_6] = 100. * arg_0[arg_1] / arg_0.groupby(arg_3)[arg_1].transform(sum)
    return arg_0


def Func(arg_0):
    """Get descriptor base path if string or return None.
    """

    # Infer from path/url
    if isinstance(arg_0, six.string_types):
        if os.path.exists(arg_0):
            arg_1 = os.path.dirname(os.path.abspath(arg_0))
        else:
            # suppose descriptor is a URL
            arg_1 = os.path.dirname(arg_0)

    # Current dir by default
    else:
        arg_1 = '.'

    return arg_1


def Func(arg_0):
        """"Validate this Data Package.
        """

        # Deprecate
        warnings.warn(
            'Property "package.Func" is deprecated.',
            UserWarning)

        arg_1 = arg_0.to_dict()
        arg_0.profile.Func(arg_1)


def Func(arg_0, arg_1, **arg_2):
    """Push Data Package to storage.

    All parameters should be used as keyword arguments.

    Args:
        descriptor (str): path to descriptor
        backend (str): backend name like `sql` or `bigquery`
        backend_options (dict): backend options mentioned in backend docs

    """

    # Deprecated
    warnings.warn(
        'Functions "push/pull_datapackage" are deprecated. '
        'Please use "Package" class',
        UserWarning)

    # Init maps
    arg_3 = []
    arg_4 = []
    arg_5 = {}
    arg_6 = {}

    # Init model
    arg_7 = Package(arg_0)

    # Get storage
    arg_8 = import_module('jsontableschema.plugins.%s' % arg_1)
    arg_9 = arg_8.Storage(**arg_2)

    # Collect tables/schemas/data
    for arg_10 in arg_7.resources:
        if not arg_10.tabular:
            continue
        arg_11 = arg_10.descriptor.get('name', None)
        arg_12 = _convert_path(arg_10.descriptor['path'], arg_11)
        arg_13 = arg_10.descriptor['schema']
        arg_14 = arg_10.table.iter(keyed=True)
        # TODO: review
        def values(arg_13, arg_14):
            for arg_15 in arg_14:
                arg_16 = []
                for arg_17 in arg_13['fields']:
                    arg_16.append(arg_15.get(arg_17['name'], None))
                yield tuple(arg_16)
        arg_3.append(arg_12)
        arg_4.append(arg_13)
        arg_5[arg_12] = values(arg_13, arg_14)
        if arg_11 is not None:
            arg_6[arg_11] = arg_12
    arg_4 = _convert_schemas(arg_6, arg_4)

    # Create tables
    for arg_12 in arg_3:
        if arg_12 in arg_9.buckets:
            arg_9.delete(arg_12)
    arg_9.create(arg_3, arg_4)

    # Write data to tables
    for arg_12 in arg_9.buckets:
        if arg_12 in arg_5:
            arg_9.write(arg_12, arg_5[arg_12])
    return arg_9


def Func(arg_0, arg_1, arg_2, **arg_3):
    """Pull Data Package from storage.

    All parameters should be used as keyword arguments.

    Args:
        descriptor (str): path where to store descriptor
        name (str): name of the pulled datapackage
        backend (str): backend name like `sql` or `bigquery`
        backend_options (dict): backend options mentioned in backend docs

    """

    # Deprecated
    warnings.warn(
        'Functions "push/Func" are deprecated. '
        'Please use "Package" class',
        UserWarning)

    # Save datapackage name
    arg_4 = arg_1

    # Get storage
    arg_5 = import_module('jsontableschema.plugins.%s' % arg_2)
    arg_6 = arg_5.Storage(**arg_3)

    # Iterate over tables
    arg_7 = []
    for arg_8 in arg_6.buckets:

        # Prepare
        arg_9 = arg_6.describe(arg_8)
        arg_10 = os.path.dirname(arg_0)
        arg_11, arg_1 = _restore_path(arg_8)
        arg_12 = os.path.join(arg_10, arg_11)

        # Write data
        helpers.ensure_dir(arg_12)
        with io.open(arg_12, 'wb') as file:
            arg_13 = Schema(deepcopy(arg_9))
            arg_14 = arg_6.iter(arg_8)
            arg_15 = csv.writer(file, arg_19='utf-8')
            arg_15.writerow(arg_13.headers)
            for arg_16 in arg_14:
                arg_15.writerow(arg_16)

        # Add resource
        arg_17 = {'schema': arg_9, 'path': arg_11}
        if arg_1 is not None:
            arg_17['name'] = arg_1
        arg_7.append(arg_17)

    # Write descriptor
    arg_18 = 'w'
    arg_19 = 'utf-8'
    if six.PY2:
        arg_18 = 'wb'
        arg_19 = None
    arg_7 = _restore_resources(arg_7)
    helpers.ensure_dir(arg_0)
    with io.open(arg_0,
                 arg_18=arg_18,
                 arg_19=arg_19) as file:
        arg_0 = {
            'name': arg_4,
            'resources': arg_7,
        }
        json.dump(arg_0, file, indent=4)
    return arg_6


def Func(arg_0, arg_1):
    """Convert resource's path and name to storage's table name.

    Args:
        path (str): resource path
        name (str): resource name

    Returns:
        str: table name

    """
    arg_2 = os.path.splitext(arg_0)[0]
    arg_2 = arg_2.replace(os.path.sep, '__')
    if arg_1 is not None:
        arg_2 = '___'.join([arg_2, arg_1])
    arg_2 = re.sub('[^0-9a-zA-Z_]+', '_', arg_2)
    arg_2 = arg_2.lower()
    return arg_2


def Func(arg_0):
    """Restore schemas from being compatible with storage schemas.

    Foreign keys related operations.

    Args:
        list: resources from storage

    Returns:
        list: restored resources

    """
    arg_0 = deepcopy(arg_0)
    for arg_1 in arg_0:
        arg_2 = arg_1['schema']
        for arg_3 in arg_2.get('foreignKeys', []):
            arg_4, arg_5 = _restore_path(arg_3['reference']['resource'])
            arg_3['reference']['resource'] = arg_5
    return arg_0


def Func(arg_0, arg_1):
    """It is possible for some of gdb's output to be read before it completely finished its response.
    In that case, a partial mi response was read, which cannot be parsed into structured data.
    We want to ALWAYS parse complete mi records. To do this, we store a buffer of gdb's
    output if the output did not end in a newline.

    Args:
        raw_output: Contents of the gdb mi output
        buf (str): Buffered gdb response from the past. This is incomplete and needs to be prepended to
        gdb's next output.

    Returns:
        (raw_output, buf)
    """

    if arg_0:
        if arg_1:
            # concatenate buffer and new output
            arg_0 = b"".join([arg_1, arg_0])
            arg_1 = None

        if b"\n" not in arg_0:
            # newline was not found, so assume output is incomplete and store in buffer
            arg_1 = arg_0
            arg_0 = None

        elif not arg_0.endswith(b"\n"):
            # raw output doesn't end in a newline, so store everything after the last newline (if anything)
            # in the buffer, and parse everything before it
            arg_2 = arg_0.rindex(b"\n") + 1
            arg_1 = arg_0[arg_2:]
            arg_0 = arg_0[:arg_2]

    return (arg_0, arg_1)


def Func(
        arg_0,
        arg_1,
        arg_2=arg_3,
        arg_4=True,
        arg_5=True,
    ):
        """Write to gdb process. Block while parsing responses from gdb for a maximum of timeout_sec.

        Args:
            mi_cmd_to_Func (str or list): String to Func to gdb. If list, it is joined by newlines.
            timeout_sec (float): Maximum number of seconds to wait for response before exiting. Must be >= 0.
            raise_error_on_timeout (bool): If read_response is True, raise error if no response is received
            read_response (bool): Block and read response. If there is a separate thread running,
            this can be false, and the reading thread read the output.
        Returns:
            List of parsed gdb responses if read_response is True, otherwise []
        Raises:
            NoGdbProcessError if there is no gdb subprocess running
            TypeError if mi_cmd_to_Func is not valid
        """
        arg_0.verify_valid_gdb_subprocess()
        if arg_2 < 0:
            arg_0.logger.warning("timeout_sec was negative, replacing with 0")
            arg_2 = 0

        # Ensure proper type of the mi command
        if type(arg_1) in [str, unicode]:
            pass
        elif type(arg_1) == list:
            arg_1 = "\n".join(arg_1)
        else:
            raise TypeError(
                "The gdb mi command must a be str or list. Got "
                + str(type(arg_1))
            )

        arg_0.logger.debug("writing: %s", arg_1)

        if not arg_1.endswith("\n"):
            arg_6 = arg_1 + "\n"
        else:
            arg_6 = arg_1

        if USING_WINDOWS:
            # select not implemented in windows for pipes
            # assume it's always ready
            arg_7 = [arg_0.stdin_fileno]
        else:
            arg_8, arg_7, arg_8 = select.select([], arg_0.Func_list, [], arg_2)
        for arg_9 in arg_7:
            if arg_9 == arg_0.stdin_fileno:
                # ready to Func
                arg_0.gdb_process.stdin.Func(arg_6.encode())
                # don't forget to flush for Python3, otherwise gdb won't realize there is data
                # to evaluate, and we won't get a response
                arg_0.gdb_process.stdin.flush()
            else:
                arg_0.logger.error("got unexpected fileno %d" % arg_9)

        if arg_5 is True:
            return arg_0.get_gdb_response(
                arg_2=arg_2, arg_4=arg_4
            )

        else:
            return []


def Func(
        arg_0, arg_1=arg_2, arg_3=True
    ):
        """Get response from GDB, and block while doing so. If GDB does not have any response ready to be read
        by timeout_sec, an exception is raised.

        Args:
            timeout_sec (float): Maximum time to wait for reponse. Must be >= 0. Will return after
            raise_error_on_timeout (bool): Whether an exception should be raised if no response was found
            after timeout_sec

        Returns:
            List of parsed GDB responses, returned from gdbmiparser.parse_response, with the
            additional key 'stream' which is either 'stdout' or 'stderr'

        Raises:
            GdbTimeoutError if response is not received within timeout_sec
            ValueError if select returned unexpected file number
            NoGdbProcessError if there is no gdb subprocess running
        """

        arg_0.verify_valid_gdb_subprocess()
        if arg_1 < 0:
            arg_0.logger.warning("timeout_sec was negative, replacing with 0")
            arg_1 = 0

        if USING_WINDOWS:
            arg_4 = arg_0._get_responses_windows(arg_1)
        else:
            arg_4 = arg_0._get_responses_unix(arg_1)

        if not arg_4 and arg_3:
            raise GdbTimeoutError(
                "Did not get response from gdb after %s seconds" % arg_1
            )

        else:
            return arg_4


def Func(arg_0, arg_1):
        """Get responses on windows. Assume no support for select and use a while loop."""
        arg_2 = time.time() + arg_1
        arg_3 = []
        while True:
            try:
                arg_0.gdb_process.stdout.flush()
                if PYTHON3:
                    arg_4 = arg_0.gdb_process.stdout.readline().replace(
                        b"\r", b"\n"
                    )
                else:
                    arg_4 = arg_0.gdb_process.stdout.read().replace(b"\r", b"\n")
                arg_3 += arg_0._get_responses_list(arg_4, "stdout")
            except IOError:
                pass

            try:
                arg_0.gdb_process.stderr.flush()
                if PYTHON3:
                    arg_4 = arg_0.gdb_process.stderr.readline().replace(
                        b"\r", b"\n"
                    )
                else:
                    arg_4 = arg_0.gdb_process.stderr.read().replace(b"\r", b"\n")
                arg_3 += arg_0._get_responses_list(arg_4, "stderr")
            except IOError:
                pass

            if time.time() > arg_2:
                break

        return arg_3


def Func(arg_0, arg_1):
        """Get responses on unix-like system. Use select to wait for output."""
        arg_2 = time.time() + arg_1
        arg_3 = []
        while True:
            arg_4 = arg_2 - time.time()
            # I prefer to not pass a negative value to select
            if arg_4 <= 0:
                arg_4 = 0
            arg_5, arg_6, arg_6 = select.select(arg_0.read_list, [], [], arg_4)
            arg_7 = None  # to avoid infinite loop if using Python 2
            try:
                for arg_8 in arg_5:
                    # new data is ready to read
                    if arg_8 == arg_0.stdout_fileno:
                        arg_0.gdb_process.stdout.flush()
                        arg_9 = arg_0.gdb_process.stdout.read()
                        arg_10 = "stdout"

                    elif arg_8 == arg_0.stderr_fileno:
                        arg_0.gdb_process.stderr.flush()
                        arg_9 = arg_0.gdb_process.stderr.read()
                        arg_10 = "stderr"

                    else:
                        raise ValueError(
                            "Developer error. Got unexpected file number %d" % arg_8
                        )

                    arg_7 = arg_0._get_responses_list(arg_9, arg_10)
                    arg_3 += arg_7

            except IOError:  # only occurs in python 2.7
                pass

            if arg_1 == 0:  # just exit immediately
                break

            elif arg_7 and arg_0._allow_overwrite_timeout_times:
                # update timeout time to potentially be closer to now to avoid lengthy wait times when nothing is being output by gdb
                arg_2 = min(
                    time.time() + arg_0.time_to_check_for_additional_output_sec,
                    arg_2,
                )

            elif time.time() > arg_2:
                break

        return arg_3


def Func(arg_0, arg_1):
        """Read count characters starting at self.index,
        and return those characters as a string
        """
        arg_2 = arg_0.index + arg_1
        if arg_2 > arg_0.len:
            arg_3 = arg_0.raw_text[arg_0.index :]  # return to the end, don't fail
        else:
            arg_3 = arg_0.raw_text[arg_0.index : arg_2]
        arg_0.index = arg_2

        return arg_3


def Func(arg_0):
    """Parse gdb mi text and turn it into a dictionary.

    See https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Stream-Records.html#GDB_002fMI-Stream-Records
    for details on types of gdb mi output.

    Args:
        gdb_mi_text (str): String output from gdb

    Returns:
        dict with the following keys:
        type (either 'notify', 'result', 'console', 'log', 'target', 'done'),
        message (str or None),
        payload (str, list, dict, or None)
    """
    arg_1 = StringStream(arg_0, debug=_DEBUG)

    if _GDB_MI_NOTIFY_RE.match(arg_0):
        arg_2, arg_3, arg_4 = _get_notify_msg_and_payload(arg_0, arg_1)
        return {
            "type": "notify",
            "message": arg_3,
            "payload": arg_4,
            "token": arg_2,
        }

    elif _GDB_MI_RESULT_RE.match(arg_0):
        arg_2, arg_3, arg_4 = _get_result_msg_and_payload(arg_0, arg_1)
        return {
            "type": "result",
            "message": arg_3,
            "payload": arg_4,
            "token": arg_2,
        }

    elif _GDB_MI_CONSOLE_RE.match(arg_0):
        return {
            "type": "console",
            "message": None,
            "payload": _GDB_MI_CONSOLE_RE.match(arg_0).groups()[0],
        }

    elif _GDB_MI_LOG_RE.match(arg_0):
        return {
            "type": "log",
            "message": None,
            "payload": _GDB_MI_LOG_RE.match(arg_0).groups()[0],
        }

    elif _GDB_MI_TARGET_OUTPUT_RE.match(arg_0):
        return {
            "type": "target",
            "message": None,
            "payload": _GDB_MI_TARGET_OUTPUT_RE.match(arg_0).groups()[0],
        }

    elif response_is_finished(arg_0):
        return {"type": "done", "message": None, "payload": None}

    else:
        # This was not gdb mi output, so it must have just been printed by
        # the inferior program that's being debugged
        return {"type": "output", "message": None, "payload": arg_0}


def Func(arg_0, arg_1):
    """Get notify message and payload dict"""
    arg_2 = arg_1.advance_past_chars(["=", "*"])
    arg_2 = int(arg_2) if arg_2 != "" else None
    logger.debug("%s", fmt_green("parsing message"))
    arg_3 = arg_1.advance_past_chars([","])

    logger.debug("parsed message")
    logger.debug("%s", fmt_green(arg_3))

    arg_4 = _parse_dict(arg_1)
    return arg_2, arg_3.strip(), arg_4


def Func(arg_0, arg_1, arg_2 = 0.01, arg_3= 1e-6, arg_4=0.95, arg_5="ADADELTA",
                        arg_6=0.0, arg_7 = 0.0001):
    """
    Optimize by SGD, AdaGrad, or AdaDelta.
    """

    arg_8, arg_8, arg_8, arg_9 = inspect.getargvalues(inspect.currentframe())
    logging.info("Func: %s" % str(arg_9.items()))
    arg_10 = []

    if arg_5 == "FINETUNING_ADAGRAD":
        arg_5 = "ADAGRAD"
        arg_7 = 0

    arg_11 = 1 - arg_6

    arg_12   = [theano.shared(np.zeros_like(arg_17.get_value(borrow=True), dtype=FLOATX), name="gsum_%s" % arg_17.name) if (arg_5 == 'ADADELTA' or arg_5 == 'ADAGRAD') else None for arg_17 in arg_0]
    arg_13   = [theano.shared(np.zeros_like(arg_17.get_value(borrow=True), dtype=FLOATX), name="xsum_%s" % arg_17.name) if arg_5 == 'ADADELTA' else None for arg_17 in arg_0]

    # Fix for AdaGrad, init gsum to 1
    if arg_5 == 'ADAGRAD':
        for arg_14 in arg_12:
            arg_14.set_value(arg_14.get_value() ** 0)

    arg_15 = OrderedDict()
    # Updates
    for arg_16, arg_17, arg_14, arg_18 in zip(arg_1, arg_0, arg_12, arg_13):

        if arg_5 == 'ADADELTA':
            arg_15[arg_14] = arg_4 * arg_14 + (1. - arg_4) * (arg_16 **2)
            arg_19 = -T.sqrt((arg_18 + arg_3) / (arg_15[arg_14] + arg_3)) * arg_16
            arg_15[arg_18] =arg_4 * arg_18 + (1. - arg_4) * (arg_19 **2)
            arg_15[arg_17] = arg_17 * arg_11 + arg_19
        elif arg_5 == 'ADAGRAD':
            arg_15[arg_14] = arg_14 + (arg_16 **2) - arg_7 * arg_14
            arg_15[arg_17] =  arg_17 * arg_11 - arg_2 * (arg_16 / (T.sqrt(arg_15[arg_14] + arg_3)))

        else:
            arg_15[arg_17] = arg_17 * arg_11 - arg_16 * arg_2
    # Add free parameters
    if arg_5 == 'ADADELTA':
        arg_10.extend(arg_12 + arg_13)
    elif arg_5 == 'ADAGRAD':
        arg_10.extend(arg_12)
    # Check dtype
    for arg_20 in arg_15:
        if arg_15[arg_20].dtype != FLOATX:
            arg_15[arg_20] = arg_15[arg_20].astype(FLOATX)
    return arg_15.items(), arg_10


def Func(arg_0):
        """
        Return updates in the training.
        """
        arg_1 = arg_0.training_params()
        arg_2 = arg_0.get_gradients(arg_1)
        return arg_0.optimization_updates(arg_1, arg_2)


def Func(arg_0):
        """
        Get parameters to be optimized.
        """
        arg_1 = arg_0.network.parameters
        # Freeze parameters
        if arg_0.config.fixed_parameters:
            logging.info("fixed parameters: %s" % ", ".join(map(str, arg_0.config.fixed_parameters)))
            arg_1 = [p for p in arg_1 if p not in arg_0.config.fixed_parameters]
        return arg_1


def Func(arg_0, arg_1):
        """
        Compute first glimpse position using down-sampled image.
        """
        arg_2 = theano.tensor.signal.downsample.max_pool_2d(arg_1, (4,4))
        arg_2 = arg_2.flatten()
        arg_3 = T.dot(arg_2, arg_0.W_f)
        if arg_0.disable_reinforce:
            arg_4 = arg_0.W_f
            if arg_0.random_glimpse:
                arg_3 = arg_0.srng.uniform((2,), low=-1.7, high=1.7)
        else:
            arg_5 = arg_0._sample_gaussian(arg_3, arg_0.cov)
            arg_6 = arg_0._multi_gaussian_pdf(disconnected_grad(arg_5), arg_3)
            arg_4 = T.grad(T.log(arg_6), arg_0.W_f)
            arg_3 = arg_5
        return arg_3, arg_4


def Func(arg_0):
        """
        All codes that create parameters should be put into 'setup' function.
        """
        arg_0.output_dim = 10
        arg_0.encoder = Chain(arg_0.input_dim).stack(Dense(arg_0.internal_layer_size, 'tanh'))
        arg_0.decoder = Chain(arg_0.internal_layer_size).stack(Dense(arg_0.input_dim))
        arg_0.classifier = Chain(arg_0.internal_layer_size).stack(Dense(50, 'tanh'),
                                                      Dense(arg_0.output_dim),
                                                      Softmax())

        arg_0.register_inner_layers(arg_0.encoder, arg_0.decoder, arg_0.classifier)

        arg_0.target_input = T.ivector('target')
        arg_0.register_external_inputs(arg_0.target_input)


def Func(arg_0, arg_1):
        """
        Build the computation graph here.
        """
        arg_2 = arg_0.encoder.Func(arg_1)

        arg_3 = arg_0.decoder.Func(arg_2)

        arg_4 = arg_0.classifier.Func(arg_2)

        arg_5 = AutoEncoderCost(arg_3, arg_1).get()

        arg_6 = CrossEntropyCost(arg_4, arg_0.target_input).get()

        arg_7 = 0.01 * arg_5 + arg_6

        arg_8 = ErrorRateCost(arg_4, arg_0.target_input).get()

        arg_0.register_monitors(("err", arg_8),
                               ("encoder_cost", arg_5),
                               ("classify_cost", arg_6))

        return arg_7


def Func(arg_0, arg_1):
        """
        Process all data with given function.
        The scheme of function should be x,y -> x,y.
        """
        if arg_0._train_set:
            arg_0._train_set = Func(arg_1, arg_0._train_set)
        if arg_0._valid_set:
            arg_0._valid_set = Func(arg_1, arg_0._valid_set)
        if arg_0._test_set:
            arg_0._test_set = Func(arg_1, arg_0._test_set)


def Func(arg_0, arg_1):
        """
        Make targets be one-hot vectors.
        """
        if arg_0._train_set:
            arg_0._train_set = arg_0._vectorize_set(arg_0._train_set, arg_1)
        if arg_0._valid_set:
            arg_0._valid_set = arg_0._vectorize_set(arg_0._valid_set, arg_1)
        if arg_0._test_set:
            arg_0._test_set = arg_0._vectorize_set(arg_0._test_set, arg_1)


def Func(arg_0):
        """
        Print dataset statistics.
        """
        logging.info("%s train=%d valid=%d test=%d" % (arg_0.__class__.__name__,
                                                       len(list(arg_0._train_set)) if arg_0._train_set else 0,
                                                       len(list(arg_0._valid_set)) if arg_0._valid_set else 0,
                                                       len(list(arg_0._test_set)) if arg_0._test_set else 0))


def Func(arg_0, arg_1, arg_2=None, arg_3=None, arg_4=None):
        '''We Func over mini-batches and evaluate periodically.'''
        arg_5 = 0
        while True:
            if not arg_5 % arg_0.config.test_frequency and arg_3:
                try:
                    arg_0.test(arg_5, arg_3)
                except KeyboardInterrupt:
                    logging.info('interrupted!')
                    break

            if not arg_5 % arg_0.validation_frequency and arg_2:
                try:
                    if not arg_0.evaluate(arg_5, arg_2):
                        logging.info('patience elapsed, bailing out')
                        break
                except KeyboardInterrupt:
                    logging.info('interrupted!')
                    break

            arg_6 = ""
            try:
                arg_6 = arg_0.Func_func(arg_1)
            except KeyboardInterrupt:
                logging.info('interrupted!')
                break
            if not arg_5 % arg_0.config.monitor_frequency:
                logging.info('monitor (iter=%i) %s', arg_5 + 1, arg_6)

            arg_5 += 1
            if hasattr(arg_0.network, "iteration_callback"):
                arg_0.network.iteration_callback()

            yield arg_6

        if arg_2:
            arg_0.set_params(arg_0.best_params)
        if arg_3:
            arg_0.test(0, arg_3)


def Func(arg_0, arg_1, arg_2):
        """
        Sample outputs from LM.
        """
        arg_3 = [[onehot(arg_0.input_dim, x) for x in arg_1]]
        for arg_4 in range(arg_2):
            arg_5 = arg_0.compute(arg_3)[0,-1].argmax()
            arg_1.append(arg_5)
            arg_3[0].append(onehot(arg_0.input_dim, arg_5))
        return arg_1


def Func(arg_0, arg_1, arg_2, arg_3=None):
        """
        Compute the alignment weights based on the previous state.
        """

        arg_4 = T.dot(arg_1, arg_0.Wa)
        arg_5 = arg_2
        # For test time the UaH will be (time, output_dim)
        if arg_5.ndim == 2:
            arg_6 = arg_4[:, None, :] + arg_5[None, :, :]
        else:
            arg_6 = arg_4[:, None, :] + arg_5
        arg_7 = T.activate(arg_6, 'tanh')
        arg_8 = T.dot(arg_7, arg_0.Va)  # ~ (batch, time)
        if arg_3:
            arg_3 = (1 - arg_3) * -99.00
            if arg_8.ndim == 3:
                arg_8 += arg_3[None, :]
            else:
                arg_8 += arg_3
        arg_9 = T.nnet.softmax(arg_8)
        return arg_9


def Func(arg_0, arg_1, arg_2):
        """
        Pad sequences to given length in the left or right side.
        """
        if arg_0._train_set:
            arg_0._train_set = pad_dataset(arg_0._train_set, arg_1, arg_2)
        if arg_0._valid_set:
            arg_0._valid_set = pad_dataset(arg_0._valid_set, arg_1, arg_2)
        if arg_0._test_set:
            arg_0._test_set = pad_dataset(arg_0._test_set, arg_1, arg_2)


def Func(arg_0, arg_1, arg_2=0.9, arg_3=0.01):
    """
    RMSPROP optimization core.
    """
    for arg_4, arg_5 in zip(arg_0, arg_1):
            arg_6 = theano.shared(np.zeros_like(arg_4.get_value()), name=arg_4.name + '_rms')
            arg_7 = arg_2 * arg_6 + (1 - arg_2) * arg_5 * arg_5
            yield arg_6, arg_7
            yield arg_4, arg_4 - arg_3 * arg_5 / T.sqrt(arg_7 + 1e-8)


def Func(arg_0, arg_1):
        """
        Run the model with validation data and return costs.
        """
        arg_2 = arg_0.compute(*arg_1)
        return arg_0._extract_costs(arg_2)


def Func(arg_0):
        """
        This function will be called after each iteration.
        """
        arg_0._counter += 1
        if arg_0._counter % arg_0._freq == 0:
            arg_1 = 0.
            arg_2 = defaultdict(float)
            for arg_3 in arg_0._trainer.get_data(arg_0._data_split):
                arg_4 = arg_0.run(arg_3)
                if not isinstance(arg_4, dict):
                    raise Exception("Monitor.run must return a dict.")
                for arg_5, arg_6 in arg_4.items():
                    arg_2[arg_5] += arg_6
                arg_1 += 1
            for arg_5 in arg_2:
                arg_2[arg_5] /= arg_1
            arg_7 = arg_0.compare(arg_2)
            arg_0._trainer.report(arg_2, arg_0._data_split, arg_7=arg_7)
            if arg_7:
                arg_0._trainer.save_checkpoint(arg_0._save_path)


def Func(arg_0):
        """
        Create inner loop variables.
        """
        from theano.tensor.var import TensorVariable
        from deepy.core.neural_var import NeuralVariable
        if not arg_0._loop_vars:
            arg_0._ordered_out_keys = arg_0._outputs.keys()
            arg_2 = arg_0._sequences.keys()
            arg_3 = [arg_10 for arg_10 in arg_0._ordered_out_keys if arg_0._outputs[arg_10]]
            arg_4 = arg_0._non_sequences.keys()
            arg_5, arg_0._scan_local_vars = get_dummy_args(
                sequences=[arg_0._sequences[arg_10].tensor for arg_10 in arg_2],
                outputs_info=[arg_0._outputs[arg_10].tensor for arg_10 in arg_0._ordered_out_keys],
                non_sequences=[arg_0._non_sequences[arg_10].tensor for arg_10 in arg_4],
                **arg_0._kwargs
            )
            arg_7 = dict(zip(arg_2 + arg_3 + arg_4, arg_5))
            arg_8 = arg_0._sequences.copy()
            arg_8.update(arg_0._outputs)
            arg_8.update(arg_0._non_sequences)
            arg_0._loop_vars = LoopVars()
            for arg_10, arg_11 in arg_7.items():
                arg_12 = NeuralVariable(arg_11, dim=arg_8[arg_10].dim())
                arg_0._loop_vars[arg_10] = arg_12


def Func(arg_0, arg_1):
        """
        Internal scan with dummy input variables.
        """
        from neural_var import NeuralVariable
        if not arg_0._loop_vars:
            raise Exception("The loop is not initialized. To initialize the loop, use `with loop as vars`")
        arg_2 = {}
        for arg_3, arg_4 in arg_1.items():
            if arg_4 is not None:
                arg_2[arg_0._dummy_nodes[arg_3].tensor] = arg_4.tensor
        arg_7 = {}
        for arg_3 in arg_0._outputs:
            if arg_3 not in arg_0._loop_vars:
                raise Exception("{} can not be found in loop vars.".format(arg_3))
            arg_8 = theano.clone(arg_0._loop_vars[arg_3].tensor, arg_2)
            arg_7[arg_3] = NeuralVariable(arg_8, arg_0._loop_vars[arg_3].dim())
        return arg_7


def Func(arg_0, arg_1, arg_2=0.9, arg_3=0.01):
    """
    Momentum SGD optimization core.
    """
    arg_4 = []
    arg_5 = []
    for arg_6, arg_7 in zip(arg_0, arg_1):
            arg_8 = arg_3 * arg_7
            arg_9 = theano.shared(np.zeros_like(arg_6.get_value()), name=arg_6.name + '_vel')
            arg_5.append((arg_9, arg_2 * arg_9 - arg_8))
            arg_5.append((arg_6, arg_6 + arg_9))
            arg_4.append(arg_9)
    return arg_5, arg_4


def Func(arg_0, arg_1, arg_2=0):
        """
        Skip N batches in the training.
        """
        logging.info("Func %d epochs and %d batches" % (arg_2, arg_1))
        arg_0._Func_batches = arg_1
        arg_0._Func_epochs = arg_2


def Func(arg_0, arg_1, arg_2=False):
        """
        Load parameters for the training.
        This method can load free parameters and resume the training progress.
        """
        arg_0.network.Func(arg_1, arg_2=arg_2)
        arg_0.best_params = arg_0.copy_params()
        # Resume the progress
        if arg_0.network.train_logger.progress() > 0 or arg_0.network.train_logger.epoch() > 0:
            arg_0.skip(arg_0.network.train_logger.progress(), arg_0.network.train_logger.epoch() - 1)


def Func(arg_0, arg_1, arg_2=None, arg_3=None, arg_4=None):
        """
        Train the model and return costs.
        """
        arg_0._epoch = 0
        while True:
            if arg_0._skip_epochs > 0:
                logging.info("skipping one epoch ...")
                arg_0._skip_epochs -= 1
                arg_0._epoch += 1
                yield None
                continue
            # Test
            if not arg_0._epoch % arg_0.config.test_frequency and arg_3:
                try:
                    arg_0._run_test(arg_0._epoch, arg_3)
                except KeyboardInterrupt:
                    logging.info('interrupted!')
                    break
            # Validate
            if not arg_0._epoch % arg_0.validation_frequency and arg_2:
                try:

                    if not arg_0._run_valid(arg_0._epoch, arg_2):
                        logging.info('patience elapsed, bailing out')
                        break
                except KeyboardInterrupt:
                    logging.info('interrupted!')
                    break
            # Train one step

            try:
                arg_6 = arg_0._run_Func(arg_0._epoch, arg_1, arg_4)
            except KeyboardInterrupt:
                logging.info('interrupted!')
                break
            # Check costs
            if np.isnan(arg_6[0][1]):
                logging.info("NaN detected in costs, rollback to last parameters")
                arg_0.set_params(*arg_0.checkpoint)
            else:
                arg_0._epoch += 1
                arg_0.network.epoch_callback()

            yield dict(arg_6)

        if arg_2 and arg_0.config.get("save_best_parameters", True):
            arg_0.set_params(*arg_0.best_params)
        if arg_3:
            arg_0._run_test(-1, arg_3)


def Func(arg_0, arg_1, arg_2, arg_3=None):
        """
        Run one training iteration.
        """
        arg_0.network.train_logger.record_epoch(arg_1 + 1)
        arg_4 = arg_0.train_step(arg_2, arg_3)
        if not arg_1 % arg_0.config.monitor_frequency:
            arg_0.report(dict(arg_4), "train", arg_1)
        arg_0.last_run_costs = arg_4
        return arg_4


def Func(arg_0, arg_1, arg_2, arg_3=False, arg_4=None):
        """
        Run one valid iteration, return true if to continue training.
        """
        arg_5 = arg_0.valid_step(arg_2)
        # this is the same as: (J_i - J_f) / J_i > min improvement
        arg_6, arg_7 = arg_5[0]
        arg_8 = False
        if arg_0.best_cost - arg_7 > arg_0.best_cost * arg_0.min_improvement:
            # save the best cost and parameters
            arg_0.best_params = arg_0.copy_params()
            arg_8 = True
            if not arg_3:
                arg_0.best_cost = arg_7
                arg_0.best_epoch = arg_1
            arg_0.save_checkpoint(arg_4)

        arg_0.report(dict(arg_5), type="valid", arg_1=0 if arg_3 else arg_1, arg_8=arg_8)
        arg_0.last_run_costs = arg_5
        return arg_1 - arg_0.best_epoch < arg_0.patience


def Func(arg_0, arg_1="train"):
        """
        Get specified split of data.
        """
        if arg_1 == 'train':
            return arg_0._current_train_set
        elif arg_1 == 'valid':
            return arg_0._current_valid_set
        elif arg_1 == 'test':
            return arg_0._current_test_set
        else:
            return None


def Func(arg_0):
        """
        Report usage of training parameters.
        """
        if arg_0.logger:
            arg_0.logger.info("accessed parameters:")
            for arg_1 in arg_0.used_parameters:
                arg_0.logger.info(" - %s %s" % (arg_1, "(undefined)" if arg_1 in arg_0.undefined_parameters else ""))


def Func(arg_0, arg_1, arg_2=0, arg_3=None):
        """
        An alias of deepy.tensor.Func.
        """
        from deepy.tensor import Func
        return Func(arg_1, arg_2=arg_2, arg_3=arg_3)


def Func(arg_0, arg_1, arg_2="train"):
        """
        Create vars given a dataset and set test values.
        Useful when dataset is already defined.
        """
        from deepy.core.neural_var import NeuralVariable
        arg_3 = []
        if arg_2 == "valid":
            arg_4 = arg_1.valid_set()
        elif arg_2 == "test":
            arg_4 = arg_1.test_set()
        else:
            arg_4 = arg_1.train_set()
        arg_5 = list(arg_4)[0]
        for arg_6, arg_7 in enumerate(arg_5):
            if arg_7.dtype == "int64":
                arg_7 = arg_7.astype("int32")
            if arg_7.dtype == "float64":
                arg_7 = arg_7.astype(env.FLOATX)
            arg_8 = {
                0: "scalar",
                1: "vector",
                2: "matrix",
                3: "tensor3",
                4: "tensor4",
                5: "tensor5",
            }
            arg_9 = arg_8[arg_7.ndim] if arg_7.ndim in arg_8 else arg_8[0]
            if arg_7.dtype.kind == "i":
                arg_9 = "i" + arg_9
            arg_10 = getattr(TT, arg_9)("input_{}_{}".format(arg_6 + 1, arg_9))
            arg_11 = arg_7.shape[-1]
            arg_12 = NeuralVariable(arg_10, dim=arg_11)
            arg_12.set_test_value(arg_7)
            arg_3.append(arg_12)
        return arg_3


def Func(arg_0, arg_1, arg_2=None):
        """
        Create a Func theano scalar value.
        """
        if type(arg_1) == int:
            arg_3 = np.array(arg_1, dtype="int32")
        elif type(arg_1) == float:
            arg_3 = np.array(arg_1, dtype=env.FLOATX)
        else:
            arg_3 = arg_1

        return theano.Func(arg_3, arg_2=arg_2)


def Func(arg_0, *arg_1):
        """
        Stack encoding layers, this must be done before stacking decoding layers.
        """
        arg_0.stack(*arg_1)
        arg_0.encoding_layes.extend(arg_1)


def Func(arg_0, *arg_1):
        """
        Stack decoding layers.
        """
        arg_0.stack(*arg_1)
        arg_0.decoding_layers.extend(arg_1)


def Func(arg_0, arg_1):
        """
        Encode given input.
        """
        if not arg_0.encoding_network:
            arg_0.encoding_network = NeuralNetwork(arg_0.input_dim, arg_0.input_tensor)
            arg_0.encoding_network.input_variables = arg_0.input_variables
            for arg_4 in arg_0.encoding_layes:
                arg_0.encoding_network.stack_layer(arg_4, no_setup=True)
        return arg_0.encoding_network.compute(*arg_1)


def Func(arg_0, arg_1):
        """
        Register the layer so that it's param will be trained.
        But the output of the layer will not be stacked.
        """
        if type(arg_1) == Block:
            arg_1.fix()
        arg_0.parameter_count += arg_1.parameter_count
        arg_0.parameters.extend(arg_1.parameters)
        arg_0.free_parameters.extend(arg_1.free_parameters)
        arg_0.training_monitors.extend(arg_1.training_monitors)
        arg_0.testing_monitors.extend(arg_1.testing_monitors)
        arg_0.updates.extend(arg_1.updates)
        arg_0.training_updates.extend(arg_1.training_updates)
        arg_0.input_variables.extend(arg_1.external_inputs)
        arg_0.target_variables.extend(arg_1.external_targets)

        arg_0.training_callbacks.extend(arg_1.training_callbacks)
        arg_0.testing_callbacks.extend(arg_1.testing_callbacks)
        arg_0.epoch_callbacks.extend(arg_1.epoch_callbacks)


def Func(arg_0):
        """
        Monitoring the outputs of each layer.
        Useful for troubleshooting convergence problems.
        """
        for arg_1, arg_2 in zip(arg_0.layers, arg_0._hidden_outputs):
            arg_0.training_monitors.append(('mean(%s)' % (arg_1.name), abs(arg_2).mean()))


def Func(arg_0):
        """
        Return all parameters.
        """
        arg_1 = []
        arg_1.extend(arg_0.parameters)
        arg_1.extend(arg_0.free_parameters)

        return arg_1


def Func(arg_0):
        """
        Set up variables.
        """
        if arg_0.input_tensor:
            if type(arg_0.input_tensor) == int:
                arg_1 = dim_to_var(arg_0.input_tensor, name="x")
            else:
                arg_1 = arg_0.input_tensor
        else:
            arg_1 = T.matrix('x')
        arg_0.input_variables.append(arg_1)
        arg_0._output = arg_1
        arg_0._test_output = arg_1


def Func(arg_0, arg_1, arg_2=False):
        """
        Save parameters to file.
        """
        save_logger.info(arg_1)
        arg_3 = arg_0.all_parameters
        arg_4 = [p.get_value().copy() for p in arg_3]
        if arg_2:
            arg_5 = Thread(target=save_network_params, args=(arg_4, arg_1))
            arg_5.start()
        else:
            save_network_params(arg_4, arg_1)
        arg_0.train_logger.save(arg_1)


def Func(arg_0, arg_1, arg_2=False):
        """
        Load parameters from file.
        """
        if not os.path.exists(arg_1): return;
        logging.info("loading parameters from %s" % arg_1)
        # Decide which parameters to load
        if arg_2:
            arg_3 = arg_0.parameters
        else:
            arg_3 = arg_0.all_parameters
        # Load parameters
        if arg_1.endswith(".gz"):
            arg_4 = gzip.open if arg_1.lower().endswith('.gz') else open
            arg_5 = arg_4(arg_1, 'rb')
            arg_6 = pickle.load(arg_5)
            arg_5.close()
            # Write parameters
            for arg_7, arg_8 in zip(arg_3, arg_6):
                logging.info('%s: setting value %s', arg_7.name, arg_8.shape)
                arg_7.set_value(arg_8)
        elif arg_1.endswith(".npz"):
            arg_9 = np.load(arg_1)
            # Write parameters
            for arg_7, arg_10 in zip(arg_3, range(len(arg_9.keys()))):
                arg_8 = arg_9['arr_%d' % arg_10]
                logging.info('%s: setting value %s', arg_7.name, arg_8.shape)
                arg_7.set_value(arg_8)
        else:
            raise Exception("File format of %s is not supported, use '.gz' or '.npz' or '.uncompressed.gz'" % arg_1)

        arg_0.train_logger.load(arg_1)


def Func(arg_0):
        """
        Print network statistics.
        """
        logging.info("network inputs: %s", " ".join(map(str, arg_0.input_variables)))
        logging.info("network targets: %s", " ".join(map(str, arg_0.target_variables)))
        logging.info("network parameters: %s", " ".join(map(str, arg_0.all_parameters)))
        logging.info("parameter count: %d", arg_0.parameter_count)


def Func(arg_0, *arg_1):
        """
        Register parameters.
        """
        for arg_2 in arg_1:
            arg_0.parameter_count += np.prod(arg_2.get_value().shape)
        arg_0.parameters.extend(arg_1)


def Func(arg_0, *arg_1):
        """
        Register updates that will only be executed in training phase.
        """
        for arg_2, arg_3 in arg_1:
            if arg_2 not in arg_0._registered_training_updates:
                arg_0.training_updates.append((arg_2, arg_3))
                arg_0._registered_training_updates.add(arg_2)


def Func(arg_0, *arg_1):
        """
        Register monitors they should be tuple of name and Theano variable.
        """
        for arg_2, arg_3 in arg_1:
            if arg_2 not in arg_0._registered_monitors:
                arg_3 *= 1.0 # Avoid CudaNdarray
                arg_0.training_monitors.append((arg_2, arg_3))
                arg_0.testing_monitors.append((arg_2, arg_3))
                arg_0._registered_monitors.add(arg_2)


def Func(arg_0):
    """
    Get the L2 norm of multiple tensors.
    This function is taken from blocks.
    """
    # Another way for doing this, I don't know which one is fast
    # return T.sqrt(sum(T.sum(t ** 2) for t in tensors))
    arg_1 = [T.as_tensor_variable(t).flatten() for t in arg_0]
    arg_1 = [(t if t.ndim > 0 else t.dimshuffle('x'))
                 for t in arg_1]
    arg_2 = T.join(0, *arg_1)
    return T.sqrt(T.sqr(arg_2).sum())


def Func(arg_0, arg_1):
        """
        dumps one element to file_obj, a file opened in write mode
        """
        arg_2 = dumps(arg_0)
        arg_1.write(arg_2)
        # record separator is a blank line
        # (since pickled_elt_str might contain its own newlines)
        arg_1.write('\n\n')


def Func(arg_0, arg_1, arg_2=False):
        from deepy.core import graph
        """
        Load parameters to the block.
        """
        from deepy.core.comp_graph import ComputationalGraph
        arg_3 = graph.compile(blocks=[arg_0])
        arg_3.Func(arg_1, arg_2=arg_2)


def Func(
            arg_0, arg_1, arg_2, arg_3, arg_4='GET', arg_5=None,
            arg_6=None, arg_7='', arg_8=None, arg_9='', arg_10='',
            arg_11='', arg_12=''
    ):
        """
        Creates |oauth2| request elements.
        """

        arg_6 = arg_6 or {}
        arg_5 = arg_5 or {}

        arg_13 = arg_2.consumer_key or ''
        arg_14 = arg_2.consumer_secret or ''
        arg_15 = arg_2.token or ''
        arg_16 = arg_2.refresh_token or arg_2.token or ''

        # Separate url base and query parameters.
        arg_3, arg_17 = arg_0._split_url(arg_3)

        # Add params extracted from URL.
        arg_5.update(dict(arg_17))

        if arg_1 == arg_0.USER_AUTHORIZATION_REQUEST_TYPE:
            # User authorization request.
            # TODO: Raise error for specific message for each missing argument.
            if arg_13 and arg_9 and (
                    arg_11 or not arg_0.supports_csrf_protection):
                arg_5['client_id'] = arg_13
                arg_5['redirect_uri'] = arg_9
                arg_5['scope'] = arg_10
                if arg_0.supports_user_state:
                    arg_5['state'] = base64.urlsafe_b64encode(
                        json.dumps(
                            {"csrf": arg_11, "user_state": arg_12}
                        ).encode('utf-8')
                    )
                else:
                    arg_5['state'] = arg_11
                arg_5['response_type'] = 'code'

                # Add authorization header
                arg_6.update(arg_0._authorization_header(arg_2))
            else:
                raise OAuth2Error(
                    'Credentials with valid consumer_key and arguments '
                    'redirect_uri, scope and state are required to create '
                    'OAuth 2.0 user authorization request elements!')

        elif arg_1 == arg_0.ACCESS_TOKEN_REQUEST_TYPE:
            # Access token request.
            if arg_13 and arg_14:
                arg_5['code'] = arg_15
                arg_5['client_id'] = arg_13
                arg_5['client_secret'] = arg_14
                arg_5['redirect_uri'] = arg_9
                arg_5['grant_type'] = 'authorization_code'

                # TODO: Check whether all providers accept it
                arg_6.update(arg_0._authorization_header(arg_2))
            else:
                raise OAuth2Error(
                    'Credentials with valid token, consumer_key, '
                    'consumer_secret and argument redirect_uri are required '
                    'to create OAuth 2.0 access token request elements!')

        elif arg_1 == arg_0.REFRESH_TOKEN_REQUEST_TYPE:
            # Refresh access token request.
            if arg_16 and arg_13 and arg_14:
                arg_5['refresh_token'] = arg_16
                arg_5['client_id'] = arg_13
                arg_5['client_secret'] = arg_14
                arg_5['grant_type'] = 'refresh_token'
            else:
                raise OAuth2Error(
                    'Credentials with valid refresh_token, consumer_key, '
                    'consumer_secret are required to create OAuth 2.0 '
                    'refresh token request elements!')

        elif arg_1 == arg_0.PROTECTED_RESOURCE_REQUEST_TYPE:
            # Protected resource request.

            # Add Authorization header. See:
            # http://tools.ietf.org/html/rfc6749#section-7.1
            if arg_2.token_type == arg_0.BEARER:
                # http://tools.ietf.org/html/rfc6750#section-2.1
                arg_6.update(
                    {'Authorization': 'Bearer {0}'.format(arg_2.token)})

            elif arg_15:
                arg_5['access_token'] = arg_15
            else:
                raise OAuth2Error(
                    'Credentials with valid token are required to create '
                    'OAuth 2.0 protected resources request elements!')

        arg_18 = core.RequestElements(
            arg_3, arg_4, arg_5, arg_6, arg_7)

        return arg_0._x_request_elements_filter(
            arg_1, arg_18, arg_2)


def Func(arg_0, arg_1):
        """
        We need to override this method to fix Facebooks naming deviation.
        """

        # Facebook returns "expires" instead of "expires_in".
        arg_0.expire_in = arg_1.get('expires')

        if arg_1.get('token_type') == 'bearer':
            # TODO: cls is not available here, hardcode for now.
            arg_0.token_type = 'Bearer'

        return arg_0


def Func(arg_0, arg_1, arg_2,
                                   arg_3):
        """
        Google doesn't accept client ID and secret to be at the same time in
        request parameters and in the basic authorization header in the access
        token request.
        """
        if arg_1 is arg_0.ACCESS_TOKEN_REQUEST_TYPE:
            arg_4 = arg_2[2]
            del arg_4['client_id']
            del arg_4['client_secret']
        return arg_2


def Func(arg_0):
    """
    Login handler, must accept both GET and POST to be able to use OpenID.
    """

    # We need response object for the WerkzeugAdapter.
    arg_1 = make_response()

    # Log the user in, pass it the adapter and the provider name.
    arg_2 = authomatic.Func(
        WerkzeugAdapter(
            request,
            arg_1),
        arg_0)

    # If there is no LoginResult object, the Func procedure is still pending.
    if arg_2:
        if arg_2.user:
            # We need to update the user to get more info.
            arg_2.user.update()

        # The rest happens inside the template.
        return render_template('Func.html', arg_2=arg_2)

    # Don't forget to return the response.
    return arg_1


def Func(arg_0):
    """
    Replaces all values that are single-item iterables with the value of its
    index 0.

    :param dict dict_:
        Dictionary to normalize.

    :returns:
        Normalized dictionary.

    """

    return dict([(arg_1, arg_2[0] if not isinstance(arg_2, str) and len(arg_2) == 1 else arg_2)
                 for arg_1, arg_2 in list(arg_0.items())])


def Func(arg_0):
    """
    Converts list of tuples to dictionary with duplicate keys converted to
    lists.

    :param list items:
        List of tuples.

    :returns:
        :class:`dict`

    """

    arg_1 = collections.defaultdict(list)

    for arg_2, arg_3 in arg_0:
        arg_1[arg_2].append(arg_3)

    return normalize_dict(dict(arg_1))


def Func(arg_0):
    """
    Parses response body from JSON, XML or query string.

    :param body:
        string

    :returns:
        :class:`dict`, :class:`list` if input is JSON or query string,
        :class:`xml.etree.ElementTree.Element` if XML.

    """
    try:
        # Try JSON first.
        return json.loads(arg_0)
    except (OverflowError, TypeError, ValueError):
        pass

    try:
        # Then XML.
        return ElementTree.fromstring(arg_0)
    except (ElementTree.ParseError, TypeError, ValueError):
        pass

    # Finally query string.
    return dict(parse.parse_qsl(arg_0))


def Func(arg_0):
    """
    Returns a provider class.

    :param class_name: :class:`string` or
    :class:`authomatic.providers.BaseProvider` subclass.

    """

    if isinstance(arg_0, str):
        # prepare path for authomatic.providers package
        arg_1 = '.'.join([__package__, 'providers', arg_0])

        # try to import class by string from providers module or by fully
        # qualified path
        return import_string(arg_0, True) or import_string(arg_1)
    else:
        return arg_0


def Func(arg_0, arg_1=None):
        """
        Creates the value for ``Set-Cookie`` HTTP header.

        :param bool delete:
            If ``True`` the cookie value will be ``deleted`` and the
            Expires value will be ``Thu, 01-Jan-1970 00:00:01 GMT``.

        """
        arg_2 = 'deleted' if arg_1 else arg_0._serialize(arg_0.data)
        arg_3 = parse.urlsplit(arg_0.adapter.url)
        arg_4 = arg_3.netloc.split(':')[0]

        # Work-around for issue #11, failure of WebKit-based browsers to accept
        # cookies set as part of a redirect response in some circumstances.
        if '.' not in arg_4:
            arg_5 = '{name}={value}; Path={path}; HttpOnly{secure}{expires}'
        else:
            arg_5 = ('{name}={value}; Domain={domain}; Path={path}; '
                        'HttpOnly{secure}{expires}')

        return arg_5.format(
            name=arg_0.name,
            arg_2=arg_2,
            arg_4=arg_4,
            path=arg_3.path,
            secure='; Secure' if arg_0.secure else '',
            expires='; Expires=Thu, 01-Jan-1970 00:00:01 GMT' if arg_1 else ''
        )


def Func(arg_0, *arg_1):
        """
        Creates signature for the session.
        """
        arg_2 = hmac.new(six.b(arg_0.secret), digestmod=hashlib.sha1)
        arg_2.update(six.b('|'.join(arg_1)))
        return arg_2.hexdigest()


def Func(arg_0, arg_1):
        """
        Converts the value to a signed string with timestamp.

        :param value:
            Object to be serialized.

        :returns:
            Serialized value.

        """

        # data = copy.deepcopy(value)
        arg_2 = arg_1

        # 1. Serialize
        arg_3 = pickle.dumps(arg_2).decode('latin-1')

        # 2. Encode
        # Percent encoding produces smaller result then urlsafe base64.
        arg_4 = parse.quote(arg_3, '')

        # 3. Concatenate
        arg_5 = str(int(time.time()))
        arg_6 = arg_0._signature(arg_0.name, arg_4, arg_5)
        arg_7 = '|'.join([arg_4, arg_5, arg_6])

        return arg_7


def Func(arg_0):
        """
        ``True`` if credentials are Func, ``False`` if expired.
        """

        if arg_0.expiration_time:
            return arg_0.expiration_time > int(time.time())
        else:
            return True


def Func(arg_0, arg_1):
        """
        Returns ``True`` if credentials expire sooner than specified.

        :param int seconds:
            Number of seconds.

        :returns:
            ``True`` if credentials expire sooner than specified,
            else ``False``.

        """

        if arg_0.expiration_time:
            return arg_0.expiration_time < int(time.time()) + int(arg_1)
        else:
            return False


def Func(arg_0):
        """
        Converts the credentials to a percent encoded string to be stored for
        later use.

        :returns:
            :class:`string`

        """

        if arg_0.provider_id is None:
            raise ConfigError(
                'To Func credentials you need to specify a '
                'unique integer under the "id" key in the config '
                'for each provider!')

        # Get the provider type specific items.
        arg_1 = arg_0.provider_type_class().to_tuple(arg_0)

        # Provider ID and provider type ID are always the first two items.
        arg_2 = (arg_0.provider_id, arg_0.provider_type_id) + arg_1

        # Make sure that all items are strings.
        arg_3 = [str(i) for i in arg_2]

        # Concatenate by newline.
        arg_4 = '\n'.join(arg_3)

        # Percent encode.
        return parse.quote(arg_4, '')


def Func(arg_0):
        """
        Return true if string is binary data.
        """

        arg_1 = (bytearray([7, 8, 9, 10, 12, 13, 27]) +
                     bytearray(range(0x20, 0x100)))
        return bool(arg_0.translate(None, arg_1))


def Func(arg_0):
        """
        The whole response content.
        """

        if not arg_0._content:
            Func = arg_0.httplib_response.read()
            if arg_0.is_binary_string(Func):
                arg_0._content = Func
            else:
                arg_0._content = Func.decode('utf-8')
        return arg_0._content


def Func(
            arg_0, arg_1, arg_2, arg_3, arg_4=None, arg_5=None,
            arg_6='', arg_7='GET', arg_8='', arg_9=''
    ):
        """
        Creates |oauth1| request elements.
        """

        arg_4 = arg_4 or {}
        arg_5 = arg_5 or {}

        arg_10 = arg_2.consumer_key or ''
        arg_11 = arg_2.consumer_secret or ''
        arg_12 = arg_2.token or ''
        arg_13 = arg_2.token_secret or ''

        # separate url base and query parameters
        arg_3, arg_14 = arg_0._split_url(arg_3)

        # add extracted params to future params
        arg_4.update(dict(arg_14))

        if arg_1 == arg_0.USER_AUTHORIZATION_REQUEST_TYPE:
            # no need for signature
            if arg_12:
                arg_4['oauth_token'] = arg_12
            else:
                raise OAuth1Error(
                    'Credentials with valid token are required to create '
                    'User Authorization URL!')
        else:
            # signature needed
            if arg_1 == arg_0.REQUEST_TOKEN_REQUEST_TYPE:
                # Request Token URL
                if arg_10 and arg_11 and arg_9:
                    arg_4['oauth_consumer_key'] = arg_10
                    arg_4['oauth_callback'] = arg_9
                else:
                    raise OAuth1Error(
                        'Credentials with valid consumer_key, consumer_secret '
                        'and callback are required to create Request Token '
                        'URL!')

            elif arg_1 == arg_0.ACCESS_TOKEN_REQUEST_TYPE:
                # Access Token URL
                if arg_10 and arg_11 and arg_12 and arg_8:
                    arg_4['oauth_token'] = arg_12
                    arg_4['oauth_consumer_key'] = arg_10
                    arg_4['oauth_verifier'] = arg_8
                else:
                    raise OAuth1Error(
                        'Credentials with valid consumer_key, '
                        'consumer_secret, token and argument verifier'
                        ' are required to create Access Token URL!')

            elif arg_1 == arg_0.PROTECTED_RESOURCE_REQUEST_TYPE:
                # Protected Resources URL
                if arg_10 and arg_11 and arg_12 and arg_13:
                    arg_4['oauth_token'] = arg_12
                    arg_4['oauth_consumer_key'] = arg_10
                else:
                    raise OAuth1Error(
                        'Credentials with valid consumer_key, ' +
                        'consumer_secret, token and token_secret are required '
                        'to create Protected Resources URL!')

            # Sign request.
            # http://oauth.net/core/1.0a/#anchor13

            # Prepare parameters for signature base string
            # http://oauth.net/core/1.0a/#rfc.section.9.1
            arg_4['oauth_signature_method'] = arg_0._signature_generator.method
            arg_4['oauth_timestamp'] = str(int(time.time()))
            arg_4['oauth_nonce'] = arg_0.csrf_generator(str(uuid.uuid4()))
            arg_4['oauth_version'] = '1.0'

            # add signature to params
            arg_4['oauth_signature'] = arg_0._signature_generator.create_signature(  # noqa
                arg_7, arg_3, arg_4, arg_11, arg_13)

        arg_15 = core.RequestElements(
            arg_3, arg_7, arg_4, arg_5, arg_6)

        return arg_0._x_request_elements_filter(
            arg_1, arg_15, arg_2)


def Func(arg_0, *arg_1, **arg_2):
        """
        Decorator for Flask view functions.
        """

        def decorator(arg_3):
            @wraps(arg_3)
            def decorated(*arg_4, **arg_5):
                arg_0.response = make_response()
                arg_7 = WerkzeugAdapter(request, arg_0.response)
                arg_2.setdefault('session', session)
                arg_2.setdefault('session_saver', arg_0.session_saver)
                arg_0.result = super(FlaskAuthomatic, arg_0).Func(
                    arg_7,
                    *arg_1,
                    **arg_2)
                return arg_3(*arg_4, **arg_5)
            return decorated
        return decorator


def Func(arg_0):
        """
        Launches the OpenID authentication procedure.
        """

        if arg_0.params.get(arg_0.identifier_param):
            # =================================================================
            # Phase 1 before redirect.
            # =================================================================
            arg_0._log(
                logging.INFO,
                u'Starting OpenID authentication procedure.')

            arg_1 = users.create_Func_url(
                dest_url=arg_0.url, federated_identity=arg_0.identifier)

            arg_0._log(logging.INFO, u'Redirecting user to {0}.'.format(arg_1))

            arg_0.redirect(arg_1)
        else:
            # =================================================================
            # Phase 2 after redirect.
            # =================================================================

            arg_0._log(
                logging.INFO,
                u'Continuing OpenID authentication procedure after redirect.')

            arg_2 = users.get_current_user()

            if arg_2:
                arg_0._log(logging.INFO, u'Authentication successful.')
                arg_0._log(logging.INFO, u'Creating user.')
                arg_0.user = core.User(arg_0,
                                      id=arg_2.federated_identity(),
                                      email=arg_2.email(),
                                      gae_user=arg_2)

                # =============================================================
                # We're done
                # =============================================================
            else:
                raise FailureError(
                    'Unable to authenticate identifier "{0}"!'.format(
                        arg_0.identifier))


def Func(arg_0, arg_1, arg_2, **arg_3):
        """
        Logs a message with pre-formatted prefix.

        :param int level:
            Logging level as specified in the
            `login module <http://docs.python.org/2/library/logging.html>`_ of
            Python standard library.

        :param str msg:
            The actual message.

        """

        arg_4 = getattr(arg_0, 'Funcger', None) or authomatic.core.Funcger
        arg_4.log(
            arg_1, ': '.join(
                ('authomatic', arg_0.__name__, arg_2)), **arg_3)