Files
2023-11-20 11:57:03 -08:00

374 lines
26 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>Using API graphs in Ruby &#8212; 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 Swift" href="codeql-for-swift.html" />
<link rel="prev" title="Analyzing data flow in Ruby" href="analyzing-data-flow-in-ruby.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 and Kotlin</a></li>
<li class="toctree-l2"><a class="reference internal" href="codeql-for-javascript.html">CodeQL for JavaScript and TypeScript</a></li>
<li class="toctree-l2"><a class="reference internal" href="codeql-for-python.html">CodeQL for Python</a></li>
<li class="toctree-l2 current"><a class="reference internal" href="codeql-for-ruby.html">CodeQL for Ruby</a><ul class="current">
<li class="toctree-l3"><a class="reference internal" href="basic-query-for-ruby-code.html">Basic query for Ruby code</a></li>
<li class="toctree-l3"><a class="reference internal" href="codeql-library-for-ruby.html">CodeQL library for Ruby</a></li>
<li class="toctree-l3"><a class="reference internal" href="abstract-syntax-tree-classes-for-working-with-ruby-programs.html">Abstract syntax tree classes for working with Ruby programs</a></li>
<li class="toctree-l3"><a class="reference internal" href="analyzing-data-flow-in-ruby.html">Analyzing data flow in Ruby</a></li>
<li class="toctree-l3 current"><a class="current reference internal" href="#">Using API graphs in Ruby</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="codeql-for-swift.html">CodeQL for Swift</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> &#187;</li>
<li class="nav-item nav-item-1"><a href="index.html"
>CodeQL language guides</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="codeql-for-ruby.html"
accesskey="U">CodeQL for Ruby</a> &#187;</li>
</ul>
</div>
</div>
<article class="p-4 col-lg-10 col-md-10 col-sm-12">
<section id="using-api-graphs-in-ruby">
<span id="id1"></span><h1>Using API graphs in Ruby<a class="headerlink" href="#using-api-graphs-in-ruby" title="Link to this heading"></a></h1>
<p>API graphs are a uniform interface for referring to functions, classes, and methods defined in
external libraries.</p>
<section id="about-this-article">
<h2>About this article<a class="headerlink" href="#about-this-article" title="Link to this heading"></a></h2>
<p>This article describes how you can use API graphs to reference classes and functions defined in library
code. API graphs are particularly useful when you want to model the remote flow sources available from external library functions.</p>
</section>
<section id="module-and-class-references">
<h2>Module and class references<a class="headerlink" href="#module-and-class-references" title="Link to this heading"></a></h2>
<p>The most common entry point into the API graph is when a top-level module or class is accessed.
For example, you can access the API graph node corresponding to the <code class="docutils literal notranslate"><span class="pre">::Regexp</span></code> class
by using the <code class="docutils literal notranslate"><span class="pre">API::getTopLevelMember</span></code> method defined in the <code class="docutils literal notranslate"><span class="pre">codeql.ruby.ApiGraphs</span></code> module, as the
following snippet demonstrates.</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.ApiGraphs
select API::getTopLevelMember(&quot;Regexp&quot;)
</pre></div>
</div>
<p>The example above finds references to a top-level class. For nested
modules and classes, you can use the <code class="docutils literal notranslate"><span class="pre">getMember</span></code> method. For example the following query selects
references to the <code class="docutils literal notranslate"><span class="pre">Net::HTTP</span></code> class.</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.ApiGraphs
select API::getTopLevelMember(&quot;Net&quot;).getMember(&quot;HTTP&quot;)
</pre></div>
</div>
<p>Note that you should specify module names without <code class="docutils literal notranslate"><span class="pre">::</span></code> symbols. If you write <code class="docutils literal notranslate"><span class="pre">API::getTopLevelMember(&quot;Net::HTTP&quot;)</span></code>, it will not do what you expect. Instead, you need to decompose this name
into an access of the <code class="docutils literal notranslate"><span class="pre">HTTP</span></code> member of the API graph node for <code class="docutils literal notranslate"><span class="pre">Net</span></code>, as shown in the example above.</p>
</section>
<section id="calls-and-class-instantiations">
<h2>Calls and class instantiations<a class="headerlink" href="#calls-and-class-instantiations" title="Link to this heading"></a></h2>
<p>To track the calls of externally defined functions, you can use the <code class="docutils literal notranslate"><span class="pre">getMethod</span></code> method. The
following snippet finds all calls of <code class="docutils literal notranslate"><span class="pre">Regexp.compile</span></code>:</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.ApiGraphs
select API::getTopLevelMember(&quot;Regexp&quot;).getMethod(&quot;compile&quot;)
</pre></div>
</div>
<p>The example above is for a call to a class method. Tracking calls to instance methods, is a two-step
process, first you need to find instances of the class before you can find the calls
to methods on those instances. The following snippet finds instantiations of the <code class="docutils literal notranslate"><span class="pre">Regexp</span></code> class:</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.ApiGraphs
select API::getTopLevelMember(&quot;Regexp&quot;).getInstance()
</pre></div>
</div>
<p>Note that the <code class="docutils literal notranslate"><span class="pre">getInstance</span></code> method also includes subclasses. For example if there is a
<code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">SpecialRegexp</span> <span class="pre">&lt;</span> <span class="pre">Regexp</span></code> then <code class="docutils literal notranslate"><span class="pre">getInstance</span></code> also finds <code class="docutils literal notranslate"><span class="pre">SpecialRegexp.new</span></code>.</p>
<p>The following snippet builds on the above to find calls of the <code class="docutils literal notranslate"><span class="pre">Regexp#match?</span></code> instance method:</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.ApiGraphs
select API::getTopLevelMember(&quot;Regexp&quot;).getInstance().getMethod(&quot;match?&quot;)
</pre></div>
</div>
</section>
<section id="subclasses">
<h2>Subclasses<a class="headerlink" href="#subclasses" title="Link to this heading"></a></h2>
<p>Many libraries are used by extending one or more library classes. To track this
in the API graph, you can use the <code class="docutils literal notranslate"><span class="pre">getASubclass</span></code> method to get the API graph node corresponding to
the immediate subclasses of a node. To find <em>all</em> subclasses, use <code class="docutils literal notranslate"><span class="pre">*</span></code> or <code class="docutils literal notranslate"><span class="pre">+</span></code> to apply the
method repeatedly. You can see an example where all subclasses are identified using <code class="docutils literal notranslate"><span class="pre">getASubclass*</span></code> below.</p>
<p>Note that <code class="docutils literal notranslate"><span class="pre">getASubclass</span></code> can only return subclasses that are extracted as part of the CodeQL database
that you are analyzing. When libraries have predefined subclasses, you will need to explicitly include them in your model.
For example, the <code class="docutils literal notranslate"><span class="pre">ActionController::Base</span></code> class has a predefined subclass <code class="docutils literal notranslate"><span class="pre">Rails::ApplicationController</span></code>. To find
all subclasses of <code class="docutils literal notranslate"><span class="pre">ActionController::Base</span></code>, you must explicitly include the subclasses of <code class="docutils literal notranslate"><span class="pre">Rails::ApplicationController</span></code> as well.</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.ApiGraphs
API::Node actionController() {
result =
[
API::getTopLevelMember(&quot;ActionController&quot;).getMember(&quot;Base&quot;),
API::getTopLevelMember(&quot;Rails&quot;).getMember(&quot;ApplicationController&quot;)
].getASubclass*()
}
select actionController()
</pre></div>
</div>
</section>
<section id="using-the-api-graph-in-dataflow-queries">
<h2>Using the API graph in dataflow queries<a class="headerlink" href="#using-the-api-graph-in-dataflow-queries" title="Link to this heading"></a></h2>
<p>Dataflow queries often search for points where data from external sources enters the code base
as well as places where data leaves the code base. API graphs provide a convenient way to refer
to external API components such as library functions and their inputs and outputs.
However, you do not use API graph nodes directly in dataflow queries.</p>
<ul class="simple">
<li><p>API graph nodes model entities that are defined outside your code base.</p></li>
<li><p>Dataflow nodes model entities defined within the current code base.</p></li>
</ul>
<p>You bridge the gap between the entities outside and inside your code base using
the API node class methods: <code class="docutils literal notranslate"><span class="pre">asSource()</span></code> and <code class="docutils literal notranslate"><span class="pre">asSink()</span></code>.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">asSource()</span></code> method is used to select dataflow nodes where a value from an external source
enters the current code base. A typical example is the return value of a library function such as
<code class="docutils literal notranslate"><span class="pre">File.read(path)</span></code>:</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.ApiGraphs
select API::getTopLevelMember(&quot;File&quot;).getMethod(&quot;read&quot;).getReturn().asSource()
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">asSink()</span></code> method is used to select dataflow nodes where a value leaves the
current code base and flows into an external library. For example the second parameter
of the <code class="docutils literal notranslate"><span class="pre">File.write(path,</span> <span class="pre">value)</span></code> method.</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.ApiGraphs
select API::getTopLevelMember(&quot;File&quot;).getMethod(&quot;write&quot;).getParameter(1).asSink()
</pre></div>
</div>
<p>A more complex example is a call to <code class="docutils literal notranslate"><span class="pre">File.open</span></code> with a block argument. This function creates a <code class="docutils literal notranslate"><span class="pre">File</span></code> instance
and passes it to the supplied block. In this case, we are interested in the first parameter of the block because this is where an
externally created value enters the code base, that is, the <code class="docutils literal notranslate"><span class="pre">|file|</span></code> in the Ruby example below:</p>
<div class="highlight-ruby notranslate"><div class="highlight"><pre><span></span><span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s2">&quot;/my/file.txt&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;w&quot;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="o">|</span><span class="n">file</span><span class="o">|</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">&lt;&lt;</span><span class="w"> </span><span class="s2">&quot;Hello world&quot;</span><span class="w"> </span><span class="p">}</span>
</pre></div>
</div>
<p>The following snippet of CodeQL finds parameters of blocks of <code class="docutils literal notranslate"><span class="pre">File.open</span></code> method calls:</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.ApiGraphs
select API::getTopLevelMember(&quot;File&quot;).getMethod(&quot;open&quot;).getBlock().getParameter(0).asSource()
</pre></div>
</div>
<p>The following example is a dataflow query that that uses API graphs to find cases where data that
is read flows into a call to <code class="docutils literal notranslate"><span class="pre">File.write</span></code>.</p>
<div class="highlight-ql notranslate"><div class="highlight"><pre><span></span>import codeql.ruby.DataFlow
import codeql.ruby.ApiGraphs
module Configuration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source = API::getTopLevelMember(&quot;File&quot;).getMethod(&quot;read&quot;).getReturn().asSource()
}
predicate isSink(DataFlow::Node sink) {
sink = API::getTopLevelMember(&quot;File&quot;).getMethod(&quot;write&quot;).getParameter(1).asSink()
}
}
module Flow = DataFlow::Global&lt;Configuration&gt;;
from DataFlow::Node src, DataFlow::Node sink
where Flow::flow(src, sink)
select src, &quot;The data read here flows into a $@ call.&quot;, sink, &quot;File.write&quot;
</pre></div>
</div>
</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/ruby/ql/src">CodeQL queries for Ruby</a></p></li>
<li><p><a class="reference external" href="https://github.com/github/codeql/tree/main/ruby/ql/examples">Example queries for Ruby</a></p></li>
<li><p><a class="reference external" href="https://codeql.github.com/codeql-standard-libraries/ruby/">CodeQL library reference for Ruby</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">&copy;
<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>