mirror of
https://github.com/hohn/codeql-info.git
synced 2025-12-16 20:53:04 +01:00
320 lines
24 KiB
HTML
320 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html lang="en" data-content_root="../">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
|
|
<title>Analyzing control flow in Python — CodeQL</title>
|
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=fa44fd50" />
|
|
<link rel="stylesheet" type="text/css" href="../_static/alabaster.css?v=93459777" />
|
|
<script src="../_static/documentation_options.js?v=5929fcd5"></script>
|
|
<script src="../_static/doctools.js?v=888ff710"></script>
|
|
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
|
|
<link rel="icon" href="../_static/favicon.ico"/>
|
|
<link rel="index" title="Index" href="../genindex.html" />
|
|
<link rel="search" title="Search" href="../search.html" />
|
|
<link rel="next" title="CodeQL for Ruby" href="codeql-for-ruby.html" />
|
|
<link rel="prev" title="Expressions and statements in Python" href="expressions-and-statements-in-python.html" />
|
|
|
|
<title>CodeQL docs</title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<link rel="stylesheet" href="../_static/custom.css" type="text/css" />
|
|
<link rel="stylesheet" href="../_static/primer.css" type="text/css" />
|
|
|
|
|
|
</head><body>
|
|
<header class="Header">
|
|
<div class="Header-item--full">
|
|
<a href="https://codeql.github.com/docs" class="Header-link f2 d-flex flex-items-center">
|
|
<!-- <%= octicon "mark-github", class: "mr-2", height: 32 %> -->
|
|
<svg height="32" class="octicon octicon-mark-github mr-2" viewBox="0 0 16 16" version="1.1" width="32"
|
|
aria-hidden="true">
|
|
<path fill-rule="evenodd"
|
|
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z">
|
|
</path>
|
|
</svg>
|
|
<span class="hide-sm">CodeQL documentation</span>
|
|
</a>
|
|
</div>
|
|
<div class="Header-item hide-sm hide-md">
|
|
<script src="https://addsearch.com/js/?key=93b4d287e2fc079a4089412b669785d5&categories=!0xhelp.semmle.com,0xcodeql.github.com,1xdocs,1xcodeql-standard-libraries,1xcodeql-query-help"></script>
|
|
</div>
|
|
<div class="Header-item">
|
|
|
|
<details class="dropdown details-reset details-overlay d-inline-block">
|
|
<summary class="btn bg-gray-dark text-white border" aria-haspopup="true">
|
|
CodeQL resources
|
|
<div class="dropdown-caret"></div>
|
|
</summary>
|
|
|
|
<ul class="dropdown-menu dropdown-menu-se dropdown-menu-dark">
|
|
<li><a class="dropdown-item" href="https://codeql.github.com/docs/codeql-overview">CodeQL overview</a></li>
|
|
<li class="dropdown-divider" role="separator"></li>
|
|
<div class="dropdown-header">
|
|
CodeQL tools
|
|
</div>
|
|
<li><a class="dropdown-item" href="https://codeql.github.com/docs/codeql-for-visual-studio-code">CodeQL for VS Code</a>
|
|
<li><a class="dropdown-item" href="https://codeql.github.com/docs/codeql-cli">CodeQL CLI</a>
|
|
</li>
|
|
<li class="dropdown-divider" role="separator"></li>
|
|
<div class="dropdown-header">
|
|
CodeQL guides
|
|
</div>
|
|
<li><a class="dropdown-item" href="https://codeql.github.com/docs/writing-codeql-queries">Writing CodeQL queries</a></li>
|
|
<li><a class="dropdown-item" href="https://codeql.github.com/docs/codeql-language-guides">CodeQL language guides</a>
|
|
<li class="dropdown-divider" role="separator"></li>
|
|
<div class="dropdown-header">
|
|
Reference docs
|
|
</div>
|
|
<li><a class="dropdown-item" href="https://codeql.github.com/docs/ql-language-reference/">QL language
|
|
reference</a>
|
|
<li><a class="dropdown-item" href="https://codeql.github.com/codeql-standard-libraries">CodeQL
|
|
standard-libraries</a>
|
|
<li><a class="dropdown-item" href="https://codeql.github.com/codeql-query-help">CodeQL
|
|
query help</a>
|
|
<li class="dropdown-divider" role="separator"></li>
|
|
<div class="dropdown-header">
|
|
Source files
|
|
</div>
|
|
<li><a class="dropdown-item" href="https://github.com/github/codeql">CodeQL repository</a>
|
|
</ul>
|
|
</details>
|
|
|
|
</div>
|
|
|
|
</header>
|
|
<main class="bg-gray-light clearfix">
|
|
<nav class="SideNav position-sticky top-0 col-lg-3 col-md-3 float-left p-4 hide-sm hide-md overflow-y-auto">
|
|
|
|
<ul class="current">
|
|
<li class="toctree-l1"><a class="reference internal" href="../codeql-overview/index.html">CodeQL overview</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="../codeql-for-visual-studio-code/index.html">CodeQL for Visual Studio Code</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="../codeql-cli/index.html">CodeQL CLI</a></li>
|
|
<li class="toctree-l1"><a class="reference internal" href="../writing-codeql-queries/index.html">Writing CodeQL queries</a></li>
|
|
<li class="toctree-l1 current"><a class="reference internal" href="index.html">CodeQL language guides</a><ul class="current">
|
|
<li class="toctree-l2"><a class="reference internal" href="codeql-for-cpp.html">CodeQL for C and C++</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="codeql-for-csharp.html">CodeQL for C#</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="codeql-for-go.html">CodeQL for Go</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="codeql-for-java.html">CodeQL for Java</a></li>
|
|
<li class="toctree-l2"><a class="reference internal" href="codeql-for-javascript.html">CodeQL for JavaScript</a></li>
|
|
<li class="toctree-l2 current"><a class="reference internal" href="codeql-for-python.html">CodeQL for Python</a><ul class="current">
|
|
<li class="toctree-l3"><a class="reference internal" href="basic-query-for-python-code.html">Basic query for Python code</a></li>
|
|
<li class="toctree-l3"><a class="reference internal" href="codeql-library-for-python.html">CodeQL library for Python</a></li>
|
|
<li class="toctree-l3"><a class="reference internal" href="analyzing-data-flow-in-python.html">Analyzing data flow in Python</a></li>
|
|
<li class="toctree-l3"><a class="reference internal" href="using-api-graphs-in-python.html">Using API graphs in Python</a></li>
|
|
<li class="toctree-l3"><a class="reference internal" href="functions-in-python.html">Functions in Python</a></li>
|
|
<li class="toctree-l3"><a class="reference internal" href="expressions-and-statements-in-python.html">Expressions and statements in Python</a></li>
|
|
<li class="toctree-l3 current"><a class="current reference internal" href="#">Analyzing control flow in Python</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="toctree-l2"><a class="reference internal" href="codeql-for-ruby.html">CodeQL for Ruby</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="toctree-l1"><a class="reference internal" href="../ql-language-reference/index.html">QL language reference</a></li>
|
|
</ul>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
<div class="body col-sm-12 col-md-9 col-lg-9 float-left border-left">
|
|
|
|
<div class="hide-lg hide-xl px-4 pt-4">
|
|
|
|
<div class="related" role="navigation" aria-label="related navigation">
|
|
<ul>
|
|
<li class="nav-item nav-item-0"><a href="../contents.html">CodeQL</a> »</li>
|
|
<li class="nav-item nav-item-1"><a href="index.html"
|
|
>CodeQL language guides</a> »</li>
|
|
<li class="nav-item nav-item-2"><a href="codeql-for-python.html"
|
|
accesskey="U">CodeQL for Python</a> »</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<article class="p-4 col-lg-10 col-md-10 col-sm-12">
|
|
|
|
<section id="analyzing-control-flow-in-python">
|
|
<span id="id1"></span><h1>Analyzing control flow in Python<a class="headerlink" href="#analyzing-control-flow-in-python" title="Link to this heading">¶</a></h1>
|
|
<p>You can write CodeQL queries to explore the control-flow graph of a Python program, for example, to discover unreachable code or mutually exclusive blocks of code.</p>
|
|
<section id="about-analyzing-control-flow">
|
|
<h2>About analyzing control flow<a class="headerlink" href="#about-analyzing-control-flow" title="Link to this heading">¶</a></h2>
|
|
<p>To analyze the control-flow graph of a <code class="docutils literal notranslate"><span class="pre">Scope</span></code> we can use the two CodeQL classes <code class="docutils literal notranslate"><span class="pre">ControlFlowNode</span></code> and <code class="docutils literal notranslate"><span class="pre">BasicBlock</span></code>. These classes allow you to ask such questions as “can you reach point A from point B?” or “Is it possible to reach point B <em>without</em> going through point A?”. To report results we use the class <code class="docutils literal notranslate"><span class="pre">AstNode</span></code>, which represents a syntactic element and corresponds to the source code - allowing the results of the query to be more easily understood. For more information, see <a class="reference external" href="https://en.wikipedia.org/wiki/Control_flow_graph">Control-flow graph</a> on Wikipedia.</p>
|
|
</section>
|
|
<section id="the-controlflownode-class">
|
|
<h2>The <code class="docutils literal notranslate"><span class="pre">ControlFlowNode</span></code> class<a class="headerlink" href="#the-controlflownode-class" title="Link to this heading">¶</a></h2>
|
|
<p>The <code class="docutils literal notranslate"><span class="pre">ControlFlowNode</span></code> class represents nodes in the control flow graph. There is a one-to-many relation between AST nodes and control flow nodes. Each syntactic element, the <code class="docutils literal notranslate"><span class="pre">AstNode,</span></code> maps to zero, one, or many <code class="docutils literal notranslate"><span class="pre">ControlFlowNode</span></code> classes, but each <code class="docutils literal notranslate"><span class="pre">ControlFlowNode</span></code> maps to exactly one <code class="docutils literal notranslate"><span class="pre">AstNode</span></code>.</p>
|
|
<p>To show why this complex relation is required consider the following Python code:</p>
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
|
|
<span class="n">might_raise</span><span class="p">()</span>
|
|
<span class="k">if</span> <span class="n">cond</span><span class="p">:</span>
|
|
<span class="k">break</span>
|
|
<span class="k">finally</span><span class="p">:</span>
|
|
<span class="n">close_resource</span><span class="p">()</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>There are many paths through the above code. There are three different paths through the call to <code class="docutils literal notranslate"><span class="pre">close_resource();</span></code> one normal path, one path that breaks out of the loop, and one path where an exception is raised by <code class="docutils literal notranslate"><span class="pre">might_raise()</span></code>.</p>
|
|
<p>An annotated flow graph:</p>
|
|
<p><img alt="Python control flow graph" src="../_images/python-flow-graph.png" /></p>
|
|
<p>The simplest use of the <code class="docutils literal notranslate"><span class="pre">ControlFlowNode</span></code> and <code class="docutils literal notranslate"><span class="pre">AstNode</span></code> classes is to find unreachable code. There is one <code class="docutils literal notranslate"><span class="pre">ControlFlowNode</span></code> per path through any <code class="docutils literal notranslate"><span class="pre">AstNode</span></code> and any <code class="docutils literal notranslate"><span class="pre">AstNode</span></code> that is unreachable has no paths flowing through it. Therefore, any <code class="docutils literal notranslate"><span class="pre">AstNode</span></code> without a corresponding <code class="docutils literal notranslate"><span class="pre">ControlFlowNode</span></code> is unreachable.</p>
|
|
<section id="example-finding-unreachable-ast-nodes">
|
|
<h3>Example finding unreachable AST nodes<a class="headerlink" href="#example-finding-unreachable-ast-nodes" title="Link to this heading">¶</a></h3>
|
|
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import python
|
|
|
|
from AstNode node
|
|
where not exists(node.getAFlowNode())
|
|
select node
|
|
</pre></div>
|
|
</div>
|
|
<p>➤ <a class="reference external" href="https://lgtm.com/query/669220024/">See this in the query console on LGTM.com</a>. The demo projects on LGTM.com all have some code that has no control flow node, and is therefore unreachable. However, since the <code class="docutils literal notranslate"><span class="pre">Module</span></code> class is also a subclass of the <code class="docutils literal notranslate"><span class="pre">AstNode</span></code> class, the query also finds any modules implemented in C or with no source code. Therefore, it is better to find all unreachable statements.</p>
|
|
</section>
|
|
<section id="example-finding-unreachable-statements">
|
|
<h3>Example finding unreachable statements<a class="headerlink" href="#example-finding-unreachable-statements" title="Link to this heading">¶</a></h3>
|
|
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import python
|
|
|
|
from Stmt s
|
|
where not exists(s.getAFlowNode())
|
|
select s
|
|
</pre></div>
|
|
</div>
|
|
<p>➤ <a class="reference external" href="https://lgtm.com/query/670720181/">See this in the query console on LGTM.com</a>. This query gives fewer results, but most of the projects have some unreachable nodes. These are also highlighted by the standard “Unreachable code” query. For more information, see <a class="reference external" href="https://lgtm.com/rules/3980095">Unreachable code</a> on LGTM.com.</p>
|
|
</section>
|
|
</section>
|
|
<section id="the-basicblock-class">
|
|
<h2>The <code class="docutils literal notranslate"><span class="pre">BasicBlock</span></code> class<a class="headerlink" href="#the-basicblock-class" title="Link to this heading">¶</a></h2>
|
|
<p>The <code class="docutils literal notranslate"><span class="pre">BasicBlock</span></code> class represents a basic block of control flow nodes. The <code class="docutils literal notranslate"><span class="pre">BasicBlock</span></code> class is not that useful for writing queries directly, but is very useful for building complex analyses, such as data flow. The reason it is useful is that it shares many of the interesting properties of control flow nodes, such as, what can reach what, and what dominates what, but there are fewer basic blocks than control flow nodes - resulting in queries that are faster and use less memory. For more information, see <a class="reference external" href="https://en.wikipedia.org/wiki/Basic_block">Basic block</a> and <a class="reference external" href="https://en.wikipedia.org/wiki/Dominator_%28graph_theory%29">Dominator</a> on Wikipedia.</p>
|
|
<section id="example-finding-mutually-exclusive-basic-blocks">
|
|
<h3>Example finding mutually exclusive basic blocks<a class="headerlink" href="#example-finding-mutually-exclusive-basic-blocks" title="Link to this heading">¶</a></h3>
|
|
<p>Suppose we have the following Python code:</p>
|
|
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">condition</span><span class="p">():</span>
|
|
<span class="k">return</span> <span class="mi">0</span>
|
|
<span class="k">pass</span>
|
|
</pre></div>
|
|
</div>
|
|
<p>Can we determine that it is impossible to reach both the <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">0</span></code> statement and the <code class="docutils literal notranslate"><span class="pre">pass</span></code> statement in a single execution of this code? For two basic blocks to be mutually exclusive it must be impossible to reach either of them from the other. We can write:</p>
|
|
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import python
|
|
|
|
from BasicBlock b1, BasicBlock b2
|
|
where b1 != b2 and not b1.strictlyReaches(b2) and not b2.strictlyReaches(b1)
|
|
select b1, b2
|
|
</pre></div>
|
|
</div>
|
|
<p>However, by that definition, two basic blocks are mutually exclusive if they are in different scopes. To make the results more useful, we require that both basic blocks can be reached from the same function entry point:</p>
|
|
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>exists(Function shared, BasicBlock entry |
|
|
entry.contains(shared.getEntryNode()) and
|
|
entry.strictlyReaches(b1) and entry.strictlyReaches(b2)
|
|
)
|
|
</pre></div>
|
|
</div>
|
|
<p>Combining these conditions we get:</p>
|
|
</section>
|
|
<section id="example-finding-mutually-exclusive-blocks-within-the-same-function">
|
|
<h3>Example finding mutually exclusive blocks within the same function<a class="headerlink" href="#example-finding-mutually-exclusive-blocks-within-the-same-function" title="Link to this heading">¶</a></h3>
|
|
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import python
|
|
|
|
from BasicBlock b1, BasicBlock b2
|
|
where b1 != b2 and not b1.strictlyReaches(b2) and not b2.strictlyReaches(b1) and
|
|
exists(Function shared, BasicBlock entry |
|
|
entry.contains(shared.getEntryNode()) and
|
|
entry.strictlyReaches(b1) and entry.strictlyReaches(b2)
|
|
)
|
|
select b1, b2
|
|
</pre></div>
|
|
</div>
|
|
<p>➤ <a class="reference external" href="https://lgtm.com/query/671000028/">See this in the query console on LGTM.com</a>. This typically gives a very large number of results, because it is a common occurrence in normal control flow. It is, however, an example of the sort of control-flow analysis that is possible. Control-flow analyses such as this are an important aid to data flow analysis. For more information, see “<a class="reference internal" href="analyzing-data-flow-in-python.html"><span class="doc">Analyzing data flow in Python</span></a>.”</p>
|
|
</section>
|
|
</section>
|
|
<section id="further-reading">
|
|
<h2>Further reading<a class="headerlink" href="#further-reading" title="Link to this heading">¶</a></h2>
|
|
<ul class="simple">
|
|
<li><p><a class="reference external" href="https://github.com/github/codeql/tree/main/python/ql/src">CodeQL queries for Python</a></p></li>
|
|
<li><p><a class="reference external" href="https://github.com/github/codeql/tree/main/python/ql/examples">Example queries for Python</a></p></li>
|
|
<li><p><a class="reference external" href="https://codeql.github.com/codeql-standard-libraries/python/">CodeQL library reference for Python</a></p></li>
|
|
</ul>
|
|
<ul class="simple">
|
|
<li><p>“<a class="reference internal" href="../ql-language-reference/index.html#ql-language-reference"><span class="std std-ref">QL language reference</span></a>”</p></li>
|
|
<li><p>“<a class="reference internal" href="../codeql-overview/codeql-tools.html#codeql-tools"><span class="std std-ref">CodeQL tools</span></a>”</p></li>
|
|
</ul>
|
|
</section>
|
|
</section>
|
|
|
|
|
|
</article>
|
|
|
|
<!-- GitHub footer, with links to terms and privacy statement -->
|
|
<div class="px-3 px-md-6 f6 py-4 d-sm-flex flex-justify-between flex-row-reverse flex-items-center border-top">
|
|
<ul class="list-style-none d-flex flex-items-center mb-3 mb-sm-0 lh-condensed-ultra">
|
|
<li class="mr-3">
|
|
<a href="https://twitter.com/github" title="GitHub on Twitter" style="color: #959da5;">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 273.5 222.3" class="d-block" height="18">
|
|
<path
|
|
d="M273.5 26.3a109.77 109.77 0 0 1-32.2 8.8 56.07 56.07 0 0 0 24.7-31 113.39 113.39 0 0 1-35.7 13.6 56.1 56.1 0 0 0-97 38.4 54 54 0 0 0 1.5 12.8A159.68 159.68 0 0 1 19.1 10.3a56.12 56.12 0 0 0 17.4 74.9 56.06 56.06 0 0 1-25.4-7v.7a56.11 56.11 0 0 0 45 55 55.65 55.65 0 0 1-14.8 2 62.39 62.39 0 0 1-10.6-1 56.24 56.24 0 0 0 52.4 39 112.87 112.87 0 0 1-69.7 24 119 119 0 0 1-13.4-.8 158.83 158.83 0 0 0 86 25.2c103.2 0 159.6-85.5 159.6-159.6 0-2.4-.1-4.9-.2-7.3a114.25 114.25 0 0 0 28.1-29.1"
|
|
fill="currentColor"></path>
|
|
</svg>
|
|
</a>
|
|
</li>
|
|
<li class="mr-3">
|
|
<a href="https://www.facebook.com/GitHub" title="GitHub on Facebook" style="color: #959da5;">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.3 15.4" class="d-block" height="18">
|
|
<path
|
|
d="M14.5 0H.8a.88.88 0 0 0-.8.9v13.6a.88.88 0 0 0 .8.9h7.3v-6h-2V7.1h2V5.4a2.87 2.87 0 0 1 2.5-3.1h.5a10.87 10.87 0 0 1 1.8.1v2.1h-1.3c-1 0-1.1.5-1.1 1.1v1.5h2.3l-.3 2.3h-2v5.9h3.9a.88.88 0 0 0 .9-.8V.8a.86.86 0 0 0-.8-.8z"
|
|
fill="currentColor"></path>
|
|
</svg>
|
|
</a>
|
|
</li>
|
|
<li class="mr-3">
|
|
<a href="https://www.youtube.com/github" title="GitHub on YouTube" style="color: #959da5;">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.17 13.6" class="d-block" height="16">
|
|
<path
|
|
d="M18.77 2.13A2.4 2.4 0 0 0 17.09.42C15.59 0 9.58 0 9.58 0a57.55 57.55 0 0 0-7.5.4A2.49 2.49 0 0 0 .39 2.13 26.27 26.27 0 0 0 0 6.8a26.15 26.15 0 0 0 .39 4.67 2.43 2.43 0 0 0 1.69 1.71c1.52.42 7.5.42 7.5.42a57.69 57.69 0 0 0 7.51-.4 2.4 2.4 0 0 0 1.68-1.71 25.63 25.63 0 0 0 .4-4.67 24 24 0 0 0-.4-4.69zM7.67 9.71V3.89l5 2.91z"
|
|
fill="currentColor"></path>
|
|
</svg>
|
|
</a>
|
|
</li>
|
|
<li class="mr-3 flex-self-start">
|
|
<a href="https://www.linkedin.com/company/github" title="GitHub on Linkedin" style="color: #959da5;">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19 18" class="d-block" height="18">
|
|
<path
|
|
d="M3.94 2A2 2 0 1 1 2 0a2 2 0 0 1 1.94 2zM4 5.48H0V18h4zm6.32 0H6.34V18h3.94v-6.57c0-3.66 4.77-4 4.77 0V18H19v-7.93c0-6.17-7.06-5.94-8.72-2.91z"
|
|
fill="currentColor"></path>
|
|
</svg>
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="https://github.com/github" title="GitHub's organization" style="color: #959da5;">
|
|
<svg version="1.1" width="20" height="20" viewBox="0 0 16 16" class="octicon octicon-mark-github"
|
|
aria-hidden="true">
|
|
<path fill-rule="evenodd"
|
|
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z">
|
|
</path>
|
|
</svg>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
<ul class="list-style-none d-flex text-gray">
|
|
<li class="mr-3">©
|
|
<script type="text/javascript">document.write(new Date().getFullYear());</script> GitHub, Inc.</li>
|
|
<li class="mr-3"><a
|
|
href="https://docs.github.com/github/site-policy/github-terms-of-service"
|
|
class="link-gray">Terms </a></li>
|
|
<li><a href="https://docs.github.com/github/site-policy/github-privacy-statement"
|
|
class="link-gray">Privacy </a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<script type="text/javascript">
|
|
$(document).ready(function () {
|
|
$(".toggle > *").hide();
|
|
$(".toggle .name").show();
|
|
$(".toggle .name").click(function () {
|
|
$(this).parent().children().not(".name").toggle(400);
|
|
$(this).parent().children(".name").toggleClass("open");
|
|
})
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html> |