Files
releases/docs/index.html
T
Torin Sandall 7b524762b8 Update data filtering example
Remove the API authorization portion of the policy as it's not relevant
in the example.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-11-26 15:10:14 -08:00

422 lines
26 KiB
HTML
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="Policy-based control for cloud native environments">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css" media="screen" charset="utf-8">
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon"/>
<title>Open Policy Agent</title>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon--arrow-up" viewBox="0 0 24 24"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/><path d="M0 0h24v24H0z" fill="none"/></symbol>
<symbol id="social-icon--medium" viewBox="0 0 55 55"><path d="M27.5 0C12.3 0 0 12.3 0 27.5S12.3 55 27.5 55 55 42.7 55 27.5 42.7 0 27.5 0zm-6.2 40.6l-9.6-4.7c-.1-.1-.3-.3-.3-.5V13.6l9.8 4.9v22.1h.1zm1.2-10.4v-9.9l8.8 14.3-8.8-4.4zm3.9-5.8l6.8-10.9 9.9 5L32.9 35l-6.5-10.6zm17 16.2l-9.6-4.7 9.6-15.6v20.3z"/></symbol>
<symbol id="social-icon--slack" viewBox="0 0 55 55"><path d="M23.45 25.382l6.066-2.04 2.01 5.97-6.067 2.04-2.01-5.97z"/><path d="M27.5 0C12.3 0 0 12.3 0 27.5S12.3 55 27.5 55 55 42.7 55 27.5 42.7 0 27.5 0zm14 31.9l-2.9 1 1 3c.5 1.5-.3 3-1.7 3.5-1.5.5-3-.3-3.5-1.7l-1-3-6.1 2 1 3c.5 1.5-.3 3-1.7 3.5-1.5.5-3-.3-3.5-1.7l-1-3-2.8.9c-1.5.5-3-.3-3.5-1.7-.5-1.5.3-3 1.7-3.5l2.8-.9-2-5.9-2.9 1c-1.5.5-3-.3-3.5-1.7-.5-1.5.3-3 1.7-3.5l2.9-1-1-2.8c-.5-1.5.3-3 1.7-3.5 1.5-.5 3 .3 3.5 1.7l1 2.8 6.1-2-1-2.9c-.5-1.5.3-3 1.7-3.5 1.5-.5 3 .3 3.5 1.7l1 2.9 2.9-1c1.5-.5 3 .3 3.5 1.7.5 1.5-.3 3-1.7 3.5l-2.9 1 2 5.9 2.9-1c1.5-.5 3 .3 3.5 1.7s-.3 3-1.7 3.5z"/></symbol>
<symbol id="social-icon--twitter" viewBox="0 0 400 400"><path fill-rule="evenodd" clip-rule="evenodd" d="M400 200c0 110.457-89.543 200-200 200S0 310.457 0 200 89.543 0 200 0s200 89.543 200 200zm-99.4-31.7c0 63.7-48.5 137.2-137.2 137.2-27.2 0-52.6-8-73.7-21.8 3.8.5 7.6.7 11.5.7 22.6 0 43.4-7.7 59.9-20.6-21.1-.4-38.9-14.3-45-33.5 3 .6 6 .9 9.1.9 4.4 0 8.7-.6 12.7-1.7-22.1-4.5-38.7-23.9-38.7-47.3v-.6c6.5 3.6 13.9 5.8 21.8 6-13-8.6-21.5-23.4-21.5-40.1 0-8.8 2.4-17.1 6.5-24.2 23.8 29.2 59.3 48.4 99.4 50.4-.9-3.5-1.3-7.2-1.3-11 0-26.6 21.6-48.2 48.2-48.2 13.9 0 26.4 5.8 35.2 15.2 11-2.2 21.3-6.2 30.6-11.7-3.6 11.3-11.2 20.7-21.2 26.7 9.8-1.2 19.1-3.8 27.7-7.6-6.5 9.7-14.7 18.2-24.1 25 .1 2 .1 4.1.1 6.2z"/></symbol>
<symbol id="social-icon--github" viewBox="0 0 55.1 53.7"><g><path d="M27.5 0C12.3 0 0 12.3 0 27.5 0 39.7 7.9 50 18.8 53.6c1.4.3 1.9-.6 1.9-1.3v-5.1C13 48.9 11.4 44 11.4 44c-1.3-3.2-3.1-4-3.1-4-2.5-1.7.2-1.7.2-1.7 2.8.2 4.2 2.8 4.2 2.8 2.5 4.2 6.4 3 8 2.3.2-1.8 1-3 1.7-3.7-6.1-.7-12.5-3.1-12.5-13.6 0-3 1.1-5.5 2.8-7.4-.3-.7-1.2-3.5.3-7.3 0 0 2.3-.7 7.6 2.8 2.2-.6 4.5-.9 6.9-.9 2.3 0 4.7.3 6.9.9 5.2-3.6 7.6-2.8 7.6-2.8 1.5 3.8.6 6.6.3 7.3 1.8 1.9 2.8 4.4 2.8 7.4 0 10.6-6.4 12.9-12.6 13.6 1 .9 1.9 2.5 1.9 5.1v7.5c0 .7.5 1.6 1.9 1.3C47.2 50 55.1 39.7 55.1 27.5 55 12.3 42.7 0 27.5 0z"/><path d="M10.4 39.5c-.1.1-.3.2-.5.1s-.3-.3-.2-.4c.1-.1.3-.2.5-.1.2 0 .3.2.2.4z"/><path d="M11.5 40.7c-.1.1-.4.1-.6-.1-.2-.2-.2-.4-.1-.6.1-.1.4-.1.6.1.2.2.3.5.1.6z"/><path d="M12.6 42.3c-.2.1-.4 0-.6-.2-.2-.2-.2-.5 0-.7.2-.1.4 0 .6.2.2.3.2.6 0 .7z"/><path d="M14.1 43.8c-.2.2-.5.1-.7-.1s-.3-.5-.2-.7c.2-.2.5-.1.7.1.3.2.4.6.2.7z"/><path d="M16.1 44.7c-.1.2-.4.3-.7.2-.3-.1-.5-.3-.5-.6.1-.2.4-.3.7-.2.4.1.6.4.5.6z"/><path d="M18.4 44.9c0 .2-.3.4-.6.4s-.6-.2-.6-.4.3-.4.6-.4.6.1.6.4z"/><path d="M20.5 44.5c0 .2-.2.4-.5.5s-.6-.1-.7-.3c0-.2.2-.5.5-.5.4 0 .7.1.7.3z"/></g></symbol>
</svg>
<header role="banner">
<nav class="nav--banner" role="navigation">
<ul class="nav--menu">
<li class="nav--menu-item nav--home"><a href="/">Open Policy Agent</a></li>
<li class="nav--menu-item nav--docs"><a href="/docs/" rel="help">Documentation</a></li>
<li class="nav--menu-item nav--docs"><a href="/docs/get-started.html" rel="help">Tutorials</a></li>
</ul>
<ul class="nav--menu">
<li class="nav--menu-item nav--social"><a href="https://blog.openpolicyagent.org/" rel="external"><svg class="nav--social-icon"><title>Medium</title><use xlink:href="#social-icon--medium"/></svg></a></li>
<li class="nav--menu-item nav--social"><a href="https://twitter.com/openpolicyagent" rel="external"><svg class="nav--social-icon"><title>Twitter</title><use xlink:href="#social-icon--twitter"/></svg></a></li>
<li class="nav--menu-item nav--social"><a href="http://slack.openpolicyagent.org/" rel="external"><svg class="nav--social-icon"><title>Slack</title><use xlink:href="#social-icon--slack"/></svg></a></li>
<li class="nav--menu-item nav--social"><a href="https://github.com/open-policy-agent/opa" rel="external"><svg class="nav--social-icon"><title>GitHub</title><use xlink:href="#social-icon--github"/></svg></a></li>
</ul>
</nav>
<div class="headline">
<div class="content">
<h1 class="headline--title">Policy-based control for cloud&nbsp;native environments</h1>
<p class="headline--subtitle">Empower your administrators with flexible, fine-grained control across your entire&nbsp;stack.</p>
<p class="headline--nav">
<a id="headline--get-started" href="/docs/get-started.html" rel="help">Get Started</a>
<a id="headline--learn-more" href="/docs/" rel="help">Learn More</a>
</p>
</div>
<div class="headline--wave--bg" role="presentation"></div>
<div class="headline--wave--fg" role="presentation"></div>
</div>
</header>
<main role="main">
<section class="traits">
<div class="content">
<h2 class="traits--title">Traits</h2>
<dl class="traits--list">
<div class="trait trait--unified">
<dt class="trait--title">Unified</dt>
<dd class="trait--body">Decouple policy decisions from your services to achieve unified control across the entire stack with any language or service.</dd>
</div>
<div class="trait trait--declarative">
<dt class="trait--title">Declarative</dt>
<dd class="trait--body">Express policies in a high-level declarative language that promotes safe, fine-grained logic and enables powerful features such as impact analysis, hot reloading, query optimization, and more.</dd>
</div>
<div class="trait trait--context-aware">
<dt class="trait--title">Context-Aware</dt>
<dd class="trait--body">Leverage arbitrary external document-oriented data (JSON) in policies to ensure that important requirements are enforced throughout the organization.</dd>
</div>
</dl>
</div>
</section>
<section id="use-cases">
<div class="use-cases">
<div class="use-cases--wave" role="presentation"></div>
<div class="content">
<div class="use-cases--content">
<h2>Use Cases</h2>
<div class="use-cases--content--columns">
<p>Open Policy Agent (OPA) is a general-purpose policy engine with uses ranging from authorization and admission control to data filtering. OPA provides greater flexibility and expressiveness than hard-coded service logic or ad-hoc domain-specific languages. And it comes with powerful tooling to help you get started.</p>
<div>
<p>Here are just a few examples of what you can do with OPA:</p>
<ul class="use-cases--toc">
<li class="use-cases--toc--item"><a href="#admission-control">Kubernetes Admission Control</a></li>
<li class="use-cases--toc--item"><a href="#api-authorization">HTTP API Authorization</a></li>
<li class="use-cases--toc--item"><a href="#remote-access">Remote Access</a></li>
<li class="use-cases--toc--item"><a href="#partial-evaluation">Data Filtering with Partial Evaluation</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="examples">
<div class="examples--wave" role="presentation"></div>
<section class="content">
<h2 class="examples--title">Examples</h2>
<section id="admission-control" class="example">
<a class="action--scroll-up" href="/"><svg class="action-icon"><title>Scroll back</title><use xlink:href="#icon--arrow-up"/></svg></a>
<h3 class="example--title">Kubernetes Admission Control</h3>
<img role="presentation" class="example--graphic" src="img/kubernetes-admission-control.svg">
<div class="example--editor">
<div class="example--editor--titlebar">
<span class="example--editor--close-button" role="presentation"></span>
<span class="example--editor--minimize-button" role="presentation"></span>
<span class="example--editor--zoom-button" role="presentation"></span>
<span class="example--editor--title">invariants.rego — ~/src/policies/admission-control/kubernetes</span>
</div>
<pre class="example--editor--body"><span class="code--comment"># Kubernetes Admission Control Invariants</span>
<span class="code--keyword">package</span> kubernetes.<span class="code--package">invariants</span>
<span class="code--keyword">import</span> data.kubernetes.<span class="code--package">ingresses</span>
<span class="code--keyword">import</span> data.kubernetes.<span class="code--package">namespaces</span>
<span class="code--comment"># ---------------------------------------------------------------------
# Ingress Invariants</span>
<span class="code--comment"># Generates a list of non-compliant ingresses identified by `namespace`
# and ingress specification `name`.</span>
<span class="code--rule">violations</span>[{
<span class="code--string">"namespace"</span>: <span class="code--local">namespace</span>,
<span class="code--string">"name"</span>: <span class="code--local">name</span>,
<span class="code--string">"message"</span>: <span class="code--string">"ingress hostname must match whitelist"</span>
}] {
<span class="code--local">ingress</span> <span class="code--operator">:=</span> <span class="code--package">ingresses</span>[<span class="code--local">namespace</span>][<span class="code--local">name</span>]
<span class="code--local">host</span> <span class="code--operator">:=</span> <span class="code--local">ingress</span>.spec.rules[<span class="code--operator">_</span>].host
<span class="code--keyword">not</span> <span class="code--rule">contains</span>(<span class="code--rule">whitelist</span>[<span class="code--local">namespace</span>], <span class="code--local">host</span>)
}
<span class="code--comment"># Generates a list of allowed hostnames per namespace.</span>
<span class="code--rule">whitelist</span>[<span class="code--local">namespace</span>] = <span class="code--local">hosts</span> {
<span class="code--local">obj</span> <span class="code--operator">:=</span> <span class="code--package">namespaces</span>[<span class="code--local">namespace</span>]
<span class="code--local">annotations</span> <span class="code--operator">:=</span> <span class="code--local">obj</span>.metadata.annotations
<span class="code--local">annotation</span> <span class="code--operator">:=</span> <span class="code--local">annotations</span>[<span class="code--string">"acmecorp.com/hostname-whitelist"</span>]</span>
<span class="code--local">hosts</span> <span class="code--operator">:=</span> <span class="code--keyword">json</span>.<span class="code--builtin">unmarshal</span>(<span class="code--local">annotation</span>)
}
<span class="code--comment"># ---------------------------------------------------------------------
# Helpers</span>
<span class="code--comment"># Checks if `list` includes an element matching `item`.</span>
<span class="code--rule">contains</span>(<span class="code--local">list</span>, <span class="code--local">item</span>) {
<span class="code--local">list</span>[<span class="code--operator">_</span>] <span class="code--operator">=</span> <span class="code--local">item</span>
}</pre>
</div>
<div class="example--wave--bg" role="presentation"></div>
<div class="example--wave--fg" role="presentation"></div>
</section>
<section id="api-authorization" class="example">
<a class="action--scroll-up" href="/"><svg class="action-icon"><title>Scroll back</title><use xlink:href="#icon--arrow-up"/></svg></a>
<h3 class="example--title">HTTP API Authorization</h3>
<img role="presentation" class="example--graphic" src="img/api-authorization.svg">
<div class="example--editor">
<div class="example--editor--titlebar">
<span class="example--editor--close-button" role="presentation"></span>
<span class="example--editor--minimize-button" role="presentation"></span>
<span class="example--editor--zoom-button" role="presentation"></span>
<span class="example--editor--title">authz.rego — ~/src/policies/httpapi/acmecorp</span>
</div>
<pre class="example--editor--body"><span class="code--comment"># HTTP API Authorization</span>
<span class="code--keyword">package</span> acmecorp.<span class="code--package">authz</span>
<span class="code--keyword">default</span> <span class="code--rule">allow</span> <span class="code--operator">=</span> <span class="code--primitive">false</span>
<span class="code--comment"># Allow people to read their own salaries.</span>
<span class="code--rule">allow</span> {
<span class="code--package">input</span>.method <span class="code--operator">=</span> <span class="code--string">"GET"</span>
<span class="code--package">input</span>.path <span class="code--operator">=</span> [<span class="code--string">"salaries"</span>, <span class="code--local">employee_id</span>]
<span class="code--package">input</span>.user <span class="code--operator">=</span> <span class="code--local">employee_id</span>
}
<span class="code--comment"># Also allow managers to read the salaries of people they manage.</span>
<span class="code--rule">allow</span> {
<span class="code--package">input</span>.method <span class="code--operator">=</span> <span class="code--string">"GET"</span>
<span class="code--package">input</span>.path <span class="code--operator">=</span> [<span class="code--string">"salaries"</span>, <span class="code--local">employee_id</span>]
<span class="code--package">input</span>.user <span class="code--operator">=</span> <span class="code--package">data</span>.manager_of[<span class="code--local">employee_id</span>]
}</pre>
</div>
<div class="example--wave--bg" role="presentation"></div>
<div class="example--wave--fg" role="presentation"></div>
</section>
<section id="remote-access" class="example">
<a class="action--scroll-up" href="/"><svg class="action-icon"><title>Scroll back</title><use xlink:href="#icon--arrow-up"/></svg></a>
<h3 class="example--title">Remote Access Authorization</h3>
<img role="presentation" class="example--graphic" src="img/ssh-authorization.svg">
<div class="example--editor">
<div class="example--editor--titlebar">
<span class="example--editor--close-button" role="presentation"></span>
<span class="example--editor--minimize-button" role="presentation"></span>
<span class="example--editor--zoom-button" role="presentation"></span>
<span class="example--editor--title">invariants.rego — ~/src/policies/admission-control/kubernetes</span>
</div>
<pre class="example--editor--body"><span class="code--comment"># Fine-Grained SSH Authorization</span>
<span class="code--keyword">package</span> ssh.<span class="code--package">fine_grained</span>
<span class="code--comment"># Allow users in the "dev" organization to SSH into hosts if they
# possess a certificate proving they are assigned to an application
# running on the host.</span>
<span class="code--rule">allow</span> {
<span class="code--comment"># Extract the X.509 certificate provided in the policy query.</span>
<span class="code--local">certs</span> <span class="code--operator">:=</span> <span class="code--builtin">crypto</span>.<span class="code--builtin">x509</span>.<span class="code--builtin">parse_certificates</span>(<span class="code--package">input</span>.certificates)
<span class="code--comment"># Check that the user is part of the "dev" organization for an app
# running on this host.</span>
<span class="code--local">certs</span>[<span class="code--local">i</span>].Subject.Organization[<span class="code--local">j</span>] <span class="code--operator">==</span> <span class="code--package">data</span>.host_info.apps[<span class="code--operator">_</span>]
<span class="code--local">certs</span>[<span class="code--local">i</span>].Subject.OrganizationalUnit[<span class="code--local">j</span>] <span class="code--operator">==</span> <span class="code--string">"dev"</span>
<span class="code--comment"># Check the certificate's validity period at the time of login.</span>
<span class="code--builtin">time</span>.<span class="code--builtin">now_ns</span>() <span class="code--operator">>=</span> <span class="code--local">certs</span>[<span class="code--local">i</span>].NotBefore
<span class="code--builtin">time</span>.<span class="code--builtin">now_ns</span>() <span class="code--operator"><=</span> <span class="code--local">certs</span>[<span class="code--local">i</span>].NotAfter
}</pre>
</div>
<div class="example--wave--bg" role="presentation"></div>
<div class="example--wave--fg" role="presentation"></div>
</section>
<section id="partial-evaluation" class="example">
<a class="action--scroll-up" href="/"><svg class="action-icon"><title>Scroll back</title><use xlink:href="#icon--arrow-up"/></svg></a>
<h3 class="example--title">Data Filtering and Partial Evaluation</h3>
<img role="presentation" class="example--graphic" src="img/partial-evaluation.svg">
<div class="example--editor">
<div class="example--editor--titlebar">
<span class="example--editor--close-button" role="presentation"></span>
<span class="example--editor--minimize-button" role="presentation"></span>
<span class="example--editor--zoom-button" role="presentation"></span>
<span class="example--editor--title">filtering.rego — ~/src/policies/partial-evaluation/app</span>
</div>
<pre class="example--editor--body"><span class="code--comment"># Partial Evaluation</span>
<span class="code--keyword">package</span> app.<span class="code--package">filtering</span>
<span class="code--comment"># ---------------------------------------------------------------------
# Data Filtering</span>
<span class="code--comment"># Allow users to see their own posts.</span>
<span class="code--rule">posts</span>[<span class="code--local">post</span>] {
<span class="code--local">post</span> <span class="code--operator">:=</span> <span class="code--package">data</span>.posts[<span class="code--operator">_</span>]
<span class="code--local">post</span>.owner <span class="code--operator">=</span> <span class="code--package">input</span>.subject.name
}
<span class="code--comment"># Allow users to see posts from their own department</span>
<span class="code--comment"># that they have sufficient clearance for.</span>
<span class="code--rule">posts</span>[<span class="code--local">post</span>] {
<span class="code--local">post</span> <span class="code--operator">:=</span> <span class="code--package">data</span>.posts[<span class="code--operator">_</span>]
<span class="code--local">post</span>.department <span class="code--operator">=</span> <span class="code--package">input</span>.subject.department
<span class="code--local">post</span>.security_level <span class="code--operator">&lt;=</span> <span class="code--package">input</span>.subject.clearance_level
}
<span class="code--comment"># Example Output:</span>
<span class="code--comment">#</span>
<span class="code--comment"># Conditions (1)</span>
<span class="code--comment"># --------------</span>
<span class="code--comment"># data.posts[x].owner = "bob"</span>
<span class="code--comment">#</span>
<span class="code--comment"># Conditions (2)</span>
<span class="code--comment"># --------------</span>
<span class="code--comment"># data.posts[x].department = "ops"</span>
<span class="code--comment"># data.posts[x].clearance_level &lt;= 3</span>
</pre>
</div>
<div class="example--wave--bg" role="presentation"></div>
<div class="example--wave--fg" role="presentation"></div>
</section>
</section>
</div>
</main>
<footer role="contentinfo">
<div class="content">
<nav class="nav--footer" role="navigation">
<ul class="nav--menu">
<li class="nav--menu-item nav--docs"><a href="/docs/" rel="help">Documentation</a></li>
<li class="nav--menu-item nav--docs"><a href="/docs/get-started.html" rel="help">Tutorials</a></li>
</ul>
<ul class="nav--menu">
<li class="nav--menu-item nav--social"><a href="https://blog.openpolicyagent.org/" rel="external"><svg class="nav--social-icon"><title>Medium</title><use xlink:href="#social-icon--medium"/></svg></a></li>
<li class="nav--menu-item nav--social"><a href="https://twitter.com/openpolicyagent" rel="external"><svg class="nav--social-icon"><title>Twitter</title><use xlink:href="#social-icon--twitter"/></svg></a></li>
<li class="nav--menu-item nav--social"><a href="http://slack.openpolicyagent.org/" rel="external"><svg class="nav--social-icon"><title>Slack</title><use xlink:href="#social-icon--slack"/></svg></a></li>
<li class="nav--menu-item nav--social"><a href="https://github.com/open-policy-agent/opa" rel="external"><svg class="nav--social-icon"><title>GitHub</title><use xlink:href="#social-icon--github"/></svg></a></li>
</ul>
</nav>
<p class="copyright">© 2017 Open Policy Agent contributors. Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>. For information about contributing, see <a href="https://github.com/open-policy-agent/opa/blob/master/CONTRIBUTING.md">CONTRIBUTING.md</a>.</p>
</div>
</footer>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');ga('create', 'UA-84550302-1', 'auto');ga('send', 'pageview');
</script>
<script>
(function () {
var scrollIncrement = 4
var scrollTop = 0
var page
function clearSchedule(x) {
clearTimeout(x)
}
function setSchedule(x) {
setTimeout(x, 16)
}
function schedule(callback) {
var frameId
(function () {
clearSchedule(frameId)
frameId = setSchedule(callback)
}())
}
function calculateScrollTop(el) {
var y = 0
var node = el
while (node) {
y += node.offsetTop
node = node.offsetParent
}
return y
}
var scrollIncrement = 4
function animateScrollTop(top, n) {
var n = n || 1
schedule(function () {
var diff = top - page.scrollTop
var increment = scrollIncrement * n
if (diff) {
if (Math.abs(diff) < increment) {
page.scrollTop += diff
} else if (diff > 0) {
page.scrollTop += increment
} else {
page.scrollTop -= increment
}
animateScrollTop(top, ++n)
}
})
}
function scrollIntoView(event) {
var el = document.getElementById(event.currentTarget.getAttribute('href').substr(1))
animateScrollTop(calculateScrollTop(el) - 120)
// XXX: When Chrome 70.0.3538.77 navigates to an internal anchor (#),
// it breaks the page layout so we dont want to do that.
event.preventDefault()
}
function scrollUp(event) {
animateScrollTop(calculateScrollTop(document.getElementById('use-cases')))
event.preventDefault()
}
function ready() {
page = document.documentElement
if (typeof requestAnimationFrame === 'function') {
clearFrame = cancelAnimationFrame
setFrame = requestAnimationFrame
}
var anchors = document.getElementsByTagName('a')
for (let i = 0, n = anchors.length; i < n; ++i) {
var anchor = anchors[i]
var href = anchor.getAttribute('href')
var classes = (anchor.className || '').split(/\s+/)
if (href && href[0] === '#') {
anchor.addEventListener('click', scrollIntoView)
} else if (classes.indexOf('action--scroll-up') > -1) {
anchor.addEventListener('click', scrollUp)
}
}
}
(function check() { /complete/.test(document.readyState) ? ready() : setTimeout(check) }())
}())
</script>
</body>
</html>