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

696
LINES

< > BotCompany Repo | #1025231 // unstructure (v16, better class finding)

JavaX fragment (include) [tags: use-pretranspiled]

Transpiled version (5158L) is out of date.

1  
// TODO: cyclic structures involving certain lists & sets
2  
3  
sO unstructure(String text) {
4  
  ret unstructure(text, false);
5  
}
6  
7  
sO unstructure(S text, bool allDynamic) {
8  
  ret unstructure(text, allDynamic, null);
9  
}
10  
11  
sO unstructure(S text, IF1<S, Class> classFinder) {
12  
  ret unstructure(text, false, classFinder);
13  
}
14  
15  
static int structure_internStringsLongerThan = 50;
16  
static int unstructure_unquoteBufSize = 100;
17  
18  
static int unstructure_tokrefs; // stats
19  
20  
abstract sclass unstructure_Receiver {
21  
  abstract void set(O o);
22  
}
23  
24  
// classFinder: func(name) -> class (optional)
25  
static Object unstructure(String text, boolean allDynamic,
26  
  O classFinder) {
27  
  if (text == null) ret null;
28  
  ret unstructure_tok(javaTokC_noMLS_iterator(text), allDynamic, classFinder);
29  
}
30  
31  
static O unstructure_reader(BufferedReader reader) {
32  
  ret unstructure_tok(javaTokC_noMLS_onReader(reader), false, null);
33  
}
34  
35  
static O unstructure_tok(final Producer<S> tok, final boolean allDynamic, final O _classFinder) {
36  
  final boolean debug = unstructure_debug;
37  
  
38  
  final class X {
39  
    int i = -1;
40  
    final O classFinder = _classFinder != null ? _classFinder : _defaultClassFinder();
41  
    new HashMap<Integer, O> refs;
42  
    new HashMap<Integer, O> tokrefs;
43  
    new HashSet<S> concepts;
44  
    new HashMap<S, Class> classesMap;
45  
    new L<Runnable> stack;
46  
    S curT;
47  
    char[] unquoteBuf = new char[unstructure_unquoteBufSize];
48  
    
49  
    Class findAClass(S fullClassName) {
50  
      ret classFinder != null ? (Class) callF(classFinder, fullClassName) : findClass_fullName(fullClassName);
51  
    }
52  
    
53  
    S unquote(S s) {
54  
      ret unquoteUsingCharArray(s, unquoteBuf); 
55  
    }
56  
57  
    // look at current token
58  
    S t() {
59  
      ret curT;
60  
    }
61  
    
62  
    // get current token, move to next
63  
    S tpp() {
64  
      S t = curT;
65  
      consume();
66  
      ret t;
67  
    }
68  
    
69  
    void parse(final unstructure_Receiver out) {
70  
      S t = t();
71  
      
72  
      int refID;
73  
      if (structure_isMarker(t, 0, l(t))) {
74  
        refID = parseInt(t.substring(1));
75  
        consume();
76  
      } else refID = -1;
77  
      
78  
      // if (debug) print("parse: " + quote(t));
79  
      
80  
      final int tokIndex = i;  
81  
      parse_inner(refID, tokIndex, new unstructure_Receiver {
82  
        void set(O o) {
83  
          if (refID >= 0)
84  
            refs.put(refID, o);
85  
          if (o != null)
86  
            tokrefs.put(tokIndex, o);
87  
          out.set(o);
88  
        }
89  
      });
90  
    }
91  
    
92  
    void parse_inner(int refID, int tokIndex, final unstructure_Receiver out) {
93  
      S t = t();
94  
      
95  
      // if (debug) print("parse_inner: " + quote(t));
96  
      
97  
      Class c = classesMap.get(t);
98  
      if (c == null) {
99  
        if (t.startsWith("\"")) {
100  
          S s = internIfLongerThan(unquote(tpp()), structure_internStringsLongerThan);
101  
          out.set(s); ret;
102  
        }
103  
        
104  
        if (t.startsWith("'")) {
105  
          out.set(unquoteCharacter(tpp())); ret;
106  
        }
107  
        if (t.equals("bigint")) {
108  
          out.set(parseBigInt()); ret;
109  
        }
110  
        if (t.equals("d")) {
111  
          out.set(parseDouble()); ret;
112  
        }
113  
        if (t.equals("fl")) {
114  
          out.set(parseFloat()); ret;
115  
        }
116  
        if (t.equals("sh")) {
117  
          consume();
118  
          t = tpp();
119  
          if (t.equals("-")) {
120  
            t = tpp();
121  
            out.set((short) (-parseInt(t)); ret;
122  
          }
123  
          out.set((short) parseInt(t)); ret;
124  
        }
125  
        if (t.equals("-")) {
126  
          consume();
127  
          t = tpp();
128  
          out.set(isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t))); ret;
129  
        }
130  
        if (isInteger(t) || isLongConstant(t)) {
131  
          consume();
132  
          //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
133  
          if (isLongConstant(t)) {
134  
            out.set(parseLong(t)); ret;
135  
          }
136  
          long l = parseLong(t);
137  
          bool isInt = l == (int) l;
138  
          ifdef unstructure_debug
139  
            print("l=" + l + ", isInt: " + isInt);
140  
          endifdef
141  
          out.set(isInt ? (O) Integer.valueOf((int) l) : (O) Long.valueOf(l)); ret;
142  
        }
143  
        if (t.equals("false") || t.equals("f")) {
144  
          consume(); out.set(false); ret;
145  
        }
146  
        if (t.equals("true") || t.equals("t")) {
147  
          consume(); out.set(true); ret;
148  
        }
149  
        if (t.equals("-")) {
150  
          consume();
151  
          t = tpp();
152  
          out.set(isLongConstant(t) ? (O) (-parseLong(t)) : (O) (-parseInt(t))); ret;
153  
        }
154  
        if (isInteger(t) || isLongConstant(t)) {
155  
          consume();
156  
          //if (debug) print("isLongConstant " + quote(t) + " => " + isLongConstant(t));
157  
          if (isLongConstant(t)) {
158  
            out.set(parseLong(t)); ret;
159  
          }
160  
          long l = parseLong(t);
161  
          bool isInt = l == (int) l;
162  
          ifdef unstructure_debug
163  
            print("l=" + l + ", isInt: " + isInt);
164  
          endifdef
165  
          out.set(isInt ? (O) Integer.valueOf((int) l) : (O) Long.valueOf(l)); ret;
166  
        }
167  
        
168  
        if (t.equals("File")) {
169  
          consume();
170  
          File f = new File(unquote(tpp()));
171  
          out.set(f); ret;
172  
        }
173  
        
174  
        if (t.startsWith("r") && isInteger(t.substring(1))) {
175  
          consume();
176  
          int ref = Integer.parseInt(t.substring(1));
177  
          O o = refs.get(ref);
178  
          if (o == null)
179  
            fail("unsatisfied back reference " + ref);
180  
          out.set(o); ret;
181  
        }
182  
      
183  
        if (t.startsWith("t") && isInteger(t.substring(1))) {
184  
          consume();
185  
          int ref = Integer.parseInt(t.substring(1));
186  
          O o = tokrefs.get(ref);
187  
          if (o == null)
188  
            fail("unsatisfied token reference " + ref + " at " + tokIndex);
189  
          out.set(o); ret;
190  
        }
191  
        
192  
        if (t.equals("hashset")) ret with parseHashSet(out);
193  
        if (t.equals("lhs")) ret with parseLinkedHashSet(out);
194  
        if (t.equals("treeset")) ret with parseTreeSet(out);
195  
        if (t.equals("ciset")) ret with parseCISet(out);
196  
        
197  
        if (eqOneOf(t, "hashmap", "hm")) {
198  
          consume();
199  
          parseMap(new HashMap, out);
200  
          ret;
201  
        }
202  
        if (t.equals("lhm")) {
203  
          consume();
204  
          parseMap(new LinkedHashMap, out);
205  
          ret;
206  
        }
207  
        if (t.equals("tm")) {
208  
          consume();
209  
          parseMap(new TreeMap, out);
210  
          ret;
211  
        }
212  
        if (t.equals("cimap")) {
213  
          consume();
214  
          parseMap(ciMap(), out);
215  
          ret;
216  
        }
217  
        
218  
        if (t.equals("ll")) {
219  
          consume();
220  
          new LinkedList l;
221  
          if (refID >= 0) refs.put(refID, l);
222  
          ret with parseList(l, out);
223  
        }
224  
225  
        if (t.equals("syncLL")) { // legacy
226  
          consume();
227  
          ret with parseList(synchroLinkedList(), out);
228  
        }
229  
230  
        if (t.equals("sync")) {
231  
          consume();
232  
          ret with parse(new unstructure_Receiver {
233  
            void set(O value) {
234  
              if (value instanceof Map) {
235  
                ifndef Android // Java 7
236  
                if (value instanceof NavigableMap)
237  
                  ret with out.set(Collections.synchronizedNavigableMap((NavigableMap) value));
238  
                endifndef
239  
                if (value instanceof SortedMap)
240  
                  ret with out.set(Collections.synchronizedSortedMap((SortedMap) value));
241  
                ret with out.set(Collections.synchronizedMap((Map) value));
242  
              } else
243  
                ret with out.set(Collections.synchronizedList((L) value);
244  
            }
245  
          });
246  
        }
247  
        
248  
        if (t.equals("{")) {
249  
          parseMap(out); ret;
250  
        }
251  
        if (t.equals("[")) {
252  
          new ArrayList l;
253  
          if (refID >= 0) refs.put(refID, l);
254  
          this.parseList(l, out); ret;
255  
        }
256  
        if (t.equals("bitset")) {
257  
          parseBitSet(out); ret;
258  
        }
259  
        if (t.equals("array") || t.equals("intarray") || t.equals("dblarray")) {
260  
          parseArray(out); ret;
261  
        }
262  
        if (t.equals("ba")) {
263  
          consume();
264  
          S hex = unquote(tpp());
265  
          out.set(hexToBytes(hex)); ret;
266  
        }
267  
        if (t.equals("boolarray")) {
268  
          consume();
269  
          int n = parseInt(tpp());
270  
          S hex = unquote(tpp());
271  
          out.set(boolArrayFromBytes(hexToBytes(hex), n)); ret;
272  
        }
273  
        if (t.equals("class")) {
274  
          out.set(parseClass()); ret;
275  
        }
276  
        if (t.equals("l")) {
277  
          parseLisp(out); ret;
278  
        }
279  
        if (t.equals("null")) {
280  
          consume(); out.set(null); ret;
281  
        }
282  
        
283  
        if (eq(t, "c")) {
284  
          consume();
285  
          t = t();
286  
          assertTrue(isJavaIdentifier(t));
287  
          concepts.add(t);
288  
        }
289  
        
290  
        // custom deserialization (new static method method)
291  
        if (eq(t, "cu")) {
292  
          consume();
293  
          t = tpp();
294  
          assertTrue(isJavaIdentifier(t));
295  
          S fullClassName = "main$" + t;
296  
          Class _c = findAClass(fullClassName);
297  
          if (_c == null) fail("Class not found: " + fullClassName);
298  
          parse(new unstructure_Receiver {
299  
            void set(O value) {
300  
              ifdef unstructure_debug
301  
                print("Consumed custom object, next token: " + t());
302  
              endifdef
303  
              out.set(call(_c, "_deserialize", value);
304  
            }
305  
          });
306  
          ret;
307  
        }
308  
      }
309  
      
310  
      if (eq(t, "j")) {
311  
        consume("j");
312  
        out.set(parseJava()); ret;
313  
      }
314  
315  
      if (c == null && !isJavaIdentifier(t))
316  
        throw new RuntimeException("Unknown token " + (i+1) + ": " + quote(t));
317  
        
318  
      // any other class name (or package name)
319  
      consume();
320  
      S className, fullClassName;
321  
      
322  
      // Is it a package name?
323  
      if (eq(t(), ".")) {
324  
        consume();
325  
        className = fullClassName = t + "." + assertIdentifier(tpp());
326  
      } else {
327  
        className = t;
328  
        fullClassName = "main$" + t;
329  
      }
330  
      
331  
      if (c == null) {
332  
        // First, find class
333  
        if (allDynamic) c = null;
334  
        else c = findAClass(fullClassName);
335  
        if (c != null)
336  
          classesMap.put(className, c);
337  
      }
338  
          
339  
      // Check if it has an outer reference
340  
      bool hasBracket = eq(t(), "(");
341  
      if (hasBracket) consume();
342  
      bool hasOuter = hasBracket && eq(t(), "this$1");
343  
      
344  
      DynamicObject dO = null;
345  
      O o = null;
346  
      fS thingName = t;
347  
      if (c != null) {
348  
        o = hasOuter ? nuStubInnerObject(c, classFinder) : nuEmptyObject(c);
349  
        if (o instanceof DynamicObject) dO = (DynamicObject) o;
350  
      } else {
351  
        if (concepts.contains(t) && (c = findAClass("main$Concept")) != null)
352  
          o = dO = (DynamicObject) nuEmptyObject(c);
353  
        else
354  
          dO = new DynamicObject;
355  
        dO.className = className;
356  
        ifdef unstructure_debug
357  
          print("Made dynamic object " + t + " " + shortClassName(dO));
358  
        endifdef
359  
      }
360  
      
361  
      // Save in references list early because contents of object
362  
      // might link back to main object
363  
      
364  
      if (refID >= 0)
365  
        refs.put(refID, o != null ? o : dO);
366  
      tokrefs.put(tokIndex, o != null ? o : dO);
367  
      
368  
      // NOW parse the fields!
369  
      
370  
      new /*Linked*/HashMap<S, O> fields; // no longer preserving order (why did we do this?)
371  
      O _o = o;
372  
      DynamicObject _dO = dO;
373  
      if (hasBracket) {
374  
        stack.add(r {
375  
          ifdef unstructure_debug
376  
            print("in object values, token: " + t());
377  
          endifdef
378  
          if (eq(t(), ",")) consume();
379  
          if (eq(t(), ")")) {
380  
            consume(")");
381  
            objRead(_o, _dO, fields, hasOuter);
382  
            out.set(_o != null ? _o : _dO);
383  
          } else {
384  
            final S key = unquote(tpp());
385  
            S t = tpp();
386  
            if (!eq(t, "="))
387  
              fail("= expected, got " + t + " after " + quote(key) + " in object " + thingName /*+ " " + sfu(fields)*/);
388  
            stack.add(this);
389  
            parse(new unstructure_Receiver {
390  
              void set(O value) {
391  
                fields.put(key, value);
392  
                /*ifdef unstructure_debug
393  
                  print("Got field value " + value + ", next token: " + t());
394  
                endifdef*/
395  
                //if (eq(t(), ",")) consume();
396  
              }
397  
            });
398  
          }
399  
        });
400  
      } else {
401  
        objRead(o, dO, fields, hasOuter);
402  
        out.set(o != null ? o : dO);
403  
      }
404  
    }
405  
    
406  
    void objRead(O o, DynamicObject dO, Map<S, O> fields, bool hasOuter) {
407  
      ifdef unstructure_debug
408  
      print("objRead " + className(o) + " " + className(dO) + " " + struct(fields));
409  
      endifdef
410  
      if (o != null) {
411  
        if (dO != null) {
412  
          ifdef unstructure_debug
413  
            printStructure("setOptAllDyn", fields);
414  
          endifdef
415  
          setOptAllDyn_pcall(dO, fields);
416  
        } else {
417  
          setOptAll_pcall(o, fields);
418  
          ifdef unstructure_debug
419  
            print("objRead now: " + struct(o));
420  
          endifdef
421  
        }
422  
        if (hasOuter)
423  
          fixOuterRefs(o);
424  
      } else for (Map.Entry<S, O> e : fields.entrySet())
425  
        setDynObjectValue(dO, intern(e.getKey()), e.getValue());
426  
427  
      if (o != null)
428  
        pcallOpt_noArgs(o, "_doneLoading");
429  
    }
430  
    
431  
    void parseSet(final Set set, final unstructure_Receiver out) {
432  
      this.parseList(new ArrayList, new unstructure_Receiver {
433  
        void set(O o) {
434  
          set.addAll((L) o);
435  
          out.set(set);
436  
        }
437  
      });
438  
    }
439  
    
440  
    void parseLisp(final unstructure_Receiver out) {
441  
      ifclass Lisp
442  
        consume("l");
443  
        consume("(");
444  
        final new ArrayList list;
445  
        stack.add(r {
446  
          if (eq(t(), ")")) {
447  
            consume(")");
448  
            out.set(Lisp((S) list.get(0), subList(list, 1)));
449  
          } else {
450  
            stack.add(this);
451  
            parse(new unstructure_Receiver {
452  
              void set(O o) {
453  
                list.add(o);
454  
                if (eq(t(), ",")) consume();
455  
              }
456  
            });
457  
          }
458  
        });
459  
        if (false) // skip fail line
460  
      endif
461  
      
462  
      fail("class Lisp not included");
463  
    }
464  
    
465  
    void parseBitSet(final unstructure_Receiver out) {
466  
      consume("bitset");
467  
      consume("{");
468  
      final new BitSet bs;
469  
      stack.add(r {
470  
        if (eq(t(), "}")) {
471  
          consume("}");
472  
          out.set(bs);
473  
        } else {
474  
          stack.add(this);
475  
          parse(new unstructure_Receiver {
476  
            void set(O o) {
477  
              bs.set((Integer) o);
478  
              if (eq(t(), ",")) consume();
479  
            }
480  
          });
481  
        }
482  
      });
483  
    }
484  
    
485  
    void parseList(final L list, final unstructure_Receiver out) {
486  
      tokrefs.put(i, list);
487  
      consume("[");
488  
      stack.add(r {
489  
        if (eq(t(), "]")) {
490  
          consume();
491  
          ifdef unstructure_debug
492  
            print("Consumed list, next token: " + t());
493  
          endifdef
494  
          out.set(list);
495  
        } else {
496  
          stack.add(this);
497  
          parse(new unstructure_Receiver {
498  
            void set(O o) {
499  
              //if (debug) print("List element type: " + getClassName(o));
500  
              list.add(o);
501  
              if (eq(t(), ",")) consume();
502  
            }
503  
          });
504  
        }
505  
      });
506  
    }
507  
    
508  
    void parseArray(final unstructure_Receiver out) {
509  
      final S type = tpp();
510  
      consume("{");
511  
      final List list = new ArrayList;
512  
      
513  
      stack.add(r {
514  
        if (eq(t(), "}")) {
515  
          consume("}");
516  
          out.set(
517  
            type.equals("intarray") ? toIntArray(list)
518  
            : type.equals("dblarray") ? toDoubleArray(list)
519  
            : list.toArray());
520  
        } else {
521  
          stack.add(this);
522  
          parse(new unstructure_Receiver {
523  
            void set(O o) {
524  
              list.add(o);
525  
              if (eq(t(), ",")) consume();
526  
            }
527  
          });
528  
        }
529  
      });
530  
    }
531  
    
532  
    Object parseClass() {
533  
      consume("class");
534  
      consume("(");
535  
      S name = unquote(tpp());
536  
      consume(")");
537  
      Class c = allDynamic ? null : findAClass(name);
538  
      if (c != null) ret c;
539  
      new DynamicObject dO;
540  
      dO.className = "java.lang.Class";
541  
      name = dropPrefix("main$", name);
542  
      dO.fieldValues.put("name", name);
543  
      ret dO;
544  
    }
545  
    
546  
    Object parseBigInt() {
547  
      consume("bigint");
548  
      consume("(");
549  
      S val = tpp();
550  
      if (eq(val, "-"))
551  
        val = "-" + tpp();
552  
      consume(")");
553  
      ret new BigInteger(val);
554  
    }
555  
    
556  
    Object parseDouble() {
557  
      consume("d");
558  
      consume("(");
559  
      S val = unquote(tpp());
560  
      consume(")");
561  
      ret Double.parseDouble(val);
562  
    }
563  
    
564  
    Object parseFloat() {
565  
      consume("fl");
566  
      S val;
567  
      if (eq(t(), "(")) {
568  
        consume("(");
569  
        val = unquote(tpp());
570  
        consume(")");
571  
      } else {
572  
        val = unquote(tpp());
573  
      }
574  
      ret Float.parseFloat(val);
575  
    }
576  
    
577  
    void parseHashSet(unstructure_Receiver out) {
578  
      consume("hashset");
579  
      parseSet(new HashSet, out);
580  
    }
581  
    
582  
    void parseLinkedHashSet(unstructure_Receiver out) {
583  
      consume("lhs");
584  
      parseSet(new LinkedHashSet, out);
585  
    }
586  
    
587  
    void parseTreeSet(unstructure_Receiver out) {
588  
      consume("treeset");
589  
      parseSet(new TreeSet, out);
590  
    }
591  
    
592  
    void parseCISet(unstructure_Receiver out) {
593  
      consume("ciset");
594  
      parseSet(ciSet(), out);
595  
    }
596  
    
597  
    void parseMap(unstructure_Receiver out) {
598  
      parseMap(new TreeMap, out);
599  
    }
600  
    
601  
    O parseJava() {
602  
      S j = unquote(tpp());
603  
      new Matches m;
604  
      if (jmatch("java.awt.Color[r=*,g=*,b=*]", j, m))
605  
        ret nuObject("java.awt.Color", parseInt($1), parseInt($2), parseInt($3));
606  
      else {
607  
        warn("Unknown Java object: " + j);
608  
        null;
609  
      }
610  
    }
611  
    
612  
    void parseMap(final Map map, final unstructure_Receiver out) {
613  
      consume("{");
614  
      stack.add(new Runnable {
615  
        bool v;
616  
        O key;
617  
        
618  
        public void run() { 
619  
          if (v) {
620  
            v = false;
621  
            stack.add(this);
622  
            if (!eq(tpp(), "="))
623  
              fail("= expected, got " + t() + " in map of size " + l(map));
624  
625  
            parse(new unstructure_Receiver {
626  
              void set(O value) {
627  
                map.put(key, value);
628  
                ifdef unstructure_debug
629  
                  print("parseMap: Got value " + getClassName(value) + ", next token: " + quote(t()));
630  
                endifdef
631  
                if (eq(t(), ",")) consume();
632  
              }
633  
            });
634  
          } else {
635  
            if (eq(t(), "}")) {
636  
              consume("}");
637  
              out.set(map);
638  
            } else {
639  
              v = true;
640  
              stack.add(this);
641  
              parse(new unstructure_Receiver {
642  
                void set(O o) {
643  
                  key = o;
644  
                }
645  
              });
646  
            }
647  
          } // if v else
648  
        } // run()
649  
      });
650  
    }
651  
    
652  
    /*void parseSub(unstructure_Receiver out) {
653  
      int n = l(stack);
654  
      parse(out);
655  
      while (l(stack) > n)
656  
        stack
657  
    }*/
658  
    
659  
    void consume() { curT = tok.next(); ++i; }
660  
    
661  
    void consume(S s) {
662  
      if (!eq(t(), s)) {
663  
        /*S prevToken = i-1 >= 0 ? tok.get(i-1) : "";
664  
        S nextTokens = join(tok.subList(i, Math.min(i+2, tok.size())));
665  
        fail(quote(s) + " expected: " + prevToken + " " + nextTokens + " (" + i + "/" + tok.size() + ")");*/
666  
        fail(quote(s) + " expected, got " + quote(t()));
667  
      }
668  
      consume();
669  
    }
670  
    
671  
    // outer wrapper function getting first token and unwinding the stack
672  
    void parse_initial(unstructure_Receiver out) {
673  
      consume(); // get first token
674  
      parse(out);
675  
      while (nempty(stack))
676  
        popLast(stack).run();
677  
    }
678  
  }
679  
  
680  
  ThreadLocal<Bool> tlLoading = dynamicObjectIsLoading_threadLocal();
681  
  Bool b = tlLoading!;
682  
  tlLoading.set(true);
683  
  try {
684  
    final new Var v;
685  
    new X x;
686  
    x.parse_initial(new unstructure_Receiver {
687  
      void set(O o) { v.set(o); }
688  
    });
689  
    unstructure_tokrefs = x.tokrefs.size();
690  
    ret v.get();
691  
  } finally {
692  
    tlLoading.set(b);
693  
  }
694  
}
695  
696  
static boolean unstructure_debug;

Author comment

Began life as a copy of #1024877

download  show line numbers  debug dex  old transpilations   

Travelled to 8 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, whxojlpjdney, xrpafgyirdlv

No comments. add comment

Snippet ID: #1025231
Snippet name: unstructure (v16, better class finding)
Eternal ID of this version: #1025231/20
Text MD5: c252754add267dff85c21fdf532edd7c
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-04-14 16:10:57
Source code size: 20685 bytes / 696 lines
Pitched / IR pitched: No / No
Views / Downloads: 368 / 588
Version history: 19 change(s)
Referenced in: [show references]