Add installation instruction file;

Order directories.
This commit is contained in:
Schimon Jehudah, Adv. 2024-11-12 15:31:05 +02:00
parent 766e51af4c
commit 3ac005708d
49 changed files with 61 additions and 0 deletions

3
rivista/__init__.py Normal file
View file

@ -0,0 +1,3 @@
from rivista.version import __version__, __version_info__
print('Rivista XJP', __version__)

14
rivista/__main__.py Normal file
View file

@ -0,0 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#import importlib.resources
from rivista.http.instance import HttpInstance
import uvicorn
def main():
http_instance = HttpInstance()
return http_instance.app
app = main()
uvicorn.run(app, host='localhost', port=8000, reload=False)

View file

@ -0,0 +1,303 @@
/*
TODO
pubsub: news.movim.eu
node: fake-news
item: fdef84f5-e3e1-41ea-9b68-af4bb9130f77
title: #14October2023EpochEclipse
date: Fri, 15 Jan 2021 20:24:46
*/
* {
color: #eee;
max-width: 100%;
}
/*
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
*/
body {
background: #000;
}
code, pre {
overflow: auto;
max-height: 100%;
max-width: 100%; }
img, svg, video {
display: block;
max-height: 500px;
width: auto;
height: auto;
}
h1#title, h2#subtitle, #actions, #references {
text-align: center;
text-transform: uppercase;
line-height: 140%;
}
h5.related > a {
margin-right: 5px;
text-decoration: none;
user-select: none;
}
h3.title > a {
display: block;
padding-top: 50px;
}
#actions, #references {
border-bottom: 1px solid #eee;
line-height: 150%;
padding: 10px;
user-select: none;
}
#actions > *, #references * {
letter-spacing: 5px;
margin: 5px;
text-decoration: none;
}
#header, #menu {
line-height: 120%;
padding-bottom: 20px;
}
#menu > h3 {
padding-left: 2%;
}
#menu > ol > li {
padding: 5px;
}
#references {
margin-top: 5em;
border-top: 1px solid #eee;
}
#articles {
min-height: 80vh;
display: flex;
}
#articles #journal {
margin-left: 2%;
margin-right: 2%;
margin-top: 2%;
min-width: 350px;
padding-bottom: 0.67em;
width: 20%;
}
#journal {
margin: auto;
padding-top: 50px;
}
#articles > ul {
margin: auto;
margin-left: 2%;
margin-top: 2%;
}
#articles #journal ol,
#articles #journal ul {
/* height: 500px; */
line-height: 160%;
overflow: auto;
word-wrap: break-word;
}
#articles div.content {
font-size: 120%;
line-height: 200%;
margin: auto;
padding-left: 2%;
padding-right: 10%;
/* text-align: justify; */
word-wrap: break-word;
}
#articles div.entry {
padding-bottom: 0.67em;
}
#articles div.entry h1 {
font-size: 115%; /* 2vw */
}
#articles div.entry h2 {
font-size: 1.5vw;
}
#selection-page {
background: #000;
bottom: 0;
left: 0;
line-height: 200%;
overflow: overlay;
position: fixed;
right: 0;
text-align: center;
top: 0;
}
#selection-page p {
margin-left: 10%;
margin-right: 10%;
}
#selection-page span {
display: inline-grid;
margin: 2%
}
#selection-page img {
height: 128px;
margin-bottom: 20%;
margin-top: 20%;
width: 128px;
}
#selection-page #selection {
margin-bottom: 2%;
}
#selection-page #return {
/* font-style: italic; */
margin: auto;
}
#selection-link, #selection-page #return {
cursor: pointer;
text-decoration: underline;
}
.content[type='text'] {
white-space: pre-wrap;
}
#articles div.entry span.tags {
display: inline-flex;
/* display: ruby; */
flex-wrap: wrap;
}
#articles div.entry span.tags > div {
margin: 5px;
}
.enclosures {
cursor: help;
direction: ltr;
margin: 5px auto 15px 1%;
padding: 15px;
padding: 1em;
/* background: #222;
border: 1px solid GrayText;
border-radius: 4px;
border-radius: .5em;
color: #525c66;
border-left: double;
max-width: 40%; */
}
.enclosure a {
margin: 3px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.enclosure > span[icon='atom']:after,
.enclosure > span[icon='html5']:after,
.enclosure > span[icon='rss']:after {
content: '📰';
margin:3px;
}
.enclosure > span.audio:after {
content: ' (Audio file) ';
}
.enclosure > span[icon='audio']:after{
content: '🎼️';
margin: 3px;
}
.enclosure > span:after {
content: ' (Document file) ';
}
.enclosure > span[icon]:after {
content: '📄️';
margin: 3px;
}
.enclosure > span.executable:after{
content: ' (Executable file) ';
}
.enclosure > span[icon='executable']:after {
content: '📦️';
margin: 3px;
}
.enclosure > span.image:after {
content: ' (Image file) ';
}
.enclosure > span[icon='image']:after {
content: '🖼️';
margin: 3px;
}
.enclosure > span.video:after {
content: ' (Video file) ';
}
.enclosure > span[icon='video']:after {
content: '📽️';
margin:3px;
}
#note, #small {
line-height: 30px;
margin: auto;
margin-top: 0.67em;
max-width: 80%;
padding: 10px;
text-align: center;
user-select: none;
}
#small {
font-size: 80%;
}
@media (max-width: 1550px) {
#articles {
display: unset;
}
#articles #journal {
margin-right: unset;
min-width: unset;
width: unset;
}
}

View file

@ -0,0 +1,18 @@
<svg width="48" xmlns="http://www.w3.org/2000/svg" height="48">
<defs>
<linearGradient id="a" y1="40" x1="43" y2="4" x2="13" gradientUnits="userSpaceOnUse">
<stop stop-color="#f27935"/>
<stop offset="1" stop-color="#f2784b"/>
</linearGradient>
<linearGradient id="b" y1="27.13" x1="24.13" y2="41" x2="38" gradientUnits="userSpaceOnUse">
<stop stop-color="#292c2f"/>
<stop offset="1" stop-opacity="0"/>
</linearGradient>
</defs>
<g stroke-linejoin="round" stroke-width="6">
<path fill="url(#a)" d="m11 4c-1.662 0-3 1.338-3 3v22.08a7.999994 7.999994 0 0 0 -4 6.916016 7.999994 7.999994 0 0 0 8 8 7.999994 7.999994 0 0 0 6.919922 -4h22.08c1.662 0 3-1.338 3-3v-30c0-1.662-1.338-3-3-3z"/>
<path opacity=".2" fill="url(#b)" d="m26 21.75l-14-1.75 6 6-6 2 12 12h17c1.662 0 2-1.25 2-1.25zm-11.172 11.422l-5.656 5.656 4.889 4.891c2.049-.547 3.796-1.884 4.859-3.719h2.738z"/>
<path fill="#b86333" d="M4.02344 35.488281A7.999994 7.999994 0 0 0 4 36 7.999994 7.999994 0 0 0 12 44 7.999994 7.999994 0 0 0 18.919922 40H41C42.662 40 44 38.662 44 37V36C44 37.662 42.662 39 41 39H18.92A7.999994 7.999994 0 0 1 12 43 7.999994 7.999994 0 0 1 4.02344 35.488281"/>
<path fill="#ffffff" d="m12 16v4c8.837 0 16 7.163 16 16h4c0-11.05-8.954-20-20-20m0 8v4c4.418 0 8 3.582 8 8h4c0-6.627-5.373-12-12-12m0 8c-2.209 0-4 1.791-4 4 0 2.209 1.791 4 4 4 2.209 0 4-1.791 4-4 0-2.209-1.791-4-4-4"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View file

@ -0,0 +1,724 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0"
width="96"
height="96"
id="svg2408"
inkscape:version="0.48.1 r9760"
sodipodi:docname="main.svg"
inkscape:export-filename="/home/buckstabu/Dropbox/Public/lcicons/lcproto2.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1020"
id="namedview68"
showgrid="false"
inkscape:zoom="6.6666666"
inkscape:cx="53.537878"
inkscape:cy="36.716849"
inkscape:window-x="-8"
inkscape:window-y="-4"
inkscape:window-maximized="1"
inkscape:current-layer="svg2408" />
<defs
id="defs2410">
<linearGradient
id="linearGradient4017">
<stop
style="stop-color:#ff6600;stop-opacity:1;"
offset="0"
id="stop4019" />
<stop
style="stop-color:#ff1e00;stop-opacity:1;"
offset="1"
id="stop4021" />
</linearGradient>
<linearGradient
id="linearGradient4145">
<stop
style="stop-color:#ff5d00;stop-opacity:1;"
offset="0"
id="stop4147" />
<stop
style="stop-color:#00b1ff;stop-opacity:0;"
offset="1"
id="stop4149" />
</linearGradient>
<linearGradient
id="linearGradient3224">
<stop
id="stop3226"
style="stop-color:#42394b;stop-opacity:1"
offset="0" />
<stop
id="stop3228"
style="stop-color:#000000;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3465">
<stop
id="stop3467"
style="stop-color:#919191;stop-opacity:1"
offset="0" />
<stop
id="stop3469"
style="stop-color:#fdfdfd;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3187">
<stop
id="stop3189"
style="stop-color:#b4b4b4;stop-opacity:1"
offset="0" />
<stop
id="stop3191"
style="stop-color:#e6e6e6;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
x1="45.447727"
y1="92.539597"
x2="45.447727"
y2="7.0165396"
id="ButtonShadow"
gradientUnits="userSpaceOnUse"
gradientTransform="scale(1.0058652,0.994169)">
<stop
id="stop3750"
style="stop-color:#000000;stop-opacity:1"
offset="0" />
<stop
id="stop3752"
style="stop-color:#000000;stop-opacity:0.58823532"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3737">
<stop
id="stop3739"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop3741"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<filter
color-interpolation-filters="sRGB"
id="filter3174">
<feGaussianBlur
id="feGaussianBlur3176"
stdDeviation="1.71" />
</filter>
<linearGradient
x1="36.357143"
y1="6"
x2="36.357143"
y2="63.893143"
id="linearGradient3188"
xlink:href="#linearGradient3737"
gradientUnits="userSpaceOnUse" />
<linearGradient
x1="48"
y1="90"
x2="48"
y2="5.9877172"
id="linearGradient3427"
xlink:href="#linearGradient3187"
gradientUnits="userSpaceOnUse" />
<radialGradient
cx="47.098362"
cy="78.286942"
r="38.957481"
fx="47.098362"
fy="78.286942"
id="radialGradient3205"
xlink:href="#linearGradient3224"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3830053,-1.0350102e-8,0,1.3123934,-18.038924,-24.218731)" />
<linearGradient
x1="43.17857"
y1="13"
x2="43.17857"
y2="83.294571"
id="linearGradient3279"
xlink:href="#linearGradient3465"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0294118,0,0,1.0294118,-1.4117647,-1.411765)" />
<linearGradient
id="linearGradient3737-7">
<stop
id="stop3739-2"
style="stop-color:#ffffff;stop-opacity:1;"
offset="0" />
<stop
id="stop3741-7"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<radialGradient
cx="48"
cy="90.171875"
r="42"
fx="48"
fy="90.171875"
id="radialGradient2874"
xlink:href="#linearGradient3737-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1573129,0,0,0.99590774,-7.551021,0.1971319)" />
<linearGradient
id="linearGradient3737-4">
<stop
id="stop3739-8"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop3741-71"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<clipPath
id="clipPath3613">
<rect
width="84"
height="84"
rx="6"
ry="6"
x="6"
y="6"
id="rect3615"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" />
</clipPath>
<filter
x="-0.192"
y="-0.192"
width="1.3839999"
height="1.3839999"
color-interpolation-filters="sRGB"
id="filter3794">
<feGaussianBlur
id="feGaussianBlur3796"
stdDeviation="5.28" />
</filter>
<linearGradient
x1="48"
y1="20.220806"
x2="48"
y2="138.66119"
id="linearGradient2908"
xlink:href="#linearGradient3737-4"
gradientUnits="userSpaceOnUse" />
<linearGradient
x1="45.447727"
y1="92.539597"
x2="45.447727"
y2="7.0165396"
id="ButtonShadow-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0058652,0,0,0.994169,100,0)">
<stop
id="stop3750-8"
style="stop-color:#000000;stop-opacity:1"
offset="0" />
<stop
id="stop3752-5"
style="stop-color:#000000;stop-opacity:0.58823532"
offset="1" />
</linearGradient>
<linearGradient
x1="32.251034"
y1="6.1317081"
x2="32.251034"
y2="90.238609"
id="linearGradient3780"
xlink:href="#ButtonShadow-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0238095,0,0,1.0119048,-1.1428571,-98.071429)" />
<linearGradient
x1="32.251034"
y1="6.1317081"
x2="32.251034"
y2="90.238609"
id="linearGradient3772"
xlink:href="#ButtonShadow-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0238095,0,0,1.0119048,-1.1428571,-98.071429)" />
<linearGradient
x1="32.251034"
y1="6.1317081"
x2="32.251034"
y2="90.238609"
id="linearGradient3725"
xlink:href="#ButtonShadow-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0238095,0,0,1.0119048,-1.1428571,-98.071429)" />
<linearGradient
x1="32.251034"
y1="6.1317081"
x2="32.251034"
y2="90.238609"
id="linearGradient3721"
xlink:href="#ButtonShadow-0"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,-97)" />
<linearGradient
x1="32.251034"
y1="6.1317081"
x2="32.251034"
y2="90.238609"
id="linearGradient3224-3"
xlink:href="#ButtonShadow-0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0238095,0,0,1.0119048,-1.1428571,-98.071429)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3737-4"
id="linearGradient3053"
gradientUnits="userSpaceOnUse"
x1="48"
y1="20.220806"
x2="48"
y2="138.66119" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3224"
id="radialGradient3071"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3830053,-1.0350102e-8,0,1.3123934,-17.140614,-23.729195)"
cx="47.098362"
cy="78.286942"
fx="47.098362"
fy="78.286942"
r="38.957481" />
<linearGradient
id="linearGradient3304">
<stop
id="stop3306"
style="stop-color:#ff8313;stop-opacity:1"
offset="0" />
<stop
id="stop3308"
style="stop-color:#ffe400;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3304"
id="linearGradient3023"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2146893,0,0,1.2146893,-90.000003,-246.69493)"
x1="143.75"
y1="334.5"
x2="143.75"
y2="276" />
<linearGradient
id="linearGradient3045">
<stop
id="stop3047"
style="stop-color:#ff8313;stop-opacity:1"
offset="0" />
<stop
id="stop3049"
style="stop-color:#ffe400;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3737"
id="linearGradient3894"
x1="49.010517"
y1="48.650372"
x2="73.444344"
y2="48.650372"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(2.1,0)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3737"
id="linearGradient3896"
x1="23.037859"
y1="48.650372"
x2="47.471485"
y2="48.650372"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(2.1,0)" />
<radialGradient
inkscape:collect="always"
xlink:href="#ButtonShadow-0"
id="radialGradient3908"
cx="61.227432"
cy="48.650372"
fx="61.227432"
fy="48.650372"
r="12.216913"
gradientTransform="translate(2.1,7.9644297e-6)"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#ButtonShadow-0"
id="radialGradient3910"
cx="35.254673"
cy="48.650372"
fx="35.254673"
fy="48.650372"
r="12.216814"
gradientTransform="translate(2.1,-5.9733707e-6)"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3224"
id="radialGradient3955"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.4908884,-1.1072317e-8,0,1.4039702,-22.221992,-28.734351)"
cx="47.098362"
cy="78.286942"
fx="47.098362"
fy="78.286942"
r="38.957481" />
<radialGradient
cx="47.098362"
cy="78.286942"
r="38.957481"
fx="47.098362"
fy="78.286942"
id="radialGradient3205-1"
xlink:href="#linearGradient3224-6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3830053,-1.0350102e-8,0,1.3123934,-18.038924,-24.218731)" />
<linearGradient
id="linearGradient3224-6">
<stop
id="stop3226-2"
style="stop-color:#42394b;stop-opacity:1"
offset="0" />
<stop
id="stop3228-1"
style="stop-color:#000000;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
x1="48"
y1="90"
x2="48"
y2="5.9877172"
id="linearGradient3427-0"
xlink:href="#linearGradient3187-5"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3187-5">
<stop
id="stop3189-3"
style="stop-color:#b4b4b4;stop-opacity:1"
offset="0" />
<stop
id="stop3191-2"
style="stop-color:#e6e6e6;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
x1="36.357143"
y1="6"
x2="36.357143"
y2="63.893143"
id="linearGradient3188-1"
xlink:href="#linearGradient3737-9"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3737-9">
<stop
id="stop3739-7"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop3741-6"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="43.17857"
y1="13"
x2="43.17857"
y2="83.294571"
id="linearGradient3279-8"
xlink:href="#linearGradient3465-2"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0294118,0,0,1.0294118,-1.4117647,-1.411765)" />
<linearGradient
id="linearGradient3465-2">
<stop
id="stop3467-0"
style="stop-color:#919191;stop-opacity:1"
offset="0" />
<stop
id="stop3469-6"
style="stop-color:#fdfdfd;stop-opacity:1"
offset="1" />
</linearGradient>
<radialGradient
cx="48"
cy="90.171875"
r="42"
fx="48"
fy="90.171875"
id="radialGradient2874-4"
xlink:href="#linearGradient3737-7-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1573129,0,0,0.99590774,-7.551021,0.1971319)" />
<linearGradient
id="linearGradient3737-7-3">
<stop
id="stop3739-2-3"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop3741-7-6"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="48"
y1="20.220806"
x2="48"
y2="138.66119"
id="linearGradient2908-9"
xlink:href="#linearGradient3737-4-0"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3737-4-0">
<stop
id="stop3739-8-4"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop3741-71-8"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<clipPath
id="clipPath3613-5">
<rect
width="84"
height="84"
rx="6"
ry="6"
x="6"
y="6"
id="rect3615-1"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" />
</clipPath>
<filter
x="-0.192"
y="-0.192"
width="1.3839999"
height="1.3839999"
color-interpolation-filters="sRGB"
id="filter3794-2">
<feGaussianBlur
id="feGaussianBlur3796-9"
stdDeviation="5.28" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3187-5"
id="linearGradient4094"
gradientUnits="userSpaceOnUse"
x1="48"
y1="90"
x2="48"
y2="5.9877172" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3737-9"
id="linearGradient4096"
gradientUnits="userSpaceOnUse"
x1="36.357143"
y1="6"
x2="36.357143"
y2="63.893143" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3465-2"
id="linearGradient4098"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0294118,0,0,1.0294118,-1.4117647,-1.411765)"
x1="43.17857"
y1="13"
x2="43.17857"
y2="83.294571" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3737-7-3"
id="radialGradient4100"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1573129,0,0,0.99590774,-7.551021,0.1971319)"
cx="48"
cy="90.171875"
fx="48"
fy="90.171875"
r="42" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3737-4-0"
id="linearGradient4102"
gradientUnits="userSpaceOnUse"
x1="48"
y1="20.220806"
x2="48"
y2="138.66119" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3224-6"
id="radialGradient4104"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3830053,-1.0350102e-8,0,1.3123934,-18.038924,-24.218731)"
cx="47.098362"
cy="78.286942"
fx="47.098362"
fy="78.286942"
r="38.957481" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3224-6"
id="radialGradient4113"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3830053,-1.0350102e-8,0,1.3123934,-17.140614,-23.729195)"
cx="47.098362"
cy="78.286942"
fx="47.098362"
fy="78.286942"
r="38.957481" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4017"
id="linearGradient4023"
x1="48.732876"
y1="37.021988"
x2="48.609169"
y2="60.526169"
gradientUnits="userSpaceOnUse" />
</defs>
<metadata
id="metadata2413">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="opacity:0.6;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3977-9"
inkscape:connector-curvature="0"
d="m 17.89831,14.489536 c -1.662,0 -3,1.338 -3,3 l 0,62 c 0,1.662 1.338,3 3,3 l 62,0 c 1.662,0 3,-1.338 3,-3 l 0,-62 c 0,-1.662 -1.338,-3 -3,-3 l -62,0 z m 0,0.96875 62,0 c 1.140081,0 2.03125,0.891169 2.03125,2.03125 l 0,62 c 0,1.140081 -0.891169,2.03125 -2.03125,2.03125 l -62,0 c -1.140081,0 -2.03125,-0.891169 -2.03125,-2.03125 l 0,-62 c 0,-1.140081 0.891169,-2.03125 2.03125,-2.03125 z" />
<g
id="layer2"
style="display:none">
<rect
width="86"
height="85"
rx="6"
ry="6"
x="5"
y="7"
id="rect3745"
style="opacity:0.9;fill:url(#ButtonShadow);fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter3174)" />
</g>
<rect
style="fill:url(#radialGradient4113);fill-opacity:1;stroke:none"
id="rect3461-7"
y="8.743969"
x="9.0391903"
ry="6.1732869"
rx="5.8527675"
height="78.516495"
width="77.914963" />
<path
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.15;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
id="rect3222-3-8"
inkscape:connector-curvature="0"
d="m 19.89831,13.489536 c -3.289406,0 -6,2.710594 -6,6 l 0,58 c 0,3.289406 2.710594,6 6,6 l 58,0 c 3.289406,0 6,-2.710594 6,-6 l 0,-58 c 0,-3.289406 -2.710594,-6 -6,-6 l -58,0 z m 0,4 58,0 c 1.142594,0 2,0.857406 2,2 l 0,58 c 0,1.142594 -0.857406,2 -2,2 l -58,0 c -1.142594,0 -2,-0.857406 -2,-2 l 0,-58 c 0,-1.142594 0.857406,-2 2,-2 z" />
<path
style="opacity:0.3;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3981-0"
inkscape:connector-curvature="0"
d="m 17.89831,14.489536 c -1.662,0 -3,1.338 -3,3 l 0,62 c 0,1.662 1.338,3 3,3 l 62,0 c 1.662,0 3,-1.338 3,-3 l 0,-62 c 0,-1.662 -1.338,-3 -3,-3 l -62,0 z m 0,1.9375 62,0 c 0.618163,0 1.0625,0.444337 1.0625,1.0625 l 0,62 c 0,0.618163 -0.444337,1.0625 -1.0625,1.0625 l -62,0 c -0.618163,0 -1.0625,-0.444337 -1.0625,-1.0625 l 0,-62 c 0,-0.618163 0.444337,-1.0625 1.0625,-1.0625 z" />
<g
id="g3912"
style="fill:url(#linearGradient4023);fill-opacity:1.0;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
transform="matrix(1.2125503,0,0,1.2125503,-13.04106,-10.991024)">
<path
d="m 26.099813,37.395511 0,22.509723 22.50972,0 0,-7.118459 -15.198872,0 0,-15.391264 -7.310848,0 z"
id="rect3294"
style="fill:url(#linearGradient4023);fill-opacity:1.0;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
d="m 52.072568,37.395511 0,22.509723 22.509727,0 0,-7.310849 -15.583656,0 0,-7.888025 15.583656,0 0,-7.310849 -22.509727,0 z"
id="rect3298"
style="fill:url(#linearGradient4023);fill-opacity:1.0;stroke:#000000;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
inkscape:connector-curvature="0" />
</g>
<path
style="opacity:0.07999998;fill:#d9c6ed;fill-opacity:1;stroke:none"
id="rect3256-3"
inkscape:connector-curvature="0"
d="m 14.89831,8.7395363 c -3.242433,0 -5.8437503,2.7674997 -5.8437503,6.1874997 l 0,49.0625 C 27.878614,50.130638 54.866224,40.195879 86.96081,42.208286 l 0,-27.28125 c 0,-3.420001 -2.63257,-6.1874997 -5.875,-6.1874997 l -66.1875,0 z" />
<g
id="layer1"
style="display:inline">
<path
d="M 12,6 C 8.676,6 6,8.676 6,12 l 0,72 c 0,3.324 2.676,6 6,6 l 72,0 c 3.324,0 6,-2.676 6,-6 L 90,12 C 90,8.676 87.324,6 84,6 L 12,6 z m 5,7 62,0 c 2.216001,0 4,1.784 4,4 l 0,62 c 10e-7,2.216001 -1.784,4 -4,4 l -62,0 c -2.215999,10e-7 -4,-1.784 -4,-4 l 0,-62 c 0,-2.215999 1.784,-4 4,-4 z"
inkscape:connector-curvature="0"
id="rect2419"
style="fill:url(#linearGradient4094);fill-opacity:1;fill-rule:nonzero;stroke:none" />
<path
d="M 12,6 C 8.676,6 6,8.676 6,12 l 0,2 0,68 0,2 c 0,0.334721 0.04135,0.6507 0.09375,0.96875 0.0487,0.295596 0.09704,0.596915 0.1875,0.875 0.00988,0.03038 0.020892,0.0636 0.03125,0.09375 0.098865,0.287771 0.2348802,0.547452 0.375,0.8125 0.1445918,0.273507 0.3156161,0.535615 0.5,0.78125 0.1843839,0.245635 0.3737765,0.473472 0.59375,0.6875 0.439947,0.428056 0.94291,0.814526 1.5,1.09375 0.278545,0.139612 0.5734731,0.246947 0.875,0.34375 -0.2562018,-0.100222 -0.4867109,-0.236272 -0.71875,-0.375 -0.00741,-0.0044 -0.023866,0.0045 -0.03125,0 -0.031933,-0.0193 -0.062293,-0.04251 -0.09375,-0.0625 -0.120395,-0.0767 -0.2310226,-0.163513 -0.34375,-0.25 -0.1061728,-0.0808 -0.2132809,-0.161112 -0.3125,-0.25 C 8.4783201,88.557317 8.3087904,88.373362 8.15625,88.1875 8.0486711,88.057245 7.9378561,87.922215 7.84375,87.78125 7.818661,87.74287 7.805304,87.69538 7.78125,87.65625 7.716487,87.553218 7.6510225,87.451733 7.59375,87.34375 7.4927417,87.149044 7.3880752,86.928049 7.3125,86.71875 7.30454,86.69694 7.288911,86.6782 7.28125,86.65625 7.2494249,86.5643 7.2454455,86.469419 7.21875,86.375 7.1884177,86.268382 7.1483606,86.171969 7.125,86.0625 7.0521214,85.720988 7,85.364295 7,85 L 7,83 7,15 7,13 C 7,10.218152 9.2181517,8 12,8 l 2,0 68,0 2,0 c 2.781848,0 5,2.218152 5,5 l 0,2 0,68 0,2 c 0,0.364295 -0.05212,0.720988 -0.125,1.0625 -0.04415,0.206893 -0.08838,0.397658 -0.15625,0.59375 -0.0077,0.02195 -0.0233,0.04069 -0.03125,0.0625 -0.06274,0.173739 -0.138383,0.367449 -0.21875,0.53125 -0.04158,0.0828 -0.07904,0.169954 -0.125,0.25 -0.0546,0.09721 -0.126774,0.18835 -0.1875,0.28125 -0.09411,0.140965 -0.204921,0.275995 -0.3125,0.40625 -0.143174,0.17445 -0.303141,0.346998 -0.46875,0.5 -0.01117,0.0102 -0.01998,0.02115 -0.03125,0.03125 -0.138386,0.125556 -0.285091,0.234436 -0.4375,0.34375 -0.102571,0.07315 -0.204318,0.153364 -0.3125,0.21875 -0.0074,0.0045 -0.02384,-0.0044 -0.03125,0 -0.232039,0.138728 -0.462548,0.274778 -0.71875,0.375 0.301527,-0.0968 0.596455,-0.204138 0.875,-0.34375 0.55709,-0.279224 1.060053,-0.665694 1.5,-1.09375 0.219973,-0.214028 0.409366,-0.441865 0.59375,-0.6875 0.184384,-0.245635 0.355408,-0.507743 0.5,-0.78125 0.14012,-0.265048 0.276135,-0.524729 0.375,-0.8125 0.01041,-0.03078 0.02133,-0.06274 0.03125,-0.09375 0.09046,-0.278085 0.1388,-0.579404 0.1875,-0.875 C 89.95865,84.6507 90,84.334721 90,84 l 0,-2 0,-68 0,-2 C 90,8.676 87.324,6 84,6 L 12,6 z"
inkscape:connector-curvature="0"
id="rect3728"
style="opacity:0.5;fill:url(#linearGradient4096);fill-opacity:1;fill-rule:nonzero;stroke:none" />
<path
d="m 17,12 c -2.752703,0 -5,2.247297 -5,5 l 0,62 c 0,2.752703 2.247298,5 5,5 l 62,0 c 2.752703,0 5.000001,-2.247297 5,-5 l 0,-62 c 0,-2.752703 -2.247297,-5 -5,-5 l -62,0 z m 0,2 62,0 c 1.679298,0 3,1.320703 3,3 l 0,62 c 10e-7,1.679297 -1.320703,3 -3,3 l -62,0 c -1.679296,0 -3,-1.320703 -3,-3 l 0,-62 c 0,-1.679297 1.320703,-3 3,-3 z"
inkscape:connector-curvature="0"
id="rect3425"
style="fill:url(#linearGradient4098);fill-opacity:1;fill-rule:nonzero;stroke:none" />
<path
d="M 12,90 C 8.676,90 6,87.324 6,84 L 6,82 6,14 6,12 c 0,-0.334721 0.04135,-0.6507 0.09375,-0.96875 0.0487,-0.295596 0.09704,-0.596915 0.1875,-0.875 C 6.29113,10.12587 6.302142,10.09265 6.3125,10.0625 6.411365,9.774729 6.5473802,9.515048 6.6875,9.25 6.8320918,8.976493 7.0031161,8.714385 7.1875,8.46875 7.3718839,8.223115 7.5612765,7.995278 7.78125,7.78125 8.221197,7.353194 8.72416,6.966724 9.28125,6.6875 9.559795,6.547888 9.8547231,6.440553 10.15625,6.34375 9.9000482,6.443972 9.6695391,6.580022 9.4375,6.71875 c -0.00741,0.0044 -0.023866,-0.0045 -0.03125,0 -0.031933,0.0193 -0.062293,0.04251 -0.09375,0.0625 -0.120395,0.0767 -0.2310226,0.163513 -0.34375,0.25 -0.1061728,0.0808 -0.2132809,0.161112 -0.3125,0.25 C 8.4783201,7.442683 8.3087904,7.626638 8.15625,7.8125 8.0486711,7.942755 7.9378561,8.077785 7.84375,8.21875 7.818661,8.25713 7.805304,8.30462 7.78125,8.34375 7.716487,8.446782 7.6510225,8.548267 7.59375,8.65625 7.4927417,8.850956 7.3880752,9.071951 7.3125,9.28125 7.30454,9.30306 7.288911,9.3218 7.28125,9.34375 7.2494249,9.4357 7.2454455,9.530581 7.21875,9.625 7.1884177,9.731618 7.1483606,9.828031 7.125,9.9375 7.0521214,10.279012 7,10.635705 7,11 l 0,2 0,68 0,2 c 0,2.781848 2.2181517,5 5,5 l 2,0 68,0 2,0 c 2.781848,0 5,-2.218152 5,-5 l 0,-2 0,-68 0,-2 C 89,10.635705 88.94788,10.279012 88.875,9.9375 88.83085,9.730607 88.78662,9.539842 88.71875,9.34375 88.71105,9.3218 88.69545,9.30306 88.6875,9.28125 88.62476,9.107511 88.549117,8.913801 88.46875,8.75 88.42717,8.6672 88.38971,8.580046 88.34375,8.5 88.28915,8.40279 88.216976,8.31165 88.15625,8.21875 88.06214,8.077785 87.951329,7.942755 87.84375,7.8125 87.700576,7.63805 87.540609,7.465502 87.375,7.3125 87.36383,7.3023 87.35502,7.29135 87.34375,7.28125 87.205364,7.155694 87.058659,7.046814 86.90625,6.9375 86.803679,6.86435 86.701932,6.784136 86.59375,6.71875 c -0.0074,-0.0045 -0.02384,0.0044 -0.03125,0 -0.232039,-0.138728 -0.462548,-0.274778 -0.71875,-0.375 0.301527,0.0968 0.596455,0.204138 0.875,0.34375 0.55709,0.279224 1.060053,0.665694 1.5,1.09375 0.219973,0.214028 0.409366,0.441865 0.59375,0.6875 0.184384,0.245635 0.355408,0.507743 0.5,0.78125 0.14012,0.265048 0.276135,0.524729 0.375,0.8125 0.01041,0.03078 0.02133,0.06274 0.03125,0.09375 0.09046,0.278085 0.1388,0.579404 0.1875,0.875 C 89.95865,11.3493 90,11.665279 90,12 l 0,2 0,68 0,2 c 0,3.324 -2.676,6 -6,6 l -72,0 z"
inkscape:connector-curvature="0"
id="path3615"
style="opacity:0.4;fill:url(#radialGradient4100);fill-opacity:1;fill-rule:nonzero;stroke:none" />
<rect
width="66"
height="66"
rx="12"
ry="12"
x="15"
y="15"
clip-path="url(#clipPath3613-5)"
id="rect3171"
style="opacity:0.1;fill:url(#linearGradient4102);fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3794-2)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 28 KiB

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 61 KiB

View file

@ -0,0 +1 @@
<svg width="95" height="97" viewBox="0 0 95 97" version="1.1" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient x1="50%" y1="99.992%" x2="50%" y2="0%" id="linearGradient-1"><stop stop-color="#FFD53F" offset="0%"/><stop stop-color="#EED64E" offset="6%"/><stop stop-color="#A6DB8C" offset="32%"/><stop stop-color="#6DDEBE" offset="55%"/><stop stop-color="#44E1E1" offset="75%"/><stop stop-color="#2BE2F7" offset="91%"/><stop stop-color="#22E3FF" offset="100%"/></linearGradient><linearGradient x1="47.461%" y1=".977%" x2="51.983%" y2="99.601%" id="linearGradient-2"><stop stop-color="#566690" offset="6%"/><stop stop-color="#00293E" offset="54%"/><stop stop-color="#001723" offset="70%"/><stop stop-color="#000609" offset="89%"/><stop stop-color="#000" offset="100%"/></linearGradient></defs><g id="Welcome" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Raven-Landing-Page-" transform="translate(-672 -4411)" fill-rule="nonzero"><g id="Pricing" transform="translate(-28 4282)"><g id="raven-app-logo" transform="translate(703 132)"><circle id="Oval" stroke="#FFF" stroke-width="3" fill="url(#linearGradient-1)" cx="44.5" cy="44.5" r="46"/><path d="M74.602 41.76C59.509 15.688 47.575 13.543 38.865 17.612c-4.255 1.99-2.476 3.82-8.54 2.505-5.396-1.168-7.91-1.565-12.653.624C12.927 22.93 11 25.757 11 27.013c0 1.256 1.268-1.88 4.744-2.204 3.477-.323 8.228 0 12.024 2.82 3.795 2.82 4.106 3.761 4.106 5.017 0 1.256-4.951-.558-9.8.624-4.284 1.043-7.59 2.505-7.909 3.76-.318 1.257 8.621.324 12.335.317 1.764.058 3.217-.492 4.448 1.88 1.275 2.497 1.579 4.407 3.165 5.009 1.586.602 1.898-1.249 3.795 2.512 1.898 3.76 2.528 5.95.312 11.59-2.217 5.64-3.47 9.43-2.52 8.483.74-.735 2.453-.91 3.306-2.005-.238 2.012 0 5.714 2.705 9.842 4.744 7.205 11.683 6.61 21.497 9.1 15.278 3.812 22.884 4.032 26.086 9.203.63 1.02 1.03 1.917.356-.529-3.143-11.392-5.79-34.682-15.048-50.671z" id="Path" fill="url(#linearGradient-2)"/><circle id="Oval" fill="#FFF" cx="41" cy="23" r="2"/></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -0,0 +1,513 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="128px"
height="128px" viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve">
<g id="Layer_30">
<g opacity="0.5">
<image overflow="visible" width="188" height="190" xlink:href="data:image/png;base64,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" transform="matrix(1 0 0 1 -28 -30)">
</image>
</g>
</g>
<g id="Layer_16">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="112.8086" y1="40.3027" x2="95.1199" y2="22.614">
<stop offset="0.0843" style="stop-color:#FFFFFF"/>
<stop offset="0.2234" style="stop-color:#F6F6F6"/>
<stop offset="0.4466" style="stop-color:#DFDFDF"/>
<stop offset="0.7243" style="stop-color:#B9B9B9"/>
<stop offset="1" style="stop-color:#8C8C8C"/>
</linearGradient>
<path fill="url(#SVGID_1_)" d="M112.064,36.457c0,0-3.871-11.953-8.89-16.971c-2.829-2.829-4.106-0.547-5.019,0.365
c-0.646,0.645-2.099,1.825-2.099,1.825s4.198,19.526,7.848,20.621C107.555,43.392,113.289,44.487,112.064,36.457z"/>
</g>
<g id="Layer_17">
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="111.1475" y1="38.2959" x2="98.8601" y2="26.0085">
<stop offset="0" style="stop-color:#D9D9D9"/>
<stop offset="0.0314" style="stop-color:#CECECE"/>
<stop offset="0.2301" style="stop-color:#909090"/>
<stop offset="0.4206" style="stop-color:#5D5D5D"/>
<stop offset="0.5978" style="stop-color:#353535"/>
<stop offset="0.7587" style="stop-color:#181818"/>
<stop offset="0.8981" style="stop-color:#060606"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<path fill="url(#SVGID_2_)" d="M101.183,32.338l2.039-2.039c0,0-1.324-3.332-1.872-5.157c-0.314-1.049,0.089-4.729,3.588,1.705
c2.828,5.201,3.89,7.98,4.134,10.156c0.308,2.738,0.354,5.855-3.312,2.19C102.095,35.529,101.183,32.338,101.183,32.338z"/>
</g>
<g id="Layer_32">
<g opacity="0.7">
<image overflow="visible" width="78" height="85" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE4AAABVCAYAAADnu9JFAAAACXBIWXMAAAsSAAALEgHS3X78AAAA
GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAc5JREFUeNrs2V1PwkAQheG2IK2C
KIrGGC+88P//Lo2AH2hAROpMcjYhKKR648S8k5wsctU8mdldaiujflUtCIADDjjgKOCAAw444Cjg
gAMOOOAo4IADDjgKOOCAAw44CjjggAMOOAo44IBrXvlGgGtQhZ6nrRW4hmgOVlm6WtOz1cBtH09/
jn3LieVCa8eysiy11sB9hduz9C1Xlhut3nXvlrnWUHDtIHA+qqU67VrrwDKzPGn9iIRXBDscvPN6
lnPLpdZDfR/qsIgAVys+jm9afRKOLUPLkbqxiIQXZY9L+1xXYzrUYeH729jyGG1co1xH0j5XqdPO
dFg41ER5iXRIRILL1/a4UwEWAnO4qUZ5Bdz3e26lbhtoXL3LnqOdrpHg8rXL8IE6rq+/Xy0P6r4F
cLsvxD2dqJUOiYkOibm6Drgtz1XpDldqRO8tI3Xfn49rVLhcd7mOPvuI3gH3s4vxQiN6q3GdMaq7
0VZCm+oSPNbnEIdD1JeF6f1cqXHNBOb3uGWEu1zkt6zFxu/T1IVcgBvucQmrzgK9VuK/XMABBxxw
FHDAAQcccBRwwAEHHHAUcMABBxwFHHDAAQccBRxwwAEHHAUccMD9x/oUYADc5V+26QzFDQAAAABJ
RU5ErkJggg==" transform="matrix(1 0 0 1 60 -16)">
</image>
</g>
</g>
<g id="Layer_15">
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="94.0039" y1="70.4434" x2="67.1808" y2="43.6203">
<stop offset="0" style="stop-color:#B2B2B2"/>
<stop offset="0.0758" style="stop-color:#CCCCCC"/>
<stop offset="0.1662" style="stop-color:#E2E2E2"/>
<stop offset="0.2643" style="stop-color:#F2F2F2"/>
<stop offset="0.3746" style="stop-color:#FCFCFC"/>
<stop offset="0.5225" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#CCCCCC"/>
</linearGradient>
<path fill="url(#SVGID_3_)" d="M86.34,25.205l8.988-9.734l1.699,6.205c3.593,13.869,14.359,26.826,13.082,14.781
c-0.413-3.891,2.131-2.413,2.131,1.819c0,4.232-0.671,5.931-3.744,9.943c-2.379,3.107-34.744,42.475-34.744,42.475L40.764,73.502
L86.34,25.205z"/>
</g>
<g id="Layer_19">
<g>
<line fill="#808080" x1="57.792" y1="75.817" x2="93.8" y2="32.823"/>
<path fill="#808080" d="M58.244,76.196c0,0,35.988-42.977,36.009-42.994c0.463-0.407-0.324-1.496-0.905-0.758
c-0.033,0.042-36.008,42.994-36.008,42.994l0.452,0.379l0,0l0,0L58.244,76.196z"/>
</g>
<g>
<line fill="#CCCCCC" x1="57.282" y1="67.535" x2="93.29" y2="24.54"/>
<path fill="#CCCCCC" d="M57.734,67.914c0,0,35.988-42.978,36.009-42.995c0.462-0.407-0.324-1.496-0.905-0.758
c-0.033,0.042-36.009,42.995-36.009,42.995l0.453,0.379l0,0l0,0L57.734,67.914z"/>
</g>
<path fill="#808080" d="M68.58,91.125c0,0,35.988-42.977,36.009-42.995c0.462-0.407-0.324-1.496-0.905-0.758
c-0.033,0.042-36.009,42.995-36.009,42.995l0.453,0.379l0,0l0,0L68.58,91.125z"/>
</g>
<g id="Layer_21">
<path fill="#E5E5E5" stroke="#CCCCCC" stroke-width="1.1805" d="M59.001,69.532c0,0,5.363,9.959,11.645,15.321
c6.282,5.363-5.057,7.202-5.057,7.202L46.284,81.177L59.001,69.532z"/>
</g>
<g id="Layer_20">
<g>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="78.5117" y1="75.3047" x2="69.041" y2="65.834">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#A6A6A6"/>
</linearGradient>
<path fill="url(#SVGID_4_)" d="M77.371,74.696l-6.254-5.124l3.469,5.22c0.134,0.181,0.246,0.217,0.335,0.109
c0.045-0.054,0.076-0.092,0.095-0.114c0.02-0.022,0.039-0.047,0.062-0.074c0.029-0.036,0.048-0.059,0.056-0.067
c0.126-0.153,0.298-0.188,0.514-0.105s0.416,0.262,0.599,0.537c0.232,0.35,0.357,0.719,0.375,1.106
c0.019,0.389-0.073,0.704-0.273,0.945c-0.089,0.107-0.221,0.24-0.396,0.398c-0.175,0.159-0.326,0.313-0.452,0.466
c-0.089,0.107-0.216,0.287-0.381,0.541c-0.166,0.253-0.294,0.433-0.383,0.54c-0.2,0.241-0.442,0.329-0.727,0.263
c-0.285-0.066-0.544-0.274-0.776-0.624c-0.183-0.275-0.292-0.562-0.33-0.861c-0.037-0.298,0.004-0.52,0.123-0.663
c0.008-0.009,0.026-0.032,0.057-0.067c0.029-0.036,0.054-0.065,0.072-0.088s0.047-0.057,0.084-0.102
c0.104-0.126,0.094-0.283-0.033-0.473l-3.828-5.761c-0.126-0.189-0.241-0.221-0.345-0.096c-0.022,0.027-0.059,0.07-0.106,0.129
c-0.049,0.059-0.084,0.101-0.106,0.128c-0.127,0.152-0.296,0.186-0.509,0.099c-0.212-0.087-0.409-0.269-0.593-0.544
c-0.232-0.35-0.357-0.718-0.375-1.106c-0.019-0.389,0.077-0.708,0.284-0.959c0.104-0.125,0.276-0.297,0.518-0.517
c0.241-0.219,0.414-0.391,0.518-0.516c0.162-0.196,0.322-0.42,0.477-0.668c0.207-0.331,0.336-0.528,0.388-0.592
c0.237-0.285,0.521-0.292,0.849-0.019l6.059,5.321l-3.226-4.854c-0.162-0.244-0.277-0.382-0.346-0.414s-0.133-0.013-0.192,0.06
l-0.056,0.067c-0.015,0.06-0.037,0.107-0.067,0.144c-0.143,0.171-0.317,0.218-0.524,0.139s-0.403-0.259-0.589-0.538
c-0.543-0.816-0.601-1.483-0.171-2c0.059-0.071,0.155-0.167,0.288-0.287c0.326-0.29,0.541-0.498,0.645-0.623
c0.147-0.178,0.273-0.36,0.376-0.546c0.132-0.241,0.254-0.429,0.364-0.563c0.17-0.205,0.386-0.261,0.646-0.169
s0.505,0.31,0.733,0.653c0.186,0.279,0.305,0.562,0.355,0.849s0.018,0.5-0.1,0.643l-0.121,0.146
c-0.096,0.115-0.112,0.24-0.05,0.374c0.021,0.051,0.097,0.177,0.23,0.377l4.664,7.02c0.253,0.379,0.378,0.688,0.377,0.927
c0,0.238-0.119,0.5-0.354,0.784l-0.874,1.054c-0.191,0.231-0.359,0.354-0.504,0.366S77.605,74.889,77.371,74.696z"/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="85.0039" y1="67.3789" x2="75.6361" y2="58.0111">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#A6A6A6"/>
</linearGradient>
<path fill="url(#SVGID_5_)" d="M78.263,60.425l1.07,1.611c0.079-0.038,0.155-0.1,0.227-0.187c0.194-0.235,0.2-0.49,0.017-0.767
c-0.078-0.117-0.137-0.199-0.178-0.246c-0.129-0.151-0.214-0.258-0.257-0.323c-0.112-0.17-0.166-0.374-0.158-0.613
c0.007-0.238,0.073-0.434,0.199-0.585c0.339-0.409,0.671-0.37,0.995,0.119c0.134,0.202,0.312,0.511,0.536,0.93
c0.087,0.163,0.24,0.409,0.458,0.738c0.24,0.361,0.503,0.723,0.787,1.087c0.216,0.275,0.391,0.514,0.524,0.715
c0.353,0.531,0.354,1.007,0.004,1.429c-0.299,0.36-0.585,0.334-0.859-0.078c-0.07-0.105-0.145-0.234-0.224-0.388
c-0.033-0.073-0.089-0.168-0.167-0.285c-0.161-0.243-0.357-0.226-0.588,0.052c-0.007,0.009-0.047,0.077-0.119,0.202l1.26,1.896
c0.212,0.319,0.395,0.453,0.548,0.401c0.087-0.029,0.19-0.115,0.31-0.259l0.925-1.116c0.201-0.242,0.313-0.45,0.339-0.624
c0.025-0.173-0.047-0.388-0.217-0.643c-0.092-0.138-0.249-0.331-0.473-0.579c-0.28-0.312-0.466-0.537-0.558-0.675
c-0.184-0.276-0.274-0.583-0.272-0.92c0.002-0.337,0.099-0.622,0.291-0.853c0.436-0.526,0.932-0.37,1.488,0.468
c0.135,0.202,0.273,0.426,0.419,0.671c0.198,0.371,0.393,0.7,0.583,0.986c0.106,0.159,0.277,0.393,0.515,0.699
c0.236,0.307,0.408,0.539,0.514,0.698c0.197,0.297,0.276,0.551,0.236,0.761c-0.04,0.21-0.178,0.458-0.414,0.743
c-0.118,0.143-0.24,0.28-0.364,0.414c-0.763,0.814-1.447,1.587-2.053,2.318c-0.2,0.24-0.489,0.621-0.869,1.141
s-0.67,0.9-0.869,1.141c-0.214,0.259-0.463,0.36-0.746,0.305s-0.543-0.262-0.779-0.618c-0.182-0.272-0.291-0.558-0.326-0.854
c-0.036-0.296,0.005-0.517,0.125-0.661c0.007-0.009,0.025-0.03,0.056-0.066c0.029-0.036,0.054-0.065,0.072-0.088
s0.047-0.057,0.084-0.102c0.104-0.126,0.094-0.284-0.034-0.476l-3.854-5.799c-0.135-0.202-0.254-0.24-0.358-0.114
c-0.008,0.009-0.022,0.027-0.045,0.054c-0.008,0.029-0.02,0.052-0.033,0.07c-0.047,0.093-0.08,0.153-0.103,0.18
c-0.119,0.144-0.287,0.174-0.504,0.09c-0.217-0.083-0.417-0.264-0.602-0.541c-0.24-0.362-0.369-0.74-0.386-1.133
c-0.016-0.393,0.083-0.718,0.296-0.975c0.161-0.195,0.479-0.535,0.95-1.021c0.354-0.364,0.719-0.772,1.094-1.224
c0.242-0.292,0.589-0.748,1.04-1.365c0.45-0.617,0.797-1.072,1.039-1.365c0.396-0.479,0.754-0.479,1.071-0.002
c0.077,0.116,0.237,0.373,0.479,0.767c0.162,0.264,0.461,0.724,0.897,1.381c0.14,0.214,0.21,0.32,0.212,0.318l0.503,0.683
c0.43,0.646,0.421,1.241-0.028,1.782c-0.419,0.506-0.812,0.484-1.177-0.065c-0.105-0.158-0.245-0.404-0.42-0.736
c-0.174-0.333-0.31-0.573-0.408-0.721c-0.176-0.264-0.321-0.393-0.437-0.387s-0.258,0.11-0.427,0.314l-0.792,0.957
c-0.235,0.283-0.355,0.5-0.362,0.65C77.961,59.892,78.06,60.12,78.263,60.425z"/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="93.0762" y1="57.7856" x2="83.5641" y2="48.2735">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#A6A6A6"/>
</linearGradient>
<path fill="url(#SVGID_6_)" d="M84.014,53.458l4.039,5.116l-4.175-8.685c-0.23-0.487-0.173-0.94,0.175-1.359
c0.259-0.312,0.45-0.495,0.574-0.549c0.211-0.102,0.427-0.028,0.647,0.224l5.836,6.679l-3.292-6.125
c-0.111-0.208-0.161-0.302-0.146-0.281c-0.078-0.116-0.153-0.159-0.227-0.129l-0.232,0.281c-0.126,0.152-0.299,0.184-0.519,0.093
c-0.22-0.09-0.425-0.278-0.616-0.565c-0.205-0.309-0.321-0.653-0.348-1.033c-0.026-0.38,0.048-0.677,0.226-0.89
c0.088-0.107,0.236-0.249,0.443-0.427s0.358-0.325,0.454-0.441c0.104-0.125,0.238-0.322,0.403-0.594
c0.165-0.271,0.295-0.464,0.392-0.58c0.191-0.231,0.419-0.319,0.683-0.263c0.263,0.056,0.5,0.244,0.712,0.562
c0.425,0.638,0.496,1.146,0.215,1.523c-0.082,0.118-0.122,0.218-0.119,0.302c0.002,0.083,0.059,0.239,0.171,0.467l4.167,8.761
c0.182,0.393,0.146,0.741-0.104,1.043c-0.074,0.089-0.189,0.216-0.346,0.38c-0.157,0.165-0.272,0.292-0.346,0.38
c-0.066,0.081-0.16,0.205-0.28,0.375c-0.12,0.169-0.213,0.294-0.279,0.374c-0.214,0.259-0.48,0.208-0.799-0.15l-3.796-4.331
l2.744,5.6c0.229,0.466,0.197,0.877-0.098,1.233c-0.052,0.062-0.091,0.103-0.118,0.123l-0.43,0.464
c-0.044,0.053-0.188,0.246-0.434,0.578c-0.032,0.051-0.078,0.113-0.137,0.184c-0.251,0.303-0.536,0.274-0.855-0.086l-5.881-6.507
c-0.198-0.219-0.338-0.289-0.419-0.21l-0.198,0.182c-0.117,0.104-0.271,0.108-0.46,0.012c-0.19-0.096-0.366-0.265-0.528-0.509
c-0.219-0.329-0.34-0.683-0.366-1.062c-0.025-0.379,0.058-0.686,0.25-0.917c0.097-0.116,0.252-0.268,0.467-0.456
c0.216-0.188,0.371-0.339,0.468-0.456c0.096-0.116,0.223-0.305,0.381-0.568c0.159-0.263,0.286-0.453,0.383-0.568
c0.191-0.232,0.425-0.312,0.699-0.241c0.273,0.072,0.523,0.277,0.749,0.617c0.417,0.627,0.465,1.152,0.145,1.577
c-0.163,0.217-0.178,0.426-0.044,0.627C83.872,53.275,83.929,53.351,84.014,53.458z"/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="99.1309" y1="50.4277" x2="89.7223" y2="41.0192">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#A6A6A6"/>
</linearGradient>
<path fill="url(#SVGID_7_)" d="M90.514,40.441c0.468-0.564,1.045-0.823,1.732-0.775c-0.197-0.516-0.146-0.954,0.151-1.312
c0.423-0.51,0.821-0.484,1.194,0.078c0.1,0.148,0.219,0.349,0.359,0.6c0.21,0.377,0.344,0.608,0.4,0.693
c0.084,0.127,0.215,0.304,0.392,0.53c0.177,0.227,0.308,0.403,0.393,0.53c0.359,0.541,0.323,1.073-0.109,1.595
c-0.396,0.477-0.786,0.507-1.171,0.089c-0.386-0.418-0.693-0.649-0.925-0.693c-0.23-0.044-0.47,0.082-0.716,0.379
c-0.187,0.225-0.286,0.494-0.301,0.807c-0.014,0.312,0.067,0.601,0.243,0.866c0.219,0.329,0.442,0.489,0.671,0.48
s0.615-0.199,1.16-0.57c1.692-1.145,3.116-0.849,4.271,0.889c0.662,0.996,1.014,2.075,1.055,3.237
c0.041,1.163-0.237,2.104-0.835,2.825c-0.517,0.624-1.154,0.985-1.912,1.085c0.218,0.527,0.179,0.969-0.116,1.325
c-0.428,0.517-0.854,0.457-1.276-0.18c-0.099-0.148-0.251-0.403-0.458-0.766c-0.143-0.248-0.273-0.463-0.394-0.643
c-0.091-0.138-0.233-0.33-0.425-0.576c-0.192-0.246-0.334-0.438-0.426-0.576c-0.366-0.551-0.292-1.137,0.223-1.758
c0.419-0.505,0.834-0.488,1.245,0.051c0.677,0.878,1.271,1.009,1.78,0.394c0.229-0.276,0.354-0.617,0.371-1.02
c0.019-0.404-0.078-0.765-0.289-1.083c-0.219-0.329-0.475-0.492-0.768-0.491c-0.294,0.001-0.712,0.177-1.256,0.527
c-1.152,0.722-2.122,0.843-2.91,0.361c-0.451-0.276-0.853-0.679-1.205-1.208c-0.619-0.933-0.944-1.939-0.974-3.02
C89.66,42.03,89.935,41.14,90.514,40.441z"/>
</g>
</g>
<g id="Layer_31">
<g opacity="0.7">
<image overflow="visible" width="110" height="128" xlink:href="data:image/png;base64,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" transform="matrix(1 0 0 1 17 -10)">
</image>
</g>
</g>
<g id="Layer_14">
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="46.6719" y1="73.4258" x2="57.2211" y2="55.154">
<stop offset="0.0056" style="stop-color:#FEFFE0"/>
<stop offset="0.2289" style="stop-color:#D4AE7F"/>
<stop offset="0.3596" style="stop-color:#BD824B"/>
<stop offset="1" style="stop-color:#CC6635"/>
</linearGradient>
<path fill="url(#SVGID_8_)" d="M58.04,79.033c0,0,5.932-7.807,7.494-10.773c1.562-2.966-11.709-4.371-14.832-8.742
c-3.123-4.372-4.528-18.11-7.182-6.401C40.866,64.826,52.731,79.813,58.04,79.033z"/>
</g>
<g id="Lower_face">
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="54.7202" y1="66.3311" x2="60.0005" y2="46.6248">
<stop offset="0.0056" style="stop-color:#FEFFE0"/>
<stop offset="0.8427" style="stop-color:#BD824B"/>
<stop offset="1" style="stop-color:#CC6635"/>
</linearGradient>
<path fill="url(#SVGID_9_)" d="M42.115,52.023c0,0,8.118,16.236,22.794,16.394c3.594,0.038,13.583-14.52,12.958-14.988
c-0.624-0.469-21.233,0.468-24.043-3.591c-2.81-4.06-12.333-10.46-12.646-6.558C40.866,47.184,42.115,52.023,42.115,52.023z"/>
</g>
<g id="Eye_mask">
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="69.2012" y1="16.2441" x2="61.5447" y2="59.6661">
<stop offset="0.0056" style="stop-color:#FEFFE0"/>
<stop offset="0.3705" style="stop-color:#FDFCDE"/>
<stop offset="0.6525" style="stop-color:#F8F2D8"/>
<stop offset="0.9059" style="stop-color:#EFE2CE"/>
<stop offset="1" style="stop-color:#EBDAC9"/>
</linearGradient>
<path fill="url(#SVGID_10_)" d="M79.486,18.961c-5.115-5.116-24.79,3.148-30.299,5.115c-5.509,1.968-7.87,16.527-4.05,23.995
c1.985,3.88,3.852,6.702,6.234,8.521c0.01,0.008,0.019,0.018,0.03,0.026c0.006,0.004,0.014,0.008,0.021,0.012
c2.193,1.656,4.039,2.271,7.603,2.271c1.826,0,3.401-1.245,5.116-1.771c0.244,0.366,1.377,2.951,3.148,2.755
c4.797-0.533,7.855-6.951,9.444-8.264c1.323-1.094,2.754,0.787,2.754,0.787c7.711-6.466,8.526-16.002,8.526-16.002
C88.013,34.57,84.602,24.076,79.486,18.961z"/>
</g>
<g id="Eye_bottom_shadow">
<radialGradient id="SVGID_11_" cx="74.4434" cy="42.3691" r="5.4414" gradientTransform="matrix(0.858 0.1654 -0.1893 0.9819 12.2848 -12.2312)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#BD824B"/>
<stop offset="0.3374" style="stop-color:#BE844E"/>
<stop offset="0.4955" style="stop-color:#C18A55"/>
<stop offset="0.6161" style="stop-color:#C79562"/>
<stop offset="0.7178" style="stop-color:#CFA474"/>
<stop offset="0.8076" style="stop-color:#D9B88C"/>
<stop offset="0.889" style="stop-color:#E6D1A9"/>
<stop offset="0.9625" style="stop-color:#F5EECB"/>
<stop offset="1" style="stop-color:#FEFFE0"/>
</radialGradient>
<path fill="url(#SVGID_11_)" d="M72.805,42.583c-0.569,2.951-3.121,4.939-5.699,4.443c-2.578-0.497-4.207-3.292-3.638-6.243
s3.121-4.94,5.699-4.443S73.373,39.632,72.805,42.583z"/>
</g>
<g id="Eye_top_shadow">
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="65.3203" y1="43.9844" x2="65.3203" y2="28.0732">
<stop offset="0.0056" style="stop-color:#FEFFE0"/>
<stop offset="1" style="stop-color:#BD824B"/>
</linearGradient>
<path fill="url(#SVGID_12_)" d="M71.818,43.534c0,0,5.872,0.973,6.187-1.547c0.258-2.062,0.475-11.835-9.667-13.713
c-7.083-1.312-13.248,3.935-15.759,12.425C51.844,43.183,70.271,44.823,71.818,43.534z"/>
</g>
<g id="Layer_29">
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="80.8516" y1="64.4702" x2="80.8516" y2="51.8232" gradientTransform="matrix(0.6329 0.2079 -0.2919 0.8884 47.8804 -19.6344)">
<stop offset="0.0056" style="stop-color:#FEFFE0"/>
<stop offset="1" style="stop-color:#CDA178"/>
</linearGradient>
<path fill="url(#SVGID_13_)" d="M80.108,50.405c0,0,2.616-4.186,4.493-6.064c1.968-1.967,1.378,0.984-3.627,7.026
C75.855,57.548,80.108,50.405,80.108,50.405z"/>
</g>
<g id="Eye">
<radialGradient id="SVGID_14_" cx="78.7246" cy="-33.2397" r="4.6543" gradientTransform="matrix(-1 0 0 -1 146.9961 7.6973)" gradientUnits="userSpaceOnUse">
<stop offset="0.0056" style="stop-color:#521B00"/>
<stop offset="0.1822" style="stop-color:#541E02"/>
<stop offset="0.3093" style="stop-color:#5D2708"/>
<stop offset="0.421" style="stop-color:#6B3713"/>
<stop offset="0.5238" style="stop-color:#804D21"/>
<stop offset="0.6205" style="stop-color:#9A6A34"/>
<stop offset="0.7126" style="stop-color:#BB8E4C"/>
<stop offset="0.7995" style="stop-color:#E1B767"/>
<stop offset="0.8595" style="stop-color:#FFD87D"/>
<stop offset="1" style="stop-color:#521B00"/>
</radialGradient>
<circle fill="url(#SVGID_14_)" cx="68.271" cy="40.937" r="4.654"/>
</g>
<g id="Layer_26">
<circle cx="68.271" cy="40.937" r="2.664"/>
</g>
<g id="Eye_glare">
<radialGradient id="SVGID_15_" cx="67.9922" cy="40.502" r="1.6831" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.225" style="stop-color:#BBBBBB"/>
<stop offset="0.5063" style="stop-color:#6C6C6C"/>
<stop offset="0.7384" style="stop-color:#313131"/>
<stop offset="0.909" style="stop-color:#0E0E0E"/>
<stop offset="1" style="stop-color:#000000"/>
</radialGradient>
<circle fill="url(#SVGID_15_)" cx="67.992" cy="40.502" r="1.683"/>
</g>
<g id="Beak">
<linearGradient id="SVGID_16_" gradientUnits="userSpaceOnUse" x1="71.5938" y1="59.001" x2="79.6533" y2="59.001">
<stop offset="0" style="stop-color:#CC3300"/>
<stop offset="0.0203" style="stop-color:#CD3703"/>
<stop offset="0.3676" style="stop-color:#E27C37"/>
<stop offset="0.658" style="stop-color:#F2AE5D"/>
<stop offset="0.8773" style="stop-color:#FBCC74"/>
<stop offset="1" style="stop-color:#FFD87D"/>
</linearGradient>
<path fill="url(#SVGID_16_)" d="M76.618,50.931c-2.714,1.034-5.152,4.684-4.84,10.616c0.354,6.721-1.249,6.558,1.249,4.84
c2.498-1.717,6.245-6.713,6.558-11.553C79.745,52.336,79.896,49.682,76.618,50.931z"/>
</g>
<g id="Layer_27">
<linearGradient id="SVGID_17_" gradientUnits="userSpaceOnUse" x1="71.5527" y1="60.5566" x2="73.5596" y2="60.5566">
<stop offset="0" style="stop-color:#CC3300"/>
<stop offset="0.0203" style="stop-color:#CD3703"/>
<stop offset="0.3676" style="stop-color:#E27C37"/>
<stop offset="0.658" style="stop-color:#F2AE5D"/>
<stop offset="0.8773" style="stop-color:#FBCC74"/>
<stop offset="1" style="stop-color:#FFD87D"/>
</linearGradient>
<path fill="url(#SVGID_17_)" d="M73.406,53.776c0,0-0.811,5.563,0,7.881c0.812,2.318-1.854,5.68-1.854,5.68
s0.695-4.637,0.231-7.187S73.406,53.776,73.406,53.776z"/>
</g>
<g id="Layer_28">
<path fill="#CC6635" d="M78.026,52.366c0,0-0.812-0.113-0.926,0.7c-0.114,0.813,0.877,2.03,0.877,2.03S78.672,54.28,78.026,52.366z
"/>
</g>
<g id="body__x0026__wing">
<radialGradient id="SVGID_18_" cx="64.9922" cy="63.9526" r="57.9235" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#CC6635"/>
<stop offset="0.1858" style="stop-color:#C86433"/>
<stop offset="0.366" style="stop-color:#BC5D2E"/>
<stop offset="0.544" style="stop-color:#A95126"/>
<stop offset="0.7206" style="stop-color:#8E401A"/>
<stop offset="0.8946" style="stop-color:#6B2A0B"/>
<stop offset="1" style="stop-color:#521B00"/>
</radialGradient>
<path fill="url(#SVGID_18_)" d="M88.013,36.406c0,0,2.894-21.287-22.562-27.02c-3.026-0.682-6.033-0.525-9.968-0.525
c-3.935,0-15.215-3.148-15.215-3.148s-2.624,0.918,0,3.542c2.623,2.624,2.623,2.624,2.623,2.624s-18.101,3.41-27.02,28.201
c0,0-15.125,18.02-4.984,45.908c8.395,23.086,26.889,34.104,39.219,35.939c4.972,0.741,8.526,0,10.1-3.017
c0.304-0.581,11.135,3.95,23.348,0.656c13.616-3.673,19.15-9.183,20.986-15.216c0.077-0.251,13.521-9.533,14.953-20.986
c0.787-6.296-1.049-8.395-1.181-8.395c-1.669,0,9.704-7.18,0.918-28.594c-4.197-10.231-4.197-3.148-4.197-1.836
s-1.574,38.825-40.924,38.825c-27.807,0-33.429-30.623-25.184-48.269c3.043-6.513,12.066-18.113,27.656-9.742
c7.923,4.254,5.528,14.333,6.972,15.775C84.995,42.571,86.045,38.373,88.013,36.406z"/>
</g>
<g id="Layer_25">
<radialGradient id="SVGID_19_" cx="62.7383" cy="77.7598" r="42.5085" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#CC6635"/>
<stop offset="0.687" style="stop-color:#793311"/>
<stop offset="1" style="stop-color:#521B00"/>
</radialGradient>
<path fill="url(#SVGID_19_)" d="M104.729,103.858c0,0-44.367,17.109-67.179-20.768c-12.134-20.148-6.095-34.526-4.499-38.636
c1.786-4.598,3.671-8.602,0.708-9.597c-3.472-1.166-9.051,6.413-11.877,22.902c-2.714,15.833-2.299,34.43,21.41,52.472
c16.126,12.271,35.321,11.012,42.873,9.832S102.842,112.119,104.729,103.858z"/>
</g>
<g id="Layer_24_copy">
<radialGradient id="SVGID_20_" cx="79.5625" cy="73.2637" r="38.6942" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#CC6635"/>
<stop offset="0.687" style="stop-color:#793311"/>
<stop offset="1" style="stop-color:#521B00"/>
</radialGradient>
<path fill="url(#SVGID_20_)" d="M120.584,47.546c-3.465-12.203-6.06-9.168-6.538,2.381c0,0,0.1,27.572-23.541,33.961
c-18.43,4.981-30.962,0.415-38.409-5.967c-3.487-2.989-8.165-9.597-11.304-15.02c-1.44-2.489-5.348-2.25-4.28,3.009
c1.788,8.796,6.116,30.308,33.243,38.263c17.232,5.054,32.901,1.651,35.046-0.348c2.144-1.999,15.927-9.139,15.035-25.263
c-0.109-1.963-0.939-4.229-0.959-4.531c1.349-1.817,2.132-3.246,2.407-3.865C122.476,67.487,124.292,60.604,120.584,47.546z"/>
</g>
<g id="Layer_5">
<linearGradient id="SVGID_21_" gradientUnits="userSpaceOnUse" x1="37.4956" y1="118.875" x2="37.4956" y2="26.5483">
<stop offset="0" style="stop-color:#CC6635"/>
<stop offset="0.1038" style="stop-color:#C35D2C"/>
<stop offset="0.4366" style="stop-color:#AC4614"/>
<stop offset="0.7442" style="stop-color:#9E3805"/>
<stop offset="1" style="stop-color:#993300"/>
</linearGradient>
<path fill="url(#SVGID_21_)" d="M27.633,27.14c-4.395,3.102-24.422,31.453-4.136,64.109c10.599,17.062,30.437,26.331,36.9,27.624
C61.69,119.132,4.894,97.85,26.6,40.841C33.695,22.205,27.633,27.14,27.633,27.14z"/>
</g>
<g id="Layer_7_copy">
<linearGradient id="SVGID_22_" gradientUnits="userSpaceOnUse" x1="59.188" y1="83.2822" x2="110.0979" y2="69.034" gradientTransform="matrix(0.8468 -0.5319 0.5319 0.8468 -22.7171 63.6917)">
<stop offset="0" style="stop-color:#CC6635"/>
<stop offset="0.4362" style="stop-color:#B85220"/>
<stop offset="1" style="stop-color:#993300"/>
</linearGradient>
<path fill="url(#SVGID_22_)" d="M63.085,88.653c7.375,3.103,20.954,5.194,30.91,3.065c13.677-2.924,19.84-11.318,24.902-17.541
c0,0-13.44,33.64-52.153,21.456c-1.126-0.354-3.446-1.096-5.325-2.349C57.255,90.509,60.319,87.49,63.085,88.653z"/>
</g>
<g id="Layer_6">
<linearGradient id="SVGID_23_" gradientUnits="userSpaceOnUse" x1="39.8994" y1="91.4883" x2="82.8093" y2="66.7142">
<stop offset="0" style="stop-color:#CC6635"/>
<stop offset="0.4362" style="stop-color:#B85220"/>
<stop offset="1" style="stop-color:#993300"/>
</linearGradient>
<path fill="url(#SVGID_23_)" d="M104.539,104.35c0,0-28.837,15.085-58.886-8.986C21.192,75.769,30.276,43.621,35.111,44.388
c3.068,0.487,1.652,9.44,1.298,13.924c-1.268,16.071,8.191,36.344,32.528,45.232C82.074,108.343,96.941,106.927,104.539,104.35z"/>
</g>
<g id="below_tuft">
<linearGradient id="SVGID_24_" gradientUnits="userSpaceOnUse" x1="46.9287" y1="32.918" x2="46.9287" y2="11.8779">
<stop offset="0" style="stop-color:#CC6635"/>
<stop offset="0.1038" style="stop-color:#C35D2C"/>
<stop offset="0.4366" style="stop-color:#AC4614"/>
<stop offset="0.7442" style="stop-color:#9E3805"/>
<stop offset="1" style="stop-color:#993300"/>
</linearGradient>
<path fill="url(#SVGID_24_)" d="M42.891,11.878c0,0,4.206,3.87,10.756,3.542c5.164-0.26,4.372,2.75,1.049,3.41
c-5.555,1.103-11.543,6.034-15.215,12.067c-2.428,3.99-3.282,1.171-2.886-0.787c0.829-4.098,2.099-6.558,3.935-9.182
c1.383-1.976,4.591-6.165,0.525-4.459c-2.743,1.15-2.739,0.303-1.968-1.049C39.642,14.447,40.53,13.058,42.891,11.878z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xml:space="preserve" viewBox="0 0 200 200" width="200px" height="200px" x="0px" y="0px" enable-background="new 0 0 200 200">
<linearGradient id="SVGID_right_" y2="1.279e-13" gradientUnits="userSpaceOnUse" x2="-1073.2" gradientTransform="translate(1196.604,37.368977)" y1="126.85" x1="-1073.2">
<stop stop-color="#1b3967" offset=".011" />
<stop stop-color="#13b5ea" offset=".467" />
<stop stop-color="#002b5c" offset=".9945" />
</linearGradient>
<linearGradient id="SVGID_left_" y2="1.279e-13" gradientUnits="userSpaceOnUse" x2="-1073.2" gradientTransform="matrix(-1,0,0,1,-994.78801,37.367977)" y1="126.85" x1="-1073.2">
<stop stop-color="#1b3967" offset=".011" />
<stop stop-color="#13b5ea" offset=".467" />
<stop stop-color="#002b5c" offset=".9945" />
</linearGradient>
<path d="m 151.80512,51.557978 c 0.077,1.313 -1.787,0.968 -1.787,2.293 0,38.551002 -46.558,97.366012 -91.687985,108.730012 v 1.639 C 118.28313,158.69999 186.89012,96.41998 188.40012,37.369977 l -36.599,14.189001 z" style="fill:url(#SVGID_right_)" />
<path d="m 133.67312,56.300978 c 0.076,1.313 0.12,2.63 0.12,3.957 0,38.551002 -30.69898,90.497012 -75.826985,101.860012 v 1.639 c 59.044005,-2.79 105.809995,-63.02401 105.809995,-109.200012 0,-2.375 -0.128,-4.729 -0.371,-7.056 l -29.73,8.798 z" style="fill:#e96d1f" />
<path d="m 163.69112,46.951978 -7.61699,2.722 c 0.041,0.962 0.066,2.254 0.066,3.225 0,41.219002 -37.271,98.204012 -87.271995,107.120012 -3.24501,1.088 -7.53801,2.077 -10.932,2.931 v 1.638 C 123.19013,159.02799 169.03613,92.72198 163.69612,46.947978 Z" style="fill:#d9541e" />
<path d="m 50.011,51.556978 c -0.077,1.313 1.787,0.968 1.787,2.293 0,38.551002 46.558007,97.366012 91.68799,108.730012 v 1.639 C 83.533,158.69899 14.926,96.41898 13.416,37.368977 l 36.599,14.189001 z" style="fill:url(#SVGID_left_)" />
<path d="m 68.143,56.299978 c -0.076,1.313 -0.12,2.63 -0.12,3.957 0,38.551002 30.698995,90.497012 75.82699,101.860012 v 1.639 C 84.806,160.96599 38.04,100.73198 38.04,54.555978 c 0,-2.375 0.128,-4.729 0.371,-7.056 l 29.73,8.798 z" style="fill:#a0ce67" />
<path d="m 38.125,46.950978 7.617,2.722 c -0.041,0.962 -0.066,2.254 -0.066,3.225 0,41.219002 37.271,98.204012 87.27199,107.120012 3.245,1.088 7.538,2.077 10.932,2.931 v 1.638 C 78.626,159.02699 32.78,92.72098 38.12,46.946978 Z" style="fill:#439639" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1 @@
This directory caches lists of PubSub nodes.

View file

@ -0,0 +1,8 @@
// Convert ISO8601 To UTC
window.onload = function(){
for (element of document.querySelectorAll('#articles > ul > li > div > h4')) {
timestamp = new Date(element.textContent);
element.textContent = timestamp.toUTCString();
}
}

6
rivista/assets/script/marked.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,7 @@
// Parse Markdown
window.onload = function(){
for (element of document.querySelectorAll('#articles > ul > li > div > p')) {
element.innerHTML = marked.parse(element.textContent);
}
}

View file

@ -0,0 +1,265 @@
window.onload = async function(){
let locationHref = new URL(location.href);
let node = locationHref.searchParams.get('node')
let pubsub = locationHref.searchParams.get('pubsub')
// Set button follow
let follow = document.querySelector('#follow');
if (follow) {
//let feedUrl = location.href.replace(/^https?:/, 'feed:');
let feedUrl = `feed://${location.host}/atom?pubsub=${pubsub}&node=${node}`;
follow.href = feedUrl;
follow.type = `application/atom+xml`;
follow.addEventListener ('click', function() {
window.open(feedUrl, "_self");
});
// Fix button subtome
document.querySelector('#subtome').href='https://www.subtome.com/#/subscribe?feeds=' + feedUrl;
}
// Convert ISO8601 To UTC
for (let element of document.querySelectorAll(
'#articles > ul > li > div > h4.published,' +
'#articles > ul > li > div > h4.updated, ' +
'#feed > #header > h2#subtitle.date')) {
let timeStamp = new Date(element.textContent);
element.textContent = timeStamp.toUTCString();
}
// Parse Markdown
for (let element of document.querySelectorAll('#articles div[type="text"]')) {
element.innerHTML = marked.parse(element.textContent);
}
// NOTE Report this issue to Movim. See node "deltachat" of pubsub "news.movim.eu".
for (let element of document.querySelectorAll('#articles div[type="html"]')) {
if (!element.children.length) {
element.innerHTML = marked.parse(element.textContent);
}
}
/*
NOTE
The reason for the following code to parse HTML inside an software which
already parses HTML, is that some people who influence the so called Gecko
HTML Engine product (mostly people from the advertisement industry with whom
I shamefully used to work with) have intentions to eliminate standards and
technologies such as Syndication (Atom/RDF/RSS), XSLT and many other
technologies that actually empower people and their privacy.
Recently, some changes were made to the XSLT parser of Gecko which result in
noncompliance with the XSLT standard.
The XSLT feature that was removed is "disable-output-escaping" which upon the
value "yes" the XSLT engine should transform and treat a subject string into
HTML, yet the Gecko HTML Engine ignores this XSLT direction.
This change was probably made in order to:
* Frustrate new XSLT developers; or
* Influence new XSLT developers to think that XSLT has a limited set of
features and believing of some sort of inability to parse HTML from a
retrieved HTML string; and
* Consequently cause developers to abstain from using the XSLT technology.
Do not use HTML browsers or use Ladybird, Pale Moon or browsers that are
powered by KHTML (WebKit) instead of anti-privacy software such as Chromium
and Gecko.
*/
// Parse HTML
//if (navigator.userAgent.includes(') Gecko/')) {
// for (let element of document.querySelectorAll('#articles div[type="html"]')) {
// element.innerHTML = element.textContent;
// }
//}
for (let element of document.querySelectorAll('#articles div[type="html"]')) {
if (!element.children.length) {
element.innerHTML = element.textContent;
}
}
// Build a journal list
if (locationHref.pathname.startsWith('/atom') && pubsub && node && !node.includes('/')) {
itemsList = await openJson(pubsub, node)
if (itemsList && locationHref.searchParams.get('item')) {
let elementDiv = document.createElement('div');
elementDiv.id = 'journal';
let elementH3 = document.createElement('h3');
elementH3.textContent = 'Journal';
elementDiv.appendChild(elementH3);
let elementH4 = document.createElement('h4');
elementH4.textContent = node;
elementDiv.appendChild(elementH4);
let elementUl = document.createElement('ol');
elementDiv.appendChild(elementUl);
for (let item of itemsList.reverse()) {
let elementLi = document.createElement('li');
let elementA = document.createElement('a');
elementA.textContent = item.title;
elementA.href = item.link;
elementLi.appendChild(elementA);
elementUl.appendChild(elementLi);
console.log(elementLi.length)
if (elementUl.children.length > 9) {break};
}
let elementB = document.createElement('b');
elementB.textContent = 'Actions';
elementDiv.appendChild(elementB);
let elementUl2 = document.createElement('ul');
elementDiv.appendChild(elementUl2);
links = [
{'text' : 'Subscribe from an XMPP client.',
'href' : `xmpp:${pubsub}?pubsub;action=subscribe;node=${node}`,
'type' : 'x-scheme-handler/xmpp'},
{'text' : 'Subscribe with a News Reader.',
'href' : `feed://${location.host}/atom?pubsub=${pubsub}&node=${node}`,
'type' : 'application/atom+xml'},
{'text' : 'Browse the journal.',
'href' : `atom?pubsub=${pubsub}&node=${node}`,
'type' : 'application/atom+xml'},
{'text' : 'Browse the portal.',
'href' : `opml?pubsub=${pubsub}`,
'type' : 'text/x-opml'}
]
for (let link of links) {
let elementLi = document.createElement('li');
let elementA = document.createElement('a');
elementA.textContent = link.text;
elementA.href = link.href;
elementA.type = link.type;
elementLi.appendChild(elementA);
elementUl2.appendChild(elementLi);
}
elementDiv.appendChild(elementUl2);
// document.querySelector('#feed').appendChild(elementDiv); // This would result in a combination of Title, Article, and Journal
document.querySelector('#articles').appendChild(elementDiv);
}
}
// Convert URI xmpp: to URI http: links.
for (let xmppLink of document.querySelectorAll(
'#articles h3 > a[href^="xmpp:"][id^="rivista-"],' +
'#articles h5.related > a[class^="rivista-"],' +
'#journal > ol > li > a[href^="xmpp:"]')) {
xmppUri = new URL(xmppLink);
let parameters = xmppUri.search.split(';');
try {
try {
let node = parameters.find(parameter => parameter.startsWith('node=')).split('=')[1];
let item = parameters.find(parameter => parameter.startsWith('item=')).split('=')[1];
let pubsub = xmppUri.pathname;
xmppLink.href = `atom?pubsub=${pubsub}&node=${node}&item=${item}`
} catch {
let node = parameters.find(parameter => parameter.startsWith('node=')).split('=')[1];
let pubsub = xmppUri.pathname;
xmppLink.href = `atom?pubsub=${pubsub}&node=${node}`
}
} catch (err) {
console.warn(err)
}
}
// Display a selection of suggested software.
const selection = {
'akregator' : {
'name' : 'Akregator',
'image' : 'akregator.svg',
'url' : 'https://apps.kde.org/akregator/'
},
'leechcraft' : {
'name' : 'LeechCraft',
'image' : 'leechcraft.png',
'url' : 'https://leechcraft.org/'
},
'liferea' : {
'name' : 'Liferea',
'image' : 'liferea.svg',
'url' : 'https://lzone.de/liferea/'
},
'raven' : {
'name' : 'Raven Reader',
'image' : 'raven.svg',
'url' : 'https://ravenreader.app/'
},
'rssguard' : {
'name' : 'RSS Guard',
'image' : 'rssguard.png',
'url' : 'https://github.com/martinrotter/rssguard'
},
'rssowl' : {
'name' : 'RSSOwl',
'image' : 'rssowl.svg',
'url' : 'http://www.rssowl.org/'
},
'tickr' : {
'name' : 'TICKR',
'image' : 'tickr.png',
'url' : 'https://www.open-tickr.net/'
}
}
let selectionLink = document.querySelector('#selection-link');
selectionLink.addEventListener ('click', function() {
let elementDiv = document.createElement('div');
elementDiv.id = 'selection-page';
let elementH1 = document.createElement('h1');
elementH1.textContent = 'Select A News Reader';
elementDiv.appendChild(elementH1);
let elementH2 = document.createElement('h2');
elementH2.textContent = 'Install A Feed Reader For Desktop And Mobile';
elementDiv.appendChild(elementH2);
const brands = Object.keys(selection);
let elementDivSel = document.createElement('div');
elementDivSel.id = 'selection';
for (let i = 0; i < brands.length; i++) {
let brand = brands[i];
let elementSpan = document.createElement('span');
let elementA = document.createElement('a');
elementA.href = selection[brand].url;
elementA.textContent = selection[brand].name;
let elementImg = document.createElement('img');
elementImg.src = 'graphic/' + selection[brand].image;
elementSpan.appendChild(elementImg);
elementSpan.appendChild(elementA);
elementDivSel.appendChild(elementSpan);
elementDiv.appendChild(elementDivSel);
}
let elementP1 = document.createElement('p');
elementP1.textContent = '' +
'This is a selection of desktop, mobile and HTML (sometimes referred to ' +
'as "online") News Readers for you to choose from.';
elementDiv.appendChild(elementP1);
let elementP2 = document.createElement('p');
elementP2.textContent = '' +
'This selection includes: Podcast Managers, Torrent ' +
'Clients, Chat Bots, HTML Browsers and Plugins which support ' +
'syndication feeds.';
elementDiv.appendChild(elementP2);
let elementSpan = document.createElement('span');
elementSpan.id = 'return';
elementSpan.textContent = 'Return';
elementSpan.addEventListener ('click', function() {
document.querySelector('#selection-page').remove();
});
elementDiv.appendChild(elementSpan);
document.body.appendChild(elementDiv);
});
}
async function openJson(pubsubJid, nodeId) {
return fetch(`/data/${pubsubJid}/${nodeId}.json`)
.then(response => {
if (!response.ok) {
throw new Error('HTTP Error: ' + response.status);
}
return response.json();
})
.then(json => {
return json;
})
.catch(err => {
console.warn(err);
})
}

View file

@ -0,0 +1,15 @@
# An account to connect XMPP Journal Publisher to the XMPP network.
[account]
xmpp = "" # Jabber ID.
pass = "" # Password.
# A default node, when no arguments are set.
[default]
pubsub = "pubsub.woodpeckersnest.space" # Jabber ID.
nodeid = "PlanetJabber" # Node ID.
# Settings
[settings]
service = 1 # Enable server as a service.
include = "" # Limit service to a given domain.
operator = "" # A Jabber ID to contact with, in case of an error.

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2016 - 2024 Schimon Jehuda. Released under MIT license
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
include https://schimon.i2p/ in attribute name='generator' of
element <meta/> inside of html element </head>
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding = 'UTF-8'
indent = 'yes'
media-type = 'application/atom+xml'
method = 'html'
version = '4.01' />
<!-- Atom Syndication Format 1.0 -->
<xsl:include href='atom_as_xhtml.xsl'/>
<!-- extract filename from given url string -->
<xsl:include href='extract-filename.xsl'/>
<!-- set page metadata -->
<xsl:include href='metadata.xsl'/>
<!-- transform filesize from given length string -->
<xsl:include href='transform-filesize.xsl'/>
</xsl:stylesheet>

View file

@ -0,0 +1,531 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2016 - 2024 Schimon Jehuda. Released under MIT license
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
include https://schimon.i2p/ in attribute name='generator' of
element <meta/> inside of html element </head>
-->
<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:xml='http://www.w3.org/XML/1998/namespace'
xmlns:media='http://search.yahoo.com/mrss/'
xmlns:georss='http://www.georss.org/georss'
xmlns:geo='http://www.w3.org/2003/01/geo/wgs84_pos#'
xmlns:atom10='http://www.w3.org/2005/Atom'
xmlns:atom='http://www.w3.org/2005/Atom'>
<xsl:template match='/atom:feed'>
<!-- index right-to-left language codes -->
<!-- TODO http://www.w3.org/TR/xpath/#function-lang -->
<xsl:variable name='rtl'
select='@xml:lang[
contains(self::node(),"ar") or
contains(self::node(),"fa") or
contains(self::node(),"he") or
contains(self::node(),"ji") or
contains(self::node(),"ku") or
contains(self::node(),"ur") or
contains(self::node(),"yi")]'/>
<html>
<head>
<xsl:call-template name='metadata'>
<xsl:with-param name='name' select='"description"' />
<xsl:with-param name='content' select='atom:subtitle' />
</xsl:call-template>
<xsl:call-template name='metadata'>
<xsl:with-param name='name' select='"generator"' />
<xsl:with-param name='content' select='Rivista' />
</xsl:call-template>
<xsl:call-template name='metadata'>
<xsl:with-param name='name' select='"mimetype"' />
<xsl:with-param name='content' select='"application/atom+xml"' />
</xsl:call-template>
<title>
<xsl:choose>
<xsl:when test='atom:title and not(atom:title="") and count(atom:entry) &gt; 1'>
<xsl:value-of select='atom:title'/>
</xsl:when>
<xsl:when test='atom:entry'>
<xsl:value-of select='atom:entry/atom:title'/>
</xsl:when>
<xsl:otherwise>Rivista</xsl:otherwise>
</xsl:choose>
</title>
<!-- TODO media='print' -->
<link rel='stylesheet' type='text/css' media='screen' href='/css/stylesheet.css'/>
<link rel='icon' type='image/svg+xml' href='/graphic/xmpp.svg'/>
<!-- whether language code is of direction right-to-left -->
<xsl:if test='$rtl'>
<link id='semitic' href='/css/stylesheet-rtl.css' rel='stylesheet' type='text/css' />
</xsl:if>
<script type='text/javascript' src='/script/marked.min.js'/>
<script type='text/javascript' src='/script/postprocess.js'/>
</head>
<body>
<div id='actions'>
<a id='follow' title='Subscribe the latest updates and news.'
onclick='window.open(location.href.replace(/^https?:/, "feed:"), "_self")'>
<!-- xsl:attribute name="href">
feed:<xsl:value-of select="atom:link[@rel='self']/@href" />
</xsl:attribute -->
Follow
</a>
<a id='subtome' title='Subscribe via SubToMe.'>
<xsl:attribute name='href'>
javascript:location.href='https://www.subtome.com/#/subscribe?feeds='+location.href;
</xsl:attribute>
<xsl:attribute name='onclick'>
(
function(btn){
var z=document.createElement('script');
document.subtomeBtn=btn;
z.src='https://www.subtome.com/load.js';document.body.appendChild(z);
}
)(this);
return false;
</xsl:attribute>
SubToMe
</a>
<a href='https://xmpp.org/about/technology-overview/'
title='Of the benefits of XMPP.'>
XMPP
</a>
<a href='https://join.jabber.network/#syndication@conference.movim.eu?join'
title='Syndictaion and PubSub.'>
Groupchat
</a>
<a href='https://aboutfeeds.com/'
title='Of the benefits of syndication feed.'
id='aboutfeeds'>
Help
</a>
</div>
<div id='feed'>
<div id='header'>
<!-- feed title -->
<h1 id='title'>
<xsl:choose>
<xsl:when test='atom:title and not(atom:title="") and count(atom:entry) &gt; 1'>
<xsl:value-of select='atom:title'/>
</xsl:when>
<xsl:when test='atom:entry'>
<xsl:value-of select='atom:entry/atom:title'/>
</xsl:when>
<xsl:otherwise>
No title
</xsl:otherwise>
</xsl:choose>
</h1>
<!-- feed subtitle -->
<h2 id='subtitle'>
<xsl:choose>
<xsl:when test='atom:title and not(atom:title="") and count(atom:entry) &gt; 1'>
<xsl:value-of select='atom:subtitle'/>
</xsl:when>
<xsl:when test='atom:entry'>
<xsl:attribute name='class'><xsl:text>date</xsl:text></xsl:attribute>
<xsl:value-of select='atom:entry/atom:updated'/>
</xsl:when>
<xsl:when test='atom:entry'>
<xsl:attribute name='class'><xsl:text>date</xsl:text></xsl:attribute>
<xsl:value-of select='atom:entry/atom:published'/>
</xsl:when>
<xsl:otherwise>
Rivista XMPP Journal Publisher
</xsl:otherwise>
</xsl:choose>
</h2>
</div>
<xsl:if test='count(atom:entry) &gt; 1'>
<div id='menu'>
<h3>Latest Posts</h3>
<!-- xsl:for-each select='atom:entry[position() &lt;21]' -->
<ol>
<xsl:for-each select='atom:entry[not(position() &gt; 20)]'>
<li>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:text>#rivista-</xsl:text>
<xsl:value-of select='position()'/>
</xsl:attribute>
<xsl:choose>
<xsl:when test='string-length(atom:title) &gt; 0'>
<xsl:value-of select='atom:title'/>
</xsl:when>
<xsl:otherwise>
*** No Title ***
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</li>
</xsl:for-each>
</ol>
</div>
</xsl:if>
<div id='articles'>
<!-- feed entry -->
<xsl:choose>
<xsl:when test='atom:entry'>
<ul>
<xsl:for-each select='atom:entry[not(position() >20)]'>
<li>
<div class='entry'>
<!-- entry title -->
<h3 class='title'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:choose>
<xsl:when test='atom:link[@rel="self"]'>
<xsl:value-of select='atom:link[@rel="self"]/@href'/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select='atom:link/@href'/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name='id'>
<xsl:text>rivista-</xsl:text>
<xsl:value-of select='position()'/>
</xsl:attribute>
<xsl:choose>
<xsl:when test='string-length(atom:title) &gt; 0'>
<xsl:value-of select='atom:title'/>
</xsl:when>
<xsl:otherwise>
*** No Title ***
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</h3>
<!-- geographic location -->
<xsl:choose>
<xsl:when test='geo:lat and geo:long'>
<xsl:variable name='lat' select='geo:lat'/>
<xsl:variable name='lng' select='geo:long'/>
<span class='geolocation'>
<a href='geo:{$lat},{$lng}'>📍</a>
</span>
</xsl:when>
<xsl:when test='geo:Point'>
<xsl:variable name='lat' select='geo:Point/geo:lat'/>
<xsl:variable name='lng' select='geo:Point/geo:long'/>
<span class='geolocation'>
<a href='geo:{$lat},{$lng}'>📍</a>
</span>
</xsl:when>
<xsl:when test='georss:point'>
<xsl:variable name='lat' select='substring-before(georss:point, " ")'/>
<xsl:variable name='lng' select='substring-after(georss:point, " ")'/>
<xsl:variable name='name' select='georss:featurename'/>
<span class='geolocation'>
<a href='geo:{$lat},{$lng}' title='{$name}'>📍</a>
</span>
</xsl:when>
</xsl:choose>
<!-- entry date -->
<xsl:element name='h4'>
<xsl:choose>
<xsl:when test='atom:updated'>
<xsl:attribute name='class'>
<xsl:text>updated</xsl:text>
</xsl:attribute>
<xsl:value-of select='atom:updated'/>
</xsl:when>
<xsl:when test='atom:published'>
<xsl:attribute name='class'>
<xsl:text>published</xsl:text>
</xsl:attribute>
<xsl:value-of select='atom:published'/>
</xsl:when>
<xsl:otherwise>
<h4 class='warning atom1 published'></h4>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
<!-- entry author -->
<xsl:if test='atom:author'>
<h4 class='author'>
<xsl:text>By </xsl:text>
<xsl:choose>
<xsl:when test='atom:author/atom:email'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:text>mailto:</xsl:text>
<xsl:value-of select='atom:author/atom:email'/>
</xsl:attribute>
<xsl:attribute name='title'>
<xsl:text>Send an Email to </xsl:text>
<xsl:value-of select='atom:author/atom:email'/>
</xsl:attribute>
<xsl:value-of select='atom:author/atom:name'/>
</xsl:element>
</xsl:when>
<xsl:when test='atom:author/atom:uri'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='atom:author/atom:uri'/>
</xsl:attribute>
<xsl:attribute name='title'>
<xsl:value-of select='atom:author/atom:summary'/>
</xsl:attribute>
<xsl:value-of select='atom:author/atom:name'/>
</xsl:element>
</xsl:when>
<xsl:when test='atom:author/atom:name'>
<xsl:value-of select='atom:author/atom:name'/>
</xsl:when>
<xsl:when test='atom:uri'>
<xsl:value-of select='atom:uri'/>
</xsl:when>
</xsl:choose>
</h4>
</xsl:if>
<h5 class='related'>
<xsl:if test='atom:link[@rel="alternate" and @type="x-scheme-handler/xmpp"]'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='atom:link[@rel="alternate" and @type="x-scheme-handler/xmpp"]/@href'/>
</xsl:attribute>
<xsl:attribute name='class'>
<xsl:text>rivista-jabber</xsl:text>
</xsl:attribute>
💡️ Source
</xsl:element>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='atom:link[@rel="alternate" and @type="x-scheme-handler/xmpp"]/@href'/>
</xsl:attribute>
(XMPP)
</xsl:element>
</xsl:if>
<xsl:if test='atom:link[@rel="contact"]'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='atom:link[@rel="contact"]/@href'/>
</xsl:attribute>
<xsl:attribute name='class'>
<xsl:text>contact-uri</xsl:text>
</xsl:attribute>
🪪️ Contact
</xsl:element>
</xsl:if>
<xsl:if test='atom:link[@rel="replies"]'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='atom:link[@rel="replies"]/@href'/>
</xsl:attribute>
<xsl:attribute name='class'>
<xsl:text>rivista-replies</xsl:text>
</xsl:attribute>
💬 Discussion
</xsl:element>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='atom:link[@rel="replies"]/@href'/>
</xsl:attribute>
(XMPP)
</xsl:element>
</xsl:if>
<xsl:if test='atom:link[@rel="alternate" and @type="text/html"]'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='atom:link[@rel="alternate" and @type="text/html"]/@href'/>
</xsl:attribute>
📜 HTML
</xsl:element>
</xsl:if>
<xsl:if test='atom:link[@rel="related" and @type="text/html"]'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='atom:link[@rel="related" and @type="text/html"]/@href'/>
</xsl:attribute>
📜 HTML (Related)
</xsl:element>
</xsl:if>
</h5>
<!-- entry content -->
<xsl:if test='atom:content or atom:summary'>
<div class='content'>
<xsl:choose>
<xsl:when test='atom:summary[contains(@type,"text")]'>
<xsl:attribute name='type'>
<xsl:value-of select='atom:summary/@type'/>
</xsl:attribute>
<xsl:value-of select='atom:summary'/>
</xsl:when>
<xsl:when test='atom:summary[contains(@type,"html")]'>
<xsl:attribute name='type'>
<xsl:value-of select='atom:summary/@type'/>
</xsl:attribute>
<xsl:value-of select='atom:summary' disable-output-escaping='yes'/>
</xsl:when>
<xsl:when test='atom:summary[contains(@type,"base64")]'>
<!-- TODO add xsl:template to handle inline media -->
</xsl:when>
<xsl:when test='atom:content[contains(@type,"text")]'>
<xsl:attribute name='type'>
<xsl:value-of select='atom:content/@type'/>
</xsl:attribute>
<xsl:value-of select='atom:content'/>
</xsl:when>
<xsl:when test='atom:content[contains(@type,"html")]'>
<xsl:attribute name='type'>
<xsl:value-of select='atom:content/@type'/>
</xsl:attribute>
<xsl:value-of select='atom:content' disable-output-escaping='yes'/>
</xsl:when>
<xsl:when test='atom:content[contains(@type,"base64")]'>
<!-- TODO add xsl:template to handle inline media -->
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test='atom:summary and not(atom:summary="")'>
<xsl:value-of select='atom:summary' disable-output-escaping='yes'/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select='atom:content' disable-output-escaping='yes'/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:if>
<!-- entry tags -->
<xsl:if test='atom:category/@term'>
<h4>Tags</h4>
<span class='tags'>
<xsl:for-each select='atom:category'>
<xsl:element name='div'>
<xsl:value-of select='@term'/>
</xsl:element>
</xsl:for-each>
</span>
</xsl:if>
<!-- entry enclosure -->
<xsl:if test='atom:link[@rel="enclosure"]'>
<h4>Media</h4>
<span class='enclosures' title='Right-click and Save link as…'>
<xsl:for-each select='atom:link[@rel="enclosure"]'>
<div class='enclosure' title='Right-click and Save link as…'>
<xsl:element name='span'>
<xsl:attribute name='icon'>
<xsl:value-of select='substring-before(@type,"/")'/>
</xsl:attribute>
</xsl:element>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='@href'/>
</xsl:attribute>
<xsl:attribute name='download'/>
<xsl:call-template name='extract-filename'>
<xsl:with-param name='url' select='@href' />
</xsl:call-template>
</xsl:element>
<xsl:element name='span'>
<xsl:attribute name='class'>
<xsl:value-of select='substring-before(@type,"/")'/>
</xsl:attribute>
</xsl:element>
<xsl:if test='@length &gt; 0'>
<xsl:call-template name='transform-filesize'>
<xsl:with-param name='length' select='@length' />
</xsl:call-template>
</xsl:if>
<br/>
</div>
</xsl:for-each>
</span>
</xsl:if>
</div>
<!-- entry id -->
<xsl:if test='not(atom:id)'>
<div class='warning atom1 id'>No entry ID</div>
</xsl:if>
</li>
</xsl:for-each>
</ul>
</xsl:when>
<xsl:otherwise>
<ul>
<li>
<div class='entry'>
<h3 class='title'>
<a href='javascript:alert("Please check that the mother PubSub node is populated with content.")'>
No content
</a>
</h3>
<h4>This entry is empty</h4>
<div class='content'>Please check that the mother PubSub node is populated with content.</div>
</div>
</li>
</ul>
</xsl:otherwise>
</xsl:choose>
</div>
</div>
<div id='references'>
<a href='https://joinjabber.org/'
title='An Inclusive Space On The Jabber Network.'>
JoinJabber
</a>
<a href='https://libervia.org/'
title='The Universal Communication Ecosystem.'>
Libervia
</a>
<a href='https://join.movim.eu/'
title='The Social Platform Shaped For Your Community.'>
Movim
</a>
<a href='https://git.xmpp-it.net/sch/Rivista'
title='A Journal Publisher And Browser For XMPP.'>
Rivista
</a>
<a href='https://git.xmpp-it.net/sch/Blasta'
title='A Social Bookmark Manager For XMPP.'>
Blasta
</a>
<a href='https://github.com/SeveFP/Reeder'
title='An XMPP-Based Feed Reader.'>
Reeder
</a>
<a href='https://modernxmpp.org/'
title='A Project To Improve The Quality Of User-To-User Messaging Applications That Use XMPP.'>
Modern
</a>
<a href='https://xmpp.org/'
title='The Universal Messaging Standard.'>
XMPP
</a>
<a href='https://xmpp.org/extensions/xep-0060.html'
title='XEP-0060: Publish-Subscribe.'>
PubSub
</a>
</div>
<!-- note -->
<p id='note'>
This an Atom document which can also be viewed with
a Syndication Feed Reader (also referred to as News Reader
or RSS Reader) which provides automated news updates and
notifications on desktop and mobile.
<span id="selection-link">Click here</span> for a
selection of software and pick the ones that would fit
to you best!
</p>
<p id='small'>
<i>
This ASF (Atom Syndication Format)
document is conveyed as an XHTML document.
This document was produced by an
XSLT <a href="xsl/atom.xsl">stylesheet</a>.
XSLT is a powerful technology which transforms XML
documents into HTML, JSON, PDF, Text XHTML, and
(modified) XML documents;
<a href="https://www.w3.org/Style/XSL/">Learn more</a>
about The Extensible Stylesheet Language Family (XSL).
</i>
</p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2016 - 2017 Schimon Jehuda. Released under MIT license
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
include https://schimon.i2p/ in attribute name='generator' of
element <meta/> inside of html element </head>
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- extract filename from given url string -->
<xsl:template name='extract-filename'>
<xsl:param name='url'/>
<xsl:choose>
<xsl:when test='contains($url,"/")'>
<xsl:call-template name='extract-filename'>
<xsl:with-param name='url' select='substring-after($url,"/")'/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select='$url'/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2016 - 2017 Schimon Jehuda. Released under MIT license
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
include https://schimon.i2p/ in attribute name='generator' of
element <meta/> inside of html element </head>
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- set page metadata -->
<xsl:template name='metadata'>
<xsl:param name='name'/>
<xsl:param name='content'/>
<xsl:if test='$content and not($content="")'>
<xsl:element name='meta'>
<xsl:attribute name='name'>
<xsl:value-of select='$name'/>
</xsl:attribute>
<xsl:attribute name='content'>
<xsl:value-of select='$content'/>
</xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2016 - 2024 Schimon Jehuda. Released under MIT license
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
include https://schimon.i2p/ in attribute name='generator' of
element <meta/> inside of html element </head>
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding = 'UTF-8'
indent = 'yes'
media-type = 'text/x-opml'
method = 'html'
version = '4.01' />
<!-- Outline Processor Markup Language 1.0 -->
<xsl:include href='opml_as_xhtml.xsl'/>
<!-- set page metadata -->
<xsl:include href='metadata.xsl'/>
</xsl:stylesheet>

View file

@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2016 - 2024 Schimon Jehuda. Released under MIT license
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
include https://schimon.i2p/ in attribute name='generator' of
element <meta/> inside of html element </head>
-->
<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:xml='http://www.w3.org/XML/1998/namespace'>
<xsl:template match='/opml'>
<!-- index right-to-left language codes -->
<!-- TODO http://www.w3.org/TR/xpath/#function-lang -->
<xsl:variable name='rtl'
select='lang[
contains(self::node(),"ar") or
contains(self::node(),"fa") or
contains(self::node(),"he") or
contains(self::node(),"ji") or
contains(self::node(),"ku") or
contains(self::node(),"ur") or
contains(self::node(),"yi")]'/>
<html>
<head>
<xsl:call-template name='metadata'>
<xsl:with-param name='name' select='"description"' />
<xsl:with-param name='content' select='subtitle' />
</xsl:call-template>
<xsl:call-template name='metadata'>
<xsl:with-param name='name' select='"generator"' />
<xsl:with-param name='content' select='Rivista' />
</xsl:call-template>
<xsl:call-template name='metadata'>
<xsl:with-param name='name' select='"mimetype"' />
<xsl:with-param name='content' select='"text/x-opml"' />
</xsl:call-template>
<title>
<xsl:choose>
<xsl:when test='//head/title and not(//head/title="")'>
<xsl:value-of select='//head/title'/>
</xsl:when>
<xsl:otherwise>Rivista OPML</xsl:otherwise>
</xsl:choose>
</title>
<!-- TODO media='print' -->
<link rel='stylesheet' type='text/css' media='screen' href='/css/stylesheet.css'/>
<link rel='icon' type='image/svg+xml' href='/graphic/xmpp.svg'/>
<!-- whether language code is of direction right-to-left -->
<xsl:if test='$rtl'>
<link id='semitic' href='/css/stylesheet-rtl.css' rel='stylesheet' type='text/css' />
</xsl:if>
<script type='text/javascript' src='/script/postprocess.js'/>
</head>
<body>
<div id='actions'>
<a href='https://xmpp.org/about/technology-overview/'
title='Of the benefits of XMPP.'>
XMPP
</a>
<a href='https://join.jabber.network/#syndication@conference.movim.eu?join'
title='Syndictaion and PubSub.'>
Groupchat
</a>
<a href='https://aboutfeeds.com/'
title='Of the benefits of syndication feed.'
id='aboutfeeds'>
Help
</a>
</div>
<div id='feed'>
<div id='header'>
<!-- feed title -->
<h1 id='title'>
<xsl:choose>
<xsl:when test='//head/title and not(//head/title="") and count(//outline) &gt; 1'>
<xsl:value-of select='//head/title'/>
</xsl:when>
<xsl:otherwise>
Rivista OPML Collection
</xsl:otherwise>
</xsl:choose>
</h1>
<!-- feed subtitle -->
<h2 id='subtitle'>
<xsl:choose>
<xsl:when test='//head/description and not(//head/description="") and count(//outline) &gt; 1'>
<xsl:value-of select='//head/description'/>
</xsl:when>
<xsl:otherwise>
Outline Processor Markup Language
</xsl:otherwise>
</xsl:choose>
</h2>
</div>
<xsl:if test='count(//outline) &gt; 1'>
<div id='menu'>
<h3>Subscriptions</h3>
<!-- xsl:for-each select='outline[position() &lt;21]' -->
<ol>
<xsl:for-each select='//outline[not(position() &gt; 20)]'>
<li>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:text>#rivista-</xsl:text>
<xsl:value-of select='position()'/>
</xsl:attribute>
<xsl:choose>
<xsl:when test='string-length(@text) &gt; 0'>
<xsl:value-of select='@text'/>
</xsl:when>
<xsl:otherwise>
*** No Title ***
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</li>
</xsl:for-each>
</ol>
</div>
</xsl:if>
<div id='articles'>
<!-- opml outline -->
<xsl:choose>
<xsl:when test='//outline'>
<ul>
<xsl:for-each select='//outline[not(position() &gt; 20)]'>
<li>
<div class='entry'>
<!-- outline title -->
<h3 class='title'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='@xmlUrl'/>
</xsl:attribute>
<xsl:attribute name='id'>
<xsl:text>rivista-</xsl:text>
<xsl:value-of select='position()'/>
</xsl:attribute>
<xsl:choose>
<xsl:when test='string-length(@text) &gt; 0'>
<xsl:value-of select='@text'/>
</xsl:when>
<xsl:otherwise>
*** No Title ***
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</h3>
<!-- entry content -->
<h4>
<xsl:value-of select='@text'/>
</h4>
<p class='content'>
<xsl:value-of select='@xmlUrl'/>
</p>
</div>
</li>
</xsl:for-each>
</ul>
</xsl:when>
<xsl:otherwise>
<div class='notice no-entry'></div>
</xsl:otherwise>
</xsl:choose>
</div>
</div>
<div id='references'>
<a href='https://joinjabber.org/'
title='An Inclusive Space On The Jabber Network.'>
JoinJabber
</a>
<a href='https://libervia.org/'
title='The Universal Communication Ecosystem.'>
Libervia
</a>
<a href='https://join.movim.eu/'
title='The Social Platform Shaped For Your Community.'>
Movim
</a>
<a href='https://git.xmpp-it.net/sch/Rivista'
title='A Journal Publisher And Browser For XMPP.'>
Rivista
</a>
<a href='https://git.xmpp-it.net/sch/Blasta'
title='A Social Bookmark Manager For XMPP.'>
Blasta
</a>
<a href='https://github.com/SeveFP/Reeder'
title='An XMPP-Based Feed Reader.'>
Reeder
</a>
<a href='https://modernxmpp.org/'
title='A Project To Improve The Quality Of User-To-User Messaging Applications That Use XMPP.'>
Modern
</a>
<a href='https://xmpp.org/'
title='The Universal Messaging Standard.'>
XMPP
</a>
<a href='https://xmpp.org/extensions/xep-0060.html'
title='XEP-0060: Publish-Subscribe.'>
PubSub
</a>
</div>
<!-- note -->
<p id='note'>
This is an OPML document which includes a collection of
subscriptions, and it can be imported to
a Syndication Feed Reader (also referred to as News Reader
or RSS Reader) which provides automated news updates and
notifications on desktop and mobile.
<span id="selection-link">Click here</span> for a
selection of software and pick the ones that would fit
to you best!
</p>
<p id='small'>
<i>
This OPML (Outline Processor Markup Language)
document is conveyed as an XHTML document.
This document was produced by an
XSLT <a href="xsl/opml.xsl">stylesheet</a>.
XSLT is a powerful technology which transforms XML
documents into HTML, JSON, PDF, Text XHTML, and
(modified) XML documents;
<a href="https://www.w3.org/Style/XSL/">Learn more</a>
about The Extensible Stylesheet Language Family (XSL).
</i>
</p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2016 - 2017 Schimon Jehuda. Released under MIT license
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
include https://schimon.i2p/ in attribute name='generator' of
element <meta/> inside of html element </head>
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
method = 'html'
indent = 'yes'
omit-xml-decleration='no' />
<!-- Atom Syndication Format 1.0 -->
<xsl:include href='atom_as_xhtml.xsl'/>
<!-- extract filename from given url string -->
<xsl:include href='extract-filename.xsl'/>
<!-- set page metadata -->
<xsl:include href='metadata.xsl'/>
<!-- transform filesize from given length string -->
<xsl:include href='transform-filesize.xsl'/>
</xsl:stylesheet>

View file

@ -0,0 +1,501 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2016 - 2017 Schimon Jehuda. Released under MIT license
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
include https://schimon.i2p/ in attribute name='generator' of
element <meta/> inside of html element </head>
-->
<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:xml='http://www.w3.org/XML/1998/namespace'
xmlns:media='http://search.yahoo.com/mrss/'
xmlns:georss='http://www.georss.org/georss'
xmlns:geo='http://www.w3.org/2003/01/geo/wgs84_pos#'
xmlns:atom10='http://www.w3.org/2005/Atom'
xmlns:atom='http://www.w3.org/2005/Atom'>
<xsl:output
method = 'html'
indent = 'yes'
omit-xml-decleration='no' />
<!-- Atom 1.0 Syndication Format -->
<xsl:template match='/atom:feed'>
<!-- index right-to-left language codes -->
<!-- TODO http://www.w3.org/TR/xpath/#function-lang -->
<xsl:variable name='rtl'
select='@xml:lang[
contains(self::node(),"ar") or
contains(self::node(),"fa") or
contains(self::node(),"he") or
contains(self::node(),"ji") or
contains(self::node(),"ku") or
contains(self::node(),"ur") or
contains(self::node(),"yi")]'/>
<html>
<head>
<xsl:call-template name='metadata'>
<xsl:with-param name='name' select='"description"' />
<xsl:with-param name='content' select='atom:subtitle' />
</xsl:call-template>
<xsl:call-template name='metadata'>
<xsl:with-param name='name' select='"generator"' />
<xsl:with-param name='content' select='StreamBurner' />
</xsl:call-template>
<xsl:call-template name='metadata'>
<xsl:with-param name='name' select='"mimetype"' />
<xsl:with-param name='content' select='"application/atom+xml"' />
</xsl:call-template>
<title>
<xsl:choose>
<xsl:when test='atom:title and not(atom:title="")'>
<xsl:value-of select='atom:title'/>
</xsl:when>
<xsl:otherwise>StreamBurner</xsl:otherwise>
</xsl:choose>
</title>
<!-- TODO media='print' -->
<link href='/css/stylesheet.css' rel='stylesheet' type='text/css' media='screen'/>
<link rel='icon' type='image/svg+xml' href='/graphic/xmpp.svg'/>
<!-- whether language code is of direction right-to-left -->
<xsl:if test='$rtl'>
<link id='semitic' href='/css/stylesheet-rtl.css' rel='stylesheet' type='text/css' />
</xsl:if>
<script type='text/javascript' src='/script/marked.min.js'/>
<script type='text/javascript' src='/script/postprocess.js'/>
</head>
<body>
<div id='actions'>
<a id='follow' title='Subscribe the latest updates and news.'
onclick='window.open(location.href.replace(/^https?:/, "feed:"), "_self")'>
<!-- xsl:attribute name="href">
feed:<xsl:value-of select="atom:link[@rel='self']/@href" />
</xsl:attribute -->
Follow
</a>
<a id='subtome' title='Subscribe via SubToMe.'>
<xsl:attribute name='href'>
javascript:location.href='https://www.subtome.com/#/subscribe?feeds='+location.href;
</xsl:attribute>
<xsl:attribute name='onclick'>
(
function(btn){
var z=document.createElement('script');
document.subtomeBtn=btn;
z.src='https://www.subtome.com/load.js';document.body.appendChild(z);
}
)(this);
return false;
</xsl:attribute>
SubToMe
</a>
<a href='https://git.xmpp-it.net/sch/PubSubToAtom'
title='About PubSub To Atom.'>
About
</a>
<a href='https://aboutfeeds.com/'
title='Of the benefits of syndication feed.'
id='aboutfeeds'>
Feeds
</a>
<a href='https://xmpp.org/about/technology-overview/'
title='Of the benefits of XMPP.'>
XMPP
</a>
<a href='https://join.jabber.network/#syndication@conference.movim.eu?join'
title='Syndictaion and PubSub.'>
Groupchat
</a>
</div>
<div id='feed'>
<div id='header'>
<!-- feed title -->
<h1 id='title'>
<xsl:choose>
<xsl:when test='atom:title and not(atom:title="") and count(atom:entry) &gt; 1'>
<xsl:value-of select='atom:title'/>
</xsl:when>
<xsl:when test='atom:entry'>
<xsl:value-of select='atom:entry/atom:title'/>
</xsl:when>
<xsl:otherwise>
StreamBurner
</xsl:otherwise>
</xsl:choose>
</h1>
<!-- feed subtitle -->
<h2 id='subtitle'>
<xsl:choose>
<xsl:when test='atom:title and not(atom:title="") and count(atom:entry) &gt; 1'>
<xsl:value-of select='atom:subtitle'/>
</xsl:when>
<xsl:when test='atom:entry'>
<xsl:attribute name='class'><xsl:text>date</xsl:text></xsl:attribute>
<xsl:value-of select='atom:entry/atom:updated'/>
</xsl:when>
<xsl:when test='atom:entry'>
<xsl:attribute name='class'><xsl:text>date</xsl:text></xsl:attribute>
<xsl:value-of select='atom:entry/atom:published'/>
</xsl:when>
</xsl:choose>
</h2>
</div>
<xsl:if test='count(atom:entry) &gt; 1'>
<div id='menu'>
<h3>Latest Posts</h3>
<!-- xsl:for-each select='atom:entry[position() &lt;21]' -->
<ul>
<xsl:for-each select='atom:entry[not(position() &gt; 20)]'>
<li>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:text>#stremburner-</xsl:text>
<xsl:value-of select='position()'/>
</xsl:attribute>
<xsl:choose>
<xsl:when test='string-length(atom:title) &gt; 0'>
<xsl:value-of select='atom:title'/>
</xsl:when>
<xsl:otherwise>
*** No Title ***
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</li>
</xsl:for-each>
</ul>
</div>
</xsl:if>
<div id='articles'>
<!-- feed entry -->
<xsl:choose>
<xsl:when test='atom:entry'>
<ul>
<xsl:for-each select='atom:entry[not(position() >20)]'>
<li>
<div class='entry'>
<!-- entry title -->
<h3 class='title'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:choose>
<xsl:when test='atom:link[contains(@rel,"alternate")]'>
<xsl:value-of select='atom:link[contains(@rel,"alternate")]/@href'/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select='atom:link/@href'/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name='title'>
<xsl:value-of select='atom:title'/>
</xsl:attribute>
<xsl:attribute name='id'>
<xsl:text>stremburner-</xsl:text>
<xsl:value-of select='position()'/>
</xsl:attribute>
<xsl:choose>
<xsl:when test='string-length(atom:title) &gt; 0'>
<xsl:value-of select='atom:title'/>
</xsl:when>
<xsl:otherwise>
*** No Title ***
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</h3>
<!-- geographic location -->
<xsl:choose>
<xsl:when test='geo:lat and geo:long'>
<xsl:variable name='lat' select='geo:lat'/>
<xsl:variable name='lng' select='geo:long'/>
<span class='geolocation'>
<a href='geo:{$lat},{$lng}'>📍</a>
</span>
</xsl:when>
<xsl:when test='geo:Point'>
<xsl:variable name='lat' select='geo:Point/geo:lat'/>
<xsl:variable name='lng' select='geo:Point/geo:long'/>
<span class='geolocation'>
<a href='geo:{$lat},{$lng}'>📍</a>
</span>
</xsl:when>
<xsl:when test='georss:point'>
<xsl:variable name='lat' select='substring-before(georss:point, " ")'/>
<xsl:variable name='lng' select='substring-after(georss:point, " ")'/>
<xsl:variable name='name' select='georss:featurename'/>
<span class='geolocation'>
<a href='geo:{$lat},{$lng}' title='{$name}'>📍</a>
</span>
</xsl:when>
</xsl:choose>
<!-- div class='posted' -->
<!-- entry author -->
<!-- xsl:if test='atom:author'>
<span class='author'>
<xsl:choose>
<xsl:when test='atom:author/atom:email'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:text>mailto:</xsl:text>
<xsl:value-of select='atom:author/atom:email'/>
</xsl:attribute>
<xsl:attribute name='title'>
<xsl:text>Send an Email to </xsl:text>
<xsl:value-of select='atom:author/atom:email'/>
</xsl:attribute>
<xsl:value-of select='atom:author/atom:name'/>
</xsl:element>
</xsl:when>
<xsl:when test='atom:author/atom:uri'>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='atom:author/atom:uri'/>
</xsl:attribute>
<xsl:attribute name='title'>
<xsl:value-of select='atom:author/atom:summary'/>
</xsl:attribute>
<xsl:value-of select='atom:author/atom:name'/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select='atom:name'/>
</xsl:otherwise>
</xsl:choose>
</span>
</xsl:if -->
<!-- entry date -->
<xsl:choose>
<xsl:when test='atom:updated'>
<h4 class='updated'>
<xsl:value-of select='atom:updated'/>
</h4>
</xsl:when>
<xsl:when test='atom:published'>
<h4 class='published'>
<xsl:value-of select='atom:published'/>
</h4>
</xsl:when>
<xsl:otherwise>
<h4 class='warning atom1 published'></h4>
</xsl:otherwise>
</xsl:choose>
<!-- /div -->
<!-- entry content -->
<!-- entry summary of GitLab Atom Syndication Feeds -->
<xsl:if test='atom:content or atom:summary'>
<p class='content'>
<xsl:choose>
<xsl:when test='atom:summary[contains(@type,"text")]'>
<xsl:attribute name='type'>
<xsl:value-of select='atom:summary/@type'/>
</xsl:attribute>
<xsl:value-of select='atom:summary'/>
</xsl:when>
<xsl:when test='atom:summary[contains(@type,"base64")]'>
<!-- TODO add xsl:template to handle inline media -->
</xsl:when>
<xsl:when test='atom:content[contains(@type,"text")]'>
<xsl:attribute name='type'>
<xsl:value-of select='atom:content/@type'/>
</xsl:attribute>
<xsl:value-of select='atom:content'/>
</xsl:when>
<xsl:when test='atom:content[contains(@type,"base64")]'>
<!-- TODO add xsl:template to handle inline media -->
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test='atom:summary and not(atom:summary="")'>
<xsl:value-of select='atom:summary' disable-output-escaping='yes'/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select='atom:content' disable-output-escaping='yes'/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</p>
</xsl:if>
<!-- entry enclosure -->
<xsl:if test='atom:link[contains(@rel,"enclosure")]'>
<div class='enclosure' title='Right-click and Save link as…'>
<xsl:for-each select='atom:link[contains(@rel,"enclosure")]'>
<xsl:element name='span'>
<xsl:attribute name='icon'>
<xsl:value-of select='substring-before(@type,"/")'/>
</xsl:attribute>
</xsl:element>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='@href'/>
</xsl:attribute>
<xsl:attribute name='download'/>
<xsl:call-template name='extract-filename'>
<xsl:with-param name='url' select='@href' />
</xsl:call-template>
</xsl:element>
<xsl:element name='span'>
<xsl:attribute name='class'>
<xsl:value-of select='substring-before(@type,"/")'/>
</xsl:attribute>
</xsl:element>
<xsl:if test='@length &gt; 0'>
<xsl:call-template name='transform-filesize'>
<xsl:with-param name='length' select='@length' />
</xsl:call-template>
</xsl:if>
<xsl:element name='br'/>
</xsl:for-each>
<xsl:for-each select='media:content'>
<xsl:element name='span'>
<xsl:attribute name='icon'>
<xsl:value-of select='@medium'/>
</xsl:attribute>
</xsl:element>
<xsl:element name='a'>
<xsl:attribute name='href'>
<xsl:value-of select='@url'/>
</xsl:attribute>
<xsl:attribute name='download'/>
<xsl:call-template name='extract-filename'>
<xsl:with-param name='url' select='@url' />
</xsl:call-template>
</xsl:element>
<xsl:element name='span'>
<xsl:attribute name='class'>
<xsl:value-of select='@medium'/>
</xsl:attribute>
</xsl:element>
<xsl:if test='@fileSize &gt; 0'>
<xsl:call-template name='transform-filesize'>
<xsl:with-param name='length' select='@fileSize' />
</xsl:call-template>
</xsl:if>
<xsl:element name='br'/>
</xsl:for-each>
</div>
</xsl:if>
</div>
<!-- entry id -->
<xsl:if test='not(atom:id)'>
<div class='warning atom1 id'></div>
</xsl:if>
</li>
</xsl:for-each>
</ul>
</xsl:when>
<xsl:otherwise>
<div class='notice no-entry'></div>
</xsl:otherwise>
</xsl:choose>
</div>
</div>
<div id='references'>
<a href='https://joinjabber.org/'
title='An inclusive space on the Jabber network.'>
JoinJabber
</a>
<a href='https://libervia.org/'
title='The Universal Communication Ecosystem.'>
Libervia
</a>
<a href='https://join.movim.eu/'
title='The social platform shaped for your community.'>
Movim
</a>
<a href='https://modernxmpp.org/'
title='A project to improve the quality of user-to-user messaging applications that use XMPP.'>
Modern
</a>
<a href='https://xmpp.org/'
title='The universal messaging standard.'>
XMPP
</a>
<a href='https://xmpp.org/extensions/xep-0060.html'
title='XEP-0060: Publish-Subscribe.'>
PubSub
</a>
</div>
<!-- note -->
<p id='note'>
<i>
This is an XMPP news feed which is conveyed as HTML,
and it can even be viewed by a syndication feed reader
which provides automated notifications on desktop and
mobile. <span id="selection-link">Click here</span> for
a selection of software that would fit you best!
</i>
</p>
</body>
</html>
</xsl:template>
<!-- extract filename from given url string -->
<!-- extract filename from given url string -->
<xsl:template name='extract-filename'>
<xsl:param name='url'/>
<xsl:choose>
<xsl:when test='contains($url,"/")'>
<xsl:call-template name='extract-filename'>
<xsl:with-param name='url' select='substring-after($url,"/")'/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select='$url'/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- set page metadata -->
<!-- set page metadata -->
<xsl:template name='metadata'>
<xsl:param name='name'/>
<xsl:param name='content'/>
<xsl:if test='$content and not($content="")'>
<xsl:element name='meta'>
<xsl:attribute name='name'>
<xsl:value-of select='$name'/>
</xsl:attribute>
<xsl:attribute name='content'>
<xsl:value-of select='$content'/>
</xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:template>
<!-- transform filesize from given length string -->
<!-- transform filesize from given length string -->
<xsl:template name='transform-filesize'>
<xsl:param name='length'/>
<!-- TODO consider xsl:decimal-format and xsl:number -->
<xsl:choose>
<!-- TODO consider removal of Byte -->
<xsl:when test='$length &lt; 2'>
<xsl:value-of select='$length'/>
Byte
</xsl:when>
<xsl:when test='floor($length div 1024) &lt; 1'>
<xsl:value-of select='$length'/>
Bytes
</xsl:when>
<xsl:when test='floor($length div (1024 * 1024)) &lt; 1'>
<xsl:value-of select='floor($length div 1024)'/>.<xsl:value-of select='substring($length mod 1024,0,2)'/>
KiB
</xsl:when>
<xsl:when test='floor($length div (1024 * 1024 * 1024)) &lt; 1'>
<xsl:value-of select='floor($length div (1024 * 1024))'/>.<xsl:value-of select='substring($length mod (1024 * 1024),0,2)'/>
MiB
</xsl:when>
<xsl:otherwise>
<!-- P2P links -->
<xsl:value-of select='floor($length div (1024 * 1024 * 1024))'/>.<xsl:value-of select='substring($length mod (1024 * 1024 * 1024),0,2)'/>
GiB
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) 2016 - 2017 Schimon Jehuda. Released under MIT license
Feeds rendered using this XSLT stylesheet, or it's derivatives, must
include https://schimon.i2p/ in attribute name='generator' of
element <meta/> inside of html element </head>
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- transform filesize from given length string -->
<xsl:template name='transform-filesize'>
<xsl:param name='length'/>
<!-- TODO consider xsl:decimal-format and xsl:number -->
<xsl:choose>
<!-- TODO consider removal of Byte -->
<xsl:when test='$length &lt; 2'>
<xsl:value-of select='$length'/>
Byte
</xsl:when>
<xsl:when test='floor($length div 1024) &lt; 1'>
<xsl:value-of select='$length'/>
Bytes
</xsl:when>
<xsl:when test='floor($length div (1024 * 1024)) &lt; 1'>
<xsl:value-of select='floor($length div 1024)'/>.<xsl:value-of select='substring($length mod 1024,0,2)'/>
KiB
</xsl:when>
<xsl:when test='floor($length div (1024 * 1024 * 1024)) &lt; 1'>
<xsl:value-of select='floor($length div (1024 * 1024))'/>.<xsl:value-of select='substring($length mod (1024 * 1024),0,2)'/>
MiB
</xsl:when>
<xsl:otherwise>
<!-- P2P links -->
<xsl:value-of select='floor($length div (1024 * 1024 * 1024))'/>.<xsl:value-of select='substring($length mod (1024 * 1024 * 1024),0,2)'/>
GiB
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

116
rivista/config.py Normal file
View file

@ -0,0 +1,116 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Functions get_directory() were taken from project jarun/buku.
By Arun Prakash Jana (jarun) and Dmitry Marakasov (AMDmi3).
"""
import os
import sys
try:
import tomllib
except:
import tomli as tomllib
class Settings:
def get_directory():
"""
Determine the directory path where setting files be stored.
* If $XDG_CONFIG_HOME is defined, use it;
* else if $HOME exists, use it;
* else if the platform is Windows, use %APPDATA%;
* else use the current directory.
Returns
-------
str
Path to configuration directory.
"""
# config_home = xdg.BaseDirectory.xdg_config_home
config_home = os.environ.get('XDG_CONFIG_HOME')
if config_home is None:
if os.environ.get('HOME') is None:
if sys.platform == 'win32':
config_home = os.environ.get('APPDATA')
if config_home is None:
return os.path.abspath('.')
else:
return os.path.abspath('.')
else:
config_home = os.path.join(
os.environ.get('HOME'), '.config'
)
return os.path.join(config_home, 'rivista')
def get_setting(filename, section):
with open(filename, mode="rb") as settings:
result = tomllib.load(settings)[section]
return result
class Data:
def get_directory():
"""
Determine the directory path where data files be stored.
* If $XDG_DATA_HOME is defined, use it;
* else if $HOME exists, use it;
* else if the platform is Windows, use %APPDATA%;
* else use the current directory.
Returns
-------
str
Path to database file.
"""
# data_home = xdg.BaseDirectory.xdg_data_home
data_home = os.environ.get('XDG_DATA_HOME')
if data_home is None:
if os.environ.get('HOME') is None:
if sys.platform == 'win32':
data_home = os.environ.get('APPDATA')
if data_home is None:
return os.path.abspath('.rivista/data')
else:
return os.path.abspath('.rivista/data')
else:
data_home = os.path.join(
os.environ.get('HOME'), '.local', 'share'
)
return os.path.join(data_home, 'rivista')
class Cache:
def get_directory():
"""
Determine the directory path where cache files be stored.
* If $XDG_CACHE_HOME is defined, use it;
* else if $HOME exists, use it;
* else if the platform is Windows, use %APPDATA%;
* else use the current directory.
Returns
-------
str
Path to cache directory.
"""
# cache_home = xdg.BaseDirectory.xdg_cache_home
cache_home = os.environ.get('XDG_CACHE_HOME')
if cache_home is None:
if os.environ.get('HOME') is None:
if sys.platform == 'win32':
cache_home = os.environ.get('APPDATA')
if cache_home is None:
return os.path.abspath('.rivista/cache')
else:
return os.path.abspath('.rivista/cache')
else:
cache_home = os.path.join(
os.environ.get('HOME'), '.cache'
)
return os.path.join(cache_home, 'rivista')

4
rivista/gmi/index.py Normal file
View file

@ -0,0 +1,4 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
class GmiIndex:

52
rivista/gmi/markdown.py Normal file
View file

@ -0,0 +1,52 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
class GmiMarkdown:
def convert_to_gmi(markdown_text):
lines = markdown_text.splitlines()
footnotes = []
footnote_counter = 1
output_lines = []
for line in lines:
# Process links in the format [text](url)
while True:
start_bracket = line.find('[')
if start_bracket == -1:
break # No more links in this line
end_bracket = line.find(']', start_bracket)
if end_bracket == -1:
break # Malformed link; exit loop
start_parenthesis = line.find('(', end_bracket)
if start_parenthesis == -1:
break # Malformed link; exit loop
end_parenthesis = line.find(')', start_parenthesis)
if end_parenthesis == -1:
break # Malformed link; exit loop
link_text = line[start_bracket + 1:end_bracket]
url = line[start_parenthesis + 1:end_parenthesis]
# Add footnote
footnotes.append(f" [{footnote_counter}]: {link_text}{url}")
footnote_marker = f"{link_text}[{footnote_counter}]"
footnote_counter += 1
# Replace link with footnote marker
line = line[:start_bracket] + footnote_marker + line[end_parenthesis + 1:]
# Remove Markdown header markers
if line.startswith('#'):
line = line.lstrip('# ').strip()
output_lines.append(line.strip())
# Combine output lines and footnotes
output_text = "\n".join(output_lines).strip()
footnotes_text = "\n".join(footnotes)
return f"{output_text}\n\n{footnotes_text}" if footnotes else output_text

79
rivista/gmi/post.py Normal file
View file

@ -0,0 +1,79 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#from markdown_text_clean import clean_text
#from md2gemini import md2gemini
#from rivista.gmi.markdown import GmiMarkdown
from rivista.html.gmi import HtmlGmi
from rivista.markdown.html import MarkdownHtml
class GmiPost:
def generate_gmi(atom: dict):
"""Generate an Gemini document."""
atom_title = atom['title']
atom_subtitle = atom['subtitle']
atom_header = f'# {atom_title}\n### {atom_subtitle}\n\n'
atom_items = []
for item in atom['items']:
item_title = item['title']
item_published = item['published']
item_updated = item['updated']
item_contents = ''
for content in item['contents']:
match content['type']:
case 'text':
content_html = MarkdownHtml.convert_to_html(content['text'])
content_text = HtmlGmi.convert_to_gmi(content_html)
#content_text = GmiMarkdown.convert_to_gmi(content['text'])
#content_text = md2gemini(content['text'], links="at-end")
#content_text = clean_text(content['text'])
item_contents += f'\n{content_text}\n'
case _ if content['type'] in ('html', 'xhtml'):
content_text = HtmlGmi.convert_to_gmi(content['text'])
item_contents += f'\n{content_text}\n'
case _:
content_text = content['text']
item_contents += f'\n```\n{content_text}\n```\n'
links = item['links'] if 'links' in item else None
item_links = ''
if links:
item_links = '\n### Related resources\n\n'
for link in links:
link_href = link['href']
link_rel = link['rel']
link_type = link['type']
if link_type:
item_links += f'=> {link_href} {link_rel} ({link_type})\n'
else:
item_links += f'=> {link_href} {link_rel}\n'
categories = item['categories'] if 'categories' in item else None
item_categories = ''
if categories:
item_categories = '\n### Categories\n\n'
for category in categories:
item_categories += f'{category}, '
item_categories = item_categories[0:len(item_categories)-2] + '.\n'
authors = item['authors'] if 'authors' in item else None
item_authors = ''
if authors:
item_authors = '\n### Authors\n\n'
for author in authors:
author_text = author['name'] or author['uri'] or author['email']
if 'email' in author and author['email']:
item_author_email = 'mailto:' + author['email']
item_authors += f'=> {author_text} {item_author_email}\n'
elif 'uri' in author and author['uri']:
item_author_uri = author['uri']
item_authors += f'=> {author_text} {item_author_uri}\n'
else:
item_authors += f'{author_text}\n'
atom_items. append(f'\n## {item_title}\n\n' +
f'Published: {item_published}\n' +
f'Updated: {item_updated}\n' +
item_contents +
item_links +
item_categories +
item_authors)
gmi_text = atom_header + '\n'.join(atom_items)
return gmi_text

51
rivista/html/gmi.py Normal file
View file

@ -0,0 +1,51 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
class HtmlGmi:
def convert_to_gmi(html_content):
soup = BeautifulSoup(html_content, 'html.parser')
footnotes = ['### References\n']
footnote_counter = 1
# Extract text and links
for a in soup.find_all('a'):
link_text = a.get_text()
url = a['href']
if not url.startswith('#') and not url.startswith('/'):
url_modified = url.replace(' ', '%20')
url_modified = url_modified.replace('(', '%28')
url_modified = url_modified.replace(')', '%29')
#footnotes.append(f"=> {url_modified} [{footnote_counter}]: {link_text}")
footnotes.append(f"=> {url_modified} [{footnote_counter}]: {url}")
footnote_marker = f"{link_text}[{footnote_counter}]"
a.replace_with(footnote_marker)
footnote_counter += 1
# Handle <code> tags
for code in soup.find_all('code'):
if code.string:
original_text = code.get_text()
modified_text = '`' + original_text + '`'
code.string.replace_with(modified_text)
# Handle <pre> tags
for pre in soup.find_all('pre'):
pre.insert_before('\n```\n') # Add Markdown code block start
pre.insert_after('\n```\n') # Add Markdown code block end
# Convert <ul> and <li> to Markdown bullet points
for ul in soup.find_all('ul'):
for li in ul.find_all('li'):
if li.string:
original_text = li.get_text()
modified_text = '- ' + original_text
li.string.replace_with(modified_text)
# Get the text without HTML tags
text = soup.get_text().strip().replace('#', '')
# Combine text with footnotes
return f"{text}\n\n" + "\n".join(footnotes) if footnotes else text

215
rivista/http/instance.py Normal file
View file

@ -0,0 +1,215 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from fastapi import FastAPI, Request, Response
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
import os
from rivista.config import Cache, Data, Settings
from rivista.gmi.post import GmiPost
from rivista.json.index import JsonIndex
from rivista.xml.atom import XmlAtom
from rivista.xml.opml import XmlOpml
from rivista.xml.xhtml import XmlXhtml
from rivista.xml.xslt import XmlXslt
from rivista.xmpp.instance import XmppInstance
from rivista.xmpp.utilities import XmppUtilities
from rivista.xmpp.xep_0060 import XmppXep0060
class HttpInstance:
def __init__(self):
directory_settings = Settings.get_directory()
filename_settings = os.path.join(directory_settings, 'settings.toml')
credentials = Settings.get_setting(filename_settings, 'account')
settings = Settings.get_setting(filename_settings, 'settings')
default = Settings.get_setting(filename_settings, 'default')
operator = Settings.get_setting(filename_settings, 'settings')['operator']
directory_data = Data.get_directory()
directory_data_css = os.path.join(directory_data, 'css')
directory_data_graphic = os.path.join(directory_data, 'graphic')
directory_data_script = os.path.join(directory_data, 'script')
directory_data_xsl = os.path.join(directory_data, 'xsl')
filename_favicon = os.path.join(directory_data, 'img', 'favicon.ico')
directory_cache = Cache.get_directory()
directory_cache_json = os.path.join(directory_cache, 'json')
self.app = FastAPI()
# Mount static graphic, script and stylesheet directories
self.app.mount("/css", StaticFiles(directory=directory_data_css), name="css")
self.app.mount("/data", StaticFiles(directory=directory_cache_json), name="data")
self.app.mount("/graphic", StaticFiles(directory=directory_data_graphic), name="graphic")
self.app.mount("/script", StaticFiles(directory=directory_data_script), name="script")
self.app.mount("/xsl", StaticFiles(directory=directory_data_xsl), name="xsl")
@self.app.get('/favicon.ico', include_in_schema=False)
async def favicon():
return FileResponse(filename_favicon)
@self.app.route('/')
@self.app.get('/opml')
async def view_pubsub_nodes(request: Request):
xmpp = XmppInstance(credentials['xmpp'], credentials['pass'])
# xmpp.connect()
pubsub = request.query_params.get('pubsub', '')
result = None
if settings['service']:
if settings['include'] in pubsub or not settings['include']:
if pubsub:
iq = await XmppXep0060.get_nodes(xmpp, pubsub)
if iq:
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
xml_opml = XmlOpml.generate_opml(iq)
result = XmlXslt.append_stylesheet(xml_opml, 'opml')
else:
text = 'Please ensure that PubSub "{}" (Jabber ID) is valid and accessible.'.format(pubsub)
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
else:
text = 'The given domain {} is not allowed.'.format(pubsub)
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
if not result:
if default['pubsub']:
if not pubsub:
pubsub = default['pubsub']
iq = await XmppXep0060.get_nodes(xmpp, pubsub)
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
xml_opml = XmlOpml.generate_opml(iq)
result = XmlXslt.append_stylesheet(xml_opml, 'opml')
elif not settings['service']:
pubsub = default['pubsub']
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
xml_opml = XmlOpml.generate_opml(iq)
result = XmlXslt.append_stylesheet(xml_opml, 'opml')
else:
text = 'Please contact the administrator and ask him to set default PubSub and Node ID.'
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
xmpp.disconnect()
response = Response(content=result, media_type="application/xml")
return response
@self.app.get('/atom')
async def view_node_items(request: Request):
xmpp = XmppInstance(credentials['xmpp'], credentials['pass'])
# xmpp.connect()
pubsub = request.query_params.get('pubsub', '')
node = request.query_params.get('node', '')
item_id = request.query_params.get('item', '')
result = None
if settings['service']:
if settings['include'] in pubsub or not settings['include']:
if pubsub and node and item_id:
iq = await XmppXep0060.get_node_item(xmpp, pubsub, node, item_id)
if iq:
link = XmppUtilities.form_an_item_link(pubsub, node, item_id)
if 'urn:xmpp:microblog:0:comments/' in node:
atom = XmlAtom.extract_atom(iq)
xml_atom = XmlAtom.generate_atom_comment(atom, pubsub, node, link)
else:
atom = XmlAtom.extract_atom(iq)
xml_atom = XmlAtom.generate_atom_post(atom, pubsub, node, link)
gmi_text = GmiPost.generate_gmi(atom)
iq = await XmppXep0060.get_node_items(xmpp, pubsub, node)
if not '/' in node:
if iq:
JsonIndex.generate_json(iq, directory_cache_json)
else:
json_data = [{'title' : 'Error retrieving node items.',
'link' : ('javascript:alert("Rivista has experienced an error '
'while attempting to retrieve the list of items for '
'Node {} of PubSub {}.")')
.format(node, pubsub)},
{'title' : 'Contact the operator.',
'link' : ('xmpp:{}?message;subject=Rivista;body=Greetings! '
'I am contacting you to inform you that there is an error listing '
'node items for Node {} on PubSub {}.').format(operator, node, pubsub)}]
filename = 'data/{}.json'.format(node)
with open(filename, 'w', encoding='utf-8') as f:
json.dump(json_data, f, ensure_ascii=False, indent=4)
else:
text = 'Please ensure that PubSub node "{}" and item "{}" are valid and accessible.'.format(node, item_id)
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
# try:
# iq = await XmppXep0060.get_node_items(xmpp, pubsub, node)
# JsonIndex.generate_json(iq, node)
# except:
# json_data = [{'title' : 'Timeout retrieving node items from {}'.format(node),
# 'link' : 'xmpp:{}?message'.format(operator)}]
# filename = 'data/{}.json'.format(node)
# with open(filename, 'w', encoding='utf-8') as f:
# json.dump(json_data, f, ensure_ascii=False, indent=4)
elif pubsub and node:
iq = await XmppXep0060.get_node_items(xmpp, pubsub, node)
if iq:
link = XmppUtilities.form_a_node_link(pubsub, node)
if 'urn:xmpp:microblog:0:comments/' in node:
atom = XmlAtom.extract_atom(iq)
xml_atom = XmlAtom.generate_atom_comment(atom, pubsub, node, link)
else:
atom = XmlAtom.extract_atom(iq)
xml_atom = XmlAtom.generate_atom_post(atom, pubsub, node, link)
gmi_text = GmiPost.generate_gmi(atom)
else:
text = 'Please ensure that PubSub node "{}" is valid and accessible.'.format(node)
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
elif pubsub:
text = 'Node parameter is missing.'
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
elif node:
text = 'PubSub parameter is missing.'
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
# else:
# text = ('Mandatory parameter PubSub and '
# 'optional parameter Node are missing.')
# xml_atom = XmlAtom.error_message(text)
# result = XmlXslt.append_stylesheet(xml_atom, 'atom')
else:
text = 'The given domain {} is not allowed.'.format(pubsub)
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
if not result:
if default['pubsub'] and default['nodeid']:
if not pubsub and not node:
pubsub = default['pubsub']
node = default['nodeid']
iq = await XmppXep0060.get_node_items(xmpp, pubsub, node)
if iq:
link = XmppUtilities.form_a_node_link(pubsub, node)
atom = XmlAtom.extract_atom(iq)
xml_atom = XmlAtom.generate_atom_post(atom, pubsub, node, link)
gmi_text = GmiPost.generate_gmi(atom)
else:
text = 'Please ensure that PubSub node "{}" is valid and accessible.'.format(node)
xml_atom = XmlAtom.error_message(text)
elif not settings['service']:
pubsub = default['pubsub']
node = default['nodeid']
iq = await XmppXep0060.get_node_items(xmpp, pubsub, node)
if iq:
link = XmppUtilities.form_a_node_link(pubsub, node)
atom = XmlAtom.extract_atom(iq)
xml_atom = XmlAtom.generate_atom_post(atom, pubsub, node, link)
gmi_text = GmiPost.generate_gmi(atom)
else:
text = 'Please ensure that PubSub node "{}" is valid and accessible.'.format(node)
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
else:
text = 'Please contact the administrator and ask him to set default PubSub and Node ID.'
xml_atom = XmlAtom.error_message(text)
result = XmlXslt.append_stylesheet(xml_atom, 'atom')
xmpp.disconnect()
response = Response(content=result, media_type="application/xml")
return response

38
rivista/json/index.py Normal file
View file

@ -0,0 +1,38 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import json
import os
from rivista.xmpp.utilities import XmppUtilities
class JsonIndex:
def generate_json(iq, directory_cache_json):
"""Create a JSON file from node items."""
json_data = []
pubsub = iq['from'].bare
node = iq['pubsub']['items']['node']
entries = iq['pubsub']['items']
for entry in entries:
item_id = entry['id']
item_payload = entry['payload']
namespace = '{http://www.w3.org/2005/Atom}'
title = item_payload.find(namespace + 'title')
title_text = '*** No Title ***' if title == None else title.text
# updated = item.find(namespace + 'updated')
# updated = None if updated == None else updated.text
# if updated: updated = datetime.datetime.fromisoformat(updated)
link_href = XmppUtilities.form_an_item_link(pubsub, node, item_id)
# link = item.find(namespace + 'link')
# link_href = '' if link == None else link.attrib['href']
json_data_entry = {'title' : title_text,
'link' : link_href}
json_data.append(json_data_entry)
#if len(json_data) > 6: break
directory = os.path.join(directory_cache_json, pubsub)
if not os.path.exists(directory):
os.mkdir(directory)
filename = os.path.join(directory_cache_json, pubsub, node)
with open(filename, 'w', encoding='utf-8') as f:
json.dump(json_data, f, ensure_ascii=False, indent=4)

11
rivista/markdown/html.py Normal file
View file

@ -0,0 +1,11 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import markdown
class MarkdownHtml:
def convert_to_html(markdown_content):
# Convert Markdown to HTML
html_content = markdown.markdown(markdown_content)
return html_content

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

2
rivista/version.py Normal file
View file

@ -0,0 +1,2 @@
__version__ = '1.0'
__version_info__ = (1, 0)

251
rivista/xml/atom.py Normal file
View file

@ -0,0 +1,251 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
from rivista.xmpp.utilities import XmppUtilities
from slixmpp.stanza.iq import Iq
import xml.etree.ElementTree as ET
class XmlAtom:
def error_message(text):
"""Error message in RFC 4287: The Atom Syndication Format."""
title = 'Rivista'
subtitle = 'XMPP Journal Publisher'
description = ('This is a syndication feed generated with Rivista, an XMPP '
'Journal Publisher, which conveys XEP-0060: Publish-'
'Subscribe nodes to standard RFC 4287: The Atom Syndication '
'Format.')
language = 'en'
feed = ET.Element("feed")
feed.set('xmlns', 'http://www.w3.org/2005/Atom')
ET.SubElement(feed, 'title', {'type': 'text'}).text = title
ET.SubElement(feed, 'subtitle', {'type': 'text'}).text = subtitle
ET.SubElement(feed, 'author', {'name':'Rivista','email':'rivista@schimon.i2p'})
ET.SubElement(feed, 'generator', {
'uri': 'https://git.xmpp-it.net/sch/Rivista',
'version': '0.1'}).text = 'Rivista XJP'
ET.SubElement(feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
entry = ET.SubElement(feed, 'entry')
ET.SubElement(entry, 'title').text = 'Error'
ET.SubElement(entry, 'id').text = 'rivista-error'
ET.SubElement(entry, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
ET.SubElement(entry, 'published').text = datetime.datetime.now(datetime.UTC).isoformat()
# ET.SubElement(entry, 'summary', {'type': summary_type_text}).text = summary_text
ET.SubElement(entry, 'content', {'type': 'text'}).text = text
return ET.tostring(feed, encoding='unicode')
def extract_atom(iq: Iq):
"""Extract data from an Atom Syndication Format (RFC 4287) of a Publish-Subscribe (XEP-0060) node item."""
jid = iq['from'].bare
node = iq['pubsub']['items']['node']
atom = {}
atom['title'] = jid
atom['subtitle'] = node
atom['language'] = iq['pubsub']['items']['lang']
atom['items'] = []
items = iq['pubsub']['items']
for item in list(items)[::-1]:
atom_item = {}
item_payload = item['payload']
namespace = '{http://www.w3.org/2005/Atom}'
title = item_payload.find(namespace + 'title')
links = item_payload.find(namespace + 'link')
if (not isinstance(title, ET.Element) and
not isinstance(links, ET.Element)): continue
title_text = 'No title' if title == None else title.text
atom_item['title'] = title_text
if isinstance(links, ET.Element):
atom_item['links'] = []
for link in item_payload.findall(namespace + 'link'):
link_href = link.attrib['href'] if 'href' in link.attrib else ''
link_type = link.attrib['type'] if 'type' in link.attrib else ''
link_rel = link.attrib['rel'] if 'rel' in link.attrib else ''
atom_item['links'].append({'href': link_href,
'rel': link_rel,
'type': link_type})
contents = item_payload.find(namespace + 'content')
atom_item['contents'] = []
if isinstance(contents, ET.Element):
for content in item_payload.findall(namespace + 'content'):
if not content.text: continue
content_text = content.text
content_type = content.attrib['type'] if 'type' in content.attrib else 'html'
content_type_text = 'html' if 'html' in content_type else 'text'
atom_item['contents'].append({'text' : content_text,
'type' : content_type_text})
else:
summary = item_payload.find(namespace + 'summary')
summary_text = summary.text if summary else None
if summary_text:
summary_type = summary.attrib['type'] if 'type' in summary.attrib else 'html'
summary_type_text = 'html' if 'html' in summary_type else 'text'
atom_item['contents'].append(summary_text)
# else:
# atom_item['contents'].append('No content.')
published = item_payload.find(namespace + 'published')
published_text = '' if published == None else published.text
atom_item['published'] = published_text
updated = item_payload.find(namespace + 'updated')
updated_text = '' if updated == None else updated.text
atom_item['updated'] = updated_text
atom_item['authors'] = []
authors = item_payload.find(namespace + 'author')
if isinstance(authors, ET.Element):
for author in item_payload.findall(namespace + 'author'):
atom_item_author = {}
author_email = author.find(namespace + 'email')
if author_email is not None:
author_email_text = author_email.text
if author_email_text:
atom_item_author['email'] = author_email_text
else:
author_email_text = None
author_uri = author.find(namespace + 'uri')
if author_uri is not None:
author_uri_text = author_uri.text
if author_uri_text:
atom_item_author['uri'] = author_uri_text
else:
author_uri_text = None
author_name = author.find(namespace + 'name')
if author_name is not None and author_name.text:
author_name_text = author_name.text
else:
author_name_text = author_uri_text or author_email_text
atom_item_author['name'] = author_name_text
atom_item['authors'].append(atom_item_author)
categories = item_payload.find(namespace + 'category')
atom_item['categories'] = []
if isinstance(categories, ET.Element):
for category in item_payload.findall(namespace + 'category'):
if 'term' in category.attrib and category.attrib['term']:
category_term = category.attrib['term']
atom_item['categories'].append(category_term)
identifier = item_payload.find(namespace + 'id')
if identifier is not None and identifier.attrib: print(identifier.attrib)
identifier_text = item['id'] if identifier == None else identifier.text
atom_item['id'] = identifier_text
#atom_item['id'] = item['id']
atom['items'].append(atom_item)
return atom
# generate_rfc_4287
def generate_atom_post(atom: dict, pubsub: str, node: str, link: str):
"""Generate an Atom Syndication Format (RFC 4287) from a Publish-Subscribe (XEP-0060) node items."""
# link = XmppUtilities.form_a_node_link(pubsub, node)
# subtitle = 'XMPP PubSub Syndication Feed'
description = ('This is a syndication feed generated with Rivista, an XMPP '
'Journal Publisher, which conveys XEP-0060: Publish-'
'Subscribe nodes to standard RFC 4287: The Atom Syndication '
'Format.')
e_feed = ET.Element("feed")
e_feed.set('xmlns', 'http://www.w3.org/2005/Atom')
ET.SubElement(e_feed, 'title', {'type': 'text'}).text = atom['title']
ET.SubElement(e_feed, 'subtitle', {'type': 'text'}).text = atom['subtitle']
ET.SubElement(e_feed, 'link', {'rel': 'self', 'href': link})
ET.SubElement(e_feed, 'generator', {
'uri': 'https://git.xmpp-it.net/sch/Rivista',
'version': '0.1'}).text = 'Rivista XJP'
ET.SubElement(e_feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
for item in atom['items']:
e_entry = ET.SubElement(e_feed, 'entry')
ET.SubElement(e_entry, 'title').text = item['title']
links = item['links'] if 'links' in item else None
if links:
for link in links:
ET.SubElement(e_entry, 'link', {'href': link['href'],
'rel': link['rel'],
'type': link['type']})
else:
# NOTE What does this instruction line do?
ET.SubElement(e_entry, 'content', {'href': ''})
link_xmpp = XmppUtilities.form_an_item_link(pubsub, node, item['id'])
ET.SubElement(e_entry, 'link', {'href': link_xmpp,
'rel': 'alternate',
'type': 'x-scheme-handler/xmpp'})
contents = item['contents'] if 'contents' in item else None
if contents:
for content in contents:
ET.SubElement(e_entry, 'content', {'type': content['type']}).text = content['text']
else:
ET.SubElement(e_entry, 'content').text = 'No content.'
ET.SubElement(e_entry, 'published').text = item['published']
ET.SubElement(e_entry, 'updated').text = item['updated']
authors = item['authors'] if 'authors' in item else None
if authors:
for author in authors:
e_author = ET.SubElement(e_entry, 'author')
if 'email' in author and author['email']:
ET.SubElement(e_author, 'email').text = author['email']
if 'uri' in author and author['uri']:
ET.SubElement(e_entry, 'uri').text = author['uri']
ET.SubElement(e_author, 'uri').text = author['uri']
ET.SubElement(e_author, 'name').text = author['name'] or author['uri'] or author['email']
categories = item['categories']
if categories:
for category in categories:
ET.SubElement(e_entry, 'category', {'term': category})
ET.SubElement(e_entry, 'id').text = item['id']
return ET.tostring(e_feed, encoding='unicode')
# generate_rfc_4287
def generate_atom_comment(atom: dict, pubsub: str, node: str, link: str):
"""Generate an Atom Syndication Format (RFC 4287) from a Publish-Subscribe (XEP-0060) node items."""
# link = XmppUtilities.form_a_node_link(pubsub, node)
# subtitle = 'XMPP PubSub Syndication Feed'
description = ('This is a syndication feed generated with Rivista, an XMPP '
'Journal Publisher, which conveys XEP-0060: Publish-'
'Subscribe nodes to standard RFC 4287: The Atom Syndication '
'Format.')
e_feed = ET.Element("feed")
e_feed.set('xmlns', 'http://www.w3.org/2005/Atom')
ET.SubElement(e_feed, 'title', {'type': 'text'}).text = atom['title']
ET.SubElement(e_feed, 'subtitle', {'type': 'text'}).text = atom['subtitle']
ET.SubElement(e_feed, 'link', {'rel': 'self', 'href': link})
ET.SubElement(e_feed, 'generator', {
'uri': 'https://git.xmpp-it.net/sch/Rivista',
'version': '0.1'}).text = 'Rivista XJP'
ET.SubElement(e_feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
for item in atom['items']:
e_entry = ET.SubElement(e_feed, 'entry')
ET.SubElement(e_entry, 'title').text = item['authors'][0]['name']
links = item['links'] if 'links' in item else None
if links:
for link in links:
ET.SubElement(e_entry, 'link', {'href': link['href'],
'rel': link['rel'],
'type': link['type']})
else:
# NOTE What does this instruction line do?
ET.SubElement(e_entry, 'content', {'href': ''})
link_xmpp = XmppUtilities.form_an_item_link(pubsub, node, item['id'])
ET.SubElement(e_entry, 'link', {'href': link_xmpp,
'rel': 'alternate',
'type': 'x-scheme-handler/xmpp'})
contents = item['contents'] if 'contents' in item else None
if contents:
for content in contents:
ET.SubElement(e_entry, 'content', {'type': content['type']}).text = content['text']
else:
ET.SubElement(e_entry, 'content').text = 'No content.'
ET.SubElement(e_entry, 'published').text = item['published']
ET.SubElement(e_entry, 'updated').text = item['updated']
authors = item['authors'] if 'authors' in item else None
if authors:
for author in authors:
e_author = ET.SubElement(e_entry, 'author')
if 'email' in author and author['email']:
ET.SubElement(e_author, 'email').text = author['email']
if 'uri' in author and author['uri']:
ET.SubElement(e_entry, 'uri').text = author['uri']
ET.SubElement(e_author, 'uri').text = author['uri']
ET.SubElement(e_author, 'name').text = author['name'] or author['uri'] or author['email']
categories = item['categories']
if categories:
for category in categories:
ET.SubElement(e_entry, 'category', {'term': category})
ET.SubElement(e_entry, 'id').text = item['id']
return ET.tostring(e_feed, encoding='unicode')

32
rivista/xml/opml.py Normal file
View file

@ -0,0 +1,32 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
from rivista.xmpp.utilities import XmppUtilities
import xml.etree.ElementTree as ET
class XmlOpml:
def generate_opml(iq):
"""Generate an OPML Collection document."""
pubsub = iq['from'].bare
items = iq['disco_items']['items']
opml = ET.Element("opml")
opml.set("version", "1.0")
head = ET.SubElement(opml, "head")
ET.SubElement(head, "title").text = 'An OPML of ' + pubsub
ET.SubElement(head, "description").text = (
"PubSub Nodes of {}").format(pubsub)
ET.SubElement(head, "generator").text = 'Rivista'
ET.SubElement(head, "urlPublic").text = 'https://git.xmpp-it.net/sch/Rivista'
time_stamp = datetime.datetime.now(datetime.UTC).isoformat()
ET.SubElement(head, "dateCreated").text = time_stamp
ET.SubElement(head, "dateModified").text = time_stamp
body = ET.SubElement(opml, "body")
for item in items:
pubsub, node, title = item
uri = XmppUtilities.form_a_node_link(pubsub, node)
outline = ET.SubElement(body, "outline")
outline.set("text", title or node)
outline.set("xmlUrl", uri)
return ET.tostring(opml, encoding='unicode')

62
rivista/xml/xhtml.py Normal file
View file

@ -0,0 +1,62 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
import xml.etree.ElementTree as ET
class XmlXhtml:
def generate_xhtml(atom: dict):
"""Generate an XHTML document."""
e_html = ET.Element('html')
e_html.set('xmlns', 'http://www.w3.org/1999/xhtml')
e_head = ET.SubElement(e_html, 'head')
ET.SubElement(e_head, 'title').text = atom['title']
ET.SubElement(e_head, 'link', {'rel': 'stylesheet',
'href': 'pubsub.css'})
e_body = ET.SubElement(e_html, "body")
ET.SubElement(e_body, "h1").text = atom['title']
ET.SubElement(e_body, "h2").text = atom['subtitle']
for item in atom['items']:
item_id = item['id']
title = item['title']
links = item['links']
e_article = ET.SubElement(e_body, 'article')
e_title = ET.SubElement(e_article, 'h3')
e_title.text = item['title']
e_title.set('id', item['id'])
e_date = ET.SubElement(e_article, 'h4')
e_date.text = item['published']
e_date.set('title', 'Updated: ' + item['updated'])
authors = item['authors']
if authors:
e_authors = ET.SubElement(e_article, "dl")
ET.SubElement(e_authors, "dt").text = 'Authors'
for author in authors:
e_dd = ET.SubElement(e_authors, 'dd')
e_author = ET.SubElement(e_dd, 'a')
e_author.text = author['name'] or author['uri'] or author['email']
if 'email' in author and author['email']:
e_author.set('href', 'mailto:' + author['email'])
elif 'uri' in author and author['uri']:
e_author.set('href', author['uri'])
for content in item['contents']:
ET.SubElement(e_article, 'p', {'type': content['type']}).text = content['text']
if links:
e_links = ET.SubElement(e_article, "dl")
e_links.set('class', 'links')
ET.SubElement(e_links, "dt").text = 'Links'
for link in links:
e_dd = ET.SubElement(e_links, 'dd')
e_link = ET.SubElement(e_dd, 'a')
e_link.set('href', link['href'])
e_link.text = link['rel']
if link['type']: ET.SubElement(e_dd, 'span').text = link['type']
categories = item['categories']
if categories:
e_categories = ET.SubElement(e_article, "dl")
e_categories.set('class', 'categories')
ET.SubElement(e_categories, "dt").text = 'Categories'
for category in categories:
ET.SubElement(e_categories, 'dd').text = category
return ET.tostring(e_html, encoding='unicode')

22
rivista/xml/xslt.py Normal file
View file

@ -0,0 +1,22 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
class XmlXslt:
"""This is a patch function to append XSLT reference to XML."""
"""Why is there no built-in function of ElementTree or LXML?"""
def append_stylesheet(xml_data, type):
# Register namespace in order to avoide ns0:
if type == 'atom': ET.register_namespace('', 'http://www.w3.org/2005/Atom')
# Load XML from string
tree = ET.fromstring(xml_data)
# The following direction removes the XML declaration
xml_data_without_a_declaration = ET.tostring(tree, encoding='unicode')
# Add XML declaration and stylesheet
xml_data_declaration = (
'<?xml version="1.0" encoding="utf-8"?>'
'<?xml-stylesheet type="text/xsl" href="xsl/{}.xsl"?>'.format(type) +
xml_data_without_a_declaration)
return xml_data_declaration

11
rivista/xmpp/instance.py Normal file
View file

@ -0,0 +1,11 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from slixmpp import ClientXMPP
class XmppInstance(ClientXMPP):
def __init__(self, jid, password):
super().__init__(jid, password)
self.register_plugin('xep_0060')
self.connect()
# self.process(forever=False)

14
rivista/xmpp/utilities.py Normal file
View file

@ -0,0 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
class XmppUtilities:
def form_a_node_link(pubsub, node):
link = 'xmpp:{pubsub}?;node={node}'.format(pubsub=pubsub, node=node)
return link
def form_an_item_link(pubsub, node, item_id):
link = 'xmpp:{pubsub}?;node={node};item={item}'.format(
pubsub=pubsub, node=node, item=item_id)
return link

27
rivista/xmpp/xep_0060.py Normal file
View file

@ -0,0 +1,27 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from slixmpp.exceptions import IqError, IqTimeout
class XmppXep0060:
async def get_node_item(self, pubsub, node, item_id):
try:
iq = await self.plugin['xep_0060'].get_item(pubsub, node, item_id, timeout=5)
return iq
except (IqError, IqTimeout) as e:
print(e)
async def get_node_items(self, pubsub, node):
try:
iq = await self.plugin['xep_0060'].get_items(pubsub, node, timeout=5)
return iq
except (IqError, IqTimeout) as e:
print(e)
async def get_nodes(self, pubsub):
try:
iq = await self.plugin['xep_0060'].get_nodes(pubsub, timeout=5)
return iq
except (IqError, IqTimeout) as e:
print(e)