HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"count": 236,
"next": "https://sillypaste.herokuapp.com/api/paste/?format=api&limit=25&offset=225",
"previous": "https://sillypaste.herokuapp.com/api/paste/?format=api&limit=25&offset=175",
"results": [
{
"id": 608,
"title": "sql join for mrroach",
"body": "SELECT\n posts.id,\n boards.id\n threadid,\n message_raw,\n dir\nFROM\n posts\nINNER JOIN boards\n ON posts.id = boards.id",
"timestamp": "2022-12-12T22:14:08.386033Z",
"expiry": null,
"freeze_hits": false,
"hits": 52,
"size": 154,
"author": 746,
"language": 130
},
{
"id": 609,
"title": "postgres mrroach solution",
"body": "SELECT\n posts.id,\n posts.thread_id as threadid,\n posts.message_raw,\n boards.id as top_post\nFROM\n posts\nINNER JOIN boards\n on posts.is_top_post = 1",
"timestamp": "2022-12-12T22:24:57.629017Z",
"expiry": null,
"freeze_hits": false,
"hits": 51,
"size": 187,
"author": 746,
"language": 130
},
{
"id": 610,
"title": "sql using join and with queries",
"body": "with a as (SELECT\n posts.id as id,\n posts.thread_id as threadid,\n posts.message_raw,\n boards.id as top_post\nFROM\n posts\nINNER JOIN boards\n on posts.is_top_post = 1)\n \nselect alpha.*, threads.board_id from a as alpha\nFULL JOIN threads on alpha.id = threads.id ",
"timestamp": "2022-12-12T22:35:30.732424Z",
"expiry": null,
"freeze_hits": false,
"hits": 50,
"size": 308,
"author": 746,
"language": 130
},
{
"id": 611,
"title": "mrroach og",
"body": "# create tables\ncreate table posts(\n id int,\n thread_id int,\n message_raw varchar(45),\n is_top_post int\n);\ncreate table threads(\n id int,\n board_id int\n);\ncreate table boards(\n id int,\n dir varchar(40)\n);\n\ninsert into boards(id, dir) values(1, 'test');\ninsert into boards(id, dir) values(2, 'test2');\ninsert into threads(id, board_id) values(1,1);\ninsert into posts(id, thread_id, message_raw, is_top_post) values(1,1,'p1t1', 1);\ninsert into posts(id, thread_id, message_raw, is_top_post) values(2,1,'p2t1', 0);\ninsert into threads(id, board_id) values(2,1);\ninsert into posts(id, thread_id, message_raw, is_top_post) values(3,2,'p3t2', 1);\ninsert into threads(id, board_id) values(3,2);\ninsert into posts(id, thread_id, message_raw, is_top_post) values(4,3,'p4t3', 1);\n\n\n# read\nselect OG.id, OG.thread_id, message_raw,\n (select dir from boards where id = (\n select board_id from threads where id = posts.thread_id)\n ) as dir,\n(\n select id from posts where is_top_post = 1 and thread_id = threadid\n) AS top_post\nfrom posts AS OG;",
"timestamp": "2022-12-14T12:16:52.412785Z",
"expiry": null,
"freeze_hits": false,
"hits": 46,
"size": 1053,
"author": 746,
"language": 130
},
{
"id": 612,
"title": "0001-gui-add-auto-scummer.patch",
"body": "From b20a2678585b94aeea093085f92d8c3c6fb28233 Mon Sep 17 00:00:00 2001\nFrom: Winston Weinert <git@winny.tech>\nDate: Wed, 14 Dec 2022 06:32:25 -0600\nSubject: [PATCH] gui: add auto-scummer\n\n---\n .gitignore | 1 +\n cmd/savecmd/save.go | 9 +--\n go.mod | 13 ++++-\n go.sum | 24 ++++++++\n gui/main.go | 84 +++++++++++++++++++++++++++-\n gui/models.go | 23 ++++++++\n gui/newsavewatcher.go | 126 ++++++++++++++++++++++++++++++++++++++++++\n gui/paths.go | 25 +++++++++\n savefile/savefile.go | 16 +++++-\n 9 files changed, 308 insertions(+), 13 deletions(-)\n create mode 100644 gui/models.go\n create mode 100644 gui/newsavewatcher.go\n create mode 100644 gui/paths.go\n\ndiff --git a/.gitignore b/.gitignore\nindex 5ef1910..6d08386 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -1,4 +1,5 @@\n /jhmod\n+/jhmod.exe\n \n # Discourage accidental staging of scratch files used by the tool.\n core.*\ndiff --git a/cmd/savecmd/save.go b/cmd/savecmd/save.go\nindex 59160ed..d083691 100644\n--- a/cmd/savecmd/save.go\n+++ b/cmd/savecmd/save.go\n@@ -29,14 +29,7 @@ func saveInfoCmd() *cobra.Command {\n \t\t\t\tif debug {\n \t\t\t\t\tfmt.Fprintf(os.Stderr, \"Reading file %s\\n\", p)\n \t\t\t\t}\n-\t\t\t\tf, openErr := os.Open(p)\n-\t\t\t\tif openErr != nil {\n-\t\t\t\t\tfmt.Fprintf(os.Stderr, \"Failed to open '%s': %v\\n\", p, openErr)\n-\t\t\t\t\terrors++\n-\t\t\t\t\tcontinue\n-\t\t\t\t}\n-\t\t\t\tdefer f.Close()\n-\t\t\t\tsave, parseErr := savefile.Parse(f)\n+\t\t\t\tsave, parseErr := savefile.ParseFile(p)\n \t\t\t\tif parseErr != nil {\n \t\t\t\t\tfmt.Fprintf(os.Stderr, \"Failed to parse '%s: %v\\n\", p, parseErr)\n \t\t\t\t\terrors++\ndiff --git a/go.mod b/go.mod\nindex 23b554d..20cbce1 100644\n--- a/go.mod\n+++ b/go.mod\n@@ -3,7 +3,9 @@ module github.com/sector-f/jhmod\n go 1.17\n \n require (\n+\tgithub.com/adrg/xdg v0.4.0\n \tgithub.com/dsnet/golib/memfile v1.0.0\n+\tgithub.com/fsnotify/fsnotify v1.6.0\n \tgithub.com/spf13/cobra v1.5.0\n \tgithub.com/spf13/pflag v1.0.5\n )\n@@ -12,7 +14,6 @@ require (\n \tfyne.io/systray v1.10.1-0.20220621085403-9a2652634e93 // indirect\n \tgithub.com/davecgh/go-spew v1.1.1 // indirect\n \tgithub.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 // indirect\n-\tgithub.com/fsnotify/fsnotify v1.5.4 // indirect\n \tgithub.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe // indirect\n \tgithub.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 // indirect\n \tgithub.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 // indirect\n@@ -21,19 +22,25 @@ require (\n \tgithub.com/godbus/dbus/v5 v5.1.0 // indirect\n \tgithub.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect\n \tgithub.com/gopherjs/gopherjs v1.17.2 // indirect\n+\tgithub.com/jinzhu/inflection v1.0.0 // indirect\n+\tgithub.com/jinzhu/now v1.1.5 // indirect\n \tgithub.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect\n+\tgithub.com/mattn/go-sqlite3 v1.14.16 // indirect\n \tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n \tgithub.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect\n \tgithub.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect\n \tgithub.com/stretchr/testify v1.7.2 // indirect\n \tgithub.com/tevino/abool v1.2.0 // indirect\n+\tgithub.com/u-root/u-root v0.10.0 // indirect\n \tgithub.com/yuin/goldmark v1.4.0 // indirect\n \tgolang.org/x/image v0.0.0-20220601225756-64ec528b34cd // indirect\n \tgolang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee // indirect\n-\tgolang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect\n-\tgolang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect\n+\tgolang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect\n+\tgolang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect\n \tgolang.org/x/text v0.3.7 // indirect\n \tgopkg.in/yaml.v3 v3.0.1 // indirect\n+\tgorm.io/driver/sqlite v1.4.3 // indirect\n+\tgorm.io/gorm v1.24.2 // indirect\n \thonnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 // indirect\n )\n \ndiff --git a/go.sum b/go.sum\nindex 3841d6e..6262fea 100644\n--- a/go.sum\n+++ b/go.sum\n@@ -44,6 +44,8 @@ fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93/go.mod h1:oM2AQqGJ1AMo4nNq\n github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\n github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=\n github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\n+github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=\n+github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=\n github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=\n github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\n github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\n@@ -82,6 +84,8 @@ github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUv\n github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\n github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=\n github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=\n+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=\n+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=\n github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe h1:A/wiwvQ0CAjPkuJytaD+SsXkPU0asQ+guQEIg1BJGX4=\n github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe/go.mod h1:d4clgH0/GrRwWjRzJJQXxT/h1TyuNSfF/X64zb/3Ggg=\n github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 h1:+31CdF/okdokeFNoy9L/2PccG3JFidQT3ev64/r4pYU=\n@@ -198,6 +202,11 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:\n github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=\n github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\n github.com/jackmordaunt/icns/v2 v2.2.1/go.mod h1:6aYIB9eSzyfHHMKqDf17Xrs1zetQPReAkiUSHzdw4cI=\n+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=\n+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=\n+github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=\n+github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=\n+github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=\n github.com/josephspurrier/goversioninfo v1.4.0/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY=\n github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\n github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\n@@ -216,6 +225,9 @@ github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2\n github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=\n github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\n github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\n+github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=\n+github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=\n+github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=\n github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=\n github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\n github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=\n@@ -281,6 +293,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F\n github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=\n github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=\n github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=\n+github.com/u-root/u-root v0.10.0 h1:nz3jSORXAxTl6bNXhRh5s9HT5oRo5hmCJXUJ0q/BK7s=\n+github.com/u-root/u-root v0.10.0/go.mod h1:lqAiThZZ0/yg0rj49gxpSCK8hfv86NSc+wPhGp5idb4=\n github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=\n github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\n github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\n@@ -388,6 +402,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd\n golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\n golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=\n golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\n+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=\n+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\n golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\n golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\n golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\n@@ -458,8 +474,11 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc\n golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\n golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\n golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\n+golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\n golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=\n golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\n+golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY=\n+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\n golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\n golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\n golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\n@@ -647,6 +666,11 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C\n gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\n gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n+gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=\n+gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=\n+gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=\n+gorm.io/gorm v1.24.2 h1:9wR6CFD+G8nOusLdvkZelOEhpJVwwHzpQOUM+REd6U0=\n+gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=\n honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 h1:oomkgU6VaQDsV6qZby2uz1Lap0eXmku8+2em3A/l700=\n honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4=\n honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\ndiff --git a/gui/main.go b/gui/main.go\nindex 09fd2eb..cc20102 100644\n--- a/gui/main.go\n+++ b/gui/main.go\n@@ -1,14 +1,96 @@\n package gui\n \n import (\n+\t\"crypto/sha256\"\n+\t\"encoding/hex\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"os\"\n+\tpath \"path/filepath\"\n+\t\"time\"\n+\n \t\"fyne.io/fyne/v2/app\"\n \t\"fyne.io/fyne/v2/widget\"\n+\t\"github.com/sector-f/jhmod/savefile\"\n+\t\"github.com/u-root/u-root/pkg/cp\"\n+\t\"gorm.io/driver/sqlite\"\n+\t\"gorm.io/gorm\" // Base ORM\n )\n \n+func sha256File(path string) ([]byte, error) {\n+\tf, err := os.Open(path)\n+\tif err != nil {\n+\t\treturn make([]byte, 0), err\n+\t}\n+\tdefer f.Close()\n+\th := sha256.New()\n+\tif _, err := io.Copy(h, f); err != nil {\n+\t\treturn make([]byte, 0), err\n+\t}\n+\treturn h.Sum(nil), nil\n+}\n+\n func Run() {\n \ta := app.New()\n \tw := a.NewWindow(\"Hello World\")\n+\tlbl := widget.NewLabel(\"Hello World!\")\n+\n+\tmkdirErr := os.Mkdir(getSaveScumDir(), 0750)\n+\tif mkdirErr != nil && !os.IsExist(mkdirErr) {\n+\t\tfmt.Fprintf(os.Stderr, \"Cannot make savescumdir %v\\n\", mkdirErr)\n+\t\treturn\n+\t}\n+\n+\tdbPath := path.Join(\n+\t\tgetSaveScumDir(),\n+\t\t\"db.sqlite3\",\n+\t)\n+\tdb, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})\n+\tif err != nil {\n+\t\tpanic(fmt.Sprintf(\"Unable to open db \\\"%s\\\" %v\", dbPath, err))\n+\t}\n+\tif err = db.AutoMigrate(&StoredSaveFile{}); err != nil {\n+\t\tpanic(fmt.Sprintf(\"Could not migrate db.\\n\"))\n+\t}\n+\n+\tgo watchForNewSave(func(p string) {\n+\t\tlbl.SetText(fmt.Sprintf(\"%s %s\", time.Now().String(), p))\n+\n+\t\tsd, err := savefile.ParseFile(p)\n+\t\tif err != nil {\n+\t\t\tfmt.Fprintf(os.Stderr, \"Could not parse save \\\"%s\\\". Aborting.\\n\", p)\n+\t\t\treturn\n+\t\t}\n+\t\tdigest, shaErr := sha256File(p)\n+\t\tif shaErr != nil {\n+\t\t\tfmt.Fprintf(os.Stderr, \"Could not SHA256 \\\"%s\\\". Aborting.\\n\", p)\n+\t\t\treturn\n+\t\t}\n+\n+\t\tdigestHex := hex.EncodeToString(digest)\n+\t\trelPath := digestHex\n+\n+\t\tstoredSaveFile := &StoredSaveFile{\n+\t\t\tOriginalBase: path.Base(p), // this don't work on the winders\n+\t\t\tStoredRelPath: relPath,\n+\t\t\tSha256Hex: digestHex,\n+\n+\t\t\tPlayerName: sd.PlayerName,\n+\t\t\tGameMode: sd.GameMode,\n+\t\t\tCurrentLevel: sd.CurrentLevel,\n+\t\t\tSeed: sd.Seed,\n+\t\t}\n+\n+\t\tdestAbs := path.Join(getSaveScumDir(), relPath)\n+\t\tif cpErr := cp.Copy(p, destAbs); cpErr != nil {\n+\t\t\tfmt.Fprintf(os.Stderr, \"Failed to copy file \\\"%s\\\" to \\\"%s\\\" (%v)\\n\", p, destAbs, cpErr)\n+\t\t\treturn\n+\t\t} else {\n+\t\t\tfmt.Printf(\"Copied \\\"%s\\\" to \\\"%s\\\" n saved to db.\\n\", p, destAbs)\n+\t\t}\n+\t\tdb.Create(storedSaveFile)\n+\t})\n \n-\tw.SetContent(widget.NewLabel(\"Hello World!\"))\n+\tw.SetContent(lbl)\n \tw.ShowAndRun()\n }\ndiff --git a/gui/models.go b/gui/models.go\nnew file mode 100644\nindex 0000000..46a911d\n--- /dev/null\n+++ b/gui/models.go\n@@ -0,0 +1,23 @@\n+package gui\n+\n+import (\n+\t\"gorm.io/gorm\"\n+)\n+\n+type StoredSaveFile struct {\n+\tgorm.Model\n+\tId int `gorm:\"primary_key\"`\n+\tOriginalBase string\n+\tStoredRelPath string `gorm:\"unique\"`\n+\tSha256Hex string `gorm:\"unique\"`\n+\n+\t// Copied verbatim from savefile.go\n+\t// Player name\n+\tPlayerName string\n+\t// Game mode. This can be \"jh\", and various others.\n+\tGameMode string\n+\t// The current level's name.\n+\tCurrentLevel string\n+\t// The seed used to generate the game.\n+\tSeed uint32\n+}\ndiff --git a/gui/newsavewatcher.go b/gui/newsavewatcher.go\nnew file mode 100644\nindex 0000000..a69a7e9\n--- /dev/null\n+++ b/gui/newsavewatcher.go\n@@ -0,0 +1,126 @@\n+package gui\n+\n+import (\n+\t\"fmt\"\n+\t\"math\"\n+\t\"path/filepath\"\n+\t\"strings\"\n+\t\"sync\"\n+\t\"time\"\n+\n+\t\"github.com/fsnotify/fsnotify\"\n+)\n+\n+type CreationCallback = func(*fsnotify.Event)\n+\n+// Depending on the system, a single \"write\" can generate many Write events; for\n+// example compiling a large Go program can generate hundreds of Write events on\n+// the binary.\n+//\n+// The general strategy to deal with this is to wait a short time for more write\n+// events, resetting the wait period for every new event.\n+func dedup(callback CreationCallback, paths ...string) {\n+\tif len(paths) < 1 {\n+\t\tpanic(\"must specify at least one path to watch\")\n+\t}\n+\n+\t// Create a new watcher.\n+\tw, err := fsnotify.NewWatcher()\n+\tif err != nil {\n+\t\tpanic(fmt.Sprintf(\"creating a new watcher: %s\", err))\n+\t}\n+\tdefer w.Close()\n+\n+\t// Start listening for events.\n+\tgo watchForCreated(w, callback)\n+\n+\t// Add all paths from the commandline.\n+\tfor _, p := range paths {\n+\t\terr = w.Add(p)\n+\t\tif err != nil {\n+\t\t\tpanic(fmt.Sprintf(\"%q: %s\", p, err))\n+\t\t}\n+\t}\n+}\n+\n+func watchForCreated(w *fsnotify.Watcher, creatcb CreationCallback) {\n+\tvar (\n+\t\t// Wait 100ms for new events; each new event resets the timer.\n+\t\twaitFor = 100 * time.Millisecond\n+\t\t// why is this not a const?\n+\n+\t\t// Keep track of the timers, as path → timer.\n+\t\tmu sync.Mutex\n+\t\ttimers = make(map[string]*time.Timer)\n+\n+\t\t// Callback we run.\n+\t\tcb = func(e fsnotify.Event) {\n+\t\t\tcreatcb(&e)\n+\n+\t\t\t// Don't need to remove the timer if you don't have a lot of files.\n+\t\t\tmu.Lock()\n+\t\t\tdelete(timers, e.Name)\n+\t\t\tmu.Unlock()\n+\t\t}\n+\t)\n+\n+\tfor {\n+\t\tselect {\n+\t\t// Read from Errors.\n+\t\tcase _, ok := <-w.Errors:\n+\t\t\tif !ok { // Channel was closed (i.e. Watcher.Close() was called).\n+\t\t\t\treturn\n+\t\t\t}\n+\t\t// Read from Events.\n+\t\tcase e, ok := <-w.Events:\n+\t\t\tif !ok { // Channel was closed (i.e. Watcher.Close() was called).\n+\t\t\t\treturn\n+\t\t\t}\n+\n+\t\t\t// We just want to watch for file creation, so ignore everything\n+\t\t\t// outside of Create and Write.\n+\t\t\tif !e.Has(fsnotify.Create) && !e.Has(fsnotify.Write) {\n+\t\t\t\tcontinue\n+\t\t\t}\n+\n+\t\t\t// Get timer.\n+\t\t\tmu.Lock()\n+\t\t\tt, ok := timers[e.Name]\n+\t\t\tmu.Unlock()\n+\n+\t\t\t// No timer yet, so create one.\n+\t\t\tif !ok {\n+\t\t\t\tt = time.AfterFunc(math.MaxInt64, func() { cb(e) })\n+\t\t\t\tt.Stop()\n+\n+\t\t\t\tmu.Lock()\n+\t\t\t\ttimers[e.Name] = t\n+\t\t\t\tmu.Unlock()\n+\t\t\t}\n+\n+\t\t\t// Reset the timer for this path, so it will start from 100ms again.\n+\t\t\tt.Reset(waitFor)\n+\t\t}\n+\t}\n+}\n+\n+type NewSaveCallback = func(string)\n+\n+func watchForNewSave(cb NewSaveCallback) {\n+\twatcher, err := fsnotify.NewWatcher()\n+\tw := watcher\n+\tif err != nil {\n+\t\tpanic(\"Could not create watcher\")\n+\t}\n+\tdefer watcher.Close()\n+\terr = watcher.Add(guessGameDir())\n+\tif err != nil {\n+\t\tpanic(fmt.Sprintf(\"Could not create add dir to watcher %v\", err))\n+\t}\n+\twatchForCreated(w, func(e *fsnotify.Event) {\n+\t\tbase := filepath.Base(e.Name)\n+\t\tif base != \"save_loading\" && strings.HasPrefix(base, \"save\") {\n+\t\t\tcb(e.Name)\n+\t\t}\n+\t})\n+}\ndiff --git a/gui/paths.go b/gui/paths.go\nnew file mode 100644\nindex 0000000..c341e6a\n--- /dev/null\n+++ b/gui/paths.go\n@@ -0,0 +1,25 @@\n+package gui\n+\n+import (\n+\t\"runtime\"\n+\n+\t\"github.com/adrg/xdg\"\n+)\n+\n+func guessGameDir() string {\n+\tos := runtime.GOOS\n+\tswitch os {\n+\tcase \"windows\":\n+\t\treturn \"C:/Program Files (x86)/Steam/steamapps/common/Jupiter Hell\"\n+\tdefault:\n+\t\tpanic(\"Don't know about OS default game dir\")\n+\t}\n+}\n+\n+func getSaveScumDir() string {\n+\tdir, err := xdg.DataFile(\"jhmod/savescum\")\n+\tif err != nil {\n+\t\tpanic(err)\n+\t}\n+\treturn dir\n+}\ndiff --git a/savefile/savefile.go b/savefile/savefile.go\nindex 224db88..c13f501 100644\n--- a/savefile/savefile.go\n+++ b/savefile/savefile.go\n@@ -7,6 +7,7 @@ import (\n \t\"errors\"\n \t\"io\"\n \t\"io/ioutil\"\n+\t\"os\"\n \t\"unicode\"\n )\n \n@@ -15,7 +16,7 @@ const (\n \tmagic = \"\\xde\\xc0\\xad\\xde\"\n )\n \n-type savedata struct {\n+type Savedata struct {\n \t// Player name\n \tPlayerName string\n \t// Game mode. This can be \"jh\", and various others.\n@@ -26,6 +27,9 @@ type savedata struct {\n \tSeed uint32\n }\n \n+// TODO port legacy type `savedata` to `Savedata`\n+type savedata = Savedata\n+\n // No magic found on save file.\n var ErrNoMagicFound error = errors.New(\"no magic found\")\n \n@@ -135,3 +139,13 @@ func Parse(r io.Reader) (savedata, error) {\n \t\tSeed: seed,\n \t}, nil\n }\n+\n+func ParseFile(path string) (savedata, error) {\n+\tf, openErr := os.Open(path)\n+\tif openErr != nil {\n+\t\treturn savedata{}, openErr\n+\t}\n+\n+\tdefer f.Close()\n+\treturn Parse(f)\n+}\n-- \n2.34.1.windows.1\n",
"timestamp": "2022-12-14T12:35:34.423582Z",
"expiry": null,
"freeze_hits": false,
"hits": 55,
"size": 19624,
"author": 747,
"language": 145
},
{
"id": 613,
"title": "merge 2 linkedlist leetcode",
"body": "#You are given the heads of two sorted linked lists list1 and list2.\n\n#Merge the two lists in a one sorted list. The list should be made by splicing together the nodes of the first two lists.\n\ndef mergeTwoLists(self, list1: ListNode, list2: ListNode) -> Optional[ListNode]:\n curr = ret = ListNode()\n while list1 and list2:\n if list1.val < list2.val:\n curr.next = list1\n list1, curr = list1.next, list1\n else:\n curr.next = list2\n list2, curr = list2.next, list2\n\n if list1 or list2:\n curr.next = list1 if list1 else list2\n \n return ret.next",
"timestamp": "2022-12-14T16:34:13.272397Z",
"expiry": null,
"freeze_hits": false,
"hits": 50,
"size": 692,
"author": 748,
"language": 471
},
{
"id": 614,
"title": "remove duplicates from sorted list[int] leetcode",
"body": "class Solution:\n def removeDuplicates(self, nums: List[int]) -> int:\n dupes = []\n\n previous = -101\n for i in range(len(nums)):\n if nums[i] == previous:\n dupes.append(nums[i])\n\n previous = nums[i]\n\n for x in dupes:\n nums.remove(x)",
"timestamp": "2022-12-14T22:07:41.461529Z",
"expiry": null,
"freeze_hits": false,
"hits": 48,
"size": 356,
"author": 748,
"language": 471
},
{
"id": 615,
"title": "example sed sebbu",
"body": "backend \"http\" {\n address = \"${val}/infra\"\n method = \"post\"\n}\n\n &sebbu | sed -i 's/${val}/test/' 615raw.txt │ Gentoo\n │17:26:03 &sebbu | single line, returns immediately after modifying the file │ gnu\n │17:26:35 &sebbu | sed -i 's/val/test/' 615raw.txt │ Jemar\n │17:26:43 &sebbu | or this if it's the variable name you wanted to change │ lard\n │17:26:56 &sebbu | but usually placeholders have specific prefix/suffix │ Number1Stunna\n │17:26:56 &sebbu | :D │ Piba\n │17:27:47 ~socraticDev | that is very nice │ Politik\n │17:27:53 &sebbu | keep using envsubst if your input already uses variables ",
"timestamp": "2022-12-14T22:23:22.771619Z",
"expiry": null,
"freeze_hits": false,
"hits": 53,
"size": 1273,
"author": 750,
"language": 49
},
{
"id": 616,
"title": "0001-gui-fix-restore-dedup-logic.patch",
"body": "From bc490fae178e9b7bcf0a2f291ab1cef2cae5dfce Mon Sep 17 00:00:00 2001\nFrom: Winston Weinert <git@winny.tech>\nDate: Wed, 14 Dec 2022 20:25:53 -0600\nSubject: [PATCH] gui: fix restore dedup logic\n\n---\n gui/main.go | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/gui/main.go b/gui/main.go\nindex 245ea29..7e1b8d7 100644\n--- a/gui/main.go\n+++ b/gui/main.go\n@@ -98,7 +98,7 @@ func Run() {\n \t\tdigestHex := hex.EncodeToString(digest)\n \t\trelPath := digestHex\n \t\tvar existing *StoredSaveFile = nil\n-\t\tif db.Where(\"sha256_hex = ?\", digestHex).Find(&existing); existing != nil {\n+\t\tif db.Where(\"sha256_hex = ?\", digestHex).Find(&existing).RowsAffected > 0 && existing != nil {\n \t\t\tfmt.Fprintf(os.Stderr, \"Saw save we already have in DB, skipping (%s).\\n\", digestHex)\n \t\t\treturn\n \t\t}\n-- \n2.34.1.windows.1\n",
"timestamp": "2022-12-15T02:26:55.012941Z",
"expiry": null,
"freeze_hits": false,
"hits": 51,
"size": 850,
"author": 747,
"language": 145
},
{
"id": 617,
"title": "update servers",
"body": "PLAY [my debian servers] *****************************************************************************************************************************\n\nTASK [Gathering Facts] *******************************************************************************************************************************\nok: [freshdatasource.com]\nok: [dailybuild.org]\n\nTASK [update and upgrade apt packages] ***************************************************************************************************************\nok: [dailybuild.org]\nchanged: [freshdatasource.com]\n\nPLAY RECAP *******************************************************************************************************************************************\ndailybuild.org : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 \nfreshdatasource.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ",
"timestamp": "2022-12-24T15:39:03.478128Z",
"expiry": null,
"freeze_hits": false,
"hits": 45,
"size": 955,
"author": 715,
"language": 179
},
{
"id": 618,
"title": "winny's cleaning robot scares Peach kot",
"body": "https://ibb.co/wpywvPK",
"timestamp": "2022-12-28T16:12:50.920921Z",
"expiry": null,
"freeze_hits": false,
"hits": 42,
"size": 61,
"author": 759,
"language": null
},
{
"id": 620,
"title": "Mastodon app apis - notes",
"body": "# dailybuild Mastodon client 🐘\n\n## app formats\n\n### CLI 🖳\n\n| command | output |\n| ------- | ----------------------------------------------- |\n| whoami | {\"user\": \"my_username\", \"url\": \"http://my_url\"} |\n| friends | list of accounts i'm following |\n\n#### public API (not logged in)\n\n|command|output|\n|-|-|\n|hashtag|url of the latest pic tooted with this keyword|\n|search|table with rows of data|\n\n### mobile 📱\n\n...\n\n### automation ⛮\n\n- automated jobs (cron; events; etc.)\n\n## use cases 🧬🏗️\n\n- augmented tweet\n- automated tweeting\n- make a poll (ask a multiple answers question to friends)\n- complimentating cat pics/videos\n\n## actual project\n\n- [https://github.com/socraticDevBlog/mastodonctl](https://github.com/socraticDevBlog/mastodonctl)\n\n## docs 📜\n\n### for newbies\n\n- [https://fedi.tips/how-to-use-mastodon-and-the-fediverse-basic-tips/](https://fedi.tips/how-to-use-mastodon-and-the-fediverse-basic-tips/)\n\n### videos\n\n- Using the Mastodon API - Posting Status Updates to Mastodon via cURL and Python - [https://www.youtube.com/watch?v=W3kb6aImHf8](https://www.youtube.com/watch?v=W3kb6aImHf8)\n\n### seriouser docs\n\n- [https://docs.joinmastodon.org/api/](https://docs.joinmastodon.org/api/)\n\n## social 🤼\n\n- [https://www.reddit.com/r/Mastadon/](https://www.reddit.com/r/Mastadon/)\n",
"timestamp": "2022-12-30T14:58:51.446023Z",
"expiry": null,
"freeze_hits": false,
"hits": 106,
"size": 1394,
"author": 715,
"language": 93
},
{
"id": 653,
"title": "add one to List[int] - leetcode",
"body": "\"\"\"\nYou are given a large integer represented as an integer array digits, where each digits[i] is the ith digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading 0's.\n\nIncrement the large integer by one and return the resulting array of digits.\n\n \n\nExample 1:\n\nInput: digits = [1,2,3]\nOutput: [1,2,4]\nExplanation: The array represents the integer 123.\nIncrementing by one gives 123 + 1 = 124.\nThus, the result should be [1,2,4].\n\"\"\"\n\nclass Solution:\n def plusOne(self, digits: List[int]) -> List[int]:\n \n number_str = \"\"\n for _, v in enumerate(digits):\n number_str = number_str + str(v)\n\n number_str = str(int(number_str) + 1)\n\n return([int(x) for x in number_str])",
"timestamp": "2023-01-02T22:51:10.079687Z",
"expiry": null,
"freeze_hits": false,
"hits": 60,
"size": 848,
"author": 715,
"language": 471
},
{
"id": 654,
"title": "colonel Canada",
"body": "https://ibb.co/TY2Bprn",
"timestamp": "2023-01-06T00:04:09.997243Z",
"expiry": null,
"freeze_hits": false,
"hits": 36,
"size": 36,
"author": 715,
"language": null
},
{
"id": 655,
"title": "optimize truck",
"body": "https://pastebin.com/fsTukbaB",
"timestamp": "2023-01-13T23:16:07.541266Z",
"expiry": null,
"freeze_hits": false,
"hits": 34,
"size": 44,
"author": 770,
"language": 471
},
{
"id": 657,
"title": "Max number of consecutive ones in an array",
"body": "class Solution {\n public int findMaxConsecutiveOnes(int[] nums) {\n int max = 0;\n int curr = 0;\n \n for (int num : nums) {\n if (num == 1) {\n curr++;\n }\n\n if (curr > 0) {\n if (curr > max) {\n max = curr;\n }\n\n if (num != 1) {\n curr = 0; \n }\n }\n }\n \n return max;\n }\n}",
"timestamp": "2023-01-14T21:17:13.136206Z",
"expiry": null,
"freeze_hits": false,
"hits": 38,
"size": 517,
"author": 715,
"language": 374
},
{
"id": 658,
"title": "return sorted squares leetcode Arrays(topic)",
"body": "class Solution {\n\n private int[] sort(int arr[]) {\n int n = arr.length;\n\n for (int i = 0; i < n - 1; i++)\n for (int j = 0; j < n - i - 1; j++)\n if (arr[j] > arr[j + 1]) {\n int temp = arr[j];\n arr[j] = arr[j + 1];\n arr[j + 1] = temp;\n }\n\n return arr;\n }\n\n public int[] sortedSquares(int[] nums) {\n int[] squares = new int[nums.length];\n\n for (int i = 0; i < nums.length; i++) {\n squares[i] = nums[i] * nums[i];\n }\n\n return this.sort(squares);\n }\n}",
"timestamp": "2023-01-15T18:04:32.244079Z",
"expiry": null,
"freeze_hits": false,
"hits": 31,
"size": 660,
"author": 715,
"language": 374
},
{
"id": 659,
"title": "transform 1d array to a 2d matrix (cagie coding challenge)",
"body": "# import numpy as np\n\n\ndef make_matrix(array, row_count, column_count):\n # make sure dimensions valid\n if row_count * column_count != len(array):\n raise ValueError(\"Invalid matrix size: dimensions are invalid\")\n\n ret = []\n idx = 0 \n for i in range(row_count):\n a_row = []\n for j in range(column_count):\n a_row.append(array[idx])\n idx = idx + 1\n\n ret.append(a_row)\n\n return ret\n\n # return array.reshape(n, m)\n\n\nif __name__ == \"__main__\":\n\n # using NumPy to help transform numbers if you do maths stuff\n # arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])\n\n # vanilla stuff\n arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]\n\n my_matrix = make_matrix(arr, 3, 4)\n\n print(f\"Original flat(1 dimension) matrix was: {arr}\\n\")\n print(\n f\"Function make_matrix instructed with n and m values made this matrix:\\n {my_matrix}\")\n",
"timestamp": "2023-01-16T02:09:55.654098Z",
"expiry": null,
"freeze_hits": false,
"hits": 34,
"size": 975,
"author": 715,
"language": 471
},
{
"id": 660,
"title": "k8s monitoring",
"body": "https://kubernetes.io/docs/tasks/debug/debug-cluster/resource-usage-monitoring/",
"timestamp": "2023-01-17T19:33:32.528442Z",
"expiry": null,
"freeze_hits": false,
"hits": 40,
"size": 93,
"author": 715,
"language": 93
},
{
"id": 661,
"title": "texstudio compile execute",
"body": "https://ibb.co/nfzrRJV",
"timestamp": "2023-01-18T15:51:56.870608Z",
"expiry": null,
"freeze_hits": false,
"hits": 31,
"size": 47,
"author": 715,
"language": null
},
{
"id": 662,
"title": "k8s certs info",
"body": "# certifications\n\n## cloud native computing foundation\n\n### Certified Kubernetes Administrator (CKA)\n\n>The purpose of the Certified Kubernetes Administrator (CKA) program is to provide assurance that CKAs have the skills, knowledge, and competency to perform the responsibilities of Kubernetes administrators.\n\n|||\n|-|-|\n|cost|395$usd|\n|Cluster Architecture, Installation & Configuration|25%|\n|Workloads & Scheduling|15%|\n|Services & Networking|20%|\n|Storage|10%|\n|Troubleshooting|30%|\n\nhttps://www.cncf.io/certification/cka/\n\n### Certified Kubernetes Application Developer (CKAD)\n\n>The Certified Kubernetes Application Developer exam certifies that users can design, build, configure, and expose cloud native applications for Kubernetes.\n>\n> A Certified Kubernetes Application Developer can define application resources and use core primitives to build, monitor, and troubleshoot scalable applications and tools in Kubernetes.\n\nThe exam assumes working knowledge of container runtimes and microservice architecture. The successful candidate will be comfortable:\n\n- working with (OCI-compliant) container images\n- applying Cloud Native application concepts and architectures\n- working with and validating Kubernetes resource definitions\n\n|||\n|-|-|\n|cost|395$usd|\n|Application Design and Build|20%|\n|Application Deployment|20%|\n|Application Observability and Maintenance|15%|\n|Application Environment, Configuration and Security|25%|\n|Services and Networking|20%|\n\nhttps://www.cncf.io/certification/ckad/\n\n\n\n\n\n\n\n",
"timestamp": "2023-01-22T16:31:39.734229Z",
"expiry": null,
"freeze_hits": false,
"hits": 40,
"size": 1532,
"author": 715,
"language": 93
},
{
"id": 663,
"title": "flake.nix",
"body": "{\n description = \"A prisma test project\";\n inputs.nixpkgs.url = \"github:NixOS/nixpkgs/master\";\n inputs.flake-utils.url = \"github:numtide/flake-utils\";\n\n outputs = { self, nixpkgs, flake-utils }:\n flake-utils.lib.eachDefaultSystem (system: let\n pkgs = nixpkgs.legacyPackages.${system};\n in {\n devShell = pkgs.mkShell {\n nativeBuildInputs = [ pkgs.bashInteractive ];\n buildInputs = with pkgs; [\n nodePackages.prisma\n yarn\n nodejs\n shellcheck\n awscli\n ];\n shellHook = with pkgs; ''\n export PRISMA_MIGRATION_ENGINE_BINARY=\"${prisma-engines}/bin/migration-engine\"\n export PRISMA_QUERY_ENGINE_BINARY=\"${prisma-engines}/bin/query-engine\"\n export PRISMA_QUERY_ENGINE_LIBRARY=\"${prisma-engines}/lib/libquery_engine.node\"\n export PRISMA_INTROSPECTION_ENGINE_BINARY=\"${prisma-engines}/bin/introspection-engine\"\n export PRISMA_FMT_BINARY=\"${prisma-engines}/bin/prisma-fmt\"\n '';\n };\n });\n}\n",
"timestamp": "2023-01-28T01:33:28.023896Z",
"expiry": null,
"freeze_hits": false,
"hits": 36,
"size": 1039,
"author": 777,
"language": 224
},
{
"id": 664,
"title": "pttt",
"body": "print(\"sss\")",
"timestamp": "2023-01-28T02:09:00.835312Z",
"expiry": null,
"freeze_hits": false,
"hits": 29,
"size": 16,
"author": 778,
"language": 471
},
{
"id": 665,
"title": "0001-scum-new-subcommand.patch",
"body": "From ad11b0d1062ad56553253d707f398e597cd3eab5 Mon Sep 17 00:00:00 2001\nFrom: Winston Weinert <git@winny.tech>\nDate: Sat, 28 Jan 2023 22:21:09 -0600\nSubject: [PATCH] scum: new subcommand\n\n* Manage the save scum database\n * use list to see entries\n * use restore to restore an entry\n---\n cmd/root.go | 2 ++\n cmd/savecmd/save.go | 5 ++--\n cmd/scumcmd/scumcmd.go | 55 ++++++++++++++++++++++++++++++++++++++++++\n gui/main.go | 29 +++++++++++++---------\n gui/storedsavefile.go | 12 +++++++++\n 5 files changed, 89 insertions(+), 14 deletions(-)\n create mode 100644 cmd/scumcmd/scumcmd.go\n\ndiff --git a/cmd/root.go b/cmd/root.go\nindex a74bbc9..0a79267 100644\n--- a/cmd/root.go\n+++ b/cmd/root.go\n@@ -7,6 +7,7 @@ import (\n \t\"github.com/sector-f/jhmod/cmd/managercmd\"\n \t\"github.com/sector-f/jhmod/cmd/nvccmd\"\n \t\"github.com/sector-f/jhmod/cmd/savecmd\"\n+\t\"github.com/sector-f/jhmod/cmd/scumcmd\"\n \t\"github.com/spf13/cobra\"\n )\n \n@@ -20,6 +21,7 @@ func init() {\n \trootCmd.AddCommand(nvccmd.Cmd())\n \trootCmd.AddCommand(savecmd.Cmd())\n \trootCmd.AddCommand(managercmd.Cmd())\n+\trootCmd.AddCommand(scumcmd.Cmd())\n }\n \n func Execute() {\ndiff --git a/cmd/savecmd/save.go b/cmd/savecmd/save.go\nindex d083691..added76 100644\n--- a/cmd/savecmd/save.go\n+++ b/cmd/savecmd/save.go\n@@ -9,7 +9,8 @@ import (\n )\n \n func init() {\n-\tsaveCmd.AddCommand(saveInfoCmd())\n+\tsaveCmd.AddCommand(info())\n+\n }\n \n var saveCmd = &cobra.Command{\n@@ -17,7 +18,7 @@ var saveCmd = &cobra.Command{\n \tShort: \"Work with save files\",\n }\n \n-func saveInfoCmd() *cobra.Command {\n+func info() *cobra.Command {\n \tcmd := &cobra.Command{\n \t\tUse: \"info FILE ...\",\n \t\tShort: \"Show information about a save file\",\ndiff --git a/cmd/scumcmd/scumcmd.go b/cmd/scumcmd/scumcmd.go\nnew file mode 100644\nindex 0000000..9885ab4\n--- /dev/null\n+++ b/cmd/scumcmd/scumcmd.go\n@@ -0,0 +1,55 @@\n+package scumcmd\n+\n+import (\n+\t\"fmt\"\n+\n+\t\"github.com/sector-f/jhmod/gui\"\n+\t\"github.com/spf13/cobra\"\n+)\n+\n+func init() {\n+\tscumCmd.AddCommand(list())\n+\tscumCmd.AddCommand(restore())\n+}\n+\n+func Cmd() *cobra.Command {\n+\treturn scumCmd\n+}\n+\n+var scumCmd = &cobra.Command{\n+\tUse: \"scum\",\n+\tShort: \"Manage save scums\",\n+}\n+\n+func restore() *cobra.Command {\n+\tcmd := &cobra.Command{\n+\t\tUse: \"restore ID\",\n+\t\tShort: \"Restores savescum db entry ID\",\n+\t\tArgs: cobra.ExactArgs(1),\n+\t\tRun: func(cmd *cobra.Command, args []string) {\n+\t\t\tdb := gui.Connect()\n+\t\t\tvar saveFile gui.StoredSaveFile\n+\t\t\tdb.First(&saveFile, args[0])\n+\t\t\tif err := saveFile.Restore(); err != nil {\n+\t\t\t\tpanic(err)\n+\t\t\t}\n+\t\t\tfmt.Printf(\"Restored %s to %s\\n\", saveFile.AbsPath(), saveFile.OriginalBase)\n+\t\t},\n+\t}\n+\treturn cmd\n+}\n+\n+func list() *cobra.Command {\n+\tcmd := &cobra.Command{\n+\t\tUse: \"list\",\n+\t\tShort: \"List savescum database entries\",\n+\t\tRun: func(cmd *cobra.Command, args []string) {\n+\t\t\tvar saveFiles []gui.StoredSaveFile\n+\t\t\tgui.Connect().Find(&saveFiles)\n+\t\t\tfor _, saveFile := range saveFiles {\n+\t\t\t\tfmt.Println(saveFile)\n+\t\t\t}\n+\t\t},\n+\t}\n+\treturn cmd\n+}\ndiff --git a/gui/main.go b/gui/main.go\nindex 7e1b8d7..6b82568 100644\n--- a/gui/main.go\n+++ b/gui/main.go\n@@ -31,6 +31,22 @@ func sha256File(path string) ([]byte, error) {\n \treturn h.Sum(nil), nil\n }\n \n+func Connect() *gorm.DB {\n+\n+\tdbPath := path.Join(\n+\t\tgetSaveScumDir(),\n+\t\t\"db.sqlite3\",\n+\t)\n+\tdb, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})\n+\tif err != nil {\n+\t\tpanic(fmt.Sprintf(\"Unable to open db \\\"%s\\\" %v\", dbPath, err))\n+\t}\n+\tif err = db.AutoMigrate(&StoredSaveFile{}); err != nil {\n+\t\tpanic(fmt.Sprintf(\"Could not migrate db.\\n\"))\n+\t}\n+\treturn db\n+}\n+\n func Run() {\n \ta := app.New()\n \tw := a.NewWindow(\"jhmod manager\")\n@@ -67,18 +83,7 @@ func Run() {\n \t\tfmt.Fprintf(os.Stderr, \"Cannot make savescumdir %v\\n\", mkdirErr)\n \t\treturn\n \t}\n-\n-\tdbPath := path.Join(\n-\t\tgetSaveScumDir(),\n-\t\t\"db.sqlite3\",\n-\t)\n-\tdb, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})\n-\tif err != nil {\n-\t\tpanic(fmt.Sprintf(\"Unable to open db \\\"%s\\\" %v\", dbPath, err))\n-\t}\n-\tif err = db.AutoMigrate(&StoredSaveFile{}); err != nil {\n-\t\tpanic(fmt.Sprintf(\"Could not migrate db.\\n\"))\n-\t}\n+\tdb := Connect()\n \n \tdb.Last(&last)\n \tupdateLast(last)\ndiff --git a/gui/storedsavefile.go b/gui/storedsavefile.go\nindex 0db1ef9..15bc8d3 100644\n--- a/gui/storedsavefile.go\n+++ b/gui/storedsavefile.go\n@@ -1,6 +1,7 @@\n package gui\n \n import (\n+\t\"fmt\"\n \t\"os\"\n \tpath \"path/filepath\"\n \n@@ -26,6 +27,17 @@ type StoredSaveFile struct {\n \tSeed uint32\n }\n \n+func (f StoredSaveFile) String() string {\n+\treturn fmt.Sprintf(\"% 3d [%s] %s %s %s (%d)\",\n+\t\tf.Id,\n+\t\tf.CreatedAt.Format(\"2006-01-02 15:04:06\"),\n+\t\tf.GameMode,\n+\t\tf.PlayerName,\n+\t\tf.CurrentLevel,\n+\t\tf.Seed,\n+\t)\n+}\n+\n func (f StoredSaveFile) AbsPath() string {\n \treturn path.Join(getSaveScumDir(), f.StoredRelPath)\n }\n-- \n2.34.1.windows.1\n",
"timestamp": "2023-01-29T06:09:52.179070Z",
"expiry": null,
"freeze_hits": false,
"hits": 30,
"size": 4783,
"author": 779,
"language": 145
},
{
"id": 667,
"title": "simple gitlab file updater",
"body": "import gitlab\n\n\nclass GitlabClient:\n def __init__(self, token, proj_id):\n self.token = token\n self.proj_id = proj_id\n self.branch = \"main\"\n\n # dont use directly\n # use function 'gl()' to get the authenticated python-gitlab client returned\n self._gl = None\n\n def gl(self):\n \"\"\"_summary_\n gitlab API client as a singleton\n Returns:\n obj: Gitlab API client object\n \"\"\"\n\n if self._gl is None:\n self._gl = gitlab.Gitlab(private_token=self.token)\n self._gl.auth()\n\n return self._gl\n\n def fetch_file(self, filepath, tmp_filename):\n \"\"\"_summary_\n\n this method will query GitLab project repo to fetch and return the manifest (yml)\n file we want to edit.\n\n Args:\n filepath (str): gitlab repo filepath + filename + extension\n tmp_filename (str): constant name of the temporary manifest.yml file\n Returns:\n nothing\n \"\"\"\n project = self.gl().projects.get(self.proj_id)\n\n with open(tmp_filename, \"wb\") as f:\n project.files.raw(\n file_path=filepath, ref=self.branch, streamed=True, action=f.write\n )\n\n def push_file(self, filepath, tmp_filename):\n \"\"\"_summary_\n\n this method will commit & push the manifest (yml) file to our Gitlab repo\n\n Args:\n filepath (str): gitlab repo filepath + filename + extension\n tmp_filename (str): constant name of the temporary manifest.yml file\n Returns:\n nothing\n \"\"\"\n data = {\n \"branch\": self.branch,\n \"commit_message\": \"img tag updated by deploy_bot\",\n \"actions\": [\n {\n \"action\": \"update\",\n \"file_path\": filepath,\n \"content\": open(tmp_filename).read(),\n },\n ],\n }\n\n project = self.gl().projects.get(self.proj_id)\n\n _ = project.commits.create(data)\n",
"timestamp": "2023-02-01T19:36:16.651109Z",
"expiry": null,
"freeze_hits": false,
"hits": 34,
"size": 2075,
"author": 782,
"language": 471
}
]
}