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

1839
LINES

< > BotCompany Repo | #1031397 // Gazelle BEA [new class naming scheme, abandoned]

JavaX source code (Dynamic Module) - run with: Stefan's OS

1  
!7
2  
3  
// TODO: prevent non-master users from setting createdBy field manually
4  
5  
!include early #1031277 // BEA general includes
6  
7  
!include once #1030833 // BEACalculations
8  
9  
set flag defaultDefaultClassFinder_debug.
10  
11  
set flag CleanImports.
12  
set flag DynModule.
13  
set flag NoNanoHTTPD.
14  
set flag AllPublic. // for dynamic BEA objects
15  
rewrite BEA with BEAObject.
16  
17  
mainPackage gazelle
18  
mainClassName main
19  
20  
module GazelleBEA > DynGazelleRocks {
21  
  switchable bool mirrorBEAObjects; // don't do it for now
22  
  switchable bool enableAutoRuns = true;
23  
  switchable bool enableNewBEAObjectNotis = true;
24  
  switchable bool printAllConceptChanges;
25  
  switchable bool useShadowLogger = true;
26  
  switchable bool autoActivateDynamicObjects = true;
27  
28  
  transient ReliableSingleThread_Multi<BEAObject> rstAutoRuns = new(1000, lambda1 performAutoRuns);
29  
  transient Q notificationQ;
30  
  transient ReliableSingleThread_Multi<BEAObject> rstDistributeNewObject = new(1000, lambda1 distributeNewObject_impl);
31  
  transient Set<BEAObject> newObjectsDistributed = weakSet();
32  
33  
  transient ReliableSingleThread_Multi<BEAObject> rstUpdateBEAMirrors = new(100, c -> enter { c.updateMirrorPost(); });
34  
  
35  
  transient ReliableSingleThread_Multi<BEAObject> rstAutoActivateDynamicObjects = new(100, c -> enter { autoActivateDynamicObject(c); });
36  
37  
  transient BEACalculations calculations = new(this);
38  
  transient BEACalculations calc = calculations;
39  
  transient int newFieldsToShow = 3;
40  
  transient bool allowAnonymousInputUpload = true; // TODO
41  
  switchable int maxInputLength = 50000;
42  
  
43  
  transient ConceptClassesDependentValue<Int> inputsWithoutRewrites;
44  
  transient ConceptClassesDependentValue<Int> inputsWithoutMatches;
45  
  transient ConceptClassesDependentValue<Int> syntacticPatternsWithoutRewrites;
46  
47  
  // add more fields here
48  
  
49  
  !include #1030883 // DB quickImport mix-in
50  
  
51  
  void init {
52  
    super.init();
53  
    //set quickDBReloadEnabled;
54  
    botName = heading = adminName = "Gazelle BEA";
55  
    set enableVars;
56  
    unset showTalkToBotLink;
57  
    unset phoneNumberSpecialInputField;
58  
    unset showMetaBotOnEveryPage;
59  
  }
60  
61  
  void startDB {
62  
    // TODO: also load classes referenced between objects
63  
    // e.g. because of subclassing
64  
    O classFinder = _defaultClassFinder();
65  
    db_mainConcepts().classFinder = func(S name) -> Class enter {
66  
      print("Looking for class " + name);
67  
      if (name.startsWith("dyn.")) {
68  
        long conceptID = firstLong_regexp(name);
69  
        BEA o = beaGet(conceptID);
70  
        
71  
        if (o != null) {
72  
          File bytecode = byteCodeFileForObject(o, shortenClassName(name));
73  
          print("Found byte code: " + bytecode);
74  
          dm_addByteCodePathToModuleClassLoader(bytecode);
75  
        }
76  
              
77  
        ret print("Found dynamic: ", _getClass(module(), name));
78  
      }
79  
      ret (Class) callF(classFinder, name);
80  
    };
81  
    
82  
    db();
83  
    db_mainConcepts().useBackRefsForSearches = true;
84  
    inputsWithoutRewrites = ConceptClassesDependentValue(litset(BEA), () -> countPred(beaList("Input"), c -> empty(beaBackRefs(c, "Rewrite"))));
85  
    inputsWithoutMatches = ConceptClassesDependentValue(litset(BEA), () -> countPred(beaList("Input"), c -> empty(beaBackRefs(c, "Match"))));
86  
    syntacticPatternsWithoutRewrites = ConceptClassesDependentValue(litset(BEA), () -> countPred(beaList("Syntactic Pattern"), c -> empty(beaBackRefs(c, "Rewrite"))));
87  
    
88  
    if (useShadowLogger) {
89  
      ConceptsShadowLogger shadowLogger = new(db_mainConcepts());
90  
      shadowLogger.install();
91  
      //shadowLogger.writer = printWriter(deflaterOutputStream_syncFlush_append(programFile("shadow.log.deflated")));
92  
      shadowLogger.writer = filePrintWriter_append(programFile("shadow.log"));
93  
      dm_doEvery(10.0, r { shadowLogger.flush(); });
94  
      ownResource(shadowLogger);
95  
    }
96  
    
97  
    if (printAllConceptChanges) printAllConceptChanges();
98  
  }
99  
100  
  void start {
101  
    set dm_isFirstSiblingModule_debug;
102  
    S name = mcDollar() + "BEAObject";
103  
    print(+name);
104  
    assertEquals(BEAObject, callF(defaultDefaultClassFinder(), name));
105  
    assertEquals(ConceptWithGlobalID, callF(defaultDefaultClassFinder(), mcDollar() + "ConceptWithGlobalID"));
106  
    seedDBFrom(#1030602);
107  
    set botDisabled;
108  
    set storeBaseClassesInStructure;
109  
    super.start();
110  
    print("main concepts: " + db_mainConcepts() + ", count: " + db_mainConcepts().countConcepts());
111  
    print(renderConceptClassesWithCount(db_mainConcepts()));
112  
    print("Inputs: " + n2(beaCount("Input")));
113  
    set showCRUDToEveryone;
114  
    //set showOnlySelectedObject;
115  
    
116  
    // reload module when lib changes
117  
    dm_onSnippetTranspiled(voidfunc(S snippetID) {
118  
      if (sameSnippetID(snippetID, #1030952))
119  
        dm_reloadModule();
120  
    });
121  
122  
    if (!enabled) ret;
123  
124  
    // mirror all objects to be sure
125  
    rstUpdateBEAMirrors.addAll(list(BEAObject));
126  
    
127  
    newObjectsDistributed.addAll(list(BEAObject));
128  
    
129  
    /*onIndividualConceptChange_notOnAllChanged(BEAObject,
130  
      p -> { calculations.makeSyntacticPattern(p); });*/
131  
      
132  
    onIndividualConceptChange_notOnAllChanged(BEAObject,
133  
      o -> {
134  
        if (enableAutoRuns) rstAutoRuns.add(o);
135  
        if (enableNewBEAObjectNotis && newObjectsDistributed.add(o))
136  
          rstDistributeNewObject.add(o);
137  
      });
138  
      
139  
    notificationQ = dm_startQ();
140  
    
141  
    // fix refs occasionally
142  
    
143  
    dm_doEvery(5*60.0, r-enter {
144  
      print(ConceptsRefChecker(db_mainConcepts()).runAndFixAll());
145  
    });
146  
    
147  
    // reactivate the dynamic objects
148  
    
149  
    if (autoActivateDynamicObjects)
150  
      dm_startThread("Reactivator", r {
151  
        var list = filter(beaList(), o -> nempty(getString meta_javaClass(o)));
152  
        
153  
        new L<BEA> toRecompile;
154  
        
155  
        bool progress;
156  
        do {
157  
          new L<BEA> postponed; // because prototype not activated yet
158  
          progress = false;
159  
          
160  
          for ping (int idx, BEA o : unpair iterateWithIndex1(list)) {
161  
            printWithMilliseconds("Reactivating object " + idx + "/" + l(list) + ": " + o);
162  
            if (basedOnUnactivatedPrototype(o)) {
163  
              print("Postponing " + o + ", waiting for " + cget meta_protype(o));
164  
              postponed.add(o);
165  
            } else pcall {
166  
              set progress;
167  
              if (!reactivateDynamicObject(o))
168  
                toRecompile.add(o);
169  
            }
170  
          }
171  
          list = postponed;
172  
        } while (progress);
173  
        
174  
        if (nempty(list))
175  
          pnl("Couldn't reactivate: ", list);
176  
        
177  
        print("Done reactivating, will recompile " + n2(toRecompile));
178  
        for (BEA o : toRecompile) pcall {
179  
          activateDynamicObject(o);
180  
        }
181  
      });
182  
  }
183  
184  
  void makeIndices :: after {    
185  
    indexConceptFieldDesc(BEAObject, "_modified");
186  
    indexConceptFieldIC(BEAObject, "type");
187  
    indexConceptFieldIC(BEAObject, "text");
188  
  }
189  
  
190  
  L<Class> crudClasses(Req req) {
191  
    ret listPlus(super.crudClasses(req), BEAObject, /*BEAPatternList*/);
192  
  }
193  
  
194  
  Set<Class> hiddenCrudClasses() {
195  
    Set<Class> set = super.hiddenCrudClasses();
196  
    addAll(set, Conversation, ExecutedStep, InputHandled);
197  
    ret set;
198  
  }
199  
  
200  
  S authFormHeading() {
201  
    ret h3("Gazelle BEA");
202  
  }
203  
  
204  
  void makeFramer(Req req) {
205  
    super.makeFramer(req);
206  
    
207  
    req.framer.addInHead(hjs_autoExpandingTextAreas());
208  
  }
209  
210  
  <A extends Concept> HCRUD_Concepts<A> crudData(Class<A> c, Req req) {
211  
    HCRUD_Concepts<A> cc = super.crudData(c, req);
212  
    
213  
    if (c == BEAObject) {
214  
      cc.humanizeFieldNames = false;
215  
      cc.convertConceptValuesToRefs = true;
216  
      cc.itemName = () -> "BEA Object";
217  
      
218  
      cc.onCreate.add(o ->
219  
        cset(o, createdBy := currentUser()));
220  
      
221  
      cc.getObjectForDuplication = id -> {
222  
        MapSO item = cc.getObjectForDuplication_base(id);
223  
        item.put(createdBy := req.auth.user!); // set default creator to current user
224  
        item.put(createdFrom := getConcept(toLong(id)));
225  
        ret item;
226  
      };
227  
      
228  
      cc.emptyObject = () -> {
229  
        MapSO item = cc.emptyObject_base();
230  
        item.put(type := "");
231  
        ret item;
232  
      };
233  
      
234  
      Set<S> deletableRefs = litciset("Match");
235  
      
236  
      cc.objectCanBeDeleted = id -> {
237  
        BEA o = cast cc.conceptForID(id);
238  
        ret userCanEditObject(user(req), o)
239  
          && all(findBackRefs(BEAObject, o), x -> contains(deletableRefs, x.type()));
240  
      };
241  
242  
      cc.actuallyDeleteConcept = o -> {
243  
        deleteConcepts(filter(findBackRefs(BEAObject, o),
244  
          o2 -> contains(deletableRefs, o2.type())));
245  
        cdelete(o);
246  
      };
247  
    }
248  
249  
    ret cc;
250  
  }
251  
252  
  <A extends Concept> HCRUD makeCRUD(Class<A> c, Req req, HTMLFramer1 framer) {
253  
    HCRUD crud = super.makeCRUD(c, req, framer);
254  
    HCRUD_Concepts data = cast crud.data;
255  
    crud.showOnlySelected = true;
256  
    crud.showSearchField = true;
257  
    if (data.customFilter == null)
258  
      crud.descending = true; // show latest objects first by default except when searching
259  
    crud.cleanItemIDs = true;
260  
261  
    if (c == BEAObject) {
262  
      crud.cellColumnToolTips = true;
263  
      crud.unshownFields = litset("mirrorPost", "globalID");
264  
      crud.showTextFieldsAsAutoExpandingTextAreas = true;
265  
      HCRUD_Concepts cc = cast crud.data;
266  
      
267  
      S typeFilter = req.get("type");
268  
      if (nempty(typeFilter))
269  
        cc.addCIFilter(type := typeFilter);
270  
      
271  
      crud.renderCmds = map -> {
272  
        BEA o = getConcept BEA(crud.itemIDAsLong(map));
273  
        
274  
        new LS cmds;
275  
        
276  
        // ask the object itself for commands
277  
        
278  
        addAll(cmds, allToString(optCast Cl(pcall(o, "cmds"))));
279  
        
280  
        // special commands for BEA types or objects with certain fields
281  
        
282  
        if (fileNotEmpty(javaSourceFileForObject(o)))
283  
          cmds.add(targetBlank(baseLink + "/javaSource?id=" + o.id, "Show Java source"));
284  
        
285  
        if (nempty(o.text()))
286  
          cmds.add(
287  
            targetBlank(addParamsToURL(baseLink + "/query",
288  
              q := o.text(), algorithm := "process input"),
289  
              "Use text as query"));
290  
291  
        if (o.typeIs("Input")) {
292  
          cmds.add(ahref(addParamsToURL(crudLink(BEAObject),
293  
            cmd := "new",
294  
            title := "Add Pattern For Input",
295  
            f_type := "Pattern",
296  
            f_text := getStringOpt text(o),
297  
            f_shouldMatch := o.id, metaInfo_shouldMatch := "concept",
298  
          ), "Add pattern"));
299  
300  
          cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.text(), algorithm := "Apply all text functions"),
301  
           "Apply all text functions"));
302  
        }
303  
304  
        if (o.typeIs("Pattern"))
305  
          cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.id, algorithm := "Run pattern"),
306  
           "Try-run pattern against all inputs"));
307  
        
308  
        if (o.typeIsOneOf("Pattern", "Syntactic Pattern")) {
309  
          cmds.add(ahref(appendParamsToURL(baseLink + "/reactAllInputsWithPattern", patternID := o.id),
310  
           "React pattern with all inputs"));
311  
           
312  
          cmds.add(ahref(appendParamsToURL(baseLink + "/convertSyntacticToSemanticMatchesForWholePattern", patternID := o.id),
313  
            "Convert all syntactic matches to semantic matches"));
314  
        }
315  
316  
        if (o.typeIs("Match")) {
317  
          cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.id, algorithm := "Find rewrites for match"),
318  
           "Find rewrites"));
319  
          if (beaTypeIs(beaGet pattern(o), "Syntactic Pattern"))
320  
            cmds.add(ahref(appendParamsToURL(baseLink + "/convertSyntacticToSemanticMatches", matchID := o.id),
321  
            "Convert to semantic matches"));
322  
        }
323  
324  
        cmds.add(
325  
          ahref(addParamsToURL(baseLink + "/markUseful",
326  
            redirect := beaShortURL(o),
327  
            objectID := o.id),
328  
            "Mark useful"));
329  
        
330  
        cmds.add(
331  
          ahref(addParamsToURL(baseLink + "/markBad",
332  
            redirect := beaShortURL(o),
333  
            objectID := o.id),
334  
            "Mark bad"));
335  
        
336  
        cmds.add(addCommentHTML(o));
337  
          
338  
        if (o.typeIsOneOf("Script", "Step in script") || eqic(beforeVerticalBar(o.type()), "Instruction"))
339  
          cmds.add(
340  
            ahref(addParamsToURL(baseLink + "/runInstruction",
341  
              instruction := o.id),
342  
              "Run"));
343  
              
344  
        if (o.typeIs("Function Result")) {
345  
          if (eqic(cget resultType(o), "string"))
346  
            cmds.add(
347  
              ahref(addParamsToURL(baseLink + "/convertResultToInput",
348  
                result := o.id),
349  
                "Convert to input"));
350  
        }
351  
        
352  
        if (o.typeIs("Auto Run"))
353  
          cmds.add(
354  
            ahref(addParamsToURL(baseLink + "/performAutoRunOnAllObjects", autoRun := o.id), "Run on all objects"));
355  
356  
        if (o.getClass() != BEA)
357  
          cmds.add(
358  
            ahref(addParamsToURL(baseLink + "/migrateToBase", id := o.id), "Migrate to BEAObject"));
359  
            
360  
        cmds.add(
361  
          ahref(addParamsToURL(baseLink + "/performAutoRuns",
362  
            onObject := o.id),
363  
            "Perform auto runs on this object"));
364  
            
365  
        framer.addInHead(hjs_copyToClipboard());
366  
        
367  
        cmds.add(ahref_onClick(formatFunctionCall copyToClipboard(jsQuote(o.globalIDStr())), "Copy global ID [" + o.globalIDStr() + "]"));
368  
        
369  
        LS items = llNempties(
370  
          crud.renderCmds_base(map),
371  
          !o.typeIsOneOf("Input", "Pattern", "Syntactic Pattern")
372  
            ? null : addRewriteHTML(o),
373  
          !canAutoMigrate(o) ? null 
374  
            : ahref(addParamsToURL(baseLink + "/autoMigrate", id := o.id), "Auto-migrate to " + shortClassName(defaultCustomClass(o))));
375  
376  
        if (isObjectWithCode(o) && isMasterAuthed(req))
377  
          items.add(ahref(baseLink + "/activateDynamicObject?id=" + o.id, "Activate custom code"));
378  
379  
        // add more commands here
380  
        
381  
        pcall { addAll(items, o.directCmds()); }
382  
        
383  
        pcall {
384  
          addAll(items, (LS) callOpt(getWebsiteEnhancer("commandsForObject"), 'commandsFor, o));
385  
        }
386  
        
387  
        items.add(hPopDownButton(cmds));
388  
        ret joinNemptiesWithVBar(items);
389  
      };
390  
      
391  
      cc.massageItemMapForList = (item, map) -> {
392  
        BEAObject o = cast item;
393  
        
394  
        if (o.typeIs("Input")) {
395  
          Cl<BEAObject> matches = objectsWhereNotIC(objectsWhereCI(findBackRefs(o, BEAObject), type := "match"),
396  
            label := "bad");
397  
          map/Map.put("Best Matches", HTML(hparagraphs(
398  
            lmap matchDescHTML(takeFirst(3, matches)))));
399  
        }
400  
        S idField = crud.idField();
401  
        O id = map/Map.get(idField);
402  
        if (id instanceof S)
403  
          map/Map.put(idField, HTML(ahref(beaShortURL(o), id)));
404  
        if (o.typeIs("Function Result")) {
405  
          O value = o~.result;
406  
          map/Map.put("result", HTML(javaValueToHTML(value)));
407  
        }
408  
        
409  
        if (o.typeIs("Match")) {
410  
          SS mapping = o.mapping();
411  
          if (mapping != null)
412  
          map/Map.put("mapping", HTML(
413  
            joinWithBR(map(mapping, (k, v) ->
414  
              htmlEncode2(k) + "=" + calculations.bestInputHTML(v)))));
415  
        }
416  
      
417  
        if (o.getClass() != BEA)
418  
          map/Map.put("Java Class", className(o));
419  
          
420  
        if (eq(req.get("showSimpleObjectScore"), "1"))
421  
          map/Map.put("Simple object score" := calculations.simpleObjectScore(o));
422  
      }; // end of massageItemMapForList
423  
      
424  
      crud.massageFormMatrix = (map, matrix) -> {
425  
        for (int i = 1; i <= newFieldsToShow; i++) {
426  
          S nf = "newField" + i;
427  
          
428  
          S refSelector =
429  
            crud.renderInput("\*nf*/_conceptValue",
430  
              cc.makeConceptsComboBox("\*nf*/_conceptValue", BEAObject), null)
431  
            + hjs([[$("[name=]] + nf + [[_conceptValue]").hide()]]);
432  
              
433  
          S userSelector =
434  
            crud.renderInput("\*nf*/_userValue",
435  
              cc.makeConceptsComboBox("\*nf*/_userValue", User), null)
436  
            + hjs([[$("[name=]] + nf + [[_userValue]").hide()]]);
437  
              
438  
          LS types = ll("String", "BEAObject", "Bool", "User");
439  
              
440  
          S typeSelector = hselect_list(types, name := "\*nf*/_type",
441  
              onchange := [[
442  
                var value = this.value;
443  
                $("[name=]] + nf + [[_value]").toggle(value == "String" || value == "Bool");
444  
                $("#]] + nf + [[_refBox").toggle(value == "BEAObject");
445  
                $("#]] + nf + [[_userSel").toggle(value == "User");
446  
              ]]);
447  
          
448  
          matrix.add(ll("Add field:<br>" + htextfield("\*nf*/_name", title := "New field name"),
449  
            htmlTable2_noHtmlEncode(ll(ll(
450  
              // string input
451  
              //htextfield("\*nf*/_value"),
452  
              htextarea("",
453  
                name := "\*nf*/_value", 
454  
                class := "auto-expand",
455  
                style := "width: 300px",
456  
              ) +
457  
              span(refSelector, id := "\*nf*/_refBox", style := "display: none"),
458  
              span(userSelector, id := "\*nf*/_userSel", style := "display: none"),
459  
            "Type", typeSelector
460  
            )),
461  
            noHeader := true,
462  
            tableParams := litobjectarray(style := "width: 100%"))));
463  
          }
464  
        };
465  
      
466  
      crud.preprocessUpdateParams = params -> {
467  
        params = cloneMap(params);
468  
469  
        // drop empty strings
470  
        //removeFromMapWhereValue(params, v -> eq(v, ""));
471  
        params = mapValues(params, v -> eq(v, "") ? null : v);
472  
        
473  
        for (int i = 1; i <= max(newFieldsToShow, 10); i++) {
474  
          S nf = "newField" + i;
475  
          S name = params.get("\*nf*/_name"),
476  
            type = params.get("\*nf*/_type"),
477  
            refValue = params.get("\*nf*/_conceptValue"),
478  
            userValue = params.get("\*nf*/_userValue"),
479  
            value = params.get("\*nf*/_value");
480  
  
481  
          if (eqic(type, "BEAObject")) {
482  
            value = refValue;
483  
            params.put("metaInfo_" + name, "concept");
484  
          } else if (eqic(type, "User")) {
485  
            value = userValue;
486  
            params.put("metaInfo_" + name, "concept");
487  
          } else if (eqic(type, "Bool"))
488  
            params.put("metaInfo_" + name, "bool");
489  
          
490  
          if (eq(value, "")) value = null;
491  
            
492  
          if (nempty(name) /*&& neqOneOf(value, null, "")*/)
493  
            params.put(crud.fieldPrefix + name, value);
494  
        }
495  
        
496  
        ret params;
497  
      };
498  
499  
      // regular users can only edit their own objects
500  
      if (!isMasterAuthed(req))
501  
        cc.objectCanBeEdited = id -> userCanEditObject(user(req), (BEA) cc.conceptForID(id));
502  
    } // end of CRUD customization for BEAObject
503  
    
504  
    ret crud;
505  
  }
506  
507  
  bool userCanEditObject(User user, BEA o) {
508  
    ret cget createdBy(o) == user;
509  
  }
510  
  
511  
  O serveBotFunction(Req req, S function, Map data, User user) {
512  
    if (eq(function, "beaList")) {
513  
      long changedAfter = toLong(data.get("changedAfter"));
514  
      double pollFor = min(bot_maxPollSeconds, toLong(data.get("pollFor"))); // how long to poll (seconds)
515  
      long startTime = sysNow();
516  
517  
      // We're super-anal about catching all changes. This will probably never trigger
518  
      if (changedAfter > 0 && changedAfter == now()) sleep(1);
519  
      
520  
      Cl<BEAObject> objects;
521  
      while true {
522  
        objects = changedAfter == 0 ? list(BEAObject)
523  
          : conceptsWithFieldGreaterThan_sorted(BEAObject, _modified := changedAfter);
524  
525  
        // return when there are results, no polling or poll expired
526  
        if (nempty(objects) || pollFor == 0 || elapsedSeconds_sysNow(startTime) >= pollFor)
527  
          ret serveJSON_breakAtLevels(2, result := map(objects, obj ->
528  
            litorderedmap(gid := str(obj.globalID()), struct := obj.structureString())
529  
          ));
530  
531  
        // sleep and try again
532  
        sleep(bot_pollInterval);
533  
      }
534  
    }
535  
    
536  
    ret super.serveBotFunction(req, function, data, user);
537  
  }
538  
539  
  O serveOtherPage2(Req req) null {
540  
    printVars_str serveOtherPage2(uri := req.uri);
541  
    try object super.serveOtherPage2(req);
542  
    
543  
    S uri = dropTrailingSlashIfNemptyAfterwards(req.uri);
544  
    new Matches m;
545  
    
546  
    if (swic_notSame(uri, "/beaCRUD/", m))
547  
      ret renderBEAObjectTable(req, urldecode(m.rest()));
548  
    
549  
    if (eq(uri, "/inputs"))
550  
      ret renderBEAObjectTable(req, "input");
551  
      
552  
    if (eq(uri, "/syntacticMatchesTable"))
553  
      ret hrefresh(baseLink + "/matchesTable?syntacticOnly=1");
554  
      
555  
    if (eq(uri, "/matchesTable")) {
556  
      bool syntacticOnly = eq("1", req.get("syntacticOnly"));
557  
558  
      new L<BEA> list;
559  
      for (BEA match : beaList("Match")) {
560  
        BEA input = cgetOpt BEA(match, "input");
561  
        BEA pat = cgetOpt BEA(match, "pattern");
562  
        if (syntacticOnly && !calculations.isSyntacticPattern(pat)) continue;
563  
        continue if calculations.patternAlwaysMatches(pat);
564  
565  
        SS mapping = match.mapping();
566  
        if (input == null || pat == null || mapping == null) continue;
567  
        list.add(match);
568  
      }
569  
      list = sortedByCalculatedFieldDesc(list,
570  
        match -> conceptID(cgetBEA input(match)));
571  
      
572  
      new HTMLPaginator paginator;
573  
      paginator.processParams(req.params());
574  
      paginator.baseLink = addParamsToURL(baseLink,
575  
        filterKeys(req.params(), p -> eq(p, "syntacticOnly")));
576  
      paginator.max = l(list);
577  
      req.framer.add(divUnlessEmpty(paginator.renderNav()));
578  
      list = subList(list, paginator.visibleRange());
579  
      
580  
      new L<Map> data;
581  
      for (BEA match : list) {
582  
        BEA input = cgetOpt BEA(match, "input");
583  
        BEA pat = cgetOpt BEA(match, "pattern");
584  
        SS mapping = match.mapping();
585  
        S patText = calculations.patternTextWithAngleBracketVars(pat);
586  
        LS tok = javaTokWithAngleBrackets(patText);
587  
        new BitSet bs;
588  
        tok = replaceAngleBracketVars(tok, mapping, bs);
589  
        for (IntRange r, bool b : unpair bitSetStreaksAndNonStreaks(bs, l(tok))) {
590  
          S t = joinSubList(tok, r);
591  
          replaceTokens(tok, r, b
592  
            ? formatSubInput(input, t, "obj" + match.id)
593  
            : htmlEncode2(t));
594  
        }
595  
        S boldenedInput = join(tok);
596  
        
597  
        data.add(litorderedmap(
598  
          "Input" := aname("obj" + match.id, joinWithBR(
599  
            ahref(beaURL(input), htmlEncode2_str(input~.text())),
600  
            boldenedInput)),
601  
          "Pattern" := ahref(beaURL(pat), htmlEncode2(pat.text())), // beaHTML(pat),
602  
          //"Sub-Inputs" := htmlEncode2_str(mapping),
603  
          "DB object" := beaHTML_justID(match),
604  
          "Feedback" := joinNemptiesWithSpace(calculations.feedbackHTML(match),
605  
            addCommentHTML(match, defaultComment := "good match", redirectAfterSave := req.uriWithParams(),
606  
            text := "+")),
607  
        ));
608  
      }
609  
        
610  
      req.framer.title = syntacticOnly ? "Syntactic matches table" : "Matches table";
611  
      req.framer.add(p());
612  
      req.framer.add(htmlTable2_noHtmlEncode(data));
613  
      ret completeFrame(req);
614  
    }
615  
            
616  
    if (eq(uri, "/rewritesTable")) {
617  
      new L<Map> data;
618  
      for (BEA input : beaList("Input"))
619  
        for (BEA r : beaBackRefs(input, "Rewrite"))
620  
          data.add(litorderedmap(
621  
            "Input" := input.text(),
622  
            "Rewrite" := tok_dropCurlyBrackets(r.text()),
623  
            "Rewrite Type" := r~.rewriteType));
624  
            
625  
      req.framer.title = "Rewrites table";
626  
      req.framer.add(p());
627  
      req.framer.add(htmlTable2(data));
628  
      ret completeFrame(req);
629  
    }
630  
631  
    if (eq(uri, "/patternRewritesTable")) {
632  
      new L<Map> data;
633  
      for (BEA pat : beaListAny("Pattern", "Syntactic Pattern"))
634  
        for (BEA r : beaBackRefs(pat, "Rewrite"))
635  
          if (cget isRewriteOf(r) == pat) {
636  
            PairS example = calculations.exampleForPatternRewrite(pat, r);
637  
            data.add(litorderedmap(
638  
              "Pattern" := ahref(beaURL(pat), htmlEncode2(pat.text())),
639  
              "Rewrite" := ahref(beaURL(r), htmlEncode2(tok_dropCurlyBrackets(r.text()))),
640  
              "Example" := joinWithBR(htmlEncode2(example.a), htmlEncode2("=> " + example.b)),
641  
              "Rewrite Type" := htmlEncode2_str(r~.rewriteType),
642  
              "Cmds" := hPopDownButton(
643  
                targetBlank(conceptEditLink(r), "Edit"),
644  
              )));
645  
          }
646  
            
647  
      req.framer.title = "Pattern rewrites table";
648  
      req.framer.add(p());
649  
      req.framer.add(htmlTable2_noHtmlEncode(data));
650  
      ret completeFrame(req);
651  
    }
652  
653  
    if (eq(uri, "/syntacticPatternsWithoutRewrites")) {
654  
      HCRUD crud = makeBEAObjectCRUD(req, "Syntactic Pattern");
655  
      HCRUD_Concepts<BEAObject> data = cast crud.data;
656  
      
657  
      IF1 prev = data.customFilter;
658  
      data.customFilter = list -> {
659  
        list = filter(list, c -> empty(beaBackRefs(c, "Rewrite")));
660  
        ret postProcess(prev, list);
661  
      };
662  
      crud.customTitle = "Syntactic patterns without rewrites";
663  
      ret serveCRUD(req, BEAObject, crud);
664  
    }
665  
      
666  
    if (eq(uri, "/inputsWithoutRewrites")) {
667  
      HCRUD crud = makeBEAObjectCRUD(req, "input");
668  
      HCRUD_Concepts<BEAObject> data = cast crud.data;
669  
      
670  
      IF1 prev = data.customFilter;
671  
      data.customFilter = list -> {
672  
        list = filter(list, c -> empty(beaBackRefs(c, "Rewrite")));
673  
        ret postProcess(prev, list);
674  
      };
675  
      crud.customTitle = "Inputs without rewrites";
676  
      ret serveCRUD(req, BEAObject, crud);
677  
    }
678  
      
679  
    if (eq(uri, "/inputsWithRewrites")) {
680  
      HCRUD crud = makeBEAObjectCRUD(req, "input");
681  
      HCRUD_Concepts<BEAObject> data = cast crud.data;
682  
      
683  
      IF1 prev = data.customFilter;
684  
      data.customFilter = list -> {
685  
        list = filter(list, c -> nempty(beaBackRefs(c, "Rewrite")));
686  
        ret postProcess(prev, list);
687  
      };
688  
      crud.customTitle = "Inputs with rewrites";
689  
      ret serveCRUD(req, BEAObject, crud);
690  
    }
691  
      
692  
    if (eq(uri, "/inputsWithoutMatches")) {
693  
      HCRUD crud = makeBEAObjectCRUD(req, "input");
694  
      HCRUD_Concepts<BEAObject> data = cast crud.data;
695  
      
696  
      IF1 prev = data.customFilter;
697  
      data.customFilter = list -> {
698  
        list = filter(list, c -> empty(beaBackRefs(c, "Match")));
699  
        ret postProcess(prev, list);
700  
      };
701  
      crud.customTitle = "Inputs without matches";
702  
      ret serveCRUD(req, BEAObject, crud);
703  
    }
704  
      
705  
    if (eq(uri, "/patterns"))
706  
      ret renderBEAObjectTable(req, "pattern");
707  
708  
    if (eq(uri, "/syntacticPatterns"))
709  
      ret renderBEAObjectTable(req, "Syntactic Pattern");
710  
711  
    if (eq(uri, "/matches"))
712  
      ret renderBEAObjectTable(req, "match");
713  
714  
    if (eq(uri, "/rewrites"))
715  
      ret renderBEAObjectTable(req, "rewrite");
716  
717  
    if (eq(uri, "/aiTasks"))
718  
      ret renderBEAObjectTable(req, "AI Task");
719  
720  
    if (eq(uri, "/query"))
721  
      ret calculations.serveQueryPage(req);
722  
      
723  
    if (eq(uri, "/saveInput")) {
724  
      S text = trim(req.get("text"));
725  
      S info = trim(req.get("info"));
726  
      if (empty(text)) ret subBot_serve500("Input empty");
727  
      if (l(text) > maxInputLength) ret subBot_serve500("Input too long");
728  
      BEAObject input = uniqCI BEAObject(type := "Input", +text, createdBy := user(req));
729  
      saveUserAgent(input);
730  
      if (nempty(info))
731  
        uniqCI BEAObject(type := "Input Source", +input, source := info);
732  
      ret hrefresh(or2(req.get("redirect"), baseLink + "/"));
733  
    }
734  
      
735  
    if (eq(uri, "/markUseful")) {
736  
      BEA o = beaGet objectID(req);
737  
      if (o == null) ret subBot_serve500("Object not found");
738  
      uniqCI BEA(type := "Useful", object := o, createdBy := user(req));
739  
      ret hrefresh(or2(req.get("redirect"), baseLink + "/"));
740  
    }
741  
      
742  
    if (eq(uri, "/markBad")) {
743  
      BEA o = beaGet objectID(req);
744  
      if (o == null) ret subBot_serve500("Object not found");
745  
      uniqCI BEA(type := "Bad", object := o, createdBy := user(req));
746  
      ret hrefresh(or2(req.get("redirect"), baseLink + "/"));
747  
    }
748  
      
749  
    if (eq(uri, "/saveAnswer")) {
750  
      S text = trim(req.get("text"));
751  
      S rewriteType = or2(trim(req.get("rewriteType")), "Suggested Answer");
752  
      long inputID = toLong(req.get("inputID"));
753  
      BEAObject input = beaGet(inputID);
754  
      if (input == null) ret subBot_serve500("Input not found");
755  
      if (empty(text)) ret subBot_serve500("Text empty");
756  
      if (l(text) > maxInputLength) ret subBot_serve500("Text too long");
757  
      uniqCI BEAObject(type := "Rewrite", +text, isRewriteOf := input, +rewriteType, createdBy := user(req));
758  
      ret hrefresh(or2(req.get("redirect"), baseLink + "/"));
759  
    }
760  
761  
    if (eq(uri, "/javaSource")) {
762  
      BEA o = beaGet id(req);
763  
      ret serveText(loadTextFile(javaSourceFileForObject(o)));
764  
    }
765  
    
766  
    if (startsWith(uri, "/beaHTML/", m)) {
767  
      req.noSpam();
768  
      BEA o = beaGet(m.rest());
769  
      IF0 result = call_optional(o, "html", req);
770  
      if (result != null) ret result!;
771  
      ret call(o, "html");
772  
    }
773  
    
774  
    // add more public URLs here
775  
      
776  
    if (!inMasterMode(req)) null;
777  
    
778  
    if (eq(uri, "/uploadInputs"))
779  
      ret serveUploadTexts(req, "Input");
780  
    
781  
    if (eq(uri, "/uploadPatterns"))
782  
      ret serveUploadTexts(req, "Pattern");
783  
      
784  
    if (eq(uri, "/analyzeInput"))
785  
      ret calculations.serveAnalyzeInput(req);
786  
      
787  
    if (eq(uri, "/allBEATypes")) {
788  
      ret h2_title("All object types")
789  
        + ul(renderObjectTypes());
790  
    }
791  
    
792  
    if (eq(uri, "/storeMatch")) {
793  
      BEAObject pattern = beaGet(req.get("pattern"));
794  
      BEAObject input = beaGet(req.get("input"));
795  
      S label = req.get("label");
796  
      BEAObject match = calculations.reactInputWithPattern(input, pattern);
797  
      if (match == null) ret "Couldn't match";
798  
      cset(match, +label);
799  
      ret hrefresh(or2(req.get("redirect"), beaObjectURL(match)));
800  
    }
801  
    
802  
    if (eq(uri, "/saveSyntacticPattern") || eq(uri, "/savePattern")) {
803  
      S type = cic(uri, "syntactic") ? "Syntactic Pattern" : "Pattern";
804  
      S text = req.get("text");
805  
      BEAObject fromInput = beaGet(req.get("fromInput"));
806  
      BEAObject pat = uniqCI BEAObject(+type, +text, createdBy := user(req));
807  
      csetIfUnset(pat, +fromInput);
808  
      if (fromInput != null)
809  
        calculations.reactInputWithPattern(fromInput, pat);
810  
      ret hrefresh(or2(req.get("redirect"), baseLink + "/"));
811  
    }
812  
    
813  
    if (eq(uri, "/runInstruction")) {
814  
      BEAObject o = beaGet(req.get("instruction"));
815  
      runInstruction(o);
816  
      ret hrefresh(beaObjectURL(o));
817  
    }
818  
    
819  
    if (eq(uri, "/convertResultToInput")) {
820  
      BEAObject result = beaGet(req.get("result"));
821  
      if (result == null) ret subBot_serve500("Object not found");
822  
      S text = unquote(getString result(result));
823  
      if (l(text) > maxInputLength) ret subBot_serve500("Input too long");
824  
      BEAObject input = uniqCI BEAObject(type := "Input", +text);
825  
      uniqCI BEAObject(type := "Input Source", +input, source := result);
826  
      ret hrefresh(beaShortURL(input));
827  
    }
828  
    
829  
    /*if (eq(uri, "/pipeStringListIntoPattern")) {
830  
      BEA r = beaGet(req.get("resultID"));
831  
      BEa pat = beaGet(req.get("patternID"));
832  
      if (r == null || pat == null) ret "Object not found";
833  
      LS result = assertStringList(cget result(r));
834  
      for (S s : result)
835  
        uniq BEA(type := "Statement", );
836  
    }*/
837  
    
838  
    if (eq(uri, "/setWordType")) {
839  
      BEA r = beaGet(req.get("resultID"));
840  
      S wordType = assertNempty(req.get("wordType"));
841  
      LS result = assertStringList(cget result(r));
842  
      for (S s : result)
843  
        uniqCI BEA(type := "Word type", word := s, +wordType);
844  
      ret "OK";
845  
    }
846  
    
847  
    if (eq(uri, "/reload")) {
848  
      dm_reloadModuleIn(3);
849  
      ret "Reloading module in 3";
850  
    }
851  
    
852  
    if (eq(uri, "/performAutoRuns")) {
853  
      BEA o = beaGet(req.get("onObject"));
854  
      if (o == null) ret "Object not found";
855  
      rstAutoRuns.add(o);
856  
      ret hrefresh(beaURL(o));
857  
    }
858  
    
859  
    if (eq(uri, "/reactAllInputsWithAllSyntacticPatterns")) {
860  
      ret str(returnTimed(r { calculations.reactAllInputsWithAllSyntacticPatterns(); }));
861  
    }
862  
    
863  
    if (eq(uri, "/reactAllInputsWithPattern")) {
864  
      BEA pat = beaGet(req.get("patternID"));
865  
      if (pat == null) ret "Pattern not found";
866  
      ret str(returnTimed(r { calculations.reactAllInputsWithPattern(pat); }));
867  
    }
868  
    
869  
    if (eq(uri, "/storeSubInput")) {
870  
      BEA input = beaGet(req.get("input"));
871  
      if (input == null) ret "Input not found";
872  
      S text = req.get("text");
873  
      S type = eqic(req.get("label"), "good") ? "Sub-Input" : "Bad Sub-Input";
874  
      BEA o = uniqCI BEA(
875  
        +type,
876  
        +input,
877  
        +text,
878  
        createdBy := currentUser());
879  
      ret hrefresh(or2(req.get("redirect"), beaURL(o)));
880  
    }
881  
    
882  
    if (eq(uri, "/performAutoRunOnAllObjects")) {
883  
      BEA autoRun = beaGet autoRun(req);
884  
      performAutoRunOnAllObjects(autoRun);
885  
      ret "OK";
886  
    }
887  
    
888  
    if (eq(uri, "/autoMigrate")) {
889  
      BEA o = beaGet id(req);
890  
      if (o == null) ret "Object not found";
891  
      S url = beaURL(o);
892  
      ret hsansserif() + "Migrated " + beaHTML(o) + " to " + className(autoMigrateToCustomClass(o))
893  
        + hrefresh(1.0, url);
894  
    }
895  
      
896  
    if (eq(uri, "/migrateToBase")) {
897  
      BEA o = beaGet id(req);
898  
      if (o == null) ret "Object not found";
899  
      S url = beaURL(o);
900  
      ret hsansserif() + "Migrated " + beaHTML(o) + " to " + className(autoMigrateToBase(o))
901  
        + hrefresh(1.0, url);
902  
    }
903  
      
904  
    if (eq(uri, "/convertSyntacticToSemanticMatches")) {
905  
      BEA match = beaGet matchID(req);
906  
      if (match == null) ret "Match not found";
907  
      ret ul_htmlEncode2(calculations.convertSyntacticToSemanticMatches(match));
908  
    }
909  
    
910  
    if (eq(uri, "/convertSyntacticToSemanticMatchesForWholePattern")) {
911  
      BEA pat = beaGet patternID(req);
912  
      if (pat == null) ret "Pattern not found";
913  
      ret ul_htmlEncode2(calculations.convertSyntacticToSemanticMatchesForWholePattern(pat));
914  
    }
915  
    
916  
    if (eq(uri, "/createPatternListFromUsefulSyntacticPatterns"))
917  
      ret hrefresh(beaURL(calc.createPatternListFromUsefulSyntacticPatterns()));
918  
      
919  
    if (eq(uri, "/createConceptShadows"))
920  
      ret createConceptShadows();
921  
922  
    if (eq(uri, "/compareConceptShadows")) {
923  
      if (conceptShadows == null) ret createConceptShadows();
924  
      L<ConceptShadow> newShadows = allConceptShadows();
925  
      L<CreatedDeletedChanged<ConceptShadow>> diff
926  
        = diffConceptShadows(conceptShadows, newShadows);
927  
      ret subBot_serveText(nDiffs(diff) + ":\n\n"
928  
        + pnlToString(diff));
929  
    }
930  
931  
    if (eq(uri, "/includeScript")) {
932  
      S snippetID = req.get("id");
933  
      O wired = hotwire(snippetID);
934  
      ret "Wired: " + wired;
935  
    }
936  
    
937  
    if (eq(uri, "/activateDynamicObject")) {
938  
      BEA o = beaGet id(req);
939  
      if (o == null) ret "Object not found";
940  
      activateDynamicObject(o);
941  
      o = beaGet id(req);
942  
      S url = beaURL(o);
943  
      ret hsansserif() + "Migrated " + beaHTML(o) + " to " + className(o)
944  
        + hrefresh(1.0, url);
945  
    }
946  
    
947  
    if (eq(uri, "/callAnyMethod")) {
948  
      BEA o = beaGet id(req);
949  
      if (o == null) ret "Object not found";
950  
      S name = req.get("name");
951  
      bool showPrints = eq("1", req.get("showPrints"));
952  
953  
      new L args;
954  
      for (S key, val : req.params()) {
955  
        int idx = parseIntOpt(regexpExtractGroup("^conceptArg(\\d+)$", key));
956  
        if (idx > 0)
957  
          listSet(args, idx-1, getConcept(parseLong(val)));
958  
      }
959  
      
960  
      S arg = req.get("arg");
961  
      if (arg != null) listSet(args, 0, arg);
962  
      
963  
      S result = hijackPrintPlusResult_text(() -> call(o, name, toObjectArray(args)));
964  
      ret serveText("Result of " + o + " . " + name + "(" + joinWithComma(args) + "):\n" + result);
965  
    }
966  
    
967  
    if (eq(uri, "/download"))
968  
      ret subBot_serveFileWithName("gazelle-database." + ymd_minus_hms() + ".gz", conceptsFile());
969  
    
970  
    // add more master-mode URLs here
971  
  } // end of serveOtherPage2
972  
  
973  
  transient L<ConceptShadow> conceptShadows;
974  
975  
  O createConceptShadows() {  
976  
    time "Make shadows" {
977  
      S profile = profileThisThreadToString(r {
978  
        conceptShadows = allConceptShadows();
979  
      });
980  
    }
981  
    ret subBot_serveText(n2(conceptShadows, "shadow") + " made in " + lastTiming_formatted() + "\n\n" + profile);
982  
  }
983  
  
984  
  HCRUD makeBEAObjectCRUD(Req req, S type) {
985  
    HCRUD crud = makeCRUD(BEAObject, req);
986  
    crud.baseLink = req.uri();
987  
    HCRUD_Concepts data = cast crud.data;
988  
    data.itemName = () -> firstToUpper(type);
989  
    data.addCIFilter(type := eqic(type, "(no type)") ? null : type);
990  
    
991  
    if (eqicOneOf(type, "Input", "Pattern", "AI Task")) {
992  
      IF0<MapSO> prev = data.emptyObject;
993  
      data.emptyObject = () -> {
994  
        MapSO item = data.emptyObject_fallback(prev);
995  
        item.put(text := ""); // show text field when creating new objects
996  
        ret item;
997  
      };
998  
    }
999  
    ret crud;
1000  
  }
1001  
  
1002  
  O renderBEAObjectTable(Req req, S type) {
1003  
    HCRUD crud = makeBEAObjectCRUD(req, type);
1004  
    ret serveCRUD(req, BEAObject, crud);
1005  
  }
1006  
  
1007  
  O serveUploadTexts(Req req, S type) {
1008  
    S inputs = req.get("text");
1009  
    
1010  
    new LS output;
1011  
    
1012  
    if (nempty(inputs)) {
1013  
      for (S text : tlft(inputs)) {
1014  
        Pair<BEAObject, Bool> p = uniqCI2_sync BEAObject(+type, +text);
1015  
        if (cget uploadedBy(p.a) == null)
1016  
          cset(p.a, uploadedBy := req.auth.user);
1017  
        output.add(type + " " + (p.b ? "added" : "exists")
1018  
          + " (ID " + p.a.id + "): " + text);
1019  
      }
1020  
    }
1021  
    
1022  
    ret h2("Upload " + plural(type))
1023  
      + hpostform(
1024  
          p(plural(type) + " (one per line):")
1025  
        + p(htextarea(inputs, name := "text"))
1026  
        + pIfNempty(htmlEncode_nlToBR(lines(output)))
1027  
        + hsubmit("Upload " + plural(type)));
1028  
  }
1029  
  
1030  
  Cl<BEAObject> beaObjectsOfType(S type) {
1031  
    ret conceptsWhereCI BEAObject(+type);
1032  
  }
1033  
  
1034  
  void reactAllInputsWithSomePatterns {
1035  
    calculations.reactAllInputsWithSomePatterns();
1036  
  }
1037  
  
1038  
  S navDiv() {
1039  
    HCRUD crud = makeCRUD(BEAObject, currentReq!);
1040  
1041  
    long time = sysNow();
1042  
    int inputsWithoutRewrites = this.inputsWithoutRewrites!;
1043  
    int inputsWithoutMatches = this.inputsWithoutMatches!;
1044  
    int syntacticPatternsWithoutRewrites = this.syntacticPatternsWithoutRewrites!;
1045  
    /*int inputsWithoutRewrites = 0;
1046  
    int inputsWithoutMatches = 0;
1047  
    int syntacticPatternsWithoutRewrites = 0;*/
1048  
    done2_always("Count Things", time);
1049  
    
1050  
    ret joinNemptiesWithVBar(
1051  
      ahref(baseLink + "/query", "Query"),
1052  
      beaNavLink("Input", crud),
1053  
      beaNavLink("Pattern", crud),
1054  
      beaNavLink("Syntactic Pattern", crud),
1055  
      ahref(baseLink + "/syntacticPatternsWithoutRewrites", n2(syntacticPatternsWithoutRewrites) + " Syntactic patterns w/o rewrites"),
1056  
      beaNavLink("Match", crud),
1057  
      beaNavLink("Rewrite", crud),
1058  
      beaNavLink("AI Task", crud),
1059  
      ahref(baseLink + "/inputsWithoutMatches", n2(inputsWithoutMatches) + " Inputs w/o matches"),
1060  
      ahref(baseLink + "/inputsWithoutRewrites", n2(inputsWithoutRewrites) + " Inputs w/o rewrites"),
1061  
      hPopDownButtonWithText("Bot Forum", navLinks(flat := true, withStats := false)),
1062  
      HTMLPopDownButton(
1063  
        ahref(baseLink + "/allBEATypes", "All object types")
1064  
          + " " + hPopDownButton(renderObjectTypes()),
1065  
        ahref(baseLink + "/stats", "Stats"),
1066  
        !isMasterAuthed() ? null : ahref(baseLink + "/download", "DB download"),
1067  
        !isMasterAuthed() ? null : ahref(baseLink + "/refchecker", "Reference checker"),
1068  
        ahref(baseLink + "/inputsWithRewrites", "Inputs with rewrites"),
1069  
        ahref(baseLink + "/rewritesTable", "Rewrites table"),
1070  
        ahref(baseLink + "/patternRewritesTable", "Pattern rewrites table"),
1071  
        ahref(baseLink + "/matchesTable", "Matches table"),
1072  
        ahref(baseLink + "/matchesTable?syntacticOnly=1", "Syntactic matches table"),
1073  
        ahref("https://gazelle.rocks/htmlBot/238410", "Classic Gazelle"),
1074  
      ).width(350).height(500).html());
1075  
  }
1076  
  
1077  
  // crud is just the cached BEAObject crud to check for creation rights
1078  
  S beaNavLink(S type, HCRUD crud, int count default beaCount(type)) {
1079  
    S plural = firstToLower(plural(type));
1080  
    S link = baseLink + "/" + camelCase(plural);
1081  
    
1082  
    ret ahref(link, n2(count) + " " + firstToUpper(plural)) + (!crud.actuallyAllowCreate() ? "" : " " + ahref(addParamToURL(link, cmd := "new"), "+"));
1083  
  }
1084  
  
1085  
  S beaObjectURL(BEAObject o) {
1086  
    ret conceptLink(o, currentReq!);
1087  
    /*ret o == null ?:
1088  
      addParamsToURL(baseLink + "/crud/BEAObject",
1089  
        selectObj := o.id) + "#" + o.id;*/
1090  
  }
1091  
  
1092  
  S matchDescHTML(BEAObject m) {
1093  
    pcall {
1094  
      BEAObject pat = cget pattern(m);
1095  
      SS mapping = cast cget mapping(m);
1096  
      ret ahref_undecorated(crudLink(m), htmlEncode2(quote(getString text(pat)))
1097  
        + "<br>&nbsp; with " + renderEqualsCommaProperties(mapping));
1098  
    }
1099  
    ret htmlEncode2(str(m));
1100  
  }
1101  
  
1102  
  int beaCount(S type) {
1103  
    ret countConceptsWhereCI BEAObject(+type);
1104  
  }
1105  
  
1106  
  Cl<BEA> beaList() {
1107  
    ret list BEA();
1108  
  }
1109  
  
1110  
  Cl<BEAObject> beaList(S type, O... params) {
1111  
    ret conceptsWhereCI BEAObject(paramsPlus_inFront(params, +type));
1112  
  }
1113  
  
1114  
  Cl<BEAObject> beaListAny(S... types) {
1115  
    ret concatLists(lmap beaList(litciset(types)));
1116  
  }
1117  
  
1118  
  BEA beaGet(long id) {
1119  
    ret getConceptOpt BEAObject(id);
1120  
  }
1121  
  
1122  
  BEA beaGet(S id) {
1123  
    ret beaGet(parseFirstLong(id));
1124  
  }
1125  
  
1126  
  // first param can be type
1127  
  BEA beaNew(O... _) {
1128  
    _ = prependParamIfOddCount("type", _);
1129  
    ret cnew BEA(_);
1130  
  }
1131  
  
1132  
  bool beaTypeIs(BEA o, S type) {
1133  
    ret o != null && o.typeIs(type);
1134  
  }
1135  
  
1136  
  BEA mapMethodLike beaGet(S key, Req req) {
1137  
    ret beaGet(req.get(key));
1138  
  }
1139  
1140  
  BEA mapMethodLike cgetBEA aka beaGet(S field, BEA o) {
1141  
    ret (BEA) cget(field, o);
1142  
  }
1143  
  
1144  
  BEAObject cgetBEA aka beaGet(BEAObject o, S field) {
1145  
    ret cgetBEA(field, o);
1146  
  }
1147  
1148  
  S beaLinkHTML aka beaToHTML aka beaHTML(BEAObject o) {  
1149  
    ret o == null ?: ahref(conceptLink(o), htmlEncode2_nlToBr(str(o)));
1150  
  }
1151  
  
1152  
  S beaHTML_justID(BEA o) { ret o == null ?: ahref(beaShortURL(o), o.id); }
1153  
  
1154  
  S beaShortURL aka beaURL(BEAObject o) {
1155  
    ret o == null ?: baseLink + "/" + o.id;
1156  
  }
1157  
1158  
  Cl<BEAObject> beaBackRefs(BEAObject o, S type) {
1159  
    ret objectsWhereCI(findBackRefs BEAObject(o), +type);
1160  
  }
1161  
  
1162  
  Cl<BEAObject> beaBackRefs(BEAObject o) {
1163  
    ret findBackRefs BEAObject(o);
1164  
  }
1165  
  
1166  
  O serveDefaultPage(Req req) {
1167  
    HTMLFramer1 framer = req.framer;
1168  
    framer.add(hcenter3(hsnippetimg_scaleToWidth(200, #1102967, 200, 110, title := "Gazelle"), style := "margin-top: 100px"));
1169  
    ret completeFrame(req);
1170  
  }
1171  
  
1172  
  S html_loggedIn() {
1173  
    User user = user(currentReq!);
1174  
    ret user == null
1175  
      ? /*"Not logged in"*/ ahref(baseLink + "/", "Log in")
1176  
      : "Logged in as " + htmlEncode2(user.name);
1177  
  }
1178  
  
1179  
  void distributeNewObject_impl(BEAObject o) {
1180  
    if (o.typeIs("Match")) ret;
1181  
    distributeNotification("New object: " + o);
1182  
  }
1183  
  
1184  
  void performAutoRuns(BEAObject o) enter {
1185  
    print("performAutoRuns", o);
1186  
    
1187  
    for (BEAObject autoRun : beaList("Auto Run")) {
1188  
      if (!isTrue(getOpt enabled(autoRun)))
1189  
        continue with print("Not enabled: " + autoRun);
1190  
      performAutoRunOnObject(autoRun, o);
1191  
    }
1192  
  }
1193  
  
1194  
  void performAutoRunOnAllObjects(BEA autoRun) {
1195  
    for (BEA o : list(BEA))
1196  
      performAutoRunOnObject(autoRun, o);
1197  
  }
1198  
  
1199  
  void performAutoRunOnObject(BEA autoRun, BEA o) {
1200  
    ping();
1201  
    S type = getString onChangedObjectOfType(autoRun);
1202  
    if (!o.typeIs(type)) ret; // with print("Wrong type: " + type);
1203  
    
1204  
    print("Running " + autoRun);
1205  
    BEAObject procedure = cast cget procedure(autoRun);
1206  
    
1207  
    S internalCode = getString internalCode(procedure);
1208  
    printVars_str(+internalCode, +o);
1209  
    
1210  
    if (eqic(internalCode, "convertInputToPattern")) {
1211  
      S text = o.text();
1212  
      if (!containsAngleBracketVars(text)) ret with print("No angle bracket vars");
1213  
      BEAObject p = uniqCI_returnIfNew BEAObject(type := "Pattern", +text);
1214  
      cset(p, fromInput := o, byProcedure := procedure, byAutoRun := autoRun);
1215  
      print(+p);
1216  
    } else if (eqic(internalCode, "convertInputToSyntacticPattern")) {
1217  
      S text = o.text();
1218  
      if (!containsStars(text)) ret with print("No stars");
1219  
      BEAObject p = uniqCI_returnIfNew BEAObject(type := "Syntactic Pattern", +text);
1220  
      cset(p, fromInput := o, byProcedure := procedure, byAutoRun := autoRun);
1221  
      print(+p);
1222  
    } else if (eqic(internalCode, "dropPunctuationFromPattern")) {
1223  
      S text = o.text();
1224  
      S text2 = dropPunctuation(text);
1225  
      if (eq(text, text2)) ret;
1226  
      
1227  
      BEAObject p = uniqCI BEA(
1228  
        type := o.type(),
1229  
        text := text2);
1230  
      cset(o, withoutPunctuation := p);
1231  
    } else if (eqic(internalCode, "makeSyntacticPattern")) {
1232  
      print(sp := calculations.makeSyntacticPattern(o));
1233  
    } else if (eqic(internalCode, "runFunctionOnInput")) {
1234  
      print("runFunctionOnInput");
1235  
      BEA function = beaGet(o, "function");
1236  
      BEA input = beaGet(o, "input");
1237  
      if (function == null || input == null) ret with print("Missing parameters");
1238  
      if (cget result(o) != null) ret with print("Has result");
1239  
1240  
      BEA result = calculations.reactFunctionWithInput(calculations.new BackEndAlgorithm, function, input);
1241  
      print(+result);
1242  
      if (result != null) {
1243  
        cset(result, request := o);
1244  
        cset(o, +result);
1245  
      }
1246  
    } else
1247  
      print("Unknown internal code");
1248  
  }
1249  
1250  
  BEAObject findInput(S text) {
1251  
    ret conceptWhereIC(BEAObject, type := "Input", +text);
1252  
  }
1253  
  
1254  
  S addRewriteHTML(BEAObject o) {
1255  
    ret ahref(addParamsToURL(crudLink(BEAObject),
1256  
      cmd := "new",
1257  
      title := "Add Rewrite",
1258  
      f_type := "Rewrite",
1259  
      f_text := getStringOpt text(o),
1260  
      f_isRewriteOf := o.id, metaInfo_isRewriteOf := "concept",
1261  
    ), "Add Rewrite");
1262  
  }
1263  
  
1264  
  O serveIntegerLink(Req req, long id) {
1265  
    BEAObject o = getConceptOpt BEAObject(id);
1266  
    if (o != null)
1267  
      ret htitle(str(o)) + hrefresh(conceptLink(o));
1268  
    ret super.serveIntegerLink(req, id);
1269  
  }
1270  
  
1271  
  void distributeTestNotification() {
1272  
    distributeNotification("It is " + localTimeWithSeconds());
1273  
  }
1274  
  
1275  
  void distributeNotification(S text) {
1276  
    notificationQ.add(r {
1277  
      /*for (User user)
1278  
        if (nemptyAfterTrim(user.notificationSetting))
1279  
          sendNotification(text);*/
1280  
          
1281  
      for (Pair<virtual WebSocket, WebSocketInfo> p : syncMapToPairs(webSockets)) {
1282  
        // TODO: check user
1283  
        S jsCode =
1284  
          "window.createNotification({ theme: 'success', showDuration: 3000 })("
1285  
          + jsonEncodeMap(message := text) + ");";
1286  
        call(p.a, "send", jsonEncodeMap(eval := jsCode));
1287  
      }
1288  
    });
1289  
  }
1290  
  
1291  
  void runInstruction(BEAObject o) {
1292  
    if (o == null) ret;
1293  
    try {
1294  
      BEAObject instruction = o;
1295  
      if (o.typeIs("Step in script"))
1296  
        instruction = (BEAObject) cget(o, "instruction");
1297  
      
1298  
      if (instruction.typeIs("Instruction | List objects by type")) {
1299  
        saveInstructionResult(o, beaList(getString typeToList(instruction)));
1300  
        ret;
1301  
      }
1302  
      
1303  
      if (instruction.typeIs("Instruction | List object types"))
1304  
        ret with saveInstructionResult(o, distinctCIFieldValuesOfConcepts(BEAObject, "type"));
1305  
1306  
      if (instruction.typeIs("Instruction | Filter list by text starting with")) {
1307  
        // find list made before
1308  
        BEAObject scriptRun = cgetBEA scriptRun(o);
1309  
        if (scriptRun == null) fail("Need to be run as part of script");
1310  
        L<BEAObject> steps = scriptRunSteps(scriptRun);
1311  
        int idx = indexOf(steps, o);
1312  
        if (idx < 0) fail("Step not found in script run");
1313  
        
1314  
        L<BEAObject> list = firstNotNull(map(reversed(takeFirst(steps, idx)),
1315  
          step -> optCast L(cget data(cgetBEA result(step)))));
1316  
         
1317  
        S prefix = getString prefix(instruction);
1318  
        L<BEAObject> filtered = filter(list, obj -> swic(obj.text(), prefix));
1319  
        saveInstructionResult(o, filtered);
1320  
        ret;
1321  
      }
1322  
      
1323  
      if (instruction.typeIs("Script")) {
1324  
        BEAObject script = instruction;
1325  
        BEAObject scriptRun = cnew BEAObject(type := "Script Run", +script);
1326  
        
1327  
        // Make an instance of all the instructions
1328  
        
1329  
        int i = 0;
1330  
        new L<BEAObject> steps;
1331  
        while not null (instruction = (BEAObject) cget(instruction, "step" + (++i))) {
1332  
          BEAObject step = cnew(BEAObject, type := "Step in script", step := i, +scriptRun, +instruction);
1333  
          steps.add(step);
1334  
        }
1335  
        
1336  
        cset(scriptRun, +steps);
1337  
        
1338  
        // TODO: run steps?
1339  
1340  
        ret;
1341  
      }
1342  
      
1343  
      cnew BEAObject(type := "Instruction Error", instruction := o, error := "Unknown instruction type");
1344  
    } catch e {
1345  
      cnew BEAObject(type := "Instruction Error", instruction := o, error := getStackTrace(e));
1346  
    }
1347  
  }
1348  
1349  
  BEAObject saveInstructionResult(BEAObject instruction, O data) {
1350  
    BEAObject result = cnew BEAObject(type := "Instruction Result",
1351  
      +instruction, +data);
1352  
    cset(instruction, +result);
1353  
    ret result;
1354  
  }
1355  
  
1356  
  L<BEAObject> scriptRunSteps(BEAObject scriptRun) {
1357  
    ret (L) cget steps(scriptRun);
1358  
  }
1359  
  
1360  
  S addCommentHTML(BEA o, O... _) {
1361  
    optPar S redirectAfterSave;
1362  
    optPar S defaultComment;
1363  
    optPar S text = "Add comment";
1364  
    
1365  
    ret ahref(addParamsToURL(crudLink(BEAObject),
1366  
      cmd := "new",
1367  
      title := "Add Comment",
1368  
      f_type := "Comment",
1369  
      f_on := o.id,
1370  
      f_text := unnull(defaultComment),
1371  
      +redirectAfterSave,
1372  
      autofocus := "f_text",
1373  
      metaInfo_on := "concept"), text);
1374  
  }
1375  
  
1376  
  S formatSubInput(BEA input, S text, S anchor) {
1377  
    S redirect = addAnchorToURL(currentReq->uriWithParams(), anchor);
1378  
    int goodCount = countConceptsCI BEA(type := "Sub-Input", +input, +text);
1379  
    int badCount = countConceptsCI BEA(type := "Bad Sub-Input", +input, +text);
1380  
    ret calculations.bestInputHTML(text)
1381  
      + " " + small(joinNemptiesWithSpace(
1382  
        ahref(addParamsToURL(
1383  
          baseLink + "/storeSubInput", 
1384  
          label := "good",
1385  
          +text,
1386  
          input := input.id,
1387  
          +redirect),
1388  
        unicode_thumbsUp()),
1389  
        goodCount == 0 ? "" : n2(goodCount),
1390  
        ahref(addParamsToURL(
1391  
          baseLink + "/storeSubInput", 
1392  
          label := "bad",
1393  
          +text,
1394  
          input := input.id,
1395  
          +redirect),
1396  
        unicode_thumbsDown()),
1397  
        badCount == 0 ? "" : n2(badCount)
1398  
      ));
1399  
  }
1400  
1401  
  LS renderObjectTypes() {
1402  
    MultiSet<S> ms = distinctCIFieldValuesOfConcepts_multiSet(BEAObject, "type");
1403  
    ret mapPairs(multiSetToPairsByPopularity(ms),
1404  
      (type, count) -> {
1405  
        S _type = or2(type, "(no type)");
1406  
        ret n2(count) + " " + ahref(baseLink + "/beaCRUD/" + urlencode(_type), htmlEncode2(_type));
1407  
      });
1408  
  }
1409  
  
1410  
  BEA autoMigrateToBase(BEA o) {
1411  
    ret autoMigrateToClass(o, BEA);
1412  
  }
1413  
  
1414  
  BEA autoMigrateToCustomClass(BEA o) {
1415  
    ret autoMigrateToClass(o, defaultCustomClass(o));
1416  
  }
1417  
  
1418  
  // accepting Concept here to allow for fixes after broken unstructuring
1419  
  // (a problem we will probably never have again)
1420  
  BEA autoMigrateToClass(Concept o, Class<? extends BEAObject> targetClass) {
1421  
    pcall {
1422  
      if (o == null || o._concepts != db_mainConcepts()) null;
1423  
      if (targetClass != null && targetClass != _getClass(o))
1424  
        ret replaceConceptAndUpdateRefs(o, unlistedCopyToClass_withConverter(targetClass, o));
1425  
    }
1426  
    ret (BEA) o;
1427  
  }
1428  
1429  
  void setCodeState(BEA o, long timestamp, S codeHash, O state) {
1430  
    if (empty(state)) state = null; else
1431  
      state = "[" + formatGMTWithMilliseconds_24(timestamp) + "] "
1432  
        + (empty(codeHash) ? "" : "Code hash: " + codeHash + ". ")
1433  
        + state;
1434  
    cset(o, meta_codeState := state);
1435  
  }
1436  
1437  
  S codeForObject(BEA o) {
1438  
    ret getString meta_code(o);
1439  
  }
1440  
  
1441  
  void activateDynamicObject(BEA o) ctex {
1442  
    ClassLoader cl = dm_moduleClassLoader();
1443  
    print(+cl);
1444  
1445  
    long timestamp = now();
1446  
    setCodeState(o, timestamp, null, "Compiling");
1447  
1448  
    S codeHash = null;
1449  
    transpileAndCompileForHotwiring_src.set(null);
1450  
1451  
    // TODO: there is still a slight possibility that erroneous code will be compiled again and again
1452  
1453  
    try {
1454  
      // Check meta_code and meta_prototype (latter overwrites the former)
1455  
      BEA proto = cget meta_prototype(o);
1456  
      S code = codeForObject(o);
1457  
      
1458  
      Class protoClass = null;
1459  
      if (proto != null) {
1460  
        if (!isActivatedDynamicObject(proto))
1461  
          fail("Prototype not activated: " + proto);
1462  
        protoClass = proto.getClass();
1463  
      }
1464  
      
1465  
      codeHash = empty(code) ? null : md5(code);
1466  
      cset(o, meta_codeHash := codeHash);
1467  
  
1468  
      if (empty(code)) {
1469  
        if (protoClass != null) {
1470  
          // no extra code, just instantiate prototype class
1471  
          o = autoMigrateToClass(o, protoClass);
1472  
          setCodeState(o, timestamp, null, "Migrated to proto class " + shortClassName(protoClass));
1473  
        } else {
1474  
          // Nothing to activate - migrate back to base
1475  
          o = autoMigrateToBase(o);
1476  
          setCodeState(o, timestamp, null, null);
1477  
        }
1478  
        ret;
1479  
      }
1480  
      
1481  
      // safety check for reference (not currently used, we just check for master user status)
1482  
      cset(o, meta_codeSafety := null/*codeSafetyCheckResult(code)*/);
1483  
1484  
      S randomID = aGlobalID();
1485  
      S id = makeJavaClassName(o, randomID);
1486  
      S mcName = makePackageName(o, randomID);
1487  
      cset(o, meta_javaClass := mcName + "." + id);
1488  
      
1489  
      S src = 
1490  
        "mainClassName " + mcName + "\n"
1491  
        + "concept " + id + " extends " +
1492  
          (protoClass == null ? "BEAObject" : protoClass.getName().replace("$", "."))
1493  
        + " {\n" + code + "\n}\n"
1494  
        + customCodePostlude();
1495  
      
1496  
      print("SRC> ", src);
1497  
      var files = filesFromClassLoader(cl);
1498  
      
1499  
      print("Compiling with path:");
1500  
      pnlIndent(files);
1501  
      
1502  
      javaCompileToJar_localLibraries.set(files);
1503  
      dm_mediumRefreshTranspiler();
1504  
      File bytecode = transpileAndCompileForHotwiring(src);
1505  
      saveTextFile(javaSourceFileForObject(o), transpileAndCompileForHotwiring_src!);
1506  
      copyFile(bytecode, byteCodeFileForObject(o, id));
1507  
      
1508  
      cset(o, meta_javaClass := mcName + "." + id);
1509  
      var p = reactivateDynamicObject_impl(o);
1510  
      o = p.a;
1511  
      setCodeState(o, timestamp, codeHash, "Custom code loaded");
1512  
      
1513  
      // migrate derivatives to new class
1514  
      // (only those who don't add any code are included right now)
1515  
      for (BEA derivative : directDerivatives(o)) pcall {
1516  
        print("Migrating derivative " + derivative + " of " + o + " to new base class " + o.getClass());
1517  
        autoMigrateToClass(derivative, o.getClass());
1518  
      }
1519  
1520  
    } catch print e {
1521  
      cset(o, meta_javaClass := null);
1522  
      setCodeState(o, timestamp, codeHash, exceptionToStringShort(e));
1523  
    }
1524  
  }
1525  
  
1526  
  bool basedOnUnactivatedPrototype(BEA o) {
1527  
    BEA proto = optCast BEA(cget meta_prototype(o));
1528  
    ret proto != null && !isActivatedDynamicObject(proto);
1529  
  }
1530  
  
1531  
  Cl<BEA> directDerivatives(BEA o) {
1532  
    ret transitiveHull(x -> filter(
1533  
      conceptsWhere BEA(meta_prototype := x),
1534  
      d -> empty(codeForObject(d))), o);
1535  
  }
1536  
  
1537  
  bool reactivateDynamicObject(BEA o) {
1538  
    try {
1539  
      ret reactivateDynamicObject_impl(o).b;
1540  
    } catch print e {
1541  
      cset(o, meta_javaClass := null);
1542  
      cset(o, meta_codeState := exceptionToStringShort(e));
1543  
      false;
1544  
    }
1545  
  }
1546  
  
1547  
  bool isActivatedDynamicObject(BEA o) {
1548  
    ret startsWith(className(o), packagePrefix());
1549  
  }
1550  
  
1551  
  Pair<BEA, Bool> reactivateDynamicObject_impl(BEA o) ctex {
1552  
    S id = getString meta_javaClass(o);
1553  
    if (empty(id)) {
1554  
      cset(o, meta_codeState := null);
1555  
      ret pair(o, false);
1556  
    }
1557  
    File bytecode = byteCodeFileForObject(o, shortenClassName(id));
1558  
    dm_addByteCodePathToModuleClassLoader(bytecode);
1559  
    S mcName = makePackageName(o, id);
1560  
    int idx = lastIndexOf(id, '.');
1561  
    S fullName = takeFirst(id, idx)/*.replace(".", "/")*/
1562  
      + substring(id, idx).replace(".", "$");
1563  
1564  
    //Class targetClass = _getClass(fullName);
1565  
    ClassLoader cl = dm_moduleClassLoader();
1566  
    Class targetClass = cl.loadClass(fullName);
1567  
    print(+targetClass);
1568  
    assertNotNull("Class not found: " + fullName, targetClass);
1569  
    o = autoMigrateToClass(o, targetClass);
1570  
1571  
    cset(o, meta_codeState := "[" + formatGMTWithMilliseconds_24() + "] " + "Custom code reloaded");
1572  
    ret pair(o, true);
1573  
  }
1574  
1575  
  File javaSourceFileForObject(BEA o) {
1576  
    ret programFile("BEA Java Sources/" + o.id + ".java");
1577  
  }
1578  
  
1579  
  File byteCodeFileForObject(BEA o, S javaClassName
1580  
    default getString meta_javaClass(o)) {
1581  
    if (empty(javaClassName)) null;
1582  
    ret programFile("Object ByteCode/" + o.id + "-" + javaClassName + ".jar");
1583  
  }
1584  
  
1585  
  BEA autoMigrateUnlistedOrKeep(BEA o) {
1586  
    ret canAutoMigrate(o) ? unlistedCopyToClass_withConverter(defaultCustomClass(o), o) : o;
1587  
  }
1588  
  
1589  
  bool canAutoMigrate(BEA o) {
1590  
    ret o != null && !eqOneOf(defaultCustomClass(o), _getClass(o), null);
1591  
  }
1592  
  
1593  
  Class<? extends BEA> defaultCustomClass(BEA o) {
1594  
    if (o == null) null;
1595  
    BEA entry = conceptWhereCI BEA(type := "Auto Custom Class", forType := o.type());
1596  
    //printVars_str defaultCustomClass(+o, +entry);
1597  
    if (entry == null) null;
1598  
    S className = getString toClassName(entry);
1599  
    //printVars_str defaultCustomClass(+className);
1600  
    Class c = findClassThroughDefaultClassFinder(className);
1601  
    //printVars_str defaultCustomClass(+c);
1602  
    ret c;
1603  
  }
1604  
  
1605  
  S queryLink(S algorithm, S q) {
1606  
    ret addParamsToURL(baseLink + "/query", +algorithm, +q);
1607  
  }
1608  
1609  
  S currentUserAgent() {  
1610  
    Req req = currentReq!;
1611  
    if (req == null) null;
1612  
    ret mapGet(req.webRequest.headers(), "user-agent");
1613  
  }
1614  
1615  
  void saveUserAgent(BEA input) {  
1616  
    S userAgent = currentUserAgent();
1617  
    if (nempty(userAgent))
1618  
      uniqCI2 BEA(type := "Input Source",  +input, +userAgent);
1619  
  }
1620  
1621  
  bool isObjectWithCode(BEA o) {
1622  
    ret o != null && (cget meta_code(o) != null || cget meta_prototype(o) != null);
1623  
  }
1624  
1625  
  bool createdByMasterUser(BEA o) {
1626  
    User user = optCast User(cget createdBy(o));
1627  
    ret user != null && user.isMaster;
1628  
  }
1629  
1630  
  void autoActivateDynamicObject(BEA o) {
1631  
    if (!autoActivateDynamicObjects) ret;
1632  
    S code = codeForObject(o);
1633  
    if (empty(code)) ret;
1634  
    if (!createdByMasterUser(o)) ret;
1635  
    S codeState = getString meta_codeState(o);
1636  
    S time = leadingAngleBracketStuff(codeState);
1637  
    long timestamp = empty(time) ? 0 : parseDateWithMillisecondsGMT(time);
1638  
    if (o._modified <= timestamp) ret;
1639  
    //S hash = regexpExtractIC("code hash: (\\w+)?", codeState);
1640  
    S hash = getString meta_codeHash(o);
1641  
    if (eq(hash, md5(code)))
1642  
      ret; // Code unchanged
1643  
    print("Auto-activating dynamic object: " + o);
1644  
    activateDynamicObject(o);
1645  
    sleepSeconds(1); // safety sleep
1646  
  }
1647  
1648  
  S customCodePostlude() {  
1649  
    ret "!include early #1031282\n\n";
1650  
  }
1651  
  
1652  
  S makeJavaClassName(BEA o, S randomID) {
1653  
    ret "B_" + o.id;
1654  
  }
1655  
  
1656  
  S packagePrefix() {
1657  
    ret "dyn.b_";
1658  
  }
1659  
  
1660  
  S makePackageName(BEA o, S randomID) {
1661  
    ret packagePrefix() + o.id + "." + randomID;
1662  
  }
1663  
  
1664  
  BEA websiteEnhancersObject() {
1665  
    Cl<BEA> l = beaList("Live Website Enhancers");
1666  
    if (l(l) > 1) warn("Multiple Live Website Enhancers: " + l);
1667  
    ret first(l);
1668  
  }
1669  
  
1670  
  BEA getWebsiteEnhancer(S key) {
1671  
    ret beaGet(websiteEnhancersObject(), key);
1672  
  }
1673  
} // end of module
1674  
1675  
extend User {
1676  
  S notificationSetting;
1677  
}
1678  
1679  
concept BEAObject > ConceptWithGlobalID {
1680  
  // optional new Ref<UserPost> mirrorPost;
1681  
  UserPost mirrorPost() { ret (UserPost) cget mirrorPost(this); }
1682  
1683  
  void change :: after {
1684  
    var mod = beaMod();
1685  
    mod.rstUpdateBEAMirrors.add(this);
1686  
    if (mod.autoActivateDynamicObjects)
1687  
      mod.rstAutoActivateDynamicObjects.add(this);
1688  
  }
1689  
1690  
  void delete :: before {
1691  
    cdelete(mirrorPost());
1692  
  }
1693  
  
1694  
  void updateMirrorPost {
1695  
    GazelleBEA mod = beaMod();
1696  
    if (isDeleted() || !mod.mirrorBEAObjects) ret;
1697  
1698  
    if (mirrorPost() == null)
1699  
      cset(this, mirrorPost := cnew UserPost(
1700  
        type := "BEA Object",
1701  
        creator := mod.internalUser(),
1702  
        botInfo := "BEA Mirror Bot"));
1703  
1704  
    S text = structureString();
1705  
1706  
    cset(mirrorPost(), 
1707  
      title := str(this),
1708  
      +text);
1709  
  }
1710  
1711  
  S structureString() {
1712  
    S text = "Error";
1713  
    pcall {
1714  
      structure_Data data = new {
1715  
        structure_ClassInfo newClass(Class c) {
1716  
          structure_ClassInfo info = super.newClass(c);
1717  
          if (c == Concept.Ref.class) {
1718  
            info.special = true;
1719  
            info.serializeObject = o -> {
1720  
              Concept cc = cast deref((Concept.Ref) o);
1721  
              //append("cu CRef " + (cc != null ? str(cc.id) : "null"), 3);
1722  
              if (cc cast BEAObject)
1723  
                append("CRef(gid=" + quote(cc.globalID()) + ")", 6);
1724  
              else if (cc != null)
1725  
                append("CRef(id=" + cc.id + ")", 6);
1726  
              else
1727  
                append("CRef", 1);
1728  
            };
1729  
          }
1730  
          ret info;
1731  
        }
1732  
1733  
        void setFields(structure_ClassInfo info, L<Field> fields) {
1734  
          if (isSubclassOf(info.c, BEAObject)) {
1735  
            // Don't serialize "refs" and "backRefs" fields
1736  
            removeAll(fields,
1737  
              getField(BEAObject, "refs"),
1738  
              getField(BEAObject, "backRefs"));
1739  
          }
1740  
          super.setFields(info, fields);
1741  
        }
1742  
      };
1743  
      
1744  
      S struct = structure(this, data);
1745  
      struct = dropLoadableUtilsPackageFromStruct(struct);
1746  
      text = indentStructureString_firstLevels(1, struct);
1747  
    }
1748  
1749  
    ret text;
1750  
  }
1751  
      
1752  
  toString {
1753  
    ret shorten(toString_long());
1754  
  }
1755  
  
1756  
  S toString_long() {
1757  
    S type = strOrNull(cget type(this));
1758  
    S s = super.toString();
1759  
    
1760  
    if (nempty(type)) {
1761  
      s = type + " " + id;
1762  
      
1763  
      s += appendBracketed(strOrNull(this~.label));
1764  
1765  
      if (eqic(type, "Match"))
1766  
        s += " " + this.~mapping
1767  
          /*+ appendBracketed(this.~input + " + " + this~.pattern)*/;
1768  
    }
1769  
    
1770  
    bool enabled = eq(true, getOpt enabled(this));
1771  
    if (enabled) s += " [enabled]";
1772  
    
1773  
    S text = or2(text(),
1774  
      getStringOpt name(this),
1775  
      getStringOpt internalCode(this));
1776  
    if (text != null)
1777  
      s += " " + quote(text);
1778  
      
1779  
    O fc = this~.functionCalled;
1780  
    if (fc != null) s += " " + fc;
1781  
      
1782  
    O result = this~.result;
1783  
    if (result != null) s += " = " + shorten_str(result);
1784  
      
1785  
    ret s;
1786  
  }
1787  
1788  
  !include #1031300 // BEAObject methods
1789  
1790  
} // end of BEAObject
1791  
1792  
beaConcept BEARegExp {
1793  
  S text;
1794  
  bool caseInsensitive = true;
1795  
  
1796  
  bool valid() { ret nempty(text); }
1797  
  
1798  
  java.util.regex.Pattern compile() {
1799  
    ret compileRegexpPossiblyIC_unicodeCase(text, caseInsensitive);
1800  
  }
1801  
}
1802  
1803  
beaConcept BEARegExpReplacement > BEARegExp {
1804  
  S replacement;
1805  
1806  
  S apply(S text) {
1807  
    try {
1808  
      ret regexpReplace_directWithRefs(compile().matcher(text), unnull(replacement));
1809  
    } catch e {
1810  
      fail(format_quoted("Was searching * in * ", this.text, text));
1811  
    }
1812  
  }
1813  
  
1814  
  LS directCmds() {
1815  
    ret listPlus(super.directCmds(),
1816  
      !valid() ? "Note: not valid"
1817  
      : targetBlank(beaMod().queryLink("Apply regular expression replacement to all inputs", str(id)), "Apply to all inputs"));
1818  
  }
1819  
}
1820  
1821  
beaConcept BEAPatternList {
1822  
  new RefL<BEA> patterns;
1823  
  
1824  
  toString {
1825  
    ret super.toString() + ": " + nPatterns(patterns);
1826  
  }
1827  
}
1828  
1829  
static GazelleBEA beaMod() {
1830  
  ret (GazelleBEA) botMod();
1831  
}
1832  
1833  
set flag hotwire_here.
1834  
1835  
// share ISpec interface with sub-modules
1836  
static JavaXClassLoader hotwire_makeClassLoader(L<File> files) {
1837  
  ClassLoader cl = myClassLoader();
1838  
   ret new JavaXClassLoaderWithParent2(null, files, cl, ll(/*TODO*/));
1839  
}

Author comment

Began life as a copy of #1031304

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt

No comments. add comment

Snippet ID: #1031397
Snippet name: Gazelle BEA [new class naming scheme, abandoned]
Eternal ID of this version: #1031397/3
Text MD5: e8ab0acf17daeebf10df88d98f147f9f
Author: stefan
Category: javax
Type: JavaX source code (Dynamic Module)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-06-24 23:38:55
Source code size: 64877 bytes / 1839 lines
Pitched / IR pitched: No / No
Views / Downloads: 166 / 179
Version history: 2 change(s)
Referenced in: [show references]