mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-12-04 18:19:54 +00:00
Categories: Show pre-populated categories
They are useless now, and cannot be edited. Also, not properly styled. You get the idea though.
This commit is contained in:
parent
94fa2e5688
commit
f5cbd5622d
@ -71,7 +71,7 @@ func PrepareWikiRoot() error {
|
||||
paths.userCredentialsJSON = filepath.Join(cfg.WikiDir, "users.json")
|
||||
|
||||
paths.tokensJSON = filepath.Join(paths.cacheDir, "tokens.json")
|
||||
paths.categoriesJSON = filepath.Join(cfg.WikiDir, "tags.json")
|
||||
paths.categoriesJSON = filepath.Join(cfg.WikiDir, "categories.json")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Package categories provides category management.
|
||||
// Package categories provides category management. All operations in this package are mutexed.
|
||||
//
|
||||
// As per the long pondering, this is how categories (cats for short)
|
||||
// work in Mycorrhiza:
|
||||
@ -14,31 +14,43 @@
|
||||
// exist. If there are 1 or more hyphae in the cat, cat A exists.
|
||||
package categories
|
||||
|
||||
// For WithHypha and Contents, should the results be sorted?
|
||||
import "sync"
|
||||
|
||||
// WithHypha returns what categories have the given hypha.
|
||||
// WithHypha returns what categories have the given hypha. The hypha name must be canonical.
|
||||
func WithHypha(hyphaName string) (categoryList []string) {
|
||||
panic("todo")
|
||||
return
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
return hyphaToCategories[hyphaName].categoryList
|
||||
}
|
||||
|
||||
// Contents returns what hyphae are in the category. If the returned slice is empty, the category does not exist, and vice versa.
|
||||
// Contents returns what hyphae are in the category. If the returned slice is empty, the category does not exist, and vice versa. The category name must be canonical.
|
||||
func Contents(catName string) (hyphaList []string) {
|
||||
panic("todo")
|
||||
return
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
return categoryToHyphae[catName].hyphaList
|
||||
}
|
||||
|
||||
// AddHyphaToCategory adds the hypha to the category and updates the records on the disk. If the hypha is already in the category, nothing happens. This operation is async-safe.
|
||||
var mutex sync.RWMutex
|
||||
|
||||
// AddHyphaToCategory adds the hypha to the category and updates the records on the disk. If the hypha is already in the category, nothing happens.
|
||||
func AddHyphaToCategory(hyphaName, catName string) {
|
||||
for _, cat := range WithHypha(hyphaName) {
|
||||
if cat == catName {
|
||||
return
|
||||
}
|
||||
mutex.Lock()
|
||||
if node, ok := hyphaToCategories[hyphaName]; ok {
|
||||
node.storeCategory(catName)
|
||||
} else {
|
||||
hyphaToCategories[hyphaName] = &hyphaNode{categoryList: []string{catName}}
|
||||
}
|
||||
panic("todo")
|
||||
|
||||
if node, ok := categoryToHyphae[catName]; ok {
|
||||
node.storeHypha(hyphaName)
|
||||
} else {
|
||||
categoryToHyphae[catName] = &categoryNode{hyphaList: []string{hyphaName}}
|
||||
}
|
||||
mutex.Unlock()
|
||||
}
|
||||
|
||||
// RemoveHyphaFromCategory removes the hypha from the category and updates the records on the disk. If the hypha is not in the category, nothing happens. This operation is async-safe.
|
||||
// RemoveHyphaFromCategory removes the hypha from the category and updates the records on the disk. If the hypha is not in the category, nothing happens.
|
||||
func RemoveHyphaFromCategory(hyphaName, catName string) {
|
||||
panic("todo")
|
||||
mutex.Lock()
|
||||
mutex.Unlock()
|
||||
}
|
109
hyphae/categories/files.go
Normal file
109
hyphae/categories/files.go
Normal file
@ -0,0 +1,109 @@
|
||||
package categories
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/bouncepaw/mycorrhiza/files"
|
||||
"github.com/bouncepaw/mycorrhiza/util"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
var categoryToHyphae = map[string]*categoryNode{}
|
||||
var hyphaToCategories = map[string]*hyphaNode{}
|
||||
|
||||
// InitCategories initializes the category system. Call it after the Structure is initialized. This function might terminate the program in case of a bad mood or filesystem faults.
|
||||
func InitCategories() {
|
||||
var (
|
||||
record, err = readCategoriesFromDisk()
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
for _, cat := range record.Categories {
|
||||
if len(cat.Hyphae) == 0 {
|
||||
continue
|
||||
}
|
||||
cat.Name = util.CanonicalName(cat.Name)
|
||||
for i, hyphaName := range cat.Hyphae {
|
||||
cat.Hyphae[i] = util.CanonicalName(hyphaName)
|
||||
}
|
||||
categoryToHyphae[cat.Name] = &categoryNode{hyphaList: cat.Hyphae}
|
||||
}
|
||||
|
||||
for cat, hyphaeInCat := range categoryToHyphae {
|
||||
for _, hyphaName := range hyphaeInCat.hyphaList {
|
||||
if node, ok := hyphaToCategories[hyphaName]; ok {
|
||||
node.storeCategory(cat)
|
||||
} else {
|
||||
hyphaToCategories[hyphaName] = &hyphaNode{categoryList: []string{cat}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Found", len(categoryToHyphae), "categories")
|
||||
for cat, catNode := range categoryToHyphae { // TODO: remove when not needed
|
||||
log.Println(cat, "->", catNode.hyphaList)
|
||||
}
|
||||
for hyp, hypNode := range hyphaToCategories {
|
||||
log.Println(hyp, "<-", hypNode.categoryList)
|
||||
}
|
||||
}
|
||||
|
||||
type categoryNode struct {
|
||||
// TODO: ensure this is sorted
|
||||
hyphaList []string
|
||||
}
|
||||
|
||||
func (cn *categoryNode) storeHypha(hypname string) {
|
||||
for _, hyphaName := range cn.hyphaList {
|
||||
if hyphaName == hypname {
|
||||
return
|
||||
}
|
||||
}
|
||||
cn.hyphaList = append(cn.hyphaList, hypname)
|
||||
}
|
||||
|
||||
type hyphaNode struct {
|
||||
// TODO: ensure this is sorted
|
||||
categoryList []string
|
||||
}
|
||||
|
||||
func (hn *hyphaNode) storeCategory(cat string) {
|
||||
for _, category := range hn.categoryList {
|
||||
if category == cat {
|
||||
return
|
||||
}
|
||||
}
|
||||
hn.categoryList = append(hn.categoryList, cat)
|
||||
}
|
||||
|
||||
type catFileRecord struct {
|
||||
Categories []catRecord `json:"categories"`
|
||||
}
|
||||
|
||||
type catRecord struct {
|
||||
Name string `json:"name"`
|
||||
Hyphae []string `json:"hyphae"`
|
||||
}
|
||||
|
||||
func readCategoriesFromDisk() (catFileRecord, error) {
|
||||
var (
|
||||
record catFileRecord
|
||||
categoriesFile = files.CategoriesJSON()
|
||||
fileContents, err = os.ReadFile(categoriesFile)
|
||||
)
|
||||
if os.IsNotExist(err) {
|
||||
return record, nil
|
||||
}
|
||||
if err != nil {
|
||||
return record, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(fileContents, &record)
|
||||
if err != nil {
|
||||
return record, err
|
||||
}
|
||||
|
||||
return record, nil
|
||||
}
|
2
main.go
2
main.go
@ -5,6 +5,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/bouncepaw/mycorrhiza/hyphae/categories"
|
||||
"github.com/bouncepaw/mycorrhiza/migration"
|
||||
"log"
|
||||
"os"
|
||||
@ -48,6 +49,7 @@ func main() {
|
||||
history.InitGitRepo()
|
||||
migration.MigrateRocketsMaybe()
|
||||
shroom.SetHeaderLinks()
|
||||
categories.InitCategories()
|
||||
|
||||
// Static files:
|
||||
static.InitFS(files.StaticFiles())
|
||||
|
@ -60,7 +60,7 @@ header { width: 100%; margin-bottom: 1rem; }
|
||||
.layout { display: grid; grid-template-columns: auto 1fr; column-gap: 1rem; margin: 0 1rem; row-gap: 1rem; }
|
||||
.main-width { margin: 0; }
|
||||
main { grid-column: 1 / span 1; grid-row: 1 / span 2; }
|
||||
.sibling-hyphae, .markup-toolbar, .help-topics { grid-column: 2 / span 1; grid-row: 1 / span 1; }
|
||||
.sibling-hyphae, .markup-toolbar, .help-topics, .categories-card { grid-column: 2 / span 1; grid-row: 1 / span 1; }
|
||||
.action-toolbar { grid-column: 2 / span 1; grid-row: 2 / span 1; }
|
||||
.layout-card { width: 100%; }
|
||||
.edit-toolbar__buttons {display: grid; }
|
||||
@ -74,10 +74,10 @@ header { width: 100%; margin-bottom: 1rem; }
|
||||
.layout { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
|
||||
.layout-card {max-width: 18rem;}
|
||||
.main-width { margin: 0 auto; }
|
||||
main { grid-column: 2 / span 1; grid-row: 1 / span 2; }
|
||||
.sibling-hyphae, .markup-toolbar, .help-topics { grid-column: 3 / span 1; margin-left: 0; }
|
||||
main { grid-column: 2 / span 1; grid-row: 1 / span 3; }
|
||||
.sibling-hyphae, .markup-toolbar, .help-topics { grid-column: 3 / span 1; margin-left: 0; grid-row: 1 / span 2; }
|
||||
.markup-toolbar { grid-column: 3 / span 1; grid-row: 1 / span 2; }
|
||||
.action-toolbar { grid-column: 1 / span 1; grid-row: 1 / span 1; }
|
||||
.action-toolbar, .categories-card { grid-column: 1 / span 1; grid-row: 1 / span 1; }
|
||||
.edit-toolbar__buttons { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
@ -275,6 +275,16 @@ table { border: 0; background-color: #444444; color: #ddd; }
|
||||
mark { background: rgba(130, 80, 30, 5); color: inherit; }
|
||||
}
|
||||
|
||||
/*
|
||||
* Categories
|
||||
*/
|
||||
.categories-card__entries {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
.categories-card__remove-form {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shortcuts
|
||||
*/
|
||||
|
59
views/categories.go
Normal file
59
views/categories.go
Normal file
@ -0,0 +1,59 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"github.com/bouncepaw/mycorrhiza/hyphae/categories"
|
||||
"github.com/bouncepaw/mycorrhiza/util"
|
||||
"html/template"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const categoriesCardTmpl = `{{$hyphaName := .HyphaName
|
||||
}}<aside class="layout-card categories-card">
|
||||
<h2 class="layout-card__title">Categories</h2>
|
||||
<ul class="categories-card__entries">
|
||||
{{range .Categories}}
|
||||
<li class="categories-card__entry">
|
||||
<a class="categories-card__link" href="/category/{{.}}">{{beautifulName .}}</a>
|
||||
<form method="POST" action="/remove-from-category" class="categories-card__remove-form">
|
||||
<input type="hidden" name="cat" value="{{.}}">
|
||||
<input type="hidden" name="hypha" value="{{$hyphaName}}">
|
||||
<input type="submit" value="X">
|
||||
</form>
|
||||
</li>
|
||||
{{end}}
|
||||
<li class="categories-card__entry categories-card__add-to-cat">
|
||||
<form method="POST" action="/add-to-category" class="categories-card__add-form">
|
||||
<label for="_cat-name">
|
||||
<input type="text">
|
||||
<input type="submit" value="Add to category">
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>`
|
||||
|
||||
var categoriesCardT *template.Template
|
||||
|
||||
func init() {
|
||||
categoriesCardT = template.Must(template.
|
||||
New("category card").
|
||||
Funcs(template.FuncMap{
|
||||
"beautifulName": util.BeautifulName,
|
||||
}).
|
||||
Parse(categoriesCardTmpl))
|
||||
}
|
||||
|
||||
func categoryCardHTML(hyphaName string) string {
|
||||
var buf strings.Builder
|
||||
err := categoriesCardT.Execute(&buf, struct {
|
||||
HyphaName string
|
||||
Categories []string
|
||||
}{
|
||||
hyphaName,
|
||||
categories.WithHypha(hyphaName),
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
@ -131,6 +131,7 @@ If you rename .prevnext, change the docs too.
|
||||
{%= hyphaInfo(rq, h) %}
|
||||
</section>
|
||||
</main>
|
||||
{%s= categoryCardHTML(h.CanonicalName()) %}
|
||||
{%= siblingHyphaeHTML(siblings, lc) %}
|
||||
</div>
|
||||
{%= viewScripts() %}
|
||||
|
@ -469,162 +469,167 @@ func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Local
|
||||
</main>
|
||||
`)
|
||||
//line views/readers.qtpl:134
|
||||
streamsiblingHyphaeHTML(qw422016, siblings, lc)
|
||||
qw422016.N().S(categoryCardHTML(h.CanonicalName()))
|
||||
//line views/readers.qtpl:134
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line views/readers.qtpl:135
|
||||
streamsiblingHyphaeHTML(qw422016, siblings, lc)
|
||||
//line views/readers.qtpl:135
|
||||
qw422016.N().S(`
|
||||
</div>
|
||||
`)
|
||||
//line views/readers.qtpl:136
|
||||
//line views/readers.qtpl:137
|
||||
streamviewScripts(qw422016)
|
||||
//line views/readers.qtpl:136
|
||||
//line views/readers.qtpl:137
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
}
|
||||
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents string) {
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
StreamHyphaHTML(qw422016, rq, lc, h, contents)
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
}
|
||||
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
func HyphaHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents string) string {
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
WriteHyphaHTML(qb422016, rq, lc, h, contents)
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
qs422016 := string(qb422016.B)
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
return qs422016
|
||||
//line views/readers.qtpl:137
|
||||
//line views/readers.qtpl:138
|
||||
}
|
||||
|
||||
//line views/readers.qtpl:139
|
||||
//line views/readers.qtpl:140
|
||||
func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents, revHash string) {
|
||||
//line views/readers.qtpl:139
|
||||
//line views/readers.qtpl:140
|
||||
qw422016.N().S(`
|
||||
<div class="layout">
|
||||
<main class="main-width">
|
||||
<section>
|
||||
<p>`)
|
||||
//line views/readers.qtpl:143
|
||||
//line views/readers.qtpl:144
|
||||
qw422016.E().S(lc.Get("ui.revision_warning"))
|
||||
//line views/readers.qtpl:143
|
||||
//line views/readers.qtpl:144
|
||||
qw422016.N().S(` <a href="/rev-text/`)
|
||||
//line views/readers.qtpl:143
|
||||
//line views/readers.qtpl:144
|
||||
qw422016.E().S(revHash)
|
||||
//line views/readers.qtpl:143
|
||||
//line views/readers.qtpl:144
|
||||
qw422016.N().S(`/`)
|
||||
//line views/readers.qtpl:143
|
||||
//line views/readers.qtpl:144
|
||||
qw422016.E().S(h.CanonicalName())
|
||||
//line views/readers.qtpl:143
|
||||
//line views/readers.qtpl:144
|
||||
qw422016.N().S(`">`)
|
||||
//line views/readers.qtpl:143
|
||||
//line views/readers.qtpl:144
|
||||
qw422016.E().S(lc.Get("ui.revision_link"))
|
||||
//line views/readers.qtpl:143
|
||||
//line views/readers.qtpl:144
|
||||
qw422016.N().S(`</a></p>
|
||||
`)
|
||||
//line views/readers.qtpl:144
|
||||
//line views/readers.qtpl:145
|
||||
qw422016.N().S(NaviTitleHTML(h))
|
||||
//line views/readers.qtpl:144
|
||||
//line views/readers.qtpl:145
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line views/readers.qtpl:145
|
||||
//line views/readers.qtpl:146
|
||||
qw422016.N().S(contents)
|
||||
//line views/readers.qtpl:145
|
||||
//line views/readers.qtpl:146
|
||||
qw422016.N().S(`
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
`)
|
||||
//line views/readers.qtpl:149
|
||||
//line views/readers.qtpl:150
|
||||
streamviewScripts(qw422016)
|
||||
//line views/readers.qtpl:149
|
||||
//line views/readers.qtpl:150
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
}
|
||||
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents, revHash string) {
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
StreamRevisionHTML(qw422016, rq, lc, h, contents, revHash)
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
}
|
||||
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
func RevisionHTML(rq *http.Request, lc *l18n.Localizer, h hyphae.Hypha, contents, revHash string) string {
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
WriteRevisionHTML(qb422016, rq, lc, h, contents, revHash)
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
qs422016 := string(qb422016.B)
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
return qs422016
|
||||
//line views/readers.qtpl:150
|
||||
//line views/readers.qtpl:151
|
||||
}
|
||||
|
||||
//line views/readers.qtpl:152
|
||||
//line views/readers.qtpl:153
|
||||
func streamviewScripts(qw422016 *qt422016.Writer) {
|
||||
//line views/readers.qtpl:152
|
||||
//line views/readers.qtpl:153
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line views/readers.qtpl:153
|
||||
//line views/readers.qtpl:154
|
||||
for _, scriptPath := range cfg.ViewScripts {
|
||||
//line views/readers.qtpl:153
|
||||
//line views/readers.qtpl:154
|
||||
qw422016.N().S(`
|
||||
<script src="`)
|
||||
//line views/readers.qtpl:154
|
||||
//line views/readers.qtpl:155
|
||||
qw422016.E().S(scriptPath)
|
||||
//line views/readers.qtpl:154
|
||||
//line views/readers.qtpl:155
|
||||
qw422016.N().S(`"></script>
|
||||
`)
|
||||
//line views/readers.qtpl:155
|
||||
//line views/readers.qtpl:156
|
||||
}
|
||||
//line views/readers.qtpl:155
|
||||
//line views/readers.qtpl:156
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
}
|
||||
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
func writeviewScripts(qq422016 qtio422016.Writer) {
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
streamviewScripts(qw422016)
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
}
|
||||
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
func viewScripts() string {
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
writeviewScripts(qb422016)
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
qs422016 := string(qb422016.B)
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
return qs422016
|
||||
//line views/readers.qtpl:156
|
||||
//line views/readers.qtpl:157
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user