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; |
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] |