Initial commit
Main structure is mostly figured out. Only a noun phrase is currently generated.
This commit is contained in:
commit
3d6c1a444f
|
@ -0,0 +1,4 @@
|
|||
bin/
|
||||
settings.json
|
||||
*.sqlite
|
||||
*.txt
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
#SOURCES= *.go \
|
||||
# api/*.go \
|
||||
# business/*.go \
|
||||
# cmd/*.go \
|
||||
# database/*.go \
|
||||
# frontend/*.go \
|
||||
# models/*.go
|
||||
|
||||
SOURCES=$(shell find . -type f -name "*.go")
|
||||
|
||||
bin/server: bin/ $(SOURCES)
|
||||
go build -o bin/server cmd/server.go
|
||||
|
||||
bin/:
|
||||
mkdir -p bin
|
|
@ -0,0 +1,2 @@
|
|||
package api
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package business
|
||||
|
||||
import (
|
||||
"github.com/zorchenhimer/hacker-quotes/models"
|
||||
//"github.com/zorchenhimer/hacker-quotes/database"
|
||||
)
|
||||
|
||||
type HackerQuotes interface {
|
||||
// Random returns a completely randomized quote.
|
||||
Random() (string, error)
|
||||
|
||||
// Format returns a quote in the given format.
|
||||
Format(format string) (string, error)
|
||||
|
||||
// InitData populates the underlying database with data from the given json file.
|
||||
InitData(filename string) error
|
||||
}
|
||||
|
||||
type Admin interface {
|
||||
AddNoun(word models.Noun) error
|
||||
AddVerb(word models.Verb) error
|
||||
|
||||
RemoveNoun(word string) error
|
||||
// Word is the indefinite form.
|
||||
RemoveVerb(word string) error
|
||||
|
||||
GetNouns() ([]models.Noun, error)
|
||||
GetVerbs() ([]models.Verb, error)
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
package business
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"github.com/zorchenhimer/hacker-quotes/database"
|
||||
"github.com/zorchenhimer/hacker-quotes/models"
|
||||
)
|
||||
|
||||
type generic struct {
|
||||
db database.DB
|
||||
}
|
||||
|
||||
func NewGeneric(db database.DB) (HackerQuotes, error) {
|
||||
return &generic{db: db}, nil
|
||||
}
|
||||
|
||||
func (g *generic) Random() (string, error) {
|
||||
definite := rand.Int() % 2 == 0
|
||||
hasAdj := rand.Int() % 2 == 0
|
||||
plural := rand.Int() % 2 == 0
|
||||
|
||||
np, err := g.nounPhrase(definite, hasAdj, plural)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
//fmt.Printf("(%s) definite: %t; hasAdj: %t; plural: %t\n", np, definite, hasAdj, plural)
|
||||
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString(np)
|
||||
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
func (g *generic) Format(format string) (string, error) {
|
||||
return "", fmt.Errorf("Not implemented")
|
||||
}
|
||||
|
||||
func (g *generic) nounPhrase(definite, hasAdj, plural bool) (string, error){
|
||||
adj := ""
|
||||
var err error
|
||||
if hasAdj {
|
||||
adj, err = g.randomAdjective()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
noun, err := g.randomNoun(plural)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
phrase := adj
|
||||
if phrase != "" {
|
||||
phrase += " " + noun
|
||||
} else {
|
||||
phrase = noun
|
||||
}
|
||||
|
||||
if definite && !plural {
|
||||
//fmt.Println("[nounPhrase] definite && !plural")
|
||||
return "the " + phrase, nil
|
||||
}
|
||||
|
||||
if !plural {
|
||||
//fmt.Println("[nounPhrase] !plural")
|
||||
return ana(phrase), nil
|
||||
}
|
||||
|
||||
return phrase, nil
|
||||
}
|
||||
|
||||
func (g *generic) randomAdjective() (string, error) {
|
||||
ids, err := g.db.GetAdjectiveIds()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[adj] get IDs error: %v", err)
|
||||
}
|
||||
|
||||
if len(ids) <= 0 {
|
||||
return "", fmt.Errorf("No adjective IDs returned from database")
|
||||
}
|
||||
|
||||
rid := int(rand.Int63n(int64(len(ids))))
|
||||
//fmt.Printf("[adj] len(ids): %d; rid: %d; %d\n", len(ids), rid, ids[rid])
|
||||
|
||||
adj, err := g.db.GetAdjective(ids[rid])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[adj] ID: %d; %v", ids[rid], err)
|
||||
}
|
||||
|
||||
return adj.Word, nil
|
||||
}
|
||||
|
||||
func (g *generic) randomNoun(plural bool) (string, error) {
|
||||
ids, err := g.db.GetNounIds()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[noun] get IDs error: %v", err)
|
||||
}
|
||||
|
||||
if len(ids) <= 0 {
|
||||
return "", fmt.Errorf("No noun IDs returned from database")
|
||||
}
|
||||
|
||||
rid := int(rand.Int63n(int64(len(ids))))
|
||||
//fmt.Printf("[noun] len(ids): %d; rid: %d; ID: %d\n", len(ids), rid, ids[rid])
|
||||
|
||||
noun, err := g.db.GetNoun(ids[rid])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[noun] ID: %d; %v", ids[rid], err)
|
||||
}
|
||||
|
||||
if plural {
|
||||
return noun.Plural(), nil
|
||||
}
|
||||
return noun.Word, nil
|
||||
}
|
||||
|
||||
func (g *generic) randomVerb() (string, error) {
|
||||
ids, err := g.db.GetVerbIds()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[verb] get IDs error: %v", err)
|
||||
}
|
||||
|
||||
if len(ids) <= 0 {
|
||||
return "", fmt.Errorf("No verb IDs returned from database")
|
||||
}
|
||||
|
||||
rid := int(rand.Int63n(int64(len(ids))))
|
||||
verb, err := g.db.GetVerb(ids[rid])
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("[verb] ID: %d; %v", ids[rid], err)
|
||||
}
|
||||
|
||||
return verb.Word, nil
|
||||
}
|
||||
|
||||
func (g *generic) InitData(filename string) error {
|
||||
fmt.Printf("Initializing database with data in %q\n", filename)
|
||||
if g.db == nil {
|
||||
return fmt.Errorf("databse is nil!")
|
||||
}
|
||||
|
||||
raw, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := map[string][][]string{}
|
||||
if err = json.Unmarshal(raw, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawadj, ok := data["adjectives"]
|
||||
if !ok {
|
||||
return fmt.Errorf("Missing adjectives key in data")
|
||||
}
|
||||
|
||||
|
||||
adjectives := []models.Adjective{}
|
||||
for _, adj := range rawadj {
|
||||
t, word := adj[0], adj[1]
|
||||
a := models.Adjective{Word: word}
|
||||
if strings.Contains(t, "a") {
|
||||
a.Absolute = true
|
||||
}
|
||||
if strings.Contains(t, "e") {
|
||||
a.AppendEst = true
|
||||
}
|
||||
if strings.Contains(t, "m") {
|
||||
a.AppendMore = true
|
||||
}
|
||||
|
||||
adjectives = append(adjectives, a)
|
||||
}
|
||||
|
||||
rawnoun, ok := data["nouns"]
|
||||
if !ok {
|
||||
return fmt.Errorf("Missing nouns key in data")
|
||||
}
|
||||
|
||||
nouns := []models.Noun{}
|
||||
for _, noun := range rawnoun {
|
||||
t, word := noun[0], noun[1]
|
||||
n := models.Noun{Word: word}
|
||||
|
||||
if strings.Contains(t, "m") {
|
||||
n.Multiple = true
|
||||
}
|
||||
|
||||
if strings.Contains(t, "b") {
|
||||
n.Begin = true
|
||||
}
|
||||
|
||||
if strings.Contains(t, "e") {
|
||||
n.End = true
|
||||
}
|
||||
|
||||
if strings.Contains(t, "a") {
|
||||
n.Alone = true
|
||||
}
|
||||
|
||||
if strings.Contains(t, "r") {
|
||||
n.Regular = true
|
||||
}
|
||||
|
||||
nouns = append(nouns, n)
|
||||
}
|
||||
|
||||
rawverbs, ok := data["verbs"]
|
||||
if !ok {
|
||||
return fmt.Errorf("Missing verbs key in data")
|
||||
}
|
||||
|
||||
verbs := []models.Verb{}
|
||||
for _, word := range rawverbs {
|
||||
v := models.Verb{Word: word[1]}
|
||||
if strings.Contains(word[0], "r") {
|
||||
v.Regular = true
|
||||
}
|
||||
|
||||
verbs = append(verbs, v)
|
||||
}
|
||||
|
||||
return g.db.InitData(adjectives, nouns, verbs, nil)
|
||||
}
|
||||
|
||||
// Prepend "a", "an" or nothing to a phrase
|
||||
func ana(phrase string) string {
|
||||
//fmt.Printf("[ana] phrase[0]: %s; %q\n", string(phrase[0]), phrase)
|
||||
if strings.ContainsAny(string(phrase[0]), "aeiou") {
|
||||
return "an " + phrase
|
||||
}
|
||||
|
||||
return "a " + phrase
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
|
||||
"github.com/zorchenhimer/hacker-quotes/business"
|
||||
"github.com/zorchenhimer/hacker-quotes/database"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("len(os.Args):", len(os.Args))
|
||||
|
||||
var count int = 1
|
||||
if len(os.Args) == 2 {
|
||||
fmt.Sscanf(os.Args[1], "%d", &count)
|
||||
}
|
||||
|
||||
db, err := database.New("sqlite", "file:db.sqlite?mode=memory")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
hq, err := business.NewGeneric(db)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = hq.InitData("word_lists.json")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if count == 1 {
|
||||
sentence, err := hq.Random()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("\n>>", sentence, "<<\n")
|
||||
} else {
|
||||
fmt.Println("")
|
||||
for i := 0; i < count; i++ {
|
||||
sentence, err := hq.Random()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(">>", sentence, "<<")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/zorchenhimer/hacker-quotes"
|
||||
)
|
||||
|
||||
func main() {
|
||||
server, err := hacker.New("settings.json")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
server.Hack()
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/zorchenhimer/hacker-quotes/models"
|
||||
)
|
||||
|
||||
type DbType string
|
||||
const (
|
||||
DB_Json DbType = "json"
|
||||
DB_PostgresSQL DbType = "pgsql"
|
||||
DB_SQLite DbType = "sqlite"
|
||||
)
|
||||
|
||||
type DB interface {
|
||||
// Sentence returns a format string for a sentence with the given ID.
|
||||
//Sentence(id int) (string, error)
|
||||
|
||||
AddAdjective(word models.Adjective) error
|
||||
AddNoun(word models.Noun) error
|
||||
AddVerb(word models.Verb) error
|
||||
|
||||
RemoveAdjective(id int) error
|
||||
RemoveNoun(id int) error
|
||||
RemoveVerb(id int) error
|
||||
|
||||
GetAdjectiveIds() ([]int, error)
|
||||
GetNounIds() ([]int, error)
|
||||
GetVerbIds() ([]int, error)
|
||||
|
||||
GetAdjective(id int) (*models.Adjective, error)
|
||||
GetNoun(id int) (*models.Noun, error)
|
||||
GetVerb(id int) (*models.Verb, error)
|
||||
|
||||
InitData([]models.Adjective, []models.Noun, []models.Verb, []string) error
|
||||
IsNew() bool
|
||||
Close()
|
||||
}
|
||||
|
||||
type dbInit func(connectionString string) (DB, error)
|
||||
var registered map[DbType]dbInit
|
||||
|
||||
func New(databaseType DbType, connectionString string) (DB, error) {
|
||||
f, ok := registered[databaseType]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Unregistered database type: %s", databaseType)
|
||||
}
|
||||
|
||||
return f(connectionString)
|
||||
}
|
||||
|
||||
func register(databaseType DbType, initFunc dbInit) {
|
||||
if registered == nil {
|
||||
registered = make(map[DbType]dbInit)
|
||||
}
|
||||
if _, exists := registered[databaseType]; exists {
|
||||
panic(fmt.Sprintf("Unable to register database with type %s: already exists.", databaseType))
|
||||
}
|
||||
|
||||
registered[databaseType] = initFunc
|
||||
}
|
||||
|
||||
// fileExists returns whether the given file or directory exists or not.
|
||||
// Taken from https://stackoverflow.com/a/10510783
|
||||
func fileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
|
||||
"github.com/zorchenhimer/hacker-quotes/models"
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(DB_SQLite, sqliteInit)
|
||||
}
|
||||
|
||||
type sqliteDb struct {
|
||||
db *sql.DB
|
||||
isNew bool
|
||||
}
|
||||
|
||||
func sqliteInit(connectionString string) (DB, error) {
|
||||
fmt.Println("[sqlite] DB file:", connectionString)
|
||||
|
||||
newDb := false
|
||||
if !fileExists(connectionString) {
|
||||
newDb = true
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s", connectionString))
|
||||
if err != nil {
|
||||
fmt.Println("[sqlite] Open error:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if newDb {
|
||||
stmt := `
|
||||
create table Adjectives (id integer not null primary key, absolute bool, appendMore bool, appendEst bool, word text);
|
||||
create table Nouns (id integer not null primary key, multiple bool, begin bool, end bool, alone bool, regular bool, word text);
|
||||
create table Verbs (id integer not null primary key, regular bool, word text);
|
||||
`
|
||||
//create table Sentences (id integer not null primary key, sentence text)
|
||||
|
||||
if _, err := db.Exec(stmt); err != nil {
|
||||
fmt.Println("[sqlite], DB table creation error:", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("[sqlite] no errors")
|
||||
return &sqliteDb{db: db, isNew: newDb}, nil
|
||||
}
|
||||
|
||||
func (s *sqliteDb) prep(query string) (*sql.Tx, *sql.Stmt, error) {
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare(query)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return tx, stmt, nil
|
||||
}
|
||||
|
||||
func (s *sqliteDb) Sentence(id int) (string, error) {
|
||||
stmt, err := s.db.Prepare("select from sentences where id = ?")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
var sentence string
|
||||
if err = stmt.QueryRow(id).Scan(&sentence); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return sentence, nil
|
||||
}
|
||||
|
||||
func (s *sqliteDb) AddAdjective(word models.Adjective) error {
|
||||
tx, stmt, err := s.prep("insert into Adjectives (Absolute, AppendMore, AppendEst, Word) values (?, ?, ?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
if _, err := stmt.Exec(word.Absolute, word.AppendMore, word.AppendEst, word.Word); err != nil {
|
||||
txerr := tx.Rollback()
|
||||
if txerr != nil {
|
||||
return fmt.Errorf("rollback error: %v; exec error: %v", txerr, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *sqliteDb) AddNoun(word models.Noun) error {
|
||||
tx, stmt, err := s.prep("insert into nouns (Multiple, Begin, End, Alone, Regular, Word) values (?, ?, ?, ?, ?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
if _, err := stmt.Exec(word.Multiple, word.Begin, word.End, word.Alone, word.Regular, word.Word); err != nil {
|
||||
txerr := tx.Rollback()
|
||||
if txerr != nil {
|
||||
return fmt.Errorf("rollback error: %v; exec error: %v", txerr, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *sqliteDb) AddVerb(word models.Verb) error {
|
||||
tx, stmt, err := s.prep("insert into verbs (Regular, Word) values (?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
if _, err := stmt.Exec(word.Regular, word.Word); err != nil {
|
||||
txerr := tx.Rollback()
|
||||
if txerr != nil {
|
||||
return fmt.Errorf("rollback error: %v; exec error: %v", txerr, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (s *sqliteDb) removeWord(query string, id int) error {
|
||||
stmt, err := s.db.Prepare(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
_, err = stmt.Exec(id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *sqliteDb) RemoveAdjective(id int) error {
|
||||
return s.removeWord("delete from adjectives where id = ?", id)
|
||||
}
|
||||
|
||||
func (s *sqliteDb) RemoveNoun(id int) error {
|
||||
return s.removeWord("delete from nouns where id = ?", id)
|
||||
}
|
||||
|
||||
func (s *sqliteDb) RemoveVerb(id int) error {
|
||||
return s.removeWord("delete from verbs where id = ?", id)
|
||||
}
|
||||
|
||||
func (s *sqliteDb) readIds(query string) ([]int, error) {
|
||||
rows, err := s.db.Query("select id from adjectives")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
ids := []int{}
|
||||
for rows.Next() {
|
||||
var id int
|
||||
if err = rows.Scan(&id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
return ids, rows.Err()
|
||||
}
|
||||
|
||||
func (s *sqliteDb) GetAdjectiveIds() ([]int, error) {
|
||||
return s.readIds("select id from adjectives")
|
||||
}
|
||||
|
||||
func (s *sqliteDb) GetNounIds() ([]int, error) {
|
||||
return s.readIds("select id from nouns")
|
||||
}
|
||||
|
||||
func (s *sqliteDb) GetVerbIds() ([]int, error) {
|
||||
return s.readIds("select id from verbs")
|
||||
}
|
||||
|
||||
func (s *sqliteDb) GetAdjective(id int) (*models.Adjective, error) {
|
||||
stmt, err := s.db.Prepare("select Id, Absolute, AppendMore, AppendEst, Word from Adjectives where id = ?")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
adj := &models.Adjective{}
|
||||
if err = stmt.QueryRow(id).Scan(&adj.Id, &adj.Absolute, &adj.AppendMore, &adj.AppendEst, &adj.Word); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return adj, nil
|
||||
}
|
||||
|
||||
func (s *sqliteDb) GetNoun(id int) (*models.Noun, error) {
|
||||
stmt, err := s.db.Prepare("select Id, Multiple, Begin, End, Alone, Regular, Word from Nouns where id = ?")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
noun := &models.Noun{}
|
||||
if err = stmt.QueryRow(id).Scan(&noun.Id, &noun.Multiple, &noun.Begin, &noun.End, &noun.Alone, &noun.Regular, &noun.Word); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return noun, nil
|
||||
}
|
||||
|
||||
func (s *sqliteDb) GetVerb(id int) (*models.Verb, error) {
|
||||
stmt, err := s.db.Prepare("select Id, Regular, Word from Verbs where id = ?")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
verb := &models.Verb{}
|
||||
if err = stmt.QueryRow(id).Scan(&verb.Id, &verb.Regular, &verb.Word); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return verb, nil
|
||||
}
|
||||
|
||||
func (s *sqliteDb) InitData(adjectives []models.Adjective, nouns []models.Noun, verbs []models.Verb, sentences []string) error {
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
astmt_txt := "insert into adjectives (Absolute, AppendMore, AppendEst, Word) values (?, ?, ?, ?)"
|
||||
fmt.Println(astmt_txt)
|
||||
|
||||
astmt, err := tx.Prepare(astmt_txt)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for _, adj := range adjectives {
|
||||
_, err = astmt.Exec(adj.Absolute, adj.AppendMore, adj.AppendEst, adj.Word)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
astmt.Close()
|
||||
|
||||
nstmt_txt := "insert into nouns (Multiple, Begin, End, Alone, Regular, Word) values (?, ?, ?, ?, ?, ?)"
|
||||
fmt.Println(nstmt_txt)
|
||||
|
||||
nstmt, err := tx.Prepare(nstmt_txt)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for _, noun := range nouns {
|
||||
if _, err = nstmt.Exec(noun.Multiple, noun.Begin, noun.End, noun.Alone, noun.Regular, noun.Word); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
nstmt.Close()
|
||||
|
||||
vstmt_txt := "insert into verbs (Regular, Word) values (?, ?)"
|
||||
fmt.Println(vstmt_txt)
|
||||
|
||||
vstmt, err := tx.Prepare(vstmt_txt)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
for _, verb := range verbs {
|
||||
_, err = vstmt.Exec(verb.Regular, verb.Word)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
vstmt.Close()
|
||||
|
||||
//sstmt, err := tx.Prepare("insert into sentences (Sentence) values (?)")
|
||||
//if err != nil {
|
||||
// tx.Rollback()
|
||||
// return err
|
||||
//}
|
||||
|
||||
//for _, sentence := range sentences {
|
||||
// _, err = sstmt.Exec(sentence)
|
||||
// if err != nil {
|
||||
// tx.Rollback()
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
//sstmt.Close()
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.isNew = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sqliteDb) IsNew() bool {
|
||||
return s.isNew
|
||||
}
|
||||
|
||||
func (s *sqliteDb) Close() {
|
||||
s.db.Close()
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package frontend
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"html/template"
|
||||
|
||||
//"github.com/gorilla/sessions"
|
||||
|
||||
//"github.com/zorchenhimer/hacker-quotes/models"
|
||||
//"github.com/zorchenhimer/hacker-quotes/database"
|
||||
"github.com/zorchenhimer/hacker-quotes/business"
|
||||
)
|
||||
|
||||
type Frontend struct {
|
||||
//db database.DB
|
||||
bs business.HackerQuotes
|
||||
//cookies *sessions.CookieStore
|
||||
templates map[string]*template.Template
|
||||
}
|
||||
|
||||
func New(bs business.HackerQuotes) (*Frontend, error) {
|
||||
f := &Frontend{
|
||||
bs: bs,
|
||||
//cookies: sessions.NewCookieStore([]byte("some auth key"), []byte("some encrypt key")),
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *Frontend) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
//parts := strings.Split(r.URL.Path, "/")
|
||||
switch r.URL.Path {
|
||||
case "/":
|
||||
f.home(w, r)
|
||||
|
||||
//case "/admin":
|
||||
// f.admin(w, r)
|
||||
|
||||
default:
|
||||
f.notFound(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Frontend) notFound(w http.ResponseWriter, r *http.Request) {
|
||||
http.NotFound(w, r)
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package frontend
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (f *Frontend) home(w http.ResponseWriter, r *http.Request) {
|
||||
words, err := f.bs.Random()
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write([]byte(words))
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
module github.com/zorchenhimer/hacker-quotes
|
||||
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/gorilla/sessions v1.2.1
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
)
|
|
@ -0,0 +1,6 @@
|
|||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
|
@ -0,0 +1,11 @@
|
|||
package models
|
||||
|
||||
type Adjective struct {
|
||||
Id int
|
||||
|
||||
Absolute bool
|
||||
AppendMore bool
|
||||
AppendEst bool
|
||||
|
||||
Word string
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Noun struct {
|
||||
Id int
|
||||
|
||||
Multiple bool
|
||||
|
||||
Begin bool
|
||||
End bool
|
||||
Alone bool
|
||||
|
||||
Regular bool
|
||||
|
||||
Word string
|
||||
}
|
||||
|
||||
func (n Noun) Plural() string {
|
||||
suffixes := []string{
|
||||
"s",
|
||||
"x",
|
||||
"sh",
|
||||
"ch",
|
||||
"ss",
|
||||
}
|
||||
|
||||
for _, sfx := range suffixes {
|
||||
if strings.HasSuffix(n.Word, sfx) {
|
||||
return n.Word + "es"
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(n.Word, "y") && !strings.ContainsAny(string(n.Word[len(n.Word)-2]), "aeiou") {
|
||||
return n.Word[:len(n.Word)-1] + "ies"
|
||||
}
|
||||
|
||||
return n.Word + "s"
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package models
|
||||
|
||||
type Verb struct {
|
||||
Id int
|
||||
|
||||
Regular bool
|
||||
|
||||
// Indefinite form
|
||||
Word string
|
||||
|
||||
ConjugationsPast []Conjugate
|
||||
ConjugationsPresent []Conjugate
|
||||
ConjugationsFuture []Conjugate
|
||||
}
|
||||
|
||||
type ConjugateType int
|
||||
const (
|
||||
CT_I ConjugateType = iota
|
||||
CT_You
|
||||
CT_It
|
||||
CT_We
|
||||
CT_They
|
||||
)
|
||||
|
||||
type Conjugate struct {
|
||||
Type ConjugateType
|
||||
Form string
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package hacker
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"fmt"
|
||||
|
||||
//"github.com/zorchenhimer/hacker-quotes/api"
|
||||
"github.com/zorchenhimer/hacker-quotes/business"
|
||||
"github.com/zorchenhimer/hacker-quotes/database"
|
||||
"github.com/zorchenhimer/hacker-quotes/frontend"
|
||||
//"github.com/zorchenhimer/hacker-quotes/models"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
db database.DB
|
||||
hs *http.Server
|
||||
bs business.HackerQuotes
|
||||
|
||||
settings *settings
|
||||
}
|
||||
|
||||
// New returns a new Server object with the settings from configFile.
|
||||
// If no file is specified, a default "settings.config" will be
|
||||
// created with default settings in the current working directory.
|
||||
func New(configFile string) (*Server, error) {
|
||||
s := &Server{}
|
||||
|
||||
if settings, err := loadSettings(configFile); err != nil {
|
||||
return nil, fmt.Errorf("Unable to load settings: %s", err)
|
||||
} else {
|
||||
s.settings = settings
|
||||
}
|
||||
|
||||
db, err := database.New(s.settings.DatabaseType, s.settings.ConnectionString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to load database type %s: %s", s.settings.DatabaseType, err)
|
||||
}
|
||||
|
||||
s.db = db
|
||||
|
||||
bs, err := business.NewGeneric(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.bs = bs
|
||||
|
||||
if s.db.IsNew() {
|
||||
fmt.Println("database is new")
|
||||
err = bs.InitData("word_lists.json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
fmt.Println("database isn't new")
|
||||
}
|
||||
|
||||
|
||||
web, err := frontend.New(s.bs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to load frontend: %s", err)
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
//mux.Handle("/api", api)
|
||||
mux.Handle("/", web)
|
||||
|
||||
hs := &http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
s.hs = hs
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Server) Hack() error {
|
||||
if err := s.hs.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
fmt.Println("Error running HTTP server:", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Shutdown() error {
|
||||
return fmt.Errorf("Not implemented")
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package hacker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/zorchenhimer/hacker-quotes/database"
|
||||
)
|
||||
|
||||
type settings struct {
|
||||
DatabaseType database.DbType
|
||||
ConnectionString string
|
||||
|
||||
HttpAddr string
|
||||
}
|
||||
|
||||
func loadSettings(filename string) (*settings, error) {
|
||||
if !fileExists(filename) {
|
||||
return nil, fmt.Errorf("%q doesn't exist", filename)
|
||||
//return &settings{
|
||||
// HttpAddr: ":8080",
|
||||
//}, nil
|
||||
}
|
||||
|
||||
raw, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error reading file: %s", err)
|
||||
}
|
||||
|
||||
s := &settings{}
|
||||
if err = json.Unmarshal(raw, s); err != nil {
|
||||
return nil, fmt.Errorf("Error unmarshaling: %s", err)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// fileExists returns whether the given file or directory exists or not.
|
||||
// Taken from https://stackoverflow.com/a/10510783
|
||||
func fileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -0,0 +1,405 @@
|
|||
{
|
||||
"adjectives": [
|
||||
["tm", "quantum"],
|
||||
["tm", "virtual"],
|
||||
["ta", "shortened"],
|
||||
["tm", "common"],
|
||||
["te", "raw"],
|
||||
["tm", "random"],
|
||||
["ta", "audio"],
|
||||
["tm", "industrial"],
|
||||
["tm", "3D-printed"],
|
||||
["tm", "proprietary"],
|
||||
["tm", "forbidden"],
|
||||
["ta", "patented"],
|
||||
["tm", "neural"],
|
||||
["tm", "wireless"],
|
||||
["tm", "online"],
|
||||
["tm", "offline"],
|
||||
["tm", "primary"],
|
||||
["ta", "8-bit"],
|
||||
["tm", "open"],
|
||||
["ta", "live"],
|
||||
["tm", "flexible"],
|
||||
["tm", "adaptive"],
|
||||
["tm", "artificial"],
|
||||
["tm", "mobile"],
|
||||
["tm", "meta"],
|
||||
["tm", "regular"],
|
||||
["tm", "variable"],
|
||||
["tm", "global"],
|
||||
["tm", "automatic"],
|
||||
["tm", "geometric"],
|
||||
["tm", "inductive"],
|
||||
["tm", "default"],
|
||||
["tm", "constant"],
|
||||
["tm", "asymmetric"],
|
||||
["tm", "symmetric"],
|
||||
["tm", "robust"],
|
||||
["tm", "analog"],
|
||||
["tm", "digital"],
|
||||
["tm", "micro"],
|
||||
["tm", "standardized"],
|
||||
["tm", "hidden"],
|
||||
["tm", "biometric"],
|
||||
["tm", "safety"],
|
||||
["tm", "emulated"],
|
||||
["ta", "root"],
|
||||
["ta", "generic"],
|
||||
["ta", "bricked"],
|
||||
["ta", "miscellaneous"],
|
||||
["ta", "haptic"],
|
||||
["tm", "logical"],
|
||||
["ta", "physical"],
|
||||
["ta", "relative"],
|
||||
["ta", "lasered"],
|
||||
["ta", "licensed"],
|
||||
["ta", "robotic"],
|
||||
["tm", "immersive"],
|
||||
["ta", "customized"],
|
||||
["ta", "malfunctioning"],
|
||||
["tm", "granular"],
|
||||
["ta", "quality"],
|
||||
["ta", "open source"],
|
||||
["tm", "sophisticated"],
|
||||
["tm", "statistical"],
|
||||
["tm", "DIY"],
|
||||
["ta", "remote"],
|
||||
["ta", "handheld"],
|
||||
["tm", "bleeding edge"],
|
||||
["tm", "modern"],
|
||||
["tm", "outdated"],
|
||||
["ta", "legacy"],
|
||||
["ta", "visual"],
|
||||
["ta", "guidance"],
|
||||
["tm", "private"],
|
||||
["tm", "public"],
|
||||
["tm", "cyber"],
|
||||
["ta", "numeric"],
|
||||
["ta", "mathematical"],
|
||||
["ta", "linguistic"],
|
||||
["ta", "platform-specific"],
|
||||
["ta", "normalized"],
|
||||
["ta", "bitwise"],
|
||||
["ta", "hexadecimal"],
|
||||
["ta", "octal"],
|
||||
["ta", "binary"],
|
||||
["ta", "decimal"],
|
||||
["te", "large"],
|
||||
["te", "small"],
|
||||
["tm", "normal"],
|
||||
["ta", "infected"],
|
||||
["ta", "internal"],
|
||||
["tm", "synchron"],
|
||||
["tm", "asynchron"],
|
||||
["ta", "biometric"],
|
||||
["ta", "idle"],
|
||||
["ta", "external"],
|
||||
["ta", "reserved"],
|
||||
["ta", "explicit"],
|
||||
["ta", "implicit"],
|
||||
["tm", "decentralized"],
|
||||
["tm", "interactive"],
|
||||
["ta", "lambda"],
|
||||
["tm", "recursive"],
|
||||
["te", "weak"],
|
||||
["ta", "matching"],
|
||||
["tm", "similar"],
|
||||
["te", "strong"],
|
||||
["ta", "partial"],
|
||||
["ta", "performance"],
|
||||
["ta", "build in"]
|
||||
],
|
||||
|
||||
"nouns":[
|
||||
["sar", "git"],
|
||||
["sar", "github"],
|
||||
["sar", "gitlab"],
|
||||
["sar", "gitea"],
|
||||
["sar", "bitbucket"],
|
||||
["smer", "branch"],
|
||||
["smer", "commit"],
|
||||
["smber", "log"],
|
||||
["smar", "pull request"],
|
||||
["smar", "merge request"],
|
||||
["smber", "stash"],
|
||||
["sber", "status"],
|
||||
["smber", "tag"],
|
||||
["smber", "origin"],
|
||||
["smber", "master"],
|
||||
["smber", "lemur"],
|
||||
["sber", "spacehuhn"],
|
||||
["smber", "laser"],
|
||||
["smber", "signal"],
|
||||
["smber", "network"],
|
||||
["smber", "analyzer"],
|
||||
["smber", "application"],
|
||||
["smber", "firewall"],
|
||||
["smber", "cybernuke"],
|
||||
["sber", "IRC"],
|
||||
["smber", "mainframe"],
|
||||
["smber", "server"],
|
||||
["smber", "cloud"],
|
||||
["smbr", "reality"],
|
||||
["smer", "request"],
|
||||
["sber", "WiFi"],
|
||||
["sber", "Bluetooth"],
|
||||
["smber", "cable"],
|
||||
["sber", "ethernet"],
|
||||
["sber", "LAN"],
|
||||
["sber", "WAN"],
|
||||
["smber", "antenna"],
|
||||
["sber", "NAS"],
|
||||
["smar", "power supply"],
|
||||
["smber", "grid"],
|
||||
["smber", "display"],
|
||||
["smber", "monitor"],
|
||||
["smber", "microcontroller"],
|
||||
["smber", "controller"],
|
||||
["ser", "SoC"],
|
||||
["sbr", "SBC"],
|
||||
["sbr", "ATX"],
|
||||
["sbr", "ITX"],
|
||||
["sbr", "USB"],
|
||||
["ser", "HDD"],
|
||||
["ser", "SSD"],
|
||||
["smber", "keyboard"],
|
||||
["smer", "transition"],
|
||||
["smber", "tree"],
|
||||
["ser", "SD"],
|
||||
["ser", "LED"],
|
||||
["ser", "IDE"],
|
||||
["smer", "editor"],
|
||||
["smer", "frame"],
|
||||
["ser", "PoC"],
|
||||
["smber", "bucket"],
|
||||
["sber", "VM"],
|
||||
["smer", "identifier"],
|
||||
["sber", "middleware"],
|
||||
["sber", "bottleneck"],
|
||||
["ser", "UI"],
|
||||
["ser", "GUI"],
|
||||
["smber", "observer"],
|
||||
["smber", "singleton"],
|
||||
["smber", "array"],
|
||||
["smber", "transmitter"],
|
||||
["smber", "DVD"],
|
||||
["ber", "logic"],
|
||||
["smber", "emulation"],
|
||||
["smer", "reader"],
|
||||
["smer", "writer"],
|
||||
["smer", "label"],
|
||||
["smber", "clock"],
|
||||
["smber", "MCU"],
|
||||
["smber", "phone"],
|
||||
["smber", "space"],
|
||||
["sber", "data"],
|
||||
["sber", "analysis"],
|
||||
["smber", "sample"],
|
||||
["sber", "intelligence"],
|
||||
["smber", "sensor"],
|
||||
["smber", "camera"],
|
||||
["smber", "battery"],
|
||||
["smber", "process"],
|
||||
["smber", "website"],
|
||||
["smber", "homepage"],
|
||||
["smber", "app"],
|
||||
["smber", "error"],
|
||||
["smber", "warning"],
|
||||
["smber", "sequence"],
|
||||
["smber", "information"],
|
||||
["sbr", "ASCII"],
|
||||
["smber", "pattern"],
|
||||
["smber", "simulation"],
|
||||
["smber", "simulator"],
|
||||
["sber", "indicator"],
|
||||
["smber", "troll"],
|
||||
["smber", "regulator"],
|
||||
["smber", "container"],
|
||||
["smber", "breadboard"],
|
||||
["sber", "IC"],
|
||||
["smber", "controller"],
|
||||
["smber", "drone"],
|
||||
["smber", "deauther"],
|
||||
["smar", "if loop"],
|
||||
["sar", "GTFO"],
|
||||
["sber", "fax"],
|
||||
["smar", "garbage collector"],
|
||||
["smer", "collector"],
|
||||
["smber", "thread"],
|
||||
["smber", "model"],
|
||||
["smber", "switch"],
|
||||
["smber", "dimension"],
|
||||
["sber", "foo"],
|
||||
["sber", "bar"],
|
||||
["smber", "key"],
|
||||
["smber", "java"],
|
||||
["smber", "coffee"],
|
||||
["sbr", "null"],
|
||||
["sbr", "NaN"],
|
||||
["sbr", "undefined"],
|
||||
["smber", "integer"],
|
||||
["smber", "double"],
|
||||
["smber", "string"],
|
||||
["sar", "bare metal"],
|
||||
["smber", "adapter"],
|
||||
["smber", "framework"],
|
||||
["smber", "system"],
|
||||
["smber", "algorithm"],
|
||||
["sbr", "spacetime"],
|
||||
["smbr", "LCD"],
|
||||
["sber", "bandwidth"],
|
||||
["smber", "virus"],
|
||||
["sbr", "UTF-8"],
|
||||
["sber", "web"],
|
||||
["sbr", "handler"],
|
||||
["smber", "exeption"],
|
||||
["smber", "path"],
|
||||
["smber", "reference"],
|
||||
["smber", "template"],
|
||||
["smber", "wildcard"],
|
||||
["smber", "interface"],
|
||||
["sber", "syntax"],
|
||||
["smber", "loop"],
|
||||
["smber", "demon"],
|
||||
["smber", "core"],
|
||||
["sber", "interpreter"],
|
||||
["smber", "string"],
|
||||
["smber", "document"],
|
||||
["smber", "cookie"],
|
||||
["smber", "codec"],
|
||||
["smber", "e-mail"],
|
||||
["sber", "OS"],
|
||||
["smber", "service"],
|
||||
["sber", "provider"],
|
||||
["smber", "cache"],
|
||||
["smber", "database"],
|
||||
["smber", "object"],
|
||||
["smbers", "dictionary"],
|
||||
["sber", "driver"],
|
||||
["smber", "index"],
|
||||
["sber", "encoder"],
|
||||
["smber", "list"],
|
||||
["smber", "tuple"],
|
||||
["smber", "range"],
|
||||
["smber", "stream"],
|
||||
["sber", "internet"],
|
||||
["smber", "component"],
|
||||
["smber", "module"],
|
||||
["smber", "library"],
|
||||
["smber", "limit"],
|
||||
["smber", "function"],
|
||||
["smer", "token"],
|
||||
["smber", "code"],
|
||||
["smber", "wave"],
|
||||
["sber", "IoT"],
|
||||
["smber", "blockchain"],
|
||||
["smber", "repository"],
|
||||
["smber", "northbridge"],
|
||||
["smber", "southbridge"]
|
||||
],
|
||||
|
||||
"verbs": [
|
||||
["r", "init"],
|
||||
["r", "pull"],
|
||||
["r", "push"],
|
||||
["r", "clone"],
|
||||
["r", "fetch"],
|
||||
["r", "commit"],
|
||||
["r", "rebase"],
|
||||
["r", "merge"],
|
||||
["r", "fork"],
|
||||
["r", "stash"],
|
||||
["r", "tag"],
|
||||
["r", "cherry-pick"],
|
||||
["r", "checkout"],
|
||||
["r", "wrap"],
|
||||
["r", "iterate"],
|
||||
["r", "loop"],
|
||||
["r", "port"],
|
||||
["r", "infect"],
|
||||
["r", "append"],
|
||||
["r", "change"],
|
||||
["r", "normalize"],
|
||||
["r", "average"],
|
||||
["r", "decrypt"],
|
||||
["r", "encrypt"],
|
||||
["r", "convert"],
|
||||
["r", "access"],
|
||||
["r", "coordinate"],
|
||||
["r", "power"],
|
||||
["r", "monitor"],
|
||||
["r", "regulate"],
|
||||
["r", "detect"],
|
||||
["r", "block"],
|
||||
["r", "debug"],
|
||||
["r", "observe"],
|
||||
["r", "bypass"],
|
||||
["r", "input"],
|
||||
["r", "synthesize"],
|
||||
["r", "connect"],
|
||||
["r", "parse"],
|
||||
["r", "generate"],
|
||||
["r", "copy"],
|
||||
["r", "analyze"],
|
||||
["r", "control"],
|
||||
["r", "benchmark"],
|
||||
["r", "request"],
|
||||
["r", "enter"],
|
||||
["r", "call"],
|
||||
["r", "detect"],
|
||||
["r", "print"],
|
||||
["r", "simulate"],
|
||||
["r", "emulate"],
|
||||
["r", "intercept"],
|
||||
["r", "sequence"],
|
||||
["r", "synchronize"],
|
||||
["r", "test"],
|
||||
["r", "tokenize"],
|
||||
["r", "format"],
|
||||
["r", "constrain"],
|
||||
["r", "import"],
|
||||
["r", "export"],
|
||||
["r", "develop"],
|
||||
["r", "invert"],
|
||||
["r", "slice"],
|
||||
["r", "index"],
|
||||
["r", "join"],
|
||||
["r", "shorten"],
|
||||
["r", "partition"],
|
||||
["r", "decompile"],
|
||||
["r", "split"],
|
||||
["r", "swap"],
|
||||
["r", "cast"],
|
||||
["r", "clear"],
|
||||
["r", "stream"],
|
||||
["r", "remove"],
|
||||
["r", "add"],
|
||||
["r", "signal"],
|
||||
["r", "process"],
|
||||
["r", "disconnect"],
|
||||
["r", "start"],
|
||||
["r", "interpret"],
|
||||
["r", "yield"],
|
||||
["r", "match"],
|
||||
["r", "inspect"],
|
||||
["r", "collect"],
|
||||
["r", "restrict"],
|
||||
["r", "display"],
|
||||
["r", "address"],
|
||||
["r", "identify"],
|
||||
["r", "load"],
|
||||
["r", "define"],
|
||||
["r", "decentralize"],
|
||||
["r", "update"],
|
||||
["r", "encode"],
|
||||
["r", "virtualize"],
|
||||
["r", "transmit"],
|
||||
["r", "compile"],
|
||||
["r", "randomize"],
|
||||
["r", "deauth"],
|
||||
["r", "alter"],
|
||||
["r", "mute"],
|
||||
["r", "hash"]
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue