├── .gitignore ├── LICENSE ├── README.md ├── YuzuQL.md ├── common ├── assets │ ├── bootstrap.min.css │ ├── cc │ │ ├── by-nc-nd.eu.png │ │ ├── by-nc-nd.png │ │ ├── by-nc-sa.eu.png │ │ ├── by-nc-sa.png │ │ ├── by-nc.eu.png │ │ ├── by-nc.png │ │ ├── by-nd.png │ │ ├── by-sa.png │ │ ├── by.png │ │ ├── cc-zero.png │ │ └── publicdomain.png │ ├── d3.min.js │ ├── favicon.ico │ ├── flag │ │ ├── ad.gif │ │ ├── ae.gif │ │ ├── af.gif │ │ ├── ag.gif │ │ ├── ai.gif │ │ ├── al.gif │ │ ├── am.gif │ │ ├── an.gif │ │ ├── ao.gif │ │ ├── ar.gif │ │ ├── ar2.gif │ │ ├── as.gif │ │ ├── at.gif │ │ ├── au.gif │ │ ├── aw.gif │ │ ├── ax.gif │ │ ├── az.gif │ │ ├── ba.gif │ │ ├── basque.gif │ │ ├── basque.png │ │ ├── bb.gif │ │ ├── be.gif │ │ ├── bf.gif │ │ ├── bg.gif │ │ ├── bh.gif │ │ ├── bi.gif │ │ ├── bj.gif │ │ ├── bm.gif │ │ ├── bn.gif │ │ ├── bo.gif │ │ ├── br.gif │ │ ├── bs.gif │ │ ├── bt.gif │ │ ├── bv.gif │ │ ├── bw.gif │ │ ├── by.gif │ │ ├── bz.gif │ │ ├── ca.gif │ │ ├── catalonia.gif │ │ ├── cc.gif │ │ ├── cd.gif │ │ ├── cf.gif │ │ ├── cg.gif │ │ ├── ch.gif │ │ ├── ci.gif │ │ ├── ck.gif │ │ ├── cl.gif │ │ ├── cm.gif │ │ ├── co.gif │ │ ├── cr.gif │ │ ├── cs.gif │ │ ├── cu.gif │ │ ├── cv.gif │ │ ├── cx.gif │ │ ├── cy.gif │ │ ├── da.gif │ │ ├── de.gif │ │ ├── dj.gif │ │ ├── dm.gif │ │ ├── do.gif │ │ ├── dz.gif │ │ ├── ec.gif │ │ ├── eg.gif │ │ ├── eh.gif │ │ ├── el.gif │ │ ├── en-gb.gif │ │ ├── en-us.gif │ │ ├── en.gif │ │ ├── eng.gif │ │ ├── england.gif │ │ ├── er.gif │ │ ├── es.gif │ │ ├── et.gif │ │ ├── eu.gif │ │ ├── europeanunion.gif │ │ ├── fam.gif │ │ ├── fi.gif │ │ ├── fj.gif │ │ ├── fk.gif │ │ ├── fm.gif │ │ ├── fo.gif │ │ ├── fr.gif │ │ ├── ga.gif │ │ ├── galicia.gif │ │ ├── gd.gif │ │ ├── ge.gif │ │ ├── gf.gif │ │ ├── gh.gif │ │ ├── gi.gif │ │ ├── gl.gif │ │ ├── gm.gif │ │ ├── gn.gif │ │ ├── gp.gif │ │ ├── gq.gif │ │ ├── gs.gif │ │ ├── gt.gif │ │ ├── gu.gif │ │ ├── gw.gif │ │ ├── gy.gif │ │ ├── he.gif │ │ ├── hk.gif │ │ ├── hm.gif │ │ ├── hn.gif │ │ ├── hr.gif │ │ ├── ht.gif │ │ ├── hu.gif │ │ ├── hy.gif │ │ ├── id.gif │ │ ├── il.gif │ │ ├── in.gif │ │ ├── io.gif │ │ ├── iq.gif │ │ ├── ir.gif │ │ ├── is.gif │ │ ├── it.gif │ │ ├── ja.gif │ │ ├── jm.gif │ │ ├── jo.gif │ │ ├── ke.gif │ │ ├── kg.gif │ │ ├── kh.gif │ │ ├── ki.gif │ │ ├── km.gif │ │ ├── kn.gif │ │ ├── ko.gif │ │ ├── kp.gif │ │ ├── kw.gif │ │ ├── ky.gif │ │ ├── kz.gif │ │ ├── la.gif │ │ ├── lb.gif │ │ ├── lc.gif │ │ ├── li.gif │ │ ├── lk.gif │ │ ├── lo.gif │ │ ├── lr.gif │ │ ├── ls.gif │ │ ├── lt.gif │ │ ├── lu.gif │ │ ├── lv.gif │ │ ├── ly.gif │ │ ├── ma.gif │ │ ├── mc.gif │ │ ├── md.gif │ │ ├── me.gif │ │ ├── mg.gif │ │ ├── mh.gif │ │ ├── mk.gif │ │ ├── ml.gif │ │ ├── mm.gif │ │ ├── mn.gif │ │ ├── mo.gif │ │ ├── mp.gif │ │ ├── mq.gif │ │ ├── mr.gif │ │ ├── ms.gif │ │ ├── mt.gif │ │ ├── mu.gif │ │ ├── mv.gif │ │ ├── mw.gif │ │ ├── mx.gif │ │ ├── my.gif │ │ ├── mz.gif │ │ ├── na.gif │ │ ├── nb.gif │ │ ├── nc.gif │ │ ├── ne.gif │ │ ├── nf.gif │ │ ├── ng.gif │ │ ├── ni.gif │ │ ├── nl.gif │ │ ├── nn.gif │ │ ├── no.gif │ │ ├── np.gif │ │ ├── nr.gif │ │ ├── nu.gif │ │ ├── nz.gif │ │ ├── om.gif │ │ ├── pa.gif │ │ ├── pe.gif │ │ ├── pf.gif │ │ ├── pg.gif │ │ ├── ph.gif │ │ ├── pk.gif │ │ ├── pl.gif │ │ ├── pm.gif │ │ ├── pn.gif │ │ ├── pr.gif │ │ ├── ps.gif │ │ ├── pt.gif │ │ ├── pw.gif │ │ ├── py.gif │ │ ├── qa.gif │ │ ├── re.gif │ │ ├── ro.gif │ │ ├── rs.gif │ │ ├── ru.gif │ │ ├── rw.gif │ │ ├── sb.gif │ │ ├── sc.gif │ │ ├── scotland.gif │ │ ├── sd.gif │ │ ├── sg.gif │ │ ├── sh.gif │ │ ├── sj.gif │ │ ├── sk.gif │ │ ├── sl.gif │ │ ├── sm.gif │ │ ├── sn.gif │ │ ├── so.gif │ │ ├── sq.gif │ │ ├── sr.gif │ │ ├── st.gif │ │ ├── sv.gif │ │ ├── sy.gif │ │ ├── sz.gif │ │ ├── tc.gif │ │ ├── td.gif │ │ ├── tf.gif │ │ ├── tg.gif │ │ ├── th.gif │ │ ├── tj.gif │ │ ├── tk.gif │ │ ├── tl.gif │ │ ├── tm.gif │ │ ├── tn.gif │ │ ├── to.gif │ │ ├── tr.gif │ │ ├── tt.gif │ │ ├── tv.gif │ │ ├── tz.gif │ │ ├── ug.gif │ │ ├── uk.gif │ │ ├── um.gif │ │ ├── und.gif │ │ ├── uy.gif │ │ ├── uz.gif │ │ ├── vc.gif │ │ ├── ve.gif │ │ ├── vg.gif │ │ ├── vi.gif │ │ ├── vn.gif │ │ ├── vu.gif │ │ ├── wales.gif │ │ ├── wf.gif │ │ ├── ws.gif │ │ ├── ye.gif │ │ ├── yt.gif │ │ ├── za.gif │ │ ├── zh-cn.gif │ │ ├── zh.gif │ │ ├── zho-tw.gif │ │ ├── zm.gif │ │ └── zw.gif │ ├── logo.svg │ ├── logo_small.png │ ├── logo_small.svg │ ├── more.png │ ├── more.svg │ ├── rdf_w3c_icon.48.gif │ └── yuzu.jpg └── html │ ├── download.html │ ├── index.html │ ├── license.html │ ├── list.html │ ├── onboarding.mustache │ ├── page.mustache │ ├── rdf2html.mustache │ ├── search.html │ ├── sparql-results.mustache │ ├── sparql.html │ └── triple.mustache ├── example.nt.gz ├── fix-emn.scala ├── fix-ref-context.scala ├── fix_unicode.scala ├── python ├── README.md ├── common ├── load_db.sh └── yuzu │ ├── __init__.py │ ├── backend.py │ ├── dataid.py │ ├── displayer.py │ ├── jsonld.py │ ├── model.py │ ├── ql │ ├── __init__.py │ ├── model.py │ ├── parse.py │ └── tests.py │ ├── server.py │ ├── settings.py │ ├── test_jsonld.py │ ├── tests.py │ └── user_text.py ├── scala ├── README.md ├── build.sbt ├── jetty-env.xml ├── load_db.sh ├── project │ └── plugins.sbt └── src │ ├── main │ ├── scala │ │ └── yuzu │ │ │ ├── backend.scala │ │ │ ├── dataid.scala │ │ │ ├── jsonld.scala │ │ │ ├── model.scala │ │ │ ├── ql │ │ │ ├── model.scala │ │ │ └── parse.scala │ │ │ ├── server.scala │ │ │ ├── settings.scala │ │ │ ├── sql.scala │ │ │ ├── triple_backend.scala │ │ │ └── user_text.scala │ └── webapp │ │ └── WEB-INF │ │ └── web.xml │ └── test │ └── scala │ └── yuzu │ ├── server_test.scala │ ├── test_jsonld.scala │ ├── test_rdfsql.scala │ └── yuzuql_test.scala └── test_server.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | bin/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # Installer logs 26 | pip-log.txt 27 | pip-delete-this-directory.txt 28 | 29 | # Unit test / coverage reports 30 | htmlcov/ 31 | .tox/ 32 | .coverage 33 | .cache 34 | nosetests.xml 35 | coverage.xml 36 | 37 | # Translations 38 | *.mo 39 | 40 | # Mr Developer 41 | .mr.developer.cfg 42 | .project 43 | .pydevproject 44 | 45 | # Rope 46 | .ropeproject 47 | 48 | # Django stuff: 49 | *.log 50 | *.pot 51 | 52 | # Sphinx documentation 53 | docs/_build/ 54 | 55 | # PyCharm 56 | .idea 57 | 58 | Thumbs.db 59 | db.sqlite 60 | 61 | scala/target 62 | scala/project/target 63 | target 64 | *.swp 65 | scala/linghub.sqlite 66 | linghub.full.nt.gz 67 | example.db 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yuzu 2 | ==== 3 | 4 | Yuzu is a micro-framework for publishing linked data. The goal of yuzu is to provide a small 5 | code base from which it is possible to quickly publish linked data for a variety of purposes. 6 | Yuzu is intended to be customised for any purpose and as such has a small and easy-to-understand 7 | code base. In addition Yuzu is maintained in two languages: Python and Scala 8 | 9 | Requirements 10 | ------------ 11 | 12 | ### Data as a Gzipped N-Triple file 13 | 14 | Yuzu assumes that all data is available as a single Gzipped N-Triples dump file. This is easily 15 | achieved with the `rapper` and `gzip` command as follows: 16 | 17 | rapper -o ntriples myfile.rdf | gzip >> all.nt.gz 18 | 19 | ### Data under a single prefix 20 | 21 | All data hosted as at a Yuzu point must start with the same URI prefix, which 22 | corresponds to the endpoint where the data is hosted. Backlinks are allowed but 23 | either the subject or the object of every triple must start with the given prefix. 24 | That is it is impossible to host triples about a resource with URIs 25 | `http://www.someotherserver.com/` on a Yuzu instance on a server with prefix 26 | `http://www.example.com/`. 27 | 28 | ### A SPARQL endpoint (optional) 29 | 30 | Yuzu does support querying by SPARQL, however the built-in database implementation 31 | is optimized for browsing and faceted search. As such, the querying is often slow 32 | or may fail, if you wish to enable querying from the web you should set up an 33 | external endpoint, for example using [Virtuoso](http://virtuoso.openlinksw.com/) 34 | or [4store](http://4store.org/). 35 | 36 | Installation 37 | ------------ 38 | 39 | Please see [Python](python/README.md) or [Scala](scala/README.md) instructions. 40 | -------------------------------------------------------------------------------- /YuzuQL.md: -------------------------------------------------------------------------------- 1 | YuzuQL - SPARQL as understood by a Yuzu Instance 2 | ================================================ 3 | 4 | Yuzu endpoints support only a small fragment of the 5 | [SPARQL Standard](http://www.w3.org/TR/sparql11-query/) to enable users to 6 | query datasets quickly while maintaing consistent server performance. This 7 | makes it easy for developers to access, develop and mash-up your data 8 | 9 | YuzuQL as a subset of SPARQL 10 | ---------------------------- 11 | 12 | _Developers who are not familiar with SPARQL should skip this section_ 13 | 14 | SPARQL is a W3C standard for querying datasets on the web, however the 15 | standard is of quite high complexity and makes it easy to write queries that 16 | can only be answered with very significant computation. It is quite a common 17 | practice to timeout queries that take too long to execute, however this is 18 | not good for web applications that build on such a method as it may fail 19 | unexpectedly if the server is under load. Instead Yuzu implements a small 20 | subset that we can guarantee is executable in reasonable time. 21 | 22 | YuzuQL relates to other projects such as 23 | [Linked Data Fragments](http://linkeddatafragments.org/) in assuming that 24 | the client should also make some part of the computation, however we note that 25 | the server has indexes of the data that are not available to the client. As 26 | such YuzuQL allows these indexes to be exploited, while still limiting 27 | server load. 28 | 29 | YuzuQL differs from SPARQL in the following way 30 | 31 | * Only `SELECT` queries may be made to the endpoint. Other query types may 32 | easily be simulated by the client, e.g., `ASK` queries should be rewritten 33 | to `SELECT` queries with `LIMIT 1`. 34 | * The query body (`WHERE` clause) is exactly a single triple tree. Many 35 | of the standard keywords, such as `FILTER`, `UNION` or `OPTIONAL` are not 36 | supported. 37 | * In all queries the property must be a URI (i.e., it cannot be a variable), 38 | this guarantees that every part of the query corresponds to some index . 39 | * In most cases, the `LIMIT` keyword is required (Yuzu instances may configure 40 | this but it is not recommended). 41 | 42 | Using YuzuQL 43 | ------------ 44 | 45 | Querying in YuzuQL is performed by URI, for example to query the 46 | [Dublin Core Language](http://purl.org/dc/elements/1.1/language) the following 47 | query is obtained: 48 | 49 | SELECT ?resource WHERE { 50 | ?resource "en" 51 | } LIMIT 100 52 | 53 | It is possible to use a `PREFIX` to abbreviate URIs, however in most cases a 54 | YuzuQL endpoint should know the prefixes it uses: 55 | 56 | PREFIX dc: 57 | SELECT ?resource WHERE { 58 | ?resource dc:language "en" 59 | } LIMIT 100 60 | 61 | Variables are denoted with a `?` (variables with `$` are not permitted) and the 62 | `WHERE` keyword may be omitted. Furthermore, all keywords are case-insensitive 63 | and a `*` may be used to select all variables: 64 | 65 | select * { 66 | ?resource dc:language "en" 67 | } limit 100 68 | 69 | You may search for multiple properties simultaneously by combining the queries 70 | with a `;` as follows: 71 | 72 | select * { 73 | ?resource dc:language ?language ; 74 | dc:type ?type 75 | } limit 100 76 | 77 | You may also query for multiple values of a property, note this only returns 78 | resource that have all values: 79 | 80 | select * { 81 | ?resource dcat:keyword "lexicon", "English" 82 | } limit 100 83 | 84 | If a literal has a language or a datatype it must be specified with `@` or 85 | `^^`: 86 | 87 | select * { 88 | ?resource rdfs:label "A label"@en ; 89 | dc:issued "2014-01-31"^^ . 90 | } limit 100 91 | 92 | The class of an element may be queried by the special property `a` (this is an 93 | abbreviation for ``): 94 | 95 | select * { 96 | ?resource a skos:Concept 97 | } limit 100 98 | 99 | You may query sub-sections of the data by means of the `[]` (note this is 100 | technically a 'blank node' which in this context is treated as an 101 | anonymous variable): 102 | 103 | select * { 104 | ?resource void:subset [ 105 | a void:LinkSet ; 106 | void:triples ?triples ] 107 | } 108 | 109 | If not enough results are returned by the first query then the `OFFSET` keyword 110 | can be used to obtain the next selection of results: 111 | 112 | select * { 113 | ?resource dc:language ?language ; 114 | dc:type ?type 115 | } limit 100 offset 100 116 | 117 | Results may be sorted by the use of an `ORDER BY` clause, where the results will 118 | be sorted by the literal order (other order may be supported at some point 119 | in the future): 120 | 121 | select ?resource { 122 | ?resource dc:issued ?date . 123 | } limit 100 order by str(?date) 124 | 125 | The `ASC` and `DESC` keywords indicate if a query is ascending or descending: 126 | 127 | select ?resource { 128 | ?resource dc:issued ?date ; 129 | dc:modified ?date2 130 | } limit 100 order by desc(str(?date)) asc(str(?date2)) 131 | 132 | In addition to returning the resources matching a resource it is possible to 133 | return the counts of resources as follows 134 | 135 | select (count(*) as ?count) { 136 | ?resource dc:language "en" 137 | } limit 1 138 | 139 | It is also possible to count according to a value of a resource, for example 140 | to provide counts by language the following query is used 141 | 142 | select (count(*) as ?count) ?languge { 143 | ?resource dc:language ?language 144 | } limit 100 group by ?language 145 | 146 | Note that in contrast to full SPARQL the count variable can only count the 147 | number of hits, and there can only be one count which must be the first 148 | specified variable. 149 | 150 | Finally, there are two non-standard extensions to SPARQL support by YuzuQL 151 | endpoints, firstly you may specify an alternative value with the `|` operator: 152 | 153 | select ?language { 154 | ?resource dc:language ?language | 155 | lvont:language ?language 156 | } limit 100 157 | 158 | NB. The set of variables used in the alternatives must be the same. 159 | 160 | This is equivalent to the following standard SPARQL query: 161 | 162 | select ?language { 163 | { 164 | ?resource dc:language ?language 165 | } union { 166 | ?resource lvont:language ?language 167 | } 168 | } limit 100 169 | 170 | Secondly a property query may be made optional by surrounding it with `()`. 171 | This may only be done after a `;`: 172 | 173 | select ?resource ?label { 174 | ?resource dc:languge "en" ; 175 | (rdfs:label ?label) 176 | } limit 100 177 | 178 | This is equivalent to the following standard SPARQL query: 179 | 180 | select ?resource ?label { 181 | ?resource dc:language "en" . 182 | optional { 183 | rdfs:label ?label 184 | } 185 | } limit 100 186 | 187 | Result Format 188 | ============= 189 | 190 | By default the results are returned using 191 | [SPARQL JSON Results](http://www.w3.org/TR/sparql11-results-json/). Other 192 | formats such as XML may be queried by setting the `Accept` header (this 193 | is the reason that HTML results are shown in a browser). A simple example 194 | of how to call a server using [jQuery](http://jquery.com) is given as follows: 195 | 196 | var query = "select * { ?s rdfs:label ?l } limit 3"; 197 | jQuery.getJSON("http://localhost:8080/sparql/?query=" + encodeURI(query), 198 | function(data) { 199 | data.results.bindings.forEach(function(result) { 200 | alert(result.s.value + " = " + result.l.value); 201 | }); 202 | }); 203 | -------------------------------------------------------------------------------- /common/assets/cc/by-nc-nd.eu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/by-nc-nd.eu.png -------------------------------------------------------------------------------- /common/assets/cc/by-nc-nd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/by-nc-nd.png -------------------------------------------------------------------------------- /common/assets/cc/by-nc-sa.eu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/by-nc-sa.eu.png -------------------------------------------------------------------------------- /common/assets/cc/by-nc-sa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/by-nc-sa.png -------------------------------------------------------------------------------- /common/assets/cc/by-nc.eu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/by-nc.eu.png -------------------------------------------------------------------------------- /common/assets/cc/by-nc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/by-nc.png -------------------------------------------------------------------------------- /common/assets/cc/by-nd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/by-nd.png -------------------------------------------------------------------------------- /common/assets/cc/by-sa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/by-sa.png -------------------------------------------------------------------------------- /common/assets/cc/by.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/by.png -------------------------------------------------------------------------------- /common/assets/cc/cc-zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/cc-zero.png -------------------------------------------------------------------------------- /common/assets/cc/publicdomain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/cc/publicdomain.png -------------------------------------------------------------------------------- /common/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/favicon.ico -------------------------------------------------------------------------------- /common/assets/flag/ad.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ad.gif -------------------------------------------------------------------------------- /common/assets/flag/ae.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ae.gif -------------------------------------------------------------------------------- /common/assets/flag/af.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/af.gif -------------------------------------------------------------------------------- /common/assets/flag/ag.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ag.gif -------------------------------------------------------------------------------- /common/assets/flag/ai.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ai.gif -------------------------------------------------------------------------------- /common/assets/flag/al.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/al.gif -------------------------------------------------------------------------------- /common/assets/flag/am.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/am.gif -------------------------------------------------------------------------------- /common/assets/flag/an.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/an.gif -------------------------------------------------------------------------------- /common/assets/flag/ao.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ao.gif -------------------------------------------------------------------------------- /common/assets/flag/ar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ar.gif -------------------------------------------------------------------------------- /common/assets/flag/ar2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ar2.gif -------------------------------------------------------------------------------- /common/assets/flag/as.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/as.gif -------------------------------------------------------------------------------- /common/assets/flag/at.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/at.gif -------------------------------------------------------------------------------- /common/assets/flag/au.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/au.gif -------------------------------------------------------------------------------- /common/assets/flag/aw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/aw.gif -------------------------------------------------------------------------------- /common/assets/flag/ax.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ax.gif -------------------------------------------------------------------------------- /common/assets/flag/az.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/az.gif -------------------------------------------------------------------------------- /common/assets/flag/ba.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ba.gif -------------------------------------------------------------------------------- /common/assets/flag/basque.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/basque.gif -------------------------------------------------------------------------------- /common/assets/flag/basque.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/basque.png -------------------------------------------------------------------------------- /common/assets/flag/bb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bb.gif -------------------------------------------------------------------------------- /common/assets/flag/be.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/be.gif -------------------------------------------------------------------------------- /common/assets/flag/bf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bf.gif -------------------------------------------------------------------------------- /common/assets/flag/bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bg.gif -------------------------------------------------------------------------------- /common/assets/flag/bh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bh.gif -------------------------------------------------------------------------------- /common/assets/flag/bi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bi.gif -------------------------------------------------------------------------------- /common/assets/flag/bj.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bj.gif -------------------------------------------------------------------------------- /common/assets/flag/bm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bm.gif -------------------------------------------------------------------------------- /common/assets/flag/bn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bn.gif -------------------------------------------------------------------------------- /common/assets/flag/bo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bo.gif -------------------------------------------------------------------------------- /common/assets/flag/br.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/br.gif -------------------------------------------------------------------------------- /common/assets/flag/bs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bs.gif -------------------------------------------------------------------------------- /common/assets/flag/bt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bt.gif -------------------------------------------------------------------------------- /common/assets/flag/bv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bv.gif -------------------------------------------------------------------------------- /common/assets/flag/bw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bw.gif -------------------------------------------------------------------------------- /common/assets/flag/by.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/by.gif -------------------------------------------------------------------------------- /common/assets/flag/bz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/bz.gif -------------------------------------------------------------------------------- /common/assets/flag/ca.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ca.gif -------------------------------------------------------------------------------- /common/assets/flag/catalonia.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/catalonia.gif -------------------------------------------------------------------------------- /common/assets/flag/cc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cc.gif -------------------------------------------------------------------------------- /common/assets/flag/cd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cd.gif -------------------------------------------------------------------------------- /common/assets/flag/cf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cf.gif -------------------------------------------------------------------------------- /common/assets/flag/cg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cg.gif -------------------------------------------------------------------------------- /common/assets/flag/ch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ch.gif -------------------------------------------------------------------------------- /common/assets/flag/ci.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ci.gif -------------------------------------------------------------------------------- /common/assets/flag/ck.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ck.gif -------------------------------------------------------------------------------- /common/assets/flag/cl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cl.gif -------------------------------------------------------------------------------- /common/assets/flag/cm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cm.gif -------------------------------------------------------------------------------- /common/assets/flag/co.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/co.gif -------------------------------------------------------------------------------- /common/assets/flag/cr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cr.gif -------------------------------------------------------------------------------- /common/assets/flag/cs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cs.gif -------------------------------------------------------------------------------- /common/assets/flag/cu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cu.gif -------------------------------------------------------------------------------- /common/assets/flag/cv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cv.gif -------------------------------------------------------------------------------- /common/assets/flag/cx.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cx.gif -------------------------------------------------------------------------------- /common/assets/flag/cy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/cy.gif -------------------------------------------------------------------------------- /common/assets/flag/da.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/da.gif -------------------------------------------------------------------------------- /common/assets/flag/de.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/de.gif -------------------------------------------------------------------------------- /common/assets/flag/dj.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/dj.gif -------------------------------------------------------------------------------- /common/assets/flag/dm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/dm.gif -------------------------------------------------------------------------------- /common/assets/flag/do.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/do.gif -------------------------------------------------------------------------------- /common/assets/flag/dz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/dz.gif -------------------------------------------------------------------------------- /common/assets/flag/ec.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ec.gif -------------------------------------------------------------------------------- /common/assets/flag/eg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/eg.gif -------------------------------------------------------------------------------- /common/assets/flag/eh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/eh.gif -------------------------------------------------------------------------------- /common/assets/flag/el.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/el.gif -------------------------------------------------------------------------------- /common/assets/flag/en-gb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/en-gb.gif -------------------------------------------------------------------------------- /common/assets/flag/en-us.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/en-us.gif -------------------------------------------------------------------------------- /common/assets/flag/en.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/en.gif -------------------------------------------------------------------------------- /common/assets/flag/eng.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/eng.gif -------------------------------------------------------------------------------- /common/assets/flag/england.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/england.gif -------------------------------------------------------------------------------- /common/assets/flag/er.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/er.gif -------------------------------------------------------------------------------- /common/assets/flag/es.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/es.gif -------------------------------------------------------------------------------- /common/assets/flag/et.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/et.gif -------------------------------------------------------------------------------- /common/assets/flag/eu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/eu.gif -------------------------------------------------------------------------------- /common/assets/flag/europeanunion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/europeanunion.gif -------------------------------------------------------------------------------- /common/assets/flag/fam.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/fam.gif -------------------------------------------------------------------------------- /common/assets/flag/fi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/fi.gif -------------------------------------------------------------------------------- /common/assets/flag/fj.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/fj.gif -------------------------------------------------------------------------------- /common/assets/flag/fk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/fk.gif -------------------------------------------------------------------------------- /common/assets/flag/fm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/fm.gif -------------------------------------------------------------------------------- /common/assets/flag/fo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/fo.gif -------------------------------------------------------------------------------- /common/assets/flag/fr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/fr.gif -------------------------------------------------------------------------------- /common/assets/flag/ga.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ga.gif -------------------------------------------------------------------------------- /common/assets/flag/galicia.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/galicia.gif -------------------------------------------------------------------------------- /common/assets/flag/gd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gd.gif -------------------------------------------------------------------------------- /common/assets/flag/ge.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ge.gif -------------------------------------------------------------------------------- /common/assets/flag/gf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gf.gif -------------------------------------------------------------------------------- /common/assets/flag/gh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gh.gif -------------------------------------------------------------------------------- /common/assets/flag/gi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gi.gif -------------------------------------------------------------------------------- /common/assets/flag/gl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gl.gif -------------------------------------------------------------------------------- /common/assets/flag/gm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gm.gif -------------------------------------------------------------------------------- /common/assets/flag/gn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gn.gif -------------------------------------------------------------------------------- /common/assets/flag/gp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gp.gif -------------------------------------------------------------------------------- /common/assets/flag/gq.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gq.gif -------------------------------------------------------------------------------- /common/assets/flag/gs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gs.gif -------------------------------------------------------------------------------- /common/assets/flag/gt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gt.gif -------------------------------------------------------------------------------- /common/assets/flag/gu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gu.gif -------------------------------------------------------------------------------- /common/assets/flag/gw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gw.gif -------------------------------------------------------------------------------- /common/assets/flag/gy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/gy.gif -------------------------------------------------------------------------------- /common/assets/flag/he.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/he.gif -------------------------------------------------------------------------------- /common/assets/flag/hk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/hk.gif -------------------------------------------------------------------------------- /common/assets/flag/hm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/hm.gif -------------------------------------------------------------------------------- /common/assets/flag/hn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/hn.gif -------------------------------------------------------------------------------- /common/assets/flag/hr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/hr.gif -------------------------------------------------------------------------------- /common/assets/flag/ht.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ht.gif -------------------------------------------------------------------------------- /common/assets/flag/hu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/hu.gif -------------------------------------------------------------------------------- /common/assets/flag/hy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/hy.gif -------------------------------------------------------------------------------- /common/assets/flag/id.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/id.gif -------------------------------------------------------------------------------- /common/assets/flag/il.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/il.gif -------------------------------------------------------------------------------- /common/assets/flag/in.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/in.gif -------------------------------------------------------------------------------- /common/assets/flag/io.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/io.gif -------------------------------------------------------------------------------- /common/assets/flag/iq.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/iq.gif -------------------------------------------------------------------------------- /common/assets/flag/ir.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ir.gif -------------------------------------------------------------------------------- /common/assets/flag/is.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/is.gif -------------------------------------------------------------------------------- /common/assets/flag/it.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/it.gif -------------------------------------------------------------------------------- /common/assets/flag/ja.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ja.gif -------------------------------------------------------------------------------- /common/assets/flag/jm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/jm.gif -------------------------------------------------------------------------------- /common/assets/flag/jo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/jo.gif -------------------------------------------------------------------------------- /common/assets/flag/ke.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ke.gif -------------------------------------------------------------------------------- /common/assets/flag/kg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/kg.gif -------------------------------------------------------------------------------- /common/assets/flag/kh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/kh.gif -------------------------------------------------------------------------------- /common/assets/flag/ki.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ki.gif -------------------------------------------------------------------------------- /common/assets/flag/km.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/km.gif -------------------------------------------------------------------------------- /common/assets/flag/kn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/kn.gif -------------------------------------------------------------------------------- /common/assets/flag/ko.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ko.gif -------------------------------------------------------------------------------- /common/assets/flag/kp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/kp.gif -------------------------------------------------------------------------------- /common/assets/flag/kw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/kw.gif -------------------------------------------------------------------------------- /common/assets/flag/ky.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ky.gif -------------------------------------------------------------------------------- /common/assets/flag/kz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/kz.gif -------------------------------------------------------------------------------- /common/assets/flag/la.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/la.gif -------------------------------------------------------------------------------- /common/assets/flag/lb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/lb.gif -------------------------------------------------------------------------------- /common/assets/flag/lc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/lc.gif -------------------------------------------------------------------------------- /common/assets/flag/li.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/li.gif -------------------------------------------------------------------------------- /common/assets/flag/lk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/lk.gif -------------------------------------------------------------------------------- /common/assets/flag/lo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/lo.gif -------------------------------------------------------------------------------- /common/assets/flag/lr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/lr.gif -------------------------------------------------------------------------------- /common/assets/flag/ls.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ls.gif -------------------------------------------------------------------------------- /common/assets/flag/lt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/lt.gif -------------------------------------------------------------------------------- /common/assets/flag/lu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/lu.gif -------------------------------------------------------------------------------- /common/assets/flag/lv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/lv.gif -------------------------------------------------------------------------------- /common/assets/flag/ly.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ly.gif -------------------------------------------------------------------------------- /common/assets/flag/ma.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ma.gif -------------------------------------------------------------------------------- /common/assets/flag/mc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mc.gif -------------------------------------------------------------------------------- /common/assets/flag/md.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/md.gif -------------------------------------------------------------------------------- /common/assets/flag/me.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/me.gif -------------------------------------------------------------------------------- /common/assets/flag/mg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mg.gif -------------------------------------------------------------------------------- /common/assets/flag/mh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mh.gif -------------------------------------------------------------------------------- /common/assets/flag/mk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mk.gif -------------------------------------------------------------------------------- /common/assets/flag/ml.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ml.gif -------------------------------------------------------------------------------- /common/assets/flag/mm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mm.gif -------------------------------------------------------------------------------- /common/assets/flag/mn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mn.gif -------------------------------------------------------------------------------- /common/assets/flag/mo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mo.gif -------------------------------------------------------------------------------- /common/assets/flag/mp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mp.gif -------------------------------------------------------------------------------- /common/assets/flag/mq.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mq.gif -------------------------------------------------------------------------------- /common/assets/flag/mr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mr.gif -------------------------------------------------------------------------------- /common/assets/flag/ms.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ms.gif -------------------------------------------------------------------------------- /common/assets/flag/mt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mt.gif -------------------------------------------------------------------------------- /common/assets/flag/mu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mu.gif -------------------------------------------------------------------------------- /common/assets/flag/mv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mv.gif -------------------------------------------------------------------------------- /common/assets/flag/mw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mw.gif -------------------------------------------------------------------------------- /common/assets/flag/mx.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mx.gif -------------------------------------------------------------------------------- /common/assets/flag/my.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/my.gif -------------------------------------------------------------------------------- /common/assets/flag/mz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/mz.gif -------------------------------------------------------------------------------- /common/assets/flag/na.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/na.gif -------------------------------------------------------------------------------- /common/assets/flag/nb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/nb.gif -------------------------------------------------------------------------------- /common/assets/flag/nc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/nc.gif -------------------------------------------------------------------------------- /common/assets/flag/ne.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ne.gif -------------------------------------------------------------------------------- /common/assets/flag/nf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/nf.gif -------------------------------------------------------------------------------- /common/assets/flag/ng.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ng.gif -------------------------------------------------------------------------------- /common/assets/flag/ni.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ni.gif -------------------------------------------------------------------------------- /common/assets/flag/nl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/nl.gif -------------------------------------------------------------------------------- /common/assets/flag/nn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/nn.gif -------------------------------------------------------------------------------- /common/assets/flag/no.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/no.gif -------------------------------------------------------------------------------- /common/assets/flag/np.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/np.gif -------------------------------------------------------------------------------- /common/assets/flag/nr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/nr.gif -------------------------------------------------------------------------------- /common/assets/flag/nu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/nu.gif -------------------------------------------------------------------------------- /common/assets/flag/nz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/nz.gif -------------------------------------------------------------------------------- /common/assets/flag/om.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/om.gif -------------------------------------------------------------------------------- /common/assets/flag/pa.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pa.gif -------------------------------------------------------------------------------- /common/assets/flag/pe.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pe.gif -------------------------------------------------------------------------------- /common/assets/flag/pf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pf.gif -------------------------------------------------------------------------------- /common/assets/flag/pg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pg.gif -------------------------------------------------------------------------------- /common/assets/flag/ph.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ph.gif -------------------------------------------------------------------------------- /common/assets/flag/pk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pk.gif -------------------------------------------------------------------------------- /common/assets/flag/pl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pl.gif -------------------------------------------------------------------------------- /common/assets/flag/pm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pm.gif -------------------------------------------------------------------------------- /common/assets/flag/pn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pn.gif -------------------------------------------------------------------------------- /common/assets/flag/pr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pr.gif -------------------------------------------------------------------------------- /common/assets/flag/ps.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ps.gif -------------------------------------------------------------------------------- /common/assets/flag/pt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pt.gif -------------------------------------------------------------------------------- /common/assets/flag/pw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/pw.gif -------------------------------------------------------------------------------- /common/assets/flag/py.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/py.gif -------------------------------------------------------------------------------- /common/assets/flag/qa.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/qa.gif -------------------------------------------------------------------------------- /common/assets/flag/re.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/re.gif -------------------------------------------------------------------------------- /common/assets/flag/ro.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ro.gif -------------------------------------------------------------------------------- /common/assets/flag/rs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/rs.gif -------------------------------------------------------------------------------- /common/assets/flag/ru.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ru.gif -------------------------------------------------------------------------------- /common/assets/flag/rw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/rw.gif -------------------------------------------------------------------------------- /common/assets/flag/sb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sb.gif -------------------------------------------------------------------------------- /common/assets/flag/sc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sc.gif -------------------------------------------------------------------------------- /common/assets/flag/scotland.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/scotland.gif -------------------------------------------------------------------------------- /common/assets/flag/sd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sd.gif -------------------------------------------------------------------------------- /common/assets/flag/sg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sg.gif -------------------------------------------------------------------------------- /common/assets/flag/sh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sh.gif -------------------------------------------------------------------------------- /common/assets/flag/sj.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sj.gif -------------------------------------------------------------------------------- /common/assets/flag/sk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sk.gif -------------------------------------------------------------------------------- /common/assets/flag/sl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sl.gif -------------------------------------------------------------------------------- /common/assets/flag/sm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sm.gif -------------------------------------------------------------------------------- /common/assets/flag/sn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sn.gif -------------------------------------------------------------------------------- /common/assets/flag/so.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/so.gif -------------------------------------------------------------------------------- /common/assets/flag/sq.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sq.gif -------------------------------------------------------------------------------- /common/assets/flag/sr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sr.gif -------------------------------------------------------------------------------- /common/assets/flag/st.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/st.gif -------------------------------------------------------------------------------- /common/assets/flag/sv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sv.gif -------------------------------------------------------------------------------- /common/assets/flag/sy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sy.gif -------------------------------------------------------------------------------- /common/assets/flag/sz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/sz.gif -------------------------------------------------------------------------------- /common/assets/flag/tc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tc.gif -------------------------------------------------------------------------------- /common/assets/flag/td.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/td.gif -------------------------------------------------------------------------------- /common/assets/flag/tf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tf.gif -------------------------------------------------------------------------------- /common/assets/flag/tg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tg.gif -------------------------------------------------------------------------------- /common/assets/flag/th.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/th.gif -------------------------------------------------------------------------------- /common/assets/flag/tj.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tj.gif -------------------------------------------------------------------------------- /common/assets/flag/tk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tk.gif -------------------------------------------------------------------------------- /common/assets/flag/tl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tl.gif -------------------------------------------------------------------------------- /common/assets/flag/tm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tm.gif -------------------------------------------------------------------------------- /common/assets/flag/tn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tn.gif -------------------------------------------------------------------------------- /common/assets/flag/to.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/to.gif -------------------------------------------------------------------------------- /common/assets/flag/tr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tr.gif -------------------------------------------------------------------------------- /common/assets/flag/tt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tt.gif -------------------------------------------------------------------------------- /common/assets/flag/tv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tv.gif -------------------------------------------------------------------------------- /common/assets/flag/tz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/tz.gif -------------------------------------------------------------------------------- /common/assets/flag/ug.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ug.gif -------------------------------------------------------------------------------- /common/assets/flag/uk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/uk.gif -------------------------------------------------------------------------------- /common/assets/flag/um.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/um.gif -------------------------------------------------------------------------------- /common/assets/flag/und.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/und.gif -------------------------------------------------------------------------------- /common/assets/flag/uy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/uy.gif -------------------------------------------------------------------------------- /common/assets/flag/uz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/uz.gif -------------------------------------------------------------------------------- /common/assets/flag/vc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/vc.gif -------------------------------------------------------------------------------- /common/assets/flag/ve.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ve.gif -------------------------------------------------------------------------------- /common/assets/flag/vg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/vg.gif -------------------------------------------------------------------------------- /common/assets/flag/vi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/vi.gif -------------------------------------------------------------------------------- /common/assets/flag/vn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/vn.gif -------------------------------------------------------------------------------- /common/assets/flag/vu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/vu.gif -------------------------------------------------------------------------------- /common/assets/flag/wales.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/wales.gif -------------------------------------------------------------------------------- /common/assets/flag/wf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/wf.gif -------------------------------------------------------------------------------- /common/assets/flag/ws.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ws.gif -------------------------------------------------------------------------------- /common/assets/flag/ye.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/ye.gif -------------------------------------------------------------------------------- /common/assets/flag/yt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/yt.gif -------------------------------------------------------------------------------- /common/assets/flag/za.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/za.gif -------------------------------------------------------------------------------- /common/assets/flag/zh-cn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/zh-cn.gif -------------------------------------------------------------------------------- /common/assets/flag/zh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/zh.gif -------------------------------------------------------------------------------- /common/assets/flag/zho-tw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/zho-tw.gif -------------------------------------------------------------------------------- /common/assets/flag/zm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/zm.gif -------------------------------------------------------------------------------- /common/assets/flag/zw.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/flag/zw.gif -------------------------------------------------------------------------------- /common/assets/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/logo_small.png -------------------------------------------------------------------------------- /common/assets/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/more.png -------------------------------------------------------------------------------- /common/assets/more.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 27 | 32 | 33 | 40 | 45 | 46 | 53 | 58 | 59 | 66 | 71 | 72 | 75 | 82 | 83 | 86 | 93 | 94 | 95 | 113 | 115 | 116 | 118 | image/svg+xml 119 | 121 | 122 | 123 | 124 | 125 | 129 | 138 | 146 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /common/assets/rdf_w3c_icon.48.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/rdf_w3c_icon.48.gif -------------------------------------------------------------------------------- /common/assets/yuzu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/common/assets/yuzu.jpg -------------------------------------------------------------------------------- /common/html/download.html: -------------------------------------------------------------------------------- 1 |

Downloads

2 | 3 |

A complete download of this resource is available here:

4 | 5 | 8 | -------------------------------------------------------------------------------- /common/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 |
7 |
8 |

Simple, light-weight linked data hosting

9 |

Browse

10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search 19 |
20 |
21 | 22 | 28 |
29 |
30 |
31 |
32 | 33 |
34 |
35 |
36 |
37 | 38 | Advanced Search 39 |
40 |
41 | 42 |
43 |
44 |
45 | 46 | -------------------------------------------------------------------------------- /common/html/license.html: -------------------------------------------------------------------------------- 1 |

License Information

2 | 3 |

This resource is has been made available in the public domains as 4 | Creative Commons 5 | Zero resource. This resource has been dedicated to the public domain 6 | and all rights to the work worldwide under copyright law, 7 | including all related and neighboring rights, to the extent allowed by law. 8 | 9 | You can copy, modify, distribute and perform the work, even for commercial 10 | purposes, all without asking permission. 11 | -------------------------------------------------------------------------------- /common/html/list.html: -------------------------------------------------------------------------------- 1 | 2 |

Index

3 | 4 |
5 |
6 |
7 |

List by:

8 |
9 | {{#facets}} 10 | {{label}} 11 | {{#values?}} 12 |
13 | {{/values?}} 14 | {{#values}} 15 | {{value}} ({{count}}) 16 | {{/values}} 17 | {{#more_values}} 18 | More values... 19 | {{/more_values}} 20 | {{#values?}} 21 |
22 | {{/values?}} 23 | {{/facets}} 24 |
25 |
26 |
27 | {{#results}} 28 |
29 | 30 | 31 | {{#model}} 32 | {{#triples}} 33 | 34 | 39 | 62 | 63 | 64 | 65 | 70 | 71 | {{/triples}} 72 | {{/model}} 73 |
35 | {{#prop}} 36 | {{display}} 37 | {{/prop}} 38 | 40 | {{#obj}}{{#elem}} 41 | {{#literal}} 42 | {{display}} 44 | {{#lang}} 45 | 46 | {{/lang}} 47 | {{#datatype}} 48 | {{display}} 49 | {{/datatype}} 50 | {{/literal}} 51 | {{^literal}} 52 | {{#bnode}} 53 | Anonymous Node 54 | {{/bnode}} 55 | {{^bnode}} 56 | {{display}} 57 | {{/bnode}} 58 | {{/literal}} 59 | {{/elem}} 60 | {{^last}} 61 |
66 | 67 | {{/last}} 68 | {{/obj}} 69 |
74 |
75 | {{/results}} 76 |
77 |
78 |
79 |
80 | << 81 | {{pages}} 82 | >> 83 |
84 | -------------------------------------------------------------------------------- /common/html/page.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{title}} 6 | 7 | 8 | 9 | 10 | 107 | 115 | 116 | 117 | 118 | 126 |
127 |
128 | 134 | {{#is_test}} 135 |
136 |

This is a Test Instance

137 |

The URL used to access this instance does not correspond to the configuration.

138 |
139 | {{/is_test}} 140 | {{{content}}} 141 |
142 |
143 | 144 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /common/html/rdf2html.mustache: -------------------------------------------------------------------------------- 1 |
2 | {{#head}} 3 |

{{display}}

4 | 5 | 17 |
18 | {{#classOf}} 19 |
Instance of: {{display}}
20 | {{/classOf}} 21 | 22 | {{#triples}} 23 | {{^has_triples}} 24 | {{> triple}} 25 | {{/has_triples}} 26 | {{/triples}} 27 | {{#inverses}} 28 | 29 | 34 | 41 | 42 | 43 | 44 | 48 | 49 | {{/inverses}} 50 | 51 |
30 | {{#prop}} 31 | Is {{display}} of 32 | {{/prop}} 33 | 35 | {{#obj}} 36 | {{#elem}} 37 | {{display}} 38 | {{/elem}} 39 | {{^last}} 40 |
45 | {{/last}} 46 | {{/obj}} 47 |
52 | 53 | {{#triples}} 54 | {{#has_triples}} 55 | {{#prop}} 56 |

{{display}}

57 | {{/prop}} 58 | {{#obj}} 59 | 60 | 61 | 62 | {{#elem}} 63 | {{#triples}} 64 | {{> triple}} 65 | {{/triples}} 66 | {{/elem}} 67 |
68 | {{/obj}} 69 | {{/has_triples}} 70 | {{/triples}} 71 | {{/head}} 72 | {{#tail}} 73 |

{{display}}

74 | {{#classOf}} 75 |
Instance of: {{display}}
76 | {{/classOf}} 77 | 78 | {{#triples}} 79 | {{^has_triples}} 80 | {{> triple}} 81 | {{/has_triples}} 82 | {{/triples}} 83 | {{#inverses}} 84 | 85 | 90 | 97 | 98 | 99 | 100 | 104 | 105 | {{/inverses}} 106 | 107 |
86 | {{#prop}} 87 | Is {{display}} of 88 | {{/prop}} 89 | 91 | {{#obj}} 92 | {{#elem}} 93 | {{display}} 94 | {{/elem}} 95 | {{^last}} 96 |
101 | {{/last}} 102 | {{/obj}} 103 |
108 | 109 | {{#triples}} 110 | {{#has_triples}} 111 | {{#prop}} 112 |

{{display}}

113 | {{/prop}} 114 | {{#obj}} 115 | 116 | 117 | 118 | {{#elem}} 119 | {{#triples}} 120 | {{> triple}} 121 | {{/triples}} 122 | {{/elem}} 123 |
124 | {{/obj}} 125 | {{/has_triples}} 126 | {{/triples}} 127 | {{/tail}} 128 | -------------------------------------------------------------------------------- /common/html/search.html: -------------------------------------------------------------------------------- 1 |

Search Results

2 | {{^results}} 3 | No Results 4 | {{/results}} 5 | {{#results}} 6 |
7 | 8 | 9 | {{#model}} 10 | {{#triples}} 11 | 12 | 17 | 40 | 41 | 42 | 43 | 48 | 49 | {{/triples}} 50 | {{/model}} 51 |
13 | {{#prop}} 14 | {{display}} 15 | {{/prop}} 16 | 18 | {{#obj}}{{#elem}} 19 | {{#literal}} 20 | {{display}} 22 | {{#lang}} 23 | 24 | {{/lang}} 25 | {{#datatype}} 26 | {{display}} 27 | {{/datatype}} 28 | {{/literal}} 29 | {{^literal}} 30 | {{#bnode}} 31 | Anonymous Node 32 | {{/bnode}} 33 | {{^bnode}} 34 | {{display}} 35 | {{/bnode}} 36 | {{/literal}} 37 | {{/elem}} 38 | {{^last}} 39 |
44 | 45 | {{/last}} 46 | {{/obj}} 47 |
52 |
53 | {{/results}} 54 |
55 |
56 |
57 | << 58 | {{pages}} 59 | >> 60 |
61 | -------------------------------------------------------------------------------- /common/html/sparql-results.mustache: -------------------------------------------------------------------------------- 1 |

SPARQL Results

2 | 3 | {{#boolean}} 4 |

{{boolean}}

5 | {{/boolean}} 6 | {{^boolean}} 7 | 8 | 9 | {{#variables}} 10 | 11 | {{/variables}} 12 | 13 | {{#results}} 14 | 15 | {{#result}} 16 | 33 | {{/result}} 34 | 35 | {{/results}} 36 |
{{name}}
17 | {{#uri}} 18 | {{display}} 19 | {{/uri}} 20 | {{#value}} 21 | {{value}} 22 | {{/value}} 23 | {{#lang}} 24 | 25 | {{/lang}} 26 | {{#datatype}} 27 | {{display}} 28 | {{/datatype}} 29 | {{#bnode}} 30 | Anonymous Node 31 | {{/bnode}} 32 |
37 | {{/boolean}} 38 | -------------------------------------------------------------------------------- /common/html/sparql.html: -------------------------------------------------------------------------------- 1 |

Advanced Search

2 | 3 |
4 |
5 | SPARQL Search 6 |
7 | 8 |
9 | 12 |
13 |
14 |
15 |
16 | 17 |
18 |
19 |
20 |
21 | 22 |

Note this endpoint only supports a subset of SPARQL defined 23 | here

24 | 25 | -------------------------------------------------------------------------------- /common/html/triple.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{#prop}} 5 | {{display}} 6 | {{/prop}} 7 | 8 | 9 | {{#obj}} 10 | {{#elem}} 11 | {{#has_triples}} 12 | 13 | 14 | {{#triples}} 15 | {{> triple}} 16 | {{/triples}} 17 |
18 |
19 | {{/has_triples}} 20 | {{^has_triples}} 21 | {{#literal}} 22 | {{display}} 24 | {{#lang}} 25 | 26 | 27 | 28 | 29 | {{/lang}} 30 | {{#datatype}} 31 | 32 | 33 | 34 | {{display}} 35 | {{/datatype}} 36 | {{^lang}} 37 | {{^datatype}} 38 | 39 | 40 | 41 | {{/datatype}} 42 | {{/lang}} 43 | {{/literal}} 44 | {{^literal}} 45 | {{#bnode}} 46 | Anonymous Node 47 | {{/bnode}} 48 | {{^bnode}} 49 | {{display}} 50 | 51 | 52 | 53 | {{/bnode}} 54 | {{/literal}} 55 | {{/has_triples}} 56 | {{/elem}} 57 | {{^last}} 58 | 59 | 60 | 61 | 62 | 63 | {{/last}} 64 | {{/obj}} 65 | 66 | 67 | -------------------------------------------------------------------------------- /example.nt.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmccrae/yuzu/1e3fdb70aa289a817cc04f45942104d8a3045fcf/example.nt.gz -------------------------------------------------------------------------------- /fix-emn.scala: -------------------------------------------------------------------------------- 1 | for(line <- io.Source.stdin.getLines) { 2 | val elems = line.split(" ") 3 | if(elems(1) == "") { 4 | var obj = elems.drop(2).dropRight(1).mkString(" ") 5 | obj = obj.replaceAll("\\\\[u]","u") 6 | val lang = elems(0).drop(" \"%s\" ." format (elems(0), lang)) 9 | } else { 10 | println(line) 11 | } 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /fix-ref-context.scala: -------------------------------------------------------------------------------- 1 | var last = "" 2 | 3 | for(line <- io.Source.stdin.getLines) { 4 | val elems = line.split(" ") 5 | if(elems(1) == "") { 6 | val obj = elems(2).takeWhile(_ != '#') 7 | println("%s %s %s> ." format (elems(0), elems(1), obj)) 8 | if(obj != last) { 9 | val label = elems(2).drop(elems(2).lastIndexOf('/') + 1).takeWhile(_ != '#').replaceAll("_", " ") 10 | println("%s> \"%s\"@en ." format 11 | (elems(2).takeWhile(_ != '#'), label)) 12 | last = obj 13 | } 14 | } else { 15 | println(line) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /fix_unicode.scala: -------------------------------------------------------------------------------- 1 | val regex = java.util.regex.Pattern.compile("""%5Cu([0-9abcdefABCDEF]{4})""") 2 | 3 | for(line <- io.Source.stdin.getLines()) { 4 | var l = line 5 | var m = regex.matcher(line) 6 | while(m.find()) { 7 | val c = Integer.parseInt(m.group(1), 16).toChar.toString 8 | l = m.replaceFirst(java.net.URLEncoder.encode(c, "UTF-8")) 9 | m = regex.matcher(l) } 10 | println(l) } 11 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | Yuzu (Python) 2 | ============= 3 | 4 | This documentation describes how to get started with the Python version 5 | of the Yuzu RDF Publishing micro-framework 6 | 7 | Requirements 8 | ------------ 9 | 10 | The Python version of Yuzu requires Python 2.7, as well as SQLite3 support 11 | (normally built-in), LXML and RDFLib. 12 | 13 | The tested versions are 14 | 15 | * Python 2.7.5 16 | * LXML 3.2.4 17 | * RDFLib 3.2.3 18 | 19 | For JSON-LD support `rdflib-jsonld` is required and can be obtained by 20 | 21 | git clone https://github.com/RDFLib/rdflib-jsonld.git 22 | cd rdflib-jsonld 23 | sudo python setup.py install 24 | 25 | Configuring 26 | ----------- 27 | 28 | The configuration of a single Yuzu instance is performed by editing the 29 | `settings.py` file, there are a number of variables that are important 30 | to change 31 | 32 | * `BASE_NAME`: This the URI where the application will be installed to and all 33 | resources hosted at this endpoint must start with this URI. 34 | * `DUMP_FILE`: The path to the dump of the data to be hosted as a Gzipped 35 | N-Triple file, preferrably the output of a `rapper -o ntriples` command 36 | * `DISPLAY_NAME`: The human-readable name of your dataset 37 | 38 | After changing these variables it is necessary to create the database by using 39 | the following command 40 | 41 | python -m yuzu.backend 42 | 43 | Testing 44 | ------- 45 | 46 | You cant test the local setup by running the following command 47 | 48 | python -m yuzu.server 49 | 50 | The server should be availalbe for testing at localhost on port 8080. 51 | 52 | Deploying 53 | --------- 54 | 55 | Yuzu should be deployed as a WSGI service, please see the [documentation](http://www.modwsgi.org/) 56 | there for more details. 57 | 58 | It is recommended you deploy the service in a virtualenv as described in 59 | the [Django documentation](https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/modwsgi/). 60 | -------------------------------------------------------------------------------- /python/common: -------------------------------------------------------------------------------- 1 | ../common -------------------------------------------------------------------------------- /python/load_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | if [[ $DIR != $(pwd) ]] 5 | then 6 | echo "You must run this script from the folder yuzu/python" 7 | exit 8 | fi 9 | 10 | python -m yuzu.backend $@ 11 | -------------------------------------------------------------------------------- /python/yuzu/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'jmccrae' 2 | -------------------------------------------------------------------------------- /python/yuzu/dataid.py: -------------------------------------------------------------------------------- 1 | from rdflib import Graph, Literal, URIRef 2 | from rdflib.namespace import Namespace 3 | from yuzu.backend import RDFBackend 4 | from yuzu.settings import (DB_FILE, METADATA_PATH, DISPLAY_NAME, LANG, 5 | BASE_NAME, LIST_PATH, ONTOLOGY, ISSUE_DATE, 6 | VERSION_INFO, DESCRIPTION, LICENSE, KEYWORDS, 7 | LICENSE_PATH, PUBLISHER_NAME, PUBLISHER_EMAIL, 8 | CREATOR_EMAILS, CREATOR_NAMES, CONTRIBUTOR_EMAILS, 9 | CONTRIBUTOR_NAMES, SPARQL_ENDPOINT, DERIVED_FROM, 10 | DUMP_URI, SPARQL_PATH) 11 | from rdflib.namespace import RDF, RDFS, XSD, DC, DCTERMS 12 | 13 | 14 | def dataid(): 15 | g = Graph() 16 | 17 | backend = RDFBackend(DB_FILE) 18 | 19 | BASE = Namespace(BASE_NAME) 20 | DCAT = Namespace("http://www.w3.org/ns/dcat#") 21 | VOID = Namespace("http://rdfs.org/ns/void#") 22 | DATAID = Namespace("http://dataid.dbpedia.org/ns#") 23 | FOAF = Namespace("http://xmlns.com/foaf/0.1/") 24 | ODRL = Namespace("http://www.w3.org/ns/odrl/2/") 25 | PROV = Namespace("http://www.w3.org/ns/prov#") 26 | 27 | dataid = BASE[METADATA_PATH] 28 | 29 | g.add((dataid, RDF.type, DCAT.Dataset)) 30 | g.add((dataid, RDF.type, VOID.Dataset)) 31 | 32 | g.add((dataid, DCAT.title, Literal(DISPLAY_NAME, lang=LANG))) 33 | 34 | g.add((dataid, RDFS.label, Literal(DISPLAY_NAME, lang=LANG))) 35 | 36 | g.add((dataid, DCAT.landingPage, URIRef(BASE_NAME))) 37 | 38 | g.add((dataid, VOID.exampleResource, 39 | URIRef(BASE[backend.list_resources(0, 1)[1][0]["link"][1:]]))) 40 | 41 | g.add((dataid, DC.language, Literal(LANG))) 42 | 43 | g.add((dataid, VOID.rootResource, URIRef(BASE[LIST_PATH[1:]]))) 44 | 45 | if ONTOLOGY: 46 | g.add((dataid, DATAID.ontologyLocation, URIRef(BASE[ONTOLOGY]))) 47 | 48 | if ISSUE_DATE: 49 | g.add((dataid, DCTERMS.issued, Literal(ISSUE_DATE, datatype=XSD.date))) 50 | 51 | if VERSION_INFO: 52 | g.add((dataid, DATAID.versionInfo, Literal(VERSION_INFO))) 53 | 54 | if DESCRIPTION: 55 | g.add((dataid, DC.description, Literal(DESCRIPTION, lang=LANG))) 56 | 57 | g.add((dataid, ODRL.license, BASE[LICENSE_PATH[1:]])) 58 | 59 | if LICENSE: 60 | g.add((dataid, DC.rights, URIRef(LICENSE))) 61 | 62 | for keyword in KEYWORDS: 63 | g.add((dataid, DCAT.keyword, Literal(keyword))) 64 | 65 | if PUBLISHER_NAME: 66 | publisher = BASE[METADATA_PATH + "#Publisher"] 67 | g.add((publisher, RDF.type, FOAF.Agent)) 68 | g.add((publisher, RDF.type, PROV.Agent)) 69 | g.add((dataid, DC.publisher, publisher)) 70 | g.add((publisher, FOAF.name, Literal(PUBLISHER_NAME))) 71 | g.add((publisher, FOAF.mbox, Literal(PUBLISHER_EMAIL))) 72 | 73 | for i in range(0, len(CREATOR_NAMES)): 74 | creator = BASE[METADATA_PATH + "#Creator-" + str(i + 1)] 75 | g.add((creator, RDF.type, FOAF.Agent)) 76 | g.add((creator, RDF.type, PROV.Agent)) 77 | g.add((dataid, DC.creator, creator)) 78 | g.add((creator, FOAF.name, Literal(CREATOR_NAMES[i]))) 79 | g.add((creator, FOAF.mbox, Literal(CREATOR_EMAILS[i]))) 80 | 81 | for i in range(0, len(CONTRIBUTOR_NAMES)): 82 | creator = BASE[METADATA_PATH + "#Contributor-" + str(i + 1)] 83 | g.add((creator, RDF.type, FOAF.Agent)) 84 | g.add((creator, RDF.type, PROV.Agent)) 85 | g.add((dataid, DC.creator, creator)) 86 | g.add((creator, FOAF.name, Literal(CONTRIBUTOR_NAMES[i]))) 87 | g.add((creator, FOAF.mbox, Literal(CONTRIBUTOR_EMAILS[i]))) 88 | 89 | for d in DERIVED_FROM: 90 | g.add((dataid, PROV.wasDerivedFrom, URIRef(d))) 91 | 92 | dump = BASE[METADATA_PATH + "#Dump"] 93 | 94 | g.add((dump, RDF.type, DCAT.Distribution)) 95 | 96 | g.add((dataid, DCAT.distribution, dump)) 97 | 98 | g.add((dump, DCAT.downloadURL, URIRef(BASE[DUMP_URI[1:]]))) 99 | 100 | g.add((dataid, VOID.triples, Literal(str(backend.triple_count()), 101 | datatype=XSD.integer))) 102 | 103 | g.add((dump, VOID.triples, Literal(str(backend.triple_count()), 104 | datatype=XSD.integer))) 105 | 106 | g.add((dump, DC["format"], Literal("application/x-gzip"))) 107 | 108 | if SPARQL_ENDPOINT: 109 | g.add((dataid, VOID.sparqlEndpoint, URIRef(SPARQL_ENDPOINT))) 110 | else: 111 | g.add((dataid, VOID.sparqlEndpoint, URIRef(BASE[SPARQL_PATH[1:]]))) 112 | 113 | i = 0 114 | for target, count in backend.link_counts(): 115 | linkset = BASE[METADATA_PATH + "#LinkSet-" + str(i + 1)] 116 | g.add((dataid, VOID.subset, linkset)) 117 | g.add((linkset, VOID.subjectsTarget, dataid)) 118 | g.add((linkset, VOID.target, URIRef(target))) 119 | g.add((linkset, VOID.triples, Literal(str(count), 120 | datatype=XSD.integer))) 121 | g.add((linkset, RDF.type, VOID.LinkSet)) 122 | i += 1 123 | 124 | return g 125 | -------------------------------------------------------------------------------- /python/yuzu/displayer.py: -------------------------------------------------------------------------------- 1 | from rdflib.term import Literal, URIRef 2 | from rdflib.namespace import RDF, RDFS, XSD, OWL, DC, DCTERMS 3 | import re 4 | from yuzu.settings import (PREFIX1_QN, PREFIX1_URI, DATAID, 5 | PREFIX2_QN, PREFIX2_URI, DCAT, 6 | PREFIX3_QN, PREFIX3_URI, FOAF, 7 | PREFIX4_QN, PREFIX4_URI, ODRL, 8 | PREFIX5_QN, PREFIX5_URI, PROV, 9 | PREFIX6_QN, PREFIX6_URI, VOID, 10 | PREFIX7_QN, PREFIX7_URI, 11 | PREFIX8_QN, PREFIX8_URI, 12 | PREFIX9_QN, PREFIX9_URI, PROP_NAMES, BASE_NAME) 13 | 14 | 15 | # Displayers are here due to circular importing :( 16 | class DefaultDisplayer: 17 | def uri_to_str(self, uri): 18 | if uri in PROP_NAMES: 19 | return PROP_NAMES[uri] 20 | elif uri.startswith(PREFIX1_URI): 21 | return "%s:%s" % (PREFIX1_QN, uri[len(PREFIX1_URI):]) 22 | elif uri.startswith(PREFIX2_URI): 23 | return "%s:%s" % (PREFIX2_QN, uri[len(PREFIX2_URI):]) 24 | elif uri.startswith(PREFIX3_URI): 25 | return "%s:%s" % (PREFIX3_QN, uri[len(PREFIX3_URI):]) 26 | elif uri.startswith(PREFIX4_URI): 27 | return "%s:%s" % (PREFIX4_QN, uri[len(PREFIX4_URI):]) 28 | elif uri.startswith(PREFIX5_URI): 29 | return "%s:%s" % (PREFIX5_QN, uri[len(PREFIX5_URI):]) 30 | elif uri.startswith(PREFIX6_URI): 31 | return "%s:%s" % (PREFIX6_QN, uri[len(PREFIX6_URI):]) 32 | elif uri.startswith(PREFIX7_URI): 33 | return "%s:%s" % (PREFIX7_QN, uri[len(PREFIX7_URI):]) 34 | elif uri.startswith(PREFIX8_URI): 35 | return "%s:%s" % (PREFIX8_QN, uri[len(PREFIX8_URI):]) 36 | elif uri.startswith(PREFIX9_URI): 37 | return "%s:%s" % (PREFIX9_QN, uri[len(PREFIX9_URI):]) 38 | elif uri.startswith(BASE_NAME): 39 | return "%s" % uri[len(BASE_NAME):] 40 | elif uri.startswith(str(RDF)): 41 | return uri[len(str(RDF)):] 42 | elif uri.startswith(str(RDFS)): 43 | return uri[len(str(RDFS)):] 44 | elif uri.startswith(str(OWL)): 45 | return uri[len(str(OWL)):] 46 | elif uri.startswith(str(DC)): 47 | return uri[len(str(DC)):] 48 | elif uri.startswith(str(DCTERMS)): 49 | return uri[len(str(DCTERMS)):] 50 | elif uri.startswith(str(XSD)): 51 | return uri[len(str(XSD)):] 52 | elif uri.startswith(DATAID): 53 | return "dataid:" + uri[len(str(DATAID)):] 54 | elif uri.startswith(DCAT): 55 | return "dcat:" + uri[len(str(DCAT)):] 56 | elif uri.startswith(FOAF): 57 | return "foaf:" + uri[len(str(FOAF)):] 58 | elif uri.startswith(ODRL): 59 | return "odrl:" + uri[len(str(ODRL)):] 60 | elif uri.startswith(PROV): 61 | return "prov:" + uri[len(str(PROV)):] 62 | elif uri.startswith(VOID): 63 | return "void:" + uri[len(str(VOID)):] 64 | else: 65 | return uri 66 | 67 | def apply(self, node): 68 | if type(node) == URIRef: 69 | u = self.uri_to_str(str(node)) 70 | if u: 71 | return u 72 | else: 73 | return str(node) 74 | elif type(node) == Literal: 75 | return str(node) 76 | else: 77 | return "" 78 | 79 | 80 | class PrettyDisplayer: 81 | @staticmethod 82 | def magic_string(text): 83 | if text: 84 | s = re.sub("([a-z])([A-Z])", "\\1 \\2", text) 85 | s = re.sub("_", " ", s) 86 | return s[0].upper() + s[1:] 87 | else: 88 | "" 89 | 90 | def uri_to_str(self, uri): 91 | if uri in PROP_NAMES: 92 | return PROP_NAMES[uri] 93 | elif uri.startswith(PREFIX1_URI): 94 | return self.magic_string( 95 | "%s" % (uri[len(PREFIX1_URI):])) 96 | elif uri.startswith(PREFIX2_URI): 97 | return self.magic_string( 98 | "%s" % (uri[len(PREFIX2_URI):])) 99 | elif uri.startswith(PREFIX3_URI): 100 | return self.magic_string( 101 | "%s" % (uri[len(PREFIX3_URI):])) 102 | elif uri.startswith(PREFIX4_URI): 103 | return self.magic_string( 104 | "%s" % (uri[len(PREFIX4_URI):])) 105 | elif uri.startswith(PREFIX5_URI): 106 | return self.magic_string( 107 | "%s" % (uri[len(PREFIX5_URI):])) 108 | elif uri.startswith(PREFIX6_URI): 109 | return self.magic_string( 110 | "%s" % (uri[len(PREFIX6_URI):])) 111 | elif uri.startswith(PREFIX7_URI): 112 | return self.magic_string( 113 | "%s" % (uri[len(PREFIX7_URI):])) 114 | elif uri.startswith(PREFIX8_URI): 115 | return self.magic_string( 116 | "%s" % (uri[len(PREFIX8_URI):])) 117 | elif uri.startswith(PREFIX9_URI): 118 | return self.magic_string( 119 | "%s" % (uri[len(PREFIX9_URI):])) 120 | elif uri.startswith(BASE_NAME): 121 | return self.magic_string("%s" % uri[len(BASE_NAME):]) 122 | elif uri.startswith(str(RDF)): 123 | return self.magic_string(uri[len(str(RDF)):]) 124 | elif uri.startswith(str(RDFS)): 125 | return self.magic_string(uri[len(str(RDFS)):]) 126 | elif uri.startswith(str(OWL)): 127 | return self.magic_string(uri[len(str(OWL)):]) 128 | elif uri.startswith(str(DC)): 129 | return self.magic_string(uri[len(str(DC)):]) 130 | elif uri.startswith(str(DCTERMS)): 131 | return self.magic_string(uri[len(str(DCTERMS)):]) 132 | elif uri.startswith(str(XSD)): 133 | return self.magic_string(uri[len(str(XSD)):]) 134 | elif uri.startswith(DATAID): 135 | return self.magic_string(uri[len(str(DATAID)):]) 136 | elif uri.startswith(DCAT): 137 | return self.magic_string(uri[len(str(DCAT)):]) 138 | elif uri.startswith(FOAF): 139 | return self.magic_string(uri[len(str(FOAF)):]) 140 | elif uri.startswith(ODRL): 141 | return self.magic_string(uri[len(str(ODRL)):]) 142 | elif uri.startswith(PROV): 143 | return self.magic_string(uri[len(str(PROV)):]) 144 | elif uri.startswith(VOID): 145 | return self.magic_string(uri[len(str(VOID)):]) 146 | else: 147 | return uri 148 | 149 | def apply(self, node): 150 | if type(node) == URIRef: 151 | u = self.uri_to_str(str(node)) 152 | if u: 153 | return u 154 | else: 155 | return str(node) 156 | elif type(node) == Literal: 157 | return str(node) 158 | if type(node) == str: 159 | return self.uri_to_str(node) 160 | else: 161 | return "" 162 | 163 | # Displayer to show URIs 164 | DISPLAYER = PrettyDisplayer() 165 | -------------------------------------------------------------------------------- /python/yuzu/jsonld.py: -------------------------------------------------------------------------------- 1 | import re 2 | from yuzu.settings import BASE_NAME 3 | from rdflib.namespace import RDF 4 | from rdflib import URIRef, BNode 5 | import json 6 | 7 | 8 | def is_alnum(string): 9 | return re.match('^\w+$', string) is not None 10 | 11 | 12 | def prop_type(p, graph): 13 | if all(isinstance(o, URIRef) or isinstance(o, BNode) 14 | for o in graph.objects(None, p)): 15 | return { 16 | "@id": str(p), 17 | "@type": "@id" 18 | } 19 | else: 20 | return str(p) 21 | 22 | 23 | def split_uri(value, graph): 24 | if value.startswith(BASE_NAME): 25 | return "", value[len(BASE_NAME):] 26 | for qn, uri in graph.namespaces(): 27 | if value.startswith(uri): 28 | return qn, value[len(uri):] 29 | return "", value 30 | 31 | 32 | def is_prefix_used(prefix, graph): 33 | for s, p, o in graph: 34 | if isinstance(s, URIRef) and str(s).startswith(prefix): 35 | return True 36 | if str(p).startswith(prefix): 37 | return True 38 | if isinstance(o, URIRef) and str(o).startswith(prefix): 39 | return True 40 | return False 41 | 42 | 43 | def extract_jsonld_context(graph, query): 44 | context = { 45 | "@base": BASE_NAME} 46 | for k, v in graph.namespaces(): 47 | if is_prefix_used(str(v), graph): 48 | context[k] = str(v) 49 | props = {} 50 | for p in set(graph.predicates()): 51 | p_str = str(p) 52 | short_name = "" 53 | if '#' in p_str: 54 | short_name = p_str[p_str.rindex('#')+1:] 55 | if not is_alnum(short_name) and '/' in p_str: 56 | short_name = p_str[p_str.rindex('/')+1:] 57 | if not is_alnum(short_name): 58 | pre, suf = split_uri(p_str, graph) 59 | short_name = suf 60 | sn = short_name 61 | i = 2 62 | while sn in context: 63 | sn = "%s%d" % (short_name, i) 64 | i += 1 65 | if p == RDF.type: 66 | sn = "@type" 67 | else: 68 | context[sn] = prop_type(p, graph) 69 | props[p_str] = sn 70 | return context, props 71 | 72 | 73 | def add_props(obj, value, context, graph, query, prop2sn, drb, stack): 74 | if value not in stack: 75 | for p in set(graph.predicates(value)): 76 | objs = sorted(list(graph.objects(value, p))) 77 | is_obj = (p == RDF.type or 78 | isinstance(context[prop2sn[str(p)]], dict)) 79 | if len(objs) == 1: 80 | graph.remove((value, p, objs[0])) 81 | obj[prop2sn[str(p)]] = jsonld_value(objs[0], context, graph, 82 | query, prop2sn, is_obj, 83 | drb, [value] + stack) 84 | else: 85 | for o in objs: 86 | graph.remove((value, p, o)) 87 | obj[prop2sn[str(p)]] = [jsonld_value(o, context, graph, query, 88 | prop2sn, is_obj, drb, 89 | [value] + stack) 90 | for o in objs] 91 | 92 | 93 | def add_inverse_props(obj, value, context, graph, query, prop2sn, drb, stack): 94 | for p in set(graph.predicates(value)): 95 | objs = sorted(list(graph.objects(value, p))) 96 | for o in objs: 97 | if isinstance(o, URIRef) or isinstance(o, BNode): 98 | add_inverse_props(obj[prop2sn[str(p)]], value, context, graph, 99 | query, prop2sn, drb, [value] + stack) 100 | 101 | if list(graph.predicates(None, value)): 102 | robj = {} 103 | obj["@reverse"] = robj 104 | for p in set(graph.predicates(None, value)): 105 | objs = sorted(list(graph.subjects(p, value))) 106 | #objs = [o for o in objs if not str(o).startswith(query)] 107 | if len(objs) == 1: 108 | graph.remove((objs[0], p, value)) 109 | robj[prop2sn[str(p)]] = jsonld_value(objs[0], context, graph, 110 | query, prop2sn, False, 111 | drb, [value] + stack) 112 | elif len(objs) > 1: 113 | for o in objs: 114 | graph.remove((o, p, value)) 115 | robj[prop2sn[str(p)]] = [jsonld_value(o, context, graph, query, 116 | prop2sn, False, drb, 117 | [value] + stack) 118 | for o in objs] 119 | 120 | 121 | def jsonld_value(value, context, graph, query, prop2sn, is_obj, drb, stack): 122 | if isinstance(value, list) and len(value) > 1: 123 | return [jsonld_value(v, context, graph, query, prop2sn, 124 | is_obj, drb, stack) 125 | for v in value] 126 | elif isinstance(value, list): 127 | return jsonld_value(value[0], context, graph, query, prop2sn, is_obj, 128 | drb, stack) 129 | elif isinstance(value, URIRef): 130 | if not list(graph.predicate_objects(value)) and is_obj: 131 | pre, suf = split_uri(str(value), graph) 132 | if pre: 133 | return "%s:%s" % (pre, suf) 134 | else: 135 | return suf 136 | else: 137 | pre, suf = split_uri(str(value), graph) 138 | if pre: 139 | obj = {"@id": "%s:%s" % (pre, suf)} 140 | else: 141 | obj = {"@id": suf} 142 | 143 | add_props(obj, value, context, graph, query, prop2sn, drb, 144 | stack) 145 | 146 | return obj 147 | elif isinstance(value, BNode): 148 | if not list(graph.predicate_objects(value)) and is_obj: 149 | if value in drb: 150 | return "_:" + str(value) 151 | else: 152 | return {} 153 | else: 154 | if value in drb: 155 | obj = {"@id": "_:" + str(value)} 156 | else: 157 | obj = {} 158 | 159 | add_props(obj, value, context, graph, query, prop2sn, drb, 160 | stack) 161 | 162 | return obj 163 | else: 164 | if value.language: 165 | return {"@value": str(value), 166 | "@language": value.language} 167 | elif value.datatype: 168 | pre, suf = split_uri(value.datatype, graph) 169 | if pre == "xsd" and suf == "integer": 170 | return int(value) 171 | elif pre == "xsd" and suf == "double": 172 | return float(value) 173 | elif pre: 174 | return {"@value": str(value), 175 | "@type": str("%s:%s" % (pre, suf))} 176 | else: 177 | return {"@value": str(value), 178 | "@type": str(suf)} 179 | else: 180 | return str(value) 181 | 182 | 183 | def double_reffed_bnodes(graph): 184 | for o in graph.objects(): 185 | if isinstance(o, BNode): 186 | if len(list(graph.subject_predicates(o))) > 1: 187 | yield(o) 188 | 189 | 190 | def write(graph, query): 191 | return json.dumps(jsonld_from_model(graph, query), indent=2) 192 | 193 | 194 | def jsonld_from_model(graph, query): 195 | context, prop2sn = extract_jsonld_context(graph, query) 196 | if query.startswith(BASE_NAME): 197 | the_id = query[len(BASE_NAME):] 198 | else: 199 | the_id = query 200 | the_obj = { 201 | "@context": context, 202 | "@id": the_id 203 | } 204 | elem = URIRef(query) 205 | 206 | drb = list(double_reffed_bnodes(graph)) 207 | add_props(the_obj, elem, context, graph, query, prop2sn, drb, []) 208 | add_inverse_props(the_obj, elem, context, graph, query, prop2sn, drb, []) 209 | 210 | rest = list(graph.subjects()) 211 | if rest: 212 | graph_obj = { 213 | "@context": context, 214 | "@graph": [ 215 | the_obj 216 | ] 217 | } 218 | del the_obj["@context"] 219 | the_obj = graph_obj 220 | while rest: 221 | the_obj["@graph"].append(jsonld_value(rest[0], context, graph, 222 | query, prop2sn, True, drb, 223 | [])) 224 | rest = list(graph.subjects()) 225 | 226 | return the_obj 227 | -------------------------------------------------------------------------------- /python/yuzu/model.py: -------------------------------------------------------------------------------- 1 | from rdflib.term import Literal, URIRef, BNode 2 | from rdflib.namespace import RDF 3 | from yuzu.settings import CONTEXT 4 | from yuzu.displayer import DISPLAYER 5 | import sys 6 | if sys.version_info[0] < 3: 7 | from urllib import quote_plus 8 | else: 9 | from urllib.parse import quote_plus 10 | 11 | 12 | def next_subject(graph, class_of): 13 | for s, p, o in graph: 14 | if (p != RDF.type or o != class_of) and isinstance(p, URIRef): 15 | return str(s) 16 | return None 17 | 18 | 19 | def from_model(graph, query): 20 | s = query 21 | rv = [] 22 | while s: 23 | elem = URIRef(s) 24 | class_of = None 25 | class_of_objects = graph.objects(elem, RDF.type) 26 | if class_of_objects: 27 | for class_of_value in graph.objects(elem, RDF.type): 28 | class_of = from_node(graph, class_of_value, [], False, query) 29 | break 30 | triples = list(triple_frags(elem, graph, [], class_of, query)) 31 | graph.remove((elem, None, None)) 32 | model = { 33 | 'display': DISPLAYER.apply(elem), 34 | 'literal_encode': quote_plus(str(elem)), 35 | 'uri': query, 36 | 'uri_encode': quote_plus(query), 37 | 'triples': triples, 38 | 'has_triples': len(triples) > 0, 39 | 'classOf': class_of, 40 | 'context': CONTEXT, 41 | 'inverses': list(inverse_triple_frags(elem, graph, query)) 42 | } 43 | graph.remove((None, None, elem)) 44 | rv.append(model) 45 | s = next_subject(graph, class_of) 46 | return { 47 | 'head': rv[0], 48 | 'tail': rv[1:] 49 | } 50 | 51 | 52 | def triple_elems(objs): 53 | N = len(objs) 54 | n = 0 55 | for o in objs: 56 | n += 1 57 | yield {"elem": o, "last": n == N} 58 | 59 | 60 | def groupby(triples): 61 | last = None 62 | result = [] 63 | block = [] 64 | for p, o in triples: 65 | if last and p["uri"] == last["uri"]: 66 | block.append(o) 67 | else: 68 | if last: 69 | result.append((last, block)) 70 | block = [o] 71 | last = p 72 | if last: 73 | result.append((last, block)) 74 | return result 75 | 76 | 77 | def triple_frags(elem, graph, stack, classOf, query): 78 | if elem in stack: 79 | for p in []: 80 | yield p 81 | else: 82 | triples = [(from_node(graph, p, [elem] + stack, True, query), 83 | from_node(graph, o, [elem] + stack, True, query)) 84 | for p, o in graph.predicate_objects(elem) 85 | if p != RDF.type or o != classOf] 86 | sortt = sorted(triples, key=lambda x: x[0]["display"] + x[0]["uri"]) 87 | grouped = groupby(sortt) 88 | for p, objs in grouped: 89 | has_triples = False 90 | for o in objs: 91 | has_triples = has_triples or o["has_triples"] 92 | yield { 93 | "has_triples": has_triples, 94 | "prop": p, 95 | "obj": list(triple_elems(objs)) 96 | } 97 | 98 | 99 | def inverse_triple_frags(elem, graph, query): 100 | triples = [(from_node(graph, p, [], False, query), 101 | from_node(graph, s, [], False, query)) 102 | for s, p in graph.subject_predicates(elem) 103 | if not str(s).startswith(query)] 104 | # if (('#' in str(s) and str(s)[:str(s).index('#')] != query) or 105 | # ('#' not in str(s) and str(s) != query))] 106 | sortt = sorted(triples, key=lambda x: x[0]["display"] + x[0]["uri"]) 107 | grouped = groupby(sortt) 108 | for p, objs in grouped: 109 | yield { 110 | "prop": p, 111 | "obj": list(triple_elems(objs)) 112 | } 113 | 114 | 115 | def from_node(graph, node, stack, recurse=True, query=None): 116 | if type(node) == URIRef: 117 | fragment = None 118 | if '#' in str(node): 119 | fragment = str(node)[str(node).index('#') + 1:] 120 | if recurse and str(node).startswith(str(query)): 121 | triples = list(triple_frags(node, graph, stack, None, query)) 122 | graph.remove((node, None, None)) 123 | return { 124 | 'display': DISPLAYER.apply(node), 125 | 'uri': str(node), 126 | 'uri_encode': quote_plus(str(node)), 127 | 'triples': triples, 128 | 'has_triples': len(triples) > 0, 129 | 'context': CONTEXT, 130 | 'fragment': fragment 131 | } 132 | else: 133 | return { 134 | 'display': DISPLAYER.apply(node), 135 | 'uri': str(node), 136 | 'uri_encode': quote_plus(str(node)), 137 | 'triples': [], 138 | 'has_triples': False, 139 | 'context': CONTEXT, 140 | 'fragment': fragment 141 | } 142 | elif type(node) == BNode: 143 | triples = list(triple_frags(node, graph, stack, None, query)) 144 | graph.remove((node, None, None)) 145 | return { 146 | 'display': DISPLAYER.apply(node), 147 | 'bnode': True, 148 | 'triples': triples, 149 | 'has_triples': len(triples) > 0, 150 | 'context': CONTEXT 151 | } 152 | elif type(node) == Literal: 153 | return { 154 | 'display': str(node), 155 | 'literal': True, 156 | 'literal_encode': quote_plus(str(node)), 157 | 'lang': node.language, 158 | 'datatype': from_dt(node.datatype), 159 | 'has_triples': False, 160 | 'context': CONTEXT 161 | } 162 | 163 | 164 | def from_dt(dt): 165 | if dt: 166 | return { 167 | 'display': DISPLAYER.apply(dt), 168 | 'uri': str(dt) 169 | } 170 | else: 171 | return None 172 | 173 | 174 | def sparql_results_to_dict(result): 175 | if result.findall( 176 | "{http://www.w3.org/2005/sparql-results#}boolean"): 177 | r = (result.findall( 178 | "{http://www.w3.org/2005/sparql-results#}boolean")[0].text == 179 | "true") 180 | return {"boolean": r} 181 | variables = [] 182 | head = result.findall( 183 | "{http://www.w3.org/2005/sparql-results#}head")[0] 184 | r = {"variables": [], "results": [], "context": CONTEXT} 185 | for variable in head: 186 | variables.append(variable.get("name")) 187 | r["variables"].append({"name": variable.get("name")}) 188 | body = result.findall( 189 | "{http://www.w3.org/2005/sparql-results#}results")[0] 190 | results = body.findall( 191 | "{http://www.w3.org/2005/sparql-results#}result") 192 | n = 0 193 | for result in results: 194 | r["results"].append({"result": []}) 195 | for v in variables: 196 | r["results"][n]["result"].append(dict()) 197 | bindings = result.findall( 198 | "{http://www.w3.org/2005/sparql-results#}binding") 199 | for binding in bindings: 200 | name = binding.get("name") 201 | target = r["results"][n]["result"][variables.index(name)] = {} 202 | if (binding[0].tag == 203 | '{http://www.w3.org/2005/sparql-results#}uri'): 204 | target['uri'] = binding[0].text 205 | target['display'] = DISPLAYER.apply(binding[0].text) 206 | if (binding[0].tag == 207 | '{http://www.w3.org/2005/sparql-results#}bnode'): 208 | target['bnode'] = binding[0].text 209 | if (binding[0].tag == 210 | '{http://www.w3.org/2005/sparql-results#}literal'): 211 | target['value'] = binding[0].text 212 | if binding[0].get( 213 | "{http://www.w3.org/XML/1998/namespace}lang"): 214 | target['lang'] = binding[0].get( 215 | "{http://www.w3.org/XML/1998/namespace}lang") 216 | elif binding[0].get("datatype"): 217 | target['datatype'] = binding[0].get("datatype") 218 | n += 1 219 | 220 | return r 221 | -------------------------------------------------------------------------------- /python/yuzu/ql/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = "John P. McCrae" 2 | -------------------------------------------------------------------------------- /python/yuzu/ql/parse.py: -------------------------------------------------------------------------------- 1 | import pyparsing as pp 2 | from yuzu.ql.model import Triple, Var, BNC, TypedLiteral, PropObjDisjunction 3 | from yuzu.ql.model import ObjList, SelectQuery, PropObj, Order, PrefixedName 4 | from yuzu.ql.model import FullURI, PlainLiteral, LangLiteral 5 | 6 | 7 | def limit_unwrap(s, l, t): 8 | if len(t) > 1: 9 | return (t[0], t[1]) 10 | else: 11 | return (t[0], -1) 12 | 13 | 14 | def offset_unwrap(s, l, t): 15 | if len(t) > 1: 16 | return (t[1], t[0]) 17 | else: 18 | return (-1, t[0]) 19 | 20 | 21 | def select_unwrap(s, l, t): 22 | print(t) 23 | prefixes = t[0] 24 | distinct = t[1] 25 | varList = t[2] 26 | where = t[3] 27 | if t[4]: 28 | orderVars = t[4][0] 29 | else: 30 | orderVars = [] 31 | if len(t[5]) > 0: 32 | limit, offset = t[5][0] 33 | else: 34 | limit = -1 35 | offset = -1 36 | return SelectQuery(distinct, varList, where, orderVars, 37 | int(limit), int(offset)).resolve(prefixes) 38 | 39 | 40 | def unwrap_count_var_list(s, l, t): 41 | if len(t) == 1: 42 | if isinstance(t[0], Var): 43 | return (t[0], None) 44 | else: 45 | return (None, t[0]) 46 | else: 47 | return (t[0], t[1]) 48 | 49 | 50 | class YuzuQLSyntax: 51 | uri = pp.Regex("<.*?>").setParseAction( 52 | lambda s, l, t: FullURI(t[0])) 53 | 54 | pn_local = pp.Regex("[A-Za-z_][A-Za-z\\-\\.0-9_]*") 55 | 56 | pn_prefix = pp.Regex("([A-Za-z][A-Za-z\\-\\.0-9_]*|)") 57 | 58 | pname_ns = pn_prefix + pp.Literal(":").suppress() 59 | 60 | pname_ln = (pname_ns + pn_local).setParseAction( 61 | lambda s, l, t: PrefixedName(t[0], t[1])) 62 | 63 | uriref = pname_ln ^ uri 64 | 65 | prefix = (pp.CaselessKeyword("prefix").suppress() + pname_ns + 66 | uri).setParseAction(lambda s, l, t: (t[0], t[1])) 67 | 68 | prefixes = pp.ZeroOrMore(prefix).setParseAction( 69 | lambda s, l, t: dict([(x, y) for x, y in t])) 70 | 71 | select = (pp.CaselessKeyword("select").suppress() + 72 | pp.Optional(pp.CaselessKeyword("distinct"))).setParseAction( 73 | lambda s, l, t: len(t) > 0) 74 | 75 | var = pp.Regex("[\?\$][A-Za-z0-9]+").setParseAction( 76 | lambda s, l, t: Var(t[0][1:])) 77 | 78 | var2 = pp.Regex("[\?\$][A-Za-z0-9]+").setParseAction( 79 | lambda s, l, t: Order(Var(t[0][1:]), 0)) 80 | 81 | count = (("(" + pp.CaselessKeyword("count") + "(" + "*" + ")" + 82 | pp.CaselessKeyword("as")).suppress() + var + 83 | pp.Literal(")").suppress()) 84 | 85 | varList = pp.Group(pp.OneOrMore(var)) 86 | 87 | countVarList = (count ^ (count + varList) ^ varList ^ "*").setParseAction( 88 | unwrap_count_var_list) 89 | 90 | where = pp.CaselessKeyword("where").suppress() 91 | 92 | stringLiteral = pp.QuotedString('"', '\\', 93 | unquoteResults=False).setParseAction( 94 | lambda s, l, t: PlainLiteral(t[0])) 95 | 96 | langLiteral = ( 97 | pp.QuotedString('"', '\\', unquoteResults=False) + "@" + 98 | pp.Word(pp.alphanums + "-")).setParseAction( 99 | lambda s, l, t: LangLiteral(t[0], t[2].lower())) 100 | 101 | typedLiteral = (pp.QuotedString('"', '\\', unquoteResults=False) 102 | + "^^" + uriref).setParseAction( 103 | lambda s, l, t: TypedLiteral(t[0], t[2])) 104 | 105 | obj_value = uriref ^ stringLiteral ^ langLiteral ^ typedLiteral 106 | 107 | a = pp.Keyword("a").setParseAction( 108 | lambda s, l, t: FullURI("")) 110 | 111 | t2 = pp.Forward() 112 | 113 | bnode = ("[" + t2 + "]").setParseAction( 114 | lambda s, l, t: BNC(t[1:-1])) 115 | 116 | obj = pp.delimitedList(obj_value ^ var ^ bnode, delim=",").setParseAction( 117 | lambda s, l, t: ObjList(t)) 118 | 119 | prop = uriref ^ a 120 | 121 | propObj3 = (prop + obj).setParseAction( 122 | lambda s, l, t: PropObj(t[0], t[1])) 123 | 124 | propObj2 = pp.delimitedList(propObj3, delim="|").setParseAction( 125 | lambda s, l, t: PropObjDisjunction(t, False)) 126 | 127 | propObjOpt = ("(" + pp.delimitedList(propObj3, delim="|") + 128 | ")").setParseAction( 129 | lambda s, l, t: PropObjDisjunction(t[1:-1], True)) 130 | 131 | propObj = propObj2 ^ propObjOpt 132 | 133 | t2 << propObj2 + pp.ZeroOrMore( 134 | pp.Literal(";").suppress() + propObj) 135 | 136 | triplePattern = (((var ^ uriref) + t2).setParseAction( 137 | lambda s, l, t: Triple(t[0], t[1:])) 138 | + pp.Optional(".").suppress()) 139 | 140 | whereClause = (pp.Literal("{").suppress() + 141 | triplePattern + pp.Literal("}").suppress()) 142 | 143 | groupByClause = (pp.CaselessKeyword("group") + pp.CaselessKeyword("by") + 144 | varList).suppress() 145 | 146 | asc = (pp.CaselessKeyword("asc").suppress() + 147 | pp.Literal("(").suppress() + pp.CaselessKeyword("str").suppress() + 148 | pp.Literal("(").suppress() + var + 149 | pp.Literal(")").suppress() + 150 | pp.Literal(")").suppress()).setParseAction( 151 | lambda s, l, t: Order(t[0], 1)) 152 | 153 | desc = (pp.CaselessKeyword("desc").suppress() + 154 | pp.Literal("(").suppress() + pp.CaselessKeyword("str").suppress() + 155 | pp.Literal("(").suppress() + var + 156 | pp.Literal(")").suppress() + 157 | pp.Literal(")").suppress()).setParseAction( 158 | lambda s, l, t: Order(t[0], -1)) 159 | 160 | orderCond = asc ^ desc ^ (pp.CaselessKeyword("str").suppress() + 161 | pp.Literal("(").suppress() + var2 + 162 | pp.Literal(")").suppress()) 163 | 164 | orderConditions = pp.Group(pp.OneOrMore(orderCond)) 165 | 166 | orderClause = (pp.CaselessKeyword("order").suppress() + 167 | pp.CaselessKeyword("by").suppress() + 168 | orderConditions) 169 | 170 | limitClause = (pp.CaselessKeyword("limit").suppress() + 171 | pp.Word(pp.nums)) 172 | 173 | offsetClause = (pp.CaselessKeyword("offset").suppress() + 174 | pp.Word(pp.nums)) 175 | 176 | limitOffsetClause = ( 177 | (limitClause + pp.Optional(offsetClause)).setParseAction( 178 | limit_unwrap) ^ 179 | (offsetClause + pp.Optional(limitClause)).setParseAction( 180 | offset_unwrap)) 181 | 182 | solutionModifier = (pp.Optional(groupByClause) + 183 | pp.Group(pp.Optional(orderClause)) + 184 | pp.Group(pp.Optional(limitOffsetClause))) 185 | 186 | query = (prefixes + select + countVarList + 187 | pp.Optional(where).suppress() + whereClause + solutionModifier) 188 | 189 | def parse(self, q, ext_prefixes): 190 | t = self.query.parseString(q, parseAll=True) 191 | prefixes, distinct, count_var_list, body, orderBy, lo = t 192 | count_var, varList = count_var_list 193 | if len(lo) > 0: 194 | limit, offset = lo[0] 195 | else: 196 | limit = -1 197 | offset = -1 198 | if orderBy: 199 | orderBy = orderBy[0] 200 | 201 | sq = SelectQuery(distinct, count_var, varList, body, orderBy, 202 | int(limit), int(offset)) 203 | for k in ext_prefixes: 204 | if k not in prefixes: 205 | prefixes[k] = ext_prefixes[k] 206 | sq = sq.resolve(prefixes) 207 | return sq 208 | -------------------------------------------------------------------------------- /python/yuzu/settings.py: -------------------------------------------------------------------------------- 1 | # This file contains all relevant configuration for the system 2 | 3 | # The location where this server is to be deployed to 4 | # Only URIs in the dump that start with this address will be published 5 | # Should end with a trailing / 6 | BASE_NAME = "http://localhost:8080/" 7 | # The prefix that this servlet will be deployed, e.g. 8 | # if the servlet is at http://www.example.org/yuzu/ the context 9 | # is /yuzu/ 10 | CONTEXT = "" 11 | # The data download will be at BASE_NAME + DUMP_URI 12 | DUMP_URI = "/example.nt.gz" 13 | # The local path to the data 14 | DUMP_FILE = "../example.nt.gz" 15 | # Where the SQLite database should appear 16 | DB_FILE = "example.db" 17 | # The name of the server 18 | DISPLAY_NAME = "Example" 19 | # The extra namespaces to be abbreviated in HTML and RDF/XML 20 | # documents if desired 21 | PREFIX1_URI = "http://www.example.com/" 22 | PREFIX1_QN = "ex1" 23 | PREFIX2_URI = "http://www.example.com/" 24 | PREFIX2_QN = "ex2" 25 | PREFIX3_URI = "http://www.example.com/" 26 | PREFIX3_QN = "ex3" 27 | PREFIX4_URI = "http://www.example.com/" 28 | PREFIX4_QN = "ex4" 29 | PREFIX5_URI = "http://www.example.com/" 30 | PREFIX5_QN = "ex5" 31 | PREFIX6_URI = "http://www.example.com/" 32 | PREFIX6_QN = "ex6" 33 | PREFIX7_URI = "http://www.example.com/" 34 | PREFIX7_QN = "ex7" 35 | PREFIX8_URI = "http://www.example.com/" 36 | PREFIX8_QN = "ex8" 37 | PREFIX9_URI = "http://www.example.com/" 38 | PREFIX9_QN = "ex9" 39 | # Used for DATAID 40 | DATAID = "http://dataid.dbpedia.org/ns#" 41 | DCAT = "http://www.w3.org/ns/dcat#" 42 | FOAF = "http://xmlns.com/foaf/0.1/" 43 | ODRL = "http://www.w3.org/ns/odrl/2/" 44 | PROV = "http://www.w3.org/ns/prov#" 45 | VOID = "http://rdfs.org/ns/void#" 46 | 47 | # The maximum number of results to return from a YuzuQL query (or -1 for no 48 | # limit) 49 | YUZUQL_LIMIT = 1000 50 | # If using an external SPARQL endpoint, the address of this 51 | # or None if you wish to use only YuzuQL 52 | SPARQL_ENDPOINT = None 53 | # Path to the license (set to None to disable) 54 | LICENSE_PATH = "/license.html" 55 | # Path to the search (set to None to disable) 56 | SEARCH_PATH = "/search" 57 | # Path to static assets 58 | ASSETS_PATH = "/assets/" 59 | # Path to SPARQL (set to None to disable) 60 | SPARQL_PATH = "/sparql" 61 | # Path to site contents list (set to None to disable) 62 | LIST_PATH = "/list" 63 | # Path to Data ID (metadata) (no initial slash) 64 | METADATA_PATH = "about" 65 | 66 | # Properties to use as facets 67 | FACETS = [ 68 | { 69 | "uri": "http://www.w3.org/2000/01/rdf-schema#label", 70 | "label": "Label", 71 | "list": True 72 | } 73 | ] 74 | # Properties to use as labels 75 | LABELS = [ 76 | "", 77 | "", 78 | "", 79 | "", 80 | "" 81 | ] 82 | 83 | # Any forced names of properties 84 | PROP_NAMES = { 85 | "http://localhost:8080/ontology#link": "Link property" 86 | } 87 | 88 | # Linked datasets (this is only used for metadata but is created 89 | # on DB load). Not linked indicates URI starts which are not to 90 | # be considered links, any other links are assumed to start with the 91 | # server. 92 | LINKED_SETS = ["http://dbpedia.org/"] 93 | NOT_LINKED = ["http://www.w3.org/", "http://purl.org/dc/", 94 | "http://xmlns.org/", "http://rdfs.org/", "http://schema.org/"] 95 | # The minimum number of links to another dataset to be included in metadata 96 | MIN_LINKS = 1 97 | 98 | # Metadata 99 | 100 | # The language of this site 101 | LANG = "en" 102 | # If a resource in the data is the schema (ontology) then include its 103 | # path here. No intial slash, should resolve at BASE_NAME + ONTOLOGY 104 | ONTOLOGY = None 105 | # The date the resource was created, e.g., 106 | # The date should be of the format YYYY-MM-DD 107 | ISSUE_DATE = None 108 | # The version number 109 | VERSION_INFO = None 110 | # A longer textual description of the resource 111 | DESCRIPTION = None 112 | # If using a standard license include the link to this license 113 | LICENSE = None 114 | # Any keywords (if necessary) 115 | KEYWORDS = [] 116 | # The publisher of the dataset 117 | PUBLISHER_NAME = None 118 | PUBLISHER_EMAIL = None 119 | # The creator(s) of the dataset 120 | # The lists must be the same size, use an empty string if you do not wish 121 | # to publish the email address 122 | CREATOR_NAMES = [] 123 | CREATOR_EMAILS = [] 124 | # The contributor(s) to the dataset 125 | CONTRIBUTOR_NAMES = [] 126 | CONTRIBUTOR_EMAILS = [] 127 | # Links to the resources this data set was derived from 128 | DERIVED_FROM = [] 129 | -------------------------------------------------------------------------------- /python/yuzu/test_jsonld.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from rdflib import Graph, URIRef, BNode, Literal 3 | from yuzu.jsonld import jsonld_from_model 4 | from yuzu.settings import BASE_NAME 5 | from rdflib.namespace import RDF, XSD 6 | 7 | 8 | class JsonLDTest(unittest.TestCase): 9 | 10 | def ctxt(self, ct): 11 | self.maxDiff = None 12 | m = {"@base": BASE_NAME} 13 | for k in ct: 14 | m[k] = ct[k] 15 | return m 16 | 17 | def test_simple(self): 18 | g = Graph() 19 | g.add((URIRef("http://localhost:8080/foo"), 20 | URIRef("http://www.example.com/bar"), 21 | Literal("foo", "en"))) 22 | obj = jsonld_from_model(g, "http://localhost:8080/foo") 23 | print("simple") 24 | print(obj) 25 | self.assertDictEqual({ 26 | "@context": self.ctxt({ 27 | "bar": "http://www.example.com/bar" 28 | }), 29 | "@id": "foo", 30 | "bar": { 31 | "@value": "foo", 32 | "@language": "en" 33 | } 34 | }, obj) 35 | 36 | def test_bnode(self): 37 | g = Graph() 38 | b1 = BNode() 39 | g.add((URIRef("http://localhost:8080/foo"), 40 | URIRef("http://www.example.com/list"), 41 | b1)) 42 | g.add((b1, URIRef("http://www.example.com/first"), 43 | URIRef("http://www.example.com/value"))) 44 | g.add((b1, URIRef("http://www.example.com/rest"), 45 | RDF.nil)) 46 | obj = jsonld_from_model(g, "http://localhost:8080/foo") 47 | print("bnode") 48 | print(obj) 49 | self.assertDictEqual({ 50 | "@context": self.ctxt({ 51 | "list": { 52 | "@id": "http://www.example.com/list", 53 | "@type": "@id" 54 | }, 55 | "first": { 56 | "@id": "http://www.example.com/first", 57 | "@type": "@id" 58 | }, 59 | "rest": { 60 | "@id": "http://www.example.com/rest", 61 | "@type": "@id" 62 | }, 63 | "rdf": str(RDF) 64 | }), 65 | "@id": "foo", 66 | "list": { 67 | "first": "http://www.example.com/value", 68 | "rest": "rdf:nil" 69 | } 70 | }, obj) 71 | 72 | def test_inverse(self): 73 | g = Graph() 74 | g.add((URIRef("http://localhost:8080/foo"), 75 | URIRef("http://www.example.com/prop"), 76 | Literal("foo"))) 77 | g.add((URIRef("http://www.example.com/bar"), 78 | URIRef("http://www.example.com/backLink"), 79 | URIRef("http://localhost:8080/foo"))) 80 | obj = jsonld_from_model(g, "http://localhost:8080/foo") 81 | print("inverse") 82 | print(obj) 83 | self.assertDictEqual({ 84 | "@context": self.ctxt({ 85 | "prop": "http://www.example.com/prop", 86 | "backLink": { 87 | "@id": "http://www.example.com/backLink", 88 | "@type": "@id" 89 | } 90 | }), 91 | "@id": "foo", 92 | "prop": "foo", 93 | "@reverse": { 94 | "backLink": {"@id": "http://www.example.com/bar"} 95 | } 96 | }, obj) 97 | 98 | def test_multi(self): 99 | g = Graph() 100 | g.add((URIRef("http://localhost:8080/foo"), 101 | URIRef("http://www.example.com/mp"), 102 | Literal("foo", "en"))) 103 | g.add((URIRef("http://localhost:8080/foo"), 104 | URIRef("http://www.example.com/mp"), 105 | URIRef("http://www.example.com/bar"))) 106 | g.add((URIRef("http://localhost:8080/foo"), 107 | URIRef("http://www.example.com/op"), 108 | URIRef("http://localhost:8080/foo#baz"))) 109 | g.add((URIRef("http://localhost:8080/foo"), 110 | URIRef("http://www.example.com/op"), 111 | URIRef("http://www.example.com/bar"))) 112 | g.add((URIRef("http://localhost:8080/foo"), 113 | URIRef("http://www.example.com/dp"), 114 | Literal("bar", datatype=URIRef("http://www.example.com/type")))) 115 | g.add((URIRef("http://localhost:8080/foo"), 116 | URIRef("http://www.example.com/dp"), 117 | Literal("baz"))) 118 | obj = jsonld_from_model(g, "http://localhost:8080/foo") 119 | print("multi") 120 | print(obj) 121 | self.assertDictEqual({ 122 | "@context": self.ctxt({ 123 | "mp": "http://www.example.com/mp", 124 | "dp": "http://www.example.com/dp", 125 | "op": { 126 | "@id": "http://www.example.com/op", 127 | "@type": "@id" 128 | } 129 | }), 130 | "@id": "foo", 131 | "mp": [ 132 | {"@id": "http://www.example.com/bar"}, 133 | {"@value": "foo", "@language": "en"} 134 | ], 135 | "op": ["foo#baz", "http://www.example.com/bar"], 136 | "dp": [ 137 | {"@value": "bar", "@type": "http://www.example.com/type"}, 138 | "baz" 139 | ] 140 | }, obj) 141 | 142 | def test_drb(self): 143 | g = Graph() 144 | b = BNode("bar") 145 | g.add((URIRef("http://localhost:8080/foo"), 146 | URIRef("http://www.example.com/prop1"), 147 | b)) 148 | g.add((URIRef("http://localhost:8080/foo"), 149 | URIRef("http://www.example.com/prop2"), 150 | b)) 151 | obj = jsonld_from_model(g, "http://localhost:8080/foo") 152 | print("drb") 153 | print(obj) 154 | self.assertDictEqual({ 155 | "@context": self.ctxt({ 156 | "prop1": { 157 | "@id": "http://www.example.com/prop1", 158 | "@type": "@id" 159 | }, 160 | "prop2": { 161 | "@id": "http://www.example.com/prop2", 162 | "@type": "@id" 163 | } 164 | }), 165 | "@id": "foo", 166 | "prop1": "_:bar", 167 | "prop2": "_:bar" 168 | }, obj) 169 | 170 | def test_others(self): 171 | g = Graph() 172 | g.add((URIRef("http://localhost:8080/foo"), 173 | URIRef("http://www.example.com/prop"), 174 | Literal("foo", "en"))) 175 | g.add((URIRef("http://localhost:8080/foo_typo"), 176 | URIRef("http://www.example.com/prop"), 177 | Literal("bar", "en"))) 178 | obj = jsonld_from_model(g, "http://localhost:8080/foo") 179 | print("others") 180 | print(obj) 181 | self.assertDictEqual({ 182 | "@context": self.ctxt({ 183 | "prop": "http://www.example.com/prop" 184 | }), 185 | "@graph": [ 186 | { 187 | "@id": "foo", 188 | "prop": { 189 | "@value": "foo", 190 | "@language": "en" 191 | } 192 | }, 193 | { 194 | "@id": "foo_typo", 195 | "prop": { 196 | "@value": "bar", 197 | "@language": "en" 198 | } 199 | } 200 | ] 201 | }, obj) 202 | 203 | def test_type(self): 204 | g = Graph() 205 | g.add((URIRef("http://localhost:8080/foo"), 206 | URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), 207 | URIRef("http://www.example.com/Bar"))) 208 | obj = jsonld_from_model(g, "http://localhost:8080/foo") 209 | print("type") 210 | print(obj) 211 | self.assertDictEqual({ 212 | "@context": self.ctxt({"rdf": str(RDF)}), 213 | "@id": "foo", 214 | "@type": "http://www.example.com/Bar"}, obj) 215 | 216 | def test_int(self): 217 | g = Graph() 218 | g.add((URIRef("http://localhost:8080/foo"), 219 | URIRef("http://www.example.com/prop"), 220 | Literal("3", datatype=XSD.integer))) 221 | obj = jsonld_from_model(g, "http://localhost:8080/foo") 222 | print("int") 223 | print(obj) 224 | self.assertDictEqual({ 225 | "@context": self.ctxt({"prop": "http://www.example.com/prop"}), 226 | "@id": "foo", 227 | "prop": 3}, obj) 228 | 229 | 230 | if __name__ == '__main__': 231 | unittest.main() 232 | -------------------------------------------------------------------------------- /python/yuzu/tests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import multiprocessing 4 | import sys 5 | import StringIO 6 | 7 | import server 8 | import backend 9 | from settings import * 10 | 11 | from rdflib import Graph, RDFS, URIRef, Literal 12 | 13 | __author__ = "John P. McCrae" 14 | 15 | class YuzuTests(unittest.TestCase): 16 | """ Test cases for Yuzu 17 | """ 18 | def setUp(self): 19 | self.srv = server.RDFServer("test.db") 20 | buf = StringIO.StringIO("<%stest_resource> \"test\"@eng .\n" % BASE_NAME) 21 | self.srv.backend.load(buf) 22 | 23 | def tearDown(self): 24 | self.srv.backend.close() 25 | os.remove("test.db") 26 | 27 | def test_resolve(self): 28 | assert(os.path.exists(server.resolve('html/rdf2html.mustache'))) 29 | 30 | def test_SPARQLExecutor_run(self): 31 | g = Graph() 32 | parent, child = multiprocessing.Pipe() 33 | executor = server.SPARQLExecutor("select * { ?s ?p ?o }", 'sparql', None, child, g) 34 | executor.start() 35 | executor.join() 36 | result_type, result = parent.recv() 37 | self.assertNotEqual('error', result_type) 38 | 39 | def test_RDFServer_render_html(self): 40 | result = self.srv.render_html("Title","Some text") 41 | self.assertIn(' ?o }", "html", None, start_response) 82 | self.assertIn('200', buf.getvalue()) 83 | buf = StringIO.StringIO() 84 | def start_response(x, y): buf.write(str(x) + "\n") 85 | self.srv.sparql_query("select * { ?s ?o }", "turtle", None, start_response) 86 | self.assertIn('400', buf.getvalue()) 87 | buf = StringIO.StringIO() 88 | def start_response(x, y): buf.write(str(x) + "\n") 89 | result = self.srv.sparql_query("select * { ?s ?o }", "html", None, start_response) 90 | self.assertIn(' 2 | / 3 | 4 | -------------------------------------------------------------------------------- /scala/load_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | if [[ $DIR != $(pwd) ]] 5 | then 6 | echo "You must run this script from the folder yuzu/scala" 7 | exit 8 | fi 9 | 10 | sbt "run-main com.github.jmccrae.yuzu.RDFBackend $@" 11 | -------------------------------------------------------------------------------- /scala/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "0.9.0") 2 | -------------------------------------------------------------------------------- /scala/src/main/scala/yuzu/backend.scala: -------------------------------------------------------------------------------- 1 | package com.github.jmccrae.yuzu 2 | 3 | import com.github.jmccrae.yuzu.YuzuSettings._ 4 | import com.hp.hpl.jena.graph.Node 5 | import com.hp.hpl.jena.rdf.model.Model 6 | import com.hp.hpl.jena.query.{ResultSet => RDFResultSet} 7 | import gnu.getopt.Getopt 8 | import java.io.{File, FileInputStream} 9 | import java.util.zip.GZIPInputStream 10 | import scala.collection.JavaConversions._ 11 | 12 | import com.github.jmccrae.sqlutils._ 13 | 14 | case class SearchResult(link : String, label : String, id : String) 15 | case class SearchResultWithCount(link : String, label : String, id : String, count : Int) 16 | 17 | 18 | trait Backend { 19 | /** Run a SPARQL query on the backend */ 20 | def query(query : String, mimeType : ResultType, defaultGraphURI : Option[String], 21 | timeout : Int = 10) : SPARQLResult 22 | /** Lookup all triples relating to be shown on a page */ 23 | def lookup(id : String) : Option[Model] 24 | /** Summarize the key triples to preview a page */ 25 | def summarize(id : String) : Model 26 | /** 27 | * List pages by property and object 28 | * @param offset The query offset 29 | * @param limit The query limit 30 | * @param prop The property (if any) 31 | * @param obj The object value (if any) 32 | */ 33 | def listResources(offset : Int, limit : Int, prop : Option[String] = None, obj : Option[String] = None) : (Boolean,Seq[SearchResult]) 34 | /** 35 | * List all values of a property 36 | * @param offset The query offset 37 | * @param limit The query limit 38 | * @param prop The property 39 | */ 40 | def listValues(offset : Int, limit : Int, prop : String) : (Boolean,Seq[SearchResultWithCount]) 41 | /** 42 | * Find pages containing a given search 43 | * @param query The search terms 44 | * @param property The property 45 | * @param limit The limit 46 | */ 47 | def search(query : String, property : Option[String], 48 | offset : Int, limit : Int) : Seq[SearchResult] 49 | /** 50 | * Load the data from an input stream 51 | */ 52 | def load(inputStream : => java.io.InputStream, ignoreErrors : Boolean, 53 | maxCache : Int = 1000000) : Unit 54 | /** 55 | * Return the total number of triples in the model 56 | */ 57 | def tripleCount : Int 58 | /** 59 | * Return the link counts 60 | */ 61 | def linkCounts : Seq[(String, Int)] 62 | } 63 | 64 | sealed trait SPARQLResult 65 | 66 | case class TableResult(result : ResultSet) extends SPARQLResult { 67 | import scala.collection.JavaConversions._ 68 | 69 | def toDict = { 70 | val variables = result.resultVars.map { name => 71 | mapAsJavaMap(Map("name" -> name)) 72 | } 73 | val results = new java.util.ArrayList[java.util.Map[String, java.util.ArrayList[java.util.Map[String,String]]]]() 74 | for(r <- result.results) { 75 | val r2 = new java.util.HashMap[String, java.util.ArrayList[java.util.Map[String,String]]]() 76 | val l2 = new java.util.ArrayList[java.util.Map[String,String]]() 77 | r2.put("result", l2) 78 | for(v <- result.resultVars) { 79 | if(r.contains(v)) { 80 | val o = r(v) 81 | val target = new java.util.HashMap[String, String]() 82 | if(o.isURI()) { 83 | target.put("uri", o.getURI()) 84 | target.put("display", DISPLAYER.uriToStr(o.getURI())) 85 | } else if(o.isLiteral()) { 86 | val l = o 87 | target.put("value", l.getLiteralLexicalForm()) 88 | if(l.getLiteralLanguage() != null) { 89 | target.put("lang", l.getLiteralLanguage()) 90 | } 91 | if(l.getLiteralDatatype() != null) { 92 | target.put("datatype", l.getLiteralDatatype().getURI()) 93 | } 94 | } else if(o.isBlank()) { 95 | target.put("bnode", o.getBlankNodeId().toString()) 96 | } 97 | l2.add(target) 98 | } else { 99 | l2.add(new java.util.HashMap[String, String]()) 100 | } 101 | } 102 | results.add(r2) 103 | } 104 | Seq[(String, Any)]("variables" -> variables, "results" -> results) 105 | } 106 | 107 | def toXML = 108 | { 109 | for(v <- result.resultVars) yield { 110 | } 111 | } 112 | { 113 | for(r <- result.results) yield { 114 | { 115 | for((varName, node) <- r) yield { 116 | { 117 | if(node.isURI()) { 118 | {node.getURI()} } 119 | else if(node.isBlank()) { 120 | {node.getBlankNodeId()} } 121 | else if(node.isLiteral() && node.getLiteralLanguage() != null 122 | && node.getLiteralLanguage() != "") { 123 | {node.getLiteralLexicalForm()} } 124 | else if(node.isLiteral() && node.getLiteralDatatypeURI() != null) { 125 | {node.getLiteralLexicalForm()} } 126 | else /*if(node.isLiteral())*/ { 127 | {node.getLiteralLexicalForm()} } 128 | }} 129 | }} 130 | } 131 | 132 | 133 | def toJSON = """{ 134 | "head": { "vars": [ %s ] }, 135 | "results": { 136 | "bindings": [ 137 | %s 138 | ] 139 | } 140 | }""" format ( 141 | result.resultVars.map("\"" + _ + "\"").mkString(", "), 142 | "{\n" + (result.results.map { m => 143 | (m.map { 144 | case (varName, node) => 145 | val binding = """ "%s": { "type": "%s", "value": "%s"%s }""" 146 | if(node.isURI()) { 147 | binding format (varName, "uri", node.getURI(), "") } 148 | else if(node.isBlank()) { 149 | binding format (varName, "bnode", node.getBlankNodeId(),"") } 150 | else if(node.isLiteral() && node.getLiteralLanguage() != null 151 | && node.getLiteralLanguage() != "") { 152 | binding format (varName, "literal", node.getLiteralLexicalForm(), 153 | ", \"xml:lang\": \"" + node.getLiteralLanguage() + "\"") } 154 | else if(node.isLiteral() && node.getLiteralDatatypeURI() != null) { 155 | binding format (varName, "literal", node.getLiteralLexicalForm(), 156 | ", \"datatype\": \"" + node.getLiteralDatatypeURI() + "\"") } 157 | else /*if(node.isLiteral())*/ { 158 | binding format (varName, "literal", node.getLiteralLexicalForm(), "") } }). 159 | mkString(",\n") } ).mkString("\n }, {\n") + "\n }") 160 | 161 | } 162 | 163 | case class BooleanResult(result : Boolean) extends SPARQLResult 164 | case class ModelResult(result : Model) extends SPARQLResult 165 | case class ErrorResult(message : String, cause : Throwable = null) extends SPARQLResult 166 | 167 | class ResultSet(val resultVars : Seq[String], val results : Seq[Map[String, Node]]) 168 | 169 | object ResultSet { 170 | def apply(resultVars : Seq[String], results : Seq[Map[String, Node]]) = 171 | new ResultSet(resultVars, results) 172 | def apply(jenaResultSet : RDFResultSet) = 173 | new ResultSet(jenaResultSet.getResultVars().toSeq, 174 | (jenaResultSet.map { r => 175 | (jenaResultSet.getResultVars().flatMap { v => 176 | if(r.contains(v)) { 177 | Some(v -> r.get(v).asNode()) } 178 | else { 179 | None }}).toMap }).toSeq) 180 | } 181 | 182 | object RDFBackend { 183 | def main(args : Array[String]) { 184 | val getopt = new Getopt("yuzubackend", args, "d:f:m:e") 185 | var opts = collection.mutable.Map[String, String]() 186 | var c = 0 187 | while({c = getopt.getopt(); c } != -1) { 188 | c match { 189 | case 'd' => opts("-d") = getopt.getOptarg() 190 | case 'f' => opts("-f") = getopt.getOptarg() 191 | case 'm' => opts("-m") = getopt.getOptarg() 192 | case 'e' => opts("-e") = "true" 193 | } 194 | } 195 | val backend = new TripleBackend(opts.getOrElse("-d", DB_FILE)) 196 | val endsGZ = ".*\\.gz".r 197 | def inputStream = opts.getOrElse("-f", DUMP_FILE) match { 198 | case file @ endsGZ() => new GZIPInputStream(new FileInputStream(file)) 199 | case file => new FileInputStream(file) 200 | } 201 | backend.load(inputStream, opts contains "-e", 202 | opts.getOrElse("-m", "1000000").toInt) 203 | //backend.close() 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /scala/src/main/scala/yuzu/dataid.scala: -------------------------------------------------------------------------------- 1 | package com.github.jmccrae.yuzu 2 | 3 | import com.github.jmccrae.yuzu.YuzuSettings._ 4 | import com.hp.hpl.jena.datatypes.xsd.XSDDateTime 5 | import com.hp.hpl.jena.graph.NodeFactory 6 | import com.hp.hpl.jena.rdf.model.{Model, ModelFactory} 7 | import com.hp.hpl.jena.vocabulary._ 8 | 9 | object DataID { 10 | 11 | def get : Model = { 12 | val model = ModelFactory.createDefaultModel() 13 | val backend = new TripleBackend(DB_FILE) 14 | 15 | val dataid = model.createResource(BASE_NAME + METADATA_PATH) 16 | 17 | dataid.addProperty(RDF.`type`, model.createResource(DCAT + "Dataset")) 18 | dataid.addProperty(RDF.`type`, model.createResource(VOID + "Dataset")) 19 | 20 | dataid.addProperty( 21 | model.createProperty(DCAT + "title"), 22 | DISPLAY_NAME, LANG) 23 | 24 | dataid.addProperty( 25 | RDFS.label, 26 | DISPLAY_NAME, LANG) 27 | 28 | dataid.addProperty( 29 | model.createProperty(DCAT + "landingPage"), 30 | model.createResource(BASE_NAME)) 31 | 32 | backend.listResources(0, 1)._2.headOption match { 33 | case Some(SearchResult(link, _, _)) => 34 | dataid.addProperty( 35 | model.createProperty(VOID + "exampleResource"), 36 | model.createResource(BASE_NAME.dropRight(1) + link)) 37 | case None => 38 | } 39 | 40 | dataid.addProperty( 41 | DC_11.language, 42 | LANG) 43 | 44 | dataid.addProperty( 45 | model.createProperty(VOID + "rootResource"), 46 | model.createResource(BASE_NAME.dropRight(1) + LIST_PATH)) 47 | 48 | ONTOLOGY match { 49 | case Some(o) => 50 | dataid.addProperty( 51 | model.createProperty(DATAID + "ontologyLocation"), 52 | model.createResource(BASE_NAME + o)) 53 | case None => 54 | } 55 | 56 | ISSUE_DATE match { 57 | case Some(id) => 58 | dataid.addProperty( 59 | DCTerms.issued, 60 | id, NodeFactory.getType(XSD.date.getURI())) 61 | case None => 62 | } 63 | 64 | VERSION_INFO match { 65 | case Some(vi) => 66 | dataid.addProperty( 67 | model.createProperty(DATAID + "versionInfo"), 68 | vi) 69 | case None => 70 | } 71 | 72 | DESCRIPTION match { 73 | case Some(d) => 74 | dataid.addProperty( 75 | DC_11.description, 76 | d, LANG) 77 | case None => 78 | } 79 | 80 | dataid.addProperty( 81 | model.createProperty(ODRL + "license"), 82 | model.createResource(BASE_NAME.dropRight(1) + LICENSE_PATH)) 83 | 84 | LICENSE match { 85 | case Some(l) => 86 | dataid.addProperty( 87 | DC_11.rights, 88 | model.createResource(l)) 89 | case None => 90 | } 91 | 92 | for(keyword <- KEYWORDS) { 93 | dataid.addProperty( 94 | model.createProperty(DCAT + "keyword"), 95 | keyword) 96 | } 97 | 98 | PUBLISHER_NAME match { 99 | case Some(pn) => 100 | val publisher = model.createResource(BASE_NAME + METADATA_PATH + "#Publisher") 101 | publisher.addProperty(RDF.`type`, model.createResource(FOAF + "Agent")) 102 | publisher.addProperty(RDF.`type`, model.createResource(PROV + "Agent")) 103 | dataid.addProperty( 104 | DC_11.publisher, 105 | publisher) 106 | publisher.addProperty( 107 | model.createProperty(FOAF + "name"), 108 | pn) 109 | PUBLISHER_EMAIL match { 110 | case Some(pe) => 111 | publisher.addProperty( 112 | model.createProperty(FOAF + "mbox"), 113 | pe) 114 | case None => 115 | } 116 | case None => 117 | } 118 | 119 | for(((cn, ce), id) <- (CREATOR_NAMES zip CREATOR_EMAILS).zipWithIndex) { 120 | val creator = model.createResource(BASE_NAME + METADATA_PATH + "#Creator-" + (id + 1)) 121 | creator.addProperty(RDF.`type`, model.createResource(FOAF + "Agent")) 122 | creator.addProperty(RDF.`type`, model.createResource(PROV + "Agent")) 123 | dataid.addProperty( 124 | DC_11.creator, 125 | creator) 126 | creator.addProperty( 127 | model.createProperty(FOAF + "name"), 128 | cn) 129 | if(ce != "") { 130 | creator.addProperty( 131 | model.createProperty(FOAF + "mbox"), 132 | ce) 133 | } 134 | } 135 | 136 | for(((cn, ce), id) <- (CONTRIBUTOR_NAMES zip CONTRIBUTOR_EMAILS).zipWithIndex) { 137 | val creator = model.createResource(BASE_NAME + METADATA_PATH + "#Contributor-" + (id + 1)) 138 | creator.addProperty(RDF.`type`, model.createResource(FOAF + "Agent")) 139 | creator.addProperty(RDF.`type`, model.createResource(PROV + "Agent")) 140 | dataid.addProperty( 141 | DC_11.creator, 142 | creator) 143 | creator.addProperty( 144 | model.createProperty(FOAF + "name"), 145 | cn) 146 | if(ce != "") { 147 | creator.addProperty( 148 | model.createProperty(FOAF + "mbox"), 149 | ce) 150 | } 151 | } 152 | 153 | for(de <- DERIVED_FROM) { 154 | dataid.addProperty( 155 | model.createProperty(PROV + "wasDerivedFrom"), 156 | model.createResource(de)) 157 | } 158 | 159 | val dump = model.createResource(BASE_NAME + METADATA_PATH + "#Dump") 160 | 161 | dump.addProperty(RDF.`type`, model.createResource(DCAT + "Distribution")) 162 | 163 | dataid.addProperty( 164 | model.createProperty(DCAT + "distribution"), 165 | dump) 166 | 167 | dump.addProperty( 168 | model.createProperty(DCAT + "downloadURL"), 169 | model.createResource(BASE_NAME.dropRight(1) + DUMP_URI)) 170 | 171 | dataid.addProperty( 172 | model.createProperty(VOID + "triples"), 173 | backend.tripleCount.toString, NodeFactory.getType(XSD.integer.getURI())) 174 | 175 | dump.addProperty( 176 | model.createProperty(VOID + "triples"), 177 | backend.tripleCount.toString, NodeFactory.getType(XSD.integer.getURI())) 178 | 179 | dump.addProperty( 180 | DC_11.format, 181 | "application/x-gzip") 182 | 183 | SPARQL_ENDPOINT match { 184 | case Some(se) => 185 | dataid.addProperty( 186 | model.createProperty(VOID + "sparqlEndpoint"), 187 | model.createResource(se)) 188 | case None => 189 | dataid.addProperty( 190 | model.createProperty(VOID + "sparqlEndpoint"), 191 | model.createProperty(BASE_NAME.dropRight(1) + SPARQL_PATH)) 192 | } 193 | 194 | for(((target, count), id) <- backend.linkCounts.zipWithIndex) { 195 | val linkset = model.createResource(BASE_NAME + METADATA_PATH + "#LinkSet-" + (id + 1)) 196 | dataid.addProperty( 197 | model.createProperty(VOID + "subset"), 198 | linkset) 199 | linkset.addProperty( 200 | model.createProperty(VOID + "subjectTargets"), 201 | dataid) 202 | linkset.addProperty( 203 | model.createProperty(VOID + "target"), 204 | model.createResource(target)) 205 | linkset.addProperty( 206 | model.createProperty(VOID + "triples"), 207 | count.toString, NodeFactory.getType(XSD.integer.getURI())) 208 | linkset.addProperty( 209 | RDF.`type`, 210 | model.createResource(VOID + "LinkSet")) 211 | } 212 | 213 | model 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /scala/src/main/scala/yuzu/ql/parse.scala: -------------------------------------------------------------------------------- 1 | package com.github.jmccrae.yuzu.ql 2 | 3 | import scala.util.parsing.combinator._ 4 | 5 | object YuzuQLSyntax extends JavaTokenParsers { 6 | private def ignoreCase(str : String) = ("(?i)\\Q" + str + "\\E").r 7 | 8 | def uri = regex("<.*?>".r) ^^ { FullURI(_) } 9 | 10 | def pnLocal = regex("[A-Za-z_][A-Za-z\\-\\.0-9_]*".r) 11 | 12 | def pnPrefix = regex("[A-Za-z][A-Za-z\\-\\.0-9_]*".r) 13 | 14 | def pnameNs = (pnPrefix | "") <~ ":" 15 | 16 | def pnameLn = pnameNs ~ pnLocal ^^ { 17 | case x ~ y => PrefixedName(x, y) 18 | } 19 | 20 | def uriref = pnameLn | uri 21 | 22 | def prefix = (ignoreCase("prefix") ~> pnameNs ~ uri) ^^ { 23 | case x ~ y => x -> y 24 | } 25 | 26 | def prefixes = rep(prefix) ^^ (es => Map() ++ es) 27 | 28 | def select = ignoreCase("select") ~> (opt(ignoreCase("distinct")) ^^ { 29 | case Some(x) => true 30 | case None => false 31 | }) 32 | 33 | def `var` = regex("[\\?\\$][A-Za-z0-9]+".r) ^^ (s => Var(s.drop(1))) 34 | 35 | def count = ("(" ~> ignoreCase("count") ~> "(" ~> "*" ~> ")" ~> 36 | ignoreCase("as") ~> `var` <~ ")") 37 | 38 | def varList = rep1(`var`) | ("*" ^^^ Nil) 39 | 40 | def countVarList = (count ~ rep1(`var`) ^^ { case x ~ y => (Some(x), y) }) | 41 | (count ^^ { x => (Some(x), Nil) }) | 42 | (varList ^^ { (None, _) }) 43 | 44 | def where = ignoreCase("where") 45 | 46 | def plainLiteral = stringLiteral ^^ { PlainLiteral(_) } 47 | 48 | def langLiteral = (stringLiteral ~ "@" ~ "[A-Za-z0-9\\-]+".r) ^^ { 49 | case x ~ y ~ z => LangLiteral(x, z.toLowerCase) 50 | } 51 | 52 | def typedLiteral = (stringLiteral ~ ("^^" ~> uriref)) ^^ { 53 | case x ~ y => TypedLiteral(x, y) 54 | } 55 | 56 | def objValue = uriref | langLiteral | typedLiteral | plainLiteral 57 | 58 | def a = "a" ^^^ FullURI("") 59 | 60 | def bnode : Parser[BNC] = "[" ~> t2 <~ "]" ^^ { BNC(_) } 61 | 62 | def obj = rep1sep(objValue | `var` | bnode, ",") ^^ { ObjList(_) } 63 | 64 | def prop = uriref | a 65 | 66 | def propObj3 = (prop ~ obj) ^^ { case x ~ y => PropObj(x, y) } 67 | 68 | def propObj2 = rep1sep(propObj3, "|") ^^ { PropObjDisjunction(_, false) } 69 | 70 | def propObjOpt = "(" ~> rep1sep(propObj3, "|") <~ ")" ^^ { 71 | PropObjDisjunction(_, true) } 72 | 73 | def propObj = propObj2 | propObjOpt 74 | 75 | def t2 = propObj2 ~ rep(";" ~> propObj) ^^ { 76 | case x ~ y => x +: y 77 | } 78 | 79 | def triplePattern = (`var` | uriref) ~ t2 ~ ".".? ^^ { 80 | case x ~ y ~ _ => Triple(x, y) } 81 | 82 | def whereClause = "{" ~> triplePattern <~ "}" 83 | 84 | def asc = ignoreCase("asc") ~> "(" ~> ignoreCase("str") ~> "(" ~> `var` <~ 85 | ")" <~ ")" ^^ { Order(_, 1) } 86 | 87 | def desc = ignoreCase("desc") ~> "(" ~> ignoreCase("str") ~> "(" ~> `var` <~ 88 | ")" <~ ")" ^^ { Order(_, -1) } 89 | 90 | def groupByClause = ignoreCase("group") ~> ignoreCase("by") ~> rep1(`var`) 91 | 92 | def orderCond = asc | desc | (ignoreCase("str") ~> "(" ~> `var` <~ ")" ^^ { Order(_, 0) }) 93 | 94 | def orderConditions = rep1(orderCond) 95 | 96 | def orderClause = ignoreCase("order") ~> ignoreCase("by") ~> orderConditions 97 | 98 | def limitClause = ignoreCase("limit") ~> "[0-9]+".r ^^ (_.toInt) 99 | 100 | def offsetClause = ignoreCase("offset") ~> "[0-9]+".r ^^ (_.toInt) 101 | 102 | def limitOffsetClause : Parser[(Int, Int)] = { 103 | ((limitClause ~ offsetClause) ^^ { case x ~ y => (x, y) }) | 104 | ((offsetClause ~ limitClause) ^^ { case x ~ y => (y, x) }) | 105 | (limitClause ^^ { (_, -1) }) | 106 | (offsetClause ^^ { (-1, _) }) 107 | } 108 | 109 | def solutionModifier = groupByClause.? ~ orderClause.? ~ limitOffsetClause.? ^^ { 110 | case z ~ x ~ y => (z, x.getOrElse(Nil), y.getOrElse((-1, -1))) } 111 | 112 | def query(prefix : PrefixLookup) = prefixes ~ select ~ countVarList ~ where.? ~ whereClause ~ 113 | solutionModifier ^^ { 114 | case p ~ s ~ cv ~ _ ~ w ~ o => 115 | val (gb, by, (l, of)) = o 116 | val (c, v) = cv 117 | if(gb != None && c != None && gb.get != v) 118 | throw new IllegalArgumentException("Group by was not select variables") 119 | SelectQuery(s, c, v, w, by, l, of).resolve(prefix ++ p) } 120 | 121 | def parse(s : String, prefix : PrefixLookup) = parseAll(query(prefix), s) match { 122 | case Success(query, _) => 123 | query 124 | case failure : NoSuccess => 125 | throw new IllegalArgumentException(failure.toString) } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /scala/src/main/scala/yuzu/settings.scala: -------------------------------------------------------------------------------- 1 | package com.github.jmccrae.yuzu 2 | 3 | object YuzuSettings { 4 | // This file contains all relevant configuration for the system 5 | 6 | // The location where this server is to be deployed to 7 | // Only URIs in the dump that start with this address will be published 8 | // Should end with a trailing / 9 | val BASE_NAME = "http://localhost:8080/" 10 | // The prefix that this servlet will be deployed, e.g. 11 | // if the servlet is at http://www.example.org/yuzu/ the context 12 | // is /yuzu 13 | // NB. To change from SBT you must separately edit jetty-env.xml 14 | val CONTEXT = "" 15 | // The data download will be at BASE_NAME + DUMP_URI 16 | val DUMP_URI = "/example.nt.gz" 17 | // The local path to the data 18 | val DUMP_FILE = "../example.nt.gz" 19 | // Where the database should appear 20 | val DB_FILE = "example.db" 21 | // The name of the server 22 | val DISPLAY_NAME = "Example" 23 | 24 | // The extra namespaces to be abbreviated in HTML and RDF/XML documents if desired 25 | val PREFIX1_URI = "http://www.example.com/" 26 | val PREFIX1_QN = "ex1" 27 | val PREFIX2_URI = "http://www.example.com/" 28 | val PREFIX2_QN = "ex2" 29 | val PREFIX3_URI = "http://www.example.com/" 30 | val PREFIX3_QN = "ex3" 31 | val PREFIX4_URI = "http://www.example.com/" 32 | val PREFIX4_QN = "ex4" 33 | val PREFIX5_URI = "http://www.example.com/" 34 | val PREFIX5_QN = "ex5" 35 | val PREFIX6_URI = "http://www.example.com/" 36 | val PREFIX6_QN = "ex6" 37 | val PREFIX7_URI = "http://www.example.com/" 38 | val PREFIX7_QN = "ex7" 39 | val PREFIX8_URI = "http://www.example.com/" 40 | val PREFIX8_QN = "ex8" 41 | val PREFIX9_URI = "http://www.example.com/" 42 | val PREFIX9_QN = "ex9" 43 | 44 | // Used for DATAID 45 | val DCAT = "http://www.w3.org/ns/dcat#" 46 | val VOID = "http://rdfs.org/ns/void#" 47 | val DATAID = "http://dataid.dbpedia.org/ns#" 48 | val FOAF = "http://xmlns.com/foaf/0.1/" 49 | val ODRL = "http://www.w3.org/ns/odrl/2/" 50 | val PROV = "http://www.w3.org/ns/prov#" 51 | 52 | // The maximum number of results to return from a YuzuQL query (or -1 for no 53 | // limit) 54 | val YUZUQL_LIMIT = 1000 55 | // If using an external SPARQL endpoint, the address of this 56 | // or None if you wish to use only YuzuQL 57 | val SPARQL_ENDPOINT : Option[String] = None 58 | // Path to the license (set to null to disable) 59 | val LICENSE_PATH = "/license.html" 60 | // Path to the search (set to null to disable) 61 | val SEARCH_PATH = "/search" 62 | // Path to static assets 63 | val ASSETS_PATH = "/assets/" 64 | // Path to SPARQL (set to null to disable) 65 | val SPARQL_PATH = "/sparql" 66 | // Path to site contents list (set to null to disable) 67 | val LIST_PATH = "/list" 68 | // Path to Data ID (metadata) (no initial slash) 69 | val METADATA_PATH = "about" 70 | 71 | // Properties to use as facets 72 | val FACETS = Seq( 73 | Map("uri" -> "http://www.w3.org/2000/01/rdf-schema#label", "label" -> "Label", "list" -> true) 74 | ) 75 | // Properties to use as labels 76 | val LABELS = Set( 77 | "", 78 | "", 79 | "", 80 | "", 81 | "" 82 | ) 83 | // The displayer for URIs 84 | val DISPLAYER = PrettyDisplayer 85 | 86 | // Any forced names on properties 87 | val PROP_NAMES = Map( 88 | "http://localhost:8080/ontology#link" -> "Link property" 89 | ) 90 | // Linked datasets (this is only used for metadata but is created 91 | // on DB load). Not linked indicates URI starts which are not to 92 | // be considered links, any other links are assumed to start with the 93 | // server. 94 | val LINKED_SETS = List("http://dbpedia.org/") 95 | val NOT_LINKED = List("http://www.w3.org/", "http://purl.org/dc/", 96 | "http://xmlns.org/", "http://rdfs.org/", "http://schema.org/") 97 | // Never show inverse links on the following pages 98 | val NO_INVERSE = List( 99 | "http://localhost:8080/ontology" 100 | ) 101 | // The minimum number of links to another dataset to be included in metadata 102 | val MIN_LINKS = 1 103 | 104 | // Metadata 105 | 106 | // The language of this site 107 | val LANG = "en" 108 | // If a resource in the data is the schema (ontology) then include its 109 | // path here. No intial slash, should resolve at BASE_NAME + ONTOLOGY 110 | val ONTOLOGY : Option[String] = None 111 | // The date the resource was created, e.g., 112 | // The date should be of the format YYYY-MM-DD 113 | val ISSUE_DATE : Option[String] = None 114 | // The version number 115 | val VERSION_INFO : Option[String] = None 116 | // A longer textual description of the resource 117 | val DESCRIPTION : Option[String] = None 118 | // If using a standard license include the link to this license 119 | val LICENSE : Option[String] = None 120 | // Any keywords (if necessary) 121 | val KEYWORDS : Seq[String] = Nil 122 | // The publisher of the dataset 123 | val PUBLISHER_NAME : Option[String] = None 124 | val PUBLISHER_EMAIL : Option[String] = None 125 | // The creator(s) of the dataset 126 | // The lists must be the same size, use an empty string if you do not wish 127 | // to publish the email address 128 | val CREATOR_NAMES : Seq[String] = Nil 129 | val CREATOR_EMAILS : Seq[String] = Nil 130 | require(CREATOR_EMAILS.size == CREATOR_NAMES.size) 131 | // The contributor(s) to the dataset 132 | val CONTRIBUTOR_NAMES : Seq[String] = Nil 133 | val CONTRIBUTOR_EMAILS : Seq[String] = Nil 134 | require(CONTRIBUTOR_EMAILS.size == CONTRIBUTOR_NAMES.size) 135 | // Links to the resources this data set was derived from 136 | val DERIVED_FROM : Seq[String] = Nil 137 | } 138 | -------------------------------------------------------------------------------- /scala/src/main/scala/yuzu/user_text.scala: -------------------------------------------------------------------------------- 1 | package com.github.jmccrae.yuzu 2 | 3 | object YuzuUserText { 4 | val YZ_MOVED_TO="Moved to" 5 | val YZ_INVALID_QUERY="The query could not be understood" 6 | val YZ_BAD_REQUEST="Bad request" 7 | val YZ_NOT_FOUND_TITLE="Not found" 8 | val YZ_NOT_FOUND_PAGE="The requested URL does not exist" 9 | val YZ_JSON_LD_NOT_INSTALLED="You requested a format not installed on this server" 10 | val YZ_NOT_IMPLEMENTED="Not Implemented" 11 | val YZ_NO_QUERY="No Query" 12 | val YZ_NO_RESULTS="No Results" 13 | val YZ_BAD_QUERY="Bad query" 14 | val YZ_BAD_MIME="Bad MIME request" 15 | val YZ_QUERY_TOO_BROAD="Query too broad" 16 | val YZ_NO_DATA="No data is yet loaded in the system" 17 | val YZ_INDEX="Index" 18 | val YZ_TIME_OUT="The query could not be processed in time" 19 | val YZ_METADATA="About this resource" 20 | val YZ_QUERY_LIMIT_EXCEEDED="No query limit or limit too high (%d is this server's limit)" 21 | val YZ_BINARY_NOT_FOUND="Could not locate binary file. Please make sure you are using absolute paths especially for the dump" 22 | } 23 | -------------------------------------------------------------------------------- /scala/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | yuzu 11 | com.github.jmccrae.yuzu.YuzuServlet 12 | 13 | 14 | 15 | yuzu 16 | /* 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /scala/src/test/scala/yuzu/server_test.scala: -------------------------------------------------------------------------------- 1 | package com.github.jmccrae.yuzu 2 | 3 | import com.hp.hpl.jena.rdf.model.{Seq => _, _} 4 | import com.hp.hpl.jena.graph.NodeFactory 5 | import com.hp.hpl.jena.query.{QueryFactory, QueryExecutionFactory} 6 | import java.io.{File, PrintWriter, StringWriter} 7 | import java.net.URL 8 | import javax.servlet.http._ 9 | import org.scalatest.mock.MockitoSugar 10 | import org.scalatest._ 11 | import org.mockito.Mockito.{when, verify} 12 | 13 | class DummyBackend extends Backend { 14 | def query(query : String, mimeType : ResultType, defaultGraphURI : Option[String], 15 | timeout : Int = 10) = BooleanResult(true) 16 | def lookup(id : String) = if(id == "test_resource") { 17 | Some(ModelFactory.createDefaultModel()) 18 | } else { 19 | None 20 | } 21 | def summarize(id : String) = ModelFactory.createDefaultModel() 22 | def listResources(offset : Int, limit : Int, prop : Option[String] = None, obj : Option[String] = None) = { 23 | (false, List(SearchResult("/test_resource", "resource", "test_resource"))) 24 | } 25 | def listValues(offset : Int, limit : Int, prop : String) = (false, Nil) 26 | //def list(subj : Option[String], prop : Option[String], obj : Option[String], offset : Int = 0, limit : Int = 20) : (Boolean,Seq[Triple]) 27 | def search(query : String, property : Option[String], offset : Int, limit : Int) = Nil 28 | def load(inputStream : => java.io.InputStream, ignoreErrors : Boolean, 29 | maxCache : Int) { } 30 | def tripleCount = 0 31 | def linkCounts = Nil 32 | } 33 | 34 | class ServerTests extends FlatSpec with BeforeAndAfterAll with MockitoSugar with Matchers { 35 | import YuzuSettings._ 36 | 37 | val rdfServer = new RDFServer(new DummyBackend()) 38 | 39 | // "sparql executor" should "answer a query" in { 40 | // val model = ModelFactory.createDefaultModel() 41 | // val q = QueryFactory.create("select * { ?s ?p ?o }") 42 | // val qx = QueryExecutionFactory.create(q, model) 43 | // val executor = new SPARQLExecutor(q, qx) 44 | // executor.run() 45 | // assert(!executor.result.isInstanceOf[ErrorResult]) 46 | // } 47 | 48 | "server" should "render html" in { 49 | val result = RDFServer.renderHTML("Title","Some text", false)(new PathResolver { def apply(s : String) = new URL("file:../common/"+s) } ) 50 | 51 | assert(result contains " ?o }")) 92 | when(mockRequest.getParameterMap()) thenReturn paramMap 93 | when(mockResponse.getWriter()) thenReturn new PrintWriter(out) 94 | when(mockRequest.getRequestURL()) thenReturn (new StringBuffer(BASE_NAME)) 95 | rdfServer.service(mockRequest, mockResponse) 96 | verify(mockResponse).setStatus(200) 97 | } 98 | 99 | //"server" should "not select into turtle" in { 100 | // val mockResponse = mock[HttpServletResponse] 101 | // val out = new StringWriter() 102 | // when(mockResponse.getWriter()) thenReturn new PrintWriter(out) 103 | // intercept[IllegalArgumentException] { 104 | // rdfServer.sparqlQuery("select * { ?s ?o }", turtle, None, mockResponse) 105 | // } 106 | //} 107 | 108 | "server" should "render sparql results in html" in { 109 | val mockResponse = mock[HttpServletResponse] 110 | val out = new StringWriter() 111 | when(mockResponse.getWriter()) thenReturn new PrintWriter(out) 112 | rdfServer.sparqlQuery("select * { ?s ?o }", html, None, mockResponse) 113 | assert(out.toString().contains("