def alarm_manager():
    alarm_stack = AlarmStack.query.filter(AlarmStack.count != 0).all()
    for alarm in alarm_stack:
        term = Term.get_by_id(alarm.term_id)
        if not term:
            continue

        if not term.config_date:
            continue

        delta = date_helper.get_current_date(format=False) - term.config_date
        if delta.total_seconds() <= alarm.interval:
            continue

        alarm.count -= 1
        alarm.save()

        emails = alarm.decode_field(alarm.emails)
        term_info = Term.get_info_by_id(alarm.term_id)
        for email in emails:
            mail.send.delay(
                TermAlarmMessage,
                to=email,
                term=term_info)
        return True
    return False
Beispiel #2
0
def terminal_info(term_id):
    """Информация о терминале"""

    firm_terms = FirmTerm.get_list_by_firm_id(g.firm_info['id'])
    if not term_id in firm_terms:
        abort(403)

    term = Term.get_info_by_id(term_id)
    if not term:
        abort(404)

    term_access = term_id in FirmTerm.get_list_by_firm_id(
        g.firm_info['id'], False)
    term_events = TermEvent().get_by_term_id(term_id)
    alarm = AlarmStack(firm_id=g.firm_info['id'],
                       term_id=term_id).get_term_alarm()

    return render_template('term/terminal/view.html',
                           term=term,
                           events=EventType.get_dict(term.type),
                           term_event=TermEvent(),
                           term_events=term_events,
                           term_access=term_access,
                           term_types=Term().get_type_list(),
                           term_factors=Term().get_factor_list(),
                           term_auth=Term().get_auth_list(),
                           term_blacklist=Term().get_blacklist_list(),
                           alarm_stack=alarm)
Beispiel #3
0
def terminal_view():
    """Отображаем страницу со списком терминалов, сам список получаем отдельным запросом"""

    return render_template('term/terminal/index.html',
                           term=Term(),
                           term_types=Term().get_type_list(),
                           term_factors=Term().get_factor_list(),
                           term_blacklist=Term().get_blacklist_list())
Beispiel #4
0
def alarm_remove():
    """Удаление оповещения"""

    answer = dict(error='yes', message=u'Произошла ошибка')

    arg = get_post_arg(request, True)
    arg['firm_id'] = int(g.firm_info['id'])

    if not 'term_id' in arg or not Term.get_by_id(arg['term_id']):
        abort(404)

    term_access = arg['term_id'] in FirmTerm.get_list_by_firm_id(
        g.firm_info['id'], False)
    if not term_access:
        term_rent = FirmTerm.query.filter_by(
            term_id=arg['term_id'], child_firm_id=g.firm_info['id']).all()
        if not term_rent:
            abort(403)

    alarm_stack = AlarmStack.query.filter_by(
        term_id=arg['term_id'], firm_id=arg['firm_id']).first()
    if not alarm_stack:
        abort(404)

    alarm_stack.delete()
    answer['error'] = 'no'
    answer['message'] = u'Оповещение удалено'

    return jsonify(answer)
Beispiel #5
0
def api_get_config(term_id):
    """Возвращает конфигурационный файл для терминала"""
    term = Term.get_valid_term(int(term_id))

    if term is None:
        abort(400)

    term = term.get_xml_view()
    term_settings = TermSettings.query.get(term.settings_id)

    if term.status == Term.STATUS_BANNED:
        config_xml = render_template(
            'api/term/config_empty.xml',
            term=term,
            config=term_settings).encode('cp1251')
        response = make_response(config_xml)
    else:
        term_events = TermEvent().get_by_term_id(term.id)
        if term_events is None:
            abort(400)

        person_events = PersonEvent.get_valid_by_term_id(term.id)
        blacklist = BlacklistSettings.query.get(term.id)

        config_xml = render_template(
            'api/term/config.xml',
            term=term,
            blacklist=blacklist,
            config=term_settings,
            term_events=term_events,
            person_events=person_events).encode('cp1251')
        response = make_response(config_xml)

    return response
Beispiel #6
0
def terminal_list():
    """Получаем список терминалов принадлежащих фирме"""

    arg = get_post_arg(request, True)
    answer = Term.select_term_list(g.firm_info['id'], **arg)

    return jsonify(answer)
Beispiel #7
0
def alarm_remove():
    """Удаление оповещения"""

    answer = dict(error='yes', message=u'Произошла ошибка')

    arg = get_post_arg(request, True)
    arg['firm_id'] = int(g.firm_info['id'])

    if not 'term_id' in arg or not Term.get_by_id(arg['term_id']):
        abort(404)

    term_access = arg['term_id'] in FirmTerm.get_list_by_firm_id(
        g.firm_info['id'], False)
    if not term_access:
        term_rent = FirmTerm.query.filter_by(
            term_id=arg['term_id'], child_firm_id=g.firm_info['id']).all()
        if not term_rent:
            abort(403)

    alarm_stack = AlarmStack.query.filter_by(term_id=arg['term_id'],
                                             firm_id=arg['firm_id']).first()
    if not alarm_stack:
        abort(404)

    alarm_stack.delete()
    answer['error'] = 'no'
    answer['message'] = u'Оповещение удалено'

    return jsonify(answer)
Beispiel #8
0
def terminal_info(term_id):
    """Информация о терминале"""

    firm_terms = FirmTerm.get_list_by_firm_id(g.firm_info['id'])
    if not term_id in firm_terms:
        abort(403)

    term = Term.get_info_by_id(term_id)
    if not term:
        abort(404)

    term_access = term_id in FirmTerm.get_list_by_firm_id(
        g.firm_info['id'], False)
    term_events = TermEvent().get_by_term_id(term_id)
    alarm = AlarmStack(
        firm_id=g.firm_info['id'],
        term_id=term_id).get_term_alarm()

    return render_template(
        'term/terminal/view.html',
        term=term,
        events=EventType.get_dict(term.type),
        term_event=TermEvent(),
        term_events=term_events,
        term_access=term_access,
        term_types=Term().get_type_list(),
        term_factors=Term().get_factor_list(),
        term_auth=Term().get_auth_list(),
        term_blacklist=Term().get_blacklist_list(),
        alarm_stack=alarm
    )
Beispiel #9
0
    def get_term_report(self, **kwargs):

        self._get_search_params(**kwargs)
        answer = self.term_general_query(**kwargs)

        result = []
        terms_name = Term.select_name_dict()
        firms_name = Firm.select_name_dict()
        for report in answer['reports']:
            search_date = date_helper.from_utc(report[0], self.tz)
            creation_date = self.format_search_date(search_date)

            data = {
                'creation_date': creation_date,
                'amount': 0,
                'count': 0
            }

            detaled_report = self.term_detaled_query(search_date)
            data['term'] = {}
            for row in detaled_report:
                term_name = terms_name[row[0]] if row[
                    0] in terms_name else 'Empty'
                firm_name = firms_name[row[1]] if row[
                    1] in firms_name else 'Empty'

                amount = float(row[2]) / 100
                count = int(row[3])

                if row[0] not in data['term']:
                    data['term'][row[0]] = {
                        'name': term_name,
                        'amount': 0,
                        'count': 0,
                        'firm': []
                    }

                data['term'][row[0]]['amount'] += amount
                data['term'][row[0]]['count'] += count

                data['term'][row[0]]['firm'].append(
                    {
                        'name': firm_name,
                        'amount': amount,
                        'count': count
                    }
                )

                data['count'] += count
                data['amount'] += amount

            result.append(data)

        value = dict(
            result=result,
            count=answer['reports_count'],
        )

        return value
Beispiel #10
0
def create_term():
    """
    Create a term from request body data

    :return: 400 response with message if request invalid otherwise
             201 response stating it's been created
    """
    req_data = request.get_json()

    resp_obj = {}
    term = Term(req_data)

    if term.has_errors():
        resp_obj["message"] = term.error_msg()
        return jsonify(resp_obj), 400

    return "created", 201
Beispiel #11
0
def terminal_list():
    """Получаем список терминалов принадлежащих фирме"""

    arg = get_post_arg(request, True)
    answer = Term.select_term_list(
        g.firm_info['id'], **arg)

    return jsonify(answer)
    def set_terms(self, term_id):
        terms = Term.select_name_dict()
        if term_id not in self.terms:

            self.terms[term_id] = dict(
                name=terms[term_id],
                amount=0
            )
        return True
Beispiel #13
0
def terminal_save(term_id, action):
    """Добавляем или редактируем терминал"""

    answer = dict(error='yes', message=u'Произошла ошибка', id=term_id)
    arg = get_post_arg(request, True)
    action_list = ('add', 'edit')

    if action not in action_list:
        abort(400)

    id = int(arg['id']) if 'id' in arg else None

    if 'hard_id' in arg:
        term = Term.get_by_hard_id(arg['hard_id'])
        if term and term.id and term.id != id:
            answer['message'] = u'Терминал с таким SN уже есть в системе'
            return jsonify(answer)

    term = Term.get_by_id(id)
    if not term:
        term = Term()

    form = TermAddForm.from_json(arg)
    if not form.validate():
        answer['message'] = u'Форма заполнена неверно, проверьте формат полей'
        return jsonify(answer)

    form.populate_obj(term)

    result = False
    if 'add' in action:
        result = term.term_add(g.firm_info['id'])
    elif 'edit' in action:
        result = term.save()

    if result:
        answer['error'] = 'no'
        answer['message'] = u'Данные сохранены'
        answer['id'] = term.id
        return jsonify(answer)

    return jsonify(answer)
def create_term(data):
    """
    Napravi objekat Term klase na osnovu .json-a
    """

    term = Term(length=data['trajanje_u_danima'])

    for exam_json in data['ispiti']:
        deps = []
        for department in exam_json['odseci']:
            deps.append(department)

        term.addExam(
            Exam(code=exam_json['sifra'],
                 applied_num=exam_json['prijavljeni'],
                 need_computers=exam_json['racunari'],
                 departments=deps))
        for dep in deps:
            if dep not in all_departments:
                all_departments.append(dep)

    return term
Beispiel #15
0
def terminal_remove(term_id):
    """Удаление терминала вместе с историей"""

    answer = dict(error='yes', message=u'Произошла ошибка')

    term = Term.get_info_by_id(term_id)
    if not term:
        abort(404)

    if term.term_remove():
        answer['error'] = 'no'
        answer['message'] = u'Операция успешно выполнена'
        return jsonify(answer)

    return jsonify(answer)
Beispiel #16
0
def terminal_remove(term_id):
    """Удаление терминала вместе с историей"""

    answer = dict(error='yes', message=u'Произошла ошибка')

    term = Term.get_info_by_id(term_id)
    if not term:
        abort(404)

    if term.term_remove():
        answer['error'] = 'no'
        answer['message'] = u'Операция успешно выполнена'
        return jsonify(answer)

    return jsonify(answer)
Beispiel #17
0
def terminal_rent_info(term_id):
    """Информация о сдачи терминала в аренду"""

    answer = dict(error='yes', message=u'Произошла ошибка')

    term = Term.get_info_by_id(term_id)
    if not term:
        abort(404)

    firm_terms = FirmTerm.get_rent(term.id, g.firm_info['id'])
    rents = [row.to_json() for row in firm_terms]

    answer['error'] = 'no'
    answer['message'] = ''
    answer['rents'] = rents
    return jsonify(answer)
Beispiel #18
0
def terminal_rent_info(term_id):
    """Информация о сдачи терминала в аренду"""

    answer = dict(error='yes', message=u'Произошла ошибка')

    term = Term.get_info_by_id(term_id)
    if not term:
        abort(404)

    firm_terms = FirmTerm.get_rent(term.id, g.firm_info['id'])
    rents = [row.to_json() for row in firm_terms]

    answer['error'] = 'no'
    answer['message'] = ''
    answer['rents'] = rents
    return jsonify(answer)
Beispiel #19
0
def terminal_rent_add(term_id):
    """Сдаём терминал в аренду"""

    answer = dict(error='yes', message=u'Произошла ошибка')
    arg = get_post_arg(request, True)
    error = False

    if not Term.get_by_id(term_id):
        abort(404)

    firm_terms = FirmTerm.query.filter_by(
        term_id=term_id,
        firm_id=g.firm_info['id']).all()
    if not firm_terms:
        abort(405)

    child_firm = Firm.query.filter_by(sub_domain=arg['sub_domain']).first()
    if not child_firm:
        answer['message'] = u'Фирма с таким поддоменом не найдена'
        return jsonify(answer)

    if child_firm.id == g.firm_info['id']:
        answer['message'] = u'Вы не можете сдать терминал сами себе'
        return jsonify(answer)

    parent_firm_id = False
    for firm_term in firm_terms:
        parent_firm_id = firm_term.firm_id
        if firm_term.child_firm_id == child_firm.id:
            error = True

    if error:
        answer['message'] = u'Вы уже сдаете этот терминал данной фирме'
        return jsonify(answer)

    firm_term = FirmTerm()
    firm_term.term_id = term_id
    firm_term.firm_id = parent_firm_id
    firm_term.child_firm_id = child_firm.id

    if firm_term.save():
        answer['error'] = 'no'
        answer['message'] = u'Операция выполнена'

    return jsonify(answer)
Beispiel #20
0
def terminal_rent_add(term_id):
    """Сдаём терминал в аренду"""

    answer = dict(error='yes', message=u'Произошла ошибка')
    arg = get_post_arg(request, True)
    error = False

    if not Term.get_by_id(term_id):
        abort(404)

    firm_terms = FirmTerm.query.filter_by(term_id=term_id,
                                          firm_id=g.firm_info['id']).all()
    if not firm_terms:
        abort(405)

    child_firm = Firm.query.filter_by(sub_domain=arg['sub_domain']).first()
    if not child_firm:
        answer['message'] = u'Фирма с таким поддоменом не найдена'
        return jsonify(answer)

    if child_firm.id == g.firm_info['id']:
        answer['message'] = u'Вы не можете сдать терминал сами себе'
        return jsonify(answer)

    parent_firm_id = False
    for firm_term in firm_terms:
        parent_firm_id = firm_term.firm_id
        if firm_term.child_firm_id == child_firm.id:
            error = True

    if error:
        answer['message'] = u'Вы уже сдаете этот терминал данной фирме'
        return jsonify(answer)

    firm_term = FirmTerm()
    firm_term.term_id = term_id
    firm_term.firm_id = parent_firm_id
    firm_term.child_firm_id = child_firm.id

    if firm_term.save():
        answer['error'] = 'no'
        answer['message'] = u'Операция выполнена'

    return jsonify(answer)
Beispiel #21
0
def terminal_event_info(term_id, term_event_id):
    """Информация о событии привязаном к терминалу"""

    term = Term.get_info_by_id(term_id)
    if not term:
        abort(404)

    term_event = TermEvent.query.get(term_event_id)
    if not term_event:
        abort(404)

    if term_event.term_id != term.id:
        abort(400)

    return render_template('term/terminal/event_view.html',
                           term=term,
                           events=EventType.get_dict(term.type),
                           term_event=term_event,
                           factor=term_event.term.factor)
Beispiel #22
0
    def CreateTerm(self, termText):
        variableName = str()
        variableValue = str()
        isNegated = bool()

        # This is a horrible hack, the fuzzy rule-based system here, doesn't really
        # care about the parentheses
        openingParenthesesCount = 0
        closingParenthesesCount = 0

        variableName = re.split(" is ", termText, flags=re.IGNORECASE)[0]\
            .strip()

        if "(" in variableName:
            openingParenthesesCount = variableName.count("(")
            variableName = variableName.replace("(", str())

        variableValue = re.split(" is ", termText, flags=re.IGNORECASE)[1]\
            .strip()\
            .split(" ")[0]\
            .strip()

        if "not" in variableValue:
            variableValue = re.split(" is ", termText, flags=re.IGNORECASE)[1]\
                .strip()\
                .split(" ")[1]\
                .strip()
            isNegated = True

        if ")" in variableValue:
            closingParenthesesCount = variableValue.count(")")
            variableValue = variableValue.replace(")", str())

        term = Term(\
            LogicalConnectiveEnum._None,\
            isNegated,\
            openingParenthesesCount,\
            closingParenthesesCount,\
            variableName,\
            variableValue)

        return term
Beispiel #23
0
def terminal_event_info(term_id, term_event_id):
    """Информация о событии привязаном к терминалу"""

    term = Term.get_info_by_id(term_id)
    if not term:
        abort(404)

    term_event = TermEvent.query.get(term_event_id)
    if not term_event:
        abort(404)

    if term_event.term_id != term.id:
        abort(400)

    return render_template(
        'term/terminal/event_view.html',
        term=term,
        events=EventType.get_dict(term.type),
        term_event=term_event,
        factor=term_event.term.factor
    )
Beispiel #24
0
def terminal_rent_remove(term_id):
    """Удаляем аренду терминала"""

    answer = dict(error='yes', message=u'Произошла ошибка')
    arg = get_post_arg(request, True)

    if 'id' not in arg:
        abort(405)

    term = Term.get_by_id(term_id)
    if not term:
        abort(404)

    firm_term = FirmTerm.query.get(int(arg['id']))
    if not firm_term:
        abort(404)

    firm_term.term_remove()
    answer['error'] = 'no'
    answer['message'] = u'Операция выполнена'
    return jsonify(answer)
Beispiel #25
0
def terminal_rent_remove(term_id):
    """Удаляем аренду терминала"""

    answer = dict(error='yes', message=u'Произошла ошибка')
    arg = get_post_arg(request, True)

    if 'id' not in arg:
        abort(405)

    term = Term.get_by_id(term_id)
    if not term:
        abort(404)

    firm_term = FirmTerm.query.get(int(arg['id']))
    if not firm_term:
        abort(404)

    firm_term.term_remove()
    answer['error'] = 'no'
    answer['message'] = u'Операция выполнена'
    return jsonify(answer)
Beispiel #26
0
def alarm_save():
    """Создание нового или редактирование оповещения"""

    answer = dict(error='yes', message=u'Произошла ошибка')

    arg = get_post_arg(request, True)
    arg['interval'] = int(arg['interval'][0:2]) * \
        60 * 60 + int(arg['interval'][3:5]) * 60

    if not 'term_id' in arg:
        abort(404)

    term = Term.get_by_id(arg['term_id'])
    if not term:
        abort(404)

    firm_term = FirmTerm.get_list_by_firm_id(g.firm_info['id'])
    if term.id not in firm_term:
        abort(403)

    alarm_stack = AlarmStack.query.filter_by(
        term_id=arg['term_id'], firm_id=g.firm_info['id']).first()
    if not alarm_stack:
        alarm_stack = AlarmStack()

    arg['emails'] = AlarmStack().encode_field(arg['emails'])
    form = TermAlarmForm.from_json(arg)
    if not form.validate():
        answer['message'] = u'Форма заполнена неверно, проверьте формат полей'
        return jsonify(answer)

    form.populate_obj(alarm_stack)
    alarm_stack.firm_id = g.firm_info['id']
    if alarm_stack.save():
        answer['error'] = 'no'
        answer['message'] = u'Оповещение сохранено'

    return jsonify(answer)
Beispiel #27
0
def api_upload_report(term_id, report_datetime):
    """Прием и сохранение отчета"""

    if not len(report_datetime) == 13:
        abort(400)

    if not re.search('\d{6}_\d{6}', str(report_datetime)):
        abort(400)

    term = Term.get_valid_term(term_id)

    if term is None:
        abort(400)

    file = request.stream.read()
    filename = "%s/%s_%s" % (
        app.config['REPORT_TMP_PACH'],
        str(term_id),
        str(report_datetime))

    if not request.headers.get('Content-MD5'):
        abort(400)

    if request.headers.get('Content-MD5') != hash_helper.get_content_md5(file):
        abort(400)

    if file:
        with open(filename, 'w') as f:
            f.write(file)
    else:
        abort(400)

    term.report_date = date_helper.get_current_date()
    term.save()

    ReportParserTask.report_manager.delay(filename)

    return set_message('success', hash_helper.get_content_md5(file), 201)
Beispiel #28
0
def alarm_save():
    """Создание нового или редактирование оповещения"""

    answer = dict(error='yes', message=u'Произошла ошибка')

    arg = get_post_arg(request, True)
    arg['interval'] = int(arg['interval'][0:2]) * \
        60 * 60 + int(arg['interval'][3:5]) * 60

    if not 'term_id' in arg:
        abort(404)

    term = Term.get_by_id(arg['term_id'])
    if not term:
        abort(404)

    firm_term = FirmTerm.get_list_by_firm_id(g.firm_info['id'])
    if term.id not in firm_term:
        abort(403)

    alarm_stack = AlarmStack.query.filter_by(
        term_id=arg['term_id'], firm_id=g.firm_info['id']).first()
    if not alarm_stack:
        alarm_stack = AlarmStack()

    arg['emails'] = AlarmStack().encode_field(arg['emails'])
    form = TermAlarmForm.from_json(arg)
    if not form.validate():
        answer['message'] = u'Форма заполнена неверно, проверьте формат полей'
        return jsonify(answer)

    form.populate_obj(alarm_stack)
    alarm_stack.firm_id = g.firm_info['id']
    if alarm_stack.save():
        answer['error'] = 'no'
        answer['message'] = u'Оповещение сохранено'

    return jsonify(answer)
Beispiel #29
0
def api_set_callback(term_id, action, version=None):
    """Сообщение об удачной загрузки настроек или черного списка"""

    VALID_ACTITON = (
        'config',
        'blacklist'
    )
    if not action in VALID_ACTITON:
        abort(405)

    term = Term.get_valid_term(term_id)

    if term is None:
        abort(404)

    if action == 'config':
        term.config_date = date_helper.get_current_date()
        AlarmStack.reset_count(term.id)
    elif action == 'blacklist':
        term.blacklist_date = date_helper.get_current_date()

    term.save()

    return set_message('success', 'Success', 201)
Beispiel #30
0
def terminal_save(term_id, action):
    """Добавляем или редактируем терминал"""

    answer = dict(error='yes', message=u'Произошла ошибка', id=term_id)
    arg = get_post_arg(request, True)
    action_list = ('add', 'edit')

    if action not in action_list:
        abort(400)

    id = int(arg['id']) if 'id' in arg else None

    if 'hard_id' in arg:
        term = Term.get_by_hard_id(arg['hard_id'])
        if term and term.id and term.id != id:
            answer['message'] = u'Терминал с таким SN уже есть в системе'
            return jsonify(answer)

    term = Term.get_by_id(id)
    if not term:
        term = Term()

    form = TermAddForm.from_json(arg)
    if not form.validate():
        answer['message'] = u'Форма заполнена неверно, проверьте формат полей'
        return jsonify(answer)

    form.populate_obj(term)

    result = False
    if 'add' in action:
        result = term.term_add(g.firm_info['id'])
    elif 'edit' in action:
        result = term.save()

    if result:
        answer['error'] = 'no'
        answer['message'] = u'Данные сохранены'
        answer['id'] = term.id
        return jsonify(answer)

    return jsonify(answer)
Beispiel #31
0
    def get_person_report(self, **kwargs):

        time_pattern = '%H:%M'
        date_pattern = '%d.%m.%Y'
        month_pattern = '%m.%Y'
        self._get_search_params(**kwargs)

        if self.period == 'day':
            result_date_pattern = date_pattern
        elif self.period == 'month':
            result_date_pattern = month_pattern

        answer = self.person_general_query(**kwargs)

        result = []
        events = Event.get_dict()
        term_name_dict = Term.select_name_dict()
        term_tz_dict = Term.select_tz_dict()
        for report in answer['reports']:
            search_date = date_helper.from_utc(
                report[0],
                self.tz)
            creation_date = search_date.strftime(date_pattern)

            data = dict(
                creation_date=search_date.strftime(result_date_pattern),
                amount=0,
                count=0
            )
            summ_kop = 0

            data['page_dates'] = answer['page_dates']
            data['detaled'] = []
            detaled_reports = self.person_detaled_query(search_date)
            for row in detaled_reports:

                term_name = 'Empty'
                if row.term_id in term_name_dict:
                    term_name = term_name_dict[row.term_id]
                    
                tz = self.tz
                if row.term_id in term_tz_dict:
                    tz = term_tz_dict[row.term_id]
                    
                creation_date = date_helper.from_utc(
                    row.creation_date,
                    tz)

                detaled_data = dict(
                    id=row.id,
                    term=term_name,
                    time=creation_date.strftime(time_pattern),
                    date=creation_date.strftime(date_pattern),
                    event=events[
                        row.event_id] if events[
                            row.event_id] else 'Empty',
                    amount=float(row.amount) / 100,
                    name=row.name,
                )
                data['count'] += 1
                summ_kop += row.amount
                data['detaled'].append(detaled_data)

            if summ_kop % 100:
                data['amount'] = "%d.%02d" % (summ_kop / 100, summ_kop % 100)
            else:
                data['amount'] = "%d" % (summ_kop / 100)
            result.append(data)

        value = dict(
            result=result,
            count=answer['reports_count'],
        )
        return value