Python FileServer

https://stackabuse.com/serving-files-with-pythons-simplehttpserver-module/

python3 -m http.server 
python3 -m http.server 8001

-- python2
python -m SimpleHTTPServer 端口号

-- File Upload
pip install uploadserver
python3 -m uploadserver

File upload

https://pypi.org/project/uploadserver/#description

https://cloud.tencent.com/developer/article/1858229

----- 命令行上传
curl -v http://localhost:8000/upload -F files=@snap2html.lua
curl -v http://192.168.22.239:8000/upload -F files=@xx

-F files=@path/to/file
-T  或者 --upload-file 
md5sum $1 | curl --user ${NEXUS_AUTH} -T - 

----- 网页上传
<body>
<h1>File Upload</h1>
<form action="upload" method="POST" enctype="multipart/form-data">
<input name="files" type="file" multiple />
<br />
<br />
<input type="submit" />
</form>
<p id="task"></p>
<p id="status"></p>
</body>

文件服务器 FTP(XAMPP)

Step1:  Start Filezilla
点击 Admin, 默认无密码,进入设置页面
Edit => Setting  设置端口, 默认21

Step2: Edit => Users
创建用户cccc,  输入密码cccc2023
添加目录D:\pub,  分配给用户cccc, 所有权限(不需要设置home)

客户端

==== 桌面
文件管理器Network, 输入 ftp://192.168.2.2
[root@archiso ~]# ls /run/user/0/gvfs/
'ftp:host=192.168.2.2'

===== 命令行
install curlftpfs 
curlftpfs cccc:cccc2023@192.168.2.2 ./pub/

文件服务器 Rsync

rsync -avzP ./kylin10sp1-desktop-x64-template.qcow2   cccc@10.31.66.80::backup
rsync -avzP ./newdir/   cccc@10.31.66.80::backup

服务器配置

echo "cccc:cccc2023" > /etc/rsync.password
chmod 600 /etc/rsync.password

sudo systemctl start rsyncd
sudo firewall-cmd --list-all

vi /etc/rsyncd.conf

uid = root
gid = root
use chroot = no
max connections = 40
pid file = /var/run/rsyncd.pid
log file = /var/log/rsyncd.log
exclude = lost+found/
transfer logging = yes
timeout = 900
ignore nonreadable = yes
dont compress   = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2
auth users = cccc
secrets file = /etc/rsync.password

[backup]
path = /data1/backup
comment = my backup dir
read only = false

文件服务器 ZFile

https://docs.zfile.vip/install/os-linux

mkdir -p /data/pub    # 本地存储

mkdir -p /root/zfile   # 声明安装到的路径
wget --no-check-certificate https://c.jun6.net/ZFILE/zfile-release.war  # 下载 zfile 最新版
unzip zfile-release.war && rm -rf zfile-release.war      # 解压并删除压缩包
chmod +x bin/*.sh                    
./bin/start.sh
http://192.168.122.209:8080

先不用onlyoffice, 好像只能用这个版本
https://docker.aityp.com/image/docker.io/onlyoffice/documentserver:7.1.1
podman run --restart=always --name onlyoffice \
    -p 8081:80 \
    -e JWT_ENABLED=false \
    -d onlyoffice

文件服务器 SMB

Fedora Not disaplay in filemanager https://discussion.fedoraproject.org/t/smbclient-works-but-how-to-mount-as-user/68984/7

# mount -t cifs -o rw,vers=3.0,credentials=/data/shareuser //192.168.2.3/Share /data/Share

sudo mount -t cifs -o username=cccc,password=cccc2023,uid=1000,gid=1000 //192.168.2.3/Share /data/Share

Fedora FileManager mount

/run/user/1000/gvfs/smb-share:server=192.168.2.3,share=share

目录浏览 Apache

   Alias /pub "D:/pub/"
    <Directory "D:/pub">
        Options +Indexes
        IndexOptions FancyIndexing FoldersFirst VersionSort
        IndexOptions NameWidth=60
        IndexOptions IconHeight=16
        IndexOptions IconWidth=16

        Require all granted
        ErrorDocument 403 /error/XAMPP_FORBIDDEN.html.var
    </Directory>

sudo mkdir /data/pub

sudo chown aaa:aaa /data/pub

====== /etc/httpd/conf.d/pub.conf
Alias /pub "/data/pub/"
<Directory "/data/pub">
    Options Indexes MultiViews FollowSymlinks
    AllowOverride None
    Require all granted

        IndexOptions FancyIndexing FoldersFirst VersionSort
        IndexOptions NameWidth=60
        IndexOptions IconHeight=16
        IndexOptions IconWidth=16
</Directory>

目录浏览 Caddy

二进制文件 /usr/loca/bin/caddy
http://mirrors.ustc.edu.cn/debian/pool/main/c/caddy/
https://github.com/caddyserver/caddy/releases/download/v2.8.4/caddy_2.8.4_linux_amd64.tar.gz
配置文件 /lib/systemd/system/caddy.service

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
#User=caddy
#Group=caddy
ExecStart=/usr/local/bin/caddy file-server --browse --root /data/share
#ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

官网deb问题

sudo apt install caddy
默认会创建caddy用户, 卸载不会删除
使用caddy用户启动服务,访问目录/data/xxx报错403 forbidden
额外启动caddy-api.service

目录浏览 Nginx

https://www.f5.com/company/blog/nginx/avoiding-top-10-nginx-configuration-mistakes

mkdir -p /data/mirror/gitpub
vi /etc/nginx/sites-available/default
location /pub/ {
    charset gbk,utf-8;
    alias /data/mirror/gitpub/;
    index off;
    autoindex on;
    autoindex_localtime on;
    autoindex_exact_size off;
}

autoindex.html

<script>
    !function () {
        website_title = ''
        max_name_length = 60
        enable_readme_md = true
        omit_icon_if_emoji = true
        datetime_format = '%Y-%m-%d %H:%M:%S'

        var dom = {
            element: null,
            get: function (o) {
                var obj = Object.create(this)
                obj.element = (typeof o == "object") ? o : document.createElement(o)
                return obj
            },
            add: function (o) {
                var obj = dom.get(o)
                this.element.appendChild(obj.element)
                return obj
            },
            text: function (t) {
                this.element.appendChild(document.createTextNode(t))
                return this
            },
            html: function (s) {
                this.element.innerHTML = s
                return this
            },
            attr: function (k, v) {
                this.element.setAttribute(k, v)
                return this
            }
        }

        head = dom.get(document.head)
        head.add('link').attr('rel', 'manifest').attr('href', '/manifest.json')
        head.add('meta').attr('charset', 'utf-8')
        head.add('meta').attr('charset', 'utf-8')
        head.add('meta').attr('name', 'viewport').attr('content', 'width=device-width,initial-scale=1')

        if (!document.title) {
            document.write(["<div class=\"container\">",
                "<h3>nginx.conf</h3>",
                "<textarea rows=8 cols=50>",
                "# download autoindex.html to /wwwroot/",
                "location ~ ^(.*)/$ {",
                "    charset utf-8;",
                "    autoindex on;",
                "    autoindex_localtime on;",
                "    autoindex_exact_size off;",
                "    add_after_body /autoindex.html;",
                "}",
                "</textarea>",
                "</div>"].join("\n"))
            return
        }

        var bodylines = document.body.innerHTML.split('\n')
        document.body.innerHTML = ''

        titlehtml = document.title.replace(/\/$/, '').split('/').slice(1).reduce(function (acc, v, i, a) {
            return acc + '<a href="/' + a.slice(0, i + 1).join('/') + '/">' + v + '</a>/'
        }, '<a href="./">Index</a> of /')
        if (website_title) {
            document.title = website_title + ' - ' + document.title
        }
        head.add('meta').attr('name', 'description').attr('content', document.title)

        div = dom.get('div').attr('class', 'container')
        div.add('table').add('tbody').add('tr').add('th').html(titlehtml)
        table = div.add('table').attr('class', 'table-hover').add('tbody')

        columns = ['Name', 'Date', 'Size']
        thead = table.add('tr')
        for (i = 0; i < columns.length; i++)
            thead.add('td').add('a').attr('href', 'javascript:sortby(' + i + ')').attr('class', 'octicon arrow-up').text(columns[i]);
        thead.add('td').attr('class', 'octicon').text('Preview')

        var insert = function (filename, datetime, size) {
            if (omit_icon_if_emoji && /^(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]) /.test(filename)) {
                css = ''
            } else if (filename == '../') {
                css = 'octicon file-symlink-directory'
            } else if (/\/$/.test(filename)) {
                css = 'octicon file-directory'
            } else if (/\.(zip|7z|bz2|gz|tar|tgz|tbz2|xz|cab)$/.test(filename)) {
                css = 'octicon file-zip'
            } else if (/\.(py|js|php|pl|rb|sh|bash|lua|sql|go|rs|java|c|h|cpp|cxx|hpp)$/.test(filename)) {
                css = 'octicon file-code'
            } else if (/\.(pdf|ps)$/.test(filename)) {
                css = 'octicon file-pdf'
            } else if (/\.(jpg|png|bmp|gif|ico|webp)$/.test(filename)) {
                css = 'octicon file-media'
            } else if (/\.(flv|mp4|mkv|avi|mkv|vp9)$/.test(filename)) {
                css = 'octicon device-camera-video'
            } else {
                css = 'octicon file'
            }

            displayname = decodeURIComponent(filename.replace(/\/$/, ''))
            if (displayname.length > max_name_length)
                displayname = displayname.substring(0, max_name_length - 3) + '..>';

            if (!isNaN(Date.parse(datetime))) {
                d = new Date(datetime)
                pad = function (s) { return s < 10 ? '0' + s : s }
                mon = function (m) { return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][m] }
                datetime = datetime_format
                    .replace('%Y', d.getFullYear())
                    .replace('%m', pad(d.getMonth() + 1))
                    .replace('%d', pad(d.getDate()))
                    .replace('%H', pad(d.getHours()))
                    .replace('%M', pad(d.getMinutes()))
                    .replace('%S', pad(d.getSeconds()))
                    .replace('%b', mon(d.getMonth()))
            }

            tr = table.add('tr')
            tr.add('td').add('a').attr('class', css).attr('href', filename).text(displayname)
            tr.add('td').text(datetime)
            tr.add('td').text(size == '-' ? '' : size)
            if (/\.(md)$/.test(filename)) {
                tr.add('td').add('input').attr('type', 'button').attr('value', 'Preview').attr('onclick', 'onPreview("' + filename + '")').attr('id', filename)
            } else {
                tr.add('td')
            }
        }

        var readme_md = ''
        insert('../', '', '-')
        for (var i in bodylines) {
            if (m = /\s*<a href="(.+?)">(.+?)<\/a>\s+(\S+)\s+(\S+)\s+(\S+)\s*/.exec(bodylines[i])) {
                filename = decodeURIComponent(m[1])
                datetime = m[3] + ' ' + m[4]
                size = m[5]
                if (filename.toLowerCase() == 'readme.md') {
                    readme_md = filename
                }
                insert(filename, datetime, size)
            }
        }

        document.documentElement.lang = navigator.language
        document.body.appendChild(div.element)

        if (enable_readme_md && readme_md !== '') {
            readme = div.add('table').add('tbody');
            readme.add('tr').add('th').attr('class', 'octicon octicon-book').text(readme_md)
            readme.add('tr').add('td').add('div').attr('id', 'readme').attr('class', 'markdown-body')
            xhr = new XMLHttpRequest()
            xhr.open('GET', location.pathname.replace(/[^/]+$/, '') + readme_md, true)
            xhr.onload = function () {
                if (xhr.status < 200 && xhr.status >= 400)
                    return
                wait('marked', function () {
                    document.getElementById("readme").innerHTML = marked.parse(xhr.responseText)
                    begin = xhr.responseText.indexOf('<!--<script>')
                    end = xhr.responseText.indexOf("\n</" + "script>-->")
                    if (begin < end)
                        div.add('script').html(xhr.responseText.substr(begin + 4 + 8, end + 1 - begin - 4 - 8))
                })
            }
            xhr.send()

            div.add('script').attr('src', 'https://jsd.737679.xyz/npm/marked@13.0.3/marked.min.js').attr('crossorigin', 'anonymous')
            div.add('link').attr('rel', 'stylesheet').attr('href', 'https://jsd.737679.xyz/npm/github-markdown-css@5.6.1/github-markdown-light.min.css').attr('crossorigin', 'anonymous')
        }
    }()

    function onPreview(filename) {
        myWindow = window.open('', '_blank', '');
        myWindow.document.write("<div id='markdown'></div");
        myWindow.document.title = filename
        ele = myWindow.document.getElementById("markdown")

        xhr = new XMLHttpRequest()
        xhr.open('GET', location.pathname.replace(/[^/]+$/, '') + filename, true)
        xhr.onload = function () {
            if (xhr.status < 200 && xhr.status >= 400)
                return
            wait('marked', function () {
                myWindow.document.getElementById("markdown").innerHTML = marked.parse(xhr.responseText)
            })
        }
        xhr.send()
        div.add('script').attr('src', 'https://jsd.737679.xyz/npm/marked@13.0.3/marked.min.js').attr('crossorigin', 'anonymous')
        div.add('link').attr('rel', 'stylesheet').attr('href', 'https://jsd.737679.xyz/npm/github-markdown-css@5.6.1/github-markdown-light.min.css').attr('crossorigin', 'anonymous')
        myWindow.focus();
    }

    function wait(name, callback) {
        var interval = 10; // ms
        window.setTimeout(function () {
            if (window[name] && !(window[name] instanceof HTMLElement)) {
                callback(window[name])
            } else if (window[name] instanceof HTMLElement && window[name].innerHTML) {
                callback(window[name])
            } else {
                window.setTimeout(arguments.callee, interval)
            }
        }, interval)
    }

    function sortby(index) {
        rows = document.getElementsByClassName('table-hover')[0].rows
        link = rows[0].getElementsByTagName('a')[index]
        arrow = link.className == 'octicon arrow-down' ? 1 : -1
        link.className = 'octicon arrow-' + (arrow == 1 ? 'up' : 'down');
        [].slice.call(rows).slice(2).map(function (e, i) {
            type = e.getElementsByTagName('a')[0].className == 'octicon file-directory' ? 0 : 1
            text = e.getElementsByTagName('td')[index].innerText
            if (index === 0) {
                value = text
            } else if (index === 1) {
                value = new Date(text).getTime()
            } else if (index === 2) {
                m = { 'G': 1024 * 1024 * 1024, 'M': 1024 * 1024, 'K': 1024 }
                value = parseInt(text || 0) * (m[text[text.search(/[KMG]B?$/)]] || 1)
            }
            return { type: type, value: value, index: i, html: e.innerHTML }
        }).sort(function (a, b) {
            if (a.type != b.type)
                return a.type - b.type
            if (a.value != b.value)
                return a.value < b.value ? -arrow : arrow
            return a.index < b.index ? -arrow : arrow
        }).forEach(function (e, i) {
            rows[2 + i].innerHTML = e.html
        })
    }
</script>

<style>
    body {
        margin: 0;
        font-family: "ubuntu", "Tahoma", "Microsoft YaHei", Arial, Serif;
    }

    .container {
        padding-right: 15px;
        padding-left: 15px;
        margin-right: auto;
        margin-left: auto;
    }

    @media (min-width: 768px) {
        .container {
            max-width: 750px;
        }
    }

    @media (min-width: 992px) {
        .container {
            max-width: 970px;
        }
    }

    @media (min-width: 1200px) {
        .container {
            max-width: 1170px;
        }
    }

    table {
        width: 100%;
        max-width: 100%;
        margin-bottom: 20px;
        border: 1px solid #ddd;
        padding: 0;
        border-collapse: collapse;
    }

    table th {
        font-size: 14px;
    }

    table tr {
        border: 1px solid #ddd;
        padding: 5px;
    }

    table tr:nth-child(odd) {
        background: #f9f9f9
    }

    table th,
    table td {
        border: 1px solid #ddd;
        font-size: 14px;
        line-height: 20px;
        padding: 3px;
        text-align: left;
    }

    a {
        color: #337ab7;
        text-decoration: none;
    }

    a:hover,
    a:focus {
        color: #2a6496;
        text-decoration: underline;
    }

    table.table-hover>tbody>tr:hover>td,
    table.table-hover>tbody>tr:hover>th {
        background-color: #f5f5f5;
    }

    .markdown-body {
        float: left;
        font-family: "ubuntu", "Tahoma", "Microsoft YaHei", Arial, Serif;
    }

    /* octicons, see https://phus.lu/code/octicons.html */
    .octicon {
        background-position: center left;
        background-repeat: no-repeat;
        padding-left: 16px;
    }

    .arrow-down {
        font-weight: bold;
        text-decoration: none !important;
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='16' viewBox='0 0 10 16'%3E%3Cpolygon id='Shape' points='7 7 7 3 3 3 3 7 0 7 5 13 10 7'%3E%3C/polygon%3E%3C/svg%3E");
    }

    .arrow-up {
        font-weight: bold;
        text-decoration: none !important;
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='16' viewBox='0 0 10 16'%3E%3Cpolygon id='Shape' points='5 3 0 9 3 9 3 13 7 13 7 9 10 9'%3E%3C/polygon%3E%3C/svg%3E");
    }

    .file {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='16' viewBox='0 0 12 16'%3E%3Cpath d='M6 5L2 5 2 4 6 4 6 5 6 5ZM2 8L9 8 9 7 2 7 2 8 2 8ZM2 10L9 10 9 9 2 9 2 10 2 10ZM2 12L9 12 9 11 2 11 2 12 2 12ZM12 4.5L12 14C12 14.6 11.6 15 11 15L1 15C0.5 15 0 14.6 0 14L0 2C0 1.5 0.5 1 1 1L8.5 1 12 4.5 12 4.5ZM11 5L8 2 1 2 1 14 11 14 11 5 11 5Z' fill='%237D94AE'/%3E%3C/svg%3E");
    }

    .file-directory {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='16' viewBox='0 0 14 16'%3E%3Cpath d='M13 4L7 4 7 3C7 2.3 6.7 2 6 2L1 2C0.5 2 0 2.5 0 3L0 13C0 13.6 0.5 14 1 14L13 14C13.6 14 14 13.6 14 13L14 5C14 4.5 13.6 4 13 4L13 4ZM6 4L1 4 1 3 6 3 6 4 6 4Z' fill='%237D94AE'/%3E%3C/svg%3E");
    }

    .file-symlink-directory {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='16' viewBox='0 0 14 16'%3E%3Cpath d='M13,4 L7,4 L7,3 C7,2.34 6.69,2 6,2 L1,2 C0.45,2 0,2.45 0,3 L0,13 C0,13.55 0.45,14 1,14 L13,14 C13.55,14 14,13.55 14,13 L14,5 C14,4.45 13.55,4 13,4 L13,4 Z M1,3 L6,3 L6,4 L1,4 L1,3 L1,3 Z M7,12 L7,10 C6.02,9.98 5.16,10.22 4.45,10.7 C3.74,11.18 3.26,11.95 3,13 C3.02,11.36 3.39,10.12 4.13,9.27 C4.86,8.43 5.82,8 7.01,8 L7.01,6 L11.01,9 L7.01,12 L7,12 Z' fill='%237D94AE' /%3E%3C/svg%3E");
    }

    .file-zip {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='16' viewBox='0 0 12 16'%3E%3Cpath d='M8.5 1L1 1C0.4 1 0 1.4 0 2L0 14C0 14.6 0.4 15 1 15L11 15C11.6 15 12 14.6 12 14L12 4.5 8.5 1ZM11 14L1 14 1 2 4 2 4 3 5 3 5 2 8 2 11 5 11 14 11 14ZM5 4L5 3 6 3 6 4 5 4 5 4ZM4 4L5 4 5 5 4 5 4 4 4 4ZM5 6L5 5 6 5 6 6 5 6 5 6ZM4 6L5 6 5 7 4 7 4 6 4 6ZM5 8L5 7 6 7 6 8 5 8 5 8ZM4 9.3C3.4 9.6 3 10.3 3 11L3 12 7 12 7 11C7 9.9 6.1 9 5 9L5 8 4 8 4 9.3 4 9.3ZM6 10L6 11 4 11 4 10 6 10 6 10Z' fill='%237D94AE'/%3E%3C/svg%3E");
    }

    .file-code {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='16' viewBox='0 0 12 16'%3E%3Cpath d='M8.5,1 L1,1 C0.45,1 0,1.45 0,2 L0,14 C0,14.55 0.45,15 1,15 L11,15 C11.55,15 12,14.55 12,14 L12,4.5 L8.5,1 L8.5,1 Z M11,14 L1,14 L1,2 L8,2 L11,5 L11,14 L11,14 Z M5,6.98 L3.5,8.5 L5,10 L4.5,11 L2,8.5 L4.5,6 L5,6.98 L5,6.98 Z M7.5,6 L10,8.5 L7.5,11 L7,10.02 L8.5,8.5 L7,7 L7.5,6 L7.5,6 Z' fill='%237D94AE' /%3E%3C/svg%3E");
    }

    .file-binary {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='16' viewBox='0 0 12 16'%3E%3Cpath d='M4,12 L5,12 L5,13 L2,13 L2,12 L3,12 L3,10 L2,10 L2,9 L4,9 L4,12 L4,12 Z M12,4.5 L12,14 C12,14.55 11.55,15 11,15 L1,15 C0.45,15 0,14.55 0,14 L0,2 C0,1.45 0.45,1 1,1 L8.5,1 L12,4.5 L12,4.5 Z M11,5 L8,2 L1,2 L1,14 L11,14 L11,5 L11,5 Z M8,4 L6,4 L6,5 L7,5 L7,7 L6,7 L6,8 L9,8 L9,7 L8,7 L8,4 L8,4 Z M2,4 L5,4 L5,8 L2,8 L2,4 L2,4 Z M3,7 L4,7 L4,5 L3,5 L3,7 L3,7 Z M6,9 L9,9 L9,13 L6,13 L6,9 L6,9 Z M7,12 L8,12 L8,10 L7,10 L7,12 L7,12 Z' fill='%237D94AE' /%3E%3C/svg%3E");
    }

    .file-media {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='16' viewBox='0 0 12 16'%3E%3Cpath d='M6 5L8 5 8 7 6 7 6 5 6 5ZM12 4.5L12 14C12 14.6 11.6 15 11 15L1 15C0.5 15 0 14.6 0 14L0 2C0 1.5 0.5 1 1 1L8.5 1 12 4.5 12 4.5ZM11 5L8 2 1 2 1 13 4 8 6 12 8 10 11 13 11 5 11 5Z' fill='%237D94AE'/%3E%3C/svg%3E");
    }

    .file-pdf {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='16' viewBox='0 0 12 16'%3E%3Cpath d='M8.5,1 L1,1 C0.44771525,1 0,1.44771525 0,2 L0,14 C0,14.5522847 0.44771525,15 1,15 L11,15 C11.5522847,15 12,14.5522847 12,14 L12,4.5 L8.5,1 Z M1,2 L5,2 C4.88021121,2.03682695 4.77292941,2.10604101 4.69,2.2 C4.57596619,2.33544491 4.49698141,2.4968486 4.46,2.67 C4.34406753,3.15093672 4.3136037,3.64851254 4.37,4.14 C4.42970074,4.74889969 4.54348307,5.35127671 4.71,5.94 C4.39913981,6.85020329 4.02832805,7.73881526 3.6,8.6 C3.1,9.6 2.8,10.26 2.69,10.44 C2.45490116,10.527838 2.22458325,10.6279762 2,10.74 C1.63797844,10.9047863 1.30126564,11.1202825 1,11.38 L1,2 L1,2 Z M5.42,6.8 C5.65615226,7.57227694 6.05511596,8.28495569 6.59,8.89 C6.8651023,9.12723152 7.18463148,9.30739159 7.53,9.42 C6.89,9.51 6.3,9.62 5.72,9.75 C5.10224214,9.89929979 4.49707287,10.0965649 3.91,10.34 C3.32292713,10.5834351 4.13,9.9 4.52,9.09 C4.8853939,8.349364 5.18973729,7.58014443 5.43,6.79 L5.43,6.79 L5.42,6.8 Z M11,14 L1.5,14 C1.44352149,14.0065306 1.38647851,14.0065306 1.33,14 C1.60061185,13.9042665 1.84896383,13.7545749 2.06,13.56 C2.76700578,12.8583965 3.36677981,12.0564515 3.84,11.18 C4.15,11.05 4.42,10.95 4.65,10.87 L5.07,10.73 C5.52,10.6 6.01,10.5 6.51,10.4 C7.01,10.3 7.51,10.24 7.99,10.2 C8.43725403,10.4162545 8.9023067,10.5935768 9.38,10.73 C9.78288787,10.8407498 10.1943157,10.9176835 10.61,10.96 L10.99,10.96 L10.99,14 L10.99,14 L11,14 Z M11,9.14 C10.7958695,9.02690387 10.5816018,8.93316173 10.36,8.86 C10.113806,8.8009088 9.86279363,8.76409365 9.61,8.75 C9.19880419,8.75303183 8.78812424,8.77974272 8.38,8.83 C8.0073597,8.68541471 7.66736947,8.46782096 7.38,8.19 C6.78281632,7.51840635 6.34221217,6.72258646 6.09,5.86 C6.20098287,5.19851127 6.26779732,4.53036675 6.29,3.86 C6.30923951,3.61037016 6.30923951,3.35962984 6.29,3.11 C6.35921678,2.80151577 6.28575056,2.47826438 6.09,2.23 C5.92718989,2.07232702 5.70638123,1.9890713 5.48,2 L8,2 L11,5 L11,9.13 L11,9.13 L11,9.14 Z' fill='%237D94AE' /%3E%3C/svg%3E");
    }

    .device-camera-video {
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M15.2,2.09 L10,5.72 L10,3 C10,2.45 9.55,2 9,2 L1,2 C0.45,2 0,2.45 0,3 L0,12 C0,12.55 0.45,13 1,13 L9,13 C9.55,13 10,12.55 10,12 L10,9.28 L15.2,12.91 C15.53,13.14 16,12.91 16,12.5 L16,2.5 C16,2.09 15.53,1.86 15.2,2.09 L15.2,2.09 Z' fill='%237D94AE' /%3E%3C/svg%3E");
    }

    .octicon-book {
        padding-left: 20px;
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M3,5 L7,5 L7,6 L3,6 L3,5 L3,5 Z M3,8 L7,8 L7,7 L3,7 L3,8 L3,8 Z M3,10 L7,10 L7,9 L3,9 L3,10 L3,10 Z M14,5 L10,5 L10,6 L14,6 L14,5 L14,5 Z M14,7 L10,7 L10,8 L14,8 L14,7 L14,7 Z M14,9 L10,9 L10,10 L14,10 L14,9 L14,9 Z M16,3 L16,12 C16,12.55 15.55,13 15,13 L9.5,13 L8.5,14 L7.5,13 L2,13 C1.45,13 1,12.55 1,12 L1,3 C1,2.45 1.45,2 2,2 L7.5,2 L8.5,3 L9.5,2 L15,2 C15.55,2 16,2.45 16,3 L16,3 Z M8,3.5 L7.5,3 L2,3 L2,12 L8,12 L8,3.5 L8,3.5 Z M15,3 L9.5,3 L9,3.5 L9,12 L15,12 L15,3 L15,3 Z' /%3E%3C/svg%3E");
    }

    .globe {
        padding-left: 20px;
        background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='16' viewBox='0 0 14 16'%3E%3Cpath d='M7,1 C3.14,1 0,4.14 0,8 C0,11.86 3.14,15 7,15 C7.48,15 7.94,14.95 8.38,14.86 C8.21,14.78 8.18,14.13 8.36,13.77 C8.55,13.36 9.17,12.32 8.56,11.97 C7.95,11.62 8.12,11.47 7.75,11.06 C7.38,10.65 7.53,10.59 7.5,10.48 C7.42,10.14 7.86,9.59 7.89,9.54 C7.91,9.48 7.91,9.27 7.89,9.21 C7.89,9.13 7.62,8.99 7.55,8.98 C7.49,8.98 7.44,9.09 7.35,9.11 C7.26,9.13 6.85,8.86 6.76,8.78 C6.67,8.7 6.62,8.55 6.49,8.44 C6.36,8.31 6.35,8.41 6.16,8.33 C5.97,8.25 5.36,8.02 4.88,7.85 C4.4,7.66 4.36,7.38 4.36,7.19 C4.34,6.99 4.06,6.72 3.94,6.52 C3.8,6.32 3.78,6.05 3.74,6.11 C3.7,6.17 3.99,6.89 3.94,6.92 C3.89,6.94 3.78,6.72 3.64,6.54 C3.5,6.35 3.78,6.45 3.34,5.59 C2.9,4.73 3.48,4.29 3.51,3.84 C3.54,3.39 3.89,4.01 3.7,3.71 C3.51,3.41 3.7,2.82 3.56,2.6 C3.43,2.38 2.68,2.85 2.68,2.85 C2.7,2.63 3.37,2.27 3.84,1.93 C4.31,1.59 4.62,1.87 5,1.98 C5.39,2.11 5.41,2.07 5.28,1.93 C5.15,1.8 5.34,1.76 5.64,1.8 C5.92,1.85 6.02,2.21 6.47,2.16 C6.94,2.13 6.52,2.25 6.58,2.38 C6.64,2.51 6.52,2.49 6.2,2.68 C5.9,2.88 6.22,2.9 6.75,3.29 C7.28,3.68 7.13,3.04 7.06,2.74 C6.99,2.44 7.45,2.68 7.45,2.68 C7.78,2.9 7.72,2.7 7.95,2.76 C8.18,2.82 8.86,3.4 8.86,3.4 C8.03,3.84 8.55,3.88 8.69,3.99 C8.83,4.1 8.41,4.29 8.41,4.29 C8.24,4.12 8.22,4.31 8.11,4.37 C8,4.43 8.09,4.59 8.09,4.59 C7.53,4.68 7.65,5.28 7.67,5.42 C7.67,5.56 7.29,5.78 7.2,6 C7.11,6.2 7.45,6.64 7.26,6.66 C7.07,6.69 6.92,6 5.95,6.25 C5.65,6.33 5.01,6.66 5.36,7.33 C5.72,8.02 6.28,7.14 6.47,7.24 C6.66,7.34 6.41,7.77 6.45,7.79 C6.49,7.81 6.98,7.81 7.01,8.4 C7.04,8.99 7.78,8.93 7.93,8.95 C8.1,8.95 8.63,8.51 8.7,8.5 C8.76,8.47 9.08,8.22 9.73,8.59 C10.39,8.95 10.71,8.9 10.93,9.06 C11.15,9.22 11.01,9.53 11.21,9.64 C11.41,9.75 12.27,9.61 12.49,9.95 C12.71,10.29 11.61,12.04 11.27,12.23 C10.93,12.42 10.79,12.87 10.43,13.15 C10.07,13.43 9.62,13.79 9.16,14.06 C8.75,14.29 8.69,14.72 8.5,14.86 C11.64,14.16 13.98,11.36 13.98,8.02 C13.98,4.16 10.84,1.02 6.98,1.02 L7,1 Z M8.64,7.56 C8.55,7.59 8.36,7.78 7.86,7.48 C7.38,7.18 7.05,7.25 7,7.2 C7,7.2 6.95,7.09 7.17,7.06 C7.61,7.01 8.15,7.47 8.28,7.47 C8.41,7.47 8.47,7.34 8.69,7.42 C8.91,7.5 8.74,7.55 8.64,7.56 L8.64,7.56 Z M6.34,1.7 C6.29,1.67 6.37,1.62 6.43,1.56 C6.46,1.53 6.45,1.45 6.48,1.42 C6.59,1.31 7.09,1.17 7,1.45 C6.89,1.72 6.42,1.75 6.34,1.7 L6.34,1.7 Z M7.57,2.59 C7.38,2.57 6.99,2.54 7.05,2.45 C7.35,2.17 6.96,2.07 6.71,2.07 C6.46,2.05 6.37,1.91 6.49,1.88 C6.61,1.85 7.1,1.9 7.19,1.96 C7.27,2.02 7.71,2.21 7.74,2.34 C7.76,2.47 7.74,2.59 7.57,2.59 L7.57,2.59 Z M9.04,2.54 C8.9,2.63 8.21,2.13 8.09,2.02 C7.53,1.54 7.2,1.71 7.09,1.61 C6.98,1.51 7.01,1.42 7.2,1.27 C7.39,1.12 7.89,1.33 8.2,1.36 C8.5,1.39 8.86,1.63 8.86,1.91 C8.88,2.16 9.19,2.41 9.05,2.54 L9.04,2.54 Z' /%3E%3C/svg%3E");
    }
</style>

```