ソースを参照

Merge pull request #1 from awesome-selfhosted/master

Sync fork
Pietro Marangon 5 年 前
コミット
fc1da4f90b
9 ファイル変更631 行追加352 行削除
  1. 4 4
      .github/CONTRIBUTING.md
  2. 9 12
      .github/PULL_REQUEST_TEMPLATE.md
  3. 9 10
      .travis.yml
  4. 79 11
      AUTHORS.md
  5. 34 54
      Makefile
  6. 260 186
      README.md
  7. 12 11
      non-free.md
  8. 1 1
      tests/check-github-commit-dates.py
  9. 223 63
      tests/test.js

+ 4 - 4
.github/CONTRIBUTING.md

@@ -1,16 +1,16 @@
 ## Contributing
 
-Please open a new issue to clarify any questions, or post in the [General discussion issue](https://github.com/Kickball/awesome-selfhosted/issues/89).
+Please open a new issue to clarify any questions, or post in the [General discussion issue](https://github.com/awesome-selfhosted/awesome-selfhosted/issues/89).
 
 All guidelines for adding new software to the list are listed in [PULL_REQUEST_TEMPLATE.md](PULL_REQUEST_TEMPLATE.md).
 
 Other recommendations:
 
-- To add a new entry, [edit the README.md file](https://github.com/Kickball/awesome-selfhosted/edit/master/README.md) through Github's web interface or a text editor, and send a Pull Request.
+- To add a new entry, [edit the README.md file](https://github.com/awesome-selfhosted/awesome-selfhosted/edit/master/README.md) through Github's web interface or a text editor, and send a Pull Request.
 - See [Editing files in another user's repository](https://help.github.com/articles/editing-files-in-another-user-s-repository/), [Creating Pull Requests](https://help.github.com/articles/creating-a-pull-request/), [Using Pull Requests](https://help.github.com/articles/using-pull-requests/) for help on sending your patch.
-- A script to help you format new entries is available at (it requires `make` to be installed): `git clone`/[download](https://github.com/Kickball/awesome-selfhosted/archive/master.zip) and enter the repository, run `make add` and follow the instructions.
+- A script to help you format new entries is available at (it requires `make` to be installed): `git clone`/[download](https://github.com/awesome-selfhosted/awesome-selfhosted/archive/master.zip) and enter the repository, run `make add` and follow the instructions.
 - A website to help you format new entries is available at https://n8225.github.io/
 - The list of contributors can be updated with `make contrib`. 
 - Software with no development activity for 6-12 months may be removed from the list.
-- Don't know where to start? Check issues labeled [`help wanted`](https://github.com/Kickball/awesome-selfhosted/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) and [`fix`](https://github.com/Kickball/awesome-selfhosted/issues?q=is%3Aissue+is%3Aopen+label%3Afix).
+- Don't know where to start? Check issues labeled [`help wanted`](https://github.com/awesome-selfhosted/awesome-selfhosted/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) and [`fix`](https://github.com/awesome-selfhosted/awesome-selfhosted/issues?q=is%3Aissue+is%3Aopen+label%3Afix).
 

+ 9 - 12
.github/PULL_REQUEST_TEMPLATE.md

@@ -2,26 +2,23 @@ Thank you for taking the time to work on a PR for Awesome-Selfhosted!
 
 To ensure your PR is dealt with swiftly please check the following:
 
-- [ ] Your submissions are formatted according to the following requirements:
-        
+- [ ] Your submissions are formatted according to the following requirements (`Demo` and `Clients` are optional, don't add a duplicate `Source code` link if it is the same as the main link):
+
 ``- [Name](http://homepage/) - Short description, less than 250 characters. ([Demo](http://url.to/demo), [Source Code](http://url.of/source/code), [Clients](https://url.to/list/of/related/clients-or-apps)) `License` `Language` ``
 
-Depends on proprietary services:
+- [ ] If your additions depend on proprietary services outside the user's control, they must be marked `⚠`.
 
 ``- [Name](http://homepage/) `⚠` - Short description, less than 250 characters. ([Demo](http://url.to/demo), [Source Code](http://url.of/source/code), [Clients](https://url.to/list/of/related/clients-or-apps)) `License` `Language` ``
 
-Non-free software in `non-free.md`:
+- [ ] Additions that are not [Free software](https://en.wikipedia.org/wiki/Free_software) must be added to `non-free.md` and marked `⊘ Proprietary`:
 
 ``- [Name](http://homepage/) `⊘ Proprietary` - Short description, less than 250 characters. ([Demo](http://url.to/demo), [Source Code](http://url.of/source/code), [Clients](https://url.to/list/of/related/clients-or-apps)) `Language` ``
 
-
 - [ ] Your additions are ordered alphabetically.
-- [ ] Your additions are [Free software](https://en.wikipedia.org/wiki/Free_software), or if not they have been added to [non-free](non-free.md) and marked `⊘ Proprietary`.
-- [ ] If your additions depend on proprietary services outside the user's control, they must be marked `⚠`.
-- [ ] Your additions are not already listed at [awesome-sysadmin](https://github.com/n1trux/awesome-sysadmin) (IT infrastructure management), [staticgen.com](https://www.staticgen.com/) or [staticsitegenerators.net](https://staticsitegenerators.net/) (static site generators).
-- [ ] Your additions have their `License` main server-side `Language`/platform/requirement listed.
-- [ ] Any licenses you have added are in our [list of licenses](https://github.com/Kickball/awesome-selfhosted/blob/master/README.md#list-of-licenses).
-- [ ] You have searched the repository for any relevant [issues](https://github.com/Kickball/awesome-selfhosted/issues) or [PRs](https://github.com/Kickball/awesome-selfhosted/pulls), including closed ones.
-- [ ] If the main link of your addition points to the program's source code, there is no need to add a duplicate _Source Code_ link. The _Demo_ and _Clients_ links are not mandatory.
+- [ ] Your additions are not already listed at [awesome-sysadmin](https://github.com/n1trux/awesome-sysadmin) (IT infrastructure management), [awesome-analytics](https://github.com/onurakpolat/awesome-analytics) (analytics), [staticgen.com](https://www.staticgen.com/) or [staticsitegenerators.net](https://staticsitegenerators.net/) (static site generators).
+- [ ] The `Language` tag is the main server-side requirement for the software - don't include frameworks/specifc dialects.
+- [ ] Any licenses you have added are in our [list of licenses](https://github.com/awesome-selfhosted/awesome-selfhosted/blob/master/README.md#list-of-licenses).
+- [ ] You have searched the repository for any relevant [issues](https://github.com/awesome-selfhosted/awesome-selfhosted/issues) or [PRs](https://github.com/awesome-selfhosted/awesome-selfhosted/pulls), including closed ones.
 - [ ] Any category you are creating has the minimum requirement of 3 items. If not, your addition may be inserted into `Misc/Other`.
 - [ ] Any software project you are adding to the list is actively maintained.
+- [ ] The pull request title is "Add aaa to bbb" for adding software aaa to section bbb. Do not call it "Update README.md".

+ 9 - 10
.travis.yml

@@ -2,21 +2,20 @@ language: node_js
 
 node_js:
   - "node"
-  
+
+cache:
+  npm: false
+
 before_install:
   - rvm install 2.6.2
   - gem install awesome_bot
-
-before_script:
+  - sudo apt update && sudo apt install python3-pip python3-setuptools
+  - cd tests && npm install chalk && cd ..
 
 script:
-  - 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then git diff origin/master -U0 README.md | grep -Pos "(?<=^\+).*" >> temp.md; fi || (exit 0)'
-  - 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then node tests/test.js temp.md; else node tests/test.js README.md; fi'
-  - 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then if [ -f temp.md ]; then awesome_bot temp.md --allow-redirect --skip-save-results; else (exit 0); fi else awesome_bot README.md --allow-redirect --skip-save-results; fi'
+  - 'echo "DEBUG: $TRAVIS_BRANCH - $TRAVIS_EVENT_TYPE - $TRAVIS_PULL_REQUEST"'
+  - 'if [[ "$TRAVIS_BRANCH" == "master" && "$TRAVIS_EVENT_TYPE" == "cron" ]]; then make check_all; fi'
+  - 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then make check_pr; fi'
 
 notifications:
   email: false
-
-branches:
-  only:
-  - master

+ 79 - 11
AUTHORS.md

@@ -1,31 +1,34 @@
 |Commits | Author |
 | :---: | --- |
-|920|nodiscc <nodiscc@gmail.com>|
+|1032|nodiscc <nodiscc@gmail.com>|
 |319|Kickball <ed.kickball@hotmail.com>|
-|215|n8225 <n8225@users.noreply.github.com>|
+|253|n8225 <n8225@users.noreply.github.com>|
 |122|Andrew Rylatt <arylatt@users.noreply.github.com>|
+|77|Meitar M <meitarm@gmail.com>|
 |35|Kovah <mail@kovah.de>|
 |31|DJCrashdummy <DJCrashdummy@users.noreply.github.com>|
+|26|worldworm <13227454+worldworm@users.noreply.github.com>|
 |23|cave beat <cave@cavebeat.org>|
 |17|Thomas Dalichow <info@thomasdalichow.de>|
-|16|Meitar M <meitarm@gmail.com>|
 |14|Miguel Piedrafita <github@miguelpiedrafita.com>|
 |13|jungle-boogie <sean@jungleboogie.me>|
 |12|Alex <alex@maximum.guru>|
 |12|Ferdinand Mütsch <mail@ferdinand-muetsch.de>|
 |12|Pe46dro <pietro@marangon.me>|
+|11|Pietro Marangon <pietro.marangon@gmail.com>|
 |9|Andrew Peng <pengc99@gmail.com>|
 |9|Joubert RedRat <eu+github@redrat.com.br>|
 |9|Lance M <mightyfree@users.noreply.github.com>|
 |9|cave <cavebeat@users.noreply.github.com>|
 |8|CooperBarrett <anthony.lhuissier@openmailbox.org>|
 |8|Nick Busey <NickBusey@users.noreply.github.com>|
-|8|Pietro Marangon <pietro.marangon@gmail.com>|
 |7|Hammy Havoc <hammy@splitanatom.com>|
 |7|Ilian <ugg.rock@gmail.com>|
+|7|aubrel <red_clover@riseup.net>|
 |7|n1trux <n1trux@users.noreply.github.com>|
 |7|phre4k <me@phre4k.at>|
 |7|édouard u. <mail@edouard.us>|
+|6|Jorge E. Gomez <jegomez@agofer.com.co>|
 |6|Per Guth <mail@perguth.de>|
 |6|Quinn Comendant <quinn@strangecode.com>|
 |6|Touhid Arastu <touhid.arastu@gmail.com>|
@@ -38,10 +41,13 @@
 |5|Max Maischein <github@corion.net>|
 |5|Mohammad Faisal <faisalhmohd@live.com>|
 |5|Moti Korets <moti.kor@gmail.com>|
+|5|Muhammad Hussein Fattahizadeh <m@mhf.ir>|
 |5|Philip Kirkbride <kirkins@gmail.com>|
 |5|Surgie Finesse <finesserus@gmail.com>|
+|5|azlux <github@azlux.fr>|
 |5|mestaritonttu <mestaritonttu@mail.com>|
 |4|/c² <cagataycali@icloud.com>|
+|4|Alejandro Celaya <alejandrocelaya@gmail.com>|
 |4|AlessioCasco <cascoalessio@gmail.com>|
 |4|Alexander Litreev <alxdrlitreev@users.noreply.github.com>|
 |4|Alexandr Emelin <frvzmb@gmail.com>|
@@ -49,12 +55,14 @@
 |4|Andrey Semakin <and-semakin@ya.ru>|
 |4|Aravindo Wingeier <synox@users.noreply.github.com>|
 |4|Arda Kılıçdağı <ardakilicdagi@gmail.com>|
+|4|Bob van Luijt <bob@semi.technology>|
 |4|Christian Bayer <cave@cavebeat.org>|
 |4|Cody Heimberger <cody.heimberger@printerlogic.com>|
 |4|Colin Pokowitz <colin@cpdev.me>|
 |4|Colin Pokowitz <colinpokowitz03@gmail.com>|
 |4|Cory Gibbons <hello@corygibbons.com>|
 |4|D <DL88250@gmail.com>|
+|4|Dave Lockwood <1261876+deamos@users.noreply.github.com>|
 |4|Dominik Pfaffenbauer <dominik@lineofcode.at>|
 |4|Dr. Azrael Tod <github.com@g33ky.de>|
 |4|Eliot Whalan <ewhal@pantsu.cat>|
@@ -66,15 +74,18 @@
 |4|Joery Zegers <accounts@jzegers.nl>|
 |4|Jorge E. Gomez <jorge@jorgee.net>|
 |4|Joshua Westerheide <dev@jdoubleu.de>|
+|4|Koichi MATSUMOTO <mzch@mac.com>|
 |4|MK <kohenkatz@gmail.com>|
 |4|Mancy <abdullah.mancy@gmail.com>|
 |4|Marius Voila <marius.voila@gmail.com>|
+|4|Meitar M <meitarm+github.1djyXhCkVsRYzZRk@gmail.com>|
 |4|Rodolfo Berrios <inbox@rodolfoberrios.com>|
 |4|Sebastian Stehle <sebastian@squidex.io>|
 |4|Tony <goofballtech@gmail.com>|
 |4|Valmik <mail@valmik.in>|
 |4|apacketofsweets <19573127+apacketofsweets@users.noreply.github.com>|
 |4|bysslord <wxwlegend@gmail.com>|
+|4|cthu1hoo <47687909+cthu1hoo@users.noreply.github.com>|
 |4|dattaz <taz@dattaz.fr>|
 |4|dpfaffenbauer <dominik@lineofcode.at>|
 |4|dyu <david.yu.ftw@gmail.com>|
@@ -84,6 +95,7 @@
 |3|Akhyar Amarullah <akhyrul@gmail.com>|
 |3|Alexey Velikiy <gmpota@gmail.com>|
 |3|BernsteinA <4685390+BernsteinA@users.noreply.github.com>|
+|3|Brandon Jones <brandon@radroot.com>|
 |3|Burak Emre Kabakcı <emrekabakci@gmail.com>|
 |3|Conor O'Callaghan <brioscaibriste@users.noreply.github.com>|
 |3|Cédric Krier <cedk@users.noreply.github.com>|
@@ -92,6 +104,7 @@
 |3|Erik <erikhubers@users.noreply.github.com>|
 |3|Ethan Lowman <ethanal@users.noreply.github.com>|
 |3|FoxMaSk <foxmask@users.noreply.github.com>|
+|3|Francisco Gálvez <crishnakh@users.noreply.github.com>|
 |3|François-Xavier Lyonnet du Moutier <fx.du.moutier@gmail.com>|
 |3|Gabin <hello@gabinaureche.com>|
 |3|Garrett Martin <me@garrettqmartin.com>|
@@ -100,17 +113,21 @@
 |3|Harvey Kandola <harvey@documize.com>|
 |3|Ilya Pirozhenko <ilya.pir@gmail.com>|
 |3|IrosTheBeggar <paul.sori@gmail.com>|
+|3|James Cole <thegrumpydictator@gmail.com>|
 |3|Jiří Komárek <xkomczax@centrum.cz>|
 |3|Kevin Hinterlong <kevinhinterlong@users.noreply.github.com>|
 |3|Lee Watson <rev@revthefox.co.uk>|
 |3|Leo Gaggl <leo@brightcookie.com.au>|
 |3|Marc Picaud <picaud.marc@gmail.com>|
+|3|MarceauKa <MarceauKa@users.noreply.github.com>|
 |3|Mariusz Kozakowski <11mariom+wordpress@gmail.com>|
 |3|Martin Gontovnikas <martin@gon.to>|
 |3|Mathieu Leplatre <mathieu@leplat.re>|
 |3|Matt Baer <matt@baer.works>|
 |3|Mitchell Urgero <info@urgero.org>|
 |3|Morris Jobke <hey@morrisjobke.de>|
+|3|Nick Fox <nick.fox@jobsite.co.uk>|
+|3|No GUI <evaryont@users.noreply.github.com>|
 |3|Ovidiu Dan <zmarty@users.noreply.github.com>|
 |3|Pavan Yara <yarapavan@gmail.com>|
 |3|Peter Thaleikis <spekulatius@users.noreply.github.com>|
@@ -121,17 +138,22 @@
 |3|Roland Whitehead <4478022+qururoland@users.noreply.github.com>|
 |3|Ryan DeShone <rfdeshon@gmail.com>|
 |3|Sergio Brighenti <sergio@brighenti.me>|
+|3|Sung Won Cho <sung@monomax.sh>|
 |3|Tobi Schäfer <interface@p3k.org>|
 |3|Yann Forget <forget.yann31@gmail.com>|
 |3|Ye Lin Aung <me@yelinaung.com>|
 |3|Yuchen Ying <github.com@yegle.net>|
+|3|ddffnn <ddffnn@users.noreply.github.com>|
 |3|icterine <account@caravat.e4ward.com>|
 |3|jungle-boogie <sean@rastasean.net>|
 |3|moba <moba@users.noreply.github.com>|
 |3|oknozor <paul.delafosse@protonmail.com>|
 |3|pszlazak <pszlazak@users.noreply.github.com>|
 |3|rett gerst <rettgerst@users.noreply.github.com>|
+|3|sapioit <sapioit@users.noreply.github.com>|
+|3|slauzon <seth.lauzon@gmail.com>|
 |3|xBytez <git@xbytez.io>|
+|2|0xflotus <0xflotus@gmail.com>|
 |2|132ikl <132@ikl.sh>|
 |2|A. Cynic <chris@mretc.net>|
 |2|Aditya Nagla <me@imadityang.xyz>|
@@ -149,12 +171,14 @@
 |2|Bartłomiej Kurzeja <B3QL@users.noreply.github.com>|
 |2|Ben Yanke <ben@benyanke.com>|
 |2|Benjamin Gamard <benjamin.gam@gmail.com>|
+|2|Braintelligence <Braintelligence@users.noreply.github.com>|
 |2|Brendan Abolivier <contact@brendanabolivier.com>|
 |2|Brian Morin <bdmorin@gmail.com>|
 |2|Carlo F. Quaglia <cfq20@users.noreply.github.com>|
 |2|Charles Farence III <charles@charlessite90.com>|
 |2|Chris Missal <chris.missal@gmail.com>|
 |2|Christopher Charbonneau Wells <cdubz@users.noreply.github.com>|
+|2|Cleberson Ramirio <cleberson.ramirio@outlook.com>|
 |2|Costin Moise <necenzurat@gmail.com>|
 |2|Daniel Heath <daniel@heath.cc>|
 |2|Daniel Ramirez Grave de Peralta <dxas90@gmail.com>|
@@ -167,10 +191,12 @@
 |2|Dominic Pratt <github@dominicpratt.de>|
 |2|Dr. Ridgewell <ridgewell@users.noreply.github.com>|
 |2|Eliot Berriot <contact@eliotberriot.com>|
+|2|Fabian Schliski <Kombustor@users.noreply.github.com>|
 |2|Feleg <fegul@users.noreply.github.com>|
 |2|Felix Bartels <felix@host-consultants.de>|
 |2|Gabin Aureche <gabin.aureche@live.fr>|
 |2|Gabriel Cossette <gabriel.cossette@gmail.com>|
+|2|Gerardo Baez <g@gerardobaez.com>|
 |2|Gleb Mazovetskiy <glex.spb@gmail.com>|
 |2|Gonçalo Valério <dethos@users.noreply.github.com>|
 |2|Greg Slepak <contact@taoeffect.com>|
@@ -178,13 +204,15 @@
 |2|Haukur Rosinkranz <hauxir@gmail.com>|
 |2|Henry Ruhs <info@redaxmedia.com>|
 |2|Hilmi Tolga Sahin <htolgasahin@gmail.com>|
+|2|Ivan Krutov <vania-pooh@vania-pooh.com>|
 |2|Jake Breindel <j.breindel2@outlook.com>|
 |2|Jake Jarvis <jakejarvis@gmail.com>|
-|2|James Cole <thegrumpydictator@gmail.com>|
 |2|Jan <jaltek@users.noreply.github.com>|
 |2|Jan Soendermann <jan.soendermann+git@gmail.com>|
 |2|Jared Shields <jwshields2006@hotmail.com>|
+|2|Jipok <braaga@inbox.ru>|
 |2|Jonas L <jooola@users.noreply.github.com>|
+|2|Jordon Replogle <jordon.replogle@blueletterbible.org>|
 |2|Joseph Dykstra <josephdykstra@gmail.com>|
 |2|Julien Bisconti <veggiemonk@users.noreply.github.com>|
 |2|Jérémie Astori <jeremie@astori.fr>|
@@ -198,7 +226,9 @@
 |2|Malte Kiefer <malte.kiefer@mailgermania.de>|
 |2|Manuel Uberti <manuel-uberti@users.noreply.github.com>|
 |2|Marc Laporte <marc@laporte.name>|
+|2|Marcel Brückner <marcelbrueckner@gmx.de>|
 |2|Marien Fressinaud <dev@marienfressinaud.fr>|
+|2|Marius Lindvall <marius@varden.info>|
 |2|Markus M. Deuerlein <mdeuerlein@users.noreply.github.com>|
 |2|MarkusMcNugen <marknewton5@gmail.com>|
 |2|Martijn <mrtijn@riseup.net>|
@@ -214,7 +244,9 @@
 |2|Nicolas Carlier <n.carlier@nunux.org>|
 |2|Oliver Giles <ohw.giles@gmail.com>|
 |2|Patrik Ragnarsson <patrik@starkast.net>|
+|2|Pavel Korotkiy <outdead@mail.ru>|
 |2|Pavel Lobashov <ShockwaveNN@gmail.com>|
+|2|Pernat1y <mirnesen@gmail.com>|
 |2|Peter Demin <poslano@gmail.com>|
 |2|Peter Ivanov <peter@microweber.com>|
 |2|Phil <phil@sapphyrus.xyz>|
@@ -233,6 +265,7 @@
 |2|Sam Tuke <mail@samtuke.com>|
 |2|Sameer Al-Sakran <salsakran@users.noreply.github.com>|
 |2|Sandeep S <ghostpirate@users.noreply.github.com>|
+|2|Sandro <sandro.jaeckel@posteo.de>|
 |2|Scot Hacker <shacker@birdhouse.org>|
 |2|Shane Cooke <shanecooke@mac.com>|
 |2|Simon Vieille <simon@deblan.fr>|
@@ -246,6 +279,7 @@
 |2|Think <iwhiz@users.noreply.github.com>|
 |2|Thomas Citharel <tcit@tcit.fr>|
 |2|Tomer <tomer@campuscruizer.com>|
+|2|Tomer Cohen <tomer@users.noreply.github.com>|
 |2|Tony Xu <yihan.xu@gmail.com>|
 |2|Vadim Rutkovsky <vrutkovs@redhat.com>|
 |2|Valentino Pesce <valentino@iltuobrand.it>|
@@ -268,24 +302,27 @@
 |2|jciskey <jciskey@gmail.com>|
 |2|jganobsik <39414138+jganobsik@users.noreply.github.com>|
 |2|jimykk <JimyKK@users.noreply.github.com>|
+|2|jtagcat <38327267+jtagcat@users.noreply.github.com>|
 |2|markkrj <markkrj@users.noreply.github.com>|
 |2|maximesrd <maximesrd@maximesourdin.ovh>|
 |2|rafael-santiago <voidbrainvoid@gmail.com>|
 |2|thomasfrivold <thomas.frivold@gmail.com>|
 |2|tillarnold <throwable42@gmail.com>|
 |2|tomc3 <wordoftheday003@gmail.com>|
-|2|worldworm <13227454+worldworm@users.noreply.github.com>|
 |2|xy2z <xy2z@users.noreply.github.com>|
 |2|yuche <i@yuche.me>|
 |2|ziλa sarikaya <sarikayaziya@gmail.com>|
 |2|znegva <znegva@users.noreply.github.com>|
+|2|Žygimantas Medelis <zygimantas.medelis@tokenmill.lt>|
 |2|王可森 <wangkesen@users.noreply.github.com>|
 |1|4oo4 <4oo4@users.noreply.github.com>|
 |1|Aaron <44198148+whalehub@users.noreply.github.com>|
 |1|Adam C <39806482+adam-redcort@users.noreply.github.com>|
 |1|Adam Johnson <me@adamj.eu>|
+|1|Adrian Kumpf <adrian.kumpf@posteo.de>|
 |1|Akos Veres <veres@akos.me>|
 |1|Alashov Berkeli <yunus.alashow@gmail.com>|
+|1|Alberto Bertogli <albertito@blitiri.com.ar>|
 |1|Alejandro Rodríguez <arcxyz@users.noreply.github.com>|
 |1|Alex Fornuto <alex@fornuto.com>|
 |1|Alex Yumashev <33555768+alex-jitbit@users.noreply.github.com>|
@@ -316,11 +353,16 @@
 |1|Austin <austi_gillm935@ahapps.anoka.k12.mn.us>|
 |1|BN <biczoxd@gmail.com>|
 |1|Bas <mega@ioexception.at>|
+|1|Bastien Wirtz <bastien.wirtz@gmail.com>|
 |1|Beard of War <rebelgeek@blainsmith.com>|
 |1|Ben <ben@rngr.org>|
 |1|Ben Abbott <ben@benabbott.nz>|
+|1|Benj Fassbind <randombenj@gmail.com>|
 |1|Benjamin Lange <benjamin.r.lange@gmail.com>|
+|1|Bernd Bestel <bernd@berrnd.de>|
+|1|Bharat Kalluri <bharatkalluri@protonmail.com>|
 |1|Blake Bourque <Techplex.Engineer@gmail.com>|
+|1|Bob "Wombat" Hogg <wombat@rwhogg.site>|
 |1|Bob Mottram <bob@robotics.uk.to>|
 |1|Brett <brettex@hotmail.com>|
 |1|Brian <bdmorin@users.noreply.github.com>|
@@ -334,6 +376,7 @@
 |1|Chandan Rai <dev.chandan.rai@gmail.com>|
 |1|Charles Barnes <cbarnes@bullhorn.com>|
 |1|Charles Barnes <charlesabarnesjr@gmail.com>|
+|1|Charlotte Tan <charlottetan@users.noreply.github.com>|
 |1|Chema <neo22s@gmail.com>|
 |1|Chris Legault <chrislegault2011@gmail.com>|
 |1|Christoph (Sheogorath) Kern <sheogorath@shivering-isles.com>|
@@ -346,10 +389,11 @@
 |1|Craig Davison <craig@davison.io>|
 |1|Cristian Menghi <cristian@menghi.biz>|
 |1|CyrilPepito <18053589+CyrilPepito@users.noreply.github.com>|
+|1|Cédric <cedric@cedricbonhomme.org>|
 |1|Damir Gainetdinov <damir.gaynetdinov@gmail.com>|
 |1|Dan <rocks.in.the.cloud@gmail.com>|
 |1|Danny <dannyvankooten@gmail.com>|
-|1|Dave Lockwood <1261876+deamos@users.noreply.github.com>|
+|1|Danny van Kooten <dannyvankooten@users.noreply.github.com>|
 |1|David <vaidd4@users.noreply.github.com>|
 |1|David Baldwynn <whitef0x0@users.noreply.github.com>|
 |1|David Ng <david90@users.noreply.github.com>|
@@ -365,6 +409,7 @@
 |1|Doğan Çelik <dogancelik@users.noreply.github.com>|
 |1|Dražen Lučanin <kermit666@gmail.com>|
 |1|Ed Tewiah <etewiah@hotmail.com>|
+|1|Edoardo Putti <edoardo.putti@gmail.com>|
 |1|Edreih Aldana <edreihaldana@yahoo.com>|
 |1|Eike Kettner <eike.kettner@posteo.de>|
 |1|Emeric POUPON <epoupon@users.noreply.github.com>|
@@ -382,6 +427,7 @@
 |1|Evgeny Petrov <groosha@protonmail.com>|
 |1|Fabian Patzke <github@patzi.de>|
 |1|Fazal Majid <github@sentfrom.com>|
+|1|Florian <flokX@users.noreply.github.com>|
 |1|Florian Kaiser <florian.kaiser@fnkr.net>|
 |1|Florian Kaldowski <flokX@users.noreply.github.com>|
 |1|Florian Wilhelm <f.wilhelm@tarent.de>|
@@ -400,9 +446,10 @@
 |1|Igor Antun <IgorAntun@users.noreply.github.com>|
 |1|Igor Petrov <garik.piton@gmail.com>|
 |1|Imron RA <42175898+imronra@users.noreply.github.com>|
-|1|Ivan Krutov <vania-pooh@vania-pooh.com>|
+|1|Isaac <isaacnoda@gmail.com>|
 |1|Izac Lorimer <izaclorimer@users.noreply.github.com>|
 |1|Jack <jackdev@mailbox.org>|
+|1|Jackson Delahunt <jackson@jacksondelahunt.com>|
 |1|Jakob Gillich <jakob@gillich.me>|
 |1|James Mills <prologic@shortcircuit.net.au>|
 |1|Jan <jayphizzle@users.noreply.github.com>|
@@ -410,6 +457,7 @@
 |1|Janos Dobronszki <dobronszki@gmail.com>|
 |1|Jarek Lipski <pub@loomchild.net>|
 |1|Jay Williams <jay@myd3.com>|
+|1|Jay Yu <265551+GitHubGeek@users.noreply.github.com>|
 |1|Jay Yu <GitHubGeek@users.noreply.github.com>|
 |1|Jean Menezes da Rocha <jean@menezesdarocha.info>|
 |1|Jelmer Vernooij <jelmer@jelmer.uk>|
@@ -417,6 +465,7 @@
 |1|Joel Calado <joelcalado@gmail.com>|
 |1|Jon Schoning <jonschoning@gmail.com>|
 |1|Jonas <j@jfgr.de>|
+|1|Jonas Hellmann <hellmann.jonas@web.de>|
 |1|Jordan <15741144+jrdnlc@users.noreply.github.com>|
 |1|Jordan Doyle <jordan@9t9t9.com>|
 |1|Jordan Doyle <jordan@doyle.la>|
@@ -428,6 +477,7 @@
 |1|Julien Reichardt <jul.reich43@opmbx.org>|
 |1|Justin Clift <justin@postgresql.org>|
 |1|Justin O'Reilly <justin@oreilly.me>|
+|1|Kacper <kacper@kacperadler.info>|
 |1|Karl Gumerlock <karl@gumerlock.com>|
 |1|KarloLuiten <github@karloluiten.nl>|
 |1|Kaveet Laxmidas <kaveetlaxmidas@gmail.com>|
@@ -437,6 +487,7 @@
 |1|Keyhaku <jones@bious.fr>|
 |1|Kieran <kieran.brahney@gmail.com>|
 |1|Kim Jahn <gitfuckinghub@maisspace.org>|
+|1|Koichi MATSUMOTO <mzch@me.com>|
 |1|Konstantin Sorokin <kvs@sigterm.ru>|
 |1|Kyle Farwell <m@kfarwell.org>|
 |1|Kyle Stetz <kylestetz@gmail.com>|
@@ -445,7 +496,9 @@
 |1|Leonard Thomas Wall <github@tenchooo.me>|
 |1|Lescaudron Mathieu <mathieu@lescaudron.com>|
 |1|Liran Tal <liran.tal@gmail.com>|
+|1|Lorenz Hübschle-Schneider <lorenzhs@users.noreply.github.com>|
 |1|Louis Grenard <louis.grenard@gmail.com>|
+|1|Lukas Masuch <Lukas.Masuch@gmail.com>|
 |1|Luuk Nieuwdorp <luuknieuwdorp@users.noreply.github.com>|
 |1|Marcin Karpezo <m.karpezo@nencki.gov.pl>|
 |1|Marco Dickert <dickert.marco@gmail.com>|
@@ -456,7 +509,9 @@
 |1|Mark Railton <mark@markrailton.com>|
 |1|Markus Dieckmann <markus.dieckmann@posteo.de>|
 |1|Martin Malinda <malindacz@gmail.com>|
+|1|Martin Tournoij <martin@arp242.net>|
 |1|Marvin <Groruk@uberdoge.network>|
+|1|Marvin Gülker <post+git@guelker.eu>|
 |1|MatFluor <MatFluor@users.noreply.github.com>|
 |1|Matt Lee <mattl@users.noreply.github.com>|
 |1|Matteo Piccina <matteo@beiphone.it>|
@@ -495,7 +550,9 @@
 |1|Paweł Jakimowski <pawel@jakimowski.info>|
 |1|Paweł Kapała <bylek77@gmail.com>|
 |1|Peter Brunner <pbrunner@gmail.com>|
+|1|Peter Tonoli <peter+github@metaverse.org>|
 |1|Peter van den Hurk <runical1991@gmail.com>|
+|1|Philipp Kutyla <philipp@kutyla.de>|
 |1|Phill <phill@formbet.co.uk>|
 |1|Phonic Mouse <phonicmouse@gmai.com>|
 |1|Pierre <21216829+pedrom34@users.noreply.github.com>|
@@ -508,6 +565,7 @@
 |1|Remi Rampin <remirampin@gmail.com>|
 |1|Remy Adriaanse <remy@adriaanse.it>|
 |1|Remy Honig <remyhonig@users.noreply.github.com>|
+|1|Richard Thornton <richard@richardthornton.com>|
 |1|Riddler <Iamjithin@live.com>|
 |1|Robert Charusta <rchar@protonmail.com>|
 |1|Roberto Rosario <roberto.rosario.gonzalez@gmail.com>|
@@ -528,13 +586,14 @@
 |1|Sergey Bronnikov <sergeyb@bronevichok.ru>|
 |1|Sergey Ponomarev <me@sergey-ponomarev.ru>|
 |1|Sheldon Rupp <me@shel.io>|
+|1|Simon Alberny <contact@simounet.net>|
 |1|Simon Hanna <simon.hanna@jesus.de>|
 |1|Sourabh Joshi <38150665+sourabh-joshi@users.noreply.github.com>|
 |1|Spencer McIntyre <zeroSteiner@gmail.com>|
+|1|Spencer Muise <spencermuise@gmail.com>|
 |1|Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>|
 |1|Stefan Weil <sw@weilnetz.de>|
 |1|Steve Divskinsy <stevesbrain@users.noreply.github.com>|
-|1|Sung Won Cho <sung@monomax.sh>|
 |1|Sylvain Boily <sylvainboilydroid@gmail.com>|
 |1|THS-on <THS-on@users.noreply.github.com>|
 |1|Tanner Collin <git@tannercollin.com>|
@@ -547,11 +606,15 @@
 |1|Timur Bublik <timur.bublik@zoho.com>|
 |1|Tobias Diekershoff <tobias.diekershoff@gmx.net>|
 |1|Tobias Kunze <rixx@cutebit.de>|
+|1|Tobias Reich <tobias.reich.ich@gmail.com>|
 |1|Tobias Zeising <tobias.zeising@aditu.de>|
+|1|Todd Hoffmann <ddffnn@gmail.com>|
 |1|Tom Hacohen <tom@stosb.com>|
 |1|Tomer Shvueli <tomer@shvueli.com>|
 |1|Tommy Ku <tommyku@users.noreply.github.com>|
+|1|Trevor Ford <trvrfrd@users.noreply.github.com>|
 |1|Vadim Markovtsev <vadim@sourced.tech>|
+|1|Vidas P <vp@automaticmode.com>|
 |1|Viktor Geringer <devfakeplus@googlemail.com>|
 |1|Vincent Dauce <eXorus@users.noreply.github.com>|
 |1|Webmasterish <webmasterish@gmail.com>|
@@ -561,6 +624,7 @@
 |1|benmaynard11 <allowin-217941-github@vhost244.maynardnetworks.com>|
 |1|bitcoinshirt <36959754+bitcoinshirt@users.noreply.github.com>|
 |1|bricej13 <bricej13@gmail.com>|
+|1|c22 <c22@users.noreply.github.com>|
 |1|cbdev <cb@cbcdn.com>|
 |1|costpermille <costpermille@users.noreply.github.com>|
 |1|cpdev <cpdevelops@users.noreply.github.com>|
@@ -569,6 +633,7 @@
 |1|domainzero <domainzero@users.noreply.github.com>|
 |1|dsx <free.robots@gmail.com>|
 |1|ePirat <epirat07@gmail.com>|
+|1|emmanouil <emmanouil@users.noreply.github.com>|
 |1|evitalis <evitalis@users.noreply.github.com>|
 |1|fghhfg <fghhfg@users.noreply.github.com>|
 |1|fi78 <31729946+fi78@users.noreply.github.com>|
@@ -583,19 +648,22 @@
 |1|jarek91 <jarek91@users.noreply.github.com>|
 |1|jgi <public-devgit-common@gissehel.org>|
 |1|josh <joshua.r.li.98@gmail.com>|
-|1|jtagcat <38327267+jtagcat@users.noreply.github.com>|
 |1|lachlan-00 <lachlan.00@gmail.com>|
+|1|lardbit <45122868+lardbit@users.noreply.github.com>|
 |1|littleguga <littleguga@users.noreply.github.com>|
 |1|lsascha <lsascha@gmail.com>|
 |1|macmusz <m.muszytowski@simplito.com>|
 |1|memorex258 <phillip.a.brown@live.com>|
 |1|mertinop <martin.santibanez.a@gmail.com>|
 |1|mrkpl125 <33229813+mrkpl125@users.noreply.github.com>|
+|1|mxroute <37432698+mxroute@users.noreply.github.com>|
 |1|n2i <xuansamdinh.n2i@gmail.com>|
 |1|nodomain <ff@nodomain.cc>|
 |1|norstbox <norstbox@users.noreply.github.com>|
 |1|pastapojken <pastapojken@users.noreply.github.com>|
+|1|phobot <piter90@gmail.com>|
 |1|pips <pips@e5150.fr>|
+|1|pnhofmann <foss@pnhofmann.de>|
 |1|poVoq <wm_jkm@yahoo.com>|
 |1|railscard <railscard@gmail.com>|
 |1|sc0repi0 <sc0repi0@gmx.de>|
@@ -614,4 +682,4 @@
 |1|wxcafé <wxcafe@wxcafe.net>|
 |1|xuansamdinh <xuansamdinh.n2i@gmail.com>|
 |1|zotlabs <mike@macgirvin.com>|
-|1|Руслан Корнев <oganer@gmail.com>|
+|1|Руслан Корнев <oganer@gmail.com>|

+ 34 - 54
Makefile

@@ -1,72 +1,52 @@
 #!/usr/bin/make -f
 SHELL = /bin/bash
-all: checks
+AWESOME_BOT_OPTIONS = --allow-redirect --skip-save-results --allow 202 --white-list airsonic.github.io/docs/apps
 
-checks: nolicenselanguage nofullstop longdescriptions syntaxerrors
+all: check_all
 
-monthly: checks awesome_bot check_github_commit_dates contrib
+# run all checks
+check_all: check_syntax_full awesome_bot check_github_commit_dates
 
-noexternallink:
-	@echo -e "\nLines with no source/demo/other link:"
-	@sed -n -e '/BEGIN SOFTWARE LIST/,/END SOFTWARE LIST/ p' README.md | egrep '^ *\* ' | egrep --color=always '[a-z\.] `'
+# check pull requests
+check_pr: check_syntax_diff
 
-nolicenselanguage:
-	@echo -e "\nLines with only 1 or no language/license entry:"
-	@! sed -n -e '/BEGIN SOFTWARE LIST/,/END SOFTWARE LIST/ p' README.md | egrep '^ *\* ' | egrep -v '` `'
+# check syntax in whole file
+check_syntax_full:
+	node tests/test.js -r README.md
 
-nofullstop:
-	@echo -e "\nLines without a full stop after description:"
-	@! sed -n -e '/BEGIN SOFTWARE LIST/,/END SOFTWARE LIST/ p' README.md | egrep '[a-z] \(\['
-	@! sed -n -e '/BEGIN SOFTWARE LIST/,/END SOFTWARE LIST/ p' README.md | egrep '[a-z] `'
-
-longdescriptions:
-	@echo -e "\nDescriptions exceeding 250 chars:"
-	@! sed -n -e '/BEGIN SOFTWARE LIST/,/END SOFTWARE LIST/ p' README.md | egrep --only-matching '\) - [Aa-Zz|.|\(|\)|/| |,|-]*\s\(\[' README.md | grep  '.\{257\}'
-
-syntaxerrors:
-	@echo -e "\nSyntax errors:" 
-	@! sed -n -e '/BEGIN SOFTWARE LIST/,/END SOFTWARE LIST/ p' README.md | egrep  '\)\(|``|\)`'
-
-#################################
-
-contrib:
-	@mv .github/.mailmap . && printf "|Commits | Author |\n| :---: | --- |\n" > AUTHORS.md && git shortlog -sne | sed -r 's/^\s*([[:digit:]]*?)\s*?(.*?)/|\1|\2|/' >> AUTHORS.md && mv .mailmap .github/.mailmap
+# check syntax in the diff from master to current branch
+check_syntax_diff:
+	git diff origin/master -U0 README.md | grep --perl-regexp --only-matching "(?<=^\+).*" >> temp.md && \
+	node tests/test.js -r README.md -d temp.md && \
+	awesome_bot -f temp.md $(AWESOME_BOT_OPTIONS)
 
+# check dead links
+# https://github.com/dkhamsing/awesome_bot
 awesome_bot:
-	# https://github.com/dkhamsing/awesome_bot
-	awesome_bot --allow-redirect -f README.md
+	awesome_bot -f README.md $(AWESOME_BOT_OPTIONS)
 
+# check date of last commit for github.com repository URLs
 check_github_commit_dates:
+	pip3 install PyGithub
 	python3 tests/check-github-commit-dates.py
 
 #################################
 
+# update the AUTHORS.md file
+contrib:
+	@mv .github/.mailmap . && printf "|Commits | Author |\n| :---: | --- |\n" > AUTHORS.md && git shortlog -sne | sed -r 's/^\s*([[:digit:]]*?)\s*?(.*?)/|\1|\2|/' >> AUTHORS.md && mv .mailmap .github/.mailmap
 
+# add a new entry
 add:
-	@#add a new entry
-	@printf 'Software name: ' ;\
-	read Name; if [ -z "$$Name" ]; then printf 'Missing software name!\n'; exit 1 ; fi ;\
-	printf 'Homepage URL: ' ;\
-	read Url; if [ -z "$$Url" ]; then printf 'Missing main project URL!\n'; exit 1 ; fi ;\
-	printf 'Description (max 250 characters, ending with .): ' ;\
-	read Description; if [ -z "$$Description" ]; then printf 'Missing description!\n'; exit 1 ; fi ;\
-	printf 'License: ' ;\
-	read License; if [ -z "$$License" ]; then printf 'Missing license!\n'; exit 1 ; fi ;\
-	printf 'Main server-side language/platform/requirement: ' ;\
-	read Language; if [ -z "$$Language" ]; then printf 'Missing language!\n'; exit 1 ; fi ;\
-	printf 'Demo URL (if any): ' ;\
-	read Demo; if [ -z "$$Demo" ]; then CDemo="" ; else CDemo="[Demo]($$Demo)" ; fi ;\
-	printf 'Source code URL (if different from Homepage): ' ;\
-	read Source; if [ -z "$$Source" ]; then CSource="" ; else CSource="[Source Code]($$Source)" ; fi ;\
-	if [[ "$$CSource" == "" && "$$Demo" == "" ]]; \
-	then Moreinfo=""; \
-	else Moreinfo=$$(echo "($$CDemo$$CSource)" | sed 's|)\[|), [|g') ;\
-	fi ;\
-	echo -e "Copy this entry to your clipboard, paste it in the appropriate category:\n\n" ;\
+	@read -r -p "Software name: " Name && [[ ! -z "$$Name" ]] && \
+	read -r -p "Homepage/URL: " Url && [[ ! -z "$$Url" ]] && \
+	read -r -p "Description (max 250 characters, ending with .): " Description && [[ ! -z "$$Description" ]] && \
+	read -r -p "License: " License && [[ ! -z "$$License" ]] && \
+	read -r -p "Main server-side language/platform/requirement: " Language && [[ ! -z "$$Language" ]] && \
+	read -r -p "Demo URL (optional,leave empty): " Demo && \
+	if [[ "$$Demo" == "" ]]; then CDemo=""; else CDemo="[Demo]($$Demo)"; fi; \
+	read -r -p "Source code URL (if different from homepage): " Source && \
+	if [[ "$$Source" == "" ]]; then CSource=""; else CSource="[Source Code]($$Source)"; fi; \
+	if [[ "$$CSource" == "" && "$$Demo" == "" ]]; then Moreinfo=""; else Moreinfo="($$CDemo $$CSource)"; fi; \
+	echo "Copy this entry to your clipboard, paste it in the appropriate category:" ;\
 	echo "- [$$Name]($$Url) - $${Description} $${Moreinfo} \`$$License\` \`$$Language\`"
-
-
-#TODO ask for category and insert item accordingly
-#TODO check for unsorted entries
-#TODO automatically sort entries/sections
-#TODO autoupdate contributors list

ファイルの差分が大きいため隠しています
+ 260 - 186
README.md


+ 12 - 11
non-free.md

@@ -4,6 +4,7 @@
 
 ## Analytics
 
+- [userTrack](https://www.usertrack.net/) `⊘ Proprietary` - userTrack is a web analytics platform with heatmaps, session recordings and powerful user segmentation feature. Updated very regularly. ([Demo](http://dashboard.usertrack.net/)) `PHP/MySQL/ReactJS`
 - [UXLens](https://uxlens.com/) `⊘ Proprietary` - UXLens is a website visitor recording software meant for identifying UI issues and fix them to improve user experience. Formerly known as SessionRecord ([Demo](https://console.uxlens.com/test)) `Docker Nodejs`
 
 
@@ -17,18 +18,15 @@
 ## Communication Systems
 
 - [Dialog](https://dlg.im) `⊘ Proprietary` - Handy and feature-rich multi-device solution with native mobile clients, SIP integration, chatbots, 3rd-party integrations. It brings communication efficiency without sacrificing privacy. Works in closed circuit, encrypts push notifications. ([Demo](https://dlg.im/en/download)) `Scala/Go`
+- [Groupboard](https://www.groupboard.com) `⊘ Proprietary` - Online whiteboard, audio/video conferencing, screen sharing, shared code editing and optional session recording/playback.
 - [HipChat](https://www.atlassian.com/software/hipchat) `⊘ Proprietary` - A team chat solution with 1:1 chat audio and video, third party integration and more. `PHP/Python`
 - [PrivMX WebMail](https://privmx.com) - an alternative private mail system - web-based, end-to-end encrypted by design, self-hosted, decentralized, uses independent PKI. Easy to install and administrate, freeware, open-source. `PHP`
-  
-## Decentralized Network
 
-- [Synereo](https://www.synereo.com/) - Decentralized network system based on blockchain that allows fast speed and great trust level. ([Source Code](https://github.com/synereo/synereo)) `Scala`  
- 
-## Federated Identity/Authentication
+## E-books and Integrated Library Systems (ILS)
 
-- [Auth0](https://auth0.com/docs/appliance): `⊘ Proprietary`. Identity made simple for developers. `NodeJS`
+- [Ubooquity](https://vaemendis.net/ubooquity/)  `⊘ Proprietary` - Ubooquity is a free to use, versatile, lightweight, multi-platform, and secure home server for your comic and e-book library. `Java`
+ 
 
-  
 ## File Sharing and Synchronization
 
 - [Resilio Sync](https://www.resilio.com/) `⊘ Proprietary` - Resilio Sync by Resilio, Inc is a proprietary peer-to-peer file synchronisation tool.
@@ -49,10 +47,11 @@
 
 ## Maps & GPS
 
-- [OpenMapTiles Server](https://openmaptiles.org/) `⊘ Proprietary` - Set of tools for self-hosting of OpenStreetMap vector tiles. ([Demo](https://openmaptiles.org/), [Partial Source Code](https://github.com/openmaptiles)) `Python/JavaScript`
+- [OpenMapTiles Server](https://openmaptiles.org/) `⊘ Proprietary` - Set of tools for self-hosting of OpenStreetMap vector tiles. ([Partial Source Code](https://github.com/openmaptiles)) `Python/JavaScript`
 
 ## Media Streaming
 
+- [Channels DVR Server](https://getchannels.com/dvr-server/) `⊘ Proprietary` - Flexible server providing a whole home self hosted DVR experience for [Channels](https://getchannels.com).
 - [Emby](https://emby.media/) `⊘ Proprietary` - Home media server supporting both DLNA and DIAL (Chromecast) devices out-of-the-box. ([Partial source Code](https://github.com/MediaBrowser/Emby)) `Proprietary with some GPL-2.0` `C#`
 - [Plex](https://plex.tv/) `⊘ Proprietary` - Plex is a centralized home media playback system with a powerful central server.
 - [Subsonic](http://subsonic.org/) - Web-based media streamer and jukebox. ([Demo](http://demo.subsonic.org/login.view?user=guest4&password=guest))
@@ -70,12 +69,14 @@
 - [ArtVenue](http://codecanyon.net/item/artvenue-image-sharing-community-script/5771542) `⊘ Proprietary` - Start your own photography community website, platform based on the Laravel PHP Framework. ([Demo](http://codecanyon.net/item/artvenue-image-sharing-community-script/full_screen_preview/5771542)) `PHP`
 - [Chevereto](https://chevereto.com/) `⊘ Proprietary` - A powerful and fast image hosting script that allows you to create your very own full featured image hosting website in just minutes. ([Demo](http://demo.chevereto.com/)) `PHP`
 - [Koken](http://koken.me/) `⊘ Proprietary` - Content management and web site publishing for photographers. `PHP`
+- [PhotoStructure](https://photostructure.com/) `⊘ Proprietary` - All your family's photos and videos automatically organized into a fun and beautiful website. Runs via Docker, NodeJS, or native desktop installers. `NodeJS`
 - [Single File PHP Gallery](http://sye.dk/sfpg/) `⊘ Proprietary` - is a web gallery in one single PHP file. `PHP` 
 
   
 ## Project Management
 - [Active Collab](https://www.activecollab.com/) `⊘ Proprietary` - Project management - `PHP`
-- [Duet](https://duetapp.com/) `⊘ Proprietary` - Invoicing and project management with an integrated client portal. ([Demo](https://duetapp.com/demo/#dashboard)) `PHP`
+- [Duet](https://duetapp.com/) `⊘ Proprietary` - Invoicing and project management with an integrated client portal. ([Demo](https://duetapp.com/start-demo)) `PHP`
+- [Kantree](https://kantree.io) `⊘ Proprietary` - Work management and collaboration - `Python`
 - [Solo](http://www.getsoloapp.com/) - Solo is a free project management app created for freelancers. Create contacts, manage tasks, upload files, track project progress, and keep notes. ([Demo](http://www.getsoloapp.com/demo/)) `PHP`
 
   
@@ -83,7 +84,7 @@
 - [Axigen](https://www.axigen.com/mail-server/free/) `⊘ Proprietary` -  Great alternative to open source. It's a turnkey messaging solution, perfect for small & micro businesses, integration projects or test environments.
 - [Cloudron](https://cloudron.io) `⊘ Proprietary` - Open-core software allowing you to effortlessly self-host web apps on your server. ([Source Code](https://git.cloudron.io/groups/cloudron)) `Nodejs/Docker`
 - [hMailServer](https://www.hmailserver.com) `⊘ Proprietary` - Open source e-mail server for Microsoft Windows. ([Source Code](https://github.com/hmailserver/hmailserver)) `C++`
-- [Poste.io](https://poste.io) `⊘ Proprietary` - Full featured solution for your Email server. Native implementation of last anti-SPAM methods, webmail and easy administration included. Free tier available. ([Demo](https://poste.io/admin/login#admin@poste.io;admin))
+- [Poste.io](https://poste.io) `⊘ Proprietary` - Full featured solution for your Email server. Native implementation of last anti-SPAM methods, webmail and easy administration included. Free tier available. ([Demo](https://poste.io/demo))
 
   
 ## Software Development
@@ -98,12 +99,12 @@
 - [JIRA](https://www.atlassian.com/software/jira) `⊘ Proprietary` - A professional and extensible issue tracker `Java`
 - [RhodeCode](https://rhodecode.com) `⊘ Proprietary` - On-premise Source Code Management for Mercurial, Git & Subversion. `Python`
 - [BitBucket Server](https://www.atlassian.com/software/bitbucket/server) `⊘ Proprietary` - An enterprise-level Git solution similar to GitLab `Java`
-
   
 ## Ticketing
 - [Full Help](https://www.fullhelp.com/en/) `⊘ Proprietary` - Simple, easy to use help desk & knowledge base software. Custom branding, custom themes, restful API, communication channels, multi-company support, multi-language support, and much more! At least 1 new release per month. [Changelog](https://www.fullhelp.com/en/changelog) `PHP`
 - [Jitbit Helpdesk](https://www.jitbit.com/helpdesk/) `⊘ Proprietary` - Self-hosted help desk software - simple but powerful. ([Demo](https://www.jitbit.com/hosted-helpdesk/trial/)) `ASP.NET`
 - [SupportPal](https://www.supportpal.com/) `⊘ Proprietary` - Powerful help desk software - easy, fast and intuitive. ([Demo](http://demo.supportpal.com/)) `PHP`
+- [Cerb](http://www.cerberusweb.com/) - Group-based e-mail management project. ([Source Code](https://github.com/wgm/cerb)) `DPL` `PHP`
 
 
 ## Time Tracking

+ 1 - 1
tests/check-github-commit-dates.py

@@ -28,7 +28,7 @@ import os
 
 __author__ = "nodiscc"
 __copyright__ = "Copyright 2019, nodiscc"
-__credits__ = ["https://github.com/kickball/awesome-selfhosted"]
+__credits__ = ["https://github.com/awesome-selfhosted/awesome-selfhosted"]
 __license__ = "MIT"
 __version__ = "1.0"
 __maintainer__ = "nodiscc"

+ 223 - 63
tests/test.js

@@ -1,91 +1,251 @@
-// Accepts input of any filename, ie. node test.js README.md
+// USAGE:
+// node test.js -r README.md  (Checks whole file)
+// node test.js -r README.md -d temp.md  (Checks just the diff)
 
 const fs = require('fs');
+const chalk = require('chalk');
+let licenses = new Set();
+let pr = false;
+let readme;
+let diff;
 
-let log = '{\n';
-let issuelog = '  "message": "#### Syntax Issues\\n\\n Name | Entry\\n----|----------------------\\n';
-let fails = ''
-const file = fs.readFileSync(process.argv[2], 'utf8'); // Reads argv into var file
+//Parse the command options and set the pr var
+function parseArgs(args) {
+  if ( args.indexOf('-r', 2) > 0 ) {
+    readme = fs.readFileSync(args[args.indexOf('-r', 2)+1], 'utf8')
+  }
+  if (args.indexOf('-d', 2) > 0) {
+    pr = true;
+    diff = fs.readFileSync(args[args.indexOf('-d', 2)+1], 'utf8');
+  }
+  if ( pr === true) {
+    console.log(chalk.blue(`Running on PR. README.md: ${args[args.indexOf('-r', 2)+1]} diff: ${args[args.indexOf('-d', 2)+1]}`))
+  }
+}
 
-function entryFilter(md) { // Function to find lines with entries
+// Function to find lines with entries
+function entryFilter(md) { 
   const linepatt = /^\s{0,2}-\s\[.*`/;
   return linepatt.test(md);
 }
 
-function split(text) { // Function to split lines into array
+// Function to find lines with licenses
+function licenseFilter(md) {
+  const linepatt = /^- `.*` - .*/;
+  return linepatt.test(md)
+}
+
+// Function to split lines into array
+function split(text) { 
   return text.split(/\r?\n/);
 }
 
-function findPattern(text) { // Test entries against 8 patterns.  If matches pattern returns true
-  const nodnospatt = /^\s{0,2}-\s\[.*?\]\(.*?\) - .{0,249}?\. `.*?` `.*?`/; // Regex for entries with no demo and no source code
-  const slpatt = /^\s{0,2}-\s\[.*?\]\(.*?\) - .{0,249}?\. \(\[Demo\b\]\(.*?\), \[Source Code\b\]\(.*?\)\) `.*?` `.*?`/; // Regex for entries with demo and source code
-  const nodpatt = /^\s{0,2}-\s\[.*?\]\(.*?\) - .{0,249}?\. \(\[Source Code\]\(.*?\)\) `.*?` `.*?`/; // Regex for entries with no demo
-  const nospatt = /^\s{0,2}-\s\[.*?\]\(.*?\) - .{0,249}?\. \(\[Demo\]\(.*?\)\) `.*?` `.*?`/; // Regex for entries with no source code
-  const pnodnospatt = /^\s{0,2}-\s\[.*?\]\(.*?\) `⚠` - .{0,249}?\. `.*?` `.*?`/; // Regex for entries with proprietary with no demo and no source code
-  const pslpatt = /^\s{0,2}-\s\[.*?\]\(.*?\) `⚠` - .{0,249}?\. \(\[Demo\b\]\(.*?\), \[Source Code\b\]\(.*?\)\) `.*?` `.*?`/; // Regex for entries with proprietary with demo and source code
-  const pnodpatt = /^\s{0,2}-\s\[.*?\]\(.*?\) `⚠` - .{0,249}?\. \(\[Source Code\]\(.*?\)\) `.*?` `.*?`/; // Regex for entries with proprietary with no demo
-  const pnospatt = /^\s{0,2}-\s\[.*?\]\(.*?\) `⚠` - .{0,249}?\. \(\[Demo\]\(.*?\)\) `.*?` `.*?`/; // Regex for entries with proprietary with no source code
-  if (nodnospatt.test(text) === true) {
-    return true;
-  } else if (slpatt.test(text) === true) {
+// All entries should match this pattern.  If matches pattern returns true.
+function findPattern(text) { 
+  const patt = /^\s{0,2}-\s\[.*?\]\(.*?\) (`⚠` )?- .{0,249}?\.( \(\[(Demo|Source Code|Clients)\]\([^)\]]*\)(, \[(Source Code|Clients)\]\([^)\]]*\))?(, \[(Source Code|Clients)\]\([^)\]]*\))*\))? \`.*?\` \`.*?\`$/;
+  if (patt.test(text) === true) {
     return true;
-  } else if (nodpatt.test(text) === true) {
-    return true;
-  } else if (nospatt.test(text) === true) {
-    return true;
-  } else if (pnodnospatt.test(text) === true) {
-    return true;
-  } else if (pslpatt.test(text) === true) {
-    return true;
-  } else if (pnodpatt.test(text) === true) {
-    return true;
-  } else if (pnospatt.test(text) === true) {
-    return true;
-  }
+  } 
   return false;
 }
 
-function entryErrorCheck(md) {
-  const namepatt = /^\s{0,2}-\s\[(.*?)\]/; // regex pattern to find name of entryArray
-  const entries = split(md); // Inserts each line into the entries array
+// Parses SPDX identifiers from list of licenses
+function parseLicense(md) {
+  const patt = /^- `(.*)` - .*/
+  return patt.exec(md)[1]
+}
+
+//Test '- [Name](http://homepage/)'
+function testMainLink(text) { 
+  let testA = /(^ {0,2}- \[.*?\]\([^)]*\.[^)]*?\))(?=\ ?\-?\ ?\w)/ // /(^ {0,2}- \[.*?\]\(.*\))(?=.?-? ?\w)/;
+  const testA1 = /(- \W?\w*\W{0,2}.*?\)?)( .*$)/;
+    if (!testA.test(text)) {
+    let a1 = testA1.exec(text)[2];
+    return chalk.red(text.replace(a1, ''))
+  }
+  return chalk.green(testA.exec(text)[1])
+}
+
+//Test  '`⚠` - Short description, less than 250 characters.'
+function testDescription(text) { 
+  const testB = /( - .*\. )(?:(\(?\[?|\`))/;
+  const testA1 = /(- \W?\w*\W{0,2}.*?\)?)( .*$)/;
+  const testB2 = /((\(\[|\`).*$)/;
+  if (!testB.test(text)) {
+    let b1 = testA1.exec(text)[1];
+    let b2 = testB2.exec(text)[1];
+    return chalk.red(text.replace(b1, '').replace(b2, ''))
+  } 
+  return chalk.green(testB.exec(text)[1])
+}
+
+//If present, tests '([Demo](http://url.to/demo), [Source Code](http://url.of/source/code), [Clients](https://url.to/list/of/related/clients-or-apps))'
+function testSrcDemCli(text) { 
+  let testC = text.search(/\.\ \(|\.\ \[|\ \(\[[sSdDcC]/); //    /\(\[|\)\,|\)\)/);
+  let testD = /(?<=\w. )(\(\[(Demo|Source Code|Clients)\]\([^)\]]*\)(, \[(Source Code|Clients)\]\([^)\]]*\))?(, \[(Source Code|Clients)\]\([^)\]]*\))*\))(?= \`?)/;
+  const testD1 = /(^- \W[a-zA-Z0-9-_ .]*\W{0,2}http[^\[]*)(?<= )/;
+  const testD2 = /(\`.*\` \`.*\`$)/;
+  if ((testC > -1) && (!testD.test(text))) {
+    let d1 = testD1.exec(text)[1];
+    let d2 = testD2.exec(text)[1];
+    return chalk.red(text.replace(d1, '').replace(d2, ''))
+} else if (testC > -1) {
+  return chalk.green(testD.exec(text)[1])
+}
+return ""
+}
+
+// Tests '`License` `Language`'
+function testLangLic(text) { 
+  const testD2 = /(\`.*\` \`.*\`$)/;
+  let testE = testD2.test(text);
+  const testE1 = /(^[^`]*)/;
+  if (!testE) {
+    let e1 = testE1.exec(text)[1];
+    return chalk.red(text.replace(e1, ''))
+  }
+  return chalk.green(testD2.exec(text)[1])
+}
+
+//Runs all the syntax tests...
+function findError(text) {
+  let res
+  res = testMainLink(text)
+  res += testDescription(text)
+  res += testSrcDemCli(text)
+  res += testLangLic(text)
+  return res + `\n`
+}
+
+//Check if license is in the list of licenses.
+function testLicense(md) {
+  let pass = true;
+  let lFailed = []
+  let lPassed = []
+  const regex = /.*\`(.*)\` .*$/;
+  try {  
+    for (l of regex.exec(md)[1].split("/")) {
+      if (!licenses.has(l)) {
+        pass = false;
+        lPassed.push(l)
+      }
+      lFailed.push(l)
+    }
+  }
+  catch(err) {
+    console.log(chalk.yellow("Error in License syntax, license not checked against list."))
+    return [false, "", ""]
+  }
+
+ 
+
+    
+
+  return [pass, lFailed, lPassed]
+}
+
+
+//Parses name from entry
+function parseName(md) {
+  const regex = /^\W*(.*?)\W/
+  return regex.exec(md)[1]
+}
+
+function entryErrorCheck() {
+  const lines = split(readme); // Inserts each line into the entries array
   let totalFail = 0;
   let totalPass = 0;
   let total = 0;
-  const entryArray = [];
-  if (entries[0] === "") {
-    console.log("0 Entries")
+  let entries = [];
+  let diffEntries = [];
+
+  if (lines[0] === "") {
+    console.log(chalk.red("0 Entries Found, check your commandline arguments"))
     process.exit(0)
   }
-  for (let i = 0, len = entries.length; i < len; i += 1) { // Loop to create array of objects
-    entryArray[i] = new Object;
-    entryArray[i].raw = entries[i];
-    if (entryFilter(entries[i]) === true) { // filter out lines that don't with * [)
-      total += 1;
-      entryArray[i].name = namepatt.exec(entries[i])[1]; // Parses name of entry
-      entryArray[i].pass = findPattern(entries[i]); // Tests against known patterns
-      if (entryArray[i].pass === true) { // If entry passes increment totalPass counter
-        totalPass += 1;
+  for (let i = 0; i < lines.length; i ++) { // Loop through array of lines
+    if (entryFilter(lines[i]) === true) { // filter out lines that don't start with * [)
+      e = {};
+      e.raw = lines[i];
+      e.line = i + 1
+      entries.push(e);
+    } else if (licenseFilter(lines[i]) === true) {
+      licenses.add(parseLicense(lines[i]))
+    }
+  }
+
+  if (pr === true) {
+    console.log(chalk.cyan("Only testing the diff from the PR.\n"))
+    const diffLines = split(diff); // Inserts each line of diff into an array
+    for (let l of diffLines) {
+      if (entryFilter(l) === true) { // filter out lines that don't start with * [)
+      e = {};
+      e.raw = l;
+      diffEntries.push(e);
+      } else if (licenseFilter(l) === true) {
+        licenses.add(parseLicense(l))
+      }
+    }
+    if (diffEntries.length === 0) {
+      console.log("No entries changed in README.md, Exiting...")
+      process.exit(0)
+    }
+    total = diffEntries.length
+    for (let e of diffEntries) {
+      e.pass = true
+      e.name = parseName(e.raw)
+      if (!findPattern(e.raw)) {
+        e.highlight = findError(e.raw);
+        e.pass = false;
+        console.log(e.highlight)
+      }
+      e.licenseTest = testLicense(e.raw);
+      if (!e.licenseTest) {
+        e.pass = false;
+        console.log(chalk.red(`${e.name}'s license is not on License list.`))
+      }
+      if (e.pass) {
+        totalPass++
+      } else {
+        totalFail++
+      }
+   }
+  } else {
+    console.log(chalk.cyan("Testing entire README.md\n"))
+    total = entries.length
+    for (let e of entries) {
+      e.pass = true
+      e.name = parseName(e.raw)
+      if (!findPattern(e.raw)) {
+        e.highlight = findError(e.raw);
+        e.pass = false;
+        console.log(`${chalk.yellow(e.line + ": ")}${e.highlight}`);
+        syntax = e.highlight;
+      }
+      e.licenseTest = testLicense(e.raw);
+      if (!e.licenseTest[0]) {
+        e.pass = false;
+        console.log(chalk.yellow(e.line + ": ") + `${e.name}'s license ${chalk.red(`'${e.licenseTest[1]}'`)} is not on the License list.\n`)
+      }
+      if (e.pass) {
+        totalPass++
       } else {
-        console.log(`${entryArray[i].name} Failed.`); // If entry fails increment totalFail counter and append error to issuelog
-        // entryArray[i].error = findError(entries[i]) //WIP
-        totalFail += 1;
-        issuelog += `${entryArray[i].name} | ${entries[i]} \\n`;
-        fails += `${entries[i]} \n\n`;
+        totalFail++
       }
     }
   }
-  if (totalFail > 0) { // Logs # passed & failed to console, and failures to syntaxcheck.json
-    console.log(`${totalFail} Failed, ${totalPass} Passed, of ${total}\n-----------------------------`);
-    console.log(fails)
-    log += ` "error": true,\n  "title": "Found ${totalFail} entries with syntax error(s).",\n`;
-    fs.writeFileSync('syntaxcheck.json', `${log} ${issuelog} "\n}`);
+  if (totalFail > 0) {
+    console.log(chalk.blue(`\n-----------------------------\n`))
+    console.log(chalk.red(`${totalFail} Failed, `) + chalk.green(`${totalPass} Passed, `) + chalk.blue(`of ${total}`))
+    console.log(chalk.blue(`\n-----------------------------\n`))
     process.exit(1);
-  } else { // Logs # of entries passed to console and error: false to syntaxcheck.json
-    console.log(`${totalFail} Failed, ${totalPass} Passed, of ${total} \n`);
-    log += '  "error": false\n}';
-    fs.writeFileSync('syntaxcheck.json', log);
-    process.exit(0);
+  } else {
+    console.log(chalk.blue(`\n-----------------------------\n`))
+    console.log(chalk.green(`${totalPass} Passed of ${total}`))
+    console.log(chalk.blue(`\n-----------------------------\n`))
+    process.exit(0)
   }
 }
 
-entryErrorCheck(file);
+parseArgs(process.argv)
+entryErrorCheck();