From a82843b2da0d116b3b53a70cce29205dbbf773b6 Mon Sep 17 00:00:00 2001 From: okxlin <61420215+okxlin@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:40:53 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0ntfy=E5=88=B0=E5=88=97?= =?UTF-8?q?=E8=A1=A8=20(#1678)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ntfy/2.11.0/data.yml | 39 ++ ntfy/2.11.0/data/ntfy/server.yml.sample | 372 ++++++++++++++++++ .../ntfy/server.yml.sample:Zone.Identifier | 0 ntfy/2.11.0/docker-compose.yml | 29 ++ ntfy/README.md | 28 ++ ntfy/data.yml | 19 + ntfy/logo.png | Bin 0 -> 5552 bytes 7 files changed, 487 insertions(+) create mode 100644 ntfy/2.11.0/data.yml create mode 100644 ntfy/2.11.0/data/ntfy/server.yml.sample create mode 100644 ntfy/2.11.0/data/ntfy/server.yml.sample:Zone.Identifier create mode 100644 ntfy/2.11.0/docker-compose.yml create mode 100644 ntfy/README.md create mode 100644 ntfy/data.yml create mode 100644 ntfy/logo.png diff --git a/ntfy/2.11.0/data.yml b/ntfy/2.11.0/data.yml new file mode 100644 index 000000000..5332a75f2 --- /dev/null +++ b/ntfy/2.11.0/data.yml @@ -0,0 +1,39 @@ +additionalProperties: + formFields: + - default: "40265" + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port + labelZh: 端口 + required: true + rule: paramPort + type: number + - default: "80" + edit: true + envKey: APP_PORT_INTERNAL + labelEn: Internal Container Ports + labelZh: 容器内部端口 + required: true + rule: paramPort + type: number + - default: "Asia/Shanghai" + edit: true + envKey: TIME_ZONE + labelEn: Time Zone + labelZh: 时区 + required: true + type: text + - default: "1000" + edit: true + envKey: PUID + labelEn: User ID + labelZh: 用户 ID + required: true + type: number + - default: "1000" + edit: true + envKey: PGID + labelEn: Group ID + labelZh: 组 ID + required: true + type: number diff --git a/ntfy/2.11.0/data/ntfy/server.yml.sample b/ntfy/2.11.0/data/ntfy/server.yml.sample new file mode 100644 index 000000000..4b48828ca --- /dev/null +++ b/ntfy/2.11.0/data/ntfy/server.yml.sample @@ -0,0 +1,372 @@ +# ntfy server config file +# +# Please refer to the documentation at https://ntfy.sh/docs/config/ for details. +# All options also support underscores (_) instead of dashes (-) to comply with the YAML spec. + +# Public facing base URL of the service (e.g. https://ntfy.sh or https://ntfy.example.com) +# +# This setting is required for any of the following features: +# - attachments (to return a download URL) +# - e-mail sending (for the topic URL in the email footer) +# - iOS push notifications for self-hosted servers (to calculate the Firebase poll_request topic) +# - Matrix Push Gateway (to validate that the pushkey is correct) +# +# base-url: + +# Listen address for the HTTP & HTTPS web server. If "listen-https" is set, you must also +# set "key-file" and "cert-file". Format: []:, e.g. "1.2.3.4:8080". +# +# To listen on all interfaces, you may omit the IP address, e.g. ":443". +# To disable HTTP, set "listen-http" to "-". +# +# listen-http: ":80" +# listen-https: + +# Listen on a Unix socket, e.g. /var/lib/ntfy/ntfy.sock +# This can be useful to avoid port issues on local systems, and to simplify permissions. +# +# listen-unix: +# listen-unix-mode: + +# Path to the private key & cert file for the HTTPS web server. Not used if "listen-https" is not set. +# +# key-file: +# cert-file: + +# If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app. +# This is optional and only required to save battery when using the Android app. +# +# firebase-key-file: + +# If "cache-file" is set, messages are cached in a local SQLite database instead of only in-memory. +# This allows for service restarts without losing messages in support of the since= parameter. +# +# The "cache-duration" parameter defines the duration for which messages will be buffered +# before they are deleted. This is required to support the "since=..." and "poll=1" parameter. +# To disable the cache entirely (on-disk/in-memory), set "cache-duration" to 0. +# The cache file is created automatically, provided that the correct permissions are set. +# +# The "cache-startup-queries" parameter allows you to run commands when the database is initialized, +# e.g. to enable WAL mode (see https://phiresky.github.io/blog/2020/sqlite-performance-tuning/)). +# Example: +# cache-startup-queries: | +# pragma journal_mode = WAL; +# pragma synchronous = normal; +# pragma temp_store = memory; +# pragma busy_timeout = 15000; +# vacuum; +# +# The "cache-batch-size" and "cache-batch-timeout" parameter allow enabling async batch writing +# of messages. If set, messages will be queued and written to the database in batches of the given +# size, or after the given timeout. This is only required for high volume servers. +# +# Debian/RPM package users: +# Use /var/cache/ntfy/cache.db as cache file to avoid permission issues. The package +# creates this folder for you. +# +# Check your permissions: +# If you are running ntfy with systemd, make sure this cache file is owned by the +# ntfy user and group by running: chown ntfy.ntfy . +# +# cache-file: +# cache-duration: "12h" +# cache-startup-queries: +# cache-batch-size: 0 +# cache-batch-timeout: "0ms" + +# If set, access to the ntfy server and API can be controlled on a granular level using +# the 'ntfy user' and 'ntfy access' commands. See the --help pages for details, or check the docs. +# +# - auth-file is the SQLite user/access database; it is created automatically if it doesn't already exist +# - auth-default-access defines the default/fallback access if no access control entry is found; it can be +# set to "read-write" (default), "read-only", "write-only" or "deny-all". +# - auth-startup-queries allows you to run commands when the database is initialized, e.g. to enable +# WAL mode. This is similar to cache-startup-queries. See above for details. +# +# Debian/RPM package users: +# Use /var/lib/ntfy/user.db as user database to avoid permission issues. The package +# creates this folder for you. +# +# Check your permissions: +# If you are running ntfy with systemd, make sure this user database file is owned by the +# ntfy user and group by running: chown ntfy.ntfy . +# +# auth-file: +# auth-default-access: "read-write" +# auth-startup-queries: + +# If set, the X-Forwarded-For header is used to determine the visitor IP address +# instead of the remote address of the connection. +# +# WARNING: If you are behind a proxy, you must set this, otherwise all visitors are rate limited +# as if they are one. +# +# behind-proxy: false + +# If enabled, clients can attach files to notifications as attachments. Minimum settings to enable attachments +# are "attachment-cache-dir" and "base-url". +# +# - attachment-cache-dir is the cache directory for attached files +# - attachment-total-size-limit is the limit of the on-disk attachment cache directory (total size) +# - attachment-file-size-limit is the per-file attachment size limit (e.g. 300k, 2M, 100M) +# - attachment-expiry-duration is the duration after which uploaded attachments will be deleted (e.g. 3h, 20h) +# +# attachment-cache-dir: +# attachment-total-size-limit: "5G" +# attachment-file-size-limit: "15M" +# attachment-expiry-duration: "3h" + +# If enabled, allow outgoing e-mail notifications via the 'X-Email' header. If this header is set, +# messages will additionally be sent out as e-mail using an external SMTP server. +# +# As of today, only SMTP servers with plain text auth (or no auth at all), and STARTLS are supported. +# Please also refer to the rate limiting settings below (visitor-email-limit-burst & visitor-email-limit-burst). +# +# - smtp-sender-addr is the hostname:port of the SMTP server +# - smtp-sender-from is the e-mail address of the sender +# - smtp-sender-user/smtp-sender-pass are the username and password of the SMTP user (leave blank for no auth) +# +# smtp-sender-addr: +# smtp-sender-from: +# smtp-sender-user: +# smtp-sender-pass: + +# If enabled, ntfy will launch a lightweight SMTP server for incoming messages. Once configured, users can send +# emails to a topic e-mail address to publish messages to a topic. +# +# - smtp-server-listen defines the IP address and port the SMTP server will listen on, e.g. :25 or 1.2.3.4:25 +# - smtp-server-domain is the e-mail domain, e.g. ntfy.sh +# - smtp-server-addr-prefix is an optional prefix for the e-mail addresses to prevent spam. If set to "ntfy-", +# for instance, only e-mails to ntfy-$topic@ntfy.sh will be accepted. If this is not set, all emails to +# $topic@ntfy.sh will be accepted (which may obviously be a spam problem). +# +# smtp-server-listen: +# smtp-server-domain: +# smtp-server-addr-prefix: + +# Web Push support (background notifications for browsers) +# +# If enabled, allows ntfy to receive push notifications, even when the ntfy web app is closed. When enabled, users +# can enable background notifications in the web app. Once enabled, ntfy will forward published messages to the push +# endpoint, which will then forward it to the browser. +# +# You must configure web-push-public/private key, web-push-file, and web-push-email-address below to enable Web Push. +# Run "ntfy webpush keys" to generate the keys. +# +# - web-push-public-key is the generated VAPID public key, e.g. AA1234BBCCddvveekaabcdfqwertyuiopasdfghjklzxcvbnm1234567890 +# - web-push-private-key is the generated VAPID private key, e.g. AA2BB1234567890abcdefzxcvbnm1234567890 +# - web-push-file is a database file to keep track of browser subscription endpoints, e.g. `/var/cache/ntfy/webpush.db` +# - web-push-email-address is the admin email address send to the push provider, e.g. `sysadmin@example.com` +# - web-push-startup-queries is an optional list of queries to run on startup` +# +# web-push-public-key: +# web-push-private-key: +# web-push-file: +# web-push-email-address: +# web-push-startup-queries: + +# If enabled, ntfy can perform voice calls via Twilio via the "X-Call" header. +# +# - twilio-account is the Twilio account SID +# - twilio-auth-token is the Twilio auth token, e.g. affebeef258625862586258625862586 +# - twilio-phone-number is the outgoing phone number you purchased, e.g. +18775132586 +# - twilio-verify-service is the Twilio Verify service SID, e.g. VA12345beefbeef67890beefbeef122586 +# +# twilio-account: +# twilio-auth-token: +# twilio-phone-number: +# twilio-verify-service: + +# Interval in which keepalive messages are sent to the client. This is to prevent +# intermediaries closing the connection for inactivity. +# +# Note that the Android app has a hardcoded timeout at 77s, so it should be less than that. +# +# keepalive-interval: "45s" + +# Interval in which the manager prunes old messages, deletes topics +# and prints the stats. +# +# manager-interval: "1m" + +# Defines topic names that are not allowed, because they are otherwise used. There are a few default topics +# that cannot be used (e.g. app, account, settings, ...). To extend the default list, define them here. +# +# Example: +# disallowed-topics: +# - about +# - pricing +# - contact +# +# disallowed-topics: + +# Defines the root path of the web app, or disables the web app entirely. +# +# Can be any simple path, e.g. "/", "/app", or "/ntfy". For backwards-compatibility reasons, +# the values "app" (maps to "/"), "home" (maps to "/app"), or "disable" (maps to "") to disable +# the web app entirely. +# +# web-root: / + +# Various feature flags used to control the web app, and API access, mainly around user and +# account management. +# +# - enable-signup allows users to sign up via the web app, or API +# - enable-login allows users to log in via the web app, or API +# - enable-reservations allows users to reserve topics (if their tier allows it) +# +# enable-signup: false +# enable-login: false +# enable-reservations: false + +# Server URL of a Firebase/APNS-connected ntfy server (likely "https://ntfy.sh"). +# +# iOS users: +# If you use the iOS ntfy app, you MUST configure this to receive timely notifications. You'll like want this: +# upstream-base-url: "https://ntfy.sh" +# +# If set, all incoming messages will publish a "poll_request" message to the configured upstream server, containing +# the message ID of the original message, instructing the iOS app to poll this server for the actual message contents. +# This is to prevent the upstream server and Firebase/APNS from being able to read the message. +# +# - upstream-base-url is the base URL of the upstream server. Should be "https://ntfy.sh". +# - upstream-access-token is the token used to authenticate with the upstream server. This is only required +# if you exceed the upstream rate limits, or the uptream server requires authentication. +# +# upstream-base-url: +# upstream-access-token: + +# Configures message-specific limits +# +# - message-size-limit defines the max size of a message body. Please note message sizes >4K are NOT RECOMMENDED, +# and largely untested. If FCM and/or APNS is used, the limit should stay 4K, because their limits are around that size. +# If you increase this size limit regardless, FCM and APNS will NOT work for large messages. +# - message-delay-limit defines the max delay of a message when using the "Delay" header. +# +# message-size-limit: "4k" +# message-delay-limit: "3d" + +# Rate limiting: Total number of topics before the server rejects new topics. +# +# global-topic-limit: 15000 + +# Rate limiting: Number of subscriptions per visitor (IP address) +# +# visitor-subscription-limit: 30 + +# Rate limiting: Allowed GET/PUT/POST requests per second, per visitor: +# - visitor-request-limit-burst is the initial bucket of requests each visitor has +# - visitor-request-limit-replenish is the rate at which the bucket is refilled +# - visitor-request-limit-exempt-hosts is a comma-separated list of hostnames, IPs or CIDRs to be +# exempt from request rate limiting. Hostnames are resolved at the time the server is started. +# Example: "1.2.3.4,ntfy.example.com,8.7.6.0/24" +# +# visitor-request-limit-burst: 60 +# visitor-request-limit-replenish: "5s" +# visitor-request-limit-exempt-hosts: "" + +# Rate limiting: Hard daily limit of messages per visitor and day. The limit is reset +# every day at midnight UTC. If the limit is not set (or set to zero), the request +# limit (see above) governs the upper limit. +# +# visitor-message-daily-limit: 0 + +# Rate limiting: Allowed emails per visitor: +# - visitor-email-limit-burst is the initial bucket of emails each visitor has +# - visitor-email-limit-replenish is the rate at which the bucket is refilled +# +# visitor-email-limit-burst: 16 +# visitor-email-limit-replenish: "1h" + +# Rate limiting: Attachment size and bandwidth limits per visitor: +# - visitor-attachment-total-size-limit is the total storage limit used for attachments per visitor +# - visitor-attachment-daily-bandwidth-limit is the total daily attachment download/upload traffic limit per visitor +# +# visitor-attachment-total-size-limit: "100M" +# visitor-attachment-daily-bandwidth-limit: "500M" + +# Rate limiting: Enable subscriber-based rate limiting (mostly used for UnifiedPush) +# +# If subscriber-based rate limiting is enabled, messages published on UnifiedPush topics** (topics starting with "up") +# will be counted towards the "rate visitor" of the topic. A "rate visitor" is the first subscriber to the topic. +# +# Once enabled, a client subscribing to UnifiedPush topics via HTTP stream, or websockets, will be automatically registered as +# a "rate visitor", i.e. the visitor whose rate limits will be used when publishing on this topic. Note that setting the rate visitor +# requires **read-write permission** on the topic. +# +# If this setting is enabled, publishing to UnifiedPush topics will lead to a HTTP 507 response if +# no "rate visitor" has been previously registered. This is to avoid burning the publisher's "visitor-message-daily-limit". +# +# visitor-subscriber-rate-limiting: false + +# Payments integration via Stripe +# +# - stripe-secret-key is the key used for the Stripe API communication. Setting this values +# enables payments in the ntfy web app (e.g. Upgrade dialog). See https://dashboard.stripe.com/apikeys. +# - stripe-webhook-key is the key required to validate the authenticity of incoming webhooks from Stripe. +# Webhooks are essential up keep the local database in sync with the payment provider. See https://dashboard.stripe.com/webhooks. +# - billing-contact is an email address or website displayed in the "Upgrade tier" dialog to let people reach +# out with billing questions. If unset, nothing will be displayed. +# +# stripe-secret-key: +# stripe-webhook-key: +# billing-contact: + +# Metrics +# +# ntfy can expose Prometheus-style metrics via a /metrics endpoint, or on a dedicated listen IP/port. +# Metrics may be considered sensitive information, so before you enable them, be sure you know what you are +# doing, and/or secure access to the endpoint in your reverse proxy. +# +# - enable-metrics enables the /metrics endpoint for the default ntfy server (i.e. HTTP, HTTPS and/or Unix socket) +# - metrics-listen-http exposes the metrics endpoint via a dedicated [IP]:port. If set, this option implicitly +# enables metrics as well, e.g. "10.0.1.1:9090" or ":9090" +# +# enable-metrics: false +# metrics-listen-http: + +# Profiling +# +# ntfy can expose Go's net/http/pprof endpoints to support profiling of the ntfy server. If enabled, ntfy will listen +# on a dedicated listen IP/port, which can be accessed via the web browser on http://:/debug/pprof/. +# This can be helpful to expose bottlenecks, and visualize call flows. See https://pkg.go.dev/net/http/pprof for details. +# +# profile-listen-http: + +# Logging options +# +# By default, ntfy logs to the console (stderr), with an "info" log level, and in a human-readable text format. +# ntfy supports five different log levels, can also write to a file, log as JSON, and even supports granular +# log level overrides for easier debugging. Some options (log-level and log-level-overrides) can be hot reloaded +# by calling "kill -HUP $pid" or "systemctl reload ntfy". +# +# - log-format defines the output format, can be "text" (default) or "json" +# - log-file is a filename to write logs to. If this is not set, ntfy logs to stderr. +# - log-level defines the default log level, can be one of "trace", "debug", "info" (default), "warn" or "error". +# Be aware that "debug" (and particularly "trace") can be VERY CHATTY. Only turn them on briefly for debugging purposes. +# - log-level-overrides lets you override the log level if certain fields match. This is incredibly powerful +# for debugging certain parts of the system (e.g. only the account management, or only a certain visitor). +# This is an array of strings in the format: +# - "field=value -> level" to match a value exactly, e.g. "tag=manager -> trace" +# - "field -> level" to match any value, e.g. "time_taken_ms -> debug" +# Warning: Using log-level-overrides has a performance penalty. Only use it for temporary debugging. +# +# Check your permissions: +# If you are running ntfy with systemd, make sure this log file is owned by the +# ntfy user and group by running: chown ntfy.ntfy . +# +# Example (good for production): +# log-level: info +# log-format: json +# log-file: /var/log/ntfy.log +# +# Example level overrides (for debugging, only use temporarily): +# log-level-overrides: +# - "tag=manager -> trace" +# - "visitor_ip=1.2.3.4 -> debug" +# - "time_taken_ms -> debug" +# +# log-level: info +# log-level-overrides: +# log-format: text +# log-file: diff --git a/ntfy/2.11.0/data/ntfy/server.yml.sample:Zone.Identifier b/ntfy/2.11.0/data/ntfy/server.yml.sample:Zone.Identifier new file mode 100644 index 000000000..e69de29bb diff --git a/ntfy/2.11.0/docker-compose.yml b/ntfy/2.11.0/docker-compose.yml new file mode 100644 index 000000000..848a72e59 --- /dev/null +++ b/ntfy/2.11.0/docker-compose.yml @@ -0,0 +1,29 @@ +services: + ntfy: + image: "binwiederhier/ntfy:v2.11.0" + container_name: ${CONTAINER_NAME} + command: + - serve + environment: + - TZ=${TIME_ZONE} + user: ${PUID}:${PGID} + volumes: + - ./data/cache/ntfy:/var/cache/ntfy + - ./data/ntfy:/etc/ntfy + ports: + - "${PANEL_APP_PORT_HTTP}:${APP_PORT_INTERNAL}" + restart: always + networks: + - 1panel-network + healthcheck: + test: ["CMD-SHELL", "wget -q --tries=1 http://localhost:${APP_PORT_INTERNAL}/v1/health -O - | grep -Eo '\"healthy\"\\s*:\\s*true' || exit 1"] + interval: 60s + timeout: 10s + retries: 3 + start_period: 40s + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/ntfy/README.md b/ntfy/README.md new file mode 100644 index 000000000..5061e1828 --- /dev/null +++ b/ntfy/README.md @@ -0,0 +1,28 @@ +![ntfy](https://github.com/binwiederhier/ntfy/raw/main/web/public/static/images/ntfy.png) + +# ntfy.sh +## 通过 PUT/POST 发送推送通知到你的手机或桌面 +[![Release](https://img.shields.io/github/release/binwiederhier/ntfy.svg?color=success&style=flat-square)](https://github.com/binwiederhier/ntfy/releases/latest) +[![Go Reference](https://pkg.go.dev/badge/heckel.io/ntfy.svg)](https://pkg.go.dev/heckel.io/ntfy/v2) +[![Tests](https://github.com/binwiederhier/ntfy/workflows/test/badge.svg)](https://github.com/binwiederhier/ntfy/actions) +[![Go Report Card](https://goreportcard.com/badge/github.com/binwiederhier/ntfy)](https://goreportcard.com/report/github.com/binwiederhier/ntfy) +[![codecov](https://codecov.io/gh/binwiederhier/ntfy/branch/main/graph/badge.svg?token=A597KQ463G)](https://codecov.io/gh/binwiederhier/ntfy) +[![Discord](https://img.shields.io/discord/874398661709295626?label=Discord)](https://discord.gg/cT7ECsZj9w) +[![Matrix](https://img.shields.io/matrix/ntfy:matrix.org?label=Matrix)](https://matrix.to/#/#ntfy:matrix.org) +[![Matrix space](https://img.shields.io/matrix/ntfy-space:matrix.org?label=Matrix+space)](https://matrix.to/#/#ntfy-space:matrix.org) +[![Healthcheck](https://healthchecks.io/badge/68b65976-b3b0-4102-aec9-980921/kcoEgrLY.svg)](https://ntfy.statuspage.io/) +[![Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod)](https://gitpod.io/#https://github.com/binwiederhier/ntfy) + +**ntfy**(发音为 "*notify*")是一个简单的基于 HTTP 的[发布-订阅](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)通知服务。通过 ntfy,你可以**通过脚本从任何计算机发送通知到你的手机或桌面**,**无需注册或支付任何费用**。如果你想运行自己的服务实例,你可以很容易地做到,因为 ntfy 是开源的。 + +你可以通过 **[ntfy.sh](https://ntfy.sh)** 访问免费的 ntfy 服务。这里还有一个[开源的 Android 应用](https://github.com/binwiederhier/ntfy-android),可以在[Google Play](https://play.google.com/store/apps/details?id=io.heckel.ntfy) 或 [F-Droid](https://f-droid.org/en/packages/io.heckel.ntfy/) 上找到,还有一个[开源的 iOS 应用](https://github.com/binwiederhier/ntfy-ios),可以在[App Store](https://apps.apple.com/us/app/ntfy/id1625396347) 上找到。 + +## 使用说明 + +可以通过修改配置文件来自定义设置,文件路径如下,按需修改,将`server.yml.sample`修改为`server.yml`, + +然后自定义修改内容即可。 + +``` +/opt/1panel/apps/local/ntfy/ntfy/data/ntfy/server.yml.sample +``` \ No newline at end of file diff --git a/ntfy/data.yml b/ntfy/data.yml new file mode 100644 index 000000000..84aeb5c18 --- /dev/null +++ b/ntfy/data.yml @@ -0,0 +1,19 @@ +name: ntfy +tags: + - 开发工具 +title: 基于 HTTP 的简单 pub-sub 通知服务 +description: 基于 HTTP 的简单 pub-sub 通知服务 +additionalProperties: + key: ntfy + name: ntfy + tags: + - DevTool + shortDescZh: 基于 HTTP 的简单 pub-sub 通知服务 + shortDescEn: A simple HTTP-based pub-sub notification service + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://ntfy.sh/ + github: https://github.com/binwiederhier/ntfy + document: https://ntfy.sh/docs diff --git a/ntfy/logo.png b/ntfy/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cf4c9c3b26335a21d537fa240387d0a5f3dad981 GIT binary patch literal 5552 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%0ACacOfR@NlqU+0~UJKW_066Q;tL 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 lRWhdpp0x`lc$Cb01