Compare commits

...

48 Commits

Author SHA1 Message Date
Antoine Bartuccio 35eab30bcd Migrate to gomodules
continuous-integration/drone/push Build is passing Details
2020-11-11 15:32:38 +01:00
Antoine Bartuccio 7b26cc3640 Merge pull request 'spongify_answer' (#19) from spongify_answer into master
continuous-integration/drone/push Build is failing Details
Reviewed-on: #19
2020-11-09 18:29:45 +00:00
madahin 7b4f2d3b25 Use camelCase instead of snake_case
Because this shity language can't deal with snake_case and
the snake_case evangile is a traitor to it's cause.
2020-11-09 19:24:22 +01:00
madahin 30397b9207 Fix formating with `go fmt` 2020-11-09 19:14:21 +01:00
madahin e786b77f62 Fix identation 2020-11-09 19:12:14 +01:00
madahin 9df38b5a88 Calling the /sponge command as a reply will now spongify the quoted message 2020-11-09 18:40:30 +01:00
Antoine Bartuccio 3d3133eaff
Fix CI
continuous-integration/drone/push Build is passing Details
2019-07-23 22:19:18 +02:00
Antoine Bartuccio c001bca84a
Fix dockerfile for CI
continuous-integration/drone/push Build is failing Details
2019-07-23 22:15:42 +02:00
Antoine Bartuccio 05203f3392
Better, faster and safer file management
the build was successful Details
continuous-integration/drone/push Build is failing Details
2019-01-05 17:48:09 +01:00
Antoine Bartuccio f722e70052 Fix Arioch
the build was successful Details
2019-01-04 11:45:28 +01:00
Antoine Bartuccio daa77fcfc4 Merge branch 'normalization' of ALFRED/ALFRED into master
the build was successful Details
2019-01-04 10:33:23 +00:00
Antoine Bartuccio cc31b9d00a Fix CI for go 1.11
the build was successful Details
2019-01-04 11:31:37 +01:00
Antoine Bartuccio ed824600e9 Upgrade to go 1.11
the build failed Details
2019-01-04 11:09:20 +01:00
Antoine Bartuccio 541ab556d7 Remove relative path and follow gometalinter guide lines
the build failed Details
2019-01-04 10:55:51 +01:00
Antoine Bartuccio 94313b4819
Fix register_private.go permission error
the build was successful Details
2019-01-03 22:03:03 +01:00
Antoine Bartuccio 21ae38639d Merge branch 'bro-features' of ALFRED/ALFRED into master
the build was successful Details
2019-01-02 23:03:55 +00:00
Antoine Bartuccio 41be91c594
Comments and doc typos
the build was successful Details
2019-01-03 00:03:00 +01:00
Antoine Bartuccio a8d8b6d69e
Add auto push notification on users when publish is used 2019-01-02 23:52:01 +01:00
Antoine Bartuccio dd7a39a158
Encode auto notify into the user data
the build was successful Details
2019-01-02 19:24:27 +01:00
Antoine Bartuccio 019a57e7cf
Use a dedicated struct for user subscriptions 2019-01-02 19:06:47 +01:00
Antoine Bartuccio f6f17e7a7b
Simplify user chat subscription with a helper
the build was successful Details
2019-01-02 15:53:11 +01:00
Antoine Bartuccio 4ecc1e2072 Merge branch 'bro-features' of ALFRED/ALFRED into master
the build was successful Details
2019-01-02 13:41:05 +00:00
Antoine Bartuccio 0acdcb6351
Best effort to provide a unpublish option
the build was successful Details
2019-01-02 02:28:01 +01:00
Antoine Bartuccio da0729d234
Store messages for subscription feature as a real Message
the build was successful Details
2019-01-02 00:58:19 +01:00
Antoine Bartuccio 7ffb5a4a2a
Save message instead of message text for subscriptions
the build was successful Details
2019-01-01 23:37:25 +01:00
Antoine Bartuccio 7edc83f003
Upgrading is a pain
the build was successful Details
2018-12-31 20:54:31 +01:00
Antoine Bartuccio 02db29beae Merge branch 'bro-features' of ALFRED/ALFRED into master
the build failed Details
2018-12-31 19:06:05 +00:00
Antoine Bartuccio c501c6645a
Upgrade go version
the build was successful Details
2018-12-31 19:59:45 +01:00
Antoine Bartuccio e9b3dabd10
Simplify Retrieve function 2018-12-31 19:59:36 +01:00
Antoine Bartuccio a47c016c62 Merge branch 'bro-features' of ALFRED/ALFRED into master
the build was successful Details
2018-12-31 16:05:50 +00:00
Amalvy Arthur 704625e930 Added publish module documentation
the build was successful Details
2018-12-31 17:04:28 +01:00
Amalvy Arthur db421c828b Codu quality patch in order to get merged with master
the build was successful Details
2018-12-31 16:50:19 +01:00
Amalvy Arthur 29add0224c Fixed a bug where persitence would cause publish module failures
the build was successful Details
2018-12-31 15:59:34 +01:00
Amalvy Arthur ff91955361 Added ListSubscriber, Unpublish and Retrieve commands
the build was successful Details
2018-12-31 02:46:05 +01:00
Amalvy Arthur ef2866e89b Added basic subscribe and unsubscribe 2018-12-31 00:48:46 +01:00
Amalvy Arthur dea2b4cfb4 Basic save feature
the build was successful Details
2018-12-30 19:31:56 +01:00
Antoine Bartuccio 14a3bc27d7
Add cool quotes
the build was successful Details
2018-11-14 00:40:59 +01:00
Antoine Bartuccio 0d142365d1
Apero time
the build was successful Details
2018-07-28 13:17:54 +02:00
Antoine Bartuccio b781ae9f53
Add specific chat data and pass chaos to an entire day
the build was successful Details
2018-07-27 16:50:13 +02:00
Antoine Bartuccio 31c4a24de0
Limit Chaos to once an hour
the build was successful Details
2018-07-26 22:53:09 +02:00
Antoine Bartuccio 368ac57b04
Bring Chaos
the build was successful Details
2018-07-26 22:36:04 +02:00
Antoine Bartuccio 22060613ad
Merge branch 'features'
the build was successful Details
2018-07-26 22:23:00 +02:00
Antoine Bartuccio ead73b25e1
Twitters Trends in Franceç 2018-07-26 22:22:34 +02:00
Antoine Bartuccio ddea4620ae Merge branch 'features' of ALFRED/ALFRED into master
the build was successful Details
2018-07-25 20:55:10 +00:00
Antoine Bartuccio 28a30c2d25
Trump
the build was successful Details
2018-07-25 22:52:32 +02:00
Antoine Bartuccio 68f6e1ffa0
Fix empty gender
the build was successful Details
2018-07-25 01:30:13 +02:00
Antoine Bartuccio 747e58099e
Removed @ from genders
the build was successful Details
2018-07-25 01:05:54 +02:00
Antoine Bartuccio 54517b8e99
Remove \ when cleaning Genders
the build was successful Details
2018-07-25 00:19:45 +02:00
25 changed files with 1408 additions and 144 deletions

View File

@ -1,34 +1,40 @@
pipeline:
build:
image: golang
group: build
commands:
- go get -v -d ./...
- go build .
test:
image: golang
group: build
secrets: [ test_api_token ]
environment: [ test_api_token ]
commands:
- go get -v -d ./...
- go test ./...
publish:
image: plugins/docker
repo: klmp200/alfred
secrets: [ docker_username, docker_password ]
when:
branch: master
event: push
deploy:
image: appleboy/drone-ssh
host:
- ollivander.diagon-alley
username: dronedeploy
secrets: [ ssh_password ]
envs: [ ssh_password ]
script:
- echo $SSH_PASSWORD | sudo -S systemctl restart alfred-bot
when:
branch: master
event: push
kind: pipeline
type: docker
name: default
steps:
- name: build
image: golang:1.14
commands:
- go build
- name: publish
image: plugins/docker
settings:
repo: klmp200/alfred
username:
from_secret: docker_username
password:
from_secret: docker_password
when:
branch: master
event: push
- name: deploy
image: appleboy/drone-ssh
environment:
SSH_PASSWORD:
from_secret: ssh_password
settings:
host:
from_secret: ssh_host
username:
from_secret: ssh_username
password:
from_secret: ssh_password
envs: [ SSH_PASSWORD ]
script:
- echo $SSH_PASSWORD | sudo -S systemctl restart alfred-bot
when:
branch: master
event: push

6
.gitignore vendored
View File

@ -11,9 +11,13 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
#swap files
*~
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
settings_custom.json
history.json
users.json
users.json
chat_data.json

View File

@ -1,25 +1,16 @@
FROM golang:1.10 AS builder
# Download and install the latest release of dep
# ADD https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64 /usr/bin/dep
# RUN chmod +x /usr/bin/dep
FROM golang:1.14 AS builder
RUN mkdir /build
WORKDIR /build
# Copy the code from the host and compile it
COPY . ./
RUN go get -v -d ./...
COPY . .
RUN mkdir res
COPY settings.json res
COPY quotes.json res
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix nocgo -o /app .
# We use Alpine for it's ca-certificates needed by http lib
FROM alpine:3.4
RUN apk add --no-cache ca-certificates apache2-utils
FROM scratch
# We need ca-certifactes for http calls
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /app ./
COPY --from=builder /go/res ./
COPY --from=builder /build/res ./
ENTRYPOINT ["./app"]

View File

@ -1,31 +1,48 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-23 15:24:22
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 20:55:53
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-05 17:47:10
*/
package main
import (
"./commands"
"./settings"
"./shared"
tb "gopkg.in/tucnak/telebot.v2"
"log"
"time"
"git.klmp200.net/ALFRED/ALFRED/commands"
"git.klmp200.net/ALFRED/ALFRED/settings"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
func main() {
registered_commands := map[string]func(*tb.Message){
tb.OnText: commands.OnText,
"/hello": commands.Hello,
"/sponge": commands.Sponge,
"/git": commands.Git,
"/framapad": commands.Framapad,
"/setgender": commands.SetGender,
"/gender": commands.Gender,
"/roll": commands.Dice,
registeredCommands := map[string]func(*tb.Message){
tb.OnText: commands.OnText,
"/registerprivate": commands.RegisterPrivate,
"/unregisterprivate": commands.UnRegisterPrivate,
"/hello": commands.Hello,
"/sponge": commands.Sponge,
"/git": commands.Git,
"/framapad": commands.Framapad,
"/setgender": commands.SetGender,
"/gender": commands.Gender,
"/roll": commands.Dice,
"/trump": commands.LastTrumpTweet,
"/trends": commands.TwitterTrends,
"/chaos": commands.TwitterSJW,
"/apero": commands.AperoTime,
"/quote": commands.Quote,
"/subscribe": commands.Subscribe,
"/unsubscribe": commands.Unsubscribe,
"/listsubscribers": commands.ListSubscribers,
"/publish": commands.Publish,
"/unpublish": commands.Unpublish,
"/retrieve": commands.Retrieve,
"/toggleupdates": commands.ToggleUpdates,
}
if err := settings.LoadSettings("settings.json", "settings_custom.json"); err != nil {
@ -37,6 +54,8 @@ func main() {
settings.Settings["history file"].(string))
log.Println("Initialize users infos")
shared.InitUsers(settings.Settings["users file"].(string))
log.Println("Initialize chat data")
shared.InitChatData(settings.Settings["chat data file"].(string))
log.Println("Bot initialisation")
b, err := tb.NewBot(tb.Settings{
@ -49,7 +68,7 @@ func main() {
}
shared.Bot = b
for key, value := range registered_commands {
for key, value := range registeredCommands {
b.Handle(key, value)
}

33
commands/apero.go Normal file
View File

@ -0,0 +1,33 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-27 19:53:09
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:36:16
*/
package commands
import (
"net/http"
"git.klmp200.net/ALFRED/ALFRED/shared"
"github.com/PuerkitoBio/goquery"
tb "gopkg.in/tucnak/telebot.v2"
)
// AperoTime checks if it's time to drink on an external website
func AperoTime(m *tb.Message) {
response, err := http.Get("http://estcequecestbientotlapero.fr")
if err != nil {
shared.Bot.Send(m.Chat, "Impossible de savoir si c'est bel et bien l'heure de l'apéro")
return
}
defer response.Body.Close()
doc, err := goquery.NewDocumentFromReader(response.Body)
if err != nil {
shared.Bot.Send(m.Chat, "La réponse qui m'a été fournit est incohérente.")
return
}
shared.Bot.Send(m.Chat, doc.Find("h2").First().Text())
}

View File

@ -1,20 +1,23 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 20:50:04
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 21:00:59
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:37:39
*/
package commands
import (
"../shared"
tb "gopkg.in/tucnak/telebot.v2"
"math/rand"
"strconv"
"strings"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
// Dice rolls a dice
func Dice(m *tb.Message) {
split := strings.Split(m.Text, " ")
if len(split) < 2 {

View File

@ -1,17 +1,18 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 12:11:26
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 12:12:58
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:38:07
*/
package commands
import (
"../shared"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
// Framapad send a link to the ALFRED framapad
func Framapad(m *tb.Message) {
shared.Bot.Send(m.Chat, "Venez participer à mon développement en posant vos idées ici : https://mensuel.framapad.org/p/ALFRED2LERETOUR.")
}

View File

@ -1,18 +1,21 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 14:55:33
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 20:29:36
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:38:32
*/
package commands
import (
"../shared"
tb "gopkg.in/tucnak/telebot.v2"
"strings"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
// SetGender register your gender on ALFRED
func SetGender(m *tb.Message) {
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction")
@ -24,6 +27,10 @@ func SetGender(m *tb.Message) {
return
}
data := strings.Join(split, " ")
if data == "" {
shared.Bot.Send(m.Chat, "Attention, votre genre est vide. Ce n'est pas enregistrable.")
return
}
shared.Users.Set(m.Sender.Username, "gender", data)
shared.Bot.Send(m.Chat, "Votre genre est enregistré, je vous considère maintenant comme « "+data+" ».")
}
@ -52,13 +59,12 @@ func Gender(m *tb.Message) {
func cleanGender(slice []string) []string {
for i := range slice {
slice[i] = strings.Replace(slice[i], "\\", "", -1)
slice[i] = strings.Replace(slice[i], "@", "", -1)
clean := false
for !clean {
clean = true
if strings.HasPrefix(slice[i], "@") {
slice[i] = strings.Replace(slice[i], "@", "", 1)
clean = false
} else if strings.HasPrefix(slice[i], "/") {
if strings.HasPrefix(slice[i], "/") {
slice[i] = strings.Replace(slice[i], "/", "", 1)
clean = false
}

View File

@ -1,17 +1,19 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 12:07:34
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 12:08:49
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:39:07
*/
package commands
import (
"../shared"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
// Git sends a link to the git repo
func Git(m *tb.Message) {
shared.Bot.Send(m.Chat, "Mon code source est accessible librement à l'adresse https://git.klmp200.net/ALFRED/ALFRED. Venez contribuer :)")
}

View File

@ -1,17 +1,19 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 12:05:45
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 12:06:39
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:39:24
*/
package commands
import (
"../shared"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
// Hello makes ALFRED say hello
func Hello(m *tb.Message) {
shared.Bot.Send(m.Chat, "Bonjour "+m.Sender.Username)
}

View File

@ -1,17 +1,19 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 12:09:37
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 12:10:26
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:39:50
*/
package commands
import (
"../shared"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
// OnText saves chat history
func OnText(m *tb.Message) {
shared.History.AddMessage(m.Chat.ID, m.Text)
}

53
commands/quote.go Normal file
View File

@ -0,0 +1,53 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-11-14 00:15:43
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:40:01
*/
package commands
import (
"encoding/json"
"io/ioutil"
"math/rand"
"sync"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
type quoteStorage struct {
mutex sync.Mutex
data []string
}
var sharedQuotes *quoteStorage
// Quote display a quote on the chat
func Quote(m *tb.Message) {
if sharedQuotes == nil {
loadQuotes("quotes.json")
}
sharedQuotes.mutex.Lock()
defer sharedQuotes.mutex.Unlock()
shared.Bot.Send(m.Chat, sharedQuotes.data[rand.Intn(len(sharedQuotes.data))])
}
func loadQuotes(path string) {
sharedQuotes = &quoteStorage{}
sharedQuotes.mutex.Lock()
defer sharedQuotes.mutex.Unlock()
sharedQuotes.data = []string{}
data, err := ioutil.ReadFile(path)
if err != nil {
return
}
if json.Unmarshal(data, &sharedQuotes.data) != nil {
sharedQuotes.data = []string{}
}
}

View File

@ -0,0 +1,48 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2019-01-02 22:46:05
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:40:28
*/
package commands
import (
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
// RegisterPrivate registers an user private chat
func RegisterPrivate(m *tb.Message) {
if m.Chat.Type != tb.ChatPrivate {
shared.Bot.Send(m.Chat, "Cette commande n'est disponible qu'en messages privés")
return
}
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Vous devez avoir enregistré un username")
return
}
shared.Users.SetUserChat(m.Sender.Username, m.Chat)
shared.Bot.Send(m.Chat, "Votre chat privé a bien été enregistré")
}
// UnRegisterPrivate delete an user private chat
func UnRegisterPrivate(m *tb.Message) {
if m.Chat.Type != tb.ChatPrivate {
shared.Bot.Send(m.Chat, "Cette commande n'est disponible qu'en messages privés")
return
}
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Vous devez avoir enregistré un username")
return
}
shared.Users.SetUserChat(m.Sender.Username, nil)
shared.Bot.Send(m.Chat, "Votre chat privé a bien été supprimé")
}

View File

@ -1,27 +1,39 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 11:52:11
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 11:58:42
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:40:38
*/
package commands
import (
"../shared"
tb "gopkg.in/tucnak/telebot.v2"
"strings"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
func spongify(inputMessage string) string {
spongifiedMessage := ""
for i, char := range inputMessage {
if i%2 == 0 {
spongifiedMessage += strings.ToLower(string(char))
} else {
spongifiedMessage += strings.ToUpper(string(char))
}
}
return spongifiedMessage
}
func Sponge(m *tb.Message) {
message := ""
for i, char := range shared.History.LastMessage(m.Chat.ID) {
if i%2 == 0 {
message += strings.ToLower(string(char))
} else {
message += strings.ToUpper(string(char))
}
if m.IsReply() {
message = spongify(m.ReplyTo.Text)
} else {
message = spongify(shared.History.LastMessage(m.Chat.ID))
}
shared.Bot.Send(m.Chat, message)
}

394
commands/subscribe.go Normal file
View File

@ -0,0 +1,394 @@
/*
* @Authors: Amalvy Arthur, Bartuccio Antoine
*/
// This module uses a property named "subscribed_chats" in the shared Users structure.
// It consists of a list of chatID as a string, chatID are separated by ":" (unix PATH style)
// This module uses a property named "saved_messages" in the shared Chats structure
// It consists of a slice of string
package commands
import (
"encoding/json"
"strconv"
"strings"
"git.klmp200.net/ALFRED/ALFRED/shared"
tb "gopkg.in/tucnak/telebot.v2"
)
type userSubscription struct {
ChatID int64
AutoNotify bool
}
// subscriptions are stored in format ChatID(int64),AutoNotify(bool):ChatID,AutoNotify
func getUserSubscribedChats(username string) []userSubscription {
serializedSubscriptions, exists := shared.Users.Get(username, "subscribed_chats")
if !exists {
return []userSubscription{}
}
subscriptions := []userSubscription{}
for _, sub := range strings.Split(serializedSubscriptions, ":") {
splitedSub := strings.Split(sub, ",")
// malformated
if len(splitedSub) == 0 {
continue
}
chatID, err := strconv.ParseInt(splitedSub[0], 10, 64)
if err != nil {
continue
}
// only ChatID
if len(splitedSub) == 1 {
subscriptions = append(subscriptions, userSubscription{
ChatID: chatID,
AutoNotify: true,
})
continue
}
autoNotify, err := strconv.ParseBool(splitedSub[1])
if err != nil {
autoNotify = true
}
subscriptions = append(subscriptions, userSubscription{
ChatID: chatID,
AutoNotify: autoNotify,
})
}
return subscriptions
}
func setUserSubscribedChats(username string, subscriptions []userSubscription) {
subs := make([]string, len(subscriptions))
for i, sub := range subscriptions {
subs[i] = strings.Join(
[]string{
strconv.FormatInt(sub.ChatID, 10),
strconv.FormatBool(sub.AutoNotify),
},
",",
)
}
shared.Users.Set(username, "subscribed_chats", strings.Join(subs, ":"))
}
func getPublishedMessages(chatID int64) []tb.Message {
messages := []tb.Message{}
serializedMessages, exists := shared.ChatData.Get(chatID, "published_messages")
if !exists {
return messages
}
if _, ok := serializedMessages.(string); !ok {
return messages
}
if json.Unmarshal([]byte(serializedMessages.(string)), &messages) != nil {
return []tb.Message{}
}
return messages
}
func setPublishedMessages(chatID int64, messages []tb.Message) {
data, err := json.Marshal(messages)
if err != nil {
return
}
shared.ChatData.Set(chatID, "published_messages", string(data))
}
// Subscribe user sending the command to the current chat
// Command syntax : /subscribe
func Subscribe(m *tb.Message) {
if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup {
shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat")
return
}
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction")
return
}
subscriptions := getUserSubscribedChats(m.Sender.Username)
alreadySuscribed := false
for _, sub := range subscriptions {
if sub.ChatID == m.Chat.ID {
alreadySuscribed = true
break
}
}
if alreadySuscribed {
shared.Bot.Send(m.Chat, "Vous êtes déjà abonné à ce chat : "+m.Chat.Title)
return
}
shared.Bot.Send(m.Chat, "Abonnement au chat : "+m.Chat.Title)
subscriptions = append(subscriptions, userSubscription{
ChatID: m.Chat.ID,
AutoNotify: true,
})
setUserSubscribedChats(m.Sender.Username, subscriptions)
}
// Unsubscribe user sending the command from the current chat
// Command syntax : /unsubscribe
func Unsubscribe(m *tb.Message) {
if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup {
shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat")
return
}
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction")
return
}
subscriptions := getUserSubscribedChats(m.Sender.Username)
if len(subscriptions) == 0 {
shared.Bot.Send(m.Chat, "Vous n'êtes abonnés à aucun chat")
return
}
filteredSubscriptions := []userSubscription{}
wasSuscribed := false
for _, sub := range subscriptions {
if sub.ChatID == m.Chat.ID {
wasSuscribed = true
continue
}
filteredSubscriptions = append(filteredSubscriptions, sub)
}
if !wasSuscribed {
shared.Bot.Send(m.Chat, "Vous n'êtes pas abonné au chat : "+m.Chat.Title)
return
}
shared.Bot.Send(m.Chat, "désabonnement du chat : "+m.Chat.Title)
setUserSubscribedChats(m.Sender.Username, filteredSubscriptions)
}
// ListSubscribers List all subscribers of the current chat
// Command syntax : /listsubscribers
func ListSubscribers(m *tb.Message) {
if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup {
shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat")
return
}
subscribers := m.Chat.Title + " subscribers : \n\n"
for _, subscriber := range getSubscribers(m.Chat.ID) {
subscribers = subscribers + "- " + subscriber + "\n"
}
shared.Bot.Send(m.Chat, subscribers)
}
// Publish a message from the current chat
// Command syntax (while replying to a message) : /publish
func Publish(m *tb.Message) {
if m.ReplyTo == nil {
shared.Bot.Send(m.Chat, "Veuillez répondre à un message pour le publier")
return
}
if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup {
shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat")
return
}
defer shared.Bot.Send(m.Chat, "Message publié : "+m.ReplyTo.Text)
savedMessages := getPublishedMessages(m.Chat.ID)
setPublishedMessages(m.Chat.ID, append(savedMessages, *m.ReplyTo))
go pushUpdates(m.Chat.ID, m.ReplyTo)
}
// Unpublish remove a message from published messages in the current chat
// Command syntax (while replying to a message) : /unpublish
func Unpublish(m *tb.Message) {
if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup {
shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat")
return
}
if m.ReplyTo == nil {
shared.Bot.Send(m.Chat, "Veuillez répondre à un message pour le dépublier")
return
}
if !m.ReplyTo.IsForwarded() {
shared.Bot.Send(m.Chat, "Ce message ne peut pas avoir été publié")
return
}
publishedMessages := getPublishedMessages(m.Chat.ID)
filteredPublishedMessages := []tb.Message{}
found := false
for _, message := range publishedMessages {
// You can't just compare messages id because
// when retrieving, the newly send message
// has a different ID from the one stored so you can't detect that's
// it's in the database except if you find the original message
// which is very unlikely to happen
// As a workaround, we check the original sender, original unix time
// and associated text
if message.Sender.ID == m.ReplyTo.OriginalSender.ID &&
message.Unixtime == int64(m.ReplyTo.OriginalUnixtime) &&
message.Text == m.ReplyTo.Text {
found = true
continue
}
filteredPublishedMessages = append(filteredPublishedMessages, message)
}
if !found {
shared.Bot.Send(m.Chat, "Ce message n'a jamais été publié")
return
}
setPublishedMessages(m.Chat.ID, filteredPublishedMessages)
shared.Bot.Send(m.Chat, "Message supprimé des publication")
}
// Retrieve If performed in MP : retrieve all messages from all subscribed sources for the user
// If performed in Group Chat : retrieved all published messages for this chat
// Command syntax : /retrieve
func Retrieve(m *tb.Message) {
chatList := []userSubscription{}
hasMessage := false
if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup && m.Chat.Type != tb.ChatPrivate {
shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat")
return
}
if m.Chat.Type == tb.ChatPrivate {
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction")
return
}
chatList = getUserSubscribedChats(m.Sender.Username)
}
if m.Chat.Type == tb.ChatGroup || m.Chat.Type == tb.ChatSuperGroup {
chatList = append(chatList, userSubscription{ChatID: m.Chat.ID})
}
shared.Bot.Send(m.Chat, "--- Messages publiés ---")
for _, sub := range chatList {
messages := getPublishedMessages(sub.ChatID)
if len(messages) > 0 {
hasMessage = true
}
for _, message := range messages {
shared.Bot.Forward(m.Chat, &message)
}
}
if !hasMessage {
shared.Bot.Send(m.Chat, "Aucun message publié")
}
shared.Bot.Send(m.Chat, "--- Messages publiés ---")
}
// ToggleUpdates activate/deactivate automatic updates from the current chat
// Command syntax : /toggleupdates
func ToggleUpdates(m *tb.Message) {
if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup {
shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat")
return
}
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction")
return
}
wasSuscribed := false
subAutoNotify := false
subscriptions := getUserSubscribedChats(m.Sender.Username)
for i, sub := range subscriptions {
if sub.ChatID == m.Chat.ID {
sub.AutoNotify = !sub.AutoNotify
subAutoNotify = sub.AutoNotify
subscriptions[i] = sub
wasSuscribed = true
break
}
}
if !wasSuscribed {
shared.Bot.Send(m.Chat, "Vous n'ête pas abonné au chat : "+m.Chat.Title)
return
}
setUserSubscribedChats(m.Sender.Username, subscriptions)
if subAutoNotify {
shared.Bot.Send(m.Chat, "Les notifications automatiques sont désormais activées pour ce chat")
return
}
shared.Bot.Send(m.Chat, "Les notifications automatiques sont désormais désactivées pour ce chat")
}
// Get all users subscribed to the provided channel
func getSubscribers(chatID int64) []string {
var subscribers []string
for _, username := range shared.Users.GetUsernames() {
subscriptions := getUserSubscribedChats(username)
for _, sub := range subscriptions {
if sub.ChatID == chatID {
subscribers = append(subscribers, username)
break
}
}
}
return subscribers
}
func pushUpdates(chatID int64, message *tb.Message) {
for _, username := range shared.Users.GetUsernames() {
for _, sub := range getUserSubscribedChats(username) {
if sub.ChatID != chatID || !sub.AutoNotify {
continue
}
chat, err := shared.Users.GetUserChat(username)
if err != nil {
continue
}
shared.Bot.Forward(chat, message)
}
}
}

127
commands/twitter.go Normal file
View File

@ -0,0 +1,127 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-25 18:51:38
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 11:44:47
*/
package commands
import (
"strconv"
"strings"
"time"
"git.klmp200.net/ALFRED/ALFRED/settings"
"git.klmp200.net/ALFRED/ALFRED/shared"
"github.com/dghubble/go-twitter/twitter"
"github.com/dghubble/oauth1"
tb "gopkg.in/tucnak/telebot.v2"
)
var client *twitter.Client
func initTwitter() {
config := oauth1.NewConfig(
settings.Settings["twitter consumer key"].(string),
settings.Settings["twitter consumer secret"].(string),
)
token := oauth1.NewToken(
settings.Settings["twitter access token"].(string),
settings.Settings["twitter access secret"].(string),
)
http_client := config.Client(oauth1.NoContext, token)
client = twitter.NewClient(http_client)
}
func testOrInitTwitter() {
if client == nil {
initTwitter()
}
}
func twitterCommunicationError(m *tb.Message) {
shared.Bot.Send(m.Chat, "Désolé, les serveurs de twitter sont injoignables.")
}
// LastTrumpTweet sends the last tweet of Donald Trump
func LastTrumpTweet(m *tb.Message) {
testOrInitTwitter()
user, _, err := client.Users.Show(&twitter.UserShowParams{ScreenName: "realDonaldTrump"})
if err != nil {
twitterCommunicationError(m)
return
}
timeline, _, err := client.Timelines.UserTimeline(&twitter.UserTimelineParams{ScreenName: "realDonaldTrump"})
if err != nil {
twitterCommunicationError(m)
return
}
response := []string{
user.Name,
"\nFollowers : ",
strconv.Itoa(user.FollowersCount),
"\nStatus : ",
user.Description,
"\n ---",
"\n" + timeline[0].Text,
"\n ---",
"\n" + timeline[0].Source,
}
shared.Bot.Send(m.Chat, strings.Join(response, " "))
}
// TwitterTrends sends the french twitter trends
func TwitterTrends(m *tb.Message) {
testOrInitTwitter()
trends, _, err := client.Trends.Place(int64(615702), nil)
if err != nil {
twitterCommunicationError(m)
return
}
message := "Voici les dernières tendances en France"
for _, trend := range trends[0].Trends {
message += "\n" + trend.Name
}
shared.Bot.Send(m.Chat, message)
}
// TwitterSJW sends lasts messages with #SJW
func TwitterSJW(m *tb.Message) {
testOrInitTwitter()
lastUse, exists := shared.ChatData.Get(m.Chat.ID, "last chaos use")
if exists {
date := time.Now()
switch serializedDate := lastUse.(type) {
case string:
parsedDate, err := time.Parse(time.RFC3339, serializedDate)
if err == nil {
date = parsedDate
}
case time.Time:
date = serializedDate
default:
shared.Bot.Send(m.Chat, "Arioch ne répondra pas à votre appel.")
return
}
if time.Now().Before(date.Add(time.Hour * 24)) {
shared.Bot.Send(m.Chat, "Arioch ne répondra pas à votre appel.")
return
}
}
shared.ChatData.Set(m.Chat.ID, "last chaos use", time.Now())
tweets, _, err := client.Search.Tweets(&twitter.SearchTweetParams{
Query: "#SJW",
})
if err != nil {
twitterCommunicationError(m)
return
}
for _, tweet := range tweets.Statuses {
shared.Bot.Send(m.Chat, tweet.Text)
}
}

74
doc/publish.md Normal file
View File

@ -0,0 +1,74 @@
# Publish system overview
The publish module intend to be a "multi-pin" feature for chats, allowing users to retrieve importants messages in a crowded conversation.
## Commands
### Subscribe
**Description** : Subscribe to this group chat publications
**Usage location** : Group chat only
**Command syntax** : /subscribe
### Unsubscribe
**Description** : Unsubscribe [target chat member] from this group chat publications. If no member is provided, unsubscribe yourself.
**Usage location** : Group chat
**Command syntax** : /unsubscribe [target chat member]
*note* : parameter [target chat member] not implemented
### ListSubscribers
**Description** : List all subscribers of this group chat
**Usage location** : Group chat
**Command syntax** : /listsubscribers
### Publish
**Description** : Publish a message to Alfred for this group chat and sends this message via MP to every subscriber of the group chat if they have not mutted it. The message can then be retrieved using the *retrieve* command.
**Usage location** : Group chat only
**Usage conditions** : Reply to the message to publish
**Command syntax** : /publish
### Unpublish
**Description** : Remove a published message from Alfred for this group chat
**Usage location** : Group chat only
**usage conditions** : Reply to the message to unpublish
**Command syntax** : /unpublish
### Retrieve
**Description** : if MP, retrieve all messages from subscribed sources for user, if Group Chat, retrieve all published messages for this chat
**Usage location** : Group Chat or MP
**Command syntax** : /retrieve
### ToggleUpdates
**Description**: Activate/Deactivate automatic notifications from publish in the group chat where the command is used. By default, this is enabled.
**Usage location** : Group Chat
**Command syntax** : /toggleupdates
*note* : No notification can be send if the user has never done /registerprivate on a private chat with the bot, this is a limitation of the telegram bot API.

11
go.mod Normal file
View File

@ -0,0 +1,11 @@
module git.klmp200.net/klmp200/abitbol
go 1.15
require (
git.klmp200.net/ALFRED/ALFRED v0.0.0-20201109182945-7b26cc3640f2
github.com/PuerkitoBio/goquery v1.6.0 // indirect
github.com/dghubble/go-twitter v0.0.0-20201011215211-4b180d0cc78d // indirect
github.com/dghubble/oauth1 v0.6.0 // indirect
gopkg.in/tucnak/telebot.v2 v2.3.5
)

33
go.sum Normal file
View File

@ -0,0 +1,33 @@
git.klmp200.net/ALFRED/ALFRED v0.0.0-20201109182945-7b26cc3640f2 h1:aFcX//JwBBVDBRxycyzBC+mJ+cuTQKrM6wIeVmdEHLM=
git.klmp200.net/ALFRED/ALFRED v0.0.0-20201109182945-7b26cc3640f2/go.mod h1:j6PTiwlXECBIqwIm/4zbrXrwfXoWYD+EY7BPZWYTKrs=
github.com/PuerkitoBio/goquery v1.6.0 h1:j7taAbelrdcsOlGeMenZxc2AWXD5fieT1/znArdnx94=
github.com/PuerkitoBio/goquery v1.6.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dghubble/go-twitter v0.0.0-20201011215211-4b180d0cc78d h1:sBKr0A8iQ1qAOozedZ8Aox+Jpv+TeP1Qv7dcQyW8V+M=
github.com/dghubble/go-twitter v0.0.0-20201011215211-4b180d0cc78d/go.mod h1:xfg4uS5LEzOj8PgZV7SQYRHbG7jPUnelEiaAVJxmhJE=
github.com/dghubble/oauth1 v0.6.0 h1:m1yC01Ohc/eF38jwZ8JUjL1a+XHHXtGQgK+MxQbmSx0=
github.com/dghubble/oauth1 v0.6.0/go.mod h1:8pFdfPkv/jr8mkChVbNVuJ0suiHe278BtWI4Tk1ujxk=
github.com/dghubble/sling v1.3.0 h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU=
github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/tucnak/telebot.v2 v2.3.5 h1:TdMJTlG8kvepsvZdy/gPeYEBdwKdwFFjH1AQTua9BOU=
gopkg.in/tucnak/telebot.v2 v2.3.5/go.mod h1:BgaIIx50PSRS9pG59JH+geT82cfvoJU/IaI5TJdN3v8=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

237
quotes.json Normal file
View File

@ -0,0 +1,237 @@
[
"There are two ways of constructing a software design: One way is to make it sosimple that there are obviously no deficiencies and the other way is to make itso complicated that there are no obvious deficiencies.— C.A.R. Hoare, The 1980 ACM Turing Award Lecture",
"The computing scientist's main challenge is not to get confused by thecomplexities of his own making.— E. W. Dijkstra",
"The cheapest, fastest, and most reliable components are those that aren't there.— Gordon Bell",
"One of my most productive days was throwing away 1000 lines of code.— <a href='http://genius.cat-v.org/ken-thompson/'>Ken Thompson</a>",
"When in doubt, use brute force.— <a href='http://genius.cat-v.org/ken-thompson/'>Ken Thompson</a>",
"Deleted code is debugged code.— Jeff Sickel",
"<a name='bwk'></a>Debugging is twice as hard as writing the code in the first place. Therefore,if you write the code as cleverly as possible, you are, by definition, notsmart enough to debug it.— <a href='http://genius.cat-v.org/brian-kernighan/'>Brian W. Kernighan</a> and P. J. Plauger in <a href='http://www.amazon.com/gp/product/0070342075?ie=UTF8&amp;tag=catv-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0070342075'><em>The Elements of Programming Style</em></a>.",
"The most effective debugging tool is still careful thought, coupled withjudiciously placed print statements.— <a href='http://genius.cat-v.org/brian-kernighan/'>Brian W. Kernighan</a>, in the paper Unix for Beginners (1979)",
"Controlling complexity is the essence of computer programming.— <a href='http://genius.cat-v.org/brian-kernighan/'>Brian Kernighan</a>",
"Beauty is more important in computing than anywhere else in technology becausesoftware is so complicated. Beauty is the ultimate defence against complexity.— David Gelernter",
"UNIX was not designed to stop its users from doing stupid things, as that wouldalso stop them from doing clever things.— Doug Gwyn",
"If you're willing to restrict the flexibility of your approach, you can almostalways do something better.— John Carmack",
"And folks, let's be honest. Sturgeon was an optimist. Way more than 90% of codeis crap.— viro [http://www.ussg.iu.edu/hypermail/linux/kernel/0310.0/0870.html]",
"A data structure is just a stupid programming language.— R. Wm. Gosper",
"The essence of <a href='http://harmful.cat-v.org/software/xml/'>XML</a> is this: the problem it solves is not hard, and it does notsolve the problem well.— Phil Wadler, POPL 2003",
"A program that produces incorrect results twice as fast is infinitely slower.— John Osterhout",
"Life is too short to run proprietary software.— Bdale Garbee",
"I had a nightmare once in which I a had convinced a friend how wonderful <a href='http://harmful.cat-v.org/software/c++/'>C++</a>is. A while later he came back., and he was mad.[sic]— Robin Rosenberg [http://groups.google.com/groups?selm=1fYEA-pz-21%40gated-at.bofh.it]",
"<a href='http://harmful.cat-v.org/software/xml/'>XML</a> is like violence: if it doesn't solve your problem, you aren't using enoughof it.— Heard from someone working at Microsoft",
"XML is like violence. Sure, it seems like a quick and easy solution at first,but then it spirals out of control into utter chaos.— Sarkos in reddit",
"Threads [and] signals [are] a platform-dependant trail of misery, despair,horror and madness.— Anthony Baxter [http://mail.python.org/pipermail/python-dev/2005-July/]",
"Computers are about making life easier in much the same way that the Republicanparty is about fiscal responsibility and a culture of life.— mister_borogove [http://www.livejournal.com/users/jwz/536902.html?thread=9506374#t9506374]",
"All software sucks, be it open-source [or] proprietary. The only question iswhat can be done with particular instance of suckage, and that's where havingthe source matters.— viro [http://www.ussg.iu.edu/hypermail/linux/kernel/0404.3/1344.html]",
"Mathematicians stand on each others' shoulders and computer scientists standon each others' toes.— Richard Hamming",
"It's not that Perl programmers are idiots, it's that the language rewardsidiotic behavior in a way that no other language or tool has ever done.— <a href='http://genius.cat-v.org/erik-naggum'>Erik Naggum</a>, comp.lang.lisp",
"Out-of-band == should be on a separate channel…— Al Viro",
"It's a curious thing about our industry: not only do we not learn from ourmistakes, we also don't learn from our successes.— Keith Braithwaite",
"Ethernet always wins.— Andy Bechtolsheim",
"The central enemy of reliability is complexity.— Geer et al.",
"Simplicity is prerequisite for reliability.— Edsger W. Dijkstra",
"Beware of « the real world ». A speaker's apeal to it is always an invitation notto challenge his tacit assumptions.— Edsger W. Dijkstra",
"<a href='http://doc.cat-v.org/unix/'>Unix</a> is a junk OS designed by a committee of PhDs.— Dave Cutler",
"i've wondered whether Linux sysfs should be called syphilis— forsyth",
"A program is portable to the extent that it can be easily moved to a newcomputing environment with much less effort than would be required to write itafresh.— W. Stan Brown [http://groups.google.com/group/comp.std.c/msg/083fb09444dbbc76]",
"Programming graphics in X is like finding the square root of PI using Roman numerals.— <a href='http://doc.cat-v.org/henry_spencer/'>Henry Spencer</a>",
"Forward thinking was just the thing that made Multics what it is today.— Erik Quanstrom",
"The Eight Fallacies of Distributed ComputingEssentially everyone, when they first build a distributed application, makesthe following eight assumptions. All prove to be false in the long run and allcause big trouble and painful learning experiences.<ol><li>The network is reliable</li><li>Latency is zero</li><li>Bandwidth is infinite</li><li>The network is secure</li><li>Topology doesn't change</li><li>There is one administrator</li><li>Transport cost is zero</li><li>The network is homogeneous</li></ol>— Peter Deutsch",
"From: rsc@plan9.bell-labs.com (Russ Cox)Subject: Re: [9fans] design clairvoyance & the 9 wayDate: Thu, 8 May 2003 04:05:31 GMT> What does tomorrow's unix look like?I'm confident that tomorrow's Unix will look like today's Unix, only cruftier.Russ",
"You want to make your way in the CS field? Simple. Calculate rough time ofamnesia (hell, 10 years is plenty, probably 10 months is plenty), go to thedusty archives, dig out something fun, and go for it. It's worked for manypeople, and it can work for you.— Ron Minnich",
"From: Alexander Viro <viro math psu edu>Subject: Re: ANNOUNCE: Linux Kernel ORB: kORBitDate: Sat, 9 Dec 2000 00:39:36 -0500 (EST)[...]Yeah... 'Infinitely extendable API' and all such. Roughly translatedas 'we can't live without API bloat'. Frankly, judging by the GNOMEcodebase people who designed the thing[GNOME] are culturally incompatible withUNIX.",
"> What's wrong with perl?It combines all the worst aspects of C and Lisp: a billion differentsublanguages in one monolithic executable. It combines the power ofC with the readability of PostScript.> To me perl is the triumph of utalitarianism.So are cockroaches. So is `sendmail'.— jwz [http://groups.google.com/groups?selm=33F4D777.7BF84EA3%40netscape.com]",
"From: ron minnich <rminnich@lanl.gov>Subject: [9fans] microkernelsare they the O-O of the OS world? Always the promises ...ron",
"Subject: Re: BK, deltas, snapshots and fate of -pre...From: Alexander Viro (viro@math.psu.edu)Url: http://groups.google.com/group/fa.linux.kernel/msg/caede4c7fd703c4e[...]Sigh... When it comes to software there are three systems of beliefs.One of them: * Thou shalt know by your heart that all software sucks. * Beware of those who say that their software does not suck, for they are either fools or liars. * Beware of those who give you garments and do not allow to mend them, for sooner or later thou shalt find what needs mending. * But beware also of those who give you badly rotten garments and say 'Thou shalt prefer that above everything, for thou art allowed to mend it'. * Thou shalt not treat software as a living being, for it is not one. * Choose a license of thine liking for sofware thou writest and do not blame those who choose differently for software they write. * Know when to say 'It can be mended, I shalt do that' and when to say 'It is rotten beyond repair'. * Choose free over non-free when it is better or when thou art willing to fix what is broken. * When shit happens, think how to fix it.Another: * All software wants to be free * Thou shalt not use non-free software * Thou shalt not mention non-free software * Thou shalt make all thine software free * Thou shalt choose free above working, even if free one is broken beyond repair * When shit happens, add new featuresand the last one: * Our 3133t! K3wl! Software! Does Not Suck!!! * Always choose our software above everything else * When shit happens, we add new featuresIf you happen to believe in second variant, you have my condolence aslong as you don't force your beliefs on everybody else. If you chooseto emulate door-to-door pests^H^H^H^Hreachers - don't expect to betreated differently.",
"People do have a right to put their code under whatever license they like.Now, <em>I</em> won't use the stuff I don't have a source for unless I haveexceptionally good reason to believe that authors of that stuff areamong the few percents of programmers who <em>can</em> find their arse withoutoutside help. But that has nothing to do with licensing or any moralconsiderations and everything to the fact that I know what kind of crapmost of the software is.— Al Viro on linux-kernel",
"Linus Torvalds wrote:> Ehh.. Telling people 'don't do that' simply doesn't work. Not if they can> do it easily anyway. Things really don't get fixed unless people have a> certain pain-level to induce it to get fixed.Umm... How about the following: you hit delete on patches that introducenew ioctls, I help to provide required level of pain. Deal?— Al Viro on linux-kernel",
"James Simmons wrote:> Crap can work. Given enough thrust pigs will fly, but it's not necessary a> good idea. [ Alexander Viro on linux-kernel ]Watch the attributions.With sufficient thrust, pigs fly just fine.However, this is not necessarily a good idea.It is hard to be sure where they are going to land,and it could be dangerous sitting under them as they fly overhead. From RFC1925, R Callon, 1996.— Al Viro on linux-kernel",
"In the same world where Vomit-Making System is elegant, SGI « designs » areand NT is The Wave Of Future™. Pardon me, but I'll stay in our universeand away from the drugs of such power.— Al Viro on linux-kernel",
"> > Or even XML. Ouch! No need to throw things at me!>> It seems they would be thrown! XML in kernel is too much. OpenOffice andThey won't be thrown. They will be slowly driven under the nails, so thatvictim could experience the joy equal to that of dealing with XML.— Alexander Viro on linux-kernel",
"A Professor of Computer Science gave a paper on how he uses Linux to teach hisundergraduates about operating systems. Someone in the audience asked why useLinux rather than Plan 9?' and the professor answered:Plan 9 looks like itwas written by experts; Linux looks like something my students could aspire towrite'.",
"Computer: Your nominators and endorsers for the Kanai Award consistentlycharacterized your work as simple yet powerful. How do you discover suchpowerful abstractions?<a href='http://genius.cat-v.org/ken-thompson/'>Ken Thompson</a>: It is the way I think. I am a very bottom-up thinker. If you giveme the right kind of Tinker Toys, I can imagine the building. I can sit thereand see primitives and recognize their power to build structures a half milehigh, if only I had just one more to make it functionally complete. I can seethose kinds of things.The converse is true, too, I think. I can't from the building imagine theTinker Toys. When I see a top-down description of a system or language that hasinfinite libraries described by layers and layers, all I just see is a morass.I can't get a feel for it. I can't understand how the pieces fit; I can'tunderstand something presented to me that's very complex. Maybe I do what I dobecause if I built anything more complicated, I couldn't understand it. Ireally must break it down into little pieces.",
"if you're capable of understanding `finalised virtual hyperstationary factoryclass', remembering the <a href='http://harmful.cat-v.org/software/java'>Java</a> class hierarchy, and all the details of the JavaMedia Framework, you are (a) a better man than i am (b) capable of filling yourmind with large chunks of complexity, so concurrent programming should besimple by comparison. go for it.ps. i made up the hyperstationary, but then again, it's probably a designpattern.— forsyth",
"At first I hoped that such a technically unsound project would collapse but Isoon realized it was doomed to success. Almost anything in software can beimplemented, sold, and even used given enough determination. There is nothing amere scientist can say that will stand against the flood of a hundred milliondollars. But there is one quality that cannot be purchased in this way -andthat is reliability. The price of reliability is the pursuit of the utmostsimplicity. It is a price which the very rich find most hard to pay.— C.A.R. Hoare",
" Vacuumware: n, software which was written specifically to fill a void in the industry, especially software which is successful more due to how well it fills that void than due to anything else, like usability or utility. I believe it may have been Dennis Ritchie who said (about X) « Sometimes whenyou fill a vacuum, it still sucks. » X is a prime example of vacuumware, and infact inspired the term.[http://www.uta.fi/FAST/US8/PLAY/inklish.html]",
"I remarked to Dennis [Ritchie] that easily half the code I was writing inMultics was error recovery code. He said, « We left all that stuff out [ofUnix]. If there's an error, we have this routine called panic, and when it iscalled, the machine crashes, and you holler down the hall, Hey, reboot it.' »— Tom Van Vleck [http://www.multicians.org/unix.html]",
"RMS is to <a href='http://doc.cat-v.org/unix/'>Unix</a>, like Hitler [was] to Nietzsche.— Federico Benavento",
"Unix is simple. It just takes a genius to understand its simplicity.— <a href='http://genius.cat-v.org/dennis-ritchie/'>Dennis Ritchie</a>",
"Most <a href='http://harmful.cat-v.org/software/xml/'>xml</a> i've seen makes me think i'mdyslexic. it also looks constipated, and two health problems in one standardis just too much.— Charles Forsyth",
"PHP is a minor evil perpetrated and created by incompetent amateurs, whereasPerl is a great and insidious evil perpetrated by skilled but pervertedprofessionals.",
"OAuth is the best that the wrong way of doing things can provide.— Mike Stay [http://blog.360.yahoo.com/blog-TBPekxc1dLNy5DOloPfzVvFIVOWMB0li?p=1006]",
"This users are idiots, and are confused by functionality' mentality of Gnomeis a disease. If you think your users are idiots, only idiots will use it.— Linus",
"{Ex-Cyber} some part of me desperately wants to believe that XML-RPC is some kind of elaborate joke, like a cross between Discordianism and IP Over Avian Carriers",
"The only places for icons is in a church, a burning church at that.— mhat",
"The key to performance is elegance, not battalions of special cases.— Jon Bentley and <a href='http://genius.cat-v.org/doug-mcilroy/'>Doug McIlroy</a>",
"Just because the standard provides a cliff in front of you, you arenot necessarily required to jump off it.— Norman Diamond",
"Are you quite sure that all those bells and whistles, all thosewonderful facilities of your so called powerful programming languages,belong to the solution set rather than the problem set?— Edsger W. Dijkstra",
"Measuring programming progress by lines of code is like measuringaircraft building progress by weight.— Bill Gates",
"The object-oriented model makes it easy to build up programs byaccretion. What this often means, in practice, is that it provides astructured way to write spaghetti code.— Paul Graham",
"First, solve the problem. Then, write the code.— John Johnson",
"Most software today is very much like an Egyptian pyramid withmillions of bricks piled on top of each other, with no structuralintegrity, but just done by brute force and thousands of slaves.— Alan Kay",
"Correctness is clearly the prime quality. If a system does not dowhat it is supposed to do, then everything else about it matterslittle.— Bertrand Meyer",
"Complexity kills. It sucks the life out of developers, it makesproducts difficult to plan, build and test, it introduces securitychallenges and it causes end-user and administrator frustration.— Ray Ozzie",
"If the designers of X Windows built cars, there would be no fewer thanfive steering wheels hidden about the cockpit, none of which followedthe same principles but youd be able to shift gears with your carstereo. Useful feature that.— Marcus J. Ranum, DEC",
"A language that doesn't have everything is actually easier to programin than some that do.— <a href='http://genius.cat-v.org/dennis-ritchie/'>Dennis M. Ritchie</a>",
"Mostly, when you see programmers, they aren't doing anything. One ofthe attractive things about programmers is that you cannot tellwhether or not they are working simply by looking at them. Very oftenthey're sitting there seemingly drinking coffee and gossiping, or juststaring into space. What the programmer is trying to do is get ahandle on all the individual and unrelated ideas that are scamperingaround in his head.— Charles M. Strauss",
"Haskell is faster than <a href='http://harmful.cat-v.org/software/c++/'>C++</a>, more concise than Perl, more regular thanPython, more flexible than Ruby, more typeful than C#, more robustthan <a href='http://harmful.cat-v.org/software/java'>Java</a>, and has absolutely nothing in common with PHP.— Autrijus Tang",
"You can't trust code that you did not totally create yourself.— <a href='http://genius.cat-v.org/ken-thompson/'>Ken Thompson</a>",
"Object-oriented design is the roman numerals of computing.— <a href='http://genius.cat-v.org/rob-pike/'>Rob Pike</a>",
"Not only is UNIX dead, it's starting to smell really bad.— <a href='http://genius.cat-v.org/rob-pike/'>Rob Pike</a> circa 1991",
"{ajh} I always viewed HURD development like the Special Olympics of free software.",
"cat came back from Berkeley waving flags— <a href='http://genius.cat-v.org/rob-pike/'>Rob Pike</a>",
"We have persistant(sic) objects, they're called files.— <a href='http://genius.cat-v.org/ken-thompson/'>Ken Thompson</a>",
"If you want to go somewhere, goto is the best way to get there.— <a href='http://genius.cat-v.org/ken-thompson/'>ken</a>",
"The X server has to be the biggest program I've ever seen that doesn't do anything for you.— <a href='http://genius.cat-v.org/ken-thompson/'>Ken Thompson</a>",
"A smart terminal is not a smartass terminal, but rather a terminal you can educate.— <a href='http://genius.cat-v.org/rob-pike/'>Rob Pike</a>",
"Simplicity is the ultimate sophistication.— Leonardo da Vinci",
"Increasingly, people seem to misinterpret complexity assophistication, which is baffling—the incomprehensible should causesuspicion rather than admiration. Possibly this trend results from amistaken belief that using a somewhat mysterious device confers anaura of power on the user.— Niklaus Wirth",
"Compatibility means deliberately repeating other people's mistakes.— David Wheeler",
"<blockquote>[Like programmers] prostitutes also think they all suck.</blockquote>And both, programmers and prostitutes, are right: they suck. The big differenceis that prostitutes got the term « user-friendly » right.— yiyus [http://www.reddit.com/r/programming/comments/8y348/my_programming_quotes_file_was_well_received_when/c0aspwo]",
"The Purpose of Computing is Insight, Not Numbers.— This is the motto of the book <a href='http://www.amazon.com/gp/product/0486652416?ie=UTF8&amp;tag=catv-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0486652416'><em>Numerical Methods for Scientists and Engineers</em></a> by Richard Hamming.",
"Every methodology I've come across has, at its kernel, a very small sectionlabelled « do magic here ».— Katie [http://www.fysh.org/~katie/computing/methodologies.txt]",
"I recommend the linux people to call it « GNU / Linux » instead of « GNU/Linux ».never hurts to distance yourself from GNU.— mjl on #plan9-social",
"For the sinner deserves not life but death, according to the diskdevices. For example, start with Plan 9, which is free of sin, thecase is different from His perspective.— <a href='http://glenda.cat-v.org/friends/mark-v-shaney/'>Mark V. Shaney</a>",
"Trying to express implicit and fuzzy relationships in ways that are explicitand sharp doesn't clarify the meaning, it destroys it.— Clay Shirky [http://www.shirky.com/writings/semantic_syllogism.html]",
"Unix has retarded OS research by 10 years and linux has retarded it by 20.— <a href='http://genius.cat-v.org/dennis-ritchie/'>Dennis Ritchie</a> as quoted by by Boyd Roberts in 9fans.",
"Any program that tries to be so generalized and configurable that it couldhandle any kind of task will either fall short of this goal, or will behorribly broken.— Chris Wenham",
"Nobody who uses <a href='http://harmful.cat-v.org/software/xml/'>XML</a> knows what they are doing.— Chris Wenham",
"Debugging time increases as a square of the program's size.— Chris Wenham",
"I guess it's like smart compiler for dumb people, and dumb compiler for smartpeople. But then smart compiler gets too smart.. so neither dumb nor smartpeople can understand it.— fgb on compilers and <a href='http://harmful.cat-v.org/software/GCC'>gcc</a>",
"in aeronautical circles, it's said that the f4 is proof that givenenough thrust even a brick will fly.linux is the f4 of computing?— erik quanstrom",
"It seems to me more like you use foresight and pessimism to avoid getting intosituations where you need to demonstrate exceptional programming ability.— mister_borogove speaking to jwz [http://jwz.livejournal.com/1096593.html]",
"Comparing a computer language to a human language is like comparing anoperating system kernel to a popcorn kernel.— kryptkpr [http://www.reddit.com/r/programming/comments/9upno/c_is_frequently_reviled_both_by_those_who_never/c0eiyqu]",
"Hofstadter's Law: It always takes longer than you expect, even when you takeinto account Hofstadter's Law.",
"My definition of an expert in any field is a person who knows enough aboutwhat's really going on to be scared.— P. J. Plauger, Computer Language, March 1983",
"Every language has an optimization operator. In C++ that operator is //",
"Nobody should start to undertake a large project. You start with a smalltrivial project, and you should never expect it to get large. If you do, you'lljust overdesign and generally think it is more important than it likely is atthat stage. Or worse, you might be scared away by the sheer size of the workyou envision. So start small, and think about the details. Don't think aboutsome big picture and fancy design. If it doesn't solve some fairly immediateneed, it's almost certainly over-designed. And don't expect people to jump inand help you. That's not how these things work. You need to get somethinghalf-way useful first, and then others will say « hey, that almost works forme », and they'll get involved in the project.— Linus Torvalds",
"Theory is when you know something, but it doesn't work. Practice is whensomething works, but you don't know why. Programmers combine theory andpractice: Nothing works and they don't know why.",
"A computer is a stupid machine with the ability to do incredibly smart things,while computer programmers are smart people with the ability to do incrediblystupid things. They are, in short, a perfect match",
"Q: What is the most often-overlooked risk in software engineering?A: Incompetent programmers. There are estimates that the number of programmersneeded in the U.S. exceeds 200,000. This is entirely misleading. It is not aquantity problem; we have a quality problem. One bad programmer can easilycreate two new jobs a year. Hiring more bad programmers will just increase ourperceived need for them. If we had more good programmers, and could easilyidentify them, we would need fewer, not more.— David Parnas",
"Well over half of the time you spend working on a project (on the order of 70percent) is spent thinking, and no tool, no matter how advanced, can think foryou. Consequently, even if a tool did everything except the thinking for you if it wrote 100 percent of the code, wrote 100 percent of the documentation,did 100 percent of the testing, burned the CD-ROMs, put them in boxes, andmailed them to your customers the best you could hope for would be a 30percent improvement in productivity. In order to do better than that, you haveto change the way you think.",
"The best code is no code at all.",
"Before software can be reusable it first has to be usable.",
"Old programs read like quiet conversations between a well-spoken research worker and a well-studied mechanical colleague, not as a debate with a compiler. Who'd have guessed sophistication bought such noise?— Dick Gabriel",
"This is one of the reasons Lisp doesn't get anywhere. The trend to promote features so clever that you stop thinking about your problem and start thinking about the clever features. CL's loop is so powerful that people invented functional programming so that they'd never have to use it.— G_Morgan in reddit [http://www.reddit.com/r/programming/comments/a481l/so_to_get_back_to_the_point_go_vs_algol68_tbh_i/c0fs2nk]",
"More computing sins are committed in the name of efficiency (withoutnecessarily achieving it) than for any other single reason - including blindstupidity.— William A. Wulf",
"There is not now, nor has there ever been, nor will there ever be, anyprogramming language in which it is the least bit difficult to write bad code.",
"Program testing can be a very effective way to show the presence of bugs, butis hopelessly inadequate for showing their absence.— Edsger W. Dijkstra",
"The competent programmer is fully aware of the limited size of his own skull.He therefore approaches his task with full humility, and avoids clever trickslike the plague.— Edsger W. Dijkstra",
"<a href='http://doc.cat-v.org/economics/parkinsons-law/'>Parkinsons Law</a>Otherwise known as the law of bureaucracy, this law states that…« <em>Work expands so as to fill the time available for its completion.</em> »",
"It has been said that the great scientific disciplines are examples of giantsstanding on the shoulders of other giants. It has also been said that thesoftware industry is an example of midgets standing on the toes of othermidgets.— Alan Cooper, About Face",
"Code never lies, comments sometimes do.— Ron Jeffries",
"What I cannot build, I do not understand.— <a href='http://genius.cat-v.org/richard-feynman/'>Richard Feynman</a>",
"If we'd asked the customers what they wanted, they would have said « faster horses »— Henry Ford",
"I (…) am rarely happier than when spending an entire day programming mycomputer to perform automatically a task that would otherwise take me a goodten seconds to do by hand.— Douglas Adams, Last Chance to See",
"Programming is not a zero-sum game. Teaching something to a fellow programmerdoesnt take it away from you. Im happy to share what I can, because Im in itfor the love of programming. The Ferraris are just gravy, honest!— John Carmack, from Michael Abrash' <a href='http://www.amazon.com/gp/product/1576101746?ie=UTF8&amp;tag=catv-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1576101746'>Graphics Programming Black Book</a>.",
"I have found that the reason a lot of people are interested in artificialintelligence is the same reason a lot of people are interested in artificiallimbs: they are missing one.— David Parnas",
"Once you've dressed and before you leave the house, look in the mirror and takeat least one thing off.— Coco Chanel",
"When I am working on a problem I never think about beauty. I think only how tosolve the problem. But when I have finished, if the solution is not beautiful,I know it is wrong.— R. Buckminster Fuller",
"I have always found that plans are useless, but planning is indispensable.— Dwight D. Eisenhower",
"I will, in fact, claim that the difference between a bad programmer and a goodone is whether he considers his code or his data structures more important. Badprogrammers worry about the code. Good programmers worry about data structuresand their relationships.— Linus Torvalds",
"Software is like entropy. It is difficult to grasp, weighs nothing, and obeysthe second law of thermodynamics; i.e. it always increases.",
"A fool with a tool is a more dangerous fool.— u.",
"The best things are simple, but finding these simple things is not simple.— bill [http://stackoverflow.com/questions/58640/great-programming-quotes/1003525#1003525]",
"Some problems are so complex that you have to be highly intelligent and wellinformed just to be undecided about them.— Laurence J. Peter",
"The most amazing achievement of the computer software industry is itscontinuing cancellation of the steady and staggering gains made by the computerhardware industry.— Henry Petroski",
"Theory is when you know something, but it doesn't work. Practice is whensomething works, but you don't know why. Programmers combine theory andpractice: Nothing works and they don't know why.",
"Once a new technology starts rolling, if you're not part of the steamroller,you're part of the road.— Stewart Brand",
"Einstein argued that there must be simplified explanations of nature, becauseGod is not capricious or arbitrary. No such faith comforts the softwareengineer.— Fred Brooks",
"… the cost of adding a feature isn't just the time it takes to code it. Thecost also includes the addition of an obstacle to future expansion. … Thetrick is to pick the features that don't fight each other.— John Carmack",
"With diligence it is possible to make anything run slowly.— Tom Duff",
"Any intelligent fool can make things bigger, more complex, and more violent. Ittakes a touch of genius and a lot of courage to move in the oppositedirection.— Albert Einstein",
"A foolish consistency is the hobgoblin of little minds, adored by littlestatesmen and philosophers and divines.— Ralph Waldo Emerson",
"For a sucessful technology, honesty must take precedence over public relationsfor nature cannot be fooled.— Richard Feynman",
"Comparing to another activity is useful if it helps you formulate questions,it's dangerous when you use it to justify answers.— Martin Fowler",
"Simplicity carried to the extreme becomes elegance.— Jon Franklin",
"Software obeys the law of gaseous expansion - it continues to grow until memoryis completely filled.— Larry Gleason",
"The unavoidable price of reliability is simplicity.— C.A.R. Hoare",
"The ability to simplify means to eliminate the unnecessary so that thenecessary may speak.— Hans Hoffmann",
"Trying to outsmart a compiler defeats much of the purpose of using one.— <a href='http://genius.cat-v.org/brian-kernighan/'>Kernighan</a> and Plauger, <a href='http://www.amazon.com/gp/product/0070342075?ie=UTF8&amp;tag=catv-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0070342075'>The Elements of Programming Style</a>.",
"You're bound to be unhappy if you optimize everything.— Donald Knuth",
"A distributed system is one in which the failure of a computer you didn't evenknow existed can render your own computer unusable.— Leslie Lamport",
"But in our enthusiasm, we could not resist a radical overhaul of the system, inwhich all of its major weaknesses have been exposed, analyzed, and replacedwith new weaknesses.— Bruce Leverett, Register Allocation in Optimizing Compilers",
"The proper use of comments is to compensate for our failure to express ourselfin code.— Robert C. MartinClean Code",
"If you want a product with certain characteristics, you must ensure that theteam has those characteristics before the product's development.— Jim McCarthy and Michele McCarthy - Software for your Head",
"You can't have great software without a great team, and most software teamsbehave like dysfunctional families.— Jim McCarthy",
"Testing by itself does not improve software quality. Test results are anindicator of quality, but in and of themselves, they don't improve it. Tryingto improve software quality by increasing the amount of testing is like tryingto lose weight by weighing yourself more often. What you eat before you steponto the scale determines how much you will weigh, and the software developmenttechniques you use determine how many errors testing will find. If you want tolose weight, don't buy a new scale; change your diet. If you want to improveyour software, don't test more; develop better.— Steve McConnell Code Complete",
"Correctness is clearly the prime quality. If a system does not do what it issupposed to do, then everything else about it matters little.— Bertrand Meyer",
"Incorrect documentation is often worse than no documentation.— Bertrand Meyer",
"Software sucks because users demand it to.— Nathan Myhrvold",
"Unformed people delight in the gaudy and in novelty. Cooked people delight inthe ordinary.— <a href='http://genius.cat-v.org/erik-naggum'>Erik Naggum</a>",
"There's no sense being exact about something if you don't even know what you'retalking about.— John von Neumann",
"That's the thing about people who think they hate computers. What they reallyhate is lousy programmers.— Larry Niven and Jerry Pournelle Oath of Fealty",
"Search all the parks in all your cities; you'll find no statues of committees.— David Ogilvy",
"Good code is short, simple, and symmetrical - the challenge is figuring out howto get there.— Sean Parent",
"Fashion is something barbarous, for it produces innovation without reason andimitation without benefit.— George Santayana",
"Forgive him, for he believes that the customs of his tribe are the laws ofnature!— G.B. Shaw",
"The only sin is to make a choice without knowing you are making one.— Jonathan Shewchuk",
"It is a painful thing to look at your own trouble and know that you yourselfand no one else has made it.— Sophocles, Ajax",
"The primary duty of an exception handler is to get the errorout of the lap of the programmer and into the surprised faceof the user. Provided you keep this cardinal rule in mind,you can't go far wrong.— Verity Stob",
"A notation is important for what it leaves out.— Joseph Stoy",
"An organisation that treats its programmers as morons will soon haveprogrammers that are willing and able to act like morons only.— Bjarne Stroustrup",
"I have always wished that my computer would be as easy to useas my telephone. My wish has come true. I no longer know howto use my telephone.— Bjarne Stroustrup",
"The most important single aspect of software development isto be clear about what you are trying to build.— Bjarne Stroustrup",
"The best is the enemy of the good.— Voltaire",
"As soon as we started programming, we found to our surprise that it wasn't aseasy to get programs right as we had thought. Debugging had to be discovered. Ican remember the exact instant when I realized that a large part of my lifefrom then on was going to be spent in finding mistakes in my own programs.— Maurice Wilkes discovers debugging, 1949",
"Software gets slower faster than hardware gets faster.— Wirth's law",
"The purpose of software engineering is to control complexity, not to create it.— Dr. Pamela Zave",
"I object to doing things that computers can do.— Olin Shivers",
"Simplicity the art of maximizing the amount of work not done is essential.— From the Agile Manifesto.",
"When you want to do something differently from the rest of the world, it's agood idea to look into whether the rest of the world knows something you don't.",
"Perilous to us all are the devices of an art deeper than that which we possessourselves.— J.R.R. Tolkien",
"Complexity has nothing to do with intelligence, simplicity does.— Larry Bossidy",
"If it doesn't work, it doesn't matter how fast it doesn't work.— Mich Ravera",
"Simplicity is hard to build, easy to use, and hard to charge for. Complexity iseasy to build, hard to use, and easy to charge for.— Chris Sacca",
"… what society overwhelmingly asks for is snake oil. Of course, the snake oilhas the most impressive names — otherwise you would be selling nothing — like« Structured Analysis and Design », « Software Engineering », « Maturity Models »,« Management Information Systems », « Integrated Project Support Environments »« Object Orientation » and « Business Process Re-engineering » (the latter threebeing known as IPSE, OO and BPR, respectively).— Edsger W. Dijkstra — EWD 1175: The strengths of the academic enterprise [Today we could add Extreme Programming', Agile Software Development' and many more.]",
"They won't tell you that they don't understand it; they will happily inventtheir way through the gaps and obscurities.— V.A. Vyssotsky on software programmers and their views on specifications",
"In software, the most beautiful code, the most beautiful functions, and themost beautiful programs are sometimes not there at all.— Jon Bentley, Beautiful Code (O'Reilly), « The Most Beautiful Code I Never Wrote »",
"Computers make it easier to do a lot of things, but most of the things theymake it easier to do don't need to be done.— Andy Rooney",
"True glory consists in doing what deserves to be written; in writing whatdeserves to be read.— Pliny the Elder",
"The whole point of getting things done is knowing what to leave undone.— Oswald Chambers",
"<ul><li>Q: What is the difference between an object methodologist and a terrorist?</li><li>A: You can negotiate with the terrorist.</li></ul>",
"One Page Principle: A specification that will not fit on one page of 8.5x11inch paper cannot be understood.— Mark Ardis",
"The whole HTML validation exercise is questionable, but validating as XHTML isflat-out masochism. Only recommended for those that enjoy pain. Or programmers.I can't always tell the difference.— Jeff Atwood",
"When in doubt, leave it out.— Joshua Bloch",
"No code is faster than no code.— merb motto",
"As a rule, software systems do not work well until they have been used, andhave failed repeatedly, in real applications.— Dave Parnas",
"<a href='http://harmful.cat-v.org/software/OO_programming/'>OOP</a> is to writing a program, what going through airport security is to flying.— Richard Mansfield",
"The problem with object-oriented languages is they've got all this implicitenvironment that they carry around with them. You wanted a banana but what yougot was a gorilla holding the banana and the entire jungle.— Joe Armstrong",
"As a programmer, it is your job to put yourself out of business. What you dotoday can be automated tomorrow.— <a href='http://genius.cat-v.org/doug-mcilroy/'>Doug McIlroy</a>",
"IDE features are language smells.— Reg Braithwaite",
"PHP is [the] Sarah Palin of programming languages.— killerstorm [http://www.reddit.com/r/programming/comments/b7j9v/debian_refuses_to_package_the_embedded_php/c0ldcqg]",
"A good way to have good ideas is by being unoriginal.— Bram Cohen",
"The comment about developers making work for themselves is also spot on. Ianswer a lot of programming questions, and the questions are always askedbecause the programmer has reached the end of a twisty maze of his owncreation. Turn around, walk, spin around, and try again. You'll find a bettersolution.— Jonathan Rockway in a Hacker News comment",
"a program is like a poem: you cannot write a poem without writing it. Yetpeople talk about programming as if it were a production process and measure« programmer productivity'in terms of 'number of lines of code produced ».In sodoing they book that number on the wrong side of the ledger: We should alwaysrefer to'the number of lines of code spent'.— E. W. Dijkstra",
"it's an old observation that in order to be useful hypothesis has to befalsifiable. Similar principle applies to design proposals - to be worth ofany attention they have to be detailed enough to allow meaningful criticism.What you have done so far is equivalent to coming to a hospital and saying« aseptic good, infection bad ». That would get pretty much the same reactions,varying from « yes, we know » to « do you have any specific suggestions? » and« stop wasting our time »[1].In short: get lost and do not come back until you have something lessvague.[1] If you are insistent enough, you might also earn a free referralto psychiatrist.— Al Viro in lkml",
"<blockquote>These are some of the types of problems engineers at REAL software shops haveto solve to be able to ship REAL product for REAL money. If you haven't HADto produce code like this yourself at some point in your carrier then you'velived a sheltered life.Its disingenuous for you to get on your ivory tower to point and laugh.</blockquote>Well, you see, after spending years cleaning up the excrements of self-styled« REAL engineers » it's either get on the tower to point and laugh or get on thetower to point and shoot.— Al Viro in lkml",
"Layered approach' is not a magic incantation to excuse any bit of snake oil.Homeopathic remedies might not harm (pure water is pure water), but that's notan excuse for quackery. And frankly, most of the security improvement' crowdsound exactly like woo-peddlers.— Al Viro",
"The trick is to fix the problem you have, rather than the problem you want.— Bram Cohen",
"Security is a state of mind.— NSA Security Manual",
"Never attribute to funny hardware that which can be adequately explained bybroken locking.— Erik Quanstrom",
"Things which any idiot could write usually have the quality of having beenwritten by an idiot.— Bram Cohen",
"In programming the hard part isn't solving problems, but deciding what problemsto solve.— Paul Graham",
"[POSIX] unifying unix? more like formalizing historical design mistakes made bymajor vendors…— ttyv0",
"Do I really want to be using a language where memoize is a PhD-level topic?— Mark Engelberg about Haskell",
"The beauty of small and simple code is that you can bend or break the rules aslong it stays small and simple. Rules allow people to write code withoutthinking. [And when] you dont think […] you get bloated code that justconcatenates stupid patterns.People stop thinking and questioning [and] then its just worshipping some ruleswithout any pruporse.— Cinap Lenrek",
"If you start programming by learning perl you will just become a menace to yourself and others.— egoncasteel",
"When there is no type hierarchy you don't have to manage the type hierarchy.— <a href='http://genius.cat-v.org/rob-pike/'>Rob Pike</a>",
"Programming languages should be designed not by piling feature on top offeature, but by removing the weaknesses and restrictions that make additionalfeatures appear necessary.— RnRS",
"Software efficiency halves every 18 months, compensating Moore's Law.— May's Law",
"So-called « smart » software usually is the worst you can imagine.— Christian Neukirchen",
"Such is modern computing: everything simple is made too complicated becauseit's easy to fiddle with; everything complicated stays complicated because it'shard to fix.— Rob Pike",
"It is not that uncommon for the cost of an abstraction to outweigh the benefitit delivers. Kill one today!— John Carmack",
"So much complexity in software comes from trying to make one thing do two things.— Ryan Singer",
"The standard rule is, when you're in a hole, stop digging; that seems not toapply [to] software nowadays.— Ron Minnich",
"Languages that try to disallow idiocy become themselves idiotic.— Rob Pike",
"<ul><li>uriel: <em>When I read « OMG (Object Management Group) » I think « Oh My God! ».</em></li><li>gobongo: <em>Fitting because whenever someone suggests I use UML I think « Oh My God (is this guy on crack?)! ».</em></li></ul>",
"There's nothing in computing that can't be broken by another level ofindirection.— Rob Pike",
"A complex system that works is invariably found to have evolved from a simplesystem that worked. The inverse proposition also appears to be true: A complexsystem designed from scratch never works and cannot be made to work.— John Gall",
"« design patterns » are concepts used by people who can't learn by any methodexcept memorization, so in place of actual programming ability, they memorize« patterns » and throw each one in sequence at a problem until it works— Dark_Shikari",
"One of the big lessons of a big project is you don't want people that aren'treally programmers programming, you'll suffer for it!— John Carmack",
"Premature optimization, that's like a sneeze. Premature abstraction is likeebola; it makes my eyes bleed.— Christer Ericson",
"Premature optimizations can be troublesome to revert, but prematuregeneralizations are often near impossible.— Emil Persson",
"Premature optimization, that's like a fart. Premature abstraction is liketaking a dump on another developer's desk.— Chris Eric",
"Normal people believe that if it ain't broke, don't fix it. Engineers believethat if it ain't broke, it doesn't have enough features yet.— Scott Adams",
"If you give someone a program, you will frustrate them for a day; if you teachthem how to program, you will frustrate them for a lifetime.— David Leinweber (NOWS)",
"And don't EVER make the mistake that you can design something better than whatyou get from ruthless massively parallel trial-and-error with a feedback cycle.That's giving your intelligence <em>much</em> too much credit.— Linus (http://tinyurl.com/2kkl77)"
]

View File

@ -1,6 +1,11 @@
{
"token": "INSERT TOKEN HERE",
"twitter access token": "INSERT TOKEN HERE",
"twitter access secret": "INSERT TOKEN HERE",
"twitter consumer key": "INSERT TOKEN HERE",
"twitter consumer secret": "INSERT TOKEN HERE",
"history size": 10,
"history file": "history.json",
"users file": "users.json"
"users file": "users.json",
"chat data file": "chat_data.json"
}

View File

@ -1,8 +1,8 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 11:56:47
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 11:58:34
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-04 10:48:26
*/
package shared
@ -11,4 +11,5 @@ import (
tb "gopkg.in/tucnak/telebot.v2"
)
// Bot contains telebot instance
var Bot *tb.Bot

106
shared/chat.go Normal file
View File

@ -0,0 +1,106 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-27 15:37:59
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-05 17:46:26
*/
package shared
import (
"encoding/json"
"fmt"
"io/ioutil"
"sync"
)
// General purpose chat info storage
type chatData struct {
mutex sync.Mutex
data map[int64]map[string]interface{}
}
type chatDataFile struct {
mutex sync.Mutex
path string
}
// ChatData manage access to stored data about a chat
var ChatData *chatData
var cdf chatDataFile
// InitChatData is meant to store infos about a chat.
func InitChatData(chatDataFilePath string) {
cdf = chatDataFile{path: chatDataFilePath}
ChatData = &chatData{data: make(map[int64]map[string]interface{})}
ChatData.mutex.Lock()
defer ChatData.mutex.Unlock()
cdf.read()
}
// Set stores data about a chat
func (c *chatData) Set(chat int64, key string, data interface{}) {
c.mutex.Lock()
defer c.mutex.Unlock()
if _, exists := c.data[chat]; !exists {
c.data[chat] = make(map[string]interface{})
}
c.data[chat][key] = data
go cdf.write()
}
// Get retrieves data about a chat
func (c *chatData) Get(chat int64, key string) (interface{}, bool) {
c.mutex.Lock()
defer c.mutex.Unlock()
m, exists := c.data[chat]
if !exists {
return nil, false
}
data, ok := m[key]
if !ok {
return nil, false
}
return data, true
}
func (c *chatDataFile) read() {
c.mutex.Lock()
defer c.mutex.Unlock()
data, err := ioutil.ReadFile(c.path)
if err != nil {
// File doesn't exist, skip import
return
}
if err := json.Unmarshal(data, &ChatData.data); err != nil {
fmt.Printf("Error while unmarshaling chat data with path %s, error : %v\n", c.path, err)
}
}
func (c *chatDataFile) write() {
c.mutex.Lock()
defer c.mutex.Unlock()
ChatData.mutex.Lock()
defer ChatData.mutex.Unlock()
data, err := json.Marshal(ChatData.data)
if err != nil {
fmt.Printf("Error while marshaling chat data file with path %s, error : %v\n", c.path, err)
return
}
if err := ioutil.WriteFile(c.path, data, 0770); err != nil {
fmt.Printf("Error writing chat data file with path %s, error %v\n", c.path, err)
}
}

View File

@ -1,14 +1,15 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 01:27:11
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 12:54:21
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-05 17:45:18
*/
package shared
import (
"encoding/json"
"fmt"
"io/ioutil"
"sync"
)
@ -24,32 +25,40 @@ type historyFile struct {
path string
}
var History history
// History manages acces to chat history
var History *history
var hf historyFile
// Init a chat history of a given size
func InitHistory(size int, history_file_path string) {
// InitHistory init a chit history of a given size
func InitHistory(size int, historyFilePath string) {
hf = historyFile{}
hf.path = history_file_path
History = history{}
hf.path = historyFilePath
History = &history{}
History.mutex.Lock()
defer History.mutex.Unlock()
History.size = size
History.data = make(map[int64][]string)
hf.read()
}
// Get the number of messages saved in the history
func (h history) Size() int {
// Size get the number of messages saved in the history
func (h *history) Size() int {
h.mutex.Lock()
defer h.mutex.Unlock()
return h.size
}
// Get a selected message in a chat history
func (h history) Message(chatID int64, n int) string {
// Message get a selected message in a chat history
func (h *history) Message(chatID int64, n int) string {
h.mutex.Lock()
defer h.mutex.Unlock()
array, exists := h.data[chatID]
if exists && n >= 0 && n < len(array) {
return array[n]
@ -57,30 +66,36 @@ func (h history) Message(chatID int64, n int) string {
return ""
}
// Append a message to a given chat
func (h history) AddMessage(chatID int64, m string) {
// AddMessage append a message to a given chat
func (h *history) AddMessage(chatID int64, m string) {
h.mutex.Lock()
defer h.mutex.Unlock()
if _, exists := h.data[chatID]; !exists {
h.data[chatID] = make([]string, h.size, h.size)
}
h.append(chatID, m)
}
// Get the last message of a given chat
func (h history) LastMessage(chatID int64) string {
// LastMessage get the last message of a given chat
func (h *history) LastMessage(chatID int64) string {
h.mutex.Lock()
defer h.mutex.Unlock()
if _, exists := h.data[chatID]; exists {
return h.data[chatID][h.size-1]
}
return ""
}
// Get a copy of a given chat history
func (h history) ChatHistory(chatID int64) []string {
// ChatHistory get a copy of a given chat history
func (h *history) ChatHistory(chatID int64) []string {
h.mutex.Lock()
defer h.mutex.Unlock()
array, exists := h.data[chatID]
if exists {
c := make([]string, h.size, h.size)
@ -92,7 +107,8 @@ func (h history) ChatHistory(chatID int64) []string {
// Add a message at the end of a chat and move everithyng up
// Assert that the slice exists and mutex already locked
func (h history) append(chatID int64, m string) {
func (h *history) append(chatID int64, m string) {
c := make([]string, h.size-1, h.size-1)
array, _ := h.data[chatID]
copy(c, array[1:])
@ -103,22 +119,35 @@ func (h history) append(chatID int64, m string) {
go hf.write()
}
func (h historyFile) read() {
func (h *historyFile) read() {
h.mutex.Lock()
defer h.mutex.Unlock()
data, err := ioutil.ReadFile(h.path)
if err != nil {
// File doesn't exist, skip import
return
}
json.Unmarshal(data, &History.data)
if err := json.Unmarshal(data, &History.data); err != nil {
fmt.Printf("Error while unmarshaling user history with path %s, error : %v\n", h.path, err)
}
}
func (h historyFile) write() {
func (h *historyFile) write() {
h.mutex.Lock()
defer h.mutex.Unlock()
History.mutex.Lock()
defer History.mutex.Unlock()
data, _ := json.Marshal(History.data)
ioutil.WriteFile(h.path, data, 0770)
data, err := json.Marshal(History.data)
if err != nil {
fmt.Printf("Error while marshaling history file with path %s, error : %v\n", h.path, err)
return
}
if err := ioutil.WriteFile(h.path, data, 0770); err != nil {
fmt.Printf("Error writing history file with path %s, error %v\n", h.path, err)
}
}

View File

@ -1,16 +1,19 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 14:41:03
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 17:49:51
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-05 17:45:59
*/
package shared
import (
"encoding/json"
"fmt"
"io/ioutil"
"sync"
tb "gopkg.in/tucnak/telebot.v2"
)
type users struct {
@ -23,23 +26,30 @@ type usersFile struct {
path string
}
var Users users
// Users shared user for commands
var Users *users
var uf usersFile
func InitUsers(users_file_path string) {
// InitUsers inits the User info storage
func InitUsers(usersFilePath string) {
uf = usersFile{}
uf.path = users_file_path
Users = users{}
uf.path = usersFilePath
Users = &users{}
Users.mutex.Lock()
defer Users.mutex.Unlock()
Users.data = make(map[string]map[string]string)
uf.read()
}
// Get an info about a given user
func (u users) Get(username string, key string) (string, bool) {
func (u *users) Get(username string, key string) (string, bool) {
u.mutex.Lock()
defer u.mutex.Unlock()
user, exists := u.data[username]
if !exists {
return "", false
@ -50,10 +60,12 @@ func (u users) Get(username string, key string) (string, bool) {
return user[key], true
}
// Add an info about a given user
func (u users) Set(username string, key, data string) {
// Set add an info about a given user
func (u *users) Set(username string, key, data string) {
u.mutex.Lock()
defer u.mutex.Unlock()
if _, exists := u.data[username]; !exists {
u.data[username] = make(map[string]string)
}
@ -61,22 +73,75 @@ func (u users) Set(username string, key, data string) {
go uf.write()
}
func (u usersFile) read() {
// GetUsernames get all usernames stored in settings
func (u *users) GetUsernames() []string {
u.mutex.Lock()
defer u.mutex.Unlock()
var usernames []string
for username := range u.data {
usernames = append(usernames, username)
}
return usernames
}
// GetUserChat retrieve the chat of the user if registered
func (u *users) GetUserChat(username string) (*tb.Chat, error) {
serializedChat, exists := u.Get(username, "private_chat")
if !exists {
return nil, fmt.Errorf("No private chat registered for %s", username)
}
chat := &tb.Chat{}
if json.Unmarshal([]byte(serializedChat), chat) != nil {
return nil, fmt.Errorf("Error while parsing chat for %s", username)
}
return chat, nil
}
// SetUserChat register a private chat for an user
func (u *users) SetUserChat(username string, chat *tb.Chat) {
serializedChat, err := json.Marshal(chat)
if err != nil {
return
}
u.Set(username, "private_chat", string(serializedChat))
}
func (u *usersFile) read() {
u.mutex.Lock()
defer u.mutex.Unlock()
data, err := ioutil.ReadFile(u.path)
if err != nil {
// File doesn't exist, skip import
return
}
json.Unmarshal(data, &Users.data)
if err := json.Unmarshal(data, &Users.data); err != nil {
fmt.Printf("Error while unmarshaling user file with path %s, error : %v\n", u.path, err)
}
}
func (u usersFile) write() {
func (u *usersFile) write() {
u.mutex.Lock()
defer u.mutex.Unlock()
Users.mutex.Lock()
defer Users.mutex.Unlock()
data, _ := json.Marshal(Users.data)
ioutil.WriteFile(u.path, data, 0770)
data, err := json.Marshal(Users.data)
if err != nil {
fmt.Printf("Error while marshaling user file with path %s, error : %v\n", u.path, err)
return
}
if err := ioutil.WriteFile(u.path, data, 0770); err != nil {
fmt.Printf("Error writing user file with path %s, error : %v\n", u.path, err)
}
}