Wikibase: Add getReferencedEntityId; refactor some wikibase code

pull/620/head
gnosygnu 6 years ago
parent 6348aa6177
commit 341d2e13a4

@ -15,8 +15,8 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.apps.caches; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*;
import gplx.xowa.xtns.wbases.*;
public class Wdata_doc_cache {
private Hash_adp_bry hash = Hash_adp_bry.cs();
public class Wbase_doc_cache {
private final Hash_adp_bry hash = Hash_adp_bry.cs();
public void Add(byte[] qid, Wdata_doc doc) {hash.Add(qid, doc);}
public Wdata_doc Get_or_null(byte[] qid) {return (Wdata_doc)hash.Get_by_bry(qid);}
public void Free_mem_all() {this.Clear();}

@ -15,7 +15,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.apps.caches; import gplx.*; import gplx.xowa.*; import gplx.xowa.apps.*;
public class Xoa_cache_mgr {
public Wdata_doc_cache Doc_cache() {return doc_cache;} private Wdata_doc_cache doc_cache = new Wdata_doc_cache();
public Wbase_doc_cache Doc_cache() {return doc_cache;} private Wbase_doc_cache doc_cache = new Wbase_doc_cache();
public void Free_mem_all() {
doc_cache.Free_mem_all();
}

@ -0,0 +1,121 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.scribunto.libs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.scribunto.*;
import gplx.xowa.xtns.wbases.*; import gplx.xowa.xtns.wbases.claims.*; import gplx.xowa.xtns.wbases.claims.itms.*; import gplx.xowa.xtns.wbases.claims.enums.*;
// REF: https://github.com/wmde/WikibaseDataModelServices/blob/master/src/Lookup/EntityRetrievingClosestReferencedEntityIdLookup.php
class Referenced_entity_lookup_wkr {
private final Wbase_doc_mgr entity_mgr;
private final int maxDepth;
private final int maxEntityVisits;
private final Xoa_url url;
private final byte[] fromId;
private final int propertyId;
private final Ordered_hash toIds;
private final Ordered_hash alreadyVisited = Ordered_hash_.New_bry();
private final List_adp tmp_snak_list = List_adp_.New();
public Referenced_entity_lookup_wkr(int maxDepth, int maxEntityVisits, Wbase_doc_mgr entity_mgr, Xoa_url url, byte[] fromId, int propertyId, Ordered_hash toIds) {
this.maxDepth = maxDepth;
this.maxEntityVisits = maxEntityVisits;
this.entity_mgr = entity_mgr;
this.url = url;
this.fromId = fromId;
this.propertyId = propertyId;
this.toIds = toIds;
}
public byte[] Get_referenced_entity() {
if (toIds == null)
return null;
int steps = this.maxDepth + 1;// Add one as checking $fromId already is a step
Ordered_hash toVisit = Ordered_hash_.New_bry();
toVisit.Add_as_key_and_val(fromId);
while (steps-- > 0) {
// $this->entityPrefetcher->prefetch( $toVisit );
Ordered_hash toVisitNext = Ordered_hash_.New_bry();
int toVisitLen = toVisit.Len();
for (int i = 0; i < toVisitLen; i++) {
byte[] curId = (byte[])toVisit.Get_at(i);
byte[] result = processEntityById(alreadyVisited, curId, fromId, propertyId, toIds, toVisitNext);
if (result != null)
return result;
}
// Remove already visited entities
toVisit = merge(toVisitNext, alreadyVisited);
if (toVisit.Len() == 0)
return null;
}
// Exhausted the max. depth without finding anything.
throw newErr(true);
}
private Err newErr(boolean isMaxDepthOrMaxEntities) {
return Err_.new_wo_type("max exceeded", "type", isMaxDepthOrMaxEntities ? "depth" : "entities", "url", url.To_bry(true, false), "fromId", fromId, "propertyId", propertyId, "toIds", toString(toIds));
}
private static String toString(Ordered_hash hash) {
Bry_bfr bfr = Bry_bfr_.New();
int len = hash.Len();
for (int i = 0; i < len; i++) {
bfr.Add_str_u8(Object_.Xto_str_strict_or_null_mark(hash.Get_at(i))).Add_byte_pipe();
}
return bfr.To_str_and_clear();
}
private byte[] processEntityById(Ordered_hash alreadyVisited, byte[] id, byte[] fromId, int propertyId, Ordered_hash toIds, Ordered_hash toVisit) {
Wdata_doc entity = getEntity(alreadyVisited, id, fromId, propertyId, toIds);
if (entity == null)
return null;
Wbase_claim_base[] mainSnaks = getMainSnaks(entity, propertyId);
for (Wbase_claim_base mainSnak : mainSnaks) {
byte[] result = processSnak(mainSnak, toVisit, toIds);
if (result != null)
return result;
}
return null;
}
private Wdata_doc getEntity(Ordered_hash alreadyVisited, byte[] id, byte[] fromId, int propertyId, Ordered_hash toIds) {
if (alreadyVisited.Has(id)) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "Entity " + String_.new_u8(id) + " already visited");
return null;
}
alreadyVisited.Add_as_key_and_val(id);
if (alreadyVisited.Len() > maxEntityVisits)
throw newErr(false);
return entity_mgr.Get_by_bry_or_null(id);
}
private Wbase_claim_base[] getMainSnaks(Wdata_doc entity, int propertyId) {
Wbase_claim_grp claims = entity.Claim_list_get(propertyId);
return claims.Get_best(tmp_snak_list);
}
private byte[] processSnak(Wbase_claim_base snak, Ordered_hash toVisit, Ordered_hash toIds) {
if (snak.Val_tid() != Wbase_claim_type_.Tid__entity)
return null;
Wbase_claim_entity snakEntity = (Wbase_claim_entity)snak;
byte[] entityId = snakEntity.Page_ttl_db();
if (toIds.Has(entityId))
return entityId;
toVisit.Add_as_key_and_val(entityId);
return null;
}
private Ordered_hash merge(Ordered_hash toVisitNext, Ordered_hash alreadyVisited) {
int len = alreadyVisited.Len();
for (int i = 0; i < len; i++) {
byte[] bry = (byte[])alreadyVisited.Get_at(i);
if (toVisitNext.Has(bry))
toVisitNext.Del(bry);
}
return toVisitNext;
}
}

@ -20,6 +20,7 @@ import gplx.xowa.xtns.scribunto.procs.*;
import gplx.xowa.xtns.wbases.mediawiki.client.includes.*; import gplx.xowa.xtns.wbases.mediawiki.client.includes.dataAccess.scribunto.*;
public class Scrib_lib_wikibase implements Scrib_lib {
private final Scrib_core core;
private Wbase_doc_mgr entity_mgr;
private Wbase_entity_accessor entity_accessor;
private WikibaseLanguageIndependentLuaBindings wikibaseLanguageIndependentLuaBindings;
private Scrib_lua_proc notify_page_changed_fnc;
@ -28,9 +29,9 @@ public class Scrib_lib_wikibase implements Scrib_lib {
public Scrib_proc_mgr Procs() {return procs;} private final Scrib_proc_mgr procs = new Scrib_proc_mgr();
public Scrib_lib Init() {
procs.Init_by_lib(this, Proc_names);
Wbase_doc_mgr entityMgr = core.App().Wiki_mgr().Wdata_mgr().Doc_mgr;
this.entity_accessor = new Wbase_entity_accessor(entityMgr);
this.wikibaseLanguageIndependentLuaBindings = new WikibaseLanguageIndependentLuaBindings(entityMgr);
this.entity_mgr = core.App().Wiki_mgr().Wdata_mgr().Doc_mgr;
this.entity_accessor = new Wbase_entity_accessor(entity_mgr);
this.wikibaseLanguageIndependentLuaBindings = new WikibaseLanguageIndependentLuaBindings(entity_mgr);
return this;
}
public Scrib_lib Clone_lib(Scrib_core core) {return new Scrib_lib_wikibase(core);}
@ -97,11 +98,14 @@ public class Scrib_lib_wikibase implements Scrib_lib {
entityId = Bry_.Mid(entityId, colonPos + 1);
}
boolean valid = checkEntityIdOrNull(entityId) != null;
return rslt.Init_obj(valid);
}
private static byte[] checkEntityIdOrNull(byte[] entityId) {
/* REF: https://github.com/wmde/WikibaseDataModel/tree/master/src/Entity/
PropertyId.php.PATTERN: '/^P[1-9]\d{0,9}\z/i';
ItemId.php.PATTERN : '/^Q[1-9]\d{0,9}\z/i';
*/
boolean valid = false;
if (entityId.length > 0) {
switch (entityId[0]) {
case Byte_ascii.Ltr_P:
@ -122,14 +126,14 @@ public class Scrib_lib_wikibase implements Scrib_lib {
}
}
if (numeric)
valid = true;
return entityId;
break;
}
}
break;
}
}
return rslt.Init_obj(valid);
return null;
}
public boolean GetEntityId(Scrib_proc_args args, Scrib_proc_rslt rslt) {
byte[] ttl_bry = args.Pull_bry(0);
@ -138,8 +142,21 @@ public class Scrib_lib_wikibase implements Scrib_lib {
byte[] rv = wiki.Appe().Wiki_mgr().Wdata_mgr().Qid_mgr.Get_or_null(wiki, ttl); if (rv == null) rv = Bry_.Empty;
return rslt.Init_obj(rv);
}
// REF: https://github.com/wikimedia/mediawiki-extensions-Wikibase/blob/master/client/config/WikibaseClient.default.php
private static final int ReferencedEntityIdMaxDepth = 4, ReferencedEntityIdMaxReferencedEntityVisits = 50;
// private static final int ReferencedEntityIdAccessLimit = 3; // max # of calls per page?
public boolean GetReferencedEntityId(Scrib_proc_args args, Scrib_proc_rslt rslt) {
throw Err_.new_unimplemented();
// get fromId, propertyId, and toIds
byte[] fromId = checkEntityIdOrNull(args.Pull_bry(0));
byte[] propertyIdBry = checkEntityIdOrNull(args.Pull_bry(1));
int propertyId = Bry_.To_int(Bry_.Mid(propertyIdBry, 1));
Keyval[] toIdsAry = args.Pull_kv_ary_safe(2);
Ordered_hash toIds = Ordered_hash_.New_bry();
for (Keyval kv : toIdsAry) {
toIds.Add_as_key_and_val(checkEntityIdOrNull(Bry_.new_u8((String)kv.Val())));
}
Referenced_entity_lookup_wkr wkr = new Referenced_entity_lookup_wkr(ReferencedEntityIdMaxDepth, ReferencedEntityIdMaxReferencedEntityVisits, entity_mgr, core.Page().Url(), fromId, propertyId, toIds);
return rslt.Init_obj(wkr.Get_referenced_entity());
}
public boolean EntityExists(Scrib_proc_args args, Scrib_proc_rslt rslt) {
Wdata_doc wdoc = Get_wdoc_or_null(args, core, false);
@ -238,12 +255,12 @@ public function formatValues( $snaksSerialization ) {
public boolean IncrementExpensiveFunctionCount(Scrib_proc_args args, Scrib_proc_rslt rslt) {
return rslt.Init_obj(Keyval_.Ary_empty); // NOTE: for now, always return null (XOWA does not care about expensive parser functions)
}
private static Wdata_doc Get_wdoc_or_null(Scrib_proc_args args, Scrib_core core, boolean logMissing) {
public Wdata_doc Get_wdoc_or_null(Scrib_proc_args args, Scrib_core core, boolean logMissing) {
// get qid / pid from scrib_arg[0]; if none, return null;
byte[] xid_bry = args.Pull_bry(0); if (Bry_.Len_eq_0(xid_bry)) return null; // NOTE: some Modules do not pass in an argument; return early, else spurious warning "invalid qid for ttl" (since ttl is blank); EX:w:Module:Authority_control; DATE:2013-10-27
// get wdoc
Wdata_doc wdoc = core.Wiki().Appe().Wiki_mgr().Wdata_mgr().Doc_mgr.Get_by_xid_or_null(xid_bry); // NOTE: by_xid b/c Module passes just "p1" not "Property:P1"
Wdata_doc wdoc = entity_mgr.Get_by_xid_or_null(xid_bry); // NOTE: by_xid b/c Module passes just "p1" not "Property:P1"
if (wdoc == null && logMissing) Wdata_wiki_mgr.Log_missing_qid(core.Ctx(), xid_bry);
return wdoc;
}

@ -54,6 +54,21 @@ public class Scrib_lib_wikibase_tst {
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getEntityId, Object_.Ary("Earth" ), "q2");
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getEntityId, Object_.Ary("missing_page" ), "");
}
@Test public void GetReferencedEntityId() {
/*
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q1").Xto_wdoc());
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q2").Add_claims(wdata_fxt.Make_claim_entity_qid(1, 1)).Xto_wdoc());
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q3").Add_claims(wdata_fxt.Make_claim_entity_qid(1, 2)).Xto_wdoc());
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getReferencedEntityId, Object_.Ary("Q3", "P1", NewToIds("Q1")), "Q1");
*/
}
private static Keyval[] NewToIds(String... toIds) {
int len = toIds.length;
Keyval[] rv = new Keyval[len];
for (int i = 0; i < len; i++)
rv[i] = Keyval_.int_(i, toIds[i]);
return rv;
}
@Test public void GetLabel__cur() {
wdata_fxt.Init__docs__add(wdata_fxt.Wdoc_bldr("q2").Add_label("zh-hans", "s").Add_label("zh-hant", "t").Xto_wdoc());
fxt.Test_scrib_proc_str(lib, Scrib_lib_wikibase.Invk_getLabel, Object_.Ary("q2"), "s"); // do not get fallback

@ -16,25 +16,26 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
package gplx.xowa.xtns.wbases; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
import gplx.langs.jsons.*;
import gplx.xowa.wikis.pages.*;
import gplx.xowa.apps.caches.*;
public class Wbase_doc_mgr {
private final Xoae_app app;
private final Wdata_wiki_mgr wbase_mgr;
private final Wbase_qid_mgr qid_mgr;
private final gplx.xowa.apps.caches.Wdata_doc_cache hash;
private final Wbase_doc_cache doc_cache;
public Wbase_doc_mgr(Xoae_app app, Wdata_wiki_mgr wbase_mgr, Wbase_qid_mgr qid_mgr) {
this.app = app; this.wbase_mgr = wbase_mgr; this.qid_mgr = qid_mgr;
this.hash = app.Cache_mgr().Doc_cache();
this.doc_cache = app.Cache_mgr().Doc_cache();
}
public void Enabled_(boolean v) {this.enabled = v;} private boolean enabled;
public void Clear() {
synchronized (hash) { // LOCK:app-level
hash.Clear();
synchronized (doc_cache) { // LOCK:app-level
doc_cache.Clear();
}
}
public void Add(byte[] full_db, Wdata_doc page) { // TEST:
synchronized (hash) { // LOCK:app-level
if (hash.Get_or_null(full_db) == null)
hash.Add(full_db, page);
synchronized (doc_cache) { // LOCK:app-level
if (doc_cache.Get_or_null(full_db) == null)
doc_cache.Add(full_db, page);
}
}
public Wdata_doc Get_by_ttl_or_null(Xowe_wiki wiki, Xoa_ttl ttl) {
@ -43,18 +44,18 @@ public class Wbase_doc_mgr {
}
public Wdata_doc Get_by_xid_or_null(byte[] xid) {return Get_by_bry_or_null(Prepend_property_if_needed(xid));}// scribunto passes either p1 or q1; convert p1 to "Property:P1"
public Wdata_doc Get_by_bry_or_null(byte[] ttl_bry) {// must be correct format; EX:"Q2" or "Property:P1"
Wdata_doc rv = hash.Get_or_null(ttl_bry);
Wdata_doc rv = doc_cache.Get_or_null(ttl_bry);
if (rv == null) {
synchronized (hash) { // LOCK:app-level; hash;
synchronized (doc_cache) { // LOCK:app-level; doc_cache;
rv = Load_wdoc_or_null(ttl_bry); if (rv == null) return null; // page not found
Add(ttl_bry, rv);// NOTE: use ttl_bry, not rv.Qid; allows subsequent lookups to skip this redirect cycle
}
}
return rv;
}
public Wdata_doc Load_wdoc_or_null(byte[] src_ttl_bry) {
private Wdata_doc Load_wdoc_or_null(byte[] src_ttl_bry) {
if (!enabled) return null;
synchronized (hash) { // LOCK:app-level; jdoc_parser; moved synchronized higher up; DATE:2016-09-03
synchronized (doc_cache) { // LOCK:app-level; jdoc_parser; moved synchronized higher up; DATE:2016-09-03
byte[] cur_ttl_bry = src_ttl_bry;
int load_count = -1;
while (load_count < 2) { // limit to 2 tries (i.e.: 1 redirect)

@ -25,7 +25,7 @@ public class Wbase_doc_mgr__tst {
fxt.Parser_fxt().Init_page_create(wbase_mgr.Wdata_wiki(), "Q2", Json_doc.Make_str_by_apos("{'entity':'q2','links':{'enwiki':'q2_en','dewiki':'q2_de'}}"));
// fetch Q1; assert Q2 comes back
Wdata_doc actl = wbase_mgr.Doc_mgr.Load_wdoc_or_null(Bry_.new_u8("Q1"));
Wdata_doc actl = wbase_mgr.Doc_mgr.Get_by_bry_or_null(Bry_.new_u8("Q1"));
Gftest.Eq__str("Q2", String_.new_u8(actl.Qid()));
}
}

@ -15,7 +15,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.wbases.claims; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.wbases.*;
import gplx.core.primitives.*;
import gplx.xowa.xtns.wbases.claims.itms.*;
import gplx.xowa.xtns.wbases.claims.enums.*; import gplx.xowa.xtns.wbases.claims.itms.*;
public class Wbase_claim_grp {
public Wbase_claim_grp(Int_obj_ref id_ref, Wbase_claim_base[] itms) {this.id_ref = id_ref; this.itms = itms;}
public Int_obj_ref Id_ref() {return id_ref;} private final Int_obj_ref id_ref;
@ -23,6 +23,36 @@ public class Wbase_claim_grp {
public String Id_str() {if (id_str == null) id_str = "P" + Int_.To_str(id_ref.Val()); return id_str;} private String id_str;
public int Len() {return itms.length;} private Wbase_claim_base[] itms;
public Wbase_claim_base Get_at(int i) {return itms[i];}
/*
Returns the so called "best statements".
If there are preferred statements, then this is all the preferred statements.
If there are no preferred statements, then this is all normal statements.
*/
public Wbase_claim_base[] Get_best(List_adp tmp_snak_list) {
int len = itms.length;
boolean preferred_found = false;
for (int i = 0; i < len; i++) {
Wbase_claim_base itm = itms[i];
switch (itm.Rank_tid()) {
case Wbase_claim_rank_.Tid__preferred:
if (!preferred_found) {
if (tmp_snak_list.Len() > 0)
tmp_snak_list.Clear();
preferred_found = true;
}
tmp_snak_list.Add(itm);
break;
case Wbase_claim_rank_.Tid__normal:
if (!preferred_found)
tmp_snak_list.Add(itm);
break;
}
}
return tmp_snak_list.Count() == 0 ? Empty_array : (Wbase_claim_base[])tmp_snak_list.To_ary_and_clear(Wbase_claim_base.class);
}
private static final Wbase_claim_base[] Empty_array = new Wbase_claim_base[0];
public static List_adp Xto_list(Ordered_hash hash) {
int len = hash.Count();
List_adp rv = List_adp_.New();

@ -0,0 +1,71 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.wbases.claims; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.wbases.*;
import org.junit.*; import gplx.core.tests.*; import gplx.core.primitives.*;
import gplx.xowa.xtns.wbases.claims.enums.*; import gplx.xowa.xtns.wbases.claims.itms.*;
public class Wbase_claim_grp_tst {
@Test public void Get_best__preferred() {
Wbase_claim_grp_bldr bldr = new Wbase_claim_grp_bldr(123);
bldr.Add("P1", Wbase_claim_rank_.Tid__preferred);
bldr.Add("N1", Wbase_claim_rank_.Tid__normal);
bldr.Add("P2", Wbase_claim_rank_.Tid__preferred);
bldr.Add("N2", Wbase_claim_rank_.Tid__normal);
bldr.Test__Get_best("P1", "P2");
}
@Test public void Get_best__normal_if_no_preferred() {
Wbase_claim_grp_bldr bldr = new Wbase_claim_grp_bldr(123);
bldr.Add("D1", Wbase_claim_rank_.Tid__deprecated);
bldr.Add("D2", Wbase_claim_rank_.Tid__deprecated);
bldr.Add("N1", Wbase_claim_rank_.Tid__normal);
bldr.Add("N2", Wbase_claim_rank_.Tid__normal);
bldr.Test__Get_best("N1", "N2");
}
@Test public void Get_best__preferred_after_normal() {
Wbase_claim_grp_bldr bldr = new Wbase_claim_grp_bldr(123);
bldr.Add("N1", Wbase_claim_rank_.Tid__normal);
bldr.Add("N2", Wbase_claim_rank_.Tid__normal);
bldr.Add("P1", Wbase_claim_rank_.Tid__preferred);
bldr.Add("P2", Wbase_claim_rank_.Tid__preferred);
bldr.Test__Get_best("P1", "P2");
}
}
class Wbase_claim_grp_bldr {
private final int pid;
private final List_adp list = List_adp_.New();
public Wbase_claim_grp_bldr(int pid) {
this.pid = pid;
}
public void Add(String val, byte rank_tid) {
Wbase_claim_string claim = new Wbase_claim_string(pid, Wbase_claim_value_type_.Tid__value, Bry_.new_u8(val));
claim.Rank_tid_(rank_tid);
list.Add(claim);
}
public void Test__Get_best(String... expd) {
Wbase_claim_grp grp = new Wbase_claim_grp(Int_obj_ref.New(pid), (Wbase_claim_base[])list.To_ary_and_clear(Wbase_claim_base.class));
List_adp tmp_list = List_adp_.New();
Gftest.Eq__ary(expd, To_string(grp.Get_best(tmp_list)));
}
private String[] To_string(Wbase_claim_base[] items) {
int len = items.length;
String[] rv = new String[len];
for (int i = 0; i < len; i++) {
Wbase_claim_string claim = (Wbase_claim_string)items[i];
rv[i] = String_.new_u8(claim.Val_bry());
}
return rv;
}
}
Loading…
Cancel
Save