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

1932
LINES

< > BotCompany Repo | #1031465 // GazelleBEA [backup before new dynamic class names]

JavaX fragment (include)

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

Author comment

Began life as a copy of #1031418

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1031465
Snippet name: GazelleBEA [backup before new dynamic class names]
Eternal ID of this version: #1031465/1
Text MD5: 83a743ba83f1448a9eef4e91fd6144b0
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-06-14 03:59:25
Source code size: 68153 bytes / 1932 lines
Pitched / IR pitched: No / No
Views / Downloads: 66 / 72
Referenced in: [show references]