mirror of
https://github.com/odoo/runbot.git
synced 2025-03-24 11:55:49 +07:00

Sort trigger and group them by category, better selection of categories to display on stats page
399 lines
26 KiB
XML
399 lines
26 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
<data>
|
|
<!-- base layout -->
|
|
<template id="runbot.base_page">
|
|
<html t-att-data-bs-theme="theme">
|
|
<head>
|
|
<title t-esc="title or 'Runbot'"/>
|
|
<link rel="stylesheet" type="text/css" href="/runbot/static/src/libs/bootstrap/css/bootstrap.css"/>
|
|
<link rel="stylesheet" type="text/css" href="/runbot/static/src/libs/fontawesome/css/font-awesome.css"/>
|
|
<link rel="stylesheet" type="text/css" href="/runbot/static/src/css/runbot.css"/>
|
|
|
|
<script src="/runbot/static/src/libs/jquery/jquery.js" type="text/javascript"/>
|
|
<script type="text/javascript" src="/runbot/static/src/libs/popper/popper.js"/>
|
|
<script type="text/javascript" src="/runbot/static/src/libs/bootstrap/js/bootstrap.bundle.js"/>
|
|
<script type="text/javascript" src="/runbot/static/src/js/runbot.js"/>
|
|
|
|
<t t-if="refresh">
|
|
<meta http-equiv="refresh" t-att-content="refresh"/>
|
|
</t>
|
|
|
|
</head>
|
|
<body>
|
|
<t t-out="0"/>
|
|
</body>
|
|
</html>
|
|
</template>
|
|
|
|
<template id="runbot.layout" inherit_id="runbot.base_page" primary="True">
|
|
<xpath expr="//body" position="replace">
|
|
<body>
|
|
<header>
|
|
<nav class="navbar navbar-expand-md bg-body-tertiary">
|
|
<a t-if="project" t-att-href="qu(search=search)">
|
|
<b class="active_project">
|
|
<t t-esc="project.name"/>
|
|
</b>
|
|
</a>
|
|
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#top_menu_collapse">
|
|
<span class="navbar-toggler-icon"/>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="top_menu_collapse">
|
|
<ul class="nav navbar-nav ms-auto text-end" id="top_menu">
|
|
<t t-if="projects">
|
|
<t t-foreach="projects" t-as="l_project">
|
|
<li class="nav-item">
|
|
<a class="nav-link" t-att-href="qu('/runbot/%s' % slug(l_project), search=search)">
|
|
<t t-esc="l_project.name"/>
|
|
</a>
|
|
</li>
|
|
</t>
|
|
</t>
|
|
<li class="nav-item divider"/>
|
|
<li class="nav-item dropdown">
|
|
<a data-bs-toggle="collapse" href="#collapsePreference" role="button" class="nav-link">
|
|
<i class="fa fa-gear"/>
|
|
</a>
|
|
</li>
|
|
<li class="nav-item divider" t-ignore="true"/>
|
|
<t t-if="not user_id._is_public()">
|
|
<t t-call="runbot.build_errors_link"/>
|
|
<li class="nav-item dropdown" t-ignore="true">
|
|
<a href="#" class="nav-link dropdown-toggle" data-bs-toggle="dropdown">
|
|
<b>
|
|
<span t-esc="user_id.name[:23] + '...' if user_id.name and len(user_id.name) > 25 else user_id.name"/>
|
|
</b>
|
|
</a>
|
|
<div class="dropdown-menu dropdown-menu-end js_usermenu" role="menu">
|
|
<a class="dropdown-item" id="o_logout" role="menuitem" t-attf-href="/web/session/logout?redirect=/">Logout</a>
|
|
<a class="dropdown-item" role="menuitem" t-attf-href="/web">Web</a>
|
|
<div t-if="user_id.runbot_team_ids" class="dropdown-divider"/>
|
|
<div t-if="user_id.runbot_team_ids" class="dropdown-header">Teams</div>
|
|
<a t-foreach="user_id.runbot_team_ids" t-as="team" class="dropdown-item" role="menuitem" t-attf-href="/runbot/teams/{{team.id}}">
|
|
<t t-esc="team.name.capitalize()"/>
|
|
</a>
|
|
</div>
|
|
</li>
|
|
</t>
|
|
<t t-else="">
|
|
<li class="nav-item dropdown" t-ignore="true">
|
|
<b>
|
|
<a class="nav-link" t-attf-href="/web/login?redirect={{request.httprequest.path}}">Login</a>
|
|
</b>
|
|
</li>
|
|
</t>
|
|
</ul>
|
|
<t t-out="nav_form or ''">
|
|
</t>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
<div id="collapsePreference" class="collapse">
|
|
<form class="px-4 py-3" method="post" action="/runbot/submit" id="preferences_form">
|
|
<input type="hidden" name="redirect" t-att-value="current_path"/>
|
|
|
|
<hr class="separator"/>
|
|
<div class="form-check form-switch">
|
|
<input onclick="document.getElementById('preferences_form').submit()" class="form-check-input" type="checkbox" role="switch" id="more" name="more" t-att-checked="more"/>
|
|
<label class="form-check-label" for="flexSwitchCheckDefault" >More info</label>
|
|
</div>
|
|
|
|
<hr class="separator"/>
|
|
<div class="text-nowrap btn-group btn-group-sm" role="group">
|
|
<button onclick="document.cookie = 'theme=legacy; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='legacy' else 'secondary'}}">Legacy</button>
|
|
<button onclick="document.cookie = 'theme=dark; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='dark' else 'secondary'}}">Dark</button>
|
|
<button onclick="document.cookie = 'theme=light; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='light' else 'secondary'}}">Light</button>
|
|
<button onclick="document.cookie = 'theme=red404; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='red404' else 'secondary'}}">Red404</button>
|
|
</div>
|
|
|
|
<hr class="separator"/>
|
|
<div class="text-nowrap btn-group btn-group-sm" role="group">
|
|
<button onclick="document.cookie = 'filter_mode=all; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='all' else 'secondary'}}">All</button>
|
|
<button onclick="document.cookie = 'filter_mode=sticky; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='sticky' else 'secondary'}}">Sticky only</button>
|
|
<button onclick="document.cookie = 'filter_mode=nosticky; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='nosticky' else 'secondary'}}">Dev only</button>
|
|
</div>
|
|
|
|
<div class="text-nowrap btn-group btn-group-sm" role="group">
|
|
<t t-foreach="categories" t-as="category">
|
|
<button t-attf-onclick="document.cookie = 'category={{category.id}}; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if category.id == active_category_id else 'secondary'}}" t-esc="category.name"/>
|
|
</t>
|
|
</div>
|
|
|
|
<hr class="separator"/>
|
|
<div t-if="triggers">
|
|
<input type="hidden" name="update_triggers" t-att-value="project.id"/>
|
|
<t t-foreach="categories" t-as="category">
|
|
<t t-set="category_triggers" t-value="triggers.filtered(lambda t: not t.manual and t.category_id == category)"/>
|
|
<t t-if="category_triggers">
|
|
<h3 t-esc="category.name"/>
|
|
<div class="row">
|
|
<t t-foreach="category_triggers" t-as="trigger">
|
|
<div class="col-md-3 text-nowrap">
|
|
<input t-attf-class="trigger_selection {{'trigger_selection_hide' if trigger.hide else 'trigger_selection_show'}}" type="checkbox" t-attf-name="trigger_{{trigger.id}}" t-attf-id="trigger_{{trigger.id}}" t-att-checked="trigger_display is None or trigger.id in trigger_display"/>
|
|
<label t-attf-for="trigger_{{trigger.id}}" t-esc="trigger.name"/>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
</div>
|
|
<button
|
|
onclick="Array.from(document.getElementsByClassName('trigger_selection_show')).forEach((element) => element.checked = true); Array.from(document.getElementsByClassName('trigger_selection_hide')).forEach((element) => element.checked = false); event.preventDefault();"
|
|
class="btn btn-secondary">Reset to default</button>
|
|
<button
|
|
onclick="Array.from(document.getElementsByClassName('trigger_selection')).forEach((element) => element.checked = true); event.preventDefault();"
|
|
class="btn btn-secondary">All</button>
|
|
<button
|
|
onclick="Array.from(document.getElementsByClassName('trigger_selection')).forEach((element) => element.checked = false); event.preventDefault();"
|
|
class="btn btn-secondary">None</button>
|
|
<button type="submit" class="btn btn-primary">Save</button>
|
|
</form>
|
|
</div>
|
|
<t t-out="0"/>
|
|
</body>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="runbot.build_errors_link">
|
|
<t t-if="nb_assigned_errors">
|
|
<li class="nav-item divider"/>
|
|
<li class="nav-item">
|
|
<a href="/runbot/errors" class="nav-link text-danger" t-attf-title="You have {{nb_assigned_errors}} random bug assigned">
|
|
<i class="fa fa-bug"/>
|
|
<t t-esc="nb_assigned_errors"/>
|
|
<span class="text-warning" t-if="nb_team_errors">+<t t-esc="nb_team_errors"/></span>
|
|
</a>
|
|
</li>
|
|
</t>
|
|
<t t-elif="nb_team_errors">
|
|
<li class="nav-item divider"/>
|
|
<li class="nav-item">
|
|
<a href="/runbot/errors" class="nav-link text-warning" t-attf-title="Your team has {{nb_team_errors}} random bug assigned">
|
|
<i class="fa fa-bug"/>
|
|
<t t-esc="nb_team_errors"/>
|
|
</a>
|
|
</li>
|
|
</t>
|
|
<t t-elif="nb_build_errors">
|
|
<li class="nav-item divider"/>
|
|
<li class="nav-item">
|
|
<a href="/runbot/errors" class="nav-link" title="Random Bugs"><i class="fa fa-bug"/></a>
|
|
</li>
|
|
</t>
|
|
</template>
|
|
|
|
<template id="runbot.slots_infos" name="Hosts slot nb pending/testing/slots">
|
|
<a href="/runbot/load_info" class="slots_infos">
|
|
<span t-attf-class="badge text-bg-{{pending_level}}">
|
|
Pending:
|
|
<t t-esc="pending_count"/><span title="Assigned build (reserved host)" t-if="pending_assigned_count">(<t t-esc="pending_assigned_count"/>)</span>
|
|
</span>
|
|
<t t-set="testing" t-value="hosts_data._total_testing()"/>
|
|
<t t-set="workers" t-value="hosts_data._total_workers()"/>
|
|
<t t-set="klass">success</t>
|
|
<t t-if="not workers" t-set="klass">danger</t>
|
|
<t t-else="">
|
|
<t t-if="int(testing)/workers > 0" t-set="klass">info</t>
|
|
<t t-if="int(testing)/workers > 0.75" t-set="klass">warning</t>
|
|
<t t-if="int(testing)/workers >= 1" t-set="klass">danger</t>
|
|
</t>
|
|
<span t-attf-class="badge text-bg-{{klass}}">
|
|
Testing:
|
|
<t t-esc="testing"/>
|
|
/
|
|
<t t-esc="workers"/>
|
|
</span>
|
|
</a>
|
|
</template>
|
|
|
|
<template id="runbot.slot_button">
|
|
<t t-set="bu" t-value="slot.build_id"/>
|
|
<t t-set="color" t-value="bu._get_color_class()"/>
|
|
<div t-attf-class="btn-group btn-group-ssm slot_button_group">
|
|
<span t-attf-class="btn btn-{{color}} disabled" t-att-title="slot.link_type">
|
|
<i t-attf-class="fa fa-{{slot._fa_link_type()}}"/>
|
|
</span>
|
|
<a t-if="bu" t-attf-href="/runbot/batch/{{slot.batch_id.id}}/build/#{bu.id}" t-attf-class="btn btn-default slot_name">
|
|
<span t-esc="slot.trigger_id.name"/>
|
|
</a>
|
|
<span t-else="" t-attf-class="btn btn-default disabled slot_name">
|
|
<span t-esc="slot.trigger_id.name"/>
|
|
</span>
|
|
<a t-if="slot.trigger_id.report_view_id" title="View last trigger report" t-attf-href="/runbot/trigger/report/{{slot.trigger_id.id}}" class="fa fa-eye btn btn-info"/>
|
|
<a t-if="bu.local_state == 'running' and bu.database_ids" t-attf-href="/runbot/run/{{bu.id}}" class="fa fa-sign-in btn btn-info"/>
|
|
<a t-if="bu.static_run" t-att-href="bu.static_run" class="fa fa-sign-in btn btn-info"/>
|
|
<t t-if="bu" t-call="runbot.build_menu"/>
|
|
<a t-if="not bu" groups="base.group_user" class="btn btn-default" title="Create build" t-attf-href="/runbot/batch/slot/{{slot.id}}/build">
|
|
<i class="fa fa-play fa-fw"/>
|
|
</a>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="runbot.build_button">
|
|
<div t-attf-class="pull-right">
|
|
<div t-attf-class="btn-group {{klass}}">
|
|
<a t-if="bu.local_state == 'running' and bu.database_ids" t-attf-href="/runbot/run/{{bu.id}}" class="btn btn-info" title="Sign in on this build" aria-label="Sign in on this build">
|
|
<i class="fa fa-sign-in"/>
|
|
</a>
|
|
<a t-if="bu.static_run" t-att-href="bu.static_run" class="btn btn-info" title="View result" aria-label="View result">
|
|
<i class="fa fa-sign-in"/>
|
|
</a>
|
|
<a groups="base.group_user" t-if="bu.local_state=='done' and (not bu.parent_id.database_ids or user_id.has_group('runbot.group_runbot_advanced_user')) and bu.requested_action != 'wake_up' and bu.database_ids" href="#" data-runbot="wakeup" t-att-data-runbot-build="bu.id" class="btn btn-default" title="Wake up this build" aria-label="Wake up this build">
|
|
<i class="fa fa-coffee"/>
|
|
</a>
|
|
<a t-attf-href="/runbot/build/{{bu['id']}}" class="btn btn-default" title="Build details" aria-label="Build details">
|
|
<i class="fa fa-file-text-o"/>
|
|
</a>
|
|
<!--<a t-if="show_commit_button" t-attf-href="https://#{repo.base_url}/commit/#{bu['name']}" class="btn btn-default" title="Open commit on GitHub" aria-label="Open commit on GitHub"><i class="fa fa-github"/></a>-->
|
|
<t t-call="runbot.build_menu"/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<!-- Event / Logs page -->
|
|
<template id="runbot.build_class">
|
|
<t t-set="rowclass">info</t>
|
|
<t t-if="build.global_state in ['running','done']">
|
|
<t t-if="build.global_result == 'ok'">
|
|
<t t-set="rowclass">success</t>
|
|
</t>
|
|
<t t-if="build.global_result == 'skipped'">
|
|
<t t-set="rowclass">default</t>
|
|
</t>
|
|
<t t-if="build.global_result in ['killed', 'manually_killed']">
|
|
<t t-set="rowclass">killed</t>
|
|
</t>
|
|
</t>
|
|
<t t-if="build.global_result == 'ko'">
|
|
<t t-set="rowclass">danger</t>
|
|
</t>
|
|
<t t-if="build.global_result == 'warn'">
|
|
<t t-set="rowclass">warning</t>
|
|
</t>
|
|
<t t-esc="rowclass"/>
|
|
</template>
|
|
|
|
<template id="runbot.build_menu">
|
|
<button t-attf-class="btn btn-default dropdown-toggle" data-bs-toggle="dropdown" title="Build options" aria-label="Build options" aria-expanded="false">
|
|
<i t-attf-class="fa {{'fa-spinner' if bu.global_state == 'pending' else 'fa-cog'}} {{'' if bu.global_state in ('done', 'running') else 'fa-spin'}} fa-fw"/>
|
|
<span class="caret"/>
|
|
</button>
|
|
<div class="dropdown-menu dropdown-menu-end" role="menu">
|
|
<a t-if="bu.global_result=='skipped'" groups="runbot.group_runbot_admin" class="dropdown-item" href="#" data-runbot="rebuild" t-att-data-runbot-build="bu['id']">
|
|
<i class="fa fa-level-up"/>
|
|
Force Build
|
|
</a>
|
|
<t t-if="bu.local_state=='running'">
|
|
<t t-foreach="bu.database_ids[1:].sorted('name')" t-as="db">
|
|
<a class="dropdown-item" t-attf-href="/runbot/run/{{bu.id}}/{{db.db_suffix}}">
|
|
<i class="fa fa-sign-in"/>
|
|
Connect <t t-esc="db.db_suffix"></t>
|
|
</a>
|
|
</t>
|
|
<a class="dropdown-item" t-attf-href="http://{{bu.domain}}/web/database/selector">
|
|
<i class="fa fa-sign-in"/>
|
|
Database selector
|
|
</a>
|
|
</t>
|
|
<a class="dropdown-item" t-if="bu.global_state in ['done','running'] or bu.requested_action == 'deathrow'" groups="base.group_user" href="#" data-runbot="rebuild" t-att-data-runbot-build="bu['id']" title="Retry this build, usefull for false positive">
|
|
<i class="fa fa-refresh"/>
|
|
Rebuild
|
|
</a>
|
|
<t t-if="bu.global_state != 'done'">
|
|
<t t-if="bu.requested_action != 'deathrow'">
|
|
<a groups="base.group_user" href="#" data-runbot="kill" class="dropdown-item" t-att-data-runbot-build="bu['id']">
|
|
<i class="fa fa-crosshairs"/>
|
|
Kill
|
|
</a>
|
|
</t>
|
|
<t t-else="">
|
|
<a groups="base.group_user" class="dropdown-item disabled">
|
|
<i class="fa fa-spinner fa-spin"/>
|
|
Killing
|
|
<i class="fa fa-crosshairs"/>
|
|
</a>
|
|
</t>
|
|
</t>
|
|
<t t-if="bu.global_state == 'done'">
|
|
<t t-if="bu.requested_action != 'wake_up' and bu.database_ids">
|
|
<a groups="base.group_user" class="dropdown-item" href="#" data-runbot="wakeup" t-att-data-runbot-build="bu['id']">
|
|
<i class="fa fa-coffee"/>
|
|
Wake up
|
|
</a>
|
|
</t>
|
|
<t t-if="bu.requested_action == 'wake_up'">
|
|
<a groups="base.group_user" class="dropdown-item disabled">
|
|
<i class="fa fa-spinner fa-spin"/>
|
|
Waking up
|
|
<i class="fa fa-crosshairs"/>
|
|
</a>
|
|
</t>
|
|
</t>
|
|
<div t-if="bu.global_state not in ('testing', 'waiting', 'pending')" groups="base.group_user" class="dropdown-divider"/>
|
|
<t t-set="log_url" t-value="'http://%s' % bu.host if bu.host != fqdn else ''"/>
|
|
<t t-if="bu.host" t-foreach="bu.log_list.split(',') if bu.log_list else []" t-as="log_name">
|
|
<a class="dropdown-item" t-attf-href="{{log_url}}/runbot/static/build/#{bu.dest}/logs/#{log_name}.txt">
|
|
<i class="fa fa-file-text-o"/>
|
|
Full
|
|
<t t-esc="log_name"/>
|
|
logs
|
|
</a>
|
|
</t>
|
|
<t groups="runbot.group_runbot_admin">
|
|
<div class="dropdown-divider"/>
|
|
<a class="dropdown-item" t-attf-href="/runbot/build/search?config_id={{bu.params_id.config_id.id}}&trigger_id={{bu.params_id.trigger_id.id}}&version_id={{bu.params_id.version_id.id}}&create_batch_id.bundle_id={{bu.params_id.create_batch_id.bundle_id.id}}&description={{bu.description or ''}}">
|
|
<i class="fa fa-search"/>
|
|
Find similar builds
|
|
</a>
|
|
<a class="dropdown-item" t-attf-href="/web/#id={{bu['id']}}&view_type=form&model=runbot.build&menu_id={{env['ir.model.data']._xmlid_to_res_id('runbot.runbot_menu_root')}}" target="new">
|
|
<i class="fa fa-list"/>
|
|
View in backend
|
|
</a>
|
|
</t>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="runbot.branch_github_menu">
|
|
<button t-attf-class="btn btn-default btn-ssm" data-bs-toggle="dropdown" title="Github links" aria-label="Github links" aria-expanded="false">
|
|
<i t-attf-class="fa fa-github {{'text-primary' if any(branch_id.is_pr and branch_id.alive for branch_id in bundle.branch_ids) else 'text-secondary' if all(not branch_id.alive for branch_id in bundle.branch_ids) else ''}}"/>
|
|
<span class="caret"/>
|
|
</button>
|
|
<div class="dropdown-menu" role="menu">
|
|
<t t-foreach="bundle.branch_ids.sorted(key=lambda b: (not b.alive, b.remote_id.repo_id.sequence, b.remote_id.repo_id.id, b.is_pr, b.id))" t-as="branch">
|
|
<t t-set="link_title" t-value="'View %s %s on Github' % ('PR' if branch.is_pr else 'Branch', branch.name)"/>
|
|
<a t-att-href="branch.branch_url" class="dropdown-item" t-att-title="link_title">
|
|
<span class="font-italic text-muted" t-esc="branch.remote_id.short_name"/> <span t-att-class="'' if branch.alive else 'line-through'" t-esc="branch.name"/> <i t-if="not branch.alive" title="deleted/closed" class="fa fa-ban text-danger"/>
|
|
</a>
|
|
</t>
|
|
</div>
|
|
</template>
|
|
|
|
<template id="runbot.branch_copy_button">
|
|
<button t-attf-class="btn btn-default {{btn_size or 'btn-ssm'}}" title="Copy Bundle name" aria-label="Copy Bundle name" t-attf-onclick="copyToClipboard('{{ bundle.name.split(':')[-1] }}')">
|
|
<i t-attf-class="fa fa-clipboard"/>
|
|
</button>
|
|
</template>
|
|
|
|
|
|
<template id="runbot.bundle_stats_dropdown">
|
|
<button t-attf-class="btn btn-default dropdown-toggle" data-bs-toggle="dropdown" title="Bundle Stats" aria-label="Bundle Stats" aria-expanded="false">
|
|
<i t-attf-class="fa fa-bar-chart"/>
|
|
<span class="caret"/>
|
|
</button>
|
|
<div class="dropdown-menu dropdown-menu-start" role="menu">
|
|
<t t-foreach="project.trigger_ids.sorted(lambda t: (t.category_id.id, t.sequence, t.id))" t-as="trigger">
|
|
<t t-if="trigger.has_stats and not trigger.manual" >
|
|
<t t-if="current_category != trigger.category_id">
|
|
<span class="dropdown-item"><b><t t-esc="trigger.category_id.name"/></b></span>
|
|
<t t-set="current_category" t-value="trigger.category_id"/>
|
|
</t>
|
|
<a class="dropdown-item" t-attf-href="/runbot/stats/{{bundle.id}}/{{trigger.id}}">
|
|
<t t-esc="trigger.name" />
|
|
</a>
|
|
</t>
|
|
</t>
|
|
</div>
|
|
</template>
|
|
</data>
|
|
</odoo>
|