Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

719
LINES

< > BotCompany Repo | #1024284 // agi.blue source [secondary version]

JavaX module (desktop) [tags: butter use-pretranspiled] - homepage

Download Jar. Libraryless. Click here for Pure Java version (16814L/121K).

1  
!7
2  
3  
// See #1023660 for the older 99 lines version
4  
5  
concept PhysicalSlice {
6  
  new Ref<Page> slicePage; // page that describes this slice
7  
}
8  
9  
concept Page {
10  
  new Ref<PhysicalSlice> slice; // where are we stored
11  
  S globalID = aGlobalID();
12  
  S url, q;
13  
}
14  
15  
concept Entry {
16  
  S globalID = aGlobalID();
17  
  new Ref<Page> page;
18  
  int count;
19  
  S key, value;
20  
  S ip;
21  
  new Ref<Signer> signer;
22  
}
23  
24  
concept Signer {
25  
  S globalID = aGlobalID();
26  
  S publicKey;
27  
  bool trusted;
28  
  S approvedBy;
29  
}
30  
31  
concept Session {
32  
  S cookie;
33  
  Page slicePage;
34  
}
35  
36  
static SS searchTypeToText = litmap(
37  
  leven := "Leven",
38  
  literal := "Literal",
39  
  scored := "Scored");
40  
41  
static int displayLength = 140;
42  
static int sideDisplayLength = 50; // when in side bar
43  
static int searchResultsToShow = 50;
44  
sS sideSearchType = 'literal;
45  
46  
static int lines;
47  
sbool asyncSearch = false;
48  
sbool allowMultipleCasesInValues = true;
49  
sbool showSliceSelector = false;
50  
static ConceptFieldIndexDesc idx_latestEntries, idx_latestCreatedPages, idx_latestChangedPages;
51  
52  
p {
53  
  dbIndexingCI(Page, 'url, Page, 'q, Entry, 'key, Entry, 'value);
54  
  dbIndexing(Signer, 'publicKey);
55  
  dbIndexing(Session, 'cookie);
56  
  
57  
  // legacy conversions!
58  
  //for (Page p) cset(p, q := p.url);
59  
  moveSlicelessPagesToTheWildSlice();
60  
61  
  idx_latestCreatedPages = new ConceptFieldIndexDesc(Page, 'created);
62  
  idx_latestChangedPages = new ConceptFieldIndexDesc(Page, '_modified);
63  
  idx_latestEntries = new ConceptFieldIndexDesc(Entry, 'created);
64  
  
65  
  // Approve this machine's key
66  
  PKIKeyPair machineKey = agiBot_trustedKeyForMachine();
67  
  if (machineKey != null) {
68  
    print("Approving this machine's key: " + machineKey.publicKey);
69  
    cset(uniq_sync(Signer, publicKey := machineKey.publicKey), trusted := true, approvedBy := "local");
70  
  }
71  
  
72  
  lines = countLines(mySource());
73  
}
74  
75  
// DB functions
76  
77  
sbool hasPage(S q) { ret hasConceptWhereIC(Page, +q); }
78  
sS getValue(Page page, S key) {
79  
  ret page == null || empty(key) ? null : getString value(highestByField count(objectsWhereIC(findBackRefs(page, Entry), +key)));
80  
}
81  
sS getValue(S page, S key) {
82  
  ret getValue(findPageFromQ(page), key);
83  
}
84  
sS pageDisplayName(Page page) {
85  
  /*S name = getValue(page, "read as");
86  
  bool unnaturalName = nempty(name) && !eq(makeAGIDomain(name), page.url);
87  
  ret unnaturalName ? name + " " + squareBracketed(page.url) : or2(name, unpackAGIDomainOpt(page.url));*/
88  
  ret page.q;
89  
}
90  
91  
// Serve page
92  
93  
set flag NoNanoHTTPD. html {
94  
  ret new Request().serve(uri, params);
95  
}
96  
97  
sclass Request {
98  
  S cookie;
99  
  Session session;
100  
  S uri;
101  
  SS params;
102  
103  
  // should also work for standalone
104  
  bool isHomeDomain() {
105  
    S domain = domain();
106  
    ret eqic(domain, "www.agi.blue") || !ewic(domain, ".agi.blue");
107  
  }
108  
  
109  
  O serve(S uri, SS params) {
110  
    this.uri = uri;
111  
    this.params = params;
112  
    new Matches m;
113  
    
114  
    print(uri + " ? " + unnull(subBot_query()));
115  
    
116  
    cookie = cookieFromUser();
117  
    if (cookie != null)
118  
      session = uniq_sync(Session, +cookie);
119  
    else
120  
      session = unlistedWithValues(Session);
121  
      
122  
    // Check for special URIs
123  
124  
    if (swic(uri, "/bot/")) ret serveBot();
125  
    
126  
    // eleu appends a slash to the URI if it's a single identifier, so we drop it again
127  
    S uri2 = dropTrailingSlash(uri);
128  
    
129  
    if (eqic(uri2, "/search")) ret serveScoredSearch();
130  
    if (eqic(uri2, "/literalSearch")) ret serveLiteralSearch();
131  
    if (eqic(uri2, "/levenSearch")) ret serveLevenSearch();
132  
    
133  
    if (eqic(uri2, "/query")) ret serveQueryPage();
134  
    
135  
    S selectSlice = params.get('slice);
136  
    if (nempty(selectSlice))
137  
      cset(session, slicePage := pageFromQ(selectSlice));
138  
139  
    S q = params.get('q);
140  
    S domain = or2(params.get('domain), domain());
141  
    
142  
    S raw = firstKeyWithValue("", params); // agi.blue?something
143  
    if (nempty(raw) && empty(q)) q = raw;
144  
    /*if (nempty(q)) {
145  
      domain = makeAGIDomain(q);
146  
      if (l(domain) > maximumDomainPartLength()) // escape with "domain="
147  
        ret hrefresh(agiBlueURL() + hquery(+domain, key := "read as", value := q));
148  
      ret hrefresh("http://" + domain + (eq(q, domain) ? "" : "/" +  hquery(key := "read as", value := q)));
149  
      //uri = "/"; replaceMapWithParams(params, key := "read as", value := q);
150  
    }*/
151  
    S url = domain + dropTrailingSlash(uri);
152  
    
153  
    // domain to query
154  
    //if (empty(q)) q = url;
155  
    if (empty(q)) q = agiBlue_urlToQuery(url);
156  
    
157  
    Page page, bool newPage = unpair uniqCI2_sync(Page, +q);
158  
    if (newPage) dbLog("New page", +q);
159  
    //printStructs(+params, +raw, +q);
160  
  
161  
    S top = hcomment("cookie: " + takeFirst(4, session.cookie))
162  
      + hSilentComputatorWithFlag("agi.blue: " + q)
163  
      + p(ahref(agiBlueURL(), hsnippetimg(#1101682, width := 565/5, height := 800/5, title := "Robot by Peerro @ DeviantArt")))
164  
      + p(small(
165  
          b(ahref(agiBlueURL(), htmlEncode2(agiBlueName())))
166  
        + (agiBlue_isOriginal() ? "" : " " + targetBlank("http://agi.blue", "[original]"))
167  
        + " | " + targetBlank(progLink(), "source code") + " of this web site (" + nLines(lines) + ") | " + targetBlank("https://gitter.im/agi-blue/community", "sponsor https?") + " | by " + targetBlank("https://BotCompany.de", "BC") + " | " + targetBlank("http://fiverr.tinybrain.de/", "Fiverr") + " | " + targetBlank("https://discordapp.com/invite/SEAjPqk", "Discord") + " | " + targetBlank("https://www.youtube.com/watch?v=b6jtRdV3Ev8", "Video")
168  
        + " | " + targetBlank("http://code.botcompany.de/1024233", "Notes")
169  
        + " | " + ahref("/query", "Query")
170  
      ));
171  
    
172  
    if (empty(params.get('q)) && empty(raw) && isHomeDomain()) {
173  
      L<Page> pages = sortedByFieldDesc _modified(list(Page)); // TODO: use index
174  
      int start = parseInt(params.get("start")), step = 100;
175  
      S nav = pageNav2("/", l(pages), start, step, "start");
176  
      ret hhtml2(hhead_title("agi.blue Overview") // SERVE HOME PAGE
177  
        + hbody(hfullcenterAndTopLeft(top
178  
          + hform(b("GIVE ME INPUT:") + "<br><br>" + htextinput('q, autofocus := true) + " " + hsubmit("Ask"))
179  
          + h1(htmlEncode2(agiBlueName()) + " has " + nPages(countConcepts(Page)) + " and " + nEntries(countConcepts(Entry)))
180  
          + p(nav)
181  
          + p_nemptyLines(map(pageToHTMLLink(), subList(pages, start, start+step))),
182  
          !showSliceSelector ? "" : hform("Select reality slice: " + hselect_list(availableSlices(), getString q(session.slicePage), name := 'slice) + " " + hsubmit("Go"))
183  
        )));
184  
    }
185  
        
186  
    S key = trim(params.get('key)), value = trim(params.get('value));
187  
    L<Entry> entries = GetEntriesAndPost().go(page, params).entries;
188  
    
189  
    Set<S> get = asCISet(nempties(subBot_paramsAsMultiMap().get('get)));
190  
    //S get = params.get('get);
191  
    if (nempty(get))
192  
      ret serveJSON(collect value(llNotNulls(firstThat(entries, e -> get.contains(e.key)))));
193  
    
194  
    S key2 = key, value2 = value; if (nempty(key) && nempty(value)) key2 = value2 = ""; // input reset
195  
  
196  
    bool withHidden = eq(params.get('withHidden), "1");
197  
    new Set<Int> hide;
198  
    if (!withHidden) for (Entry e : entries) if (eqic(e.key, 'hide) && isSquareBracketedInt(e.value)) addAll(hide, e.count, parseInt(unSquareBracket(e.value)));
199  
    new MultiMap<Int, S> mmMeta;
200  
    for (Entry e : entries) if (isSquareBracketedInt(e.key)) mmMeta.put(parseInt(unSquareBracket(e.key)), e.value);
201  
    new MultiMap<S> mm;
202  
    for (Entry e : entries) mm.put(e.key, e.value);
203  
    
204  
    //S name = or2(/* ouch */ last(mm.get("read as")), /* end ouch */ unpackAGIDomain(page.url), page.url);
205  
    S name = page.q;
206  
    
207  
    // Find references
208  
    
209  
    L<Entry> refs = concatLists(conceptsWhereIC Entry(value := name),
210  
      conceptsWhereIC Entry(key := name));
211  
    Set<Page> refPages = asSet(ccollect page(refs));
212  
    refPages.remove(page); // don't list current page as reference
213  
    
214  
    // Search in page names (depending on default search type)
215  
    
216  
    L<Page> searchResults;
217  
    if (eq(sideSearchType, 'leven))
218  
      searchResults = levenSearch(page.q, max := 50);
219  
    else if (eq(sideSearchType, 'literal))
220  
      searchResults = literalSearch(page.q, max := 50);
221  
    else
222  
      searchResults = (L<Page>) dm_call('agiBlueSearch, 'search, page.q, maxResult := searchResultsToShow+1, agiBlueBotID := programID());
223  
    searchResults.remove(page);
224  
225  
    S mainContents =
226  
        top + h1(ahref_unstyled("http://" + url + hquery(+q), htmlEncode2(shorten(displayLength, name))) + (newPage ? " [huh????]" : ""))
227  
      + p_nemptyLines(map(entries, func(Entry e) -> S {
228  
        !withHidden && (hide.contains(e.count) || eqic(e.key, "read as") && eqic(e.value, name)) ? ""
229  
        : "[" + e.count + "] " +
230  
          renderThing(e.key, false) + ": " +
231  
          b(renderThing(e.value, cic(mmMeta.get(e.count), "is a URL")))
232  
        }))
233  
      + hpostform(h3("Add an entry")
234  
        + "Key: " + hinputfield(key := key2) + " Value: " + hinputfield(value := value2) + "<br><br>" + hsubmit("Add")
235  
        )
236  
        
237  
      + p(ahref(agiBlueURL() + "/literalSearch" + hquery(q := page.q), "[literal search]", title := "Search pages with a name containing this page's name literally")
238  
       + " " +
239  
       ahref(agiBlueURL() + "/levenSearch" + hquery(q := page.q), "[leven search 1]", title := "Search pages with a Levenshtein similarity of 1 containing this page's name literally")
240  
       + " " +
241  
       ahref(agiBlueURL() + "/search" + hquery(q := page.q), "[scored search]", title := "Search pages with ScoredSearch"));
242  
        
243  
    S sideContents =
244  
      hform(b("GIVE ME INPUT:") + " "
245  
        + htextinput('q) + " "
246  
        + hsubmit("Ask", onclick := "document.getElementById('newInputForm').target = '';") + " "
247  
        + hsubmit("+Tab", title := "Ask and show result in a new tab", onclick := "document.getElementById('newInputForm').target = '_blank';"),
248  
        id := 'newInputForm)
249  
      
250  
      + h3("References (" + l(refPages) + ")")
251  
      
252  
      + p_nemptyLines_showFirst(10, map(pageToHTMLLink(displayLength := sideDisplayLength), refPages))
253  
      
254  
      + h3(searchTypeToText.get(sideSearchType) + " search results (" + (l(searchResults) >= searchResultsToShow ? searchResultsToShow + "+" : str(l(searchResults))) + ")")
255  
      
256  
      + p_nemptyLines_showFirst(searchResultsToShow, map(pageToHTMLLink(displayLength := sideDisplayLength), searchResults))
257  
      
258  
      + hdiv("", id := 'extraStuff);
259  
      
260  
    // TODO: sync search delivery with WebSocket creation
261  
    if (asyncSearch)
262  
      doLater(6.0, r { dm_call('agiBlueSearch, 'searchAndPost, page.q, agiBlueBotID := programID()) });
263  
      
264  
    // serve a concept page
265  
    ret hhtml2(hhead_title(pageDisplayName(page)) + hbody(
266  
      tag('table, tr(
267  
        td(mainContents, align := 'center, valign := 'top) +
268  
        td(sideContents, align := 'right, valign := 'top)),
269  
        width := "100%", height := "100%")));
270  
  }
271  
  
272  
  O servePagesToBot(Iterable<Page> pages) {
273  
    ret serveListToBot(map(pageToMap(wrapMapAsParams(params)), pages));
274  
  }
275  
276  
  O serveListToBot(Collection l) {
277  
    if (nempty(params.get('max)))
278  
      l = takeFirst(parseInt(params.get('max)), l);
279  
    ret serveJSON(l);
280  
  }
281  
282  
  // uri starts with "/bot/"
283  
  O serveBot() {
284  
    S q = params.get('q);
285  
    
286  
    if (eqic(uri, "/bot/hello")) ret serveJSON("hello");
287  
    if (eqic(uri, "/bot/hasPage")) ret serveJSON(hasPage(q));
288  
    if (eqic(uri, "/bot/randomPageContaining")) {
289  
      assertNempty(q);
290  
      ret servePageToBot(random(filter(list(Page), p -> cic(p.q, q))), params);
291  
    }
292  
    if (eqic(uri, "/bot/allPages"))
293  
      ret servePagesToBot(list(Page));
294  
    if (eqic(uri, "/bot/allPagesStartingWith")) {
295  
      assertNempty(q);
296  
      ret servePagesToBot(filter(list(Page), p -> swic(p.q, q)));
297  
    }
298  
    if (eqic(uri, "/bot/allPagesEndingWith")) {
299  
      assertNempty(q);
300  
      ret servePagesToBot(filter(list(Page), p -> ewic(p.q, q)));
301  
    }
302  
    if (eqic(uri, "/bot/allPagesContaining")) {
303  
      assertNempty(q);
304  
      ret servePagesToBot(filter(list(Page), p -> cic(p.q, q)));
305  
    }
306  
    if (eqic(uri, "/bot/allPagesContainingRegexp")) {
307  
      assertNempty(q);
308  
      Pattern pat = regexpIC(q);
309  
      ret servePagesToBot(filter(list(Page), p -> regexpFindIC(pat, p.q)));
310  
    }
311  
    
312  
    if (eqicOneOf(uri, "/bot/postSigned", "/bot/makePhysicalSlice", "/bot/approveTrustRequest")) {
313  
      S text = rtrim(params.get('text));
314  
      S key = getSignerKey(text);
315  
      if (empty(key)) ret subBot_serve500("Please include your public key");
316  
      if (!isSignedWithKey(text, key)) ret subBot_serve500("Signature didn't verify");
317  
      text = dropLastTwoLines(text); // drop signer + sig line
318  
      
319  
      Signer signer = uniq_sync Signer(publicKey := key);
320  
      
321  
      if (eqic(uri, "/bot/makePhysicalSlice")) {
322  
        if (!signer.trusted) ret subBot_serve500("Untrusted signer");
323  
        Page page = findPageFromParams(jsonDecodeMap(text));
324  
        if (page == null) ret subBot_serve500("Page not found");
325  
        ret serveJSON(uniq2_sync(PhysicalSlice, slicePage := page).b ? "Slice made" : "Slice exists");
326  
      }
327  
    
328  
      if (eqic(uri, "/bot/postSigned")) {
329  
        new L out;
330  
        for (S line : tlft(text)) {
331  
          SS map = jsonDecodeMap(line);
332  
          new GetEntriesAndPost x;
333  
          x.signer = signer;
334  
          Page page = findOrMakePageFromParams(map);
335  
          if (page == null) continue with out.add("Invalid page reference");
336  
          x.go(page, map);
337  
          out.add(x.newEntry ? "Saved" : x.entry != null ? "Entry exists" : "Need key and value");
338  
        }
339  
        ret serveJSON(out);
340  
      }
341  
      
342  
      if (eqic(uri, "/bot/approveTrustRequest")) {
343  
        if (!signer.trusted) ret subBot_serve500("Untrusted signer");
344  
        Signer toApprove = conceptWhere Signer(publicKey := trim(text));
345  
        if (toApprove == null) ret subBot_serve500("Signer to approve not found");
346  
        cset(toApprove, trusted := true, approvedBy := signer.globalID);
347  
        ret serveJSON("Approved: " + trim(text));
348  
      }
349  
      
350  
      ret subBot_serve500("CONFUSION");
351  
    }
352  
    
353  
    if (eqic(uri, "/bot/post")) {
354  
      new GetEntriesAndPost x;
355  
      x.go(pageFromQ(q), params);
356  
      ret serveJSON(x.newEntry ? "Saved" : x.entry != null ? "Entry exists" : "Need key and value");
357  
    }
358  
    
359  
    if (eqic(uri, "/bot/entriesOnPage"))
360  
      ret serveJSON(map(entriesOnPage(findPageFromParams(params)), entryToMap(false)));
361  
  
362  
    if (eqic(uri, "/bot/lookup")) {
363  
      S key = params.get('key);
364  
      if (empty(key)) ret serveJSON("Need key");
365  
      S value = getValue(findPageFromParams(params), key);
366  
      ret serveJSON(empty(value) ? "" : litmap(+value));
367  
    }
368  
  
369  
    if (eqic(uri, "/bot/latestEntries"))
370  
      ret serveJSON(map(takeFirst(10, idx_latestEntries.objectIterator()), entryToMap(true)));
371  
    if (eqic(uri, "/bot/latestPages"))
372  
      ret serveJSON(map(takeFirst(10, idx_latestCreatedPages.objectIterator()), pageToMap()));
373  
    if (eqic(uri, "/bot/latestChangedPages"))
374  
      ret serveJSON(map(takeFirst(10, idx_latestChangedPages.objectIterator()), pageToMap()));
375  
      
376  
    if (eqic(uri, "/bot/totalPageCount"))
377  
      ret serveJSON(countConcepts(Page));
378  
    if (eqic(uri, "/bot/pageWithoutPhysicalSliceCount"))
379  
      ret serveJSON(countConceptsWhere(Page, slice := null));
380  
    if (eqic(uri, "/bot/physicalSliceCount"))
381  
      ret serveJSON(countConcepts(PhysicalSlice));
382  
    if (eqic(uri, "/bot/trustedSignersCount"))
383  
      ret serveJSON(countConcepts(Signer, trusted := true));
384  
      
385  
    if (eqic(uri, "/bot/valueSearch")) {
386  
      S value = params.get('value);
387  
      L<Entry> entries = conceptsWhereIC Entry(+value);
388  
      ret serveJSON(map(takeFirst(100, entries), entryToMap(true)));
389  
    }
390  
      
391  
    if (eqic(uri, "/bot/keyAndValueSearch")) {
392  
      S key = params.get('key), value = params.get('value);
393  
      Cl<Page> pages = pagesForKeyAndValue(key, value);
394  
      ret servePagesToBot(pages);
395  
    }
396  
    
397  
    if (eqic(uri, "/bot/keyValuePairsByPopularity")) {
398  
      L<PairS> pairs = map(list(Entry), e -> pair(e.key, e.value));
399  
      LPair<S, Int> pairs2 = multiSetTopPairs(ciMultiSet(map pairToUglyStringForCIComparison(pairs)));
400  
      ret serveJSON(map(pairs2, p -> {
401  
        S key, value = unpair pairFromUglyString(p.a);
402  
        ret litorderedmap(n := p.b, +key, +value);
403  
      }));
404  
    }
405  
    
406  
    if (eqic(uri, "/bot/allKeys"))
407  
      ret serveListToBot(distinctCIFieldValuesOfConcepts Entry('key));
408  
      
409  
    if (eqic(uri, "/bot/allKeysByPopularity"))
410  
      ret serveListToBot(mapMultiSetByPopularity(distinctCIFieldValuesOfConcepts_multiSet Entry('key), (key, n) -> litorderedmap(+n, +key)));
411  
      
412  
    if (eqic(uri, "/bot/dbSize"))
413  
      ret serveJSON(l(conceptsFile()));
414  
      
415  
    if (eqic(uri, "/bot/query")) {
416  
      S query = params.get('query);
417  
      L<ALQLLine> lines = agiBlue_parseQueryScript(query);
418  
      
419  
      SS vars = ciMap();
420  
      for (ALQLLine line : lines) {
421  
        if (line cast ALQLReturn)
422  
          ret serveJSON(ll(getOrKeep(vars, line.var)));
423  
        else if (line cast ALQLTriple) {
424  
          T3S t = line.triple;
425  
          t = tripleMap(t, s -> getOrKeep(vars, s));
426  
          Cl<Page> pages;
427  
          S var;
428  
          if (isDollarVar(t.c)) {
429  
            var = t.c;
430  
            if (isDollarVar(t.a)) {
431  
              if (isDollarVar(t.b)) todo(t);
432  
              Entry e = random(conceptsWhereCI Entry(key := t.b));
433  
              if (e == null) ret serveJSON("No results for " + var);
434  
              pages = pagesForKeyAndValue(t.b, t.c);
435  
              vars.put(t.a, e.page->q);
436  
              vars.put(t.c, e.value);
437  
              continue;
438  
            } else if (isDollarVar(t.b)) {
439  
              Page page = findPageFromQ(t.a);
440  
              Entry e = random(findBackRefs(page, Entry));
441  
              if (e == null) ret serveJSON("No results for " + var);
442  
              vars.put(t.b, e.key);
443  
              vars.put(t.c, e.value);
444  
              continue;
445  
            } else {
446  
              S val = getValue(t.a, t.b);
447  
              if (val == null) ret serveJSON("No results for " + var);
448  
              pages = ll(pageFromQ(val));
449  
            }
450  
          } else if (isDollarVar(t.b)) {
451  
            var = t.b;
452  
            if (isDollarVar(t.c)) todo(t);
453  
            if (isDollarVar(t.a)) {
454  
              L<Entry> entries = conceptsWhereCI Entry(value := t.c);
455  
              if (empty(entries)) ret serveJSON("No results for " + var);
456  
              Entry e = random(entries);
457  
              vars.put(t.a, e.page->q);
458  
              vars.put(t.b, e.key);
459  
              continue;
460  
            } else {
461  
              Cl<S> keys = keysForPageAndValue(t.a, t.c);
462  
              if (empty(keys)) ret serveJSON("No results for " + var);
463  
              pages = map pageFromQ(keys);
464  
            }
465  
          } else {
466  
            var = t.a;
467  
            if (!isDollarVar(t.a)) todo(t);
468  
            if (isDollarVar(t.b)) todo(t);
469  
            if (isDollarVar(t.c)) todo(t);
470  
            pages = pagesForKeyAndValue(t.b, t.c);
471  
          }
472  
          if (empty(pages)) ret serveJSON("No results for " + var);
473  
          vars.put(var, random(pages).q);
474  
        } else
475  
          fail("Can't interpret: " + line);
476  
      }
477  
      
478  
      ret serveJSON("No return statement");
479  
    }
480  
481  
    // end of serveBot()
482  
  
483  
    ret subBot_serve404();
484  
  }
485  
  
486  
  O serveLiteralSearch() {
487  
    S q = params.get('q);
488  
    L<Page> searchResults = literalSearch(q);
489  
    ret serveSearchResults("literal search" , q, searchResultsToShow, searchResults);
490  
  }
491  
  
492  
  L<Page> literalSearch(S q, O... _) {
493  
    int searchResultsToShow = optPar max(_, 100);
494  
    
495  
    // quick search in random order
496  
    //L<Page> searchResults = takeFirst(searchResultsToShow+1, filterIterator(iterator(list(Page)), p -> cic(p.q, q));
497  
    
498  
    // full search, order by length
499  
    ret takeFirst(searchResultsToShow+1, pagesSortedByLength(filter(list(Page), p -> cic(p.q, q))));
500  
  }
501  
  
502  
  O serveScoredSearch() {
503  
    S q = params.get('q);
504  
    L<Page> searchResults = (L<Page>) dm_call('agiBlueSearch, 'search, q);
505  
    ret serveSearchResults("scored search" , q, searchResultsToShow, searchResults);
506  
  }
507  
  
508  
  O serveLevenSearch() {
509  
    S q = params.get('q);
510  
    L<Page> searchResults = levenSearch(q);
511  
    ret serveSearchResults("leven search with distance 1" , q, searchResultsToShow, searchResults);
512  
  }
513  
  
514  
  L<Page> levenSearch(S q, O... _) {
515  
    int searchResultsToShow = optPar max(_, 100);
516  
    int maxEditDistance = 1;
517  
    
518  
    new Map<Page, Int> map;
519  
    for (Page p) {
520  
      int distance = leven_limitedIC(q, p.q, maxEditDistance+1);
521  
      if (distance <= maxEditDistance) map.put(p, distance);
522  
    }
523  
    ret takeFirst(searchResultsToShow+1, keysSortedByValue(map));
524  
  }
525  
  
526  
  O serveSearchResults(S searchType, S q, int searchResultsToShow, Collection<Page> searchResults) {
527  
    S title = "agi.blue " + searchType + " for " + htmlEncode2(quote(q)) + " (" + (l(searchResults) >= searchResultsToShow ? searchResultsToShow + "+ results" : nResults(l(searchResults))) + ")";
528  
    
529  
    ret hhtml2(hhead_title(htmldecode_dropAllTags(title))
530  
      + hbody(hfullcenter(//top +
531  
        h3(title)
532  
      + p_nemptyLines_showFirst(searchResultsToShow, map(pageToHTMLLink(), searchResults)))));
533  
  }
534  
  
535  
  O serveQueryPage() {
536  
    S query = params.get('query);
537  
    if (query == null) query = loadSnippet(#1024258);
538  
    S title = ahref("/", "agi.blue") + " | Execute a query script (" + targetBlank("http://code.botcompany.de/1024274", "ALQL") + ")";
539  
    ret hhtml2(hhead_title(htmldecode_dropAllTags(title))
540  
      + hbody(hfullcenter(
541  
        h3(title)
542  
      + form(
543  
        htextarea(query, name := 'query, cols := 80, rows := 10, autofocus := true)
544  
        + "<br><br>"
545  
        + hsubmit("Execute"), action := "/bot/query")
546  
      )));    
547  
  }
548  
549  
} // end of class Request
550  
551  
svoid dbLog(O... params) {
552  
  logStructure(programFile("db.log"), ll(params));
553  
}
554  
555  
static IF1<Page, Map> pageToMap(O... _) {
556  
  optPar bool withEntries;
557  
  
558  
  bool nameOnly = eqOneOf(optPar nameOnly(_), "1", true);
559  
  if (nameOnly) ret (IF1<Page, Map>) p -> litmap(q := p.q);
560  
  
561  
  ret (IF1<Page, Map>) p -> {
562  
    L<Entry> entries = findBackRefs(p, Entry);
563  
    ret litorderedmap(
564  
      q := p.q,
565  
      nEntries := l(entries),
566  
      created := p.created,
567  
      modified := p._modified,
568  
      entries := !withEntries ? null : map(entries, entryToMap(false)));
569  
  };
570  
}
571  
572  
static IF1<Entry, Map> entryToMap(bool withPage) {
573  
  ret (IF1<Entry, Map>) e -> litorderedmap(
574  
    created := e.created,
575  
    i := e.count,
576  
    key := e.key,
577  
    value := e.value,
578  
    q := withPage ? e.page->q : null,
579  
    signer := getString globalID(e.signer!));
580  
}
581  
582  
sO servePageToBot(Page page, SS params) {
583  
  if (page == null) ret serveJSON(null);
584  
  params = asCIMap(params);
585  
  Map map = pageToMap(withEntries := valueIs1 withEntries(params)).get(page);
586  
  ret serveJSON(map);
587  
}
588  
589  
sclass GetEntriesAndPost {
590  
  L<Entry> entries;
591  
  Entry entry;
592  
  bool newEntry;
593  
  Signer signer;
594  
  
595  
  GetEntriesAndPost go(Page page, SS params) {
596  
    S key = trim(params.get('key)), value = trim(params.get('value));
597  
    print("GetEntriesAndPost: " + quote(page.q) + ", " + quote(key) + " := " + quote(value));
598  
    withDBLock {
599  
      entries = findBackRefs(page, Entry);
600  
      if (nempty(key) && nempty(value)) {
601  
        S ip = subBot_clientIP();
602  
        entry = firstThat(e -> eqic(e.key, key) && eq_icIf(!allowMultipleCasesInValues, e.value, value) && eq(e.ip, ip), entries);
603  
        if (entry == null) {
604  
          print("SAVING");
605  
          Entry e = cnew Entry(+page, +key, +value, +ip, count := l(entries) + 1, +signer);
606  
          page.change(); // bump modification date
607  
          entry = e;
608  
          newEntry = true;
609  
          entries.add(entry);
610  
          dbLog("New entry", page := page.q, globalID := e.globalID, count := e.count, +key, +value);
611  
        }
612  
      }
613  
    }
614  
615  
    sortByFieldInPlace created(entries);
616  
    numberEntriesInConceptField count(entries);
617  
    this;
618  
  }
619  
}
620  
621  
static Page findPageFromParams(Map map) {
622  
  S q = getString q(map);
623  
  ret empty(q) ? null : findPageFromQ(q);
624  
}
625  
626  
static Page findOrMakePageFromParams(Map map) {
627  
  ret pageFromQ(getString q(map));
628  
}
629  
630  
static Page findPageFromQ(S q) {
631  
  ret conceptWhereCI Page(+q);
632  
}
633  
634  
static Page pageFromQ(S q) {
635  
  ret empty(q) ? null : uniqCI_sync Page(+q);
636  
}
637  
638  
static F1<Page, S> pageToHTMLLink(O... _) {
639  
  optPar int displayLength = main.displayLength;
640  
  ret func(Page p) -> S {
641  
    S name = pageDisplayName(p);
642  
    ret ahref(agiBlueURL() + hquery(q := p.q),
643  
      htmlEncode2(shorten(displayLength, name)),
644  
      title := name);
645  
  };
646  
}
647  
648  
static Collection<S> backSearch(S key, S value) {
649  
  // we query the index for the value field because that yields fewer results
650  
  ret map(conceptsWhereCI Entry(value := "a slice of reality", key := "is"), e -> e.page->q);
651  
}
652  
653  
static Collection<S> availableSlices() {
654  
  ret moveElementToBeginningIC("the default slice", backSearch("is", "a slice of reality"));
655  
  //ret ll("the default slice", "the everything slice", "the robot slice");
656  
}
657  
658  
static PhysicalSlice getOrMakePhysicalSlice(Page p) {
659  
  PhysicalSlice slice = first(findBackRefs PhysicalSlice(p));
660  
  if (slice == null)
661  
    slice = uniq_sync(PhysicalSlice, slicePage := p);
662  
  ret slice;
663  
}
664  
665  
static PhysicalSlice theWildSlice() {
666  
  ret getOrMakePhysicalSlice(pageFromQ("the wild slice"));
667  
}
668  
669  
svoid moveSlicelessPagesToTheWildSlice() {
670  
  PhysicalSlice slice = theWildSlice();
671  
  for (Page p : conceptsWhere Page(slice := null))  {
672  
    print("Moving to wild slice: " + p.q);
673  
    cset_sync(p, +slice);
674  
  }
675  
}
676  
677  
sS renderThing(S s, bool forceURLDisplay) {
678  
  ret forceURLDisplay || isURL(s) || isAGIDomain(s)
679  
    ? ahref(fixAGILink(absoluteURL(s)), htmlencode2(shorten(displayLength, s)))
680  
    : ahref(agiBlue_linkForPhrase(s), htmlencode2(shorten(displayLength, s)));
681  
}
682  
683  
static L<Entry> entriesOnPage(Page p) {
684  
  ret p == null ? null : sortedByField count(findBackRefs(p, Entry));
685  
}
686  
687  
static L<Page> pagesSortedByLength(L<Page> l) {
688  
  ret sortedByCalculatedField(l, p -> l(p.q));
689  
}
690  
691  
sS hhtml2(S contents) {
692  
  ret hhtml(hAddToHead_fast(contents, 
693  
    hIncludeGoogleFont("Source Sans Pro")
694  
    + hmobilefix()
695  
    + hstylesheet("body { font-family: Source Sans Pro }")));
696  
}
697  
698  
static Set<Page> pagesForKeyAndValue(S key, S value) {
699  
  L<Entry> entries = conceptsWhereIC Entry(+value, +key);
700  
  ret asSet(ccollect page(entries));
701  
}
702  
703  
static Cl<S> keysForPageAndValue(S q, S value) {
704  
  Page page = findPageFromQ(q);
705  
  if (page == null) null;
706  
  ret collect key(conceptsWhereIC Entry(+page, +value));
707  
}
708  
709  
sbool agiBlue_isOriginal() {
710  
  ret amProgram(#1023558);
711  
}
712  
713  
sS agiBlueURL() {
714  
  ret agiBlue_isOriginal() ? "http://agi.blue" : myLink("");
715  
}
716  
717  
sS agiBlueName() {
718  
  ret agiBlue_isOriginal() ? "agi.blue" : "agi.blue clone " + programID();
719  
}

Author comment

Began life as a copy of #1023558

download  show line numbers  debug dex  old transpilations   

Travelled to 6 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1024284
Snippet name: agi.blue source [secondary version]
Eternal ID of this version: #1024284/11
Text MD5: d1354c07bda37ca068235eb169b11e4f
Transpilation MD5: c30f20450f8dd014383cc6c3d2eae583
Author: stefan
Category: javax / html
Type: JavaX module (desktop)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-07-29 13:45:17
Source code size: 27162 bytes / 719 lines
Pitched / IR pitched: No / No
Views / Downloads: 297 / 1737
Version history: 10 change(s)
Referenced in: [show references]