逆向工程谷歌
回到博客主页

逆向工程谷歌

谷歌Colaboratory被全世界的数据科学家称为“Colab”,是一个免费的云木星笔记本平台。除了为用户提供运行Python和R笔记本的环境外,Colab还慷慨地允许用户共享对有限数量的gpu和tpu的免费访问。

Colab已经迅速成为实际的环境在木星笔记本中进行编码。然而,要利用Colab的计算能力处理木星笔记本以外的任何东西是非常困难的。机器学习工程师想要生产他们的模型,让他们走出笔记本阶段,这是一个特别相关的问题;笔记本虽然非常适合探索,但与更高级的MLOps工具(将训练过程编纂成正式的管道)不太匹配。

几天前我就处在这个位置上,我决定不围绕Colab的限制改变我的工作流程,而是围绕我的工作流程改变Colab !

因此,今天我们将一窥谷歌Colab的内部结构,并发现我们如何可以稍微改变Colab的规则。需要明确的是,我们在这里所做的一切都不会对Colab或该服务的用户造成任何伤害,我们只是在幕后探索。

在窗帘后面

Colab的秘密秘诀在于它的后端:谷歌服务器提供基础设施,让您只需打个响指,按一下按钮就可以运行代码。因此,我们的第一步是分析后端API。要做到这一点,最简单的方法是检查Colab在正常运行期间进行的API调用。为此,我们启动Chrome的开发者工具,找到网络选项卡,然后尝试运行一段代码。DevTools开始记录Colab的每个请求,我们几乎立刻就发现了一些有趣的东西。

socketio request.gif
socketio request.png

它看起来像这样的URL (/桶/ m / < id > / socket . io)是运行在远程机器上的Jupyter套接字的代理。

如果启动Files窗格(该窗格显示/内容从Colab UI的左窗格,我们得到了另一个有趣的请求:

filespane.gif
filespane request.png

这一次,响应体是JSON,枚举远程主机上的文件。看来URL (/桶/ m / < id > / api /内容/)指向提供文件元数据的服务。

filespane json.png

双击Files窗格中的文件,Colab将下载并显示该文件。如果我们试着点击/内容/ sample_data / README.md,我们注意到一个请求/桶/ m / < id > /文件/它返回该文件的内容。

filecontent.png
filecontent response.png

很明显,https://colab.research.google.com/tun/m/ < id > /是运行Colab实例的服务器的反向代理,它提供了/ socket . io/文件,/ api /内容端点。

让我们试着看看这些服务是否在Colab容器实例本身中运行。的lsof程序安装在Colab内部,所以我们运行lsof -iTCP stcp:听列出正在侦听TCP端口上的网络请求的所有进程。

lsof.png

啊哈!colab-fileshim节点,jupyter-notebook这些表面看起来都很值得探索。最佳电子竞技即时竞猜平台。因为我们已经使用了Files窗格,所以让我们看看colab-fileshim第一。它有PID 28,所以我们检查/ proc文件系统查看进程的完整命令行:

fileshim cmdline.png

下一步是调查/usr/local/bin/colab-fileshim.py.具有讽刺意味的是,我们可以通过在“文件”窗格本身中浏览它来做到这一点。该程序看起来就像一个无趣的文件服务器,除了服务器本身的响应外,我们从它中学不到太多东西localhost: 3453 /文件(包含实际的文件内容)和localhost: 3453 / api /内容(JSON元数据)。这意味着Colab将这些请求从隧道URL转发到实例本身的3453端口。

在Chrome DevTools的Network选项卡中,我们可以右键单击一个请求来复制cURL命令来重新生成它。例如,下面是查看README的cURL命令。md文件:

$卷发' https://colab.research.google.com/tun/m/m-s-3oy94z70yrj59/files/content/sample_data/README.md?authuser=0 ' \ - h的权威:colab.research.google.com \ - h”x-colab-tunnel:谷歌“\ - h”接受 : */*' \ - H的dnt: 1 \ - H的接收语言:en - us, en; q = 0.9 \ - H的sec-fetch-site:同源\ - H ' sec-fetch-mode:歌珥\ - H的sec-fetch-dest:空\ - H的推荐人:https://colab.research.google.com/ \ - H的饼干:< < READACTED > >“\ - H的范围:字节= 0 - 930 \——压缩

如果在本地计算机的终端上运行此命令,则会将该README文件的内容打印到我们的终端。通过一些尝试和错误,我们看到我们可以删减大部分的头文件,只留下

$ curl 'https://colab.research.google.com/tun/m/m-s-3oy94z70yrj59/files/content/sample_data/README.md?authuser=0' \ -H 'x-colab-tunnel:谷歌' \ -H 'cookie: << readwritten >>'

x-colab-tunnel头的存在是为了防止我们(或邪恶的攻击者)从普通的浏览器选项卡发出这些请求,表面上是为了阻止XSS攻击。的饼干头向谷歌提供身份验证,以证明我们已经访问了notebook实例。因为cookie很长,处理起来很麻烦,所以我们将把它存储到shell变量中COLAB_COOKIE美元本文的其余部分。

$ COLAB_COOKIE="<<先前修订的值>>" #使用:$ curl…- h“饼干:$ COLAB_COOKIE”

胜利1:暴露我们自己的服务器

现在我们已经发现了Colab的反向代理,让我们看看是否可以使用它来隧道我们自己的请求!

而不是试图打乱现有的colab-fileshim.py服务器,我们可以简单地用我们自己的服务器替换这个进程!我们运行pkill - f colab-fileshim杀死它,这样我们就可以在相同的端口上启动自己的服务器。

作为一个简短而简单的演示,我们将启动python的默认HTTP服务器来提供我们自己的文件localhost: 3453 /文件

新fileshim.png

瞧!我们现在可以更改cURL命令来下载我们自己的文件!

$ curl 'https://colab.research.google.com/tun/m/m-s-3oy94z70yrj59/files/message.txt?authuser=0' \ -H "x-colab-tunnel:谷歌" -H "cookie: $COLAB_COOKIE"嗨!这是我们自己的文件服务器!
$ curl 'https://colab.research.google.com/tun/m/m-s-3oy94z70yrj59/files/shadow?authuser=0' \ -H "x-colab-tunnel:谷歌" -H "cookie: $COLAB_COOKIE" root:*:18585:0:99999:7::: daemon:*:18585:0:99999:7::: bin:*:18585:0:99999:7::: sys:*:18585:0:99999:7:: sync:*:18585:0:99999:7::: #…

注意Colab单元格中的日志行,证明我们的服务器处理了请求:

在0.0.0.0端口3453 (http://0.0.0.0:3453/)上服务HTTP…172.28.0.1 - - [22/Jun/2022 16:43:10] "GET /files/message.txt HTTP/1.1" 200 - 172.28.0.1 - - [22/Jun/2022 16:43:16] "GET /files/shadow HTTP/1.1" 200 -

不幸的是,因为要求x-colab-tunnel:谷歌头,我们无法从浏览器访问服务器。

进一步侦查

让我们继续研究,这次看看我们之前发现的另一个有趣的过程,节点.如果我们检查/proc/7/cmdline,我们看到进程正在运行/ datalab / web / app.js

一旦我们跳到那里读代码,我们就能找到/ datalab /网络包含一个相当标准的NodeJS应用程序。和前面看到的一样/ socketio /路由,它也暴露了一个/ _proxy /{港口}/路线。啊哈!这应该能让我们进入任何URL从任何Colab实例上的端口!

让我们启动一个快速服务器并进行测试。

httpserver.png
$ curl 'https://colab.research.google.com/tun/m/m-s-3oy94z70yrj59/_proxy/1234/some/path?authuser=0' \ -H "x-colab-tunnel:谷歌" -H "cookie: $COLAB_COOKIE" Colab转发服务器!身体负责人< /名称> < / > < > < h1 >从Colab你好!< / h1 > < h2 >路径= /一些/路径< / h2 > < /身体> < / html > %</code></pre>
        <p>如果我们能从浏览器选项卡查看这个HTML页面就好了。不幸的是,科拉布拒绝代理任何请求,除非他们有<code>x-colab-tunnel:谷歌</code>标题设置。如果我们试图从浏览器访问这些url,我们会遇到一个通用的HTTP 400客户端错误页面:</p>
        <figure class="kg-card kg-image-card">
         <img src="//www.kkolawyers.com/blog/content/images/2022/06/400error.png" class="kg-image" alt="400年error.png" srcset="//www.kkolawyers.com/blog/content/images/size/w600/2022/06/400error.png 600w, //www.kkolawyers.com/blog/content/images/2022/06/400error.png 847w" sizes="(min-width: 720px) 720px">
        </figure>
        <h1 id="victory-2-expose-entire-webpages"><strong>胜利2:暴露整个网页</strong></h1>
        <p>幸运的是,我们可以使用<a href="https://chrome.google.com/webstore/detail/modheader/idgpnmonknjnojddfkpgkljpfnnfcklj?src=dagshub">一个Chrome扩展插入HTTP头到浏览器请求实时运行</a>.我们设置它发送<code>x-colab-tunnel:谷歌</code>所有请求的头:</p>
        <figure class="kg-card kg-image-card">
         <img src="//www.kkolawyers.com/blog/content/images/2022/06/modheader.png" class="kg-image" alt="modheader.png" srcset="//www.kkolawyers.com/blog/content/images/size/w600/2022/06/modheader.png 600w, //www.kkolawyers.com/blog/content/images/2022/06/modheader.png 618w">
        </figure>
        <p>然后我们可以在浏览器中启动隧道url !</p>
        <figure class="kg-card kg-image-card">
         <img src="//www.kkolawyers.com/blog/content/images/2022/06/lookma.png" class="kg-image" alt="lookma.png" srcset="//www.kkolawyers.com/blog/content/images/size/w600/2022/06/lookma.png 600w, //www.kkolawyers.com/blog/content/images/size/w1000/2022/06/lookma.png 1000w, //www.kkolawyers.com/blog/content/images/2022/06/lookma.png 1080w" sizes="(min-width: 720px) 720px">
        </figure>
        <h1 id="to-the-moon-planet-jupyter-">来<s>月亮</s>行星Jupyter !</h1>
        <p>最后,让我们看看第三个也是最后一个有趣的过程,<code>jupyter-notebook</code>,它在端口上监听<code>9000</code>.</p>
        <p>首先,我们可以尝试使用前面提到的代理和报头技巧从浏览器访问端口<code>/桶/ m / < id > / _proxy / 9000</code>.不幸的是,我们遇到的是HTTP 500服务器错误页面,而不是理想的Jupyter UI。</p>
        <p>奇怪。我们试着通过跑步来诊断<code>! curl - localhost: 9000</code>从Colab笔记本本身,但我们仍然得到一个错误消息:</p>
        <figure class="kg-card kg-image-card">
         <img src="//www.kkolawyers.com/blog/content/images/2022/06/curlfail.png" class="kg-image" alt="curlfail.png" srcset="//www.kkolawyers.com/blog/content/images/size/w600/2022/06/curlfail.png 600w, //www.kkolawyers.com/blog/content/images/2022/06/curlfail.png 735w" sizes="(min-width: 720px) 720px">
        </figure>
        <p>的输出<code>lsof</code>之前的故事给了我们一个提示与其继续听<code>0.0.0.0</code>/<code>::</code>(所有接口上的所有IP), Jupyter只监听给Colab实例的私有IP。这大概是为了避免木星的界面暴露给我们。</p>
        <p>谷歌当然没有尽力隐藏它,而且有一个快速修复方法。</p>
        <p>为了绕过侦听地址限制,我们需要创建一个在所有接口和IP上侦听的进程,并将它收到的所有流量转发到Jupyter正在侦听的特定IP地址。我们可以安装套接字代理工具<code>socat</code>(“插座猫”)这样做。我们将使用<code>socat</code>转发来自<code>localhost: 9000</code>来<code>主机名:9000美元</code>并返回:</p>
        <figure class="kg-card kg-image-card">
         <img src="//www.kkolawyers.com/blog/content/images/2022/06/socat.png" class="kg-image" alt="socat.png" srcset="//www.kkolawyers.com/blog/content/images/size/w600/2022/06/socat.png 600w, //www.kkolawyers.com/blog/content/images/2022/06/socat.png 739w" sizes="(min-width: 720px) 720px">
        </figure>
        <p>这是一个开始!如果我们在浏览器中重新加载URL,我们会看到Jupyter UI的片段,但它显然已经损坏了。</p>
        <figure class="kg-card kg-image-card">
         <img src="//www.kkolawyers.com/blog/content/images/2022/06/brokenjupyter.png" class="kg-image" alt="brokenjupyter.png" srcset="//www.kkolawyers.com/blog/content/images/size/w600/2022/06/brokenjupyter.png 600w, //www.kkolawyers.com/blog/content/images/2022/06/brokenjupyter.png 919w" sizes="(min-width: 720px) 720px">
        </figure>
        <p>这是因为Jupyter期望在域的根(URL路径)处被访问<code>/</code>),但我们的科拉布隧道有一条<code>/桶/ m / < id > / _proxy / 9000</code>这样一来,CSS和JS文件等资源的绝对路径就会被打乱。</p>
        <p>这里没有简单的解决方案——我们需要一个完整的(子)域来将流量转发到我们的木星服务器。</p>
        <h1 id="victory-3-exposing-jupyter-ui">胜利3:揭露木星UI</h1>
        <p>值得庆幸的是,Colab确实有一个隐藏得很好但官方的端口转发解决方案,它确实提供了整个子域!有趣的是,它隐藏得非常好,我花了比发现内部反向代理更长的时间才找到它!</p>
        <p>要了解如何使用Colab的官方端口转发,您需要从左边栏打开Code Snippets选项卡,并找到Output Handling代码段。点击“查看源笔记本”,你就会被带到<code>advanced_outputs.ipynb</code>,<a href="https://colab.research.google.com/notebooks/snippets/advanced_outputs.ipynb">Colab的强大用户片段花园展示了稻草人记录的平台功能</a>.我们需要的具体代码片段可以在标题“浏览到内核上执行的服务器”下找到。</p>
        <p>我们可以使用这个代码片段将Jupyter UI公开为子域。</p>
        <figure class="kg-card kg-image-card">
         <img src="//www.kkolawyers.com/blog/content/images/2022/06/officialproxy.png" class="kg-image" alt="officialproxy.png" srcset="//www.kkolawyers.com/blog/content/images/size/w600/2022/06/officialproxy.png 600w, //www.kkolawyers.com/blog/content/images/2022/06/officialproxy.png 741w" sizes="(min-width: 720px) 720px">
        </figure>
        <p>现在,我们可以单击链接(并添加)<code>/树</code>到URL来安抚Jupyter),并看到完整的工作* Jupyter UI!</p>
        <figure class="kg-card kg-image-card">
         <img src="//www.kkolawyers.com/blog/content/images/2022/06/workingjupyter.png" class="kg-image" alt="workingjupyter.png" srcset="//www.kkolawyers.com/blog/content/images/size/w600/2022/06/workingjupyter.png 600w, //www.kkolawyers.com/blog/content/images/2022/06/workingjupyter.png 923w" sizes="(min-width: 720px) 720px">
        </figure>
        <p><em>嗯,几乎完全工作。谷歌似乎已经将官方代理限制为只允许GET请求,从而允许我们查看但不运行笔记本。</em></p>
        <h1 id="wrap-up">总结</h1>
        <p>恭喜你,你坚持到了最后!我希望这篇文章对向您展示您所不知道的关于Colab如何工作的事情是有价值的,同时也帮助您学习了一般逆向工程工具的半结构化方法。我也希望这能激励您更深入地了解您每天使用的工具和产品的内部结构!</p>
        <hr>
        <blockquote>
         如果您是一名数据科学家,希望将您的组织的数据和机器学习过程提升到一个新的水平,那么就去看看吧<a href="//www.kkolawyers.com/?utm_source=internal_blog_post_cta">DagsHub</a>.我们的协作平台允许您开发可复制的数据管道,跟踪模型实验,并在整个机器学习生命周期中收集训练数据、注释和训练模型。<br>
         <br>
         <a href="//www.kkolawyers.com/?utm_source=internal_blog_post_cta">DagsHub:人们建立数据科学项目的地方。</a>
        </blockquote>
        <section class="m-tags in-post">
         <h3 class="m-submenu-title">标签</h3>
         <ul>
          <li><a href="//www.kkolawyers.com/blog/tag/open-source-data-science-tools/" title="雷竞技技官网下载开源数据科学工具">雷竞技技官网下载开源数据科学工具</a></li>
          <li><a href="//www.kkolawyers.com/blog/tag/google-colab/" title="谷歌Colab">谷歌Colab</a></li>
         </ul>
        </section>
       </div>
      </div>
     </div>
     <section class="m-sign-up-section show-when-signed-out">
      <div class="l-wrapper in-post">
       <div class="m-sign-up-section__content">
        <div class="m-sign-up-section__text">
         <h4 class="m-sign-up-section__title">加入DAGsHub</h4>
         <p class="m-sign-up-section__description">加入一个有成千上万数据科学家的社区。<br>使用出色的开源工具创建机器学习项目。雷竞技技官网下载</p>
        </div>
        <div class="m-sign-up-section__form">
         <div class="cta signup button">
          <a class="in-post-cta" href="//www.kkolawyers.com/user/sign_up?utm_source=internal_blog_post">注册DAGsHub</a>
          <p class="info-below-sign-up">获得免费的数据存储和<br>MLflow跟踪服务器</p>
         </div>
        </div>
       </div>
      </div>
     </section>
     <section class="m-author">
      <div class="m-author__content">
       <div class="m-author__picture">
        <a href="//www.kkolawyers.com/blog/author/arjvik/" class="m-author-picture" aria-label="Arjun Vikram">
         <div style="background-image: url(//www.kkolawyers.com/blog/content/images/2022/06/Arjun.jpg);"></div></a>
       </div>
       <div class="m-author__info">
        <h4 class="m-author__name"><a href="//www.kkolawyers.com/blog/author/arjvik/">Arjun Vikram</a></h4>
        <p class="m-author__bio">雷竞技技官网下载开源数据科学家@ DagsHub</p>
        <ul class="m-author-links"></ul>
       </div>
      </div>
     </section>
     <section class="m-recommended">
      <div class="l-wrapper in-recommended">
       <h3 class="m-section-title in-recommended">推荐给你</h3>
       <div class="m-recommended-articles">
        <div class="m-recommended-slider glide js-recommended-slider">
         <div class="glide__track" data-glide-el="track">
          <div class="glide__slides">
           <div class="m-recommended-slider__item glide__slide">
            <article class="m-article-card  post tag-ci-cd tag-data-science-workflow tag-github tag-machine-learning tag-machine-learning-production tag-open-source-data-science-tools tag-streamlit tag-tutorial tag-mlops">
             <div class="m-article-card__picture">
              <a href="//www.kkolawyers.com/blog/ci-cd-for-machine-learning-test-and-and-deploy-your-ml-model-with-github-actions/" class="m-article-card__picture-link" aria-hidden="true" tabindex="-1"></a>
              <img class="m-article-card__picture-background" src="//www.kkolawyers.com/blog/content/images/size/w600/2022/06/james-harrison-vpOeXr5wmR4-unsplash.jpg" loading="lazy" alt="">
              <a href="//www.kkolawyers.com/blog/author/khuyen/" class="m-article-card__author js-tooltip" aria-label="Khuyen Tran" data-tippy-content="Posted by Khuyen Tran ">
               <div style="background-image: url(//www.gravatar.com/avatar/cdfdeccf7cd7a1e8a70481674d6a6650?s=250&d=mm&r=x);"></div></a>
             </div>
             <div class="m-article-card__info">
              <a href="//www.kkolawyers.com/blog/tag/ci-cd/" class="m-article-card__tag">CI / CD</a>
              <a href="//www.kkolawyers.com/blog/ci-cd-for-machine-learning-test-and-and-deploy-your-ml-model-with-github-actions/" class="m-article-card__info-link" aria-label="CI/CD for Machine Learning: Test and Deploy Your ML Model with GitHub Actions">
               <div>
                <h2 class="m-article-card__title js-article-card-title " title="CI/CD for Machine Learning: Test and Deploy Your ML Model with GitHub Actions">机器学习CI/CD:用GitHub动作测试和部署您的ML模型</h2>
               </div>
               <div class="m-article-card__timestamp">
                <span>2个月前</span>
                <span>•</span>
                <span>9分钟阅读</span>
               </div></a>
             </div>
            </article>
           </div>
           <div class="m-recommended-slider__item glide__slide">
            <article class="m-article-card  post tag-data-science tag-machine-learning tag-list tag-open-source-data-science-tools tag-tabular-data">
             <div class="m-article-card__picture">
              <a href="//www.kkolawyers.com/blog/imbalance-dataset-test-and-validate-resampled-tabular-data/" class="m-article-card__picture-link" aria-hidden="true" tabindex="-1"></a>
              <img class="m-article-card__picture-background" src="//www.kkolawyers.com/blog/content/images/size/w600/2022/07/colton-sturgeon-6KkYYqTEDwQ-unsplash.jpg" loading="lazy" alt="">
              <a href="//www.kkolawyers.com/blog/author/eryk/" class="m-article-card__author js-tooltip" aria-label="Eryk Lewinson" data-tippy-content="Posted by Eryk Lewinson ">
               <div style="background-image: url(/blog/assets/images/default-avatar-square-small.jpg?v=73d32022ea);"></div></a>
             </div>
             <div class="m-article-card__info">
              <a href="//www.kkolawyers.com/blog/tag/data-science/" class="m-article-card__tag">数据科学</a>
              <a href="//www.kkolawyers.com/blog/imbalance-dataset-test-and-validate-resampled-tabular-data/" class="m-article-card__info-link" aria-label="Using data validation techniques to investigate the impact of data resampling">
               <div>
                <h2 class="m-article-card__title js-article-card-title " title="Using data validation techniques to investigate the impact of data resampling">使用数据验证技术来研究数据重采样的影响</h2>
               </div>
               <div class="m-article-card__timestamp">
                <span>23天前</span>
                <span>•</span>
                <span>14分钟阅读</span>
               </div></a>
             </div>
            </article>
           </div>
           <div class="m-recommended-slider__item glide__slide">
            <article class="m-article-card  post tag-fds tag-git tag-dvc tag-open-source-data-science-tools tag-versioning">
             <div class="m-article-card__picture">
              <a href="//www.kkolawyers.com/blog/fds-fast-data-science-with-git-and-dvc/" class="m-article-card__picture-link" aria-hidden="true" tabindex="-1"></a>
              <img class="m-article-card__picture-background" src="//www.kkolawyers.com/blog/content/images/size/w600/2021/06/fastds-blog3x-1.png" loading="lazy" alt="">
              <a href="//www.kkolawyers.com/blog/author/guy/" class="m-article-card__author js-tooltip" aria-label="Guy Smoilovsky" data-tippy-content="Posted by Guy Smoilovsky ">
               <div style="background-image: url(/blog/content/images/size/w100/2020/08/guyprofile.jpeg);"></div></a>
             </div>
             <div class="m-article-card__info">
              <a href="//www.kkolawyers.com/blog/tag/fds/" class="m-article-card__tag">FDS</a>
              <a href="//www.kkolawyers.com/blog/fds-fast-data-science-with-git-and-dvc/" class="m-article-card__info-link" aria-label="Launching FDS: Ease Of Use And Automation for Git & DVC">
               <div>
                <h2 class="m-article-card__title js-article-card-title " title="Launching FDS: Ease Of Use And Automation for Git & DVC">发布FDS: Git和DVC的易用性和自动化</h2>
               </div>
               <div class="m-article-card__timestamp">
                <span>一年前</span>
                <span>•</span>
                <span>6分钟阅读</span>
               </div></a>
             </div>
            </article>
           </div>
          </div>
         </div>
         <div data-glide-el="controls" class="glide__arrows js-controls">
          <button data-glide-dir="<" class="m-icon-button filled in-recommended-articles glide-prev" aria-label="Previous"><span class="icon-arrow-left" aria-hidden="true"></span></button>
          <button data-glide-dir=">" class="m-icon-button filled in-recommended-articles glide-next" aria-label="Next"><span class="icon-arrow-right" aria-hidden="true"></span></button>
         </div>
        </div>
       </div>
      </div>
     </section>
    </div>
   </article>
  </main>
  <div class="m-search js-search" role="dialog" aria-modal="true" aria-label="Search">
   <button class="m-icon-button outlined as-close-search js-close-search" aria-label="Close search"><span class="icon-close" aria-hidden="true"></span></button>
   <div class="m-search__content">
    <form class="m-search__form">
     <div class="pos-relative">
      <span class="icon-search m-search-icon" aria-hidden="true"></span>
      <label for="search-input" class="sr-only">类型搜索</label>
      <input id="search-input" type="text" class="m-input in-search js-input-search" placeholder="Type to search">
     </div>
    </form>
    <div class="js-search-results hide"></div>
    <p class="m-not-found align-center hide js-no-results">您的搜索没有结果,请尝试用其他的。</p>
   </div>
  </div>
  <footer class="m-footer">
   <div class="m-footer__content">
    <div class="m-footer-copyright">
     <p>RAYBET雷竞技©2022 DagsHub博客</p>
     <p class="made-with">用<a href="https://ghost.org" target="_blank" rel="noopener noreferrer">鬼</a></p>
    </div>
    <nav class="m-footer-social">
     <a href="https://twitter.com/TheRealDAGsHub" target="_blank" rel="noopener" aria-label="Twitter"><span class="icon-twitter" aria-hidden="true"></span></a>
     <a href="https://www.youtube.com/channel/UCeuZrCdpIY69XNWqn9OeSYQ" target="_blank" rel="noopener" aria-label="YouTube"><span class="icon-youtube" aria-hidden="true"></span></a>
     <a href="https://www.linkedin.com/company/dagshub" target="_blank" rel="noopener" aria-label="LinkedIn"><span class="icon-linkedin" aria-hidden="true"></span></a>
     <a href="https://discord.com/invite/9gU36Y6" target="_blank" rel="noopener" aria-label="Discord"><span class="icon-discord" aria-hidden="true"></span></a>
    </nav>
   </div>
  </footer>
  <div class="m-alert success subscribe js-alert" data-notification="subscribe">
   太棒了!您已经成功订阅。<button class="m-alert__close js-notification-close" aria-label="Close"><span class="icon-close"></span></button>
  </div>
  <div class="m-alert success signup js-alert" data-notification="signup">
   太棒了!接下来,完成签出以获得完全访问权限。<button class="m-alert__close js-notification-close" aria-label="Close"><span class="icon-close"></span></button>
  </div>
  <div class="m-alert success signin js-alert" data-notification="signin">
   欢迎回来!您已经成功登录。<button class="m-alert__close js-notification-close" aria-label="Close"><span class="icon-close"></span></button>
  </div>
  <div class="m-alert success checkout js-alert" data-notification="checkout">
   成功!您的帐户已完全激活,您现在可以访问所有内容。<button class="m-alert__close js-notification-close" aria-label="Close"><span class="icon-close"></span></button>
  </div>
  <!-- script tag -->
  <!-- prism.js -->
 </body>
</html>