commit 2e678edfeac2b76b65619d58b0d08ab13871de5d Author: Ed Date: Thu Dec 28 14:17:31 2023 +0100 First commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea3fb1d --- /dev/null +++ b/.gitignore @@ -0,0 +1,163 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Output pelican folder +output/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..252df93 --- /dev/null +++ b/Makefile @@ -0,0 +1,72 @@ +PY?= +PELICAN?=pelican +PELICANOPTS= + +BASEDIR=$(CURDIR) +INPUTDIR=$(BASEDIR)/content +OUTPUTDIR=$(BASEDIR)/output +CONFFILE=$(BASEDIR)/pelicanconf.py +PUBLISHCONF=$(BASEDIR)/publishconf.py + + +DEBUG ?= 0 +ifeq ($(DEBUG), 1) + PELICANOPTS += -D +endif + +RELATIVE ?= 0 +ifeq ($(RELATIVE), 1) + PELICANOPTS += --relative-urls +endif + +SERVER ?= "0.0.0.0" + +PORT ?= 0 +ifneq ($(PORT), 0) + PELICANOPTS += -p $(PORT) +endif + + +help: + @echo 'Makefile for a pelican Web site ' + @echo ' ' + @echo 'Usage: ' + @echo ' make html (re)generate the web site ' + @echo ' make clean remove the generated files ' + @echo ' make regenerate regenerate files upon modification ' + @echo ' make publish generate using production settings ' + @echo ' make serve [PORT=8000] serve site at http://localhost:8000' + @echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 ' + @echo ' make devserver [PORT=8000] serve and regenerate together ' + @echo ' make devserver-global regenerate and serve on 0.0.0.0 ' + @echo ' ' + @echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html ' + @echo 'Set the RELATIVE variable to 1 to enable relative urls ' + @echo ' ' + +html: + "$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) + +clean: + [ ! -d "$(OUTPUTDIR)" ] || rm -rf "$(OUTPUTDIR)" + +regenerate: + "$(PELICAN)" -r "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) + +serve: + "$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) + +serve-global: + "$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -b $(SERVER) + +devserver: + "$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) + +devserver-global: + "$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -b 0.0.0.0 + +publish: + "$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(PUBLISHCONF)" $(PELICANOPTS) + + +.PHONY: html help clean regenerate serve serve-global devserver devserver-global publish \ No newline at end of file diff --git a/content/images/index/lounge.jpg b/content/images/index/lounge.jpg new file mode 100644 index 0000000..8b28eb5 Binary files /dev/null and b/content/images/index/lounge.jpg differ diff --git a/content/images/index/officina.jpg b/content/images/index/officina.jpg new file mode 100644 index 0000000..ef136a6 Binary files /dev/null and b/content/images/index/officina.jpg differ diff --git a/content/images/index/server.jpg b/content/images/index/server.jpg new file mode 100644 index 0000000..01b0ba3 Binary files /dev/null and b/content/images/index/server.jpg differ diff --git a/content/page/index.html b/content/page/index.html new file mode 100644 index 0000000..481da98 --- /dev/null +++ b/content/page/index.html @@ -0,0 +1,64 @@ + + + + Foxolab + + + + +

Homepage

+

Cosa è foxolab?

+

È un hackerspace, un luogo dove appassionati di tecnologia possono riunirsi, condividere idee e lavorare su progetti in comune.
+ Foxolab mette a disposizione spazio e attrezzature. I propri membri mettono a disposizione idee.

+

Viene definito "hackerspace" in quanto i membri che lo partecipano solitamente si ritrovano nei principi della "hacker ethic", tuttavia qualsiasi persona può partecipare se passa il vibe check.

+ +

Spazio e attrezzature?

+

Foxolab è diviso in tre spazi, utilizzabili in tre modi differenti.

+ +

Questi spazi e le attrezzature in loro contenute sono a disposizione dei membri. A loro volta possono ospitare "minilab", ovvero piccoli sotto laboratori o progetti tematici che vengono gestiti in modo autonomo da membri diversi.

+ +

Ma quindi voi fate cose illegali?

+

No. Sebbene la parola "hacker" sia conosciuta in ambito collettivo come "malintenzionato informatico", il significato della parola è ben diverso.

+

Un hacker è colui che [cit. Wikipedia] utilizza le proprie competenze [...] per esplorare i dettagli dei sistemi [...] e sperimenta come estenderne l'utilizzo.

+ +

Cos'è il vibe check?

+

Per fare in modo che il foxolab resti un ambiente sano e gradevole, tutti i membri devono essere positivi, rispettosi e inclusivi degli altri. Qualsiasi siano le capacità tecniche, idee e opinioni di una persona, desideriamo che il benessere di tutti sia messo al primo posto.

+

Ciò significa in generale seguire la Netiquette, le regole dell'Hacker Etico e la Legge di Wheaton.

+

I membri del Foxolab hanno solitamente a cuore cinque concetti fondamentali:

+ + +

Cosa NON è foxolab?

+

Il foxolab non è un pub, un bar, un ostello o una sala giochi. Per quanto lo svago possa servire a ristorare l'animo di un hacker affaticato, ricordiamo che l'obbiettivo resta sempre produrre e condividere idee. È possibile certamente divertirsi al suo interno, ma sempre in modo costruttivo e senza recare danni o disturbo agli altri ospiti.

+ +

Posso partecipare?

+

Correntemente foxolab è in costruzione, pertanto è necessario ancora un po' di tempo prima che aprano le adesioni ufficiali. Tuttavia, se desideri passare e curiosare dentro sei il benvenuto. Scrivi un messaggio :)

+ +

A costruzione ultimata, l'ingresso sarà limitato ai soli membri.

+ +

Membri?

+

Lo stabile in cui sorge Foxolab presenta limiti dimensionali e di accesso che non ne consentono una completa apertura al pubblico. Ciò che significa che, legalmente, solo le persone facenti parte dell'associazione e che avranno versato la quota associativa potranno accedere ai servizi offerti dall'hackerspace.

+ +

Quanto costa?

+

La quota associativa è ancora in fase di progettazione ma si spera di poter offrire un accesso sotto la soglia dei 100€ annuali, con sconti per studenti e membri che contribuiscono in modo sostanziale alla vita dell'hackerspace.

+ +

Contatti?

+ + Premi qui per ricevere un indirizzo mail univoco a cui poter scrivere una mail. + + diff --git a/content/page/net.html b/content/page/net.html new file mode 100644 index 0000000..4758ff2 --- /dev/null +++ b/content/page/net.html @@ -0,0 +1,49 @@ + + + + FOXO-NET + + + +

FOXO-NET

+
"Cosa sarebbe un hackerspace senza server?"
+ +

Foxo-net è una rete sperimentale creata per poter studiare e esplorare i meccanismi di internet e delle reti senza creare danni nel mondo reale, e per promuovere la decentralizzazione e il self-hosting. + +

L'upstream del foxolab

+

Fortunatamente il palazzo dove sorge foxolab è dotato di FTTH in grado di raggiungere fino a 2.5/1.0gbit. La vicinanza a Milano e la diretta connessione con i datacenter più importanti della zona la rende molto appetibile per colocation e altri servizi.

+

Oltre alla fibra è presente anche una rete secondaria basata su 4G in grado di sopperire ad eventuali guasti della linea principale.

+ +

Il ferro

+

Una piccola stanza è stata addobbata a "server-room" e agisce da "base" della FOXO-NET.

+ +

Colocation

+

Ad ogni membro è permesso portare e colocare i propri dispositivi a patto che siano di piccole dimensioni e con consumi contenuti (SBC, router, embedded...). Eventuali consumi e dimensioni superiori saranno considerati caso per caso.

+ +

Lo scopo di questo servizio è quello di poter studiare il comportamento di una rete composta da dispositivi eterogenei, con i connessi rischi.

+ +

Backup su nastro

+

Un server Proxmox Backup Server collegato a una tape library con 8 nastri LTO6. È possibile richiedere dati di accesso per effettuare backup.

+

Grazie alla caratteristica "disconnessione" fisica tra il robot che carica e scarica i nastri ed il lettore collegato al server, è possibile fare in modo che i backup più recenti siano "irraggiungibili" da eventuali ransomware o malintenzionati che possano volerne prendere possesso.

+ +

Lo scopo di questo servizio è lo studio di un sistema di backup zero-trust (criptato su client) parzialmente disconnesso (air gap)

+ +

DN42 IXP

+

Foxo-NET è interconnesso con dn42 e permette ai propri membri di annunciare le proprie sottoreti e fare "peering" localmente o con altri membri di dn42. Attraverso dn42 è possibile raggiungere altri hackerspace e sperimentare tecnologie comunemente usate sul web come BGP e DNS, ma senza i costi e i rischi di lavorare "in produzione" su internet.

+

Ogni membro può decidere, a tal proposito, di annunciare il proprio prefisso sul router locale (bring your own IP) o utilizzare IP dalla sottorete annunciata direttamente da foxolab.

+ +

Lo scopo di questo servizio è quello di sperimentare meccanismi di peering e tunneling per creare collegamenti fra sistemi autonomi.

+ +

I servizi

+

Postgresql

+

+ +

Postgresql può essere utilizzato per sperimentare su database SQL avanzato moderno.

+ + + diff --git a/content/page/regolamento.html b/content/page/regolamento.html new file mode 100644 index 0000000..0229b2e --- /dev/null +++ b/content/page/regolamento.html @@ -0,0 +1,50 @@ + + + + Regolamento interno + + + +

Regolamento

+

Preambolo: Hacker Ethic

+ +
+ +
+ +

Regole

+ +

0: Don't be a dick // Don't ruin the vibe

+

Un mondo ideale non ha bisogno di regole e pace e armonia ne farebbero da padrone. Purtroppo, però, non viviamo in quel tipo di mondo.

+

Ciò non significa non poterci provare.

+

Le regole qui sotto più che essere ferree imposizioni vogliono essere consigli su come vivere al meglio la propria presenza nell'associazione e - di conseguenza - nell'hackerspace.

+ +

1: Entra

+

L'accesso all'hackerspace è consentito a tutti i membri, ogni qualvolta l'hackerspace sia ufficialmente aperto (open day o eventi, come comunicato sul sito). Per evitare problemi logistici (la metratura è limitata!) è gradito prenotarsi prima dell'arrivo, anche se imminente.

+

Potrebbero avvenire aperture sporadiche da parte di membri con accesso 24/7. In tal caso, è bene chiedere se è possibile entrare a chi è presente per evitare spiacevoli inconvenienti (ad esempio, trovare l'hackerspace chiuso all'arrivo!).

+ +

2: Usa

+

L'hackerspace è pieno di attrezzature e spazi di libero utilizzo da parte degli associati. Nessuno può impedire a nessun'altro di goderne, a meno che ciò non vada a ledere a sua volta la possibilità di farlo.

+ +

3: Contribuisci

+

L'hackerspace richiede costi operativi mensili che possono essere più o meno ampi in base alle persone che lo abitano. Spese condominiali, bollette, assicurazione, consumo delle attrezzature...

+

Un hackerspace viene mantenuto dalla sua comunità, ed buona cosa che ogni membro abbia il buonsenso di contribuire almeno quanto pensi di aver giovato dall'hackerspace.

+

Il modo migliore per farlo è economicamente, ma può essere persino più efficace farlo aiutando con idee e azioni fisiche. Nel dubbio, chiedi in giro se qualcuno ha bisogno di qualcosa!

+ + Attenzione: alcuni macchinari hanno costi operativi orari prefissati da cui non è possibile scappare! + +

4: Stai al sicuro

+ +

La sicurezza di tutti è in prima linea, e al Foxolab sono presenti attrezzature che possono mordere e fare male. Utilizzare qualcosa in modo pericoloso significa prendersene piena responsabilità, ma non è meno responsabilità vedere qualcuno farlo e non impedire che accada.

+

Nel caso tu abbia bisogno di aiuto o di formazione, chiedi a qualcuno che ha già usato quelle macchine.

+

Per la sicurezza di tutti, alcune macchine possono essere usate solo in presenza dei loro responsabili!

+ + diff --git a/content/page/statuto.html b/content/page/statuto.html new file mode 100644 index 0000000..a1a44d0 --- /dev/null +++ b/content/page/statuto.html @@ -0,0 +1,114 @@ + + + + Statuto + + + +

Statuto

+
+1. È costituita l'Associazione "Foxolab APS" (di seguito, Associazione), una libera Associazione di fatto, apartitica e apolitica, con durata illimitata nel tempo e senza scopo di lucro nè diretto nè indiretto, regolata a norma del Titolo I Cap. III, art. 36 e segg. del codice civile, nonché del presente Statuto.
+
+2. L'Associazione persegue i seguenti scopi:
+- ampliare la conoscenza della cultura informatica e tecnologica, più precisamente ricalcando i principi della "hacker ethic"
+- promuovere il libero uso delle risorse informatiche, e la sperimentazione per scopi didattici, ricreativi e artistici - con l'obbiettivo di abbattere barriere economiche e sociali che possano impedirlo
+- gestire un "Hackerspace" con impronta nord-europea, un ambiente collaborativo e aperto concepito per favorire la condivisione di conoscenze, la realizzazione di progetti tecnologici, e la creazione di una rete di professionisti e appassionati del settore
+
+3. L'Associazione per il raggiungimento dei suoi fini, intende promuovere varie attività, in particolare:
+- attività culturali: convegni, conferenze, dibattiti, seminari, proiezioni di films e documenti, concerti, lezioni e altro, in presenza o avvalendosi di mezzi informatici, anche in modo ibrido
+- attività di formazione: corsi e laboratori teorico/pratici per i propri membri, istituzione di gruppi di studio e di ricerca;
+- attività editoriale: pubblicazione di contenuti testuali e audiovisivi, artistici, informatici e di ricerca, che perseguiscano i propri scopi
+
+4. L'associazione è offerta a tutti coloro che, interessati alla realizzazione delle finalità istituzionali, ne condividono lo spirito e gli ideali.
+- soci fondatori: le persone che hanno sottoscritto l'atto costitutivo
+- soci ordinari: persone o enti che si impegnano a pagare, per tutta la permanenza del vincolo associativo, la quota annuale stabilita dal Consiglio direttivo
+- soci ordinari: persone, enti o istituzioni che abbiano contribuito in maniera determinante, con la loro opera od il loro sostegno ideale ovvero economico alla costituzione dell'associazione. Hanno carattere e sono esonerati dal versamento di quote annuali
+- soci locali: persone fisiche aventi residenza o domicilio presso il medesimo stabile della sede dell'Associazione. Sono esonerati dal versamento della quota annuale.
+- soci speciali: persone fisiche minorenni, studenti o disoccupati. Sono esonerati dal versamento della quota annuale.
+
+Le quote o il contributo associativo non è trasmissibile ad eccezione dei trasferimenti a causa di morte e non è soggetta a rivalutazione.
+
+5. L'ammissione dei soci ordinari è deliberata, su domanda scritta del richiedente controfirmata da almeno tre soci, dal Consiglio direttivo.
+Contro il rifiuto di ammissione è ammesso appello, entro 30 giorni, al collegio dei probiviri.
+
+6. Tutti i soci sono tenuti a rispettare le norme del presente statuto e il regolamento interno, secondo le deliberazioni assunte dagli organi preposti. In caso di comportamento difforme, che rechi pregiudizio agli scopi o al patrimonio dell'associazione il Consiglio direttivo dovrà intervenire ed potrà applicare le seguenti sanzioni: richiamo, diffida, espulsione della Associazione.
+I soci espulsi possono ricorrere per iscritto contro il provvedimento entro trenta giorni al Collegio dei probiviri.
+
+7. Tutti i soci maggiorenni hanno diritto di voto per l'approvazione e le modificazioni dello statuto e dei regolamenti e per la nomina degli organi direttivi dell'associazione. Il diritto di voto non può essere escluso neppure in caso di partecipazione temporanea alla vita associativa.
+8. Le risorse economiche dell'associazione sono costituite da:
+- beni, immobili e mobili;
+- contributi;
+- donazioni e lasciti;
+- rimborsi;
+- attività marginali di carattere commerciale e produttivo;
+- ogni altro tipo di entrate.
+
+I contributi degli aderenti sono costituiti dalle quote di associazione annuale, stabilite dal Consiglio direttivo e da eventuali contributi straordinari stabiliti dall'assemblea, che ne determina l'ammontare.
+Le elargizioni in danaro, le donazioni e i lasciti, sono accettate dall'assemblea, che delibera sulla utilizzazione di esse, in armonia con finalità statuarie dell'organizzazione. 
+È vietato distribuire, anche in modo indiretto, utili o avanzi di gestione nonché fondi, riserve o capitale durante la vita dell'Associazione, salvo che la destinazione o la distribuzione non siano imposte dalla legge.
+
+9. L'anno finanziario inizia il 1° Gennaio e termina il 31 Dicembre di ogni anno.
+Il Consiglio direttivo deve redigere il bilancio preventivo e quello consuntivo.
+Il bilancio preventivo e consuntivo devono essere approvati dall'Assemblea ordinaria ogni anno entro il mese di Aprile.
+Esso deve essere depositato presso la sede dell'Associazione entro i 15 giorni precedenti la seduta per poter essere consultato da ogni associato.
+
+10. Gli organi dell'Associazione sono:
+- l'assemblea dei soci;
+- il Consiglio direttivo;
+- il Presidente;
+- il Collegio dei revisori;
+- il Collegio dei probiviri;
+
+11. L'assemblea dei soci è il momento fondamentale di confronto, atto ad assicurare una corretta gestione dell'Associazione ed è composta da tutti i soci, ognuno dei quali ha diritto ad un voto, qualunque sia il valore della quota. Essa è convocata almeno una volta all'anno in via ordinaria, ed in via straordinaria quando sia necessaria o sia necessaria o sia richiesta dal Consiglio direttivo o da almeno un decimo degli associati.
+In prima convocazione l'assemblea ordinaria è valida se è presente la maggioranza dei soci, e delibera validamente con la maggioranza dei presenti; in seconda convocazione la validità prescinde dal numero dei presenti.
+L'assemblea straordinaria delibera in prima convocazione con la presenza e col voto favorevole della maggioranza dei soci e in seconda convocazione la validità prescinde dal numero dei presenti.
+La convocazione va fatta con avviso pubblico affisso all'albo della sede almeno 15 giorni prima della data dell'assemblea.
+Delle delibere assembleari deve essere data pubblicità mediante affissione all'albo della sede del relativo verbale.
+
+Gli avvisi pubblici e i verbali verranno altresi pubblicati digitalmente sul sito istituzionale a visione dei membri dell'associazione.
+
+12. L'assemblea ordinaria ha i seguenti compiti:
+- elegge il Consiglio direttivo, il Collegio dei revisori e il Collegio dei probiviri;
+- approva il bilancio preventivi e consuntivo;
+- approva il regolamento interno.
+
+L'assemblea straordinaria delibera sulle modifiche dello Statuto e l'eventuale scioglimento dell'Associazione.
+All'apertura di ogni seduta l'assemblea elegge un presidente ed un segretario che dovranno sottoscrivere il verbale finale.
+
+13. Il consiglio direttivo è composto da 3 membri, eletti dall'Assemblea fra i propri componenti.
+Il Consiglio direttivo è validamente costituito quando sono presenti 2 membri. I membri del Consiglio direttivo svolgono la loro attività gratuitamente e durano in carica 3 anni. Il consiglio direttivo può essere revocato dall'assemblea con la maggioranza di 2/3 dei soci.ù
+
+14. Il Consiglio direttivo è l'organo esecutivo dell'Associazione. Si riunisce in media 2 volte all'anno ed è convocato da:
+- il presidente;
+- da almeno 2 dei componenti, su richiesta motivata;
+- richiesta motivata e scritta di almeno il 30% dei soci.
+
+Il consiglio direttivo ha tutti i poteri di ordinaria e straordinaria amministrazione.
+
+Nella gestione ordinaria i suoi compiti sono:
+- predisporre gli atti da sottoporre all'assemblea;
+- formalizzare le proposte per la gestione dell'Associazione;
+- elaborare il bilancio consuntivo che deve contenere le singole voci di spesa e di entrata relative al periodo di un anno;
+- elaborare il bilancio preventivo che deve contenere, suddivise in singole voci, le previsioni delle spese e delle entrate relative all'esercizio annuale successivo;
+- stabilire gli importi delle quote annuali delle varie categorie di soci;
+
+Di ogni riunione deve essere redatto verbale da affliggere all'albo dell'Associazione.
+
+15. Il presidente dura in carica tre anni ed è legale rappresentante dell'Associazione a tutti gli effetti.
+Egli convoca e presiede il Consiglio direttivo, sottoscrive tutti gli atti amministrativi compiuti dall'Associazione; può aprire e chiudere conti correnti bancari e postali e procedure agli incassi.
+Conferisce ai soci procura speciale per la gestione di attività varie, previa approvazione del Consiglio direttivo.
+
+16. Il Collegio dei revisori è composto da tre soci eletti dall'Assemblea al di fuori dei componenti del Consiglio direttivo. Verifica periodicamente la regolarità formale e sostanziale della contabilità, redige apposita relazione da allegare al bilancio preventivo e consuntivo.
+
+17. Il Collegio dei probiviri è composto da tre soci eletti in assemblea. Dura in carica tre anni.
+Decide insindacabilmente, entro trenta giorni dalla presentazione del ricorso, sulle decisioni di espulsione e sui dinieghi di ammissione.
+
+18. Lo scioglimento dell'Associazione è deliberato da assemblea straordinaria. Il patrimonio residuo dell'ente deve essere devoluto ad associazione con finalità analoghe o per fini di pubblica utilità, sentito l'organismo di controllo di cui all'art. 3, comma 190 della legge 23.12.96, n. 662.
+
+19. Tutte le cariche elettive sono gratuite.
+Ai soci compete solo il rimborso delle spese varie regolarmente documentate.
+
+20. Per quanto non previsto dal presente statuto valgono le norme di legge vigente in maniera.
+		
+ + diff --git a/content/post/test.html b/content/post/test.html new file mode 100644 index 0000000..676c2e3 --- /dev/null +++ b/content/post/test.html @@ -0,0 +1,14 @@ + + + My super title + + + + + + + + + This is the content of my super blog post. + + diff --git a/content/test.html b/content/test.html new file mode 100644 index 0000000..8efa4e2 --- /dev/null +++ b/content/test.html @@ -0,0 +1,12 @@ + + + My super title + + + + + + + This is the content of my super blog post. sex + + diff --git a/foxotheme/static/css/style.css b/foxotheme/static/css/style.css new file mode 100644 index 0000000..e57e3e0 --- /dev/null +++ b/foxotheme/static/css/style.css @@ -0,0 +1,58 @@ + + +:root { + --accent: #1e90ff; + --main: #111; + --bg: #eee; + --bg2: #e3e3e3; + --bg3: #fff; +} + +/* Dark mode alt colors */ +@media (prefers-color-scheme: dark) { + :root { + --main: #ddd; + --bg: #111; + --bg2: #131313; + --bg3: #000; + } + + .dark-invert {filter: invert(1);} +} + +/* Layout */ +body {color:var(--main);background-color: var(--bg);text-align:justify;font-family:'IBM Plex Serif', serif;font-size: 1.1em;} +main {display:block;max-width:55em;margin:1em auto;background:var(--bg);padding:2em;} +header {background: #000;line-height:2.8rem;padding:0.5em 2em;display:flex;align-items: center;justify-content:space-between;} +footer {margin: 1em;text-align: center;} + +nav {display: grid;grid-auto-flow: column;grid-column-gap: 2em} +header a {text-decoration:none;font-family: 'Chakra Petch', sans-serif;} + +/* Text elements */ +p {line-height: 1.5em;font-weight:300;} +dfn {color:var(--accent);text-decoration: underline dashed var(--main) 1px;} +a {color: var(--accent);} +strong {font-weight: 700} + +ul {list-style: none;list-style-position:inside;padding-left:1em} +ul li::before {content: "> ";color:var(--accent);margin:0;} + +/* Headers */ +h1,h2,h3,h4,h5,h6 {font-family: 'Chakra Petch', sans-serif;} +h1 img {height:1.8em;padding:.3em .3em .3em 0;vertical-align:middle;} +h2::before {content: "> ";color:var(--accent);} +h3::before {content: "# ";color:var(--accent);} + +/* Quotes */ +blockquote {display: block;font-style:italic;overflow-x: scroll;padding:1em;margin:1em;border-left: 3px solid var(--accent);} + +/* Code blocks */ +code {font-family: monospace; background: var(--bg3);padding:0.5em 0.5em;} +pre code {display: block;white-space: pre;overflow-x: scroll;padding:1em;margin:1em;border-left: 3px solid var(--accent);} + +.boxes {margin:0;padding:0;display:flex;justify-content:space-around;gap:0.5em;} +.boxes > * {padding: 3em 1em;background:var(--accent);flex: 1 1 0;text-align:center;border-radius:0.4em;background-size:cover;text-shadow: 0 0 5px #000000;} + +.status-closed {color: #FF441F;} +.status-open {color: #1FFF1F;} diff --git a/foxotheme/static/img/favicon.svg b/foxotheme/static/img/favicon.svg new file mode 100644 index 0000000..13d75ad --- /dev/null +++ b/foxotheme/static/img/favicon.svg @@ -0,0 +1,168 @@ + + + + + + image/svg+xml + + + diff --git a/foxotheme/static/img/silhouette.svg b/foxotheme/static/img/silhouette.svg new file mode 100644 index 0000000..e517beb --- /dev/null +++ b/foxotheme/static/img/silhouette.svg @@ -0,0 +1,269 @@ + +image/svg+xml + + + + + + diff --git a/foxotheme/templates/archives.html b/foxotheme/templates/archives.html new file mode 100644 index 0000000..c7fb212 --- /dev/null +++ b/foxotheme/templates/archives.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block title %}{{ SITENAME|striptags }} - Archives{% endblock %} + +{% block content %} +

Archives for {{ SITENAME }}

+ +
+{% for article in dates %} +
{{ article.locale_date }}
+
{{ article.title }}
+{% endfor %} +
+{% endblock %} diff --git a/foxotheme/templates/article.html b/foxotheme/templates/article.html new file mode 100644 index 0000000..9d1f9ef --- /dev/null +++ b/foxotheme/templates/article.html @@ -0,0 +1,65 @@ +{% extends "base.html" %} +{% block html_lang %}{{ article.lang }}{% endblock %} + +{% block title %}{{ SITENAME|striptags }} - {{ article.title|striptags }}{% endblock %} + +{% block head %} + {{ super() }} + + {% import 'translations.html' as translations with context %} + {% if translations.entry_hreflang(article) %} + {{ translations.entry_hreflang(article) }} + {% endif %} + + {% if article.description %} + + {% endif %} + + {% for tag in article.tags %} + + {% endfor %} + +{% endblock %} + +{% block content %} +
+
+

+ {{ article.title }}

+ {% import 'translations.html' as translations with context %} + {{ translations.translations_for(article) }} +
+ {{ article.content }} +
+

Published:

+ {% if article.modified %} +

Last updated:

+ {% endif %} + {% if article.authors %} +
+ By {% for author in article.authors %} + {{ author }} + {% endfor %} +
+ {% endif %} + {% if article.category %} +

+ Category: {{ article.category }} +

+ {% endif %} + {% if article.tags %} +

+ Tags: + {% for tag in article.tags %} + {{ tag }} + {% endfor %} +

+ {% endif %} +
+
+{% endblock %} diff --git a/foxotheme/templates/author.html b/foxotheme/templates/author.html new file mode 100644 index 0000000..9b30dfe --- /dev/null +++ b/foxotheme/templates/author.html @@ -0,0 +1,7 @@ +{% extends "index.html" %} + +{% block title %}{{ SITENAME|striptags }} - Articles by {{ author }}{% endblock %} + +{% block content_title %} +

Articles by {{ author }}

+{% endblock %} diff --git a/foxotheme/templates/authors.html b/foxotheme/templates/authors.html new file mode 100644 index 0000000..01b4f6f --- /dev/null +++ b/foxotheme/templates/authors.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block title %}{{ SITENAME|striptags }} - Authors{% endblock %} + +{% block content %} +

Authors on {{ SITENAME }}

+ +{% endblock %} diff --git a/foxotheme/templates/base.html b/foxotheme/templates/base.html new file mode 100644 index 0000000..8a09d88 --- /dev/null +++ b/foxotheme/templates/base.html @@ -0,0 +1,64 @@ + + + + {% block head %} + {% block title %}{{ SITENAME|striptags }}{% endblock title %} + + + + + + + + {% if SITESUBTITLE %} + + {% endif %} + {% if STYLESHEET_URL %} + + {% endif %} + {% if FEED_ALL_ATOM %} + + {% endif %} + {% if FEED_ALL_RSS %} + + {% endif %} + {% if FEED_ATOM %} + + {% endif %} + {% if FEED_RSS %} + + {% endif %} + {% if CATEGORY_FEED_ATOM and category %} + + {% endif %} + {% if CATEGORY_FEED_RSS and category %} + + {% endif %} + {% if TAG_FEED_ATOM and tag %} + + {% endif %} + {% if TAG_FEED_RSS and tag %} + + {% endif %} + {% endblock head %} + + +
+

{{ SITENAME }}WIP

+ {% if SITESUBTITLE %}

{{ SITESUBTITLE }}

{% endif %} + +
+
+ {% block content %}{% endblock %} +
+ + + diff --git a/foxotheme/templates/categories.html b/foxotheme/templates/categories.html new file mode 100644 index 0000000..7da19fb --- /dev/null +++ b/foxotheme/templates/categories.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block title %}{{ SITENAME|striptags }} - Categories{% endblock %} + +{% block content %} +

Categories on {{ SITENAME }}

+ +{% endblock %} diff --git a/foxotheme/templates/category.html b/foxotheme/templates/category.html new file mode 100644 index 0000000..16525fb --- /dev/null +++ b/foxotheme/templates/category.html @@ -0,0 +1,7 @@ +{% extends "index.html" %} + +{% block title %}{{ SITENAME|striptags }} - {{ category }} category{% endblock %} + +{% block content_title %} +

Articles in the {{ category }} category

+{% endblock %} diff --git a/foxotheme/templates/index.html b/foxotheme/templates/index.html new file mode 100644 index 0000000..c9837b5 --- /dev/null +++ b/foxotheme/templates/index.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} +{% block content %} +{% block content_title %} +

All articles

+{% endblock %} + + +{% for article in articles_page.object_list %} +
+

{{ article.title }}

+
{{ article.summary }}
+
+

Published:

+
By + {% for author in article.authors %} + {{ author }} + {% endfor %} +
+
+
+{% endfor %} + +{% if articles_page.has_other_pages() %} + {% include 'pagination.html' %} +{% endif %} + +{% endblock content %} diff --git a/foxotheme/templates/page.html b/foxotheme/templates/page.html new file mode 100644 index 0000000..c9c2c7c --- /dev/null +++ b/foxotheme/templates/page.html @@ -0,0 +1,26 @@ +{% extends "base.html" %} +{% block html_lang %}{{ page.lang }}{% endblock %} + +{% block title %}{{ SITENAME|striptags }} - {{ page.title|striptags }}{%endblock%} + +{% block head %} + {{ super() }} + + {% import 'translations.html' as translations with context %} + {% if translations.entry_hreflang(page) %} + {{ translations.entry_hreflang(page) }} + {% endif %} +{% endblock %} + +{% block content %} + {% import 'translations.html' as translations with context %} + {{ translations.translations_for(page) }} + + {{ page.content }} +{% endblock %} + +{% block footer %} + {% if page.modified %} +

Last updated: {{page.locale_modified}}

+ {% endif %} +{% endblock %} diff --git a/foxotheme/templates/pagination.html b/foxotheme/templates/pagination.html new file mode 100644 index 0000000..45e7f16 --- /dev/null +++ b/foxotheme/templates/pagination.html @@ -0,0 +1,17 @@ +{% if DEFAULT_PAGINATION %} +{% set first_page = articles_paginator.page(1) %} +{% set last_page = articles_paginator.page(articles_paginator.num_pages) %} + +{% endif %} diff --git a/foxotheme/templates/period_archives.html b/foxotheme/templates/period_archives.html new file mode 100644 index 0000000..595def5 --- /dev/null +++ b/foxotheme/templates/period_archives.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} + +{% block title %}{{ SITENAME|striptags }} - {{ period | reverse | join(' ') }} archives{% endblock %} + +{% block content %} +

Archives for {{ period | reverse | join(' ') }}

+ +
+{% for article in dates %} +
{{ article.locale_date }}
+
{{ article.title }}
+{% endfor %} +
+{% endblock %} diff --git a/foxotheme/templates/tag.html b/foxotheme/templates/tag.html new file mode 100644 index 0000000..f9b71f4 --- /dev/null +++ b/foxotheme/templates/tag.html @@ -0,0 +1,7 @@ +{% extends "index.html" %} + +{% block title %}{{ SITENAME|striptags }} - {{ tag }} tag{% endblock %} + +{% block content_title %} +

Articles tagged with {{ tag }}

+{% endblock %} diff --git a/foxotheme/templates/tags.html b/foxotheme/templates/tags.html new file mode 100644 index 0000000..6b5c6b1 --- /dev/null +++ b/foxotheme/templates/tags.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block title %}{{ SITENAME|striptags }} - Tags{% endblock %} + +{% block content %} +

Tags for {{ SITENAME }}

+ +{% endblock %} diff --git a/foxotheme/templates/translations.html b/foxotheme/templates/translations.html new file mode 100644 index 0000000..f0e2478 --- /dev/null +++ b/foxotheme/templates/translations.html @@ -0,0 +1,16 @@ +{% macro translations_for(article) %} +{% if article.translations %} +Translations: +{% for translation in article.translations %} +{{ translation.lang }} +{% endfor %} +{% endif %} +{% endmacro %} + +{% macro entry_hreflang(entry) %} +{% if entry.translations %} + {% for translation in entry.translations %} + + {% endfor %} +{% endif %} +{% endmacro %} diff --git a/pelicanconf.py b/pelicanconf.py new file mode 100644 index 0000000..83ef386 --- /dev/null +++ b/pelicanconf.py @@ -0,0 +1,70 @@ +# Site info +AUTHOR = 'Foxolab APS' +SITENAME = 'Foxolab' +SITEURL = "https://lab.foxo.me" + +# Paths +PATH = "content" +PAGE_PATHS = ['page'] +ARTICLE_PATHS = ['post'] + +# Assume every article/page has no category and is in italian +DEFAULT_METADATA = { + 'lang': 'it' +} + +# Time and Language +TIMEZONE = 'Europe/Rome' + +DEFAULT_LANG = 'it' +DEFAULT_DATE = 'fs' + +# Feed generation is usually not desired when developing +FEED_ALL_ATOM = None +CATEGORY_FEED_ATOM = None +TRANSLATION_FEED_ATOM = None +AUTHOR_FEED_ATOM = None +AUTHOR_FEED_RSS = None + +# Theme +THEME = 'foxotheme' +THEME_STATIC_DIR = '' +CSS_FILE = 'style.css' + +# Menu items +MENUITEMS = ( + ("Homepage", "/"), +# ("Net", "/net.html"), +# ("Labs", "/labs/"), +# ("Where", "/where.html"), + +) + +# Blogroll +LINKS = ( + ("Pelicaan", "https://getpelican.com/"), + ("Python.org", "https://www.python.org/"), + ("Jinja2", "https://palletsprojects.com/p/jinja/"), + ("You can modify those links in your config file", "#"), +) + +# Social widget +SOCIAL = ( + ("You can add links in your config file", "#"), + ("Another social link", "#"), +) + +SLUGIFY_SOURCE = 'basename' + +DEFAULT_PAGINATION = False + +# Uncomment following line if you want document-relative URLs when developing +RELATIVE_URLS = True + +ARTICLE_SAVE_AS = 'post/{slug}.html' +ARTICLE_URL = 'post/{slug}.html' + +PAGE_SAVE_AS = '{slug}.html' +PAGE_URL = '{slug}.html' + +INDEX_SAVE_AS = '' diff --git a/publishconf.py b/publishconf.py new file mode 100644 index 0000000..982374c --- /dev/null +++ b/publishconf.py @@ -0,0 +1,22 @@ +# This file is only used if you use `make publish` or +# explicitly specify it as your config file. + +import os +import sys + +sys.path.append(os.curdir) +from pelicanconf import * + +# If your site is available via HTTPS, make sure SITEURL begins with https:// +SITEURL = "https://lab.foxo.me" +RELATIVE_URLS = False + +FEED_ALL_ATOM = "feeds/all.atom.xml" +CATEGORY_FEED_ATOM = "feeds/{slug}.atom.xml" + +DELETE_OUTPUT_DIRECTORY = True + +# Following items are often useful when publishing + +# DISQUS_SITENAME = "" +# GOOGLE_ANALYTICS = "" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..fa95caf --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pelican diff --git a/tasks.py b/tasks.py new file mode 100644 index 0000000..16ba5e9 --- /dev/null +++ b/tasks.py @@ -0,0 +1,147 @@ +import os +import shlex +import shutil +import sys +import datetime + +from invoke import task +from invoke.main import program +from invoke.util import cd +from pelican import main as pelican_main +from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer +from pelican.settings import DEFAULT_CONFIG, get_settings_from_file + +OPEN_BROWSER_ON_SERVE = True +SETTINGS_FILE_BASE = "pelicanconf.py" +SETTINGS = {} +SETTINGS.update(DEFAULT_CONFIG) +LOCAL_SETTINGS = get_settings_from_file(SETTINGS_FILE_BASE) +SETTINGS.update(LOCAL_SETTINGS) + +CONFIG = { + "settings_base": SETTINGS_FILE_BASE, + "settings_publish": "publishconf.py", + # Output path. Can be absolute or relative to tasks.py. Default: 'output' + "deploy_path": SETTINGS["OUTPUT_PATH"], + # Host and port for `serve` + "host": "localhost", + "port": 8000, +} + + +@task +def clean(c): + """Remove generated files""" + if os.path.isdir(CONFIG["deploy_path"]): + shutil.rmtree(CONFIG["deploy_path"]) + os.makedirs(CONFIG["deploy_path"]) + + +@task +def build(c): + """Build local version of site""" + pelican_run("-s {settings_base}".format(**CONFIG)) + + +@task +def rebuild(c): + """`build` with the delete switch""" + pelican_run("-d -s {settings_base}".format(**CONFIG)) + + +@task +def regenerate(c): + """Automatically regenerate site upon file modification""" + pelican_run("-r -s {settings_base}".format(**CONFIG)) + + +@task +def serve(c): + """Serve site at http://$HOST:$PORT/ (default is localhost:8000)""" + + class AddressReuseTCPServer(RootedHTTPServer): + allow_reuse_address = True + + server = AddressReuseTCPServer( + CONFIG["deploy_path"], + (CONFIG["host"], CONFIG["port"]), + ComplexHTTPRequestHandler, + ) + + if OPEN_BROWSER_ON_SERVE: + # Open site in default browser + import webbrowser + + webbrowser.open("http://{host}:{port}".format(**CONFIG)) + + sys.stderr.write("Serving at {host}:{port} ...\n".format(**CONFIG)) + server.serve_forever() + + +@task +def reserve(c): + """`build`, then `serve`""" + build(c) + serve(c) + + +@task +def preview(c): + """Build production version of site""" + pelican_run("-s {settings_publish}".format(**CONFIG)) + +@task +def livereload(c): + """Automatically reload browser tab upon file modification.""" + from livereload import Server + + def cached_build(): + cmd = "-s {settings_base} -e CACHE_CONTENT=true LOAD_CONTENT_CACHE=true" + pelican_run(cmd.format(**CONFIG)) + + cached_build() + server = Server() + theme_path = SETTINGS["THEME"] + watched_globs = [ + CONFIG["settings_base"], + f"{theme_path}/templates/**/*.html", + ] + + content_file_extensions = [".md", ".rst"] + for extension in content_file_extensions: + content_glob = "{}/**/*{}".format(SETTINGS["PATH"], extension) + watched_globs.append(content_glob) + + static_file_extensions = [".css", ".js"] + for extension in static_file_extensions: + static_file_glob = f"{theme_path}/static/**/*{extension}" + watched_globs.append(static_file_glob) + + for glob in watched_globs: + server.watch(glob, cached_build) + + if OPEN_BROWSER_ON_SERVE: + # Open site in default browser + import webbrowser + + webbrowser.open("http://{host}:{port}".format(**CONFIG)) + + server.serve(host=CONFIG["host"], port=CONFIG["port"], root=CONFIG["deploy_path"]) + + +@task +def publish(c): + """Publish to production via rsync""" + pelican_run("-s {settings_publish}".format(**CONFIG)) + c.run( + 'rsync --delete --exclude ".DS_Store" -pthrvz -c ' + '-e "ssh -p {ssh_port}" ' + "{} {ssh_user}@{ssh_host}:{ssh_path}".format( + CONFIG["deploy_path"].rstrip("/") + "/", **CONFIG + ) + ) + + +def pelican_run(cmd): + cmd += " " + program.core.remainder # allows to pass-through args to pelican + pelican_main(shlex.split(cmd)) \ No newline at end of file