21 | 抱歉,当前图片未能通过审查,可能含有不良内容,故无法进行加载。
22 |
23 | Sorry, the current image failed to pass the review and may contain undesirable content, so it cannot be loaded.
24 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/functions/api/manage/list.js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) {
2 | // Contents of context object
3 | const {
4 | request, // same as existing Worker API
5 | env, // same as existing Worker API
6 | params, // if filename includes [id] or [[path]]
7 | waitUntil, // same as ctx.waitUntil in existing Worker API
8 | next, // used for middleware or to fetch assets
9 | data, // arbitrary space for passing data between middlewares
10 | } = context;
11 | console.log(env)
12 | const value = await env.img_url.list();
13 |
14 | console.log(value)
15 | //let res=[]
16 | //for (let i in value.keys){
17 | //add to res
18 | //"metadata":{"TimeStamp":19876541,"ListType":"None","rating_label":"None"}
19 | //let tmp = {
20 | // name: value.keys[i].name,
21 | // TimeStamp: value.keys[i].metadata.TimeStamp,
22 | // ListType: value.keys[i].metadata.ListType,
23 | // rating_label: value.keys[i].metadata.rating_label,
24 | //}
25 | //res.push(tmp)
26 | //}
27 | const info = JSON.stringify(value.keys);
28 | return new Response(info);
29 |
30 | }
--------------------------------------------------------------------------------
/whitelist-on.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | WhiteList Mode is ON| Telegraph-Image
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 | 抱歉,当前已开启白名单模式,上传的图片需要审核通过后才能展示,请等待审核通过后再进行访问。
22 |
23 | Sorry, the whitelist mode is currently enabled, the uploaded images need to be audited before they can be displayed, please wait for the audit to be passed before visiting.
24 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/_nuxt/318bf53201c4127c79fc.js:
--------------------------------------------------------------------------------
1 | !function(e){function r(data){for(var r,n,l=data[0],f=data[1],d=data[2],i=0,h=[];i character.charCodeAt(0));
23 | const decoded = new TextDecoder().decode(buffer).normalize();
24 |
25 | // The username & password are split by the first colon.
26 | //=> example: "username:password"
27 | const index = decoded.indexOf(':');
28 |
29 | // The user & password are split by the first colon and MUST NOT contain control characters.
30 | // @see https://tools.ietf.org/html/rfc5234#appendix-B.1 (=> "CTL = %x00-1F / %x7F")
31 | if (index === -1 || /[\0-\x1F\x7F]/.test(decoded)) {
32 | throw new BadRequestException('Invalid authorization value.');
33 | }
34 |
35 | return {
36 | user: decoded.substring(0, index),
37 | pass: decoded.substring(index + 1),
38 | };
39 | }
40 |
41 | function UnauthorizedException(reason) {
42 | return new Response(reason, {
43 | status: 401,
44 | statusText: 'Unauthorized',
45 | headers: {
46 | 'Content-Type': 'text/plain;charset=UTF-8',
47 | // Disables caching by default.
48 | 'Cache-Control': 'no-store',
49 | // Returns the "Content-Length" header for HTTP HEAD requests.
50 | 'Content-Length': reason.length,
51 | },
52 | });
53 | }
54 |
55 | function BadRequestException(reason) {
56 | return new Response(reason, {
57 | status: 400,
58 | statusText: 'Bad Request',
59 | headers: {
60 | 'Content-Type': 'text/plain;charset=UTF-8',
61 | // Disables caching by default.
62 | 'Cache-Control': 'no-store',
63 | // Returns the "Content-Length" header for HTTP HEAD requests.
64 | 'Content-Length': reason.length,
65 | },
66 | });
67 | }
68 |
69 |
70 | function authentication(context) {
71 | //context.env.BASIC_USER="admin"
72 | //context.env.BASIC_PASS="admin"
73 | //check if the env variables Disable_Dashboard are set
74 | if (typeof context.env.img_url == "undefined" || context.env.img_url == null || context.env.img_url == "") {
75 | return new Response('Dashboard is disabled. Please bind a KV namespace to use this feature.', { status: 200 });
76 | }
77 |
78 | console.log(context.env.BASIC_USER)
79 | if(typeof context.env.BASIC_USER == "undefined" || context.env.BASIC_USER == null || context.env.BASIC_USER == ""){
80 | return context.next();
81 | }else{
82 | if (context.request.headers.has('Authorization')) {
83 | // Throws exception when authorization fails.
84 | const { user, pass } = basicAuthentication(context.request);
85 |
86 |
87 | if (context.env.BASIC_USER !== user || context.env.BASIC_PASS !== pass) {
88 | return UnauthorizedException('Invalid credentials.');
89 | }else{
90 | return context.next();
91 | }
92 |
93 | } else {
94 | return new Response('You need to login.', {
95 | status: 401,
96 | headers: {
97 | // Prompts the user for credentials.
98 | 'WWW-Authenticate': 'Basic realm="my scope", charset="UTF-8"',
99 | },
100 | });
101 | }
102 | }
103 |
104 | }
105 |
106 | export const onRequest = [errorHandling, authentication];
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Telegraph-Image
2 | 免费图片托管解决方案,Flickr/imgur替代品。使用Cloudflare Pages和Telegraph。
3 |
4 | [English](README-EN.md)|中文
5 |
6 | ## 如何部署
7 |
8 | ### 提前准备
9 | 你唯一需要提前准备的就是一个Cloudflare账户 (如果需要在自己的服务器上部署,不依赖Cloudflare,可参考[#46](https://github.com/cf-pages/Telegraph-Image/issues/46) )
10 |
11 | ### 手把手教程
12 | 简单3步,即可部署本项目,拥有自己的图床
13 |
14 | 1.下载或Fork本仓库 (注意:目前请使用fork,在使用下载[#14](https://github.com/cf-pages/Telegraph-Image/issues/14)部署存在问题)
15 |
16 | 2.打开Cloudflare Dashboard,进入Pages管理页面,选择创建项目,如果在第一步中选择的是fork本仓库,则选择`连接到 Git 提供程序`,如果第一步中选择的是下载本仓库则选择`直接上传`
17 | 
18 |
19 | 3. 按照页面提示输入项目名称,选择需要连接的git仓库(第一步选择的是fork)或是上传刚刚下载的仓库文件(第一步选择的是下载本仓库),点击`部署站点`即可完成部署
20 |
21 | ## 特性
22 | 1.无限图片储存数量,你可以上传不限数量的图片
23 |
24 | 2.无需购买服务器,托管于Cloudflare的网络上,当使用量不超过Cloudflare的免费额度时,完全免费
25 |
26 | 3.无需购买域名,可以使用Cloudflare Pages提供的`*.pages.dev`的免费二级域名,同时也支持绑定自定义域名
27 |
28 | 4.支持图片审查API,可根据需要开启,开启后不良图片将自动屏蔽,不再加载
29 |
30 | 5.支持后台图片管理,可以对上传的图片进行在线预览,添加白名单,黑名单等操作
31 |
32 | ### 绑定自定义域名
33 | 在pages的自定义域里面,绑定cloudflare中存在的域名,在cloudflare托管的域名,自动会修改dns记录
34 | 
35 |
36 | ### 开启图片审查
37 | 1.请前往https://moderatecontent.com/ 注册并获得一个免费的用于审查图像内容的API key
38 |
39 | 2.打开Cloudflare Pages的管理页面,依次点击`设置`,`环境变量`,`添加环境变量`
40 |
41 | 3.添加一个`变量名称`为`ModerateContentApiKey`,`值`为你刚刚第一步获得的`API key`,点击`保存`即可
42 |
43 | 注意:由于所做的更改将在下次部署时生效,你或许还需要进入`部署`页面,重新部署一下该本项目
44 |
45 | 开启图片审查后,因为审查需要时间,首次的图片加载将会变得缓慢,之后的图片加载由于存在缓存,并不会受到影响
46 | 
47 |
48 | ### 限制
49 | 1.由于图片文件实际存储于Telegraph,Telegraph限制上传的图片大小最大为5MB
50 |
51 | 2.由于使用Cloudflare的网络,图片的加载速度在某些地区可能得不到保证
52 |
53 | 3.Cloudflare Function免费版每日限制100,000个请求(即上传或是加载图片的总次数不能超过100,000次)如超过可能需要选择购买Cloudflare Function的付费套餐,如开启图片管理功能还会存在KV操作数量的限制,如超过需购买付费套餐
54 |
55 | ### 感谢
56 | Hostloc @feixiang和@乌拉擦 提供的思路和代码
57 |
58 | ## 更新日志
59 | 2023年1月18日--图片管理功能更新
60 |
61 | 1、支持图片管理功能,默认是关闭的,如需开启请部署完成后前往后台依次点击`设置`->`函数`->`KV 命名空间绑定`->`编辑绑定`->`变量名称`填写:`img_url` `KV 命名空间` 选择你提前创建好的KV储存空间,开启后访问http(s)://你的域名/admin 即可打开后台管理页面
62 | | 变量名称 | KV 命名空间 |
63 | | ----------- | ----------- |
64 | | img_url | 选择提前创建好的KV储存空间 |
65 |
66 | 
67 | 
68 |
69 | 2、后台管理页面新增登录验证功能,默认也是关闭的,如需开启请部署完成后前往后台依次点击`设置`->`环境变量`->`为生产环境定义变量`->`编辑变量` 添加如下表格所示的变量即可开启登录验证
70 | | 变量名称 | 值 |
71 | | ----------- | ----------- |
72 | |BASIC_USER = | <后台管理页面登录用户名称>|
73 | |BASIC_PASS = | <后台管理页面登录用户密码>|
74 |
75 | 
76 |
77 | 当然你也可以不设置这两个值,这样访问后台管理页面时将无需验证,直接跳过登录步骤,这一设计使得你可以结合Cloudflare Access进行使用,实现支持邮件验证码登录,Microsoft账户登录,Github账户登录等功能,能够与你域名上原有的登录方式所集成,无需再次记忆多一组后台的账号密码,添加Cloudflare Access的方式请参考官方文档,注意需要保护路径包括/admin 以及 /api/manage/*
78 |
79 | 3、新增图片总数量统计
80 | 当开启图片管理功能后,可在后台顶部查看记录中的图片数量
81 |
82 | 
83 |
84 | 4、新增图片文件名搜索
85 | 当开启图片管理功能后,可在后台搜索框使用图片文件名称,快速搜索定位需要管理的图片
86 |
87 | 
88 |
89 | 5、新增图片状态显示
90 | 当开启图片管理功能后,可在后台查看图片当前的状态{ "ListType": "None", "TimeStamp": 1673984678274 }
91 | ListType代表图片当前是否在黑白名单当中,None则表示既不在黑名单中也不在白名单中,White表示在在白名单中,Block表示在黑名单中,TimeStamp为图片首次加载的时间戳,如开启的图片审查API,则这里还会显示图片审查的结果用Label标识
92 |
93 | 
94 |
95 | 6、新增黑名单功能
96 | 当开启图片管理功能后,可在后台手动为图片加入黑名单,加入黑名单的图片将无法正常加载
97 |
98 | 
99 |
100 | 7、新增白名单功能
101 | 当开启图片管理功能后,可在后台手动为图片加入白名单,加入白名单的图片无论如何都会正常加载,可绕过图片审查API的结果
102 |
103 | 
104 |
105 | 8、新增记录删除功能
106 | 当开启图片管理功能后,可在后台手动删除图片记录,即不再后台显示该图片,除非有人再次上传并加载该图片,注意由于图片储存在telegraph的服务器上,我们无法删除上传的原始图片,只能通过上述第6点的黑名单功能屏蔽图片的加载
107 |
108 | 9、新增程序运行模式:白名单模式
109 | 当开启图片管理功能后,除了默认模式外,这次更新还新增了一项新的运行模式,在该模式下,只有被添加进白名单的图片才会被加载,上传的图片需要审核通过后才能展示,最大程度的防止不良图片的加载,如需开启请设置环境变量:WhiteList_Mode=="true"
110 |
111 | 10、新增后台图片预览功能
112 | 当开启图片管理功能后,可在后台预览通过你的域名加载过的图片,点击图片可以进行放大,缩小,旋转等操作
113 |
114 | 
115 |
116 | ## 已经部署了的,如何更新?
117 | 其实更新非常简单,只需要参照上面的更新内容,先进入到Cloudflare Pages后台,把需要使用的环境变量提前设置好并绑定上KV命名空间,然后去到Github你之前fork过的仓库依次选择`Sync fork`->`Update branch`即可,稍等一会,Cloudflare Pages那边检测到你的仓库更新了之后就会自动部署最新的代码了
118 |
119 | ## 一些限制:
120 | Cloudflare KV每天只有1000次的免费写入额度,每有一张新的图片加载都会占用该写入额度,如果超过该额度,图片管理后台将无法记录新加载的图片
121 |
122 | 每天最多 100,000 次免费读取操作,图片每加载一次都会占用该额度(在没有缓存的情况下,如果你的域名在Cloudflare开启了缓存,当缓存未命中时才会占用该额度),超过黑白名单等功能可能会失效
123 |
124 | 每天最多 1,000 次免费删除操作,每有一条图片记录都会占用该额度,超过将无法删除图片记录
125 |
126 | 每天最多 1,000 次免费列出操作,每打开或刷新一次后台/admin都会占用该额度,超过将进行后台图片管理
127 |
128 | 绝大多数情况下,该免费额度都基本够用,并且可以稍微超出一点,不是已超出就立马停用,且每项额度单独计算,某项操作超出免费额度后只会停用该项操作,不影响其他的功能,即即便我的免费写入额度用完了,我的读写功能不受影响,图片能够正常加载,只是不能在图片管理后台看到新的图片了。
129 |
130 | 如果你的免费额度不够用,可以自行向Cloudflare购买Cloudflare Workers的付费版本,每月$5起步,按量收费,没有上述额度限制
131 |
132 | 另外针对环境变量所做的更改将在下次部署时生效,如更改了`环境变量`,针对某项功能进行了开启或关闭,请记得重新部署。
133 |
134 | 
135 |
136 | ### Sponsorship
137 | This project is tested with BrowserStack.
138 |
139 | This project is support by [Cloudflare](https://www.cloudflare.com/).
140 |
--------------------------------------------------------------------------------
/functions/file/[id].js:
--------------------------------------------------------------------------------
1 | export async function onRequest(context) { // Contents of context object
2 | const {
3 | request, // same as existing Worker API
4 | env, // same as existing Worker API
5 | params, // if filename includes [id] or [[path]]
6 | waitUntil, // same as ctx.waitUntil in existing Worker API
7 | next, // used for middleware or to fetch assets
8 | data, // arbitrary space for passing data between middlewares
9 | } = context;
10 | context.request
11 | const url = new URL(request.url);
12 |
13 | const response = fetch('https://telegra.ph/' + url.pathname + url.search, {
14 | method: request.method,
15 | headers: request.headers,
16 | body: request.body,
17 | }).then(async (response) => {
18 | console.log(response.ok); // true if the response status is 2xx
19 | console.log(response.status); // 200
20 | if(response.ok){
21 | // Referer header equal to the admin page
22 | console.log(url.origin+"/admin")
23 | if (request.headers.get('Referer') == url.origin+"/admin") {
24 | //show the image
25 | return response;
26 | }
27 |
28 | if (typeof env.img_url == "undefined" || env.img_url == null || env.img_url == ""){}else{
29 | //check the record from kv
30 | const record = await env.img_url.getWithMetadata(params.id);
31 | console.log("record")
32 | console.log(record)
33 | if (record.metadata === null) {
34 |
35 | }else{
36 |
37 | //if the record is not null, redirect to the image
38 | if (record.metadata.ListType=="White"){
39 | return response;
40 | }else if (record.metadata.ListType=="Block"){
41 | console.log("Referer")
42 | console.log(request.headers.get('Referer'))
43 | if(typeof request.headers.get('Referer') == "undefined" ||request.headers.get('Referer') == null || request.headers.get('Referer') == ""){
44 | return Response.redirect(url.origin+"/block-img.html", 302)
45 | }else{
46 | return Response.redirect("https://static-res.pages.dev/teleimage/img-block-compressed.png", 302)
47 | }
48 |
49 | }else if (record.metadata.Label=="adult"){
50 | if(typeof request.headers.get('Referer') == "undefined" ||request.headers.get('Referer') == null || request.headers.get('Referer') == ""){
51 | return Response.redirect(url.origin+"/block-img.html", 302)
52 | }else{
53 | return Response.redirect("https://static-res.pages.dev/teleimage/img-block-compressed.png", 302)
54 | }
55 | }
56 | //check if the env variables WhiteList_Mode are set
57 | console.log("env.WhiteList_Mode:",env.WhiteList_Mode)
58 | if (env.WhiteList_Mode=="true"){
59 | //if the env variables WhiteList_Mode are set, redirect to the image
60 | return Response.redirect(url.origin+"/whitelist-on.html", 302);
61 | }else{
62 | //if the env variables WhiteList_Mode are not set, redirect to the image
63 | return response;
64 | }
65 | }
66 |
67 | }
68 |
69 | //get time
70 | let time = new Date().getTime();
71 |
72 | let apikey=env.ModerateContentApiKey
73 |
74 | if(typeof apikey == "undefined" || apikey == null || apikey == ""){
75 |
76 | if (typeof env.img_url == "undefined" || env.img_url == null || env.img_url == ""){
77 | console.log("Not enbaled KV")
78 |
79 | }else{
80 | //add image to kv
81 | await env.img_url.put(params.id, "",{
82 | metadata: { ListType: "None", Label: "None",TimeStamp: time },
83 | });
84 |
85 | }
86 | }else{
87 | await fetch(`https://api.moderatecontent.com/moderate/?key=`+apikey+`&url=https://telegra.ph/` + url.pathname + url.search).
88 | then(async (response) => {
89 | let moderate_data = await response.json();
90 | console.log(moderate_data)
91 | console.log("---env.img_url---")
92 | console.log(env.img_url=="true")
93 | if (typeof env.img_url == "undefined" || env.img_url == null || env.img_url == ""){}else{
94 | //add image to kv
95 | await env.img_url.put(params.id, "",{
96 | metadata: { ListType: "None", Label: moderate_data.rating_label,TimeStamp: time },
97 | });
98 | }
99 | if (moderate_data.rating_label=="adult"){
100 | return Response.redirect(url.origin+"/block-img.html", 302)
101 | }});
102 |
103 | }
104 | }
105 | return response;
106 | });
107 |
108 | return response;
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/bg.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/admin.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |