[
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Unit tests\n\non:\n  - push\n  - pull_request\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version: ['2.7', '3.7', '3.8', '3.9', '3.10']\n\n    steps:\n    - uses: actions/checkout@v1\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v2\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        python -m pip install tox tox-gh-actions\n    - name: Test with tox\n      run: tox\n"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# Distribution / packaging\nenv/\nbuild/\ndist/\n\n# Unit test / coverage reports\n.tox/\n\n# Sphinx documentation\ndocs/_build/\n"
  },
  {
    "path": "CHANGES",
    "content": "0.7.1 (2020-01-11):\n    * include README file in pypi\n\n0.7 (2020-01-09):\n    * removed support for PUIDs and Echoprint (Alastair Porter, #237)\n    * removed the 'artists' include for work lookup (Alastair Porter, #231 & #227)\n    * allow the 'work-level-rels' include for recording lookups (Shen-Ta Hsieh, #213)\n    * added support for 'target-credit' elements (Itay Brandes, #162 & #217)\n    * update valid search fields (Alastair Porter, #239)\n    * use https by default with musicbrainz.org (Frederik “Freso” S. Olesen, #197)\n\n0.6 (2016-04-11):\n    * don't require authentication when getting public collections (#87)\n    * allow submit_ratings() and submit_tags() to submit for all supported entities (Ian McEwen, #145)\n    * allow 'tags' and 'user-tags' includes on releases (Jérémie Detrey, #150)\n    * set the parser when the webservice format is changed\n    * read the error message from musicbrainz and return it in\n      a raised exception\n    * send authenticaion headers when required (Ryan Helinski, #153)\n    * added get_series_by_id(), search_areas(), search_series() (Ian McEwen, #148)\n    * updated options for get_releases_by_discid() to support 'media-format'\n      and discid-less requests (Ian McEwen, #148)\n    * parse work attributes (Wieland Hoffmann, #151)\n    * added various methods to retrieve data from the Cover Art Archive (Alastair Porter & Wieland Hoffmann, #115)\n    * added support for pregap tracks (Rui Gonçalves, #154 & #165)\n    * return 'offset-list' and 'offset-count' for get_releases_by_discid()\n      (Johannes Dewender, #169)\n    * added support for search and browse of events (Shadab Zafar, #168)\n    * added support for 'data-track-list' elements (Jérémie Detrey, #180)\n    * added support for get and search instruments\n    * added support to read all collection types (#175)\n    * added support for search and browse of places (#176)\n    * allow single strings to be used as includes for browse requests (#172)\n    * allow single strings to be used at tag submission (#172)\n    * added support for browse artist by work and work by artist\n    * added support for 'track-count' elements in 'medium-list's returned by search\n    * added support to read xml attributes in 'attribute-list' elements (#142)\n\n0.5 (2014-02-06):\n    * added get_url_by_id() and browse_urls() (Ian McEwen, #117)\n    * added get_area_by_id() and get_place_by_id() (Ian McEwen, #119 + #132)\n    * added support for custom parsers with set_parser() (Ryan Helinski, #129)\n    * added support for different WS formats with set_format() (Johannes Dewender, #131)\n    * added support for URL MBIDs (Ian McEwen, #132)\n    * added support for link type UUIDs (Ian McEwen, #127 + #132)\n    * support fuzzy disc lookup by TOC (Johannes Dewender, #105)\n    * add -count element for browse and search requests (Johannes Dewender, #135)\n    * deprecated puid and echoprint support (Johannes Dewender, #106)\n    * updated valid includes and browse includes (Ian McEwen, #118)\n    * updated valid search fields and release group types (Ian McEwen, #132)\n    * browsing for get_releases_in_collection() (Johannes Dewender, #88 + #128)\n    * allow browsing releases by track_artist (Johannes Dewender, #107)\n    * fix list submission for isrcs (Johannes Dewender, #113)\n    * fix debug logging and many unparsed entities (Johannes Dewender, #134)\n    * don't install tests with setup.py (Johannes Dewender, #112)\n    * add ISC license (compat.py) to COPYING (Wieland Hoffmann, #111 and #110)\n    * parse the video element of recordings (Wieland Hoffmann, #136)\n    * parse track ids (Wieland Hoffmann)\n    * fixed undefined name in submit_barcodes (Simon Chopin, #109)\n\n    The github repository and RTD doc urls were renamed to python-musicbrainzngs\n    (formerly python-musicbrainz-ngs).\n\n0.4 (2013-05-15):\n    Thanks to Johannes Dewender for all his work in this release!\n    * Improve documentation\n    * Fix get_recordings_by_puid/isrc\n    * Update search fields\n    * Parse CDStubs in release results\n    * Correct release_type/release_status checking\n    * Allow iso-8859-1 passwords\n    * Convert single isrcs to list when submitting\n    * Parse ISRC results\n    * Escape forward slashes in search queries (Adrian Sampson)\n    * Package documentation and examples in release (Alastair Porter)\n\n0.3 (2013-03-11):\n    * Lots of bug fixes! also:\n    * Catch network errors when reading data (Adrian Sampson, #78)\n    * Get and search annotations (Wieland Hoffmann)\n    * Better alias support (Sam Doshi, #83, #86)\n    * Parse track artist-credit if present (Galen Hazelwood, #75)\n    * Show relevancy scores on search results (Alastair Porter, #37)\n    * Perform searches in lower case (Adrian Sampson, #36)\n    * Use AND instead of OR by default in searches (Johannes Dewender)\n    * Parse artist disambiguation field (Paul Bailey, #48)\n    * Send zero-length body requests correctly (Adrian Sampson)\n    * Fix bug in get methods when includes, release status, or release type\n      are included (Alastair Porter, reported by palli81)\n    * Support python 2 and python 3\n    * Update valid includes for some entity queries\n    * Add usage examples\n\n0.2 (2012-03-06):\n    * ISRC submission support (Wieland Hoffmann)\n    * Various submission bug fixes (Wieland Hoffmann)\n    * Retry the query if the connection is reset (Adrian Sampson)\n    * Rename some methods to make the API more consistent (Alastair Porter)\n    * Use test methods from Python 2.6 (Alastair Porter)\n\n0.1: Initial release\n    Contributions by Alastair Porter, Adrian Sampson, Michael Marineau,\n    Thomas Vander Stichele, Ian McEwen\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribute\n\n1. Fork the [repository](https://github.com/alastair/python-musicbrainzngs>)\n   on Github.\n2. Make and test whatever changes you desire.\n3. Signoff and commit your changes using ``git commit -s``.\n4. Send a pull request.\n"
  },
  {
    "path": "COPYING",
    "content": "Copyright 2011 Alastair Porter, Adrian Sampson, and others.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\nThe license for the file `musicbrainzngs/compat.py` is\n\nCopyright (c) 2012 Kenneth Reitz.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include COPYING README.rst CHANGES query.py\nrecursive-include test *.py\nrecursive-include test/data *.xml\ninclude test/data/artist test/data/label test/data/release\ninclude test/data/release-group test/data/work\nrecursive-include docs *.rst\ninclude docs/conf.py docs/Makefile docs/make.bat\nrecursive-include examples *.py\n"
  },
  {
    "path": "README.rst",
    "content": "Musicbrainz NGS bindings\n########################\n\nThis library implements webservice bindings for the Musicbrainz NGS site, also known as /ws/2\nand the `Cover Art Archive <https://coverartarchive.org/>`_.\n\nFor more information on the musicbrainz webservice see `<http://wiki.musicbrainz.org/XML_Web_Service>`_.\n\nUsage\n*****\n\n.. code:: python\n\n    # Import the module\n    import musicbrainzngs\n\n    # If you plan to submit data, authenticate\n    musicbrainzngs.auth(\"user\", \"password\")\n\n    # Tell musicbrainz what your app is, and how to contact you\n    # (this step is required, as per the webservice access rules\n    # at http://wiki.musicbrainz.org/XML_Web_Service/Rate_Limiting )\n    musicbrainzngs.set_useragent(\"Example music app\", \"0.1\", \"http://example.com/music\")\n\n    # If you are connecting to a different server\n    musicbrainzngs.set_hostname(\"beta.musicbrainz.org\")\n\nSee the ``query.py`` file for more examples.\n\nMore documentation is available at\n`Read the Docs <https://python-musicbrainzngs.readthedocs.org>`_.\n\nContribute\n**********\n\nIf you want to contribute to this repository, please read `the\ncontribution guidelines\n<https://github.com/alastair/python-musicbrainzngs/blob/master/CONTRIBUTING.md>`_ first.\n\n\nAuthors\n*******\n\nThese bindings were written by `Alastair Porter <http://github.com/alastair>`_.\nContributions have been made by:\n\n* `Adrian Sampson <https://github.com/sampsyo>`_\n* `Corey Farwell <https://github.com/frewsxcv>`_\n* `Galen Hazelwood <https://github.com/galenhz>`_\n* `Greg Ward <https://github.com/gward>`_\n* `Ian McEwen <https://github.com/ianmcorvidae>`_\n* `Jérémie Detrey <https://github.com/jdetrey>`_\n* `Johannes Dewender <https://github.com/JonnyJD>`_\n* `Michael Marineau <https://github.com/marineam>`_\n* `Patrick Speiser <https://github.com/doskir>`_\n* `Pavan Chander <https://github.com/navap>`_\n* `Paul Bailey <https://github.com/paulbailey>`_\n* `Rui Gonçalves <https://github.com/ruippeixotog>`_\n* `Ryan Helinski <https://github.com/rlhelinski>`_\n* `Sam Doshi <https://github.com/samdoshi>`_\n* `Shadab Zafar <https://github.com/dufferzafar>`_\n* `Simon Chopin <https://github.com/laarmen>`_\n* `Thomas Vander Stichele <https://github.com/thomasvs>`_\n* `Wieland Hoffmann <https://github.com/mineo>`_\n\nLicense\n*******\n\nThis library is released under the simplified BSD license except for the file\n``musicbrainzngs/compat.py`` which is licensed under the ISC license.\nSee COPYING for details.\n"
  },
  {
    "path": "docs/Makefile",
    "content": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = $(shell command -v sphinx-build || command -v sphinx-build2)\nPAPER         =\nBUILDDIR      = _build\n\n# Internal variables.\nPAPEROPT_a4     = -D latex_paper_size=a4\nPAPEROPT_letter = -D latex_paper_size=letter\nALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .\n# the i18n builder cannot share the environment and doctrees with the others\nI18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .\n\n.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext\n\nhelp:\n\t@echo \"Please use \\`make <target>' where <target> is one of\"\n\t@echo \"  html       to make standalone HTML files\"\n\t@echo \"  dirhtml    to make HTML files named index.html in directories\"\n\t@echo \"  singlehtml to make a single large HTML file\"\n\t@echo \"  pickle     to make pickle files\"\n\t@echo \"  json       to make JSON files\"\n\t@echo \"  htmlhelp   to make HTML files and a HTML help project\"\n\t@echo \"  qthelp     to make HTML files and a qthelp project\"\n\t@echo \"  devhelp    to make HTML files and a Devhelp project\"\n\t@echo \"  epub       to make an epub\"\n\t@echo \"  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\"\n\t@echo \"  latexpdf   to make LaTeX files and run them through pdflatex\"\n\t@echo \"  text       to make text files\"\n\t@echo \"  man        to make manual pages\"\n\t@echo \"  texinfo    to make Texinfo files\"\n\t@echo \"  info       to make Texinfo files and run them through makeinfo\"\n\t@echo \"  gettext    to make PO message catalogs\"\n\t@echo \"  changes    to make an overview of all changed/added/deprecated items\"\n\t@echo \"  linkcheck  to check all external links for integrity\"\n\t@echo \"  doctest    to run all doctests embedded in the documentation (if enabled)\"\n\nclean:\n\t-rm -rf $(BUILDDIR)/doctrees\n\t-rm -rf $(BUILDDIR)/html/*\n\nhtml:\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/html.\"\n\ndirhtml:\n\t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml\n\t@echo\n\t@echo \"Build finished. The HTML pages are in $(BUILDDIR)/dirhtml.\"\n\nsinglehtml:\n\t$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml\n\t@echo\n\t@echo \"Build finished. The HTML page is in $(BUILDDIR)/singlehtml.\"\n\npickle:\n\t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle\n\t@echo\n\t@echo \"Build finished; now you can process the pickle files.\"\n\njson:\n\t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json\n\t@echo\n\t@echo \"Build finished; now you can process the JSON files.\"\n\nhtmlhelp:\n\t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp\n\t@echo\n\t@echo \"Build finished; now you can run HTML Help Workshop with the\" \\\n\t      \".hhp project file in $(BUILDDIR)/htmlhelp.\"\n\nqthelp:\n\t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp\n\t@echo\n\t@echo \"Build finished; now you can run \"qcollectiongenerator\" with the\" \\\n\t      \".qhcp project file in $(BUILDDIR)/qthelp, like this:\"\n\t@echo \"# qcollectiongenerator $(BUILDDIR)/qthelp/musicbrainzngs.qhcp\"\n\t@echo \"To view the help file:\"\n\t@echo \"# assistant -collectionFile $(BUILDDIR)/qthelp/musicbrainzngs.qhc\"\n\ndevhelp:\n\t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp\n\t@echo\n\t@echo \"Build finished.\"\n\t@echo \"To view the help file:\"\n\t@echo \"# mkdir -p $$HOME/.local/share/devhelp/musicbrainzngs\"\n\t@echo \"# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/musicbrainzngs\"\n\t@echo \"# devhelp\"\n\nepub:\n\t$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub\n\t@echo\n\t@echo \"Build finished. The epub file is in $(BUILDDIR)/epub.\"\n\nlatex:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo\n\t@echo \"Build finished; the LaTeX files are in $(BUILDDIR)/latex.\"\n\t@echo \"Run \\`make' in that directory to run these through (pdf)latex\" \\\n\t      \"(use \\`make latexpdf' here to do that automatically).\"\n\nlatexpdf:\n\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex\n\t@echo \"Running LaTeX files through pdflatex...\"\n\t$(MAKE) -C $(BUILDDIR)/latex all-pdf\n\t@echo \"pdflatex finished; the PDF files are in $(BUILDDIR)/latex.\"\n\ntext:\n\t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text\n\t@echo\n\t@echo \"Build finished. The text files are in $(BUILDDIR)/text.\"\n\nman:\n\t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man\n\t@echo\n\t@echo \"Build finished. The manual pages are in $(BUILDDIR)/man.\"\n\ntexinfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo\n\t@echo \"Build finished. The Texinfo files are in $(BUILDDIR)/texinfo.\"\n\t@echo \"Run \\`make' in that directory to run these through makeinfo\" \\\n\t      \"(use \\`make info' here to do that automatically).\"\n\ninfo:\n\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo\n\t@echo \"Running Texinfo files through makeinfo...\"\n\tmake -C $(BUILDDIR)/texinfo info\n\t@echo \"makeinfo finished; the Info files are in $(BUILDDIR)/texinfo.\"\n\ngettext:\n\t$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale\n\t@echo\n\t@echo \"Build finished. The message catalogs are in $(BUILDDIR)/locale.\"\n\nchanges:\n\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes\n\t@echo\n\t@echo \"The overview file is in $(BUILDDIR)/changes.\"\n\nlinkcheck:\n\t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck\n\t@echo\n\t@echo \"Link check complete; look for any errors in the above output \" \\\n\t      \"or in $(BUILDDIR)/linkcheck/output.txt.\"\n\ndoctest:\n\t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest\n\t@echo \"Testing of doctests in the sources finished, look at the \" \\\n\t      \"results in $(BUILDDIR)/doctest/output.txt.\"\n"
  },
  {
    "path": "docs/api.rst",
    "content": "API\n~~~\n.. module:: musicbrainzngs\n\nThis is a shallow python binding of the MusicBrainz web service\nso you should read\n:musicbrainz:`Development/XML Web Service/Version 2`\nto understand how that web service works in general.\n\nAll requests that fetch data return the data in the form of a :class:`dict`.\nAttributes and elements both map to keys in the dict.\nList entities are of type :class:`list`.\n\nThis part will give an overview of available functions.\nHave a look at :doc:`usage` for examples on how to use them.\n\nGeneral\n-------\n\n.. autofunction:: auth\n.. autofunction:: set_rate_limit\n.. autofunction:: set_useragent\n.. autofunction:: set_hostname\n.. autofunction:: set_caa_hostname\n.. autofunction:: set_parser\n.. autofunction:: set_format\n\nGetting Data\n------------\n\nAll of these functions will fetch a MusicBrainz entity or a list of entities\nas a dict.\nYou can specify a list of `includes` to get more data\nand you can filter on `release_status` and `release_type`.\nSee :const:`musicbrainz.VALID_RELEASE_STATUSES`\nand :const:`musicbrainz.VALID_RELEASE_TYPES`.\nThe valid includes are listed for each function.\n\n.. autofunction:: get_area_by_id\n.. autofunction:: get_artist_by_id\n.. autofunction:: get_event_by_id\n.. autofunction:: get_instrument_by_id\n.. autofunction:: get_label_by_id\n.. autofunction:: get_place_by_id\n.. autofunction:: get_recording_by_id\n.. autofunction:: get_recordings_by_isrc\n.. autofunction:: get_release_group_by_id\n.. autofunction:: get_release_by_id\n.. autofunction:: get_releases_by_discid\n.. autofunction:: get_series_by_id\n.. autofunction:: get_work_by_id\n.. autofunction:: get_works_by_iswc\n.. autofunction:: get_url_by_id\n.. autofunction:: get_collections\n.. autofunction:: get_releases_in_collection\n\n.. autodata:: musicbrainzngs.musicbrainz.VALID_RELEASE_TYPES\n.. autodata:: musicbrainzngs.musicbrainz.VALID_RELEASE_STATUSES\n\n.. _caa_api:\n\nCover Art\n---------\n\n.. autofunction:: get_image_list\n.. autofunction:: get_release_group_image_list\n.. autofunction:: get_image\n.. autofunction:: get_image_front\n.. autofunction:: get_release_group_image_front\n.. autofunction:: get_image_back\n\n\n.. _search_api:\n\nSearching\n---------\n\nFor all of these search functions you can use any of the allowed search fields\nas parameter names.\nThe documentation of what these fields do is on\n:musicbrainz:`Development/XML Web Service/Version 2/Search`.\n\nYou can also set the `query` parameter to any lucene query you like.\nWhen you use any of the search fields as parameters,\nspecial characters are escaped in the `query`.\n\nBy default the elements are concatenated with spaces in between,\nso lucene essentially does a fuzzy search.\nThat search might include results that don't match the complete query,\nthough these will be ranked lower than the ones that do.\nIf you want all query elements to match for all results,\nyou have to set `strict=True`.\n\nBy default the web service returns 25 results per request and you can set\na `limit` of up to 100.\nYou have to use the `offset` parameter to set how many results you have\nalready seen so the web service doesn't give you the same results again.\n\n.. autofunction:: search_annotations\n.. autofunction:: search_areas\n.. autofunction:: search_artists\n.. autofunction:: search_events\n.. autofunction:: search_instruments\n.. autofunction:: search_labels\n.. autofunction:: search_places\n.. autofunction:: search_recordings\n.. autofunction:: search_release_groups\n.. autofunction:: search_releases\n.. autofunction:: search_series\n.. autofunction:: search_works\n\nBrowsing\n--------\n\nYou can browse entities of a certain type linked to one specific entity.\nThat is you can browse all recordings by an artist, for example.\n\nThese functions can be used to to include more than the maximum of 25 linked\nentities returned by the functions in `Getting Data`_.\nYou can set a `limit` as high as 100. The default is still 25.\nSimilar to the functions in `Searching`_, you have to specify\nan `offset` to see the results you haven't seen yet.\n\nYou have to provide exactly one MusicBrainz ID to these functions.\n\n.. autofunction:: browse_artists\n.. autofunction:: browse_events\n.. autofunction:: browse_labels\n.. autofunction:: browse_places\n.. autofunction:: browse_recordings\n.. autofunction:: browse_release_groups\n.. autofunction:: browse_releases\n.. autofunction:: browse_urls\n\n.. _api_submitting:\n\nSubmitting\n----------\n\nThese are the only functions that write to the MusicBrainz database.\nThey take one or more dicts with multiple entities as keys,\nwhich take certain values or a list of values.\n\nYou have to use :func:`auth` before using any of these functions.\n\n.. autofunction:: submit_barcodes\n.. autofunction:: submit_isrcs\n.. autofunction:: submit_tags\n.. autofunction:: submit_ratings\n.. autofunction:: add_releases_to_collection\n.. autofunction:: remove_releases_from_collection\n\nExceptions\n----------\n\nThese are the main exceptions that are raised by functions in musicbrainzngs.\nYou might want to catch some of these at an appropriate point in your code.\n\nSome of these might have subclasses that are not listed here.\n\n.. autoclass:: MusicBrainzError\n\n.. autoclass:: UsageError\n   :show-inheritance:\n\n.. autoclass:: WebServiceError\n   :show-inheritance:\n\n.. autoclass:: AuthenticationError\n   :show-inheritance:\n\n.. autoclass:: NetworkError\n   :show-inheritance:\n\n.. autoclass:: ResponseError\n   :show-inheritance:\n\nLogging\n-------\n\n`musicbrainzngs` logs debug and informational messages using Python's\n:mod:`logging` module.\nAll logging is done in the logger with the name `musicbrainzngs`.\n\nYou can enable this output in your application with::\n\n    import logging\n    logging.basicConfig(level=logging.DEBUG)\n    # optionally restrict musicbrainzngs output to INFO messages\n    logging.getLogger(\"musicbrainzngs\").setLevel(logging.INFO)\n"
  },
  {
    "path": "docs/conf.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# musicbrainzngs documentation build configuration file, created by\n# sphinx-quickstart2 on Thu Apr 26 15:56:46 2012.\n#\n# This file is execfile()d with the current directory set to its containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\nimport sys, os\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\nsys.path.insert(0, os.path.abspath('..'))\nimport musicbrainzngs\nfrom musicbrainzngs.musicbrainz import _version\n\n# -- General configuration -----------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be extensions\n# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.\nextensions = ['sphinx.ext.autodoc', 'sphinx.ext.extlinks',\n              'sphinx.ext.intersphinx']\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The suffix of source filenames.\nsource_suffix = '.rst'\n\n# The encoding of source files.\n#source_encoding = 'utf-8-sig'\n\n# The master toctree document.\nmaster_doc = 'index'\n\n# General information about the project.\nproject = u'musicbrainzngs'\ncopyright = u'2012, Alastair Porter et al'\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The short X.Y version.\nversion = _version\n# The full version, including alpha/beta/rc tags.\nrelease = version\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#language = None\n\n# There are two options for replacing |today|: either, you set today to some\n# non-false value, then it is used:\n#today = ''\n# Else, today_fmt is used as the format for a strftime call.\n#today_fmt = '%B %d, %Y'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\nexclude_patterns = ['_build']\n\n# The reST default role (used for this markup: `text`) to use for all documents.\n#default_role = None\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\n#add_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\n#add_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\n#show_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = 'sphinx'\n\n# A list of ignored prefixes for module index sorting.\n#modindex_common_prefix = []\n\nextlinks = {\n    'musicbrainz': ('https://musicbrainz.org/doc/%s', ''),\n}\n\nintersphinx_mapping = {\n    'python': ('http://python.readthedocs.io/en/latest/', None),\n    'python2': ('http://python.readthedocs.io/en/v2.7.2/', None),\n    'discid': ('http://python-discid.readthedocs.io/en/latest/', None),\n}\n\n\n# -- Options for HTML output ---------------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\nhtml_theme = 'default'\n\n# force default theme on readthedocs\nhtml_style = \"/default.css\"\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\nhtml_theme_options = {\n        \"footerbgcolor\": \"#e7e7e7\",\n        \"footertextcolor\": \"#444444\",\n        \"sidebarbgcolor\": \"#ffffff\",\n        \"sidebartextcolor\": \"#000000\",\n        \"sidebarlinkcolor\": \"002bba\",\n        \"relbarbgcolor\": \"#5c5789\",\n        \"relbartextcolor\": \"#000000\",\n        \"bgcolor\": \"#ffffff\",\n        \"textcolor\": \"#000000\",\n        \"linkcolor\": \"#002bba\",\n        \"headbgcolor\": \"#ffba58\",\n        \"headtextcolor\": \"#515151\",\n        \"codebgcolor\":  \"#dddddd\",\n        \"codetextcolor\": \"#000000\"\n        }\n\n# Add any paths that contain custom themes here, relative to this directory.\n#html_theme_path = []\n\n# The name for this set of Sphinx documents.  If None, it defaults to\n# \"<project> v<release> documentation\".\n#html_title = None\n\n# A shorter title for the navigation bar.  Default is the same as html_title.\n#html_short_title = None\n\n# The name of an image file (relative to this directory) to place at the top\n# of the sidebar.\n#html_logo = None\n\n# The name of an image file (within the static path) to use as favicon of the\n# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32\n# pixels large.\n#html_favicon = None\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\n#html_static_path = ['_static']\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,\n# using the given strftime format.\nhtml_last_updated_fmt = '%b %d, %Y'\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n#html_use_smartypants = True\n\n# Custom sidebar templates, maps document names to template names.\n#html_sidebars = {}\n\n# Additional templates that should be rendered to pages, maps page names to\n# template names.\n#html_additional_pages = {}\n\n# If false, no module index is generated.\n#html_domain_indices = True\n\n# If false, no index is generated.\n#html_use_index = True\n\n# If true, the index is split into individual pages for each letter.\n#html_split_index = False\n\n# If true, links to the reST sources are added to the pages.\nhtml_show_sourcelink = False\n\n# If true, \"Created using Sphinx\" is shown in the HTML footer. Default is True.\n#html_show_sphinx = True\n\n# If true, \"(C) Copyright ...\" is shown in the HTML footer. Default is True.\n#html_show_copyright = True\n\n# If true, an OpenSearch description file will be output, and all pages will\n# contain a <link> tag referring to it.  The value of this option must be the\n# base URL from which the finished HTML is served.\n#html_use_opensearch = ''\n\n# This is the file name suffix for HTML files (e.g. \".xhtml\").\n#html_file_suffix = None\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = 'musicbrainzngsdoc'\n\n\n# -- Options for LaTeX output --------------------------------------------------\n\nlatex_elements = {\n# The paper size ('letterpaper' or 'a4paper').\n#'papersize': 'letterpaper',\n\n# The font size ('10pt', '11pt' or '12pt').\n#'pointsize': '10pt',\n\n# Additional stuff for the LaTeX preamble.\n#'preamble': '',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title, author, documentclass [howto/manual]).\nlatex_documents = [\n  ('index', 'musicbrainzngs.tex', u'musicbrainzngs Documentation',\n   u'Alastair Porter et. al', 'manual'),\n]\n\n# The name of an image file (relative to this directory) to place at the top of\n# the title page.\n#latex_logo = None\n\n# For \"manual\" documents, if this is true, then toplevel headings are parts,\n# not chapters.\n#latex_use_parts = False\n\n# If true, show page references after internal links.\n#latex_show_pagerefs = False\n\n# If true, show URL addresses after external links.\n#latex_show_urls = False\n\n# Documents to append as an appendix to all manuals.\n#latex_appendices = []\n\n# If false, no module index is generated.\n#latex_domain_indices = True\n\n\n# -- Options for manual page output --------------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [\n    ('index', 'musicbrainzngs', u'musicbrainzngs Documentation',\n     [u'Alastair Porter et. al'], 1)\n]\n\n# If true, show URL addresses after external links.\n#man_show_urls = False\n\n\n# -- Options for Texinfo output ------------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n  ('index', 'musicbrainzngs', u'musicbrainzngs Documentation',\n   u'Alastair Porter et. al', 'musicbrainzngs', 'One line description of project.',\n   'Miscellaneous'),\n]\n\n# Documents to append as an appendix to all manuals.\n#texinfo_appendices = []\n\n# If false, no module index is generated.\n#texinfo_domain_indices = True\n\n# How to display URL addresses: 'footnote', 'no', or 'inline'.\n#texinfo_show_urls = 'footnote'\n"
  },
  {
    "path": "docs/index.rst",
    "content": "musicbrainzngs |release|\n========================\n\n`musicbrainzngs` implements Python bindings of the `MusicBrainz Web Service`_\n(WS/2, NGS).\nWith this library you can retrieve all kinds of music metadata\nfrom the `MusicBrainz`_ database.\n\n`musicbrainzngs` is released under a simplified BSD style license.\n\n.. _`MusicBrainz`: http://musicbrainz.org\n.. _`MusicBrainz Web Service`: http://musicbrainz.org/doc/Development/XML%20Web%20Service/Version%202\n\nContents\n--------\n.. toctree::\n\n    installation\n    usage\n    api\n\n.. currentmodule:: musicbrainzngs.musicbrainz\n\nIndices and tables\n------------------\n\n* :ref:`genindex`\n* :ref:`search`\n"
  },
  {
    "path": "docs/installation.rst",
    "content": "Installation\n~~~~~~~~~~~~\n\nPackage manager\n---------------\n\nIf you want the latest stable version of musicbrainzngs, the first place to\ncheck is your systems package manager. Being a relatively new library, you\nmight not be able to find it packaged by your distribution and need to use one\nof the alternate installation methods.\n\nPyPI\n----\n\nMusicbrainzngs is available on the Python Package Index. This makes installing\nit with `pip <http://www.pip-installer.org>`_ as easy as::\n\n    pip install musicbrainzngs\n\nGit\n---\n\nIf you want the latest code or even feel like contributing, the code is\navailable on `GitHub <https://github.com/alastair/python-musicbrainzngs>`_.\n\nYou can easily clone the code with git::\n\n    git clone git://github.com/alastair/python-musicbrainzngs.git\n\nNow you can start hacking on the code or install it system-wide::\n\n    python setup.py install\n"
  },
  {
    "path": "docs/make.bat",
    "content": "@ECHO OFF\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-build2\n)\nset BUILDDIR=_build\nset ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .\nset I18NSPHINXOPTS=%SPHINXOPTS% .\nif NOT \"%PAPER%\" == \"\" (\n\tset ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%\n\tset I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%\n)\n\nif \"%1\" == \"\" goto help\n\nif \"%1\" == \"help\" (\n\t:help\n\techo.Please use `make ^<target^>` where ^<target^> is one of\n\techo.  html       to make standalone HTML files\n\techo.  dirhtml    to make HTML files named index.html in directories\n\techo.  singlehtml to make a single large HTML file\n\techo.  pickle     to make pickle files\n\techo.  json       to make JSON files\n\techo.  htmlhelp   to make HTML files and a HTML help project\n\techo.  qthelp     to make HTML files and a qthelp project\n\techo.  devhelp    to make HTML files and a Devhelp project\n\techo.  epub       to make an epub\n\techo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\n\techo.  text       to make text files\n\techo.  man        to make manual pages\n\techo.  texinfo    to make Texinfo files\n\techo.  gettext    to make PO message catalogs\n\techo.  changes    to make an overview over all changed/added/deprecated items\n\techo.  linkcheck  to check all external links for integrity\n\techo.  doctest    to run all doctests embedded in the documentation if enabled\n\tgoto end\n)\n\nif \"%1\" == \"clean\" (\n\tfor /d %%i in (%BUILDDIR%\\*) do rmdir /q /s %%i\n\tdel /q /s %BUILDDIR%\\*\n\tgoto end\n)\n\nif \"%1\" == \"html\" (\n\t%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished. The HTML pages are in %BUILDDIR%/html.\n\tgoto end\n)\n\nif \"%1\" == \"dirhtml\" (\n\t%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.\n\tgoto end\n)\n\nif \"%1\" == \"singlehtml\" (\n\t%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.\n\tgoto end\n)\n\nif \"%1\" == \"pickle\" (\n\t%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished; now you can process the pickle files.\n\tgoto end\n)\n\nif \"%1\" == \"json\" (\n\t%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished; now you can process the JSON files.\n\tgoto end\n)\n\nif \"%1\" == \"htmlhelp\" (\n\t%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished; now you can run HTML Help Workshop with the ^\n.hhp project file in %BUILDDIR%/htmlhelp.\n\tgoto end\n)\n\nif \"%1\" == \"qthelp\" (\n\t%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished; now you can run \"qcollectiongenerator\" with the ^\n.qhcp project file in %BUILDDIR%/qthelp, like this:\n\techo.^> qcollectiongenerator %BUILDDIR%\\qthelp\\musicbrainzngs.qhcp\n\techo.To view the help file:\n\techo.^> assistant -collectionFile %BUILDDIR%\\qthelp\\musicbrainzngs.ghc\n\tgoto end\n)\n\nif \"%1\" == \"devhelp\" (\n\t%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished.\n\tgoto end\n)\n\nif \"%1\" == \"epub\" (\n\t%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished. The epub file is in %BUILDDIR%/epub.\n\tgoto end\n)\n\nif \"%1\" == \"latex\" (\n\t%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished; the LaTeX files are in %BUILDDIR%/latex.\n\tgoto end\n)\n\nif \"%1\" == \"text\" (\n\t%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished. The text files are in %BUILDDIR%/text.\n\tgoto end\n)\n\nif \"%1\" == \"man\" (\n\t%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished. The manual pages are in %BUILDDIR%/man.\n\tgoto end\n)\n\nif \"%1\" == \"texinfo\" (\n\t%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.\n\tgoto end\n)\n\nif \"%1\" == \"gettext\" (\n\t%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Build finished. The message catalogs are in %BUILDDIR%/locale.\n\tgoto end\n)\n\nif \"%1\" == \"changes\" (\n\t%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.The overview file is in %BUILDDIR%/changes.\n\tgoto end\n)\n\nif \"%1\" == \"linkcheck\" (\n\t%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Link check complete; look for any errors in the above output ^\nor in %BUILDDIR%/linkcheck/output.txt.\n\tgoto end\n)\n\nif \"%1\" == \"doctest\" (\n\t%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest\n\tif errorlevel 1 exit /b 1\n\techo.\n\techo.Testing of doctests in the sources finished, look at the ^\nresults in %BUILDDIR%/doctest/output.txt.\n\tgoto end\n)\n\n:end\n"
  },
  {
    "path": "docs/usage.rst",
    "content": "Usage\n~~~~~\n\nIn general you need to set a useragent for your application,\nstart searches to get to know corresponding MusicBrainz IDs\nand then retrieve information about these entities.\n\nThe data is returned in form of a :class:`dict`.\n\nIf you also want to submit data,\nthen you must authenticate as a MusicBrainz user.\n\nThis part of the documentation will give you usage examples.\nFor an overview of available functions you can have a look at\nthe :doc:`api`.\n\nIdentification\n--------------\n\nTo access the MusicBrainz webservice through this library, you `need to\nidentify your application\n<http://musicbrainz.org/doc/XML_Web_Service/Version_2#Identifying_your_application_to_the_MusicBrainz_Web_Service>`_\nby setting the useragent header made in HTTP requests to one that is unique to\nyour application.\n\nTo ease this, the convenience function :meth:`musicbrainzngs.set_useragent` is\nprovided which automatically sets the useragent based on information about the\napplication name, version and contact information to the format `recommended by\nMusicBrainz\n<http://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting#Provide_meaningful_User-Agent_strings>`_.\n\nIf a request is made without setting the useragent beforehand, a\n:exc:`musicbrainzngs.UsageError` will be raised.\n\nAuthentication\n--------------\n\nCertain calls to the webservice require user authentication prior to the call\nitself. The affected functions state this requirement in their documentation.\nThe user and password used for authentication are the same as for the\nMusicBrainz website itself and can be set with the :meth:`musicbrainzngs.auth`\nmethod. After calling this function, the credentials will be saved and\nautomatically used by all functions requiring them.\n\nIf a method requiring authentication is called without authenticating, a\n:exc:`musicbrainzngs.UsageError` will be raised.\n\nIf the credentials provided are wrong and the server returns a status code of\n401, a :exc:`musicbrainzngs.AuthenticationError` will be raised.\n\nGetting Data\n------------\n\nRegular MusicBrainz Data\n^^^^^^^^^^^^^^^^^^^^^^^^\n\nYou can get MusicBrainz entities as a :class:`dict`\nwhen retrieving them with some form of identifier.\nAn example using :func:`musicbrainzngs.get_artist_by_id`::\n\n  artist_id = \"c5c2ea1c-4bde-4f4d-bd0b-47b200bf99d6\"\n  try:\n      result = musicbrainzngs.get_artist_by_id(artist_id)\n  except WebServiceError as exc:\n      print(\"Something went wrong with the request: %s\" % exc)\n  else:\n      artist = result[\"artist\"]\n      print(\"name:\\t\\t%s\" % artist[\"name\"])\n      print(\"sort name:\\t%s\" % artist[\"sort-name\"])\n\nYou can get more information about entities connected to the artist\nwith adding `includes` and you filter releases and release_groups::\n\n  result = musicbrainzngs.get_artist_by_id(artist_id,\n                includes=[\"release-groups\"], release_type=[\"album\", \"ep\"])\n  for release_group in result[\"artist\"][\"release-group-list\"]:\n      print(\"{title} ({type})\".format(title=release_group[\"title\"],\n                                      type=release_group[\"type\"]))\n\n.. tip:: Compilations are also of primary type \"album\".\n   You have to filter these out manually if you don't want them.\n\n.. note:: You can only get at most 25 release groups using this method.\n   If you want to fetch all release groups you will have to\n   `browse <browsing>`_.\n\nCover Art Data\n^^^^^^^^^^^^^^\n\nThis library includes a few methods to access data from the `Cover Art Archive\n<https://coverartarchive.org/>`_ which has a `documented API\n<https://musicbrainz.org/doc/Cover_Art_Archive/API>`_.\n\nBoth :func:`musicbrainzngs.get_image_list` and\n:func:`musicbrainzngs.get_release_group_image_list` return the deserialized\ncover art listing for a `release\n<https://musicbrainz.org/doc/Cover_Art_Archive/API#.2Frelease.2F.7Bmbid.7D.2F>`_\nor `release group\n<https://musicbrainz.org/doc/Cover_Art_Archive/API#.2Frelease-group.2F.7Bmbid.7D.2F>`_.\nTo find out whether a release\nhas an approved front image, you could use the following example code::\n\n  release_id = \"46a48e90-819b-4bed-81fa-5ca8aa33fbf3\"\n  data = musicbrainzngs.get_cover_art_list(\"46a48e90-819b-4bed-81fa-5ca8aa33fbf3\")\n  for image in data[\"images\"]:\n      if \"Front\" in image[\"types\"] and image[\"approved\"]:\n          print \"%s is an approved front image!\" % image[\"thumbnails\"][\"large\"]\n          break\n\nTo retrieve an image itself, use :func:`musicbrainzngs.get_image`. A\nfew convenience functions like :func:`musicbrainzngs.get_image_front`\nare provided to allow easy access to often requested images.\n\n.. warning:: There is no upper bound for the size of images uploaded to the\n   Cover Art Archive and downloading an image will return the binary data in\n   memory. Consider using the :py:mod:`tempfile` module or similar\n   techniques to save images to disk as soon as possible.\n\nSearching\n---------\n\nWhen you don't know the MusicBrainz IDs yet, you have to start a search.\nUsing :func:`musicbrainzngs.search_artists`::\n\n  result = musicbrainzngs.search_artists(artist=\"xx\", type=\"group\",\n                                         country=\"GB\")\n  for artist in result['artist-list']:\n      print(u\"{id}: {name}\".format(id=artist['id'], name=artist[\"name\"]))\n\n.. tip:: Musicbrainzngs returns unicode strings.\n   It's up to you to make sure Python (2) doesn't try to convert these\n   to ascii again. In the example we force a unicode literal for print.\n   Python 3 works without fixes like these.\n\nYou can also use the query without specifying the search fields::\n\n  musicbrainzngs.search_release_groups(\"the clash london calling\")\n\nThe query and the search fields can also be used at the same time.\n\nBrowsing\n--------\n\nWhen you want to fetch a list of entities greater than 25,\nyou have to use one of the browse functions.\nNot only can you specify a `limit` as high as 100,\nbut you can also specify an `offset` to get the complete list\nin multiple requests.\n\nAn example would be using :func:`musicbrainzngs.browse_release_groups`\nto get all releases for a label::\n\n  label = \"71247f6b-fd24-4a56-89a2-23512f006f0c\"\n  limit = 100\n  offset = 0\n  releases = []\n  page = 1\n  print(\"fetching page number %d..\" % page)\n  result = musicbrainzngs.browse_releases(label=label, includes=[\"labels\"],\n                  release_type=[\"album\"], limit=limit)\n  page_releases = result['release-list']\n  releases += page_releases\n  # release-count is only available starting with musicbrainzngs 0.5\n  if \"release-count\" in result:\n          count = result['release-count']\n          print(\"\")\n  while len(page_releases) >= limit:\n      offset += limit\n      page += 1\n      print(\"fetching page number %d..\" % page)\n      result = musicbrainzngs.browse_releases(label=label, includes=[\"labels\"],\n                          release_type=[\"album\"], limit=limit, offset=offset)\n      page_releases = result['release-list']\n      releases += page_releases\n  print(\"\")\n  for release in releases:\n      for label_info in release['label-info-list']:\n          catnum = label_info.get('catalog-number')\n          if label_info['label']['id'] == label and catnum:\n              print(\"{catnum:>17}: {date:10} {title}\".format(catnum=catnum,\n                          date=release['date'], title=release['title']))\n  print(\"\\n%d releases on  %d pages\" % (len(releases), page))\n\n.. tip:: You should always try to filter in the query, when possible,\n   rather than fetching everything and filtering afterwards.\n   This will make your application faster\n   since web service requests are throttled.\n   In the example we filter by `release_type`.\n\nSubmitting\n----------\n\nYou can also submit data using musicbrainzngs.\nPlease use :func:`musicbrainzngs.set_hostname` to set the host to\ntest.musicbrainz.org when testing the submission part of your application.\n\n`Authentication`_ is necessary to submit any data to MusicBrainz.\n\nAn example using :func:`musicbrainzngs.submit_barcodes` looks like this::\n\n  musicbrainzngs.set_hostname(\"test.musicbrainz.org\")\n  musicbrainzngs.auth(\"test\", \"mb\")\n\n  barcodes = {\n      \"174a5513-73d1-3c9d-a316-3c1c179e35f8\": \"5099749534728\",\n      \"838952af-600d-3f51-84d5-941d15880400\": \"602517737280\"\n  }\n  musicbrainzngs.submit_barcodes(barcodes)\n\nSee :ref:`api_submitting` in the API for other possibilities.\n\nMore Examples\n-------------\n\nYou can find some examples for using `musicbrainzngs` in the\n`examples directory <https://github.com/alastair/python-musicbrainzngs/tree/master/examples>`_.\n"
  },
  {
    "path": "examples/collection.py",
    "content": "#!/usr/bin/env python\n\"\"\"View and modify your MusicBrainz collections.\n\nTo show a list of your collections:\n\n    $ ./collection.py USERNAME\n    Password for USERNAME:\n    All collections for this user:\n    My Collection by USERNAME (4137a646-a104-4031-b549-da4e1f36a463)\n\nTo show the releases in a collection:\n\n    $ ./collection.py USERNAME 4137a646-a104-4031-b549-da4e1f36a463\n    Password for USERNAME:\n    Releases in My Collection:\n    None Shall Pass (b0885908-cbe2-4e51-95d8-c4f3b9721ad6)\n    ...\n\nTo add a release to a collection or remove one:\n\n    $ ./collection.py USERNAME 4137a646-a104-4031-b549-da4e1f36a463\n        --add 0d432d8b-8865-4ae9-8479-3a197620a37b\n    $ ./collection.py USERNAME 4137a646-a104-4031-b549-da4e1f36a463\n        --remove 0d432d8b-8865-4ae9-8479-3a197620a37b\n\"\"\"\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\nimport musicbrainzngs\nimport getpass\nfrom optparse import OptionParser\nimport sys\n\ntry:\n    user_input = raw_input\nexcept NameError:\n    user_input = input\n\nmusicbrainzngs.set_useragent(\n    \"python-musicbrainzngs-example\",\n    \"0.1\",\n    \"https://github.com/alastair/python-musicbrainzngs/\",\n)\n\ndef show_collections():\n    \"\"\"Fetch and display the current user's collections.\n    \"\"\"\n    result = musicbrainzngs.get_collections()\n    print('All collections for this user:')\n    for collection in result['collection-list']:\n        # entity-type only available starting with musicbrainzngs 0.6\n        if \"entity-type\" in collection:\n            print('\"{name}\" by {editor} ({cat}, {count} {entity}s)\\n\\t{mbid}'\n                    .format(\n                name=collection['name'], editor=collection['editor'],\n                cat=collection['type'], entity=collection['entity-type'],\n                count=collection[collection['entity-type']+'-count'],\n                mbid=collection['id']\n            ))\n        else:\n            print('\"{name}\" by {editor}\\n\\t{mbid}'.format(\n                name=collection['name'], editor=collection['editor'],\n                mbid=collection['id']\n            ))\n\ndef show_collection(collection_id, ctype):\n    \"\"\"Show a given collection.\n    \"\"\"\n    if ctype == \"release\":\n        result = musicbrainzngs.get_releases_in_collection(\n                                                collection_id, limit=0)\n    elif ctype == \"artist\":\n        result = musicbrainzngs.get_artists_in_collection(\n                                                collection_id, limit=0)\n    elif ctype == \"event\":\n        result = musicbrainzngs.get_events_in_collection(\n                                                collection_id, limit=0)\n    elif ctype == \"place\":\n        result = musicbrainzngs.get_places_in_collection(\n                                                collection_id, limit=0)\n    elif ctype == \"recording\":\n        result = musicbrainzngs.get_recordings_in_collection(\n                                                collection_id, limit=0)\n    elif ctype == \"work\":\n        result = musicbrainzngs.get_works_in_collection(\n                                                collection_id, limit=0)\n    collection = result['collection']\n    # entity-type only available starting with musicbrainzngs 0.6\n    if \"entity-type\" in collection:\n        print('{mbid}\\n\"{name}\" by {editor} ({cat}, {entity})'.format(\n            name=collection['name'], editor=collection['editor'],\n            cat=collection['type'], entity=collection['entity-type'],\n            mbid=collection['id']\n        ))\n    else:\n        print('{mbid}\\n\"{name}\" by {editor}'.format(\n            name=collection['name'], editor=collection['editor'],\n            mbid=collection['id']\n        ))\n    print('')\n    # release count is only available starting with musicbrainzngs 0.5\n    if \"release-count\" in collection:\n        print('{} releases'.format(collection['release-count']))\n    if \"artist-count\" in collection:\n        print('{} artists'.format(collection['artist-count']))\n    if \"event-count\" in collection:\n        print('{} events'.format(collection['release-count']))\n    if \"place-count\" in collection:\n        print('{} places'.format(collection['place-count']))\n    if \"recording-count\" in collection:\n        print('{} recordings'.format(collection['recording-count']))\n    if \"work-count\" in collection:\n        print('{} works'.format(collection['work-count']))\n    print('')\n\n    if \"release-list\" in collection:\n        show_releases(collection)\n    else:\n        pass # TODO\n\ndef show_releases(collection):\n    result = musicbrainzngs.get_releases_in_collection(collection_id, limit=25)\n    release_list = result['collection']['release-list']\n    print('Releases:')\n    releases_fetched = 0\n    while len(release_list) > 0:\n        print(\"\")\n        releases_fetched += len(release_list)\n        for release in release_list:\n            print('{title} ({mbid})'.format(\n                title=release['title'], mbid=release['id']\n            ))\n        if user_input(\"Would you like to display more releases? [y/N] \") != \"y\":\n            break;\n\n        # fetch next batch of releases\n        result = musicbrainzngs.get_releases_in_collection(collection_id,\n                            limit=25, offset=releases_fetched)\n        collection = result['collection']\n        release_list = collection['release-list']\n\n    print(\"\")\n    print(\"Number of fetched releases: %d\" % releases_fetched)\n\nif __name__ == '__main__':\n    parser = OptionParser(usage=\"%prog [options] USERNAME [COLLECTION-ID]\")\n    parser.add_option('-a', '--add', metavar=\"RELEASE-ID\",\n                      help=\"add a release to the collection\")\n    parser.add_option('-r', '--remove', metavar=\"RELEASE-ID\",\n                      help=\"remove a release from the collection\")\n    parser.add_option('-t', '--type', metavar=\"TYPE\", default=\"release\",\n                      help=\"type of the collection (default: release)\")\n    options, args = parser.parse_args()\n\n    if not args:\n        parser.error('no username specified')\n    username = args.pop(0)\n\n    # Input the password.\n    password = getpass.getpass('Password for {}: '.format(username))\n\n    # Call musicbrainzngs.auth() before making any API calls that\n    # require authentication.\n    musicbrainzngs.auth(username, password)\n\n    if args:\n        # Actions for a specific collection.\n        collection_id = args[0]\n        if options.add:\n            if option.type == \"release\":\n                musicbrainzngs.add_releases_to_collection(\n                    collection_id, [options.add]\n                )\n            else:\n                sys.exit(\"only release collections can be modified ATM\")\n        elif options.remove:\n            if option.type == \"release\":\n                musicbrainzngs.remove_releases_from_collection(\n                    collection_id, [options.remove]\n                )\n            else:\n                sys.exit(\"only release collections can be modified ATM\")\n        else:\n            # Print out the collection's contents.\n            print(\"\")\n            show_collection(collection_id, options.type)\n    else:\n        # Show all collections.\n        print(\"\")\n        show_collections()\n"
  },
  {
    "path": "examples/find_disc.py",
    "content": "#!/usr/bin/env python\n\"\"\"A script that looks for a release in the MusicBrainz database by disc ID\n\n    $ ./find_disc.py kKOqMEuRDSeW_.K49SUEJXensLY-\n    disc:\n        Sectors: 295099\n        London Calling\n            MusicBrainz ID: 174a5513-73d1-3c9d-a316-3c1c179e35f8\n            EAN/UPC: 5099749534728\n            cat#: 495347 2\n\n        ...\n\"\"\"\n\nfrom __future__ import unicode_literals\nimport musicbrainzngs\nimport sys\n\nmusicbrainzngs.set_useragent(\n    \"python-musicbrainzngs-example\",\n    \"0.1\",\n    \"https://github.com/alastair/python-musicbrainzngs/\",\n)\n\ndef show_release_details(rel):\n    \"\"\"Print some details about a release dictionary to stdout.\n    \"\"\"\n    print(\"\\t{}\".format(rel['title']))\n    print(\"\\t\\tMusicBrainz ID: {}\".format(rel['id']))\n    if rel.get('barcode'):\n        print(\"\\t\\tEAN/UPC: {}\".format(rel['barcode']))\n    for info in rel['label-info-list']:\n        if info.get('catalog-number'):\n            print(\"\\t\\tcat#: {}\".format(info['catalog-number']))\n\ndef show_offsets(offset_list):\n    offsets = None\n    for offset in offset_list:\n        if offsets == None:\n            offsets = str(offset)\n        else:\n            offsets += \" \" + str(offset)\n    print(\"\\toffsets: {}\".format(offsets))\n\nif __name__ == '__main__':\n    args = sys.argv[1:]\n    if len(args) != 1:\n        sys.exit(\"usage: {} DISC_ID\".format(sys.argv[0]))\n    discid = args[0]\n\n    try:\n        # the \"labels\" include enables the cat#s we display\n        result = musicbrainzngs.get_releases_by_discid(discid,\n                includes=[\"labels\"])\n    except musicbrainzngs.ResponseError as err:\n        if err.cause.code == 404:\n            sys.exit(\"disc not found\")\n        else:\n            sys.exit(\"received bad response from the MB server\")\n\n    # The result can either be a \"disc\" or a \"cdstub\"\n    if result.get('disc'):\n        print(\"disc:\")\n        print(\"\\tSectors: {}\".format(result['disc']['sectors']))\n        # offset-list only available starting with musicbrainzngs 0.6\n        if \"offset-list\" in result['disc']:\n            show_offsets(result['disc']['offset-list'])\n            print(\"\\tTracks: {}\".format(result['disc']['offset-count']))\n        for release in result['disc']['release-list']:\n            show_release_details(release)\n            print(\"\")\n    elif result.get('cdstub'):\n        print(\"cdstub:\")\n        print(\"\\tArtist: {}\".format(result['cdstub']['artist']))\n        print(\"\\tTitle: {}\".format(result['cdstub']['title']))\n        if result['cdstub'].get('barcode'):\n            print(\"\\tBarcode: {}\".format(result['cdstub']['barcode']))\n    else:\n        sys.exit(\"no valid results\")\n"
  },
  {
    "path": "examples/releasesearch.py",
    "content": "#!/usr/bin/env python\n\"\"\"A simple script that searches for a release in the MusicBrainz\ndatabase and prints out a few details about the first 5 matching release.\n\n    $ ./releasesearch.py \"the beatles\" revolver\n    Revolver, by The Beatles\n    Released 1966-08-08 (Official)\n    MusicBrainz ID: b4b04cbf-118a-3944-9545-38a0a88ff1a2\n\"\"\"\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\nimport musicbrainzngs\nimport sys\n\nmusicbrainzngs.set_useragent(\n    \"python-musicbrainzngs-example\",\n    \"0.1\",\n    \"https://github.com/alastair/python-musicbrainzngs/\",\n)\n\ndef show_release_details(rel):\n    \"\"\"Print some details about a release dictionary to stdout.\n    \"\"\"\n    # \"artist-credit-phrase\" is a flat string of the credited artists\n    # joined with \" + \" or whatever is given by the server.\n    # You can also work with the \"artist-credit\" list manually.\n    print(\"{}, by {}\".format(rel['title'], rel[\"artist-credit-phrase\"]))\n    if 'date' in rel:\n        print(\"Released {} ({})\".format(rel['date'], rel['status']))\n    print(\"MusicBrainz ID: {}\".format(rel['id']))\n\nif __name__ == '__main__':\n    args = sys.argv[1:]\n    if len(args) != 2:\n        sys.exit(\"usage: {} ARTIST ALBUM\".format(sys.argv[0]))\n    artist, album = args\n\n    # Keyword arguments to the \"search_*\" functions limit keywords to\n    # specific fields. The \"limit\" keyword argument is special (like as\n    # \"offset\", not shown here) and specifies the number of results to\n    # return.\n    result = musicbrainzngs.search_releases(artist=artist, release=album,\n                                            limit=5)\n    # On success, result is a dictionary with a single key:\n    # \"release-list\", which is a list of dictionaries.\n    if not result['release-list']:\n        sys.exit(\"no release found\")\n    for (idx, release) in enumerate(result['release-list']):\n        print(\"match #{}:\".format(idx+1))\n        show_release_details(release)\n        print()\n"
  },
  {
    "path": "musicbrainzngs/__init__.py",
    "content": "from musicbrainzngs.musicbrainz import *\nfrom musicbrainzngs.caa import *\n"
  },
  {
    "path": "musicbrainzngs/caa.py",
    "content": "# This file is part of the musicbrainzngs library\n# Copyright (C) Alastair Porter, Wieland Hoffmann, and others\n# This file is distributed under a BSD-2-Clause type license.\n# See the COPYING file for more information.\n\n__all__ = [\n    'set_caa_hostname', 'get_image_list', 'get_release_group_image_list',\n    'get_release_group_image_front', 'get_image_front', 'get_image_back',\n    'get_image'\n    ]\n\nimport json\n\nfrom musicbrainzngs import compat\nfrom musicbrainzngs import musicbrainz\nfrom musicbrainzngs.util import _unicode\n\nhostname = \"coverartarchive.org\"\nhttps = True\n\n\ndef set_caa_hostname(new_hostname, use_https=False):\n    \"\"\"Set the base hostname for Cover Art Archive requests.\n    Defaults to 'coverartarchive.org', accessing over https.\n    For backwards compatibility, `use_https` is False by default.\n\n    :param str new_hostname: The hostname (and port) of the CAA server to connect to\n    :param bool use_https: `True` if the host should be accessed using https. Default is `False`\n\"\"\"\n    global hostname\n    global https\n    hostname = new_hostname\n    https = use_https\n\n\ndef _caa_request(mbid, imageid=None, size=None, entitytype=\"release\"):\n    \"\"\" Make a CAA request.\n\n    :param imageid: ``front``, ``back`` or a number from the listing obtained\n                    with :meth:`get_image_list`.\n    :type imageid: str\n\n    :param size: \"250\", \"500\", \"1200\"\n    :type size: str or None\n\n    :param entitytype: ``release`` or ``release-group``\n    :type entitytype: str\n    \"\"\"\n    # Construct the full URL for the request, including hostname and\n    # query string.\n    path = [entitytype, mbid]\n    if imageid and size:\n        path.append(\"%s-%s\" % (imageid, size))\n    elif imageid:\n        path.append(imageid)\n    url = compat.urlunparse((\n        'https' if https else 'http',\n        hostname,\n        '/%s' % '/'.join(path),\n        '',\n        '',\n        ''\n    ))\n    musicbrainz._log.debug(\"GET request for %s\" % (url, ))\n\n    # Set up HTTP request handler and URL opener.\n    httpHandler = compat.HTTPHandler(debuglevel=0)\n    handlers = [httpHandler]\n\n    opener = compat.build_opener(*handlers)\n\n    # Make request.\n    req = musicbrainz._MusicbrainzHttpRequest(\"GET\", url, None)\n    # Useragent isn't needed for CAA, but we'll add it if it exists\n    if musicbrainz._useragent != \"\":\n        req.add_header('User-Agent', musicbrainz._useragent)\n        musicbrainz._log.debug(\"requesting with UA %s\" % musicbrainz._useragent)\n\n    resp = musicbrainz._safe_read(opener, req, None)\n\n    # TODO: The content type declared by the CAA for JSON files is\n    # 'applicaiton/octet-stream'. This is not useful to detect whether the\n    # content is JSON, so default to decoding JSON if no imageid was supplied.\n    # http://tickets.musicbrainz.org/browse/CAA-75\n    if imageid:\n        # If we asked for an image, return the image\n        return resp\n    else:\n        # Otherwise it's json\n        data = _unicode(resp)\n        return json.loads(data)\n\n\ndef get_image_list(releaseid):\n    \"\"\"Get the list of cover art associated with a release.\n\n    The return value is the deserialized response of the `JSON listing\n    <http://musicbrainz.org/doc/Cover_Art_Archive/API#.2Frelease.2F.7Bmbid.7D.2F>`_\n    returned by the Cover Art Archive API.\n\n    If an error occurs then a :class:`~musicbrainzngs.ResponseError` will\n    be raised with one of the following HTTP codes:\n\n    * 400: `releaseid` is not a valid UUID\n    * 404: The release with an MBID of `releaseid` does not exist or\n           there is no cover art available for it.\n    * 503: Ratelimit exceeded\n    \"\"\"\n    return _caa_request(releaseid)\n\n\ndef get_release_group_image_list(releasegroupid):\n    \"\"\"Get the list of cover art associated with a release group.\n\n    The return value is the deserialized response of the `JSON listing\n    <http://musicbrainz.org/doc/Cover_Art_Archive/API#.2Frelease-group.2F.7Bmbid.7D.2F>`_\n    returned by the Cover Art Archive API.\n\n    If an error occurs then a :class:`~musicbrainzngs.ResponseError` will\n    be raised with one of the following HTTP codes:\n\n    * 400: `releasegroupid` is not a valid UUID\n    * 404: The release group with an MBID of `releasegroupid` does not exist or\n           there is no cover art available for it.\n    * 503: Ratelimit exceeded\n    \"\"\"\n    return _caa_request(releasegroupid, entitytype=\"release-group\")\n\n\ndef get_release_group_image_front(releasegroupid, size=None):\n    \"\"\"Download the front cover art for a release group.\n    The `size` argument and the possible error conditions are the same as for\n    :meth:`get_image`.\n    \"\"\"\n    return get_image(releasegroupid, \"front\", size=size,\n                     entitytype=\"release-group\")\n\n\ndef get_image_front(releaseid, size=None):\n    \"\"\"Download the front cover art for a release.\n    The `size` argument and the possible error conditions are the same as for\n    :meth:`get_image`.\n    \"\"\"\n    return get_image(releaseid, \"front\", size=size)\n\n\ndef get_image_back(releaseid, size=None):\n    \"\"\"Download the back cover art for a release.\n    The `size` argument and the possible error conditions are the same as for\n    :meth:`get_image`.\n    \"\"\"\n    return get_image(releaseid, \"back\", size=size)\n\n\ndef get_image(mbid, coverid, size=None, entitytype=\"release\"):\n    \"\"\"Download cover art for a release. The coverart file to download\n    is specified by the `coverid` argument.\n\n    If `size` is not specified, download the largest copy present, which can be\n    very large.\n\n    If an error occurs then a :class:`~musicbrainzngs.ResponseError`\n    will be raised with one of the following HTTP codes:\n\n    * 400: `releaseid` is not a valid UUID or `coverid` is invalid\n    * 404: The release with an MBID of `releaseid` does not exist or no cover\n           art with an id of `coverid` exists.\n    * 503: Ratelimit exceeded\n\n    :param coverid: ``front``, ``back`` or a number from the listing obtained\n                    with :meth:`get_image_list`\n    :type coverid: int or str\n\n    :param size: \"250\", \"500\", \"1200\" or None. If it is None, the largest\n                 available picture will be downloaded. If the image originally\n                 uploaded to the Cover Art Archive was smaller than the\n                 requested size, only the original image will be returned.\n    :type size: str or None\n\n    :param entitytype: The type of entity for which to download the cover art.\n                       This is either ``release`` or ``release-group``.\n    :type entitytype: str\n    :return: The binary image data\n    :type: str\n    \"\"\"\n    if isinstance(coverid, int):\n        coverid = \"%d\" % (coverid, )\n    if isinstance(size, int):\n        size = \"%d\" % (size, )\n    return _caa_request(mbid, coverid, size=size, entitytype=entitytype)\n"
  },
  {
    "path": "musicbrainzngs/compat.py",
    "content": "# -*- coding: utf-8 -*-\n# Copyright (c) 2012 Kenneth Reitz.\n\n# Permission to use, copy, modify, and/or distribute this software for any\n# purpose with or without fee is hereby granted, provided that the above\n# copyright notice and this permission notice appear in all copies.\n\n# THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n\"\"\"\npythoncompat\n\"\"\"\n\n\nimport sys\n\n# -------\n# Pythons\n# -------\n\n# Syntax sugar.\n_ver = sys.version_info\n\n#: Python 2.x?\nis_py2 = (_ver[0] == 2)\n\n#: Python 3.x?\nis_py3 = (_ver[0] == 3)\n\n# ---------\n# Specifics\n# ---------\n\nif is_py2:\n\tfrom StringIO import StringIO\n\tfrom urllib2 import HTTPPasswordMgr, HTTPDigestAuthHandler, Request,\\\n\t\t\t\t\t\tHTTPHandler, build_opener, HTTPError, URLError\n\tfrom httplib import BadStatusLine, HTTPException\n\tfrom urlparse import urlunparse\n\tfrom urllib import urlencode, quote_plus\n\n\tbytes = str\n\tunicode = unicode\n\tbasestring = basestring\nelif is_py3:\n\tfrom io import StringIO\n\tfrom urllib.request import HTTPPasswordMgr, HTTPDigestAuthHandler, Request,\\\n\t\t\t\t\t\t\t\tHTTPHandler, build_opener\n\tfrom urllib.error import HTTPError, URLError\n\tfrom http.client import HTTPException, BadStatusLine\n\tfrom urllib.parse import urlunparse, urlencode, quote_plus\n\n\tunicode = str\n\tbytes = bytes\n\tbasestring = (str,bytes)\n"
  },
  {
    "path": "musicbrainzngs/mbxml.py",
    "content": "# This file is part of the musicbrainzngs library\n# Copyright (C) Alastair Porter, Adrian Sampson, and others\n# This file is distributed under a BSD-2-Clause type license.\n# See the COPYING file for more information.\n\nimport re\nimport xml.etree.ElementTree as ET\nimport logging\n\nfrom . import util\n\n\ndef fixtag(tag, namespaces):\n    # given a decorated tag (of the form {uri}tag), return prefixed\n    # tag and namespace declaration, if any\n    if isinstance(tag, ET.QName):\n        tag = tag.text\n    namespace_uri, tag = tag[1:].split(\"}\", 1)\n    prefix = namespaces.get(namespace_uri)\n    if prefix is None:\n        prefix = \"ns%d\" % len(namespaces)\n        namespaces[namespace_uri] = prefix\n        if prefix == \"xml\":\n            xmlns = None\n        else:\n            xmlns = (\"xmlns:%s\" % prefix, namespace_uri)\n    else:\n        xmlns = None\n    return \"%s:%s\" % (prefix, tag), xmlns\n\n\nNS_MAP = {\"http://musicbrainz.org/ns/mmd-2.0#\": \"ws2\",\n          \"http://musicbrainz.org/ns/ext#-2.0\": \"ext\"}\n_log = logging.getLogger(\"musicbrainzngs\")\n\ndef get_error_message(error):\n    \"\"\" Given an error XML message from the webservice containing\n    <error><text>x</text><text>y</text></error>, return a list\n    of [x, y]\"\"\"\n    try:\n        tree = util.bytes_to_elementtree(error)\n        root = tree.getroot()\n        errors = []\n        if root.tag == \"error\":\n            for ch in root:\n                if ch.tag == \"text\":\n                    errors.append(ch.text)\n        return errors\n    except ET.ParseError:\n        return None\n\ndef make_artist_credit(artists):\n    names = []\n    for artist in artists:\n        if isinstance(artist, dict):\n            if \"name\" in artist:\n                names.append(artist.get(\"name\", \"\"))\n            else:\n                names.append(artist.get(\"artist\", {}).get(\"name\", \"\"))\n        else:\n                names.append(artist)\n    return \"\".join(names)\n\ndef parse_elements(valid_els, inner_els, element):\n    \"\"\" Extract single level subelements from an element.\n        For example, given the element:\n        <element>\n            <subelement>Text</subelement>\n        </element>\n        and a list valid_els that contains \"subelement\",\n        return a dict {'subelement': 'Text'}\n\n        Delegate the parsing of multi-level subelements to another function.\n        For example, given the element:\n        <element>\n            <subelement>\n                <a>Foo</a><b>Bar</b>\n            </subelement>\n        </element>\n        and a dictionary {'subelement': parse_subelement},\n        call parse_subelement(<subelement>) and\n        return a dict {'subelement': <result>}\n        if parse_subelement returns a tuple of the form\n        (True, {'subelement-key': <result>})\n        then merge the second element of the tuple into the\n        result (which may have a key other than 'subelement' or\n        more than 1 key)\n    \"\"\"\n    result = {}\n    for sub in element:\n        t = fixtag(sub.tag, NS_MAP)[0]\n        if \":\" in t:\n            t = t.split(\":\")[1]\n        if t in valid_els:\n            result[t] = sub.text or \"\"\n        elif t in inner_els.keys():\n            inner_result = inner_els[t](sub)\n            if isinstance(inner_result, tuple) and inner_result[0]:\n                result.update(inner_result[1])\n            else:\n                result[t] = inner_result\n            # add counts for lists when available\n            m = re.match(r'([a-z0-9-]+)-list', t)\n            if m and \"count\" in sub.attrib:\n                result[\"%s-count\" % m.group(1)] = int(sub.attrib[\"count\"])\n        else:\n            _log.info(\"in <%s>, uncaught <%s>\",\n                      fixtag(element.tag, NS_MAP)[0], t)\n    return result\n\ndef parse_attributes(attributes, element):\n    \"\"\" Extract attributes from an element.\n        For example, given the element:\n        <element type=\"Group\" />\n        and a list attributes that contains \"type\",\n        return a dict {'type': 'Group'}\n    \"\"\"\n    result = {}\n    for attr in element.attrib:\n        if \"{\" in attr:\n            a = fixtag(attr, NS_MAP)[0]\n        else:\n            a = attr\n        if a in attributes:\n            result[a] = element.attrib[attr]\n        else:\n            _log.info(\"in <%s>, uncaught attribute %s\", fixtag(element.tag, NS_MAP)[0], attr)\n\n    return result\n\ndef parse_message(message):\n    tree = util.bytes_to_elementtree(message)\n    root = tree.getroot()\n    result = {}\n    valid_elements = {\"area\": parse_area,\n                      \"artist\": parse_artist,\n                      \"instrument\": parse_instrument,\n                      \"label\": parse_label,\n                      \"place\": parse_place,\n                      \"event\": parse_event,\n                      \"release\": parse_release,\n                      \"release-group\": parse_release_group,\n                      \"series\": parse_series,\n                      \"recording\": parse_recording,\n                      \"work\": parse_work,\n                      \"url\": parse_url,\n\n                      \"disc\": parse_disc,\n                      \"cdstub\": parse_cdstub,\n                      \"isrc\": parse_isrc,\n\n                      \"annotation-list\": parse_annotation_list,\n                      \"area-list\": parse_area_list,\n                      \"artist-list\": parse_artist_list,\n                      \"label-list\": parse_label_list,\n                      \"place-list\": parse_place_list,\n                      \"event-list\": parse_event_list,\n                      \"instrument-list\": parse_instrument_list,\n                      \"release-list\": parse_release_list,\n                      \"release-group-list\": parse_release_group_list,\n                      \"series-list\": parse_series_list,\n                      \"recording-list\": parse_recording_list,\n                      \"work-list\": parse_work_list,\n                      \"url-list\": parse_url_list,\n\n                      \"collection-list\": parse_collection_list,\n                      \"collection\": parse_collection,\n\n                      \"message\": parse_response_message\n                      }\n    result.update(parse_elements([], valid_elements, root))\n    return result\n\ndef parse_response_message(message):\n    return parse_elements([\"text\"], {}, message)\n\ndef parse_collection_list(cl):\n    return [parse_collection(c) for c in cl]\n\ndef parse_collection(collection):\n    result = {}\n    attribs = [\"id\", \"type\", \"entity-type\"]\n    elements = [\"name\", \"editor\"]\n    inner_els = {\"release-list\": parse_release_list,\n                 \"artist-list\": parse_artist_list,\n                 \"event-list\": parse_event_list,\n                 \"place-list\": parse_place_list,\n                 \"recording-list\": parse_recording_list,\n                 \"work-list\": parse_work_list}\n    result.update(parse_attributes(attribs, collection))\n    result.update(parse_elements(elements, inner_els, collection))\n\n    return result\n\ndef parse_annotation_list(al):\n    return [parse_annotation(a) for a in al]\n\ndef parse_annotation(annotation):\n    result = {}\n    attribs = [\"type\", \"ext:score\"]\n    elements = [\"entity\", \"name\", \"text\"]\n    result.update(parse_attributes(attribs, annotation))\n    result.update(parse_elements(elements, {}, annotation))\n    return result\n\ndef parse_lifespan(lifespan):\n    parts = parse_elements([\"begin\", \"end\", \"ended\"], {}, lifespan)\n\n    return parts\n\ndef parse_area_list(al):\n    return [parse_area(a) for a in al]\n\ndef parse_area(area):\n    result = {}\n    attribs = [\"id\", \"type\", \"ext:score\"]\n    elements = [\"name\", \"sort-name\", \"disambiguation\"]\n    inner_els = {\"life-span\": parse_lifespan,\n                 \"alias-list\": parse_alias_list,\n                 \"relation-list\": parse_relation_list,\n                 \"annotation\": parse_annotation,\n                 \"iso-3166-1-code-list\": parse_element_list,\n                 \"iso-3166-2-code-list\": parse_element_list,\n                 \"iso-3166-3-code-list\": parse_element_list}\n\n    result.update(parse_attributes(attribs, area))\n    result.update(parse_elements(elements, inner_els, area))\n\n    return result\n\ndef parse_artist_list(al):\n    return [parse_artist(a) for a in al]\n\ndef parse_artist(artist):\n    result = {}\n    attribs = [\"id\", \"type\", \"ext:score\"]\n    elements = [\"name\", \"sort-name\", \"country\", \"user-rating\",\n                \"disambiguation\", \"gender\", \"ipi\"]\n    inner_els = {\"area\": parse_area,\n                 \"begin-area\": parse_area,\n                 \"end-area\": parse_area,\n                 \"life-span\": parse_lifespan,\n                 \"recording-list\": parse_recording_list,\n                 \"relation-list\": parse_relation_list,\n                 \"release-list\": parse_release_list,\n                 \"release-group-list\": parse_release_group_list,\n                 \"work-list\": parse_work_list,\n                 \"tag-list\": parse_tag_list,\n                 \"user-tag-list\": parse_tag_list,\n                 \"rating\": parse_rating,\n                 \"ipi-list\": parse_element_list,\n                 \"isni-list\": parse_element_list,\n                 \"alias-list\": parse_alias_list,\n                 \"annotation\": parse_annotation}\n\n    result.update(parse_attributes(attribs, artist))\n    result.update(parse_elements(elements, inner_els, artist))\n\n    return result\n\ndef parse_coordinates(c):\n    return parse_elements(['latitude', 'longitude'], {}, c)\n\ndef parse_place_list(pl):\n    return [parse_place(p) for p in pl]\n\ndef parse_place(place):\n    result = {}\n    attribs = [\"id\", \"type\", \"ext:score\"]\n    elements = [\"name\", \"address\",\n                \"ipi\", \"disambiguation\"]\n    inner_els = {\"area\": parse_area,\n                 \"coordinates\": parse_coordinates,\n                 \"life-span\": parse_lifespan,\n                 \"tag-list\": parse_tag_list,\n                 \"user-tag-list\": parse_tag_list,\n                 \"alias-list\": parse_alias_list,\n                 \"relation-list\": parse_relation_list,\n                 \"annotation\": parse_annotation}\n\n    result.update(parse_attributes(attribs, place))\n    result.update(parse_elements(elements, inner_els, place))\n\n    return result\n\ndef parse_event_list(el):\n    return [parse_event(e) for e in el]\n\ndef parse_event(event):\n    result = {}\n    attribs = [\"id\", \"type\", \"ext:score\"]\n    elements = [\"name\", \"time\", \"setlist\", \"cancelled\", \"disambiguation\", \"user-rating\"]\n    inner_els = {\"life-span\": parse_lifespan,\n                 \"relation-list\": parse_relation_list,\n                 \"alias-list\": parse_alias_list,\n                 \"tag-list\": parse_tag_list,\n                 \"user-tag-list\": parse_tag_list,\n                 \"rating\": parse_rating}\n\n    result.update(parse_attributes(attribs, event))\n    result.update(parse_elements(elements, inner_els, event))\n\n    return result\n\ndef parse_instrument(instrument):\n    result = {}\n    attribs = [\"id\", \"type\", \"ext:score\"]\n    elements = [\"name\", \"description\", \"disambiguation\"]\n    inner_els = {\"relation-list\": parse_relation_list,\n                 \"tag-list\": parse_tag_list,\n                 \"alias-list\": parse_alias_list,\n                 \"annotation\": parse_annotation}\n    result.update(parse_attributes(attribs, instrument))\n    result.update(parse_elements(elements, inner_els, instrument))\n\n    return result\n\ndef parse_label_list(ll):\n    return [parse_label(l) for l in ll]\n\ndef parse_label(label):\n    result = {}\n    attribs = [\"id\", \"type\", \"ext:score\"]\n    elements = [\"name\", \"sort-name\", \"country\", \"label-code\", \"user-rating\",\n                \"ipi\", \"disambiguation\"]\n    inner_els = {\"area\": parse_area,\n                 \"life-span\": parse_lifespan,\n                 \"release-list\": parse_release_list,\n                 \"tag-list\": parse_tag_list,\n                 \"user-tag-list\": parse_tag_list,\n                 \"rating\": parse_rating,\n                 \"ipi-list\": parse_element_list,\n                 \"alias-list\": parse_alias_list,\n                 \"relation-list\": parse_relation_list,\n                 \"annotation\": parse_annotation}\n\n    result.update(parse_attributes(attribs, label))\n    result.update(parse_elements(elements, inner_els, label))\n\n    return result\n\ndef parse_relation_target(tgt):\n    attributes = parse_attributes(['id'], tgt)\n    if 'id' in attributes:\n        return (True, {'target-id': attributes['id']})\n    else:\n        return (True, {'target-id': tgt.text})\n\ndef parse_relation_list(rl):\n    attribs = [\"target-type\"]\n    ttype = parse_attributes(attribs, rl)\n    key = \"%s-relation-list\" % ttype[\"target-type\"]\n    return (True, {key: [parse_relation(r) for r in rl]})\n\ndef parse_relation(relation):\n    result = {}\n    attribs = [\"type\", \"type-id\"]\n    elements = [\"target\", \"direction\", \"begin\", \"end\", \"ended\", \"ordering-key\"]\n    inner_els = {\"area\": parse_area,\n                 \"artist\": parse_artist,\n                 \"instrument\": parse_instrument,\n                 \"label\": parse_label,\n                 \"place\": parse_place,\n                 \"event\": parse_event,\n                 \"recording\": parse_recording,\n                 \"release\": parse_release,\n                 \"release-group\": parse_release_group,\n                 \"series\": parse_series,\n                 \"attribute-list\": parse_element_list,\n                 \"work\": parse_work,\n                 \"target\": parse_relation_target\n                }\n    result.update(parse_attributes(attribs, relation))\n    result.update(parse_elements(elements, inner_els, relation))\n    # We parse attribute-list again to get attributes that have both\n    # text and attribute values\n    result.update(parse_elements(['target-credit'], {\"attribute-list\": parse_relation_attribute_list}, relation))\n\n    return result\n\ndef parse_relation_attribute_list(attributelist):\n    ret = []\n    for attribute in attributelist:\n        ret.append(parse_relation_attribute_element(attribute))\n    return (True, {\"attributes\": ret})\n\ndef parse_relation_attribute_element(element):\n    # Parses an attribute into a dictionary containing an element\n    # {\"attribute\": <text value>} and also an additional element\n    # containing any xml attributes.\n    # e.g <attribute value=\"BuxWV 1\">number</attribute>\n    # -> {\"attribute\": \"number\", \"value\": \"BuxWV 1\"}\n    result = {}\n    for attr in element.attrib:\n        if \"{\" in attr:\n            a = fixtag(attr, NS_MAP)[0]\n        else:\n            a = attr\n        result[a] = element.attrib[attr]\n    result[\"attribute\"] = element.text\n    return result\n\ndef parse_release(release):\n    result = {}\n    attribs = [\"id\", \"ext:score\"]\n    elements = [\"title\", \"status\", \"disambiguation\", \"quality\", \"country\",\n                \"barcode\", \"date\", \"packaging\", \"asin\"]\n    inner_els = {\"text-representation\": parse_text_representation,\n                 \"artist-credit\": parse_artist_credit,\n                 \"label-info-list\": parse_label_info_list,\n                 \"medium-list\": parse_medium_list,\n                 \"release-group\": parse_release_group,\n                 \"tag-list\": parse_tag_list,\n                 \"user-tag-list\": parse_tag_list,\n                 \"relation-list\": parse_relation_list,\n                 \"annotation\": parse_annotation,\n                 \"cover-art-archive\": parse_caa,\n                 \"release-event-list\": parse_release_event_list}\n\n    result.update(parse_attributes(attribs, release))\n    result.update(parse_elements(elements, inner_els, release))\n    if \"artist-credit\" in result:\n        result[\"artist-credit-phrase\"] = make_artist_credit(\n                                                        result[\"artist-credit\"])\n\n    return result\n\ndef parse_medium_list(ml):\n    \"\"\"medium-list results from search have an additional\n    <track-count> element containing the number of tracks\n    over all mediums. Optionally add this\"\"\"\n    medium_list = []\n    track_count = None\n    for m in ml:\n        tag = fixtag(m.tag, NS_MAP)[0]\n        if tag == \"ws2:medium\":\n            medium_list.append(parse_medium(m))\n        elif tag == \"ws2:track-count\":\n            track_count = int(m.text)\n    ret = {\"medium-list\": medium_list}\n    if track_count is not None:\n        ret[\"medium-track-count\"] = track_count\n\n    return (True, ret)\n\ndef parse_release_event_list(rel):\n    return [parse_release_event(re) for re in rel]\n\ndef parse_release_event(event):\n    result = {}\n    elements = [\"date\"]\n    inner_els = {\"area\": parse_area}\n\n    result.update(parse_elements(elements, inner_els, event))\n    return result\n\ndef parse_medium(medium):\n    result = {}\n    elements = [\"position\", \"format\", \"title\"]\n    inner_els = {\"disc-list\": parse_disc_list,\n                 \"pregap\": parse_track,\n                 \"track-list\": parse_track_list,\n                 \"data-track-list\": parse_track_list}\n\n    result.update(parse_elements(elements, inner_els, medium))\n    return result\n\ndef parse_disc_list(dl):\n    return [parse_disc(d) for d in dl]\n\ndef parse_text_representation(textr):\n    return parse_elements([\"language\", \"script\"], {}, textr)\n\ndef parse_release_group(rg):\n    result = {}\n    attribs = [\"id\", \"type\", \"ext:score\"]\n    elements = [\"title\", \"user-rating\", \"first-release-date\", \"primary-type\",\n                \"disambiguation\"]\n    inner_els = {\"artist-credit\": parse_artist_credit,\n                 \"release-list\": parse_release_list,\n                 \"tag-list\": parse_tag_list,\n                 \"user-tag-list\": parse_tag_list,\n                 \"secondary-type-list\": parse_element_list,\n                 \"relation-list\": parse_relation_list,\n                 \"rating\": parse_rating,\n                 \"annotation\": parse_annotation}\n\n    result.update(parse_attributes(attribs, rg))\n    result.update(parse_elements(elements, inner_els, rg))\n    if \"artist-credit\" in result:\n        result[\"artist-credit-phrase\"] = make_artist_credit(result[\"artist-credit\"])\n\n    return result\n\ndef parse_recording(recording):\n    result = {}\n    attribs = [\"id\", \"ext:score\"]\n    elements = [\"title\", \"length\", \"user-rating\", \"disambiguation\", \"video\"]\n    inner_els = {\"artist-credit\": parse_artist_credit,\n                 \"release-list\": parse_release_list,\n                 \"tag-list\": parse_tag_list,\n                 \"user-tag-list\": parse_tag_list,\n                 \"rating\": parse_rating,\n                 \"isrc-list\": parse_external_id_list,\n                 \"relation-list\": parse_relation_list,\n                 \"annotation\": parse_annotation}\n\n    result.update(parse_attributes(attribs, recording))\n    result.update(parse_elements(elements, inner_els, recording))\n    if \"artist-credit\" in result:\n        result[\"artist-credit-phrase\"] = make_artist_credit(result[\"artist-credit\"])\n\n    return result\n\ndef parse_series_list(sl):\n    return [parse_series(s) for s in sl]\n\ndef parse_series(series):\n    result = {}\n    attribs = [\"id\", \"type\", \"ext:score\"]\n    elements = [\"name\", \"disambiguation\"]\n    inner_els = {\"alias-list\": parse_alias_list,\n                 \"relation-list\": parse_relation_list,\n                 \"annotation\": parse_annotation}\n\n    result.update(parse_attributes(attribs, series))\n    result.update(parse_elements(elements, inner_els, series))\n\n    return result\n\ndef parse_external_id_list(pl):\n    return [parse_attributes([\"id\"], p)[\"id\"] for p in pl]\n\ndef parse_element_list(el):\n    return [e.text for e in el]\n\ndef parse_work_list(wl):\n    return [parse_work(w) for w in wl]\n\ndef parse_work(work):\n    result = {}\n    attribs = [\"id\", \"ext:score\", \"type\"]\n    elements = [\"title\", \"user-rating\", \"language\", \"iswc\", \"disambiguation\"]\n    inner_els = {\"tag-list\": parse_tag_list,\n                 \"user-tag-list\": parse_tag_list,\n                 \"rating\": parse_rating,\n                 \"alias-list\": parse_alias_list,\n                 \"iswc-list\": parse_element_list,\n                 \"relation-list\": parse_relation_list,\n                 \"annotation\": parse_response_message,\n                 \"attribute-list\": parse_work_attribute_list\n    }\n\n    result.update(parse_attributes(attribs, work))\n    result.update(parse_elements(elements, inner_els, work))\n\n    return result\n\ndef parse_work_attribute_list(wal):\n    return [parse_work_attribute(wa) for wa in wal]\n\ndef parse_work_attribute(wa):\n    attribs = [\"type\"]\n    typeinfo = parse_attributes(attribs, wa)\n    result = {}\n    if typeinfo:\n        result = {\"attribute\": typeinfo[\"type\"],\n                  \"value\": wa.text}\n\n    return result\n\n\ndef parse_url_list(ul):\n    return [parse_url(u) for u in ul]\n\ndef parse_url(url):\n    result = {}\n    attribs = [\"id\"]\n    elements = [\"resource\"]\n    inner_els = {\"relation-list\": parse_relation_list}\n\n    result.update(parse_attributes(attribs, url))\n    result.update(parse_elements(elements, inner_els, url))\n\n    return result\n\ndef parse_disc(disc):\n    result = {}\n    attribs = [\"id\"]\n    elements = [\"sectors\"]\n    inner_els = {\"release-list\": parse_release_list,\n                 \"offset-list\": parse_offset_list\n    }\n\n    result.update(parse_attributes(attribs, disc))\n    result.update(parse_elements(elements, inner_els, disc))\n\n    return result\n\ndef parse_cdstub(cdstub):\n    result = {}\n    attribs = [\"id\"]\n    elements = [\"title\", \"artist\", \"barcode\"]\n    inner_els = {\"track-list\": parse_track_list}\n\n    result.update(parse_attributes(attribs, cdstub))\n    result.update(parse_elements(elements, inner_els, cdstub))\n\n    return result\n\ndef parse_offset_list(ol):\n    return [int(o.text) for o in ol]\n\ndef parse_instrument_list(rl):\n    result = []\n    for r in rl:\n        result.append(parse_instrument(r))\n    return result\n\ndef parse_release_list(rl):\n    result = []\n    for r in rl:\n        result.append(parse_release(r))\n    return result\n\ndef parse_release_group_list(rgl):\n    result = []\n    for rg in rgl:\n        result.append(parse_release_group(rg))\n    return result\n\ndef parse_isrc(isrc):\n    result = {}\n    attribs = [\"id\"]\n    inner_els = {\"recording-list\": parse_recording_list}\n\n    result.update(parse_attributes(attribs, isrc))\n    result.update(parse_elements([], inner_els, isrc))\n\n    return result\n\ndef parse_recording_list(recs):\n    result = []\n    for r in recs:\n        result.append(parse_recording(r))\n    return result\n\ndef parse_artist_credit(ac):\n    result = []\n    for namecredit in ac:\n        result.append(parse_name_credit(namecredit))\n        join = parse_attributes([\"joinphrase\"], namecredit)\n        if \"joinphrase\" in join:\n            result.append(join[\"joinphrase\"])\n    return result\n\ndef parse_name_credit(nc):\n    result = {}\n    elements = [\"name\"]\n    inner_els = {\"artist\": parse_artist}\n\n    result.update(parse_elements(elements, inner_els, nc))\n\n    return result\n\ndef parse_label_info_list(lil):\n    result = []\n\n    for li in lil:\n        result.append(parse_label_info(li))\n    return result\n\ndef parse_label_info(li):\n    result = {}\n    elements = [\"catalog-number\"]\n    inner_els = {\"label\": parse_label}\n\n    result.update(parse_elements(elements, inner_els, li))\n    return result\n\ndef parse_track_list(tl):\n    result = []\n    for t in tl:\n        result.append(parse_track(t))\n    return result\n\ndef parse_track(track):\n    result = {}\n    attribs = [\"id\"]\n    elements = [\"number\", \"position\", \"title\", \"length\"]\n    inner_els = {\"recording\": parse_recording,\n                 \"artist-credit\": parse_artist_credit}\n\n    result.update(parse_attributes(attribs, track))\n    result.update(parse_elements(elements, inner_els, track))\n    if \"artist-credit\" in result.get(\"recording\", {}) and \"artist-credit\" not in result:\n        result[\"artist-credit\"] = result[\"recording\"][\"artist-credit\"]\n    if \"artist-credit\" in result:\n        result[\"artist-credit-phrase\"] = make_artist_credit(result[\"artist-credit\"])\n    # Make a length field that contains track length or recording length\n    track_or_recording = None\n    if \"length\" in result:\n        track_or_recording = result[\"length\"]\n    elif result.get(\"recording\", {}).get(\"length\"):\n        track_or_recording = result.get(\"recording\", {}).get(\"length\")\n    if track_or_recording:\n        result[\"track_or_recording_length\"] = track_or_recording\n    return result\n\ndef parse_tag_list(tl):\n    return [parse_tag(t) for t in tl]\n\ndef parse_tag(tag):\n    result = {}\n    attribs = [\"count\"]\n    elements = [\"name\"]\n\n    result.update(parse_attributes(attribs, tag))\n    result.update(parse_elements(elements, {}, tag))\n\n    return result\n\ndef parse_rating(rating):\n    result = {}\n    attribs = [\"votes-count\"]\n\n    result.update(parse_attributes(attribs, rating))\n    result[\"rating\"] = rating.text\n\n    return result\n\ndef parse_alias_list(al):\n    return [parse_alias(a) for a in al]\n\ndef parse_alias(alias):\n    result = {}\n    attribs = [\"locale\", \"sort-name\", \"type\", \"primary\",\n               \"begin-date\", \"end-date\"]\n\n    result.update(parse_attributes(attribs, alias))\n    result[\"alias\"] = alias.text\n\n    return result\n\ndef parse_caa(caa_element):\n    result = {}\n    elements = [\"artwork\", \"count\", \"front\", \"back\", \"darkened\"]\n\n    result.update(parse_elements(elements, {}, caa_element))\n    return result\n\n\n###\n\ndef make_barcode_request(release2barcode):\n    NS = \"http://musicbrainz.org/ns/mmd-2.0#\"\n    root = ET.Element(\"{%s}metadata\" % NS)\n    rel_list = ET.SubElement(root, \"{%s}release-list\" % NS)\n    for release, barcode in release2barcode.items():\n        rel_xml = ET.SubElement(rel_list, \"{%s}release\" % NS)\n        bar_xml = ET.SubElement(rel_xml, \"{%s}barcode\" % NS)\n        rel_xml.set(\"{%s}id\" % NS, release)\n        bar_xml.text = barcode\n\n    return ET.tostring(root, \"utf-8\")\n\ndef make_tag_request(**kwargs):\n    NS = \"http://musicbrainz.org/ns/mmd-2.0#\"\n    root = ET.Element(\"{%s}metadata\" % NS)\n    for entity_type in ['artist', 'label', 'place', 'recording', 'release', 'release_group', 'work']:\n        entity_tags = kwargs.pop(entity_type + '_tags', None)\n        if entity_tags is not None:\n            e_list = ET.SubElement(root, \"{%s}%s-list\" % (NS, entity_type.replace('_', '-')))\n            for e, tags in entity_tags.items():\n                e_xml = ET.SubElement(e_list, \"{%s}%s\" % (NS, entity_type.replace('_', '-')))\n                e_xml.set(\"{%s}id\" % NS, e)\n                taglist = ET.SubElement(e_xml, \"{%s}user-tag-list\" % NS)\n                for tag in tags:\n                    usertag_xml = ET.SubElement(taglist, \"{%s}user-tag\" % NS)\n                    name_xml = ET.SubElement(usertag_xml, \"{%s}name\" % NS)\n                    name_xml.text = tag\n    if kwargs.keys():\n        raise TypeError(\"make_tag_request() got an unexpected keyword argument '%s'\" % kwargs.popitem()[0])\n\n    return ET.tostring(root, \"utf-8\")\n\ndef make_rating_request(**kwargs):\n    NS = \"http://musicbrainz.org/ns/mmd-2.0#\"\n    root = ET.Element(\"{%s}metadata\" % NS)\n    for entity_type in ['artist', 'label', 'recording', 'release_group', 'work']:\n        entity_ratings = kwargs.pop(entity_type + '_ratings', None)\n        if entity_ratings is not None:\n            e_list = ET.SubElement(root, \"{%s}%s-list\" % (NS, entity_type.replace('_', '-')))\n            for e, rating in entity_ratings.items():\n                e_xml = ET.SubElement(e_list, \"{%s}%s\" % (NS, entity_type.replace('_', '-')))\n                e_xml.set(\"{%s}id\" % NS, e)\n                rating_xml = ET.SubElement(e_xml, \"{%s}user-rating\" % NS)\n                rating_xml.text = str(rating)\n    if kwargs.keys():\n        raise TypeError(\"make_rating_request() got an unexpected keyword argument '%s'\" % kwargs.popitem()[0])\n\n    return ET.tostring(root, \"utf-8\")\n\ndef make_isrc_request(recording2isrcs):\n    NS = \"http://musicbrainz.org/ns/mmd-2.0#\"\n    root = ET.Element(\"{%s}metadata\" % NS)\n    rec_list = ET.SubElement(root, \"{%s}recording-list\" % NS)\n    for rec, isrcs in recording2isrcs.items():\n        if len(isrcs) > 0:\n            rec_xml = ET.SubElement(rec_list, \"{%s}recording\" % NS)\n            rec_xml.set(\"{%s}id\" % NS, rec)\n            isrc_list_xml = ET.SubElement(rec_xml, \"{%s}isrc-list\" % NS)\n            isrc_list_xml.set(\"{%s}count\" % NS, str(len(isrcs)))\n            for isrc in isrcs:\n                isrc_xml = ET.SubElement(isrc_list_xml, \"{%s}isrc\" % NS)\n                isrc_xml.set(\"{%s}id\" % NS, isrc)\n    return ET.tostring(root, \"utf-8\")\n"
  },
  {
    "path": "musicbrainzngs/musicbrainz.py",
    "content": "# This file is part of the musicbrainzngs library\n# Copyright (C) Alastair Porter, Adrian Sampson, and others\n# This file is distributed under a BSD-2-Clause type license.\n# See the COPYING file for more information.\n\nimport re\nimport threading\nimport time\nimport logging\nimport socket\nimport hashlib\nimport locale\nimport sys\nimport json\nimport xml.etree.ElementTree as etree\nfrom xml.parsers import expat\nfrom warnings import warn\n\nfrom musicbrainzngs import mbxml\nfrom musicbrainzngs import util\nfrom musicbrainzngs import compat\n\n_version = \"0.7.1\"\n_log = logging.getLogger(\"musicbrainzngs\")\n_max_retries = 8\n\nLUCENE_SPECIAL = r'([+\\-&|!(){}\\[\\]\\^\"~*?:\\\\\\/])'\n\n# Constants for validation.\n\nRELATABLE_TYPES = ['area', 'artist', 'label', 'place', 'event', 'recording', 'release', 'release-group', 'series', 'url', 'work', 'instrument']\nRELATION_INCLUDES = [entity + '-rels' for entity in RELATABLE_TYPES]\nTAG_INCLUDES = [\"tags\", \"user-tags\", \"genres\", \"user-genres\"]\nRATING_INCLUDES = [\"ratings\", \"user-ratings\"]\n\nVALID_INCLUDES = {\n    'area' : [\"aliases\", \"annotation\"] + RELATION_INCLUDES + TAG_INCLUDES,\n    'artist': [\n        \"recordings\", \"releases\", \"release-groups\", \"works\", # Subqueries\n        \"various-artists\", \"discids\", \"media\", \"isrcs\",\n        \"aliases\", \"annotation\"\n    ] + RELATION_INCLUDES + TAG_INCLUDES + RATING_INCLUDES,\n    'annotation': [\n\n    ],\n    'instrument': [\"aliases\", \"annotation\"\n    ] + RELATION_INCLUDES + TAG_INCLUDES,\n    'label': [\n        \"releases\", # Subqueries\n        \"discids\", \"media\",\n        \"aliases\", \"annotation\"\n    ] + RELATION_INCLUDES + TAG_INCLUDES + RATING_INCLUDES,\n    'place' : [\"aliases\", \"annotation\"] + RELATION_INCLUDES + TAG_INCLUDES,\n    'event' : [\"aliases\"] + RELATION_INCLUDES + TAG_INCLUDES + RATING_INCLUDES,\n    'recording': [\n        \"artists\", \"releases\", # Subqueries\n        \"discids\", \"media\", \"artist-credits\", \"isrcs\",\n        \"work-level-rels\", \"annotation\", \"aliases\"\n    ] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,\n    'release': [\n        \"artists\", \"labels\", \"recordings\", \"release-groups\", \"media\",\n        \"artist-credits\", \"discids\", \"isrcs\",\n        \"recording-level-rels\", \"work-level-rels\", \"annotation\", \"aliases\"\n    ] + TAG_INCLUDES + RELATION_INCLUDES,\n    'release-group': [\n        \"artists\", \"releases\", \"discids\", \"media\",\n        \"artist-credits\", \"annotation\", \"aliases\"\n    ] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,\n    'series': [\n        \"annotation\", \"aliases\"\n    ] + RELATION_INCLUDES + TAG_INCLUDES,\n    'work': [\n        \"aliases\", \"annotation\"\n    ] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,\n    'url': RELATION_INCLUDES,\n    'discid': [ # Discid should be the same as release\n        \"artists\", \"labels\", \"recordings\", \"release-groups\", \"media\",\n        \"artist-credits\", \"discids\", \"isrcs\",\n        \"recording-level-rels\", \"work-level-rels\", \"annotation\", \"aliases\"\n    ] + RELATION_INCLUDES,\n    'isrc': [\"artists\", \"releases\", \"isrcs\"],\n    'iswc': [\"artists\"],\n    'collection': ['releases'],\n}\nVALID_BROWSE_INCLUDES = {\n    'artist': [\"aliases\"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,\n    'event': [\"aliases\"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,\n    'label': [\"aliases\"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,\n    'recording': [\"artist-credits\", \"isrcs\", \"work-level-rels\"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,\n    'release': [\"artist-credits\", \"labels\", \"recordings\", \"isrcs\",\n                \"release-groups\", \"media\", \"discids\"] + RELATION_INCLUDES,\n    'place': [\"aliases\"] + TAG_INCLUDES + RELATION_INCLUDES,\n    'release-group': [\"artist-credits\"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,\n    'url': RELATION_INCLUDES,\n    'work': [\"aliases\", \"annotation\"] + TAG_INCLUDES + RATING_INCLUDES + RELATION_INCLUDES,\n}\n\n#: These can be used to filter whenever releases are includes or browsed\nVALID_RELEASE_TYPES = [\n    \"nat\",\n    \"album\", \"single\", \"ep\", \"broadcast\", \"other\", # primary types\n    \"compilation\", \"soundtrack\", \"spokenword\", \"interview\", \"audiobook\",\n    \"live\", \"remix\", \"dj-mix\", \"mixtape/street\", \"audio drama\" # secondary types\n]\n#: These can be used to filter whenever releases or release-groups are involved\nVALID_RELEASE_STATUSES = [\"official\", \"promotion\", \"bootleg\", \"pseudo-release\"]\nVALID_SEARCH_FIELDS = {\n    'annotation': [\n        'entity', 'name', 'text', 'type'\n    ],\n    'area': [\n        'aid', 'alias', 'area', 'areaaccent', 'begin', 'comment', 'end',\n        'ended', 'iso', 'iso1', 'iso2', 'iso3', 'sortname', 'tag', 'type'\n    ],\n    'artist': [\n        'alias', 'area', 'arid', 'artist', 'artistaccent', 'begin', 'beginarea',\n        'comment', 'country', 'end', 'endarea', 'ended', 'gender',\n        'ipi', 'isni', 'primary_alias', 'sortname', 'tag', 'type'\n    ],\n    'event': [\n        'aid', 'alias', 'area', 'arid', 'artist', 'begin', 'comment', 'eid',\n        'end', 'ended', 'event', 'eventaccent', 'pid', 'place', 'tag', 'type'\n    ],\n    'instrument': [\n        'alias', 'comment', 'description', 'iid', 'instrument',\n        'instrumentaccent', 'tag', 'type'\n    ],\n    'label': [\n        'alias', 'area', 'begin', 'code', 'comment', 'country', 'end', 'ended',\n        'ipi', 'label', 'labelaccent', 'laid', 'release_count', 'sortname',\n        'tag', 'type'\n    ],\n    'place': [\n        'address', 'alias', 'area', 'begin', 'comment', 'end', 'ended', 'lat', 'long',\n        'pid', 'place', 'placeaccent', 'type'\n    ],\n    'recording': [\n        'alias', 'arid', 'artist', 'artistname', 'comment', 'country',\n        'creditname', 'date', 'dur', 'format', 'isrc', 'number', 'position',\n        'primarytype', 'qdur', 'recording', 'recordingaccent', 'reid',\n        'release', 'rgid', 'rid', 'secondarytype', 'status', 'tag', 'tid',\n        'tnum', 'tracks', 'tracksrelease', 'type', 'video'],\n\n    'release-group': [\n        'alias', 'arid', 'artist', 'artistname', 'comment', 'creditname',\n        'primarytype', 'reid', 'release', 'releasegroup', 'releasegroupaccent',\n        'releases', 'rgid', 'secondarytype', 'status', 'tag', 'type'\n    ],\n    'release': [\n        'alias', 'arid', 'artist', 'artistname', 'asin', 'barcode', 'catno',\n        'comment', 'country', 'creditname', 'date', 'discids', 'discidsmedium',\n        'format', 'label', 'laid', 'lang', 'mediums', 'primarytype', 'quality',\n        'reid', 'release', 'releaseaccent', 'rgid', 'script', 'secondarytype',\n        'status', 'tag', 'tracks', 'tracksmedium', 'type'\n    ],\n    'series': [\n        'alias', 'comment', 'orderingattribute', 'series', 'seriesaccent',\n        'sid', 'tag', 'type'\n    ],\n    'work': [\n        'alias', 'arid', 'artist', 'comment', 'iswc', 'lang', 'recording',\n        'recording_count', 'rid', 'tag', 'type', 'wid', 'work', 'workaccent'\n    ]\n}\n\n# Constants\nclass AUTH_YES: pass\nclass AUTH_NO: pass\nclass AUTH_IFSET: pass\n\n\nAUTH_REQUIRED_INCLUDES = [\"user-tags\", \"user-ratings\", \"user-genres\"]\n\n\n# Exceptions.\n\nclass MusicBrainzError(Exception):\n\t\"\"\"Base class for all exceptions related to MusicBrainz.\"\"\"\n\tpass\n\nclass UsageError(MusicBrainzError):\n\t\"\"\"Error related to misuse of the module API.\"\"\"\n\tpass\n\nclass InvalidSearchFieldError(UsageError):\n\tpass\n\nclass InvalidIncludeError(UsageError):\n\tdef __init__(self, msg='Invalid Includes', reason=None):\n\t\tsuper(InvalidIncludeError, self).__init__(self)\n\t\tself.msg = msg\n\t\tself.reason = reason\n\n\tdef __str__(self):\n\t\treturn self.msg\n\nclass InvalidFilterError(UsageError):\n\tdef __init__(self, msg='Invalid Includes', reason=None):\n\t\tsuper(InvalidFilterError, self).__init__(self)\n\t\tself.msg = msg\n\t\tself.reason = reason\n\n\tdef __str__(self):\n\t\treturn self.msg\n\nclass WebServiceError(MusicBrainzError):\n\t\"\"\"Error related to MusicBrainz API requests.\"\"\"\n\tdef __init__(self, message=None, cause=None):\n\t\t\"\"\"Pass ``cause`` if this exception was caused by another\n\t\texception.\n\t\t\"\"\"\n\t\tself.message = message\n\t\tself.cause = cause\n\n\tdef __str__(self):\n\t\tif self.message:\n\t\t\tmsg = \"%s, \" % self.message\n\t\telse:\n\t\t\tmsg = \"\"\n\t\tmsg += \"caused by: %s\" % str(self.cause)\n\t\treturn msg\n\nclass NetworkError(WebServiceError):\n\t\"\"\"Problem communicating with the MB server.\"\"\"\n\tpass\n\nclass ResponseError(WebServiceError):\n\t\"\"\"Bad response sent by the MB server.\"\"\"\n\tpass\n\nclass AuthenticationError(WebServiceError):\n\t\"\"\"Received a HTTP 401 response while accessing a protected resource.\"\"\"\n\tpass\n\n\n# Helpers for validating and formatting allowed sets.\n\ndef _check_includes_impl(includes, valid_includes):\n    for i in includes:\n        if i not in valid_includes:\n            raise InvalidIncludeError(\"Bad includes: \"\n                                      \"%s is not a valid include\" % i)\ndef _check_includes(entity, inc):\n    _check_includes_impl(inc, VALID_INCLUDES[entity])\n\ndef _check_filter(values, valid):\n\tfor v in values:\n\t\tif v not in valid:\n\t\t\traise InvalidFilterError(v)\n\ndef _check_filter_and_make_params(entity, includes, release_status=[], release_type=[]):\n    \"\"\"Check that the status or type values are valid. Then, check that\n    the filters can be used with the given includes. Return a params\n    dict that can be passed to _do_mb_query.\n    \"\"\"\n    if isinstance(release_status, compat.basestring):\n        release_status = [release_status]\n    if isinstance(release_type, compat.basestring):\n        release_type = [release_type]\n    _check_filter(release_status, VALID_RELEASE_STATUSES)\n    _check_filter(release_type, VALID_RELEASE_TYPES)\n\n    if (release_status\n            and \"releases\" not in includes and entity != \"release\"):\n        raise InvalidFilterError(\"Can't have a status with no release include\")\n    if (release_type\n            and \"release-groups\" not in includes and \"releases\" not in includes\n            and entity not in [\"release-group\", \"release\"]):\n        raise InvalidFilterError(\"Can't have a release type \"\n                \"with no releases or release-groups involved\")\n\n    # Build parameters.\n    params = {}\n    if len(release_status):\n        params[\"status\"] = \"|\".join(release_status)\n    if len(release_type):\n        params[\"type\"] = \"|\".join(release_type)\n    return params\n\ndef _docstring_get(entity):\n    includes = list(VALID_INCLUDES.get(entity, []))\n    return _docstring_impl(\"includes\", includes)\n\ndef _docstring_browse(entity):\n    includes = list(VALID_BROWSE_INCLUDES.get(entity, []))\n    return _docstring_impl(\"includes\", includes)\n\ndef _docstring_search(entity):\n    search_fields = list(VALID_SEARCH_FIELDS.get(entity, []))\n    return _docstring_impl(\"fields\", search_fields)\n\ndef _docstring_impl(name, values):\n    def _decorator(func):\n        vstr = \", \".join(values)\n        args = {name: vstr}\n        if func.__doc__:\n            func.__doc__ = func.__doc__.format(**args)\n        return func\n\n    return _decorator\n\n\n# Global authentication and endpoint details.\n\nuser = password = \"\"\nhostname = \"musicbrainz.org\"\nhttps = True\n_client = \"\"\n_useragent = \"\"\n\ndef auth(u, p):\n\t\"\"\"Set the username and password to be used in subsequent queries to\n\tthe MusicBrainz XML API that require authentication.\n\t\"\"\"\n\tglobal user, password\n\tuser = u\n\tpassword = p\n\ndef set_useragent(app, version, contact=None):\n    \"\"\"Set the User-Agent to be used for requests to the MusicBrainz webservice.\n    This must be set before requests are made.\"\"\"\n    global _useragent, _client\n    if not app or not version:\n        raise ValueError(\"App and version can not be empty\")\n    if contact is not None:\n        _useragent = \"%s/%s python-musicbrainzngs/%s ( %s )\" % (app, version, _version, contact)\n    else:\n        _useragent = \"%s/%s python-musicbrainzngs/%s\" % (app, version, _version)\n    _client = \"%s-%s\" % (app, version)\n    _log.debug(\"set user-agent to %s\" % _useragent)\n\n\ndef set_hostname(new_hostname, use_https=False):\n    \"\"\"Set the hostname for MusicBrainz webservice requests.\n    Defaults to 'musicbrainz.org', accessing over https.\n    For backwards compatibility, `use_https` is False by default.\n\n    :param str new_hostname: The hostname (and port) of the MusicBrainz server to connect to\n    :param bool use_https: `True` if the host should be accessed using https. Default is `False`\n\n    Specify a non-standard port by adding it to the hostname,\n    for example 'localhost:8000'.\"\"\"\n    global hostname\n    global https\n    hostname = new_hostname\n    https = use_https\n\n# Rate limiting.\n\nlimit_interval = 1.0\nlimit_requests = 1\ndo_rate_limit = True\n\ndef set_rate_limit(limit_or_interval=1.0, new_requests=1):\n    \"\"\"Sets the rate limiting behavior of the module. Must be invoked\n    before the first Web service call.\n    If the `limit_or_interval` parameter is set to False then\n    rate limiting will be disabled. If it is a number then only\n    a set number of requests (`new_requests`) will be made per\n    given interval (`limit_or_interval`).\n    \"\"\"\n    global limit_interval\n    global limit_requests\n    global do_rate_limit\n    if isinstance(limit_or_interval, bool):\n        do_rate_limit = limit_or_interval\n    else:\n        if limit_or_interval <= 0.0:\n            raise ValueError(\"limit_or_interval can't be less than 0\")\n        if new_requests <= 0:\n            raise ValueError(\"new_requests can't be less than 0\")\n        do_rate_limit = True\n        limit_interval = limit_or_interval\n        limit_requests = new_requests\n\nclass _rate_limit(object):\n    \"\"\"A decorator that limits the rate at which the function may be\n    called. The rate is controlled by the `limit_interval` and\n    `limit_requests` global variables.  The limiting is thread-safe;\n    only one thread may be in the function at a time (acts like a\n    monitor in this sense). The globals must be set before the first\n    call to the limited function.\n    \"\"\"\n    def __init__(self, fun):\n        self.fun = fun\n        self.last_call = 0.0\n        self.lock = threading.Lock()\n        self.remaining_requests = None # Set on first invocation.\n\n    def _update_remaining(self):\n        \"\"\"Update remaining requests based on the elapsed time since\n        they were last calculated.\n        \"\"\"\n        # On first invocation, we have the maximum number of requests\n        # available.\n        if self.remaining_requests is None:\n            self.remaining_requests = float(limit_requests)\n\n        else:\n            since_last_call = time.time() - self.last_call\n            self.remaining_requests += since_last_call * \\\n                                       (limit_requests / limit_interval)\n            self.remaining_requests = min(self.remaining_requests,\n                                          float(limit_requests))\n\n        self.last_call = time.time()\n\n    def __call__(self, *args, **kwargs):\n        with self.lock:\n            if do_rate_limit:\n                self._update_remaining()\n\n                # Delay if necessary.\n                while self.remaining_requests < 0.999:\n                    time.sleep((1.0 - self.remaining_requests) *\n                               (limit_requests / limit_interval))\n                    self._update_remaining()\n\n                # Call the original function, \"paying\" for this call.\n                self.remaining_requests -= 1.0\n            return self.fun(*args, **kwargs)\n\n# From pymb2\nclass _RedirectPasswordMgr(compat.HTTPPasswordMgr):\n\tdef __init__(self):\n\t\tself._realms = { }\n\n\tdef find_user_password(self, realm, uri):\n\t\t# ignoring the uri parameter intentionally\n\t\ttry:\n\t\t\treturn self._realms[realm]\n\t\texcept KeyError:\n\t\t\treturn (None, None)\n\n\tdef add_password(self, realm, uri, username, password):\n\t\t# ignoring the uri parameter intentionally\n\t\tself._realms[realm] = (username, password)\n\nclass _DigestAuthHandler(compat.HTTPDigestAuthHandler):\n    def get_authorization (self, req, chal):\n        qop = chal.get ('qop', None)\n        if qop and ',' in qop and 'auth' in qop.split (','):\n            chal['qop'] = 'auth'\n\n        return compat.HTTPDigestAuthHandler.get_authorization (self, req, chal)\n\n    def _encode_utf8(self, msg):\n        \"\"\"The MusicBrainz server also accepts UTF-8 encoded passwords.\"\"\"\n        encoding = sys.stdin.encoding or locale.getpreferredencoding()\n        try:\n            # This works on Python 2 (msg in bytes)\n            msg = msg.decode(encoding)\n        except AttributeError:\n            # on Python 3 (msg is already in unicode)\n            pass\n        return msg.encode(\"utf-8\")\n\n    def get_algorithm_impls(self, algorithm):\n        # algorithm should be case-insensitive according to RFC2617\n        algorithm = algorithm.upper()\n        # lambdas assume digest modules are imported at the top level\n        if algorithm == 'MD5':\n            H = lambda x: hashlib.md5(self._encode_utf8(x)).hexdigest()\n        elif algorithm == 'SHA':\n            H = lambda x: hashlib.sha1(self._encode_utf8(x)).hexdigest()\n        # XXX MD5-sess\n        KD = lambda s, d: H(\"%s:%s\" % (s, d))\n        return H, KD\n\nclass _MusicbrainzHttpRequest(compat.Request):\n\t\"\"\" A custom request handler that allows DELETE and PUT\"\"\"\n\tdef __init__(self, method, url, data=None):\n\t\tcompat.Request.__init__(self, url, data)\n\t\tallowed_m = [\"GET\", \"POST\", \"DELETE\", \"PUT\"]\n\t\tif method not in allowed_m:\n\t\t\traise ValueError(\"invalid method: %s\" % method)\n\t\tself.method = method\n\n\tdef get_method(self):\n\t\treturn self.method\n\n\n# Core (internal) functions for calling the MB API.\n\ndef _safe_read(opener, req, body=None, max_retries=_max_retries, retry_delay_delta=2.0):\n\t\"\"\"Open an HTTP request with a given URL opener and (optionally) a\n\trequest body. Transient errors lead to retries.  Permanent errors\n\tand repeated errors are translated into a small set of handleable\n\texceptions. Return a bytestring.\n\t\"\"\"\n\tlast_exc = None\n\tfor retry_num in range(max_retries):\n\t\tif retry_num: # Not the first try: delay an increasing amount.\n\t\t\t_log.info(\"retrying after delay (#%i)\" % retry_num)\n\t\t\ttime.sleep(retry_num * retry_delay_delta)\n\n\t\ttry:\n\t\t\tif body:\n\t\t\t\tf = opener.open(req, body)\n\t\t\telse:\n\t\t\t\tf = opener.open(req)\n\t\t\treturn f.read()\n\n\t\texcept compat.HTTPError as exc:\n\t\t\tif exc.code in (400, 404, 411):\n\t\t\t\t# Bad request, not found, etc.\n\t\t\t\traise ResponseError(cause=exc)\n\t\t\telif exc.code in (503, 502, 500):\n\t\t\t\t# Rate limiting, internal overloading...\n\t\t\t\t_log.info(\"HTTP error %i\" % exc.code)\n\t\t\telif exc.code in (401, ):\n\t\t\t\traise AuthenticationError(cause=exc)\n\t\t\telse:\n\t\t\t\t# Other, unknown error. Should handle more cases, but\n\t\t\t\t# retrying for now.\n\t\t\t\t_log.info(\"unknown HTTP error %i\" % exc.code)\n\t\t\tlast_exc = exc\n\t\texcept compat.BadStatusLine as exc:\n\t\t\t_log.info(\"bad status line\")\n\t\t\tlast_exc = exc\n\t\texcept compat.HTTPException as exc:\n\t\t\t_log.info(\"miscellaneous HTTP exception: %s\" % str(exc))\n\t\t\tlast_exc = exc\n\t\texcept compat.URLError as exc:\n\t\t\tif isinstance(exc.reason, socket.error):\n\t\t\t\tcode = exc.reason.errno\n\t\t\t\tif code == 104: # \"Connection reset by peer.\"\n\t\t\t\t\tcontinue\n\t\t\traise NetworkError(cause=exc)\n\t\texcept socket.timeout as exc:\n\t\t\t_log.info(\"socket timeout\")\n\t\t\tlast_exc = exc\n\t\texcept socket.error as exc:\n\t\t\tif exc.errno == 104:\n\t\t\t\tcontinue\n\t\t\traise NetworkError(cause=exc)\n\t\texcept IOError as exc:\n\t\t\traise NetworkError(cause=exc)\n\n\t# Out of retries!\n\traise NetworkError(\"retried %i times\" % max_retries, last_exc)\n\n# Get the XML parsing exceptions to catch. The behavior chnaged with Python 2.7\n# and ElementTree 1.3.\nif hasattr(etree, 'ParseError'):\n\tETREE_EXCEPTIONS = (etree.ParseError, expat.ExpatError)\nelse:\n\tETREE_EXCEPTIONS = (expat.ExpatError)\n\n\n# Parsing setup\n\ndef mb_parser_null(resp):\n    \"\"\"Return the raw response (XML)\"\"\"\n    return resp\n\ndef mb_parser_xml(resp):\n    \"\"\"Return a Python dict representing the XML response\"\"\"\n    # Parse the response.\n    try:\n        return mbxml.parse_message(resp)\n    except UnicodeError as exc:\n        raise ResponseError(cause=exc)\n    except Exception as exc:\n        if isinstance(exc, ETREE_EXCEPTIONS):\n            raise ResponseError(cause=exc)\n        else:\n            raise\n\n# Defaults\nparser_fun = mb_parser_xml\nws_format = \"xml\"\n\ndef set_parser(new_parser_fun=None):\n    \"\"\"Sets the function used to parse the response from the\n    MusicBrainz web service.\n\n    If no parser is given, the parser is reset to the default parser\n    :func:`mb_parser_xml`.\n    \"\"\"\n    global parser_fun\n    if new_parser_fun is None:\n        new_parser_fun = mb_parser_xml\n    if not callable(new_parser_fun):\n        raise ValueError(\"new_parser_fun must be callable\")\n    parser_fun = new_parser_fun\n\ndef set_format(fmt=\"xml\"):\n    \"\"\"Sets the format that should be returned by the Web Service.\n    The server currently supports `xml` and `json`.\n\n    This method will set a default parser for the specified format,\n    but you can modify it with :func:`set_parser`.\n\n    .. warning:: The json format used by the server is different from\n        the json format returned by the `musicbrainzngs` internal parser\n        when using the `xml` format! This format may change at any time.\n    \"\"\"\n    global ws_format\n    if fmt == \"xml\":\n        ws_format = fmt\n        set_parser() # set to default\n    elif fmt == \"json\":\n        ws_format = fmt\n        warn(\"The json format is non-official and may change at any time\")\n        set_parser(json.loads)\n    else:\n        raise ValueError(\"invalid format: %s\" % fmt)\n\n\n@_rate_limit\ndef _mb_request(path, method='GET', auth_required=AUTH_NO,\n                client_required=False, args=None, data=None, body=None):\n    \"\"\"Makes a request for the specified `path` (endpoint) on /ws/2 on\n    the globally-specified hostname. Parses the responses and returns\n    the resulting object.  `auth_required` and `client_required` control\n    whether exceptions should be raised if the username/password and\n    client are left unspecified, respectively.\n    \"\"\"\n    global parser_fun\n\n    if args is None:\n        args = {}\n    else:\n        args = dict(args) or {}\n\n    if _useragent == \"\":\n        raise UsageError(\"set a proper user-agent with \"\n                         \"set_useragent(\\\"application name\\\", \\\"application version\\\", \\\"contact info (preferably URL or email for your application)\\\")\")\n\n    if client_required:\n        args[\"client\"] = _client\n\n    if ws_format != \"xml\":\n        args[\"fmt\"] = ws_format\n\n    # Convert args from a dictionary to a list of tuples\n    # so that the ordering of elements is stable for easy\n    # testing (in this case we order alphabetically)\n    # Encode Unicode arguments using UTF-8.\n    newargs = []\n    for key, value in sorted(args.items()):\n        if isinstance(value, compat.unicode):\n            value = value.encode('utf8')\n        newargs.append((key, value))\n\n    # Construct the full URL for the request, including hostname and\n    # query string.\n    url = compat.urlunparse((\n        'https' if https else 'http',\n        hostname,\n        '/ws/2/%s' % path,\n        '',\n        compat.urlencode(newargs),\n        ''\n    ))\n    _log.debug(\"%s request for %s\" % (method, url))\n\n    # Set up HTTP request handler and URL opener.\n    httpHandler = compat.HTTPHandler(debuglevel=0)\n    handlers = [httpHandler]\n\n    # Add credentials if required.\n    add_auth = False\n    if auth_required == AUTH_YES:\n        _log.debug(\"Auth required for %s\" % url)\n        if not user:\n            raise UsageError(\"authorization required; \"\n                             \"use auth(user, pass) first\")\n        add_auth = True\n\n    if auth_required == AUTH_IFSET and user:\n        _log.debug(\"Using auth for %s because user and pass is set\" % url)\n        add_auth = True\n\n    if add_auth:\n        passwordMgr = _RedirectPasswordMgr()\n        authHandler = _DigestAuthHandler(passwordMgr)\n        authHandler.add_password(\"musicbrainz.org\", (), user, password)\n        handlers.append(authHandler)\n\n    opener = compat.build_opener(*handlers)\n\n    # Make request.\n    req = _MusicbrainzHttpRequest(method, url, data)\n    req.add_header('User-Agent', _useragent)\n    _log.debug(\"requesting with UA %s\" % _useragent)\n    if body:\n        req.add_header('Content-Type', 'application/xml; charset=UTF-8')\n    elif not data and not req.has_header('Content-Length'):\n        # Explicitly indicate zero content length if no request data\n        # will be sent (avoids HTTP 411 error).\n        req.add_header('Content-Length', '0')\n    resp = _safe_read(opener, req, body)\n\n    return parser_fun(resp)\n\n\ndef _get_auth_type(entity, id, includes):\n    \"\"\" Some calls require authentication. This returns\n    a constant (Yes, No, IfSet) for the auth status of the call.\n    \"\"\"\n    if \"user-tags\" in includes or \"user-ratings\" in includes or \"user-genres\" in includes:\n        return AUTH_YES\n    elif entity.startswith(\"collection\"):\n        if not id:\n            return AUTH_YES\n        else:\n            return AUTH_IFSET\n    else:\n        return AUTH_NO\n\n\ndef _do_mb_query(entity, id, includes=[], params={}):\n\t\"\"\"Make a single GET call to the MusicBrainz XML API. `entity` is a\n\tstring indicated the type of object to be retrieved. The id may be\n\tempty, in which case the query is a search. `includes` is a list\n\tof strings that must be valid includes for the entity type. `params`\n\tis a dictionary of additional parameters for the API call. The\n\tresponse is parsed and returned.\n\t\"\"\"\n\t# Build arguments.\n\tif not isinstance(includes, list):\n\t\tincludes = [includes]\n\t_check_includes(entity, includes)\n\tauth_required = _get_auth_type(entity, id, includes)\n\targs = dict(params)\n\tif len(includes) > 0:\n\t\tinc = \" \".join(includes)\n\t\targs[\"inc\"] = inc\n\n\t# Build the endpoint components.\n\tpath = '%s/%s' % (entity, id)\n\treturn _mb_request(path, 'GET', auth_required, args=args)\n\ndef _do_mb_search(entity, query='', fields={},\n\t\t  limit=None, offset=None, strict=False):\n\t\"\"\"Perform a full-text search on the MusicBrainz search server.\n\t`query` is a lucene query string when no fields are set,\n\tbut is escaped when any fields are given. `fields` is a dictionary\n\tof key/value query parameters. They keys in `fields` must be valid\n\tfor the given entity type.\n\t\"\"\"\n\t# Encode the query terms as a Lucene query string.\n\tquery_parts = []\n\tif query:\n\t\tclean_query = util._unicode(query)\n\t\tif fields:\n\t\t\tclean_query = re.sub(LUCENE_SPECIAL, r'\\\\\\1',\n\t\t\t\t\t     clean_query)\n\t\t\tif strict:\n\t\t\t\tquery_parts.append('\"%s\"' % clean_query)\n\t\t\telse:\n\t\t\t\tquery_parts.append(clean_query.lower())\n\t\telse:\n\t\t\tquery_parts.append(clean_query)\n\tfor key, value in fields.items():\n\t\t# Ensure this is a valid search field.\n\t\tif key not in VALID_SEARCH_FIELDS[entity]:\n\t\t\traise InvalidSearchFieldError(\n\t\t\t\t'%s is not a valid search field for %s' % (key, entity)\n\t\t\t)\n\n\t\t# Escape Lucene's special characters.\n\t\tvalue = util._unicode(value)\n\t\tvalue = re.sub(LUCENE_SPECIAL, r'\\\\\\1', value)\n\t\tif value:\n\t\t\tif strict:\n\t\t\t\tquery_parts.append('%s:\"%s\"' % (key, value))\n\t\t\telse:\n\t\t\t\tvalue = value.lower() # avoid AND / OR\n\t\t\t\tquery_parts.append('%s:(%s)' % (key, value))\n\tif strict:\n\t\tfull_query = ' AND '.join(query_parts).strip()\n\telse:\n\t\tfull_query = ' '.join(query_parts).strip()\n\n\tif not full_query:\n\t\traise ValueError('at least one query term is required')\n\n\t# Additional parameters to the search.\n\tparams = {'query': full_query}\n\tif limit:\n\t\tparams['limit'] = str(limit)\n\tif offset:\n\t\tparams['offset'] = str(offset)\n\n\treturn _do_mb_query(entity, '', [], params)\n\ndef _do_mb_delete(path):\n\t\"\"\"Send a DELETE request for the specified object.\n\t\"\"\"\n\treturn _mb_request(path, 'DELETE', AUTH_YES, True)\n\ndef _do_mb_put(path):\n\t\"\"\"Send a PUT request for the specified object.\n\t\"\"\"\n\treturn _mb_request(path, 'PUT', AUTH_YES, True)\n\ndef _do_mb_post(path, body):\n\t\"\"\"Perform a single POST call for an endpoint with a specified\n\trequest body.\n\t\"\"\"\n\treturn _mb_request(path, 'POST', AUTH_YES, True, body=body)\n\n\n# The main interface!\n\n# Single entity by ID\n\n@_docstring_get(\"area\")\ndef get_area_by_id(id, includes=[], release_status=[], release_type=[]):\n    \"\"\"Get the area with the MusicBrainz `id` as a dict with an 'area' key.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"area\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"area\", id, includes, params)\n\n@_docstring_get(\"artist\")\ndef get_artist_by_id(id, includes=[], release_status=[], release_type=[]):\n    \"\"\"Get the artist with the MusicBrainz `id` as a dict with an 'artist' key.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"artist\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"artist\", id, includes, params)\n\n@_docstring_get(\"instrument\")\ndef get_instrument_by_id(id, includes=[], release_status=[], release_type=[]):\n    \"\"\"Get the instrument with the MusicBrainz `id` as a dict with an 'artist' key.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"instrument\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"instrument\", id, includes, params)\n\n@_docstring_get(\"label\")\ndef get_label_by_id(id, includes=[], release_status=[], release_type=[]):\n    \"\"\"Get the label with the MusicBrainz `id` as a dict with a 'label' key.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"label\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"label\", id, includes, params)\n\n@_docstring_get(\"place\")\ndef get_place_by_id(id, includes=[], release_status=[], release_type=[]):\n    \"\"\"Get the place with the MusicBrainz `id` as a dict with an 'place' key.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"place\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"place\", id, includes, params)\n\n@_docstring_get(\"event\")\ndef get_event_by_id(id, includes=[], release_status=[], release_type=[]):\n    \"\"\"Get the event with the MusicBrainz `id` as a dict with an 'event' key.\n\n    The event dict has the following keys:\n    `id`, `type`, `name`, `time`, `disambiguation` and `life-span`.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"event\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"event\", id, includes, params)\n\n@_docstring_get(\"recording\")\ndef get_recording_by_id(id, includes=[], release_status=[], release_type=[]):\n    \"\"\"Get the recording with the MusicBrainz `id` as a dict\n    with a 'recording' key.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"recording\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"recording\", id, includes, params)\n\n@_docstring_get(\"release\")\ndef get_release_by_id(id, includes=[], release_status=[], release_type=[]):\n    \"\"\"Get the release with the MusicBrainz `id` as a dict with a 'release' key.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"release\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"release\", id, includes, params)\n\n@_docstring_get(\"release-group\")\ndef get_release_group_by_id(id, includes=[],\n                            release_status=[], release_type=[]):\n    \"\"\"Get the release group with the MusicBrainz `id` as a dict\n    with a 'release-group' key.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"release-group\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"release-group\", id, includes, params)\n\n@_docstring_get(\"series\")\ndef get_series_by_id(id, includes=[]):\n    \"\"\"Get the series with the MusicBrainz `id` as a dict with a 'series' key.\n\n    *Available includes*: {includes}\"\"\"\n    return _do_mb_query(\"series\", id, includes)\n\n@_docstring_get(\"work\")\ndef get_work_by_id(id, includes=[]):\n    \"\"\"Get the work with the MusicBrainz `id` as a dict with a 'work' key.\n\n    *Available includes*: {includes}\"\"\"\n    return _do_mb_query(\"work\", id, includes)\n\n@_docstring_get(\"url\")\ndef get_url_by_id(id, includes=[]):\n    \"\"\"Get the url with the MusicBrainz `id` as a dict with a 'url' key.\n\n    *Available includes*: {includes}\"\"\"\n    return _do_mb_query(\"url\", id, includes)\n\n\n# Searching\n\n@_docstring_search(\"annotation\")\ndef search_annotations(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for annotations and return a dict with an 'annotation-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('annotation', query, fields, limit, offset, strict)\n\n@_docstring_search(\"area\")\ndef search_areas(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for areas and return a dict with an 'area-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('area', query, fields, limit, offset, strict)\n\n@_docstring_search(\"artist\")\ndef search_artists(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for artists and return a dict with an 'artist-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('artist', query, fields, limit, offset, strict)\n\n@_docstring_search(\"event\")\ndef search_events(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for events and return a dict with an 'event-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('event', query, fields, limit, offset, strict)\n\n@_docstring_search(\"instrument\")\ndef search_instruments(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for instruments and return a dict with a 'instrument-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('instrument', query, fields, limit, offset, strict)\n\n@_docstring_search(\"label\")\ndef search_labels(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for labels and return a dict with a 'label-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('label', query, fields, limit, offset, strict)\n\n@_docstring_search(\"place\")\ndef search_places(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for places and return a dict with a 'place-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('place', query, fields, limit, offset, strict)\n\n@_docstring_search(\"recording\")\ndef search_recordings(query='', limit=None, offset=None,\n                      strict=False, **fields):\n    \"\"\"Search for recordings and return a dict with a 'recording-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('recording', query, fields, limit, offset, strict)\n\n@_docstring_search(\"release\")\ndef search_releases(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for recordings and return a dict with a 'recording-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('release', query, fields, limit, offset, strict)\n\n@_docstring_search(\"release-group\")\ndef search_release_groups(query='', limit=None, offset=None,\n\t\t\t  strict=False, **fields):\n    \"\"\"Search for release groups and return a dict\n    with a 'release-group-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('release-group', query, fields, limit, offset, strict)\n\n@_docstring_search(\"series\")\ndef search_series(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for series and return a dict with a 'series-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('series', query, fields, limit, offset, strict)\n\n@_docstring_search(\"work\")\ndef search_works(query='', limit=None, offset=None, strict=False, **fields):\n    \"\"\"Search for works and return a dict with a 'work-list' key.\n\n    *Available search fields*: {fields}\"\"\"\n    return _do_mb_search('work', query, fields, limit, offset, strict)\n\n\n# Lists of entities\n@_docstring_get(\"discid\")\ndef get_releases_by_discid(id, includes=[], toc=None, cdstubs=True, media_format=None):\n    \"\"\"Search for releases with a :musicbrainz:`Disc ID` or table of contents.\n\n    When a `toc` is provided and no release with the disc ID is found,\n    a fuzzy search by the toc is done.\n    The `toc` should have to same format as :attr:`discid.Disc.toc_string`.\n    When a `toc` is provided, the format of the discid itself is not\n    checked server-side, so any value may be passed if searching by only\n    `toc` is desired.\n\n    If no toc matches in musicbrainz but a :musicbrainz:`CD Stub` does,\n    the CD Stub will be returned. Prevent this from happening by\n    passing `cdstubs=False`.\n\n    By default only results that match a format that allows discids\n    (e.g. CD) are included. To include all media formats, pass\n    `media_format='all'`.\n\n    The result is a dict with either a 'disc' , a 'cdstub' key\n    or a 'release-list' (fuzzy match with TOC).\n    A 'disc' has an 'offset-count', an 'offset-list' and a 'release-list'.\n    A 'cdstub' key has direct 'artist' and 'title' keys.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"discid\", includes, release_status=[],\n                                           release_type=[])\n    if toc:\n        params[\"toc\"] = toc\n    if not cdstubs:\n        params[\"cdstubs\"] = \"no\"\n    if media_format:\n        params[\"media-format\"] = media_format\n    return _do_mb_query(\"discid\", id, includes, params)\n\n\n@_docstring_get(\"recording\")\ndef get_recordings_by_isrc(isrc, includes=[], release_status=[],\n                           release_type=[]):\n    \"\"\"Search for recordings with an :musicbrainz:`ISRC`.\n    The result is a dict with an 'isrc' key,\n    which again includes a 'recording-list'.\n\n    *Available includes*: {includes}\"\"\"\n    params = _check_filter_and_make_params(\"isrc\", includes,\n                                           release_status, release_type)\n    return _do_mb_query(\"isrc\", isrc, includes, params)\n\n@_docstring_get(\"work\")\ndef get_works_by_iswc(iswc, includes=[]):\n    \"\"\"Search for works with an :musicbrainz:`ISWC`.\n    The result is a dict with a`work-list`.\n\n    *Available includes*: {includes}\"\"\"\n    return _do_mb_query(\"iswc\", iswc, includes)\n\n\ndef _browse_impl(entity, includes, limit, offset, params, release_status=[], release_type=[]):\n    includes = includes if isinstance(includes, list) else [includes]\n    valid_includes = VALID_BROWSE_INCLUDES[entity]\n    _check_includes_impl(includes, valid_includes)\n    p = {}\n    for k,v in params.items():\n        if v:\n            p[k] = v\n    if len(p) > 1:\n        raise Exception(\"Can't have more than one of \" + \", \".join(params.keys()))\n    if limit: p[\"limit\"] = limit\n    if offset: p[\"offset\"] = offset\n    filterp = _check_filter_and_make_params(entity, includes, release_status, release_type)\n    p.update(filterp)\n    return _do_mb_query(entity, \"\", includes, p)\n\n# Browse methods\n# Browse include are a subset of regular get includes, so we check them here\n# and the test in _do_mb_query will pass anyway.\n@_docstring_browse(\"artist\")\ndef browse_artists(recording=None, release=None, release_group=None,\n                   work=None, includes=[], limit=None, offset=None):\n    \"\"\"Get all artists linked to a recording, a release or a release group.\n    You need to give one MusicBrainz ID.\n\n    *Available includes*: {includes}\"\"\"\n    params = {\"recording\": recording,\n              \"release\": release,\n              \"release-group\": release_group,\n              \"work\": work}\n    return _browse_impl(\"artist\", includes, limit, offset, params)\n\n@_docstring_browse(\"event\")\ndef browse_events(area=None, artist=None, place=None,\n                   includes=[], limit=None, offset=None):\n    \"\"\"Get all events linked to a area, a artist or a place.\n    You need to give one MusicBrainz ID.\n\n    *Available includes*: {includes}\"\"\"\n    params = {\"area\": area,\n              \"artist\": artist,\n              \"place\": place}\n    return _browse_impl(\"event\", includes, limit, offset, params)\n\n@_docstring_browse(\"label\")\ndef browse_labels(release=None, includes=[], limit=None, offset=None):\n    \"\"\"Get all labels linked to a relase. You need to give a MusicBrainz ID.\n\n    *Available includes*: {includes}\"\"\"\n    params = {\"release\": release}\n    return _browse_impl(\"label\", includes, limit, offset, params)\n\n@_docstring_browse(\"place\")\ndef browse_places(area=None, includes=[], limit=None, offset=None):\n    \"\"\"Get all places linked to an area. You need to give a MusicBrainz ID.\n\n    *Available includes*: {includes}\"\"\"\n    params = {\"area\": area}\n    return _browse_impl(\"place\", includes, limit, offset, params)\n\n@_docstring_browse(\"recording\")\ndef browse_recordings(artist=None, release=None, includes=[],\n                      limit=None, offset=None):\n    \"\"\"Get all recordings linked to an artist or a release.\n    You need to give one MusicBrainz ID.\n\n    *Available includes*: {includes}\"\"\"\n    params = {\"artist\": artist,\n              \"release\": release}\n    return _browse_impl(\"recording\", includes, limit, offset, params)\n\n@_docstring_browse(\"release\")\ndef browse_releases(artist=None, track_artist=None, label=None, recording=None,\n                    release_group=None, release_status=[], release_type=[],\n                    includes=[], limit=None, offset=None):\n    \"\"\"Get all releases linked to an artist, a label, a recording\n    or a release group. You need to give one MusicBrainz ID.\n\n    You can also browse by `track_artist`, which gives all releases where some\n    tracks are attributed to that artist, but not the whole release.\n\n    You can filter by :data:`musicbrainz.VALID_RELEASE_TYPES` or\n    :data:`musicbrainz.VALID_RELEASE_STATUSES`.\n\n    *Available includes*: {includes}\"\"\"\n    # track_artist param doesn't work yet\n    params = {\"artist\": artist,\n              \"track_artist\": track_artist,\n              \"label\": label,\n              \"recording\": recording,\n              \"release-group\": release_group}\n    return _browse_impl(\"release\", includes, limit, offset,\n                        params, release_status, release_type)\n\n@_docstring_browse(\"release-group\")\ndef browse_release_groups(artist=None, release=None, release_type=[],\n                          includes=[], limit=None, offset=None):\n    \"\"\"Get all release groups linked to an artist or a release.\n    You need to give one MusicBrainz ID.\n\n    You can filter by :data:`musicbrainz.VALID_RELEASE_TYPES`.\n\n    *Available includes*: {includes}\"\"\"\n    params = {\"artist\": artist,\n              \"release\": release}\n    return _browse_impl(\"release-group\", includes, limit,\n                        offset, params, [], release_type)\n\n@_docstring_browse(\"url\")\ndef browse_urls(resource=None, includes=[], limit=None, offset=None):\n    \"\"\"Get urls by actual URL string.\n    You need to give a URL string as 'resource'\n\n    *Available includes*: {includes}\"\"\"\n    params = {\"resource\": resource}\n    return _browse_impl(\"url\", includes, limit, offset, params)\n\n@_docstring_browse(\"work\")\ndef browse_works(artist=None, includes=[], limit=None, offset=None):\n    \"\"\"Get all works linked to an artist\n\n    *Available includes*: {includes}\"\"\"\n    params = {\"artist\": artist}\n    return _browse_impl(\"work\", includes, limit, offset, params)\n\n# Collections\ndef get_collections():\n    \"\"\"List the collections for the currently :func:`authenticated <auth>` user\n    as a dict with a 'collection-list' key.\"\"\"\n    # Missing <release-list count=\"n\"> the count in the reply\n    return _do_mb_query(\"collection\", '')\n\ndef _do_collection_query(collection, collection_type, limit, offset):\n    params = {}\n    if limit: params[\"limit\"] = limit\n    if offset: params[\"offset\"] = offset\n    return _do_mb_query(\"collection\", \"%s/%s\" % (collection, collection_type), [], params)\n\ndef get_artists_in_collection(collection, limit=None, offset=None):\n    \"\"\"List the artists in a collection.\n    Returns a dict with a 'collection' key, which again has a 'artist-list'.\n\n    See `Browsing`_ for how to use `limit` and `offset`.\n    \"\"\"\n    return _do_collection_query(collection, \"artists\", limit, offset)\n\ndef get_releases_in_collection(collection, limit=None, offset=None):\n    \"\"\"List the releases in a collection.\n    Returns a dict with a 'collection' key, which again has a 'release-list'.\n\n    See `Browsing`_ for how to use `limit` and `offset`.\n    \"\"\"\n    return _do_collection_query(collection, \"releases\", limit, offset)\n\ndef get_events_in_collection(collection, limit=None, offset=None):\n    \"\"\"List the events in a collection.\n    Returns a dict with a 'collection' key, which again has a 'event-list'.\n\n    See `Browsing`_ for how to use `limit` and `offset`.\n    \"\"\"\n    return _do_collection_query(collection, \"events\", limit, offset)\n\ndef get_places_in_collection(collection, limit=None, offset=None):\n    \"\"\"List the places in a collection.\n    Returns a dict with a 'collection' key, which again has a 'place-list'.\n\n    See `Browsing`_ for how to use `limit` and `offset`.\n    \"\"\"\n    return _do_collection_query(collection, \"places\", limit, offset)\n\ndef get_recordings_in_collection(collection, limit=None, offset=None):\n    \"\"\"List the recordings in a collection.\n    Returns a dict with a 'collection' key, which again has a 'recording-list'.\n\n    See `Browsing`_ for how to use `limit` and `offset`.\n    \"\"\"\n    return _do_collection_query(collection, \"recordings\", limit, offset)\n\ndef get_works_in_collection(collection, limit=None, offset=None):\n    \"\"\"List the works in a collection.\n    Returns a dict with a 'collection' key, which again has a 'work-list'.\n\n    See `Browsing`_ for how to use `limit` and `offset`.\n    \"\"\"\n    return _do_collection_query(collection, \"works\", limit, offset)\n\n\n# Submission methods\n\ndef submit_barcodes(release_barcode):\n    \"\"\"Submits a set of {release_id1: barcode, ...}\"\"\"\n    query = mbxml.make_barcode_request(release_barcode)\n    return _do_mb_post(\"release\", query)\n\n\ndef submit_isrcs(recording_isrcs):\n    \"\"\"Submit ISRCs.\n    Submits a set of {recording-id1: [isrc1, ...], ...}\n    or {recording_id1: isrc, ...}.\n    \"\"\"\n    rec2isrcs = dict()\n    for (rec, isrcs) in recording_isrcs.items():\n        rec2isrcs[rec] = isrcs if isinstance(isrcs, list) else [isrcs]\n    query = mbxml.make_isrc_request(rec2isrcs)\n    return _do_mb_post(\"recording\", query)\n\ndef submit_tags(**kwargs):\n    \"\"\"Submit user tags.\n    Takes parameters named e.g. 'artist_tags', 'recording_tags', etc.,\n    and of the form:\n    {entity_id1: [tag1, ...], ...}\n    If you only have one tag for an entity you can use a string instead\n    of a list.\n\n    The user's tags for each entity will be set to that list, adding or\n    removing tags as necessary. Submitting an empty list for an entity\n    will remove all tags for that entity by the user.\n    \"\"\"\n    for k, v in kwargs.items():\n        for id, tags in v.items():\n            kwargs[k][id] = tags if isinstance(tags, list) else [tags]\n\n    query = mbxml.make_tag_request(**kwargs)\n    return _do_mb_post(\"tag\", query)\n\ndef submit_ratings(**kwargs):\n    \"\"\"Submit user ratings.\n    Takes parameters named e.g. 'artist_ratings', 'recording_ratings', etc.,\n    and of the form:\n    {entity_id1: rating, ...}\n\n    Ratings are numbers from 0-100, at intervals of 20 (20 per 'star').\n    Submitting a rating of 0 will remove the user's rating.\n    \"\"\"\n    query = mbxml.make_rating_request(**kwargs)\n    return _do_mb_post(\"rating\", query)\n\ndef add_releases_to_collection(collection, releases=[]):\n    \"\"\"Add releases to a collection.\n    Collection and releases should be identified by their MBIDs\n    \"\"\"\n    # XXX: Maximum URI length of 16kb means we should only allow ~400 releases\n    releaselist = \";\".join(releases)\n    return _do_mb_put(\"collection/%s/releases/%s\" % (collection, releaselist))\n\ndef remove_releases_from_collection(collection, releases=[]):\n    \"\"\"Remove releases from a collection.\n    Collection and releases should be identified by their MBIDs\n    \"\"\"\n    releaselist = \";\".join(releases)\n    return _do_mb_delete(\"collection/%s/releases/%s\" % (collection, releaselist))\n"
  },
  {
    "path": "musicbrainzngs/util.py",
    "content": "# This file is part of the musicbrainzngs library\n# Copyright (C) Alastair Porter, Adrian Sampson, and others\n# This file is distributed under a BSD-2-Clause type license.\n# See the COPYING file for more information.\n\nimport sys\nimport locale\nimport xml.etree.ElementTree as ET\n\nfrom . import compat\n\ndef _unicode(string, encoding=None):\n    \"\"\"Try to decode byte strings to unicode.\n    This can only be a guess, but this might be better than failing.\n    It is safe to use this on numbers or strings that are already unicode.\n    \"\"\"\n    if isinstance(string, compat.unicode):\n        unicode_string = string\n    elif isinstance(string, compat.bytes):\n        # use given encoding, stdin, preferred until something != None is found\n        if encoding is None:\n            encoding = sys.stdin.encoding\n        if encoding is None:\n            encoding = locale.getpreferredencoding()\n        unicode_string = string.decode(encoding, \"ignore\")\n    else:\n        unicode_string = compat.unicode(string)\n    return unicode_string.replace('\\x00', '').strip()\n\ndef bytes_to_elementtree(bytes_or_file):\n\t\"\"\"Given a bytestring or a file-like object that will produce them,\n\tparse and return an ElementTree.\n\t\"\"\"\n\tif isinstance(bytes_or_file, compat.basestring):\n\t\ts = bytes_or_file\n\telse:\n\t\ts = bytes_or_file.read()\n\n\tif compat.is_py3:\n\t\ts = _unicode(s, \"utf-8\")\n\n\tf = compat.StringIO(s)\n\ttree = ET.ElementTree(file=f)\n\treturn tree\n"
  },
  {
    "path": "query.py",
    "content": "import sys\n\nimport musicbrainzngs as m\n\ndef main():\n\tm.set_useragent(\"application\", \"0.01\", \"http://example.com\")\n\tprint m.get_artist_by_id(\"952a4205-023d-4235-897c-6fdb6f58dfaa\", [])\n\t#print m.get_label_by_id(\"aab2e720-bdd2-4565-afc2-460743585f16\")\n\t#print m.get_release_by_id(\"e94757ff-2655-4690-b369-4012beba6114\")\n\t#print m.get_release_group_by_id(\"9377d65d-ffd5-35d6-b64d-43f86ef9188d\")\n\t#print m.get_recording_by_id(\"cb4d4d70-930c-4d1a-a157-776de18be66a\")\n\t#print m.get_work_by_id(\"7e48685c-72dd-3a8b-9274-4777efb2aa75\")\n\n\t#print m.get_releases_by_discid(\"BG.iuI50.qn1DOBAWIk8fUYoeHM-\")\n\t#print m.get_recordings_by_isrc(\"GBAYE9300106\")\n\n\tm.auth(\"\", \"\")\n\t#m.submit_barcodes({\"e94757ff-2655-4690-b369-4012beba6114\": \"9421021463277\"})\n\t#m.submit_tags(recording_tags={\"cb4d4d70-930c-4d1a-a157-776de18be66a\":[\"these\", \"are\", \"my\", \"tags\"]})\n\t#m.submit_tags(artist_tags={\"952a4205-023d-4235-897c-6fdb6f58dfaa\":[\"NZ\", \"twee\"]})\n\n\t#m.submit_ratings(recording_ratings={\"cb4d4d70-930c-4d1a-a157-776de18be66a\":20})\n\nif __name__ == \"__main__\":\n\tmain()\n"
  },
  {
    "path": "setup.py",
    "content": "#!/usr/bin/env python\n\nfrom setuptools import setup\n\nfrom musicbrainzngs import musicbrainz\n\nwith open(\"README.rst\", \"r\") as fh:\n    long_description = fh.read()\n\nsetup(\n    name=\"musicbrainzngs\",\n    version=musicbrainz._version,\n    description=\"Python bindings for the MusicBrainz NGS and\"\n    \" the Cover Art Archive webservices\",\n    long_description=long_description,\n    long_description_content_type=\"text/x-rst\",\n    author=\"Alastair Porter\",\n    author_email=\"alastair@porter.net.nz\",\n    url=\"https://python-musicbrainzngs.readthedocs.io/\",\n    python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',\n    packages=['musicbrainzngs'],\n    license='BSD 2-clause',\n    classifiers=[\n        \"Development Status :: 5 - Production/Stable\",\n        \"License :: OSI Approved :: BSD License\",\n        \"License :: OSI Approved :: ISC License (ISCL)\",\n        \"Intended Audience :: Developers\",\n        \"Operating System :: OS Independent\",\n        \"Programming Language :: Python\",\n        \"Topic :: Database :: Front-Ends\",\n        \"Topic :: Software Development :: Libraries :: Python Modules\"\n    ]\n)\n\n"
  },
  {
    "path": "test/__init__.py",
    "content": ""
  },
  {
    "path": "test/_common.py",
    "content": "\"\"\"Common support for the test cases.\"\"\"\nimport time\n\nimport musicbrainzngs\nfrom musicbrainzngs import compat\nfrom os.path import join\n\ntry:\n    from urllib2 import OpenerDirector\nexcept ImportError:\n    from urllib.request import OpenerDirector\n\nfrom io import BytesIO\n\ntry:\n    import StringIO\nexcept ImportError:\n    import io as StringIO\n\nclass FakeOpener(OpenerDirector):\n    \"\"\" A URL Opener that saves the URL requested and\n    returns a dummy response or raises an exception \"\"\"\n    def __init__(self, response=\"<response/>\", exception=None):\n        self.myurl = None\n        self.headers = None\n        self.response = response\n        self.exception = exception\n        self.handlers = []\n\n    def open(self, request, body=None):\n        self.myurl = request.get_full_url()\n        self.headers = request.header_items()\n        self.request = request\n\n        if self.exception:\n            raise self.exception\n\n        if isinstance(self.response, compat.unicode):\n            return StringIO.StringIO(self.response)\n        else:\n            return BytesIO(self.response)\n\n    def get_url(self):\n        return self.myurl\n\n    def add_handlers_and_return(self, handlers=[]):\n        self.handlers.extend(handlers)\n        return self\n\n\n# Mock timing.\nclass Timecop(object):\n    \"\"\"Mocks the timing system (namely time() and sleep()) for testing.\n    Inspired by the Ruby timecop library.\n    \"\"\"\n    def __init__(self):\n        self.now = time.time()\n\n    def time(self):\n        return self.now\n\n    def sleep(self, amount):\n        self.now += amount\n\n    def install(self):\n        self.orig = {\n            'time': time.time,\n            'sleep': time.sleep,\n        }\n        time.time = self.time\n        time.sleep = self.sleep\n\n    def restore(self):\n        time.time = self.orig['time']\n        time.sleep = self.orig['sleep']\n\ndef open_and_parse_test_data(datadir, filename):\n    \"\"\" Opens an XML file dumped from the MusicBrainz web service and returns\n    the parses it.\n\n    :datadir: The directory containing the file\n    :filename: The filename of the XML file\n    :returns: The parsed representation of the XML files content\n\n    \"\"\"\n    with open(join(datadir, filename), 'rb') as msg:\n        res = musicbrainzngs.mbxml.parse_message(msg)\n    return res\n"
  },
  {
    "path": "test/data/artist/0e43fe9d-c472-4b62-be9e-55f971a023e1-aliases.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><artist type=\"Person\" id=\"0e43fe9d-c472-4b62-be9e-55f971a023e1\"><name>Сергей Сергеевич Прокофьев</name><sort-name>Prokofiev, Sergei Sergeyevich</sort-name><disambiguation>Russian composer</disambiguation><gender>Male</gender><country>RU</country><life-span><begin>1891-04-27</begin><end>1953-03-05</end><ended>true</ended></life-span><alias-list count=\"28\"><alias sort-name=\"Prokofief\">Prokofief</alias><alias sort-name=\"Prokofieff\">Prokofieff</alias><alias sort-name=\"Prokofiev\">Prokofiev</alias><alias sort-name=\"Prokofiev, Sergei\">Prokofiev, Sergei</alias><alias sort-name=\"Prokofiev, Sergej\">Prokofiev, Sergej</alias><alias sort-name=\"Prokovieff\">Prokovieff</alias><alias sort-name=\"S. Prokofiev\">S. Prokofiev</alias><alias sort-name=\"Serge Prokofieff\">Serge Prokofieff</alias><alias sort-name=\"Serge Prokofiev\">Serge Prokofiev</alias><alias sort-name=\"Serge Prokofjev\">Serge Prokofjev</alias><alias sort-name=\"Serge Prokofjew\">Serge Prokofjew</alias><alias sort-name=\"Sergei Prokofief\">Sergei Prokofief</alias><alias sort-name=\"Sergei Prokofieff\">Sergei Prokofieff</alias><alias sort-name=\"Sergei Prokofiev\">Sergei Prokofiev</alias><alias sort-name=\"Sergei Prokofjef\">Sergei Prokofjef</alias><alias primary=\"primary\" sort-name=\"Prokofjev, Sergei\" locale=\"et\">Sergei Prokofjev</alias><alias sort-name=\"Sergei Prokoviev\">Sergei Prokoviev</alias><alias primary=\"primary\" sort-name=\"Prokofiev, Sergei Sergeyevich\" locale=\"en\">Sergei Sergeyevich Prokofiev</alias><alias sort-name=\"Sergej Prokofjev\">Sergej Prokofjev</alias><alias sort-name=\"Sergej Prokofjew\">Sergej Prokofjew</alias><alias sort-name=\"Sergej Sergeevič Prokof'ev\">Sergej Sergeevič Prokof'ev</alias><alias sort-name=\"Sergey Prokofiev\">Sergey Prokofiev</alias><alias sort-name=\"Sergey Sergeyevich Prokofiev\">Sergey Sergeyevich Prokofiev</alias><alias sort-name=\"Serghei Prokofiev\">Serghei Prokofiev</alias><alias sort-name=\"Sergi Prokofiev\">Sergi Prokofiev</alias><alias primary=\"primary\" sort-name=\"Prokofiev, Sergueï\" locale=\"fr\">Sergueï Prokofiev</alias><alias sort-name=\"Прокофьев|Prokofiev\">Прокофьев|Prokofiev</alias><alias sort-name=\"プロコフィエフ\">プロコフィエフ</alias></alias-list></artist></metadata>"
  },
  {
    "path": "test/data/artist/2736bad5-6280-4c8f-92c8-27a5e63bbab2-aliases.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><artist type=\"Group\" id=\"2736bad5-6280-4c8f-92c8-27a5e63bbab2\"><name>Errors</name><sort-name>Errors</sort-name><country>GB</country><life-span><begin>2004</begin></life-span></artist></metadata>"
  },
  {
    "path": "test/data/artist/b3785a55-2cf6-497d-b8e3-cfa21a36f997-artist-rels.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><artist type=\"Group\" type-id=\"e431f5f6-b5d2-343d-8b36-72607fffb74b\" id=\"b3785a55-2cf6-497d-b8e3-cfa21a36f997\"><name>EXO</name><sort-name>EXO</sort-name><disambiguation>South Korean-Chinese boy group</disambiguation><country>KR</country><area id=\"b9f7d640-46e8-313e-b158-ded6d18593b3\"><name>South Korea</name><sort-name>South Korea</sort-name><iso-3166-1-code-list><iso-3166-1-code>KR</iso-3166-1-code></iso-3166-1-code-list></area><begin-area id=\"aa03e165-4c73-4959-91c0-a99f9fa8ecab\"><name>Seoul</name><sort-name>Seoul</sort-name><iso-3166-2-code-list><iso-3166-2-code>KR-11</iso-3166-2-code></iso-3166-2-code-list></begin-area><life-span><begin>2011-12-23</begin></life-span><relation-list target-type=\"artist\"><relation type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\" type=\"member of band\"><target>143472cb-de19-4da3-b8ac-8a7d01b6638d</target><direction>backward</direction><begin>2011</begin><end>2015</end><ended>true</ended><attribute-list><attribute>original</attribute></attribute-list><artist id=\"143472cb-de19-4da3-b8ac-8a7d01b6638d\"><name>黄子韬</name><sort-name>Huang Zitao</sort-name></artist><target-credit>TAO</target-credit></relation><relation type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\" type=\"member of band\"><target>1fed07c6-adf1-4668-b34b-434ae9741763</target><direction>backward</direction><begin>2011</begin><attribute-list><attribute>lead vocals</attribute><attribute>original</attribute></attribute-list><artist id=\"1fed07c6-adf1-4668-b34b-434ae9741763\"><name>D.O.</name><sort-name>D.O.</sort-name><disambiguation>South Korean singer, member of EXO</disambiguation></artist><target-credit>D.O.</target-credit></relation><relation type-id=\"7802f96b-d995-4ce9-8f70-6366faad758e\" type=\"subgroup\"><target>254658f7-f4eb-4c62-bafb-28f57707517b</target><direction>backward</direction><begin>2012</begin><artist id=\"254658f7-f4eb-4c62-bafb-28f57707517b\"><name>EXO-K</name><sort-name>EXO-K</sort-name></artist></relation><relation type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\" type=\"member of band\"><target>2e675c4a-396c-49e8-96b7-a8a72361df84</target><direction>backward</direction><begin>2011</begin><end>2014</end><ended>true</ended><attribute-list><attribute>original</attribute></attribute-list><artist id=\"2e675c4a-396c-49e8-96b7-a8a72361df84\"><name>吴亦凡</name><sort-name>Wu, Yi Fan</sort-name></artist><target-credit>KRIS</target-credit></relation><relation type-id=\"7802f96b-d995-4ce9-8f70-6366faad758e\" type=\"subgroup\"><target>31e909fa-cdf6-4b7d-a7d3-8b928de4e0ba</target><direction>backward</direction><begin>2012</begin><artist id=\"31e909fa-cdf6-4b7d-a7d3-8b928de4e0ba\"><name>EXO-M</name><sort-name>EXO-M</sort-name></artist></relation><relation type=\"member of band\" type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\"><target>36af49c3-7edf-44bf-b040-cf5d9b21ebe7</target><direction>backward</direction><begin>2011</begin><attribute-list><attribute>original</attribute></attribute-list><artist id=\"36af49c3-7edf-44bf-b040-cf5d9b21ebe7\"><name>시우민</name><sort-name>Xiumin</sort-name></artist><target-credit>XIUMIN</target-credit></relation><relation type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\" type=\"member of band\"><target>439c9247-9291-47a8-8282-7f80bc3f369d</target><direction>backward</direction><begin>2011</begin><attribute-list><attribute>lead vocals</attribute><attribute>original</attribute></attribute-list><artist id=\"439c9247-9291-47a8-8282-7f80bc3f369d\"><name>첸</name><sort-name>Chen</sort-name></artist><target-credit>CHEN</target-credit></relation><relation type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\" type=\"member of band\"><target>53be8ba6-8be8-4e3b-8b20-f83c08ecf124</target><direction>backward</direction><begin>2011-12</begin><end>2014-10-10</end><ended>true</ended><attribute-list><attribute>original</attribute></attribute-list><artist id=\"53be8ba6-8be8-4e3b-8b20-f83c08ecf124\"><name>鹿晗</name><sort-name>Lu Han</sort-name></artist><target-credit>LUHAN</target-credit></relation><relation type=\"member of band\" type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\"><target>5d7686b2-90d5-44c6-ab70-693e98506fb6</target><direction>backward</direction><begin>2011</begin><attribute-list><attribute>original</attribute></attribute-list><artist id=\"5d7686b2-90d5-44c6-ab70-693e98506fb6\"><name>LAY</name><sort-name>LAY</sort-name><disambiguation>EXO</disambiguation></artist></relation><relation type=\"member of band\" type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\"><target>6afff86d-fc4a-4446-a41e-f88e1322a5be</target><direction>backward</direction><begin>2011</begin><attribute-list><attribute>original</attribute></attribute-list><artist id=\"6afff86d-fc4a-4446-a41e-f88e1322a5be\"><name>카이</name><sort-name>Kai</sort-name><disambiguation>EXO</disambiguation></artist><target-credit>KAI</target-credit></relation><relation type=\"member of band\" type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\"><target>7100af1a-1224-4636-83ad-7f7fcf0973d7</target><direction>backward</direction><begin>2011</begin><attribute-list><attribute>original</attribute></attribute-list><artist id=\"7100af1a-1224-4636-83ad-7f7fcf0973d7\"><name>찬열</name><sort-name>Chanyeol</sort-name></artist><target-credit>CHANYEOL</target-credit></relation><relation type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\" type=\"member of band\"><target>7593e0e2-fc1c-4855-a645-731c7504e16b</target><direction>backward</direction><begin>2011</begin><attribute-list><attribute>original</attribute></attribute-list><artist id=\"7593e0e2-fc1c-4855-a645-731c7504e16b\"><name>백현</name><sort-name>Baekhyun</sort-name></artist><target-credit>BAEKHYUN</target-credit></relation><relation type=\"member of band\" type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\"><target>9892db11-4c1b-4029-bed5-6aae508e7fce</target><direction>backward</direction><begin>2011</begin><attribute-list><attribute>original</attribute></attribute-list><artist id=\"9892db11-4c1b-4029-bed5-6aae508e7fce\"><name>세훈</name><sort-name>Sehun</sort-name></artist><target-credit>SEHUN</target-credit></relation><relation type=\"member of band\" type-id=\"5be4c609-9afa-4ea0-910b-12ffb71e3821\"><target>9aba1d1e-c460-400d-88a7-35f08721d311</target><direction>backward</direction><begin>2011</begin><attribute-list><attribute>original</attribute></attribute-list><artist id=\"9aba1d1e-c460-400d-88a7-35f08721d311\"><name>수호</name><sort-name>Suho</sort-name></artist><target-credit>SUHO</target-credit></relation><relation type-id=\"7802f96b-d995-4ce9-8f70-6366faad758e\" type=\"subgroup\"><target>db095c11-8b25-41b5-adda-d850d9001dcd</target><direction>backward</direction><begin>2016-10</begin><artist id=\"db095c11-8b25-41b5-adda-d850d9001dcd\"><name>EXO-CBX</name><sort-name>EXO-CBX</sort-name></artist></relation></relation-list></artist></metadata>"
  },
  {
    "path": "test/data/collection/0b15c97c-8eb8-4b4f-81c3-0eb24266a2ac-releases.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><collection entity-type=\"release\" type=\"Release\" id=\"0b15c97c-8eb8-4b4f-81c3-0eb24266a2ac\"><name>My Collection</name><editor>JonnyJD</editor><release-list count=\"400\"><release id=\"256b1535-83d8-4245-933b-7d1ed683cbc3\"><title>Entities</title><status>Official</status><quality>normal</quality><packaging>Cardboard/Paper Sleeve</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1992-10</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1992-10</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>4013859210366</barcode></release><release id=\"2df7deb7-604e-4861-8e42-79f570d4a22d\"><title>German Mystic Sound Sampler, Volume III: Indie-Classics, Volume IV</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1992-11-06</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1992-11-06</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>0718759100529</barcode></release><release id=\"3f831ec6-e8bb-35fa-b6a0-134dabf30b3f\"><title>Boys Don’t Cry</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1986-04-29</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1986-04-29</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>042281501128</barcode></release><release id=\"5aa039be-d3b7-42e6-b805-d066867cb9dd\"><title>Zillo Romantic Sound Sampler: Indie Classics, Volume III</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1991</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1991</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>718759100222</barcode></release><release id=\"63e0d752-5d05-4b16-9b11-02252ce7c599\"><title>Bram Stoker's Dracula</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1992-11-04</date><country>US</country><release-event-list count=\"1\"><release-event><date>1992-11-04</date><area id=\"489ce91b-6658-3307-9877-795b68554c98\"><name>United States</name><sort-name>United States</sort-name><iso-3166-1-code-list><iso-3166-1-code>US</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>074645316529</barcode></release><release id=\"7bf735e8-d0aa-35b7-8e05-e1487ed17976\"><title>Black Sabbath</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1970</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1970</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode /></release><release id=\"91481687-d5f4-4d93-ab7a-f25204dc91be\"><title>Follow the Blind</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1989</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1989</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list></release><release id=\"9c3da2f7-f11b-4d9e-a333-ce53038c267c\"><title>Live! Exile on Valletta Street</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1991-09-13</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1991-09-13</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>731451117527</barcode></release><release id=\"a467cfea-68fb-4003-85a3-07ba5d19e0c7\"><title>German Mystic Sound Sampler, Volume I: Indie-Classics, Volume I</title><status>Promotion</status><quality>normal</quality><text-representation><language>mul</language><script>Latn</script></text-representation><date>1991-05-17</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1991-05-17</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>4012170902028</barcode></release><release id=\"a4e06d7f-d0d9-429b-bde0-6ff63ddaa245\"><title>Fixed</title><status>Official</status><quality>high</quality><packaging>Digipak</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1992-12-07</date><country>US</country><release-event-list count=\"1\"><release-event><date>1992-12-07</date><area id=\"489ce91b-6658-3307-9877-795b68554c98\"><name>United States</name><sort-name>United States</sort-name><iso-3166-1-code-list><iso-3166-1-code>US</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>606949609320</barcode></release><release id=\"b57c17cd-ba06-4331-ba2e-6b7360925208\"><title>Gothic Rock</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1992</date><country>GB</country><release-event-list count=\"1\"><release-event><date>1992</date><area id=\"8a754a16-0027-3a29-b6d7-2b40ea0481ed\"><name>United Kingdom</name><sort-name>United Kingdom</sort-name><iso-3166-1-code-list><iso-3166-1-code>GB</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>5013145203828</barcode></release><release id=\"b8337232-1233-4666-b048-c81aa853d4ce\"><title>Burning From the Inside</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1988</date><country>GB</country><release-event-list count=\"1\"><release-event><date>1988</date><area id=\"8a754a16-0027-3a29-b6d7-2b40ea0481ed\"><name>United Kingdom</name><sort-name>United Kingdom</sort-name><iso-3166-1-code-list><iso-3166-1-code>GB</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>5012093004525</barcode></release><release id=\"bce8246c-5ad0-4578-8a33-f15e49574760\"><title>High</title><status>Official</status><quality>normal</quality><packaging>Digipak</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1992-02-27</date><country>US</country><release-event-list count=\"1\"><release-event><date>1992-02-27</date><area id=\"489ce91b-6658-3307-9877-795b68554c98\"><name>United States</name><sort-name>United States</sort-name><iso-3166-1-code-list><iso-3166-1-code>US</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>075596643726</barcode></release><release id=\"c619795b-7426-4bb9-9957-d53c5ab1814b\"><title>Methods of Silence</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1989-09-12</date><country>US</country><release-event-list count=\"1\"><release-event><date>1989-09-12</date><area id=\"489ce91b-6658-3307-9877-795b68554c98\"><name>United States</name><sort-name>United States</sort-name><iso-3166-1-code-list><iso-3166-1-code>US</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>075678200229</barcode></release><release id=\"cc3763b2-55e0-4718-a245-bf410020ef12\"><title>Bouquet of Dreams</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1991-08-19</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1991-08-19</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>0718751108523</barcode></release><release id=\"cd59608e-d847-4391-a813-969ae10101e7\"><title>German Mystic Sound Sampler, Volume II: Indie-Classics, Volume II</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1991</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1991</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>0718759100123</barcode></release><release id=\"d497b726-c646-4302-93e7-22ce52c3d49b\"><title>Haus der Lüge</title><status>Official</status><quality>normal</quality><text-representation><language>deu</language><script>Latn</script></text-representation><date>1989</date><country>US</country><release-event-list count=\"1\"><release-event><date>1989</date><area id=\"489ce91b-6658-3307-9877-795b68554c98\"><name>United States</name><sort-name>United States</sort-name><iso-3166-1-code-list><iso-3166-1-code>US</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>023138007123</barcode></release><release id=\"dc4d63d7-af36-44e6-bab1-49362d389700\"><title>Front by Front</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1992</date><country>US</country><release-event-list count=\"1\"><release-event><date>1992</date><area id=\"489ce91b-6658-3307-9877-795b68554c98\"><name>United States</name><sort-name>United States</sort-name><iso-3166-1-code-list><iso-3166-1-code>US</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>074645240626</barcode></release><release id=\"e0cac4b8-ea17-4c0e-83c0-5934b42e9b32\"><title>I: Lieder der Arbeiterklasse &amp; Lieder aus dem spanischen Bürgerkrieg</title><status>Official</status><quality>normal</quality><text-representation><language>deu</language><script>Latn</script></text-representation><date>1989-05-02</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1989-05-02</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>4007198839876</barcode></release><release id=\"e4f8ec20-6cd3-4f46-a773-b6272b6051fe\"><title>Monarchie und Alltag</title><status>Official</status><quality>normal</quality><text-representation><language>deu</language><script>Latn</script></text-representation><date>1980</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1980</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list></release><release id=\"e8086bec-de5d-3ca3-bfae-c48a1dc672f2\"><title>Methods of Silence</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1989-06-05</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1989-06-05</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>042283961326</barcode></release><release id=\"ed2a7e38-1125-4b19-be16-2ddccff0cdb0\"><title>Basically Sad</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1986</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1986</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>042283508224</barcode></release><release id=\"eed4a1ee-7043-4013-916c-81821a48dd4f\"><title>Electro Revenge</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1991</date><country>SE</country><release-event-list count=\"1\"><release-event><date>1991</date><area id=\"23d10872-f5ae-3f0c-bf55-332788a16ecb\"><name>Sweden</name><sort-name>Sweden</sort-name><iso-3166-1-code-list><iso-3166-1-code>SE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>7391946035014</barcode></release><release id=\"f49e85de-5cda-4981-ba59-49b27e628e6f\"><title>Gold und Liebe</title><status>Official</status><quality>normal</quality><text-representation><language>deu</language><script>Latn</script></text-representation><date>1981-11</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1981-11</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list></release><release id=\"fec34d45-457a-4d21-81c9-21e48bbe3511\"><title>Flags of Revolution</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1990</date><country>DE</country><release-event-list count=\"1\"><release-event><date>1990</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list></release></release-list></collection></metadata>"
  },
  {
    "path": "test/data/collection/20562e36-c7cc-44fb-96b4-486d51a1174b-events.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><collection entity-type=\"event\" id=\"20562e36-c7cc-44fb-96b4-486d51a1174b\" type=\"Event\"><name>event collection</name><editor>alastairp</editor><event-list count=\"1\"><event id=\"fe4bce99-6e9b-4050-9681-eac48cdf3199\"><name>T on the Fringe 2006</name><life-span><begin>2006-08-04</begin><end>2006-08-30</end></life-span></event></event-list></collection></metadata>"
  },
  {
    "path": "test/data/collection/2326c2e8-be4b-4300-acc6-dbd0adf5645b-works.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><collection id=\"2326c2e8-be4b-4300-acc6-dbd0adf5645b\" type=\"Work\" entity-type=\"work\"><name>work collection</name><editor>alastairp</editor><work-list count=\"1\"><work id=\"541f07e2-389d-4a0c-8a97-896b6752dd35\"><title>Maggot Brain</title></work></work-list></collection></metadata>"
  },
  {
    "path": "test/data/collection/29611d8b-b3ad-4ffb-acb5-27f77342a5b0-artists.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><collection entity-type=\"artist\" type=\"Artist\" id=\"29611d8b-b3ad-4ffb-acb5-27f77342a5b0\"><name>artist collection</name><editor>alastairp</editor><artist-list count=\"1\"><artist id=\"0383dadf-2a4e-4d10-a46a-e9e041da8eb3\"><name>Queen</name><sort-name>Queen</sort-name><disambiguation>UK rock group</disambiguation><life-span><begin>1970-06-27</begin></life-span></artist></artist-list></collection></metadata>"
  },
  {
    "path": "test/data/collection/855b134e-9a3b-4717-8df8-8c4838d89924-places.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><collection entity-type=\"place\" type=\"Place\" id=\"855b134e-9a3b-4717-8df8-8c4838d89924\"><name>place collection</name><editor>alastairp</editor><place-list count=\"1\"><place id=\"f75dd832-8cac-4068-8432-de0472866d33\"><name>San Francisco Bath House</name><disambiguation>aka 'San Fran'</disambiguation><address>171 Cuba Street, Wellington, New Zealand</address></place></place-list></collection></metadata>"
  },
  {
    "path": "test/data/collection/a91320b2-fd2f-4a93-9e4e-603d16d514b6-recordings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><collection type=\"Recording\" id=\"a91320b2-fd2f-4a93-9e4e-603d16d514b6\" entity-type=\"recording\"><name>recording collection</name><editor>alastairp</editor><recording-list count=\"1\"><recording id=\"be462d72-b71b-4cb0-8f65-3434f99822a7\"><title>Maggot Brain</title><length>1201000</length></recording></recording-list></collection></metadata>"
  },
  {
    "path": "test/data/discid/f7agNZK1HMQ2WUWq9bwDymw9aHA-.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><disc id=\"f7agNZK1HMQ2WUWq9bwDymw9aHA-\"><sectors>217245</sectors><offset-list count=\"13\"><offset position=\"1\">17990</offset><offset position=\"2\">26452</offset><offset position=\"3\">38762</offset><offset position=\"4\">55052</offset><offset position=\"5\">78990</offset><offset position=\"6\">96705</offset><offset position=\"7\">109755</offset><offset position=\"8\">126972</offset><offset position=\"9\">137342</offset><offset position=\"10\">156600</offset><offset position=\"11\">171900</offset><offset position=\"12\">188400</offset><offset position=\"13\">203475</offset></offset-list><release-list count=\"2\"><release id=\"55a5a355-042f-39d0-9ba0-0de8090c84b9\"><title>Geräusch</title><status>Official</status><quality>normal</quality><text-representation><language>deu</language><script>Latn</script></text-representation><date>2003</date><country>AT</country><release-event-list count=\"1\"><release-event><date>2003</date><area id=\"caac77d1-a5c8-3e6e-8e27-90b44dcc1446\"><name>Austria</name><sort-name>Austria</sort-name><iso-3166-1-code-list><iso-3166-1-code>AT</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>0602498655023</barcode><asin>B000UH8BIG</asin><cover-art-archive><artwork>false</artwork><count>0</count><front>false</front><back>false</back></cover-art-archive><medium-list count=\"2\"><medium><title>Schwarzes Geräusch</title><position>1</position><format>CD</format><disc-list count=\"1\"><disc id=\"f7agNZK1HMQ2WUWq9bwDymw9aHA-\"><sectors>217245</sectors><offset-list count=\"13\"><offset position=\"1\">17990</offset><offset position=\"2\">26452</offset><offset position=\"3\">38762</offset><offset position=\"4\">55052</offset><offset position=\"5\">78990</offset><offset position=\"6\">96705</offset><offset position=\"7\">109755</offset><offset position=\"8\">126972</offset><offset position=\"9\">137342</offset><offset position=\"10\">156600</offset><offset position=\"11\">171900</offset><offset position=\"12\">188400</offset><offset position=\"13\">203475</offset></offset-list></disc></disc-list><track-list count=\"13\" /></medium><medium><title>Rotes Geräusch</title><position>2</position><format>CD</format><disc-list count=\"1\"><disc id=\"EMM4xgOXn40XXFgxCd2hf84lc1Q-\"><sectors>215300</sectors><offset-list count=\"13\"><offset position=\"1\">150</offset><offset position=\"2\">18245</offset><offset position=\"3\">34376</offset><offset position=\"4\">45773</offset><offset position=\"5\">62903</offset><offset position=\"6\">85481</offset><offset position=\"7\">102576</offset><offset position=\"8\">120412</offset><offset position=\"9\">139696</offset><offset position=\"10\">156229</offset><offset position=\"11\">174924</offset><offset position=\"12\">184535</offset><offset position=\"13\">192889</offset></offset-list></disc></disc-list><track-list count=\"13\" /></medium></medium-list></release><release id=\"e6f8f4d8-851c-4f6f-b611-71fa97f9dd5c\"><title>Geräusch</title><status>Official</status><quality>normal</quality><packaging>Other</packaging><text-representation><language>deu</language><script>Latn</script></text-representation><date>2003-09-29</date><country>DE</country><release-event-list count=\"1\"><release-event><date>2003-09-29</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>4019593899829</barcode><asin>B0000AN32D</asin><cover-art-archive><artwork>true</artwork><count>3</count><front>true</front><back>true</back></cover-art-archive><medium-list count=\"2\"><medium><title>Schwarzes Geräusch</title><position>1</position><format>CD</format><disc-list count=\"1\"><disc id=\"f7agNZK1HMQ2WUWq9bwDymw9aHA-\"><sectors>217245</sectors><offset-list count=\"13\"><offset position=\"1\">17990</offset><offset position=\"2\">26452</offset><offset position=\"3\">38762</offset><offset position=\"4\">55052</offset><offset position=\"5\">78990</offset><offset position=\"6\">96705</offset><offset position=\"7\">109755</offset><offset position=\"8\">126972</offset><offset position=\"9\">137342</offset><offset position=\"10\">156600</offset><offset position=\"11\">171900</offset><offset position=\"12\">188400</offset><offset position=\"13\">203475</offset></offset-list></disc></disc-list><track-list count=\"13\" /></medium><medium><title>Rotes Geräusch</title><position>2</position><format>CD</format><disc-list count=\"2\"><disc id=\"EMM4xgOXn40XXFgxCd2hf84lc1Q-\"><sectors>215300</sectors><offset-list count=\"13\"><offset position=\"1\">150</offset><offset position=\"2\">18245</offset><offset position=\"3\">34376</offset><offset position=\"4\">45773</offset><offset position=\"5\">62903</offset><offset position=\"6\">85481</offset><offset position=\"7\">102576</offset><offset position=\"8\">120412</offset><offset position=\"9\">139696</offset><offset position=\"10\">156229</offset><offset position=\"11\">174924</offset><offset position=\"12\">184535</offset><offset position=\"13\">192889</offset></offset-list></disc><disc id=\"j_3_T0_IpgzY05fJpD2cQkg2gaQ-\"><sectors>217140</sectors><offset-list count=\"13\"><offset position=\"1\">150</offset><offset position=\"2\">18398</offset><offset position=\"3\">34682</offset><offset position=\"4\">46232</offset><offset position=\"5\">63515</offset><offset position=\"6\">86246</offset><offset position=\"7\">103494</offset><offset position=\"8\">121483</offset><offset position=\"9\">140920</offset><offset position=\"10\">157606</offset><offset position=\"11\">176455</offset><offset position=\"12\">186219</offset><offset position=\"13\">194727</offset></offset-list></disc></disc-list><track-list count=\"13\" /></medium></medium-list></release></release-list></disc></metadata>"
  },
  {
    "path": "test/data/discid/xp5tz6rE4OHrBafj0bLfDRMGK48-.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><disc id=\"xp5tz6rE4OHrBafj0bLfDRMGK48-\"><sectors>212075</sectors><offset-list count=\"8\"><offset position=\"1\">182</offset><offset position=\"2\">33322</offset><offset position=\"3\">52597</offset><offset position=\"4\">73510</offset><offset position=\"5\">98882</offset><offset position=\"6\">136180</offset><offset position=\"7\">169185</offset><offset position=\"8\">187490</offset></offset-list><release-list count=\"3\"><release id=\"68c27a13-97a9-3614-b482-5e6e780bd230\"><title>Tales of Ephidrina</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>1993-07-05</date><country>GB</country><release-event-list count=\"1\"><release-event><date>1993-07-05</date><area id=\"8a754a16-0027-3a29-b6d7-2b40ea0481ed\"><name>United Kingdom</name><sort-name>United Kingdom</sort-name><iso-3166-1-code-list><iso-3166-1-code>GB</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>077778823827</barcode><asin>B000026GLQ</asin><cover-art-archive><artwork>false</artwork><count>0</count><front>false</front><back>false</back></cover-art-archive><medium-list count=\"1\"><medium><position>1</position><format>CD</format><disc-list count=\"4\"><disc id=\"5sQ7UZcKjJaCH43UKtt_61W7avw-\"><sectors>212115</sectors><offset-list count=\"8\"><offset position=\"1\">222</offset><offset position=\"2\">33362</offset><offset position=\"3\">52637</offset><offset position=\"4\">73550</offset><offset position=\"5\">98922</offset><offset position=\"6\">136220</offset><offset position=\"7\">169225</offset><offset position=\"8\">187530</offset></offset-list></disc><disc id=\"DNlrvGROpc28aJtprTzehV.XE7o-\"><sectors>212043</sectors><offset-list count=\"8\"><offset position=\"1\">150</offset><offset position=\"2\">33290</offset><offset position=\"3\">52565</offset><offset position=\"4\">73478</offset><offset position=\"5\">98850</offset><offset position=\"6\">136148</offset><offset position=\"7\">169153</offset><offset position=\"8\">187458</offset></offset-list></disc><disc id=\"eXuIBrzsHYjtlF_OQgrFxUCg0NA-\"><sectors>211912</sectors><offset-list count=\"8\"><offset position=\"1\">150</offset><offset position=\"2\">33150</offset><offset position=\"3\">52428</offset><offset position=\"4\">73340</offset><offset position=\"5\">98715</offset><offset position=\"6\">136015</offset><offset position=\"7\">169015</offset><offset position=\"8\">187323</offset></offset-list></disc><disc id=\"xp5tz6rE4OHrBafj0bLfDRMGK48-\"><sectors>212075</sectors><offset-list count=\"8\"><offset position=\"1\">182</offset><offset position=\"2\">33322</offset><offset position=\"3\">52597</offset><offset position=\"4\">73510</offset><offset position=\"5\">98882</offset><offset position=\"6\">136180</offset><offset position=\"7\">169185</offset><offset position=\"8\">187490</offset></offset-list></disc></disc-list><track-list count=\"8\" /></medium></medium-list></release><release id=\"6bed9eb1-c7ff-4ddb-ac5d-171e6b335263\"><title>Tales of Ephidrina</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1993</date><country>CA</country><release-event-list count=\"1\"><release-event><date>1993</date><area id=\"71bbafaa-e825-3e15-8ca9-017dcad1748b\"><name>Canada</name><sort-name>Canada</sort-name><iso-3166-1-code-list><iso-3166-1-code>CA</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><cover-art-archive><artwork>false</artwork><count>0</count><front>false</front><back>false</back></cover-art-archive><medium-list count=\"1\"><medium><position>1</position><format>CD</format><disc-list count=\"4\"><disc id=\"5sQ7UZcKjJaCH43UKtt_61W7avw-\"><sectors>212115</sectors><offset-list count=\"8\"><offset position=\"1\">222</offset><offset position=\"2\">33362</offset><offset position=\"3\">52637</offset><offset position=\"4\">73550</offset><offset position=\"5\">98922</offset><offset position=\"6\">136220</offset><offset position=\"7\">169225</offset><offset position=\"8\">187530</offset></offset-list></disc><disc id=\"DNlrvGROpc28aJtprTzehV.XE7o-\"><sectors>212043</sectors><offset-list count=\"8\"><offset position=\"1\">150</offset><offset position=\"2\">33290</offset><offset position=\"3\">52565</offset><offset position=\"4\">73478</offset><offset position=\"5\">98850</offset><offset position=\"6\">136148</offset><offset position=\"7\">169153</offset><offset position=\"8\">187458</offset></offset-list></disc><disc id=\"eXuIBrzsHYjtlF_OQgrFxUCg0NA-\"><sectors>211912</sectors><offset-list count=\"8\"><offset position=\"1\">150</offset><offset position=\"2\">33150</offset><offset position=\"3\">52428</offset><offset position=\"4\">73340</offset><offset position=\"5\">98715</offset><offset position=\"6\">136015</offset><offset position=\"7\">169015</offset><offset position=\"8\">187323</offset></offset-list></disc><disc id=\"xp5tz6rE4OHrBafj0bLfDRMGK48-\"><sectors>212075</sectors><offset-list count=\"8\"><offset position=\"1\">182</offset><offset position=\"2\">33322</offset><offset position=\"3\">52597</offset><offset position=\"4\">73510</offset><offset position=\"5\">98882</offset><offset position=\"6\">136180</offset><offset position=\"7\">169185</offset><offset position=\"8\">187490</offset></offset-list></disc></disc-list><track-list count=\"8\" /></medium></medium-list></release><release id=\"aad0161e-83f7-3468-9816-26528ca3898d\"><title>Tales of Ephidrina</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1993-07-30</date><country>US</country><release-event-list count=\"1\"><release-event><date>1993-07-30</date><area id=\"489ce91b-6658-3307-9877-795b68554c98\"><name>United States</name><sort-name>United States</sort-name><iso-3166-1-code-list><iso-3166-1-code>US</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>017046610124</barcode><asin>B000003RVA</asin><cover-art-archive><artwork>false</artwork><count>0</count><front>false</front><back>false</back></cover-art-archive><medium-list count=\"1\"><medium><position>1</position><format>CD</format><disc-list count=\"4\"><disc id=\"5sQ7UZcKjJaCH43UKtt_61W7avw-\"><sectors>212115</sectors><offset-list count=\"8\"><offset position=\"1\">222</offset><offset position=\"2\">33362</offset><offset position=\"3\">52637</offset><offset position=\"4\">73550</offset><offset position=\"5\">98922</offset><offset position=\"6\">136220</offset><offset position=\"7\">169225</offset><offset position=\"8\">187530</offset></offset-list></disc><disc id=\"DNlrvGROpc28aJtprTzehV.XE7o-\"><sectors>212043</sectors><offset-list count=\"8\"><offset position=\"1\">150</offset><offset position=\"2\">33290</offset><offset position=\"3\">52565</offset><offset position=\"4\">73478</offset><offset position=\"5\">98850</offset><offset position=\"6\">136148</offset><offset position=\"7\">169153</offset><offset position=\"8\">187458</offset></offset-list></disc><disc id=\"eXuIBrzsHYjtlF_OQgrFxUCg0NA-\"><sectors>211912</sectors><offset-list count=\"8\"><offset position=\"1\">150</offset><offset position=\"2\">33150</offset><offset position=\"3\">52428</offset><offset position=\"4\">73340</offset><offset position=\"5\">98715</offset><offset position=\"6\">136015</offset><offset position=\"7\">169015</offset><offset position=\"8\">187323</offset></offset-list></disc><disc id=\"xp5tz6rE4OHrBafj0bLfDRMGK48-\"><sectors>212075</sectors><offset-list count=\"8\"><offset position=\"1\">182</offset><offset position=\"2\">33322</offset><offset position=\"3\">52597</offset><offset position=\"4\">73510</offset><offset position=\"5\">98882</offset><offset position=\"6\">136180</offset><offset position=\"7\">169185</offset><offset position=\"8\">187490</offset></offset-list></disc></disc-list><track-list count=\"8\" /></medium></medium-list></release></release-list></disc></metadata>"
  },
  {
    "path": "test/data/event/770fb0b4-0ad8-4774-9275-099b66627355-place-rels.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><event type=\"Concert\" id=\"770fb0b4-0ad8-4774-9275-099b66627355\"><name>1987-06-07: Rock am Ring, Nürburgring, Nürburg, Germany</name><life-span><begin>1987-06-07</begin><end>1987-06-07</end></life-span><relation-list target-type=\"place\"><relation type-id=\"e2c6f697-07dc-38b1-be0b-83d740165532\" type=\"held at\"><target>7643f13a-dcda-4db4-8196-3ffcc1b99ab7</target><place id=\"7643f13a-dcda-4db4-8196-3ffcc1b99ab7\"><name>Nürburgring</name><address>Nürburgring Boulevard 1, 53520 Nürburg</address><coordinates><latitude>50.33556</latitude><longitude>6.9475</longitude></coordinates></place></relation></relation-list></event></metadata>\n"
  },
  {
    "path": "test/data/event/e921686d-ba86-4122-bc3b-777aec90d231-tags-artist-rels.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><event id=\"e921686d-ba86-4122-bc3b-777aec90d231\" type=\"Concert\"><name>Skunk D.F. @ Sala Arena, Madrid (Gira 20 aniversario)</name><life-span><begin>2014-12-14</begin><end>2014-12-14</end></life-span><time>20:00</time><setlist>* [64de7281-02d7-42a4-a099-9e2927ffca8b|En Noches como Esta]\r* [ddcbce3d-721a-4485-8320-e1da5a73cbf3|Cirkus]\r* [24ebb1eb-a865-4c5c-b790-17bdf17893c7|Decreto Ley]\r* [025608b0-5013-4746-ab77-2919c4aa8285|Estrella de la Muerte]\r* [475cbb7f-5a0d-4220-8579-476a03119989|Musa]\r* [ffbf45b0-04a1-4a2c-94b5-020e3db1109c|Supernova]\r* [38ce45f2-baa3-3a83-8bbe-6691f92120b6|En 5 minutos]\r* [3241a14b-6ece-4261-b309-a77695cca246|Muerte y destrucción]\r* [1f5fd9f1-76d1-438c-a482-83b62ac0c544|El año del Dragón]\r* [8e5c5177-a43c-4562-afe5-e8a40be4856b|Lucha Interior]\r* [fb1809bb-0a70-4e39-9276-672deb6a5a31|Mantis]\r* [13f6b3ef-77b2-453b-85f7-4bdb13a64fe7|Loto]\r* [e40c39cb-ef2e-468d-9e49-7c380029f30a|El Encanto de la Imperfección]\r* [2728c7ae-0922-36ed-9b92-707d7aa31f0f|El Cuarto Oscuro]\r* [f5c8b0fe-9262-4181-b208-2060a000b840|Última Oportunidad]\r* [c44747cc-eedc-42b0-ae0b-d588965e900f|Himen]\r* [b104089e-b299-4aa6-a5bc-5d5d0f8e85de|La vida es ahora (acústico)]\r* [9c347f02-0494-4f74-a339-078310ce70b5|Crisol]\r* [798b281a-687b-478b-a093-2e0406e90551|Anestesia]\r* [a941424e-728a-4229-ab0c-4e36ceb3b04c|Alicia]\r* [7e901163-6f72-463a-b6f6-215508f880be|Algo Grande]\r* [9d9c9ad6-47b2-4478-beca-a9af9ff80de2|Carpe Diem]</setlist><relation-list target-type=\"artist\"><relation type-id=\"936c7c95-3156-3889-a062-8a0cd57f8946\" type=\"main performer\"><target>f9113809-1403-4575-8c20-61bfa96b48db</target><direction>backward</direction><artist id=\"f9113809-1403-4575-8c20-61bfa96b48db\"><name>Skunk D.F.</name><sort-name>Skunk D.F.</sort-name></artist></relation></relation-list><tag-list><tag count=\"1\"><name>redundant-title</name></tag></tag-list></event></metadata>"
  },
  {
    "path": "test/data/instrument/01ba56a2-4306-493d-8088-c7e9b671c74e-instrument-rels.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><instrument id=\"01ba56a2-4306-493d-8088-c7e9b671c74e\" type=\"String instrument\"><name>kemenche</name><description>Various types of stringed bowed musical instruments having their origin in the Eastern Mediterranean</description><relation-list target-type=\"instrument\"><relation type-id=\"12678b88-1adb-3536-890e-9b39b9a14b2d\" type=\"children\"><target>04a21d03-535a-4ace-9098-12013867b8e5</target><direction>backward</direction><instrument id=\"04a21d03-535a-4ace-9098-12013867b8e5\"><name>fiddle</name></instrument></relation><relation type=\"children\" type-id=\"12678b88-1adb-3536-890e-9b39b9a14b2d\"><target>ad09a4ed-d1b6-47c3-ac85-acb531244a4d</target><instrument id=\"ad09a4ed-d1b6-47c3-ac85-acb531244a4d\"><name>kemençe of the Black Sea</name><description>Turkish box-shaped kemenche, mainly used for folk music.</description></instrument></relation><relation type=\"children\" type-id=\"12678b88-1adb-3536-890e-9b39b9a14b2d\"><target>b9692581-c117-47f3-9524-3deeb69c6d3f</target><instrument id=\"b9692581-c117-47f3-9524-3deeb69c6d3f\"><name>classical kemençe</name><description>Turkish bowl-shaped kemenche, mainly used in classical Ottoman music</description></instrument></relation></relation-list></instrument></metadata>"
  },
  {
    "path": "test/data/instrument/6505f98c-f698-4406-8bf4-8ca43d05c36f-aliases.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><instrument type=\"Other instrument\" id=\"6505f98c-f698-4406-8bf4-8ca43d05c36f\"><name>bass</name><description>Bass is a common but generic credit which refers to more than one instrument, the most common being the bass guitar and the double bass (a.k.a. contrabass, acoustic upright bass, wood bass). Please use the correct instrument if you know which one is intended.</description><alias-list count=\"14\"><alias locale=\"de\" primary=\"primary\" sort-name=\"Bass\" type=\"Instrument name\">Bass</alias><alias locale=\"it\" sort-name=\"Basso\" primary=\"primary\" type=\"Instrument name\">Basso</alias><alias sort-name=\"baixo\" primary=\"primary\" locale=\"pt_BR\" type=\"Instrument name\">baixo</alias><alias type=\"Instrument name\" sort-name=\"bajo (genérico, no usar)\" primary=\"primary\" locale=\"es\">bajo (genérico, no usar)</alias><alias locale=\"da\" primary=\"primary\" sort-name=\"bas\" type=\"Instrument name\">bas</alias><alias type=\"Instrument name\" primary=\"primary\" sort-name=\"bas\" locale=\"hr\">bas</alias><alias type=\"Instrument name\" primary=\"primary\" sort-name=\"bas\" locale=\"nl\">bas</alias><alias type=\"Instrument name\" primary=\"primary\" sort-name=\"bas\" locale=\"tr\">bas</alias><alias type=\"Instrument name\" locale=\"en\" primary=\"primary\" sort-name=\"bass\">bass</alias><alias type=\"Instrument name\" sort-name=\"bass\" primary=\"primary\" locale=\"et\">bass</alias><alias locale=\"fr\" primary=\"primary\" sort-name=\"basses\" type=\"Instrument name\">basses</alias><alias type=\"Instrument name\" locale=\"fi\" sort-name=\"basso\" primary=\"primary\">basso</alias><alias type=\"Instrument name\" sort-name=\"μπάσο\" primary=\"primary\" locale=\"el\">μπάσο</alias><alias type=\"Instrument name\" locale=\"ja\" primary=\"primary\" sort-name=\"ベース\">ベース</alias></alias-list></instrument></metadata>"
  },
  {
    "path": "test/data/instrument/6505f98c-f698-4406-8bf4-8ca43d05c36f-tags.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><instrument id=\"6505f98c-f698-4406-8bf4-8ca43d05c36f\" type=\"Other instrument\"><name>bass</name><description>Bass is a common but generic credit which refers to more than one instrument, the most common being the bass guitar and the double bass (a.k.a. contrabass, acoustic upright bass, wood bass). Please use the correct instrument if you know which one is intended.</description><tag-list><tag count=\"1\"><name>fixme</name></tag><tag count=\"0\"><name>never use this</name></tag><tag count=\"0\"><name>please don't use this</name></tag></tag-list></instrument></metadata>"
  },
  {
    "path": "test/data/instrument/9447c0af-5569-48f2-b4c5-241105d58c91.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><instrument id=\"9447c0af-5569-48f2-b4c5-241105d58c91\" type=\"Wind instrument\"><name>bass saxophone</name><description>The bass saxophone is the second largest existing member of the saxophone family (not counting the subcontrabass tubax). It is similar in design to a baritone saxophone, but it is larger, with a longer loop near the mouthpiece.</description></instrument></metadata>"
  },
  {
    "path": "test/data/instrument/d00cec5f-f9bc-4235-a54f-6639a02d4e4c-annotation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><instrument type=\"Other instrument\" id=\"d00cec5f-f9bc-4235-a54f-6639a02d4e4c\"><name>bullroarer</name><description>A bullroarer consists of a piece of wood attached to a long cord which is then swung in a circle.</description><annotation><text>Hornbostel-Sachs: 412.22</text></annotation></instrument></metadata>"
  },
  {
    "path": "test/data/instrument/d00cec5f-f9bc-4235-a54f-6639a02d4e4c-url-rels.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><instrument id=\"d00cec5f-f9bc-4235-a54f-6639a02d4e4c\" type=\"Other instrument\"><name>bullroarer</name><description>A bullroarer consists of a piece of wood attached to a long cord which is then swung in a circle.</description><relation-list target-type=\"url\"><relation type-id=\"0e62afec-12f3-3d0f-b122-956207839854\" type=\"information page\"><target id=\"e0132182-3ab0-405f-adde-f2504c97900e\">http://en.wikisource.org/wiki/1911_Encyclop%C3%A6dia_Britannica/Bullroarer</target></relation><relation type-id=\"1486fccd-cf59-35e4-9399-b50e2b255877\" type=\"wikidata\"><target id=\"5c0633b0-12fd-4e54-8383-9cc0e049aa3a\">http://www.wikidata.org/wiki/Q666971</target></relation><relation type-id=\"f64eacbd-1ea1-381e-9886-2cfb552b7d90\" type=\"image\"><target id=\"8513926d-184f-4ef7-920c-ec3b69e9a00a\">https://commons.wikimedia.org/wiki/File:Bull_roarers.jpg</target></relation></relation-list></instrument></metadata>"
  },
  {
    "path": "test/data/instrument/dabdeb41-560f-4d84-aa6a-cf22349326fe.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><instrument type=\"String instrument\" id=\"dabdeb41-560f-4d84-aa6a-cf22349326fe\"><name>tar</name><disambiguation>lute</disambiguation><description>The tar is a long-necked, waisted lute found in Azerbaijan, Iran, Armenia, Georgia, and other areas near the Caucasus region. Not to be confused with the drum of the same name.</description></instrument></metadata>"
  },
  {
    "path": "test/data/label/022fe361-596c-43a0-8e22-bad712bb9548-aliases.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><label type=\"Original Production\" id=\"022fe361-596c-43a0-8e22-bad712bb9548\"><name>EMI Records</name><sort-name>EMI Records</sort-name><label-code>542</label-code><country>GB</country><life-span><begin>1972</begin></life-span><alias-list count=\"4\"><alias sort-name=\"EMI\">EMI</alias><alias sort-name=\"EMI Records (UK)\">EMI Records (UK)</alias><alias sort-name=\"EMI Records Ltd\">EMI Records Ltd</alias><alias sort-name=\"EMI UK\">EMI UK</alias></alias-list></label></metadata>"
  },
  {
    "path": "test/data/label/e72fabf2-74a3-4444-a9a5-316296cbfc8d-aliases.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><label type=\"Publisher\" id=\"e72fabf2-74a3-4444-a9a5-316296cbfc8d\"><name>Ki/oon Music Inc.</name><sort-name>Ki/oon Music Inc.</sort-name><disambiguation>do NOT file releases here. Name was &quot;Ki/oon Records Inc.&quot; prior to 2012-04</disambiguation><country>JP</country><alias-list count=\"1\"><alias sort-name=\"Ki/oon Records Inc.\" begin-date=\"2001-10\" end-date=\"2012-04\">Ki/oon Records Inc.</alias></alias-list></label></metadata>"
  },
  {
    "path": "test/data/place/0c79cdbb-acd6-4e30-aaa3-a5c8d6b36a48-aliases-tags.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><place type=\"Religious building\" id=\"0c79cdbb-acd6-4e30-aaa3-a5c8d6b36a48\"><name>All Saints' Church</name><disambiguation>East Finchley, Durham Road</disambiguation><address>38 Durham Road, London N2 9DP, United Kingdom</address><coordinates><latitude>51.591812</latitude><longitude>-0.159699</longitude></coordinates><area id=\"f03d09b3-39dc-4083-afd6-159e3f0d462f\"><name>London</name><sort-name>London</sort-name></area><life-span><begin>1891</begin></life-span><alias-list count=\"1\"><alias type=\"Search hint\" sort-name=\"All Saints' Durham Road\">All Saints' Durham Road</alias></alias-list><tag-list><tag count=\"1\"><name>type=church</name></tag></tag-list></place></metadata>"
  },
  {
    "path": "test/data/place/browse-area-74e50e58-5deb-4b99-93a2-decbb365c07f-annotation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><place-list count=\"395\"><place type=\"Studio\" id=\"0ec8cbd3-9d2d-4392-b3d1-feae21c08f31\"><name>440 Studios</name></place><place type=\"Studio\" id=\"37b7a8bb-fdcb-456b-a9d2-5277e3ba87b9\"><name>Adrian Carr Studios</name></place><place type=\"Venue\" id=\"37f3952e-305e-4740-868f-db3bd005b96c\"><name>Art D'Lugoff's Top of the Gate</name></place><place id=\"38f738f7-69c1-48e3-b00b-21748a8bafc9\" type=\"Studio\"><name>Apex Studios</name></place><place id=\"3ca3c679-7861-4b46-bd82-9974ba8f5807\" type=\"Studio\"><name>Atomic Heart Studios</name></place><place id=\"3d6e5345-78a5-47f8-8b90-b71b97c53f93\"><name>Arf Mastering</name></place><place type=\"Studio\" id=\"3ed274dc-2a1a-43c5-bd1f-00df934e8126\"><name>AudioMASTER Vargas</name><address>New York, NY 11367</address></place><place type=\"Studio\" id=\"5b2dde24-1bec-470b-9450-339e33216fe4\"><name>A&amp;R Recording Studio</name><address>322 West 48 Street</address><coordinates><latitude>40.761498</latitude><longitude>-73.988169</longitude></coordinates></place><place id=\"5e66add8-710a-4efd-892d-7f3704fbe75d\" type=\"Venue\"><name>A.C. Pianocraft Recital Hall</name></place><place id=\"6685e2e3-5c5e-4ae3-8e73-2e277e4863bc\"><name>Aura Recording Studios</name><address>136 West 52nd Street, New York, New York 10019</address></place><place id=\"75d6523c-59a4-43a4-bf8f-58de787aa668\" type=\"Studio\"><name>3rd Floor</name></place><place id=\"7db23ec1-f597-417a-a865-5a93e59a3a0e\"><name>a.l.l. digital</name></place><place id=\"7ea7c7dc-37fa-41c6-a599-74d8b03acdc1\" type=\"Studio\"><name>Allido Studios</name><disambiguation>studio for Mark Ronson's Allido label</disambiguation></place><place type=\"Studio\" id=\"8064c635-6bd0-4221-b2f9-c090f2de4abc\"><name>Allegro Sound Studios</name><address>1650 Broadway, West 51st Street, 7th Avenue</address><annotation><text>was later renamed [http://www.discogs.com/label/267460-Generation-Sound-Studios|Generation Sound Studios], according to wikipedia: https://en.wikipedia.org/wiki/Brill_Building#1650_Broadway</text></annotation></place><place id=\"8442761f-7506-4cbc-85fa-5908aefb6e44\"><name>American Record Corporation Studios</name><address>1776 Broadway, NYC</address></place><place type=\"Venue\" id=\"96facf8c-586f-4609-a7fe-aa5376e60188\"><name>Academy of Music</name><disambiguation>New York City</disambiguation><address>125 East 14th Street, New York, NY 10003</address><coordinates><latitude>40.734568</latitude><longitude>-73.988489</longitude></coordinates><life-span><begin>1854</begin><end>1926</end><ended>true</ended></life-span></place><place type=\"Studio\" id=\"a5bcfea2-8334-451a-8fcc-93af13098ef6\"><name>Avator Studio</name></place><place id=\"ab514196-688d-4cdf-ae04-b7cdb1bffb01\" type=\"Studio\"><name>Avatar Studios, Studio A</name><address>441 West 53rd Street, New York, NY 10019</address><coordinates><latitude>40.766389</latitude><longitude>-73.989444</longitude></coordinates></place><place type=\"Venue\" id=\"acc83706-72a8-4ee5-b38b-17e326e93a26\"><name>Anderson Theater</name><address>66 2nd Ave</address><coordinates><latitude>40.725979</latitude><longitude>-73.98957</longitude></coordinates><life-span><begin>1957-08</begin><end>1977</end><ended>true</ended></life-span></place><place type=\"Studio\" id=\"d26f74ed-e921-44b6-84bc-c7221b5f3c4d\"><name>39th Street Music Studio</name></place><place id=\"e55158ef-bdd4-4d43-9ef7-4e7c5219613e\" type=\"Studio\"><name>AlgoRhythms</name></place><place type=\"Studio\" id=\"ea022b6f-edc4-424a-90df-ee5782ec04c2\"><name>321 Studios</name></place><place type=\"Venue\" id=\"f23acad7-c5d9-433c-929f-46ab4efc68cc\"><name>Apollo Theater</name><address>253 West 125th Street, Manhattan, New York City, USA</address><coordinates><latitude>40.810047</latitude><longitude>-73.95015</longitude></coordinates><life-span><begin>1914</begin></life-span></place><place type=\"Venue\" id=\"f4d6debd-3a1c-4c5e-a797-3dbf8e88479f\"><name>Aeolian Hall</name><address>29-33 West 42nd Street, New York</address><life-span><begin>1912</begin><end>1926</end><ended>true</ended></life-span></place><place type=\"Studio\" id=\"fc12e55a-8ca7-49c2-8427-4744282c857d\"><name>Avatar Studios</name><address>441 West 53rd Street, New York, NY 10019</address><coordinates><latitude>40.766389</latitude><longitude>-73.989444</longitude></coordinates><life-span><begin>1996-05</begin></life-span></place></place-list></metadata>"
  },
  {
    "path": "test/data/recording/f606f733-c1eb-43f3-93c1-71994ea611e3-artist-rels.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><recording id=\"f606f733-c1eb-43f3-93c1-71994ea611e3\"><title>Shades of Gray</title><length>259600</length><relation-list target-type=\"artist\"><relation type=\"producer\" type-id=\"5c0ceac3-feb4-41f0-868d-dc06f6e27fc0\"><target>09b1131d-9803-4acf-8b3c-3438e6c2b9c7</target><direction>backward</direction><artist id=\"09b1131d-9803-4acf-8b3c-3438e6c2b9c7\"><name>Tom Jung</name><sort-name>Jung, Tom</sort-name></artist></relation><relation type-id=\"a01ee869-80a8-45ef-9447-c59e91aa7926\" type=\"recording\"><target>09b1131d-9803-4acf-8b3c-3438e6c2b9c7</target><direction>backward</direction><artist id=\"09b1131d-9803-4acf-8b3c-3438e6c2b9c7\"><name>Tom Jung</name><sort-name>Jung, Tom</sort-name></artist></relation><relation type=\"instrument\" type-id=\"59054b12-01ac-43ee-a618-285fd397e461\"><target>83c6ecce-ebc2-4064-ad28-49c7354469f4</target><direction>backward</direction><attribute-list><attribute credited-as=\"Yamaha and Steinway pianos\">piano</attribute></attribute-list><artist id=\"83c6ecce-ebc2-4064-ad28-49c7354469f4\"><name>Billy Barber</name><sort-name>Barber, Billy</sort-name></artist></relation><relation type=\"producer\" type-id=\"5c0ceac3-feb4-41f0-868d-dc06f6e27fc0\"><target>83c6ecce-ebc2-4064-ad28-49c7354469f4</target><direction>backward</direction><artist id=\"83c6ecce-ebc2-4064-ad28-49c7354469f4\"><name>Billy Barber</name><sort-name>Barber, Billy</sort-name></artist></relation></relation-list></recording></metadata>"
  },
  {
    "path": "test/data/release/212895ca-ee36-439a-a824-d2620cd10461-recordings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><release id=\"212895ca-ee36-439a-a824-d2620cd10461\"><title>We♥TechPara -mission style-</title><status>Official</status><quality>normal</quality><packaging>Keep Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>2006</date><country>JP</country><release-event-list count=\"1\"><release-event><date>2006</date><area id=\"2db42837-c832-3c27-b4a3-08198f75693c\"><name>Japan</name><sort-name>Japan</sort-name><iso-3166-1-code-list><iso-3166-1-code>JP</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>4988064913695</barcode><asin>B000EIF602</asin><cover-art-archive><artwork>true</artwork><count>11</count><front>true</front><back>true</back></cover-art-archive><medium-list count=\"1\"><medium><position>1</position><track-list count=\"18\" offset=\"0\"><track id=\"78a74c1f-d5e4-3d4c-beeb-4d279b49b212\"><position>1</position><number/><length>33000</length><recording id=\"d717ade4-9e3b-4441-8da1-4a7deb07b12a\"><title>[intro]</title><length>33000</length></recording></track><track id=\"4c4f6310-e4bc-33a7-9f5d-0e37a6f4b9e7\"><position>2</position><number>1</number><length>188000</length><recording id=\"de9a07ea-b2af-492f-8232-15e2ed3c968e\"><title>WILD BOY &lt;MISSION\"B\"RE-EDIT&gt;</title></recording></track><track id=\"10f0c790-859f-3064-a65f-b6817ff43395\"><position>3</position><number>2</number><length>170000</length><recording id=\"b7f43e70-03a3-4bc3-bbb1-84fce5c640b8\"><title>FAIRY DUST</title></recording></track><track id=\"0b843a91-ee15-37f4-a080-73f3f1d62b15\"><position>4</position><number>3</number><length>178000</length><recording id=\"1a85e67a-b8a8-48ef-afae-051f058007d9\"><title>BRAVO</title></recording></track><track id=\"0ebfc6d7-0c25-3f6f-831d-10739ec942df\"><position>5</position><number>4</number><length>167000</length><recording id=\"9086aa1e-53ff-4fad-bc98-c6107b58e863\"><title>VIERNES &lt;MISSION\"B\"RE-EDIT&gt;</title></recording></track><track id=\"00f87bbc-af63-3489-ab85-52ee1a17c295\"><position>6</position><number>5</number><length>105000</length><recording id=\"b5bc6f4f-d805-42d8-b39f-26c255f0c784\"><title>GUESS WHO'S BACK</title></recording></track><track id=\"7988bfcd-16ea-3f7f-b66d-fcfda1751f21\"><position>7</position><number>6</number><length>140000</length><recording id=\"741eb0e7-3f9e-4ebd-b505-fb08554d9e32\"><title>BABY BABY・・・DON'T STOP!</title></recording></track><track id=\"b096a300-41ce-30c1-b062-26b39f54012f\"><position>8</position><number>7</number><length>130000</length><recording id=\"a4b2619f-9edd-4600-a210-115b67304a76\"><title>DESTINO &lt;MISSION\"B\"REMIX POWER -UP VERSION&gt;</title></recording></track><track id=\"81db44c5-11ec-36fc-8a80-20049112e8db\"><position>9</position><number>8</number><length>150000</length><recording id=\"9f013928-df91-42ef-b294-c9c2ca1d9614\"><title>SO HIGH</title></recording></track><track id=\"85fe850d-39ba-3600-9fef-d2ba2a0cbe32\"><position>10</position><number>9</number><length>191000</length><recording id=\"9dfb34bd-adde-4fb9-8b82-55c508f98c02\"><title>BAILAN MUY BIEN</title></recording></track><track id=\"f0061dc5-5e3c-31e0-b652-3fee5f13cd6d\"><position>11</position><number>10</number><length>146000</length><recording id=\"30f6f031-68d9-4291-8540-13c8ac0b5858\"><title>HYPER TECHNO fairy</title></recording></track><track id=\"968d92ed-85b9-3e94-9183-9ddc6f618cae\"><position>12</position><number>11</number><length>120000</length><recording id=\"0f372db4-a288-447a-8140-4e62caef3114\"><title>A LOVE AT FIRST SIGHT &lt;MISSION\"HMX\"REMIX&gt;</title></recording></track><track id=\"64a19f48-0660-3c1f-924c-22559bf90225\"><position>13</position><number>12</number><length>173000</length><recording id=\"1d2f5bcc-9733-4202-80b0-b039229c01a6\"><title>BLUE EYES</title></recording></track><track id=\"b26f9f60-db2a-3e76-8a72-dd6add8e666b\"><position>14</position><number>13</number><length>137000</length><recording id=\"deec6e54-a09a-45d2-887f-14b88811e458\"><title>MADE IN NEWYORK &lt;DJ KEN-BOW EDIT&gt;</title></recording></track><track id=\"52f5f495-f2c8-3741-b213-80a384fc5afd\"><position>15</position><number>14</number><length>159000</length><recording id=\"7b388992-4643-4c10-a517-8ef3466edee8\"><title>BILLY JIVE (WITH WILLY'S WIFE) &lt;Y &amp; Co. REMIX&gt;</title></recording></track><track id=\"916d3c05-e0af-3cfe-b37c-3af7bbe24765\"><position>16</position><number>15</number><length>204000</length><recording id=\"51af3b2c-a988-4b28-96c5-b962211ee5fb\"><title>U TURN ME ON &lt;SUPER RAVE REMIX&gt;</title></recording></track><track id=\"0fbfdcb1-62bd-3b3f-86a3-807ba3efc12a\"><position>17</position><number/><length>246000</length><recording id=\"336e7f74-e862-40a3-bcd6-fa136bb86743\"><title>[credits / behind the scenes]</title><length>246000</length></recording></track><track id=\"ffc7a1cd-037c-38b6-b868-3e785fbdfca4\"><position>18</position><number>16</number><length>99000</length><recording id=\"c381e1ed-c718-4bc5-86cd-9cfad0017b9c\"><title>TEMPO &lt;ONLY THE SHORT TechPara SHOW VERSION&gt;</title></recording></track></track-list></medium></medium-list></release></metadata>"
  },
  {
    "path": "test/data/release/833d4c3a-2635-4b7a-83c4-4e560588f23a-recordings+artist-credits.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><release id=\"833d4c3a-2635-4b7a-83c4-4e560588f23a\"><title>Ruined Subjects</title><status>Official</status><packaging>None</packaging><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit><date>2011-08-09</date><country>XW</country><medium-list count=\"1\"><medium><position>1</position><track-list count=\"21\" offset=\"0\"><track><position>1</position><number>1</number><length>246000</length><recording id=\"886631b4-94d1-4f1b-a9ce-7b3a21385616\"><title>Pollux</title><length>246000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>2</position><number>2</number><length>96000</length><recording id=\"94d01f1a-6361-438f-b87d-d7c4c33f3797\"><title>Vega</title><length>96000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>3</position><number>3</number><length>132000</length><recording id=\"80379de4-a843-4315-8e80-a849b4454c30\"><title>Deneb</title><length>132000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>4</position><number>4</number><length>536000</length><recording id=\"45bc883a-31e3-4d42-8595-0d8612077b19\"><title>Sirius</title><length>536000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>5</position><number>5</number><length>132000</length><recording id=\"c0290398-7c3c-4758-8cdf-2e8eb97e120e\"><title>Descent</title><length>132000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>6</position><number>6</number><length>44000</length><recording id=\"38a84bde-12b2-4698-9ce5-0dccb689450d\"><title>The Grand Machine</title><length>44000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>7</position><number>7</number><title>In the Clounds</title><length>68000</length><recording id=\"f811191c-c3d5-4f9f-a818-ea3dee496815\"><title>In The Clounds</title><length>68000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>8</position><number>8</number><length>148000</length><recording id=\"46e27edd-5f07-4321-b18b-65af0e39046d\"><title>Paranoia</title><length>148000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>9</position><number>9</number><length>160000</length><recording id=\"7ae4113e-4833-4b71-841f-32c2d48241be\"><title>Cubic</title><length>160000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>10</position><number>10</number><length>251000</length><recording id=\"3a466765-8ae9-414d-82b0-726f2f28ccc2\"><title>Separation</title><length>251000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>11</position><number>11</number><length>239000</length><recording id=\"27b3c578-a298-41fd-86cb-cb0bf77fffc2\"><title>Retarded Retard</title><length>239000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>12</position><number>12</number><length>129000</length><recording id=\"1b43d02a-dfd4-4ba0-8738-098dbd88b168\"><title>Umlaut Ampersand</title><length>129000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>13</position><number>13</number><length>16000</length><recording id=\"e5a2fca0-6b19-4c62-9593-5a3fc577fc3b\"><title>Trees</title><length>16000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>14</position><number>14</number><length>86000</length><recording id=\"04a20931-d402-42bd-b24c-ee298cdff266\"><title>The Multiverse</title><length>86000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>15</position><number>15</number><length>171000</length><recording id=\"3f3984f3-f8e1-47bc-bc35-dcf51b35820a\"><title>Flux's Curiosity</title><length>171000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>16</position><number>16</number><length>116000</length><recording id=\"6b985a9c-ae6b-4082-a9c8-5ba3cd54778a\"><title>Infinimarch</title><length>116000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>17</position><number>17</number><length>152000</length><recording id=\"459f1e07-8fda-425c-a97a-ce1c2fd44202\"><title>Deathboat</title><length>152000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>18</position><number>18</number><length>105000</length><recording id=\"458ecec6-9e4b-41d7-92e9-bcbafe515dac\"><title>Painter's Vista</title><length>105000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>19</position><number>19</number><length>194000</length><recording id=\"24801404-b62a-49e7-93f1-3c98a393f6f4\"><title>The City</title><length>194000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>20</position><number>20</number><length>123000</length><recording id=\"ce1e3811-c61b-4704-b3d1-e29d77545c51\"><title>New Beginning</title><length>123000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track><track><position>21</position><number>21</number><length>54000</length><recording id=\"6705a4b7-57d8-4d2f-a7df-47bd2ac303aa\"><title>Memories of Onus</title><length>54000</length><artist-credit><name-credit><artist id=\"fbb941cc-6891-4c8f-8697-1e464aaa8c78\"><name>JT Bruce</name><sort-name>Bruce, JT</sort-name></artist></name-credit></artist-credit></recording></track></track-list></medium></medium-list></release></metadata>"
  },
  {
    "path": "test/data/release/8eb2b179-643d-3507-b64c-29fcc6745156-recordings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><release id=\"8eb2b179-643d-3507-b64c-29fcc6745156\"><title>Sea of Cowards</title><status>Official</status><quality>normal</quality><packaging>Jewel Case</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>2010-05-10</date><country>GB</country><release-event-list count=\"1\"><release-event><date>2010-05-10</date><area id=\"8a754a16-0027-3a29-b6d7-2b40ea0481ed\"><name>United Kingdom</name><sort-name>United Kingdom</sort-name><iso-3166-1-code-list><iso-3166-1-code>GB</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>093624966524</barcode><asin>BT00CHI1V2</asin><cover-art-archive><artwork>true</artwork><count>1</count><front>true</front><back>false</back></cover-art-archive><medium-list count=\"1\"><medium><position>1</position><pregap id=\"ac0c0731-9776-4550-a621-90f9504be55c\"><position>0</position><number>0</number><length>35000</length><recording id=\"b29b1ef2-2add-4f4d-8f9d-c134f6f0a442\"><title>[untitled]</title><length>35000</length></recording></pregap><track-list count=\"11\" offset=\"0\"><track id=\"94928c4c-5cd9-3a3e-b72f-6d0bc8023c9c\"><position>1</position><number>1</number><length>202306</length><recording id=\"4f16eff1-0df6-4d94-89ba-e1470bc7b61f\"><title>Blue Blood Blues</title><length>202306</length></recording></track><track id=\"a0cd80b3-bbd0-3a82-a3d5-b308039ae3e6\"><position>2</position><number>2</number><length>225666</length><recording id=\"beffad8a-1350-424d-be80-a86bbf3e93ce\"><title>Hustle and Cuss</title><length>225666</length></recording></track><track id=\"ec2ac7a6-65d9-3608-a063-d41842c90f40\"><position>3</position><number>3</number><length>217320</length><recording id=\"be2c7946-cbf6-4d75-a638-168618edcbb6\"><title>The Difference Between Us</title><length>217320</length></recording></track><track id=\"56db5993-e434-38d4-9eb4-4df18ef281c0\"><position>4</position><number>4</number><title>I'm Mad</title><length>196226</length><recording id=\"3d9b5b5a-28eb-4ba8-8ff1-19e51e8cb52c\"><title>I’m Mad</title><length>196226</length></recording></track><track id=\"1f5de7ed-e771-3d85-9e3b-3e075751cca2\"><position>5</position><number>5</number><length>209213</length><recording id=\"d5d3fa38-2c13-45dc-8f0e-d64dd0445732\"><title>Die by the Drop</title><length>209213</length></recording></track><track id=\"7e07469c-a018-320f-ba71-ee3fcc8f2048\"><position>6</position><number>6</number><title>I Can't Hear You</title><length>215093</length><recording id=\"6a223970-d6a3-46d4-b7db-c0832a1f4634\"><title>I Can’t Hear You</title><length>215093</length></recording></track><track id=\"6532604c-60cf-3a1d-a95c-8c7d29627972\"><position>7</position><number>7</number><length>164840</length><recording id=\"45dabf9f-9c03-4cd1-9c07-7522ad162b3c\"><title>Gasoline</title><length>164840</length></recording></track><track id=\"a302cb9d-5771-3aa4-804a-55601876ace8\"><position>8</position><number>8</number><length>169053</length><recording id=\"c4fbc7e2-9b2d-482e-9126-807d3308a7e9\"><title>No Horse</title><length>169053</length></recording></track><track id=\"1fe4c36b-cc05-38ad-a8b5-c852e0ca73da\"><position>9</position><number>9</number><length>162026</length><recording id=\"f9e88df3-15c2-4fba-be5e-5f2525165279\"><title>Looking at the Invisible Man</title><length>162026</length></recording></track><track id=\"f4b1e4a1-a020-3985-a497-28644fc85d27\"><position>10</position><number>10</number><length>178040</length><recording id=\"725805b8-9724-4ed2-9d87-776510f0e4fe\"><title>Jawbreaker</title><length>178040</length></recording></track><track id=\"270e7fd2-869d-3a6d-acad-624b100dbc96\"><position>11</position><number>11</number><length>172973</length><recording id=\"8136b0af-5202-42b9-b1d4-6befbc0532d5\"><title>Old Mary</title><length>172973</length></recording></track></track-list></medium></medium-list></release></metadata>"
  },
  {
    "path": "test/data/release/9ce41d09-40e4-4d33-af0c-7fed1e558dba-recordings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><release id=\"9ce41d09-40e4-4d33-af0c-7fed1e558dba\"><title>Ramasser les morceaux : Le punk pour les nul-le-s</title><status>Official</status><quality>normal</quality><packaging>Cardboard/Paper Sleeve</packaging><text-representation><language>mul</language><script>Latn</script></text-representation><date>2013-05</date><country>FR</country><release-event-list count=\"1\"><release-event><date>2013-05</date><area id=\"08310658-51eb-3801-80de-5a0739207115\"><name>France</name><sort-name>France</sort-name><iso-3166-1-code-list><iso-3166-1-code>FR</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode/><cover-art-archive><artwork>false</artwork><count>0</count><front>false</front><back>false</back></cover-art-archive><medium-list count=\"1\"><medium><position>1</position><track-list offset=\"0\" count=\"0\"/><data-track-list count=\"198\"><track id=\"0b388bd9-8249-4eb9-b92b-82a93f721c1f\"><position>1</position><number>1</number><length>172000</length><recording id=\"35ae913f-b65a-4b57-b744-397c539b9a04\"><title>Kick Out the Jams</title><length>172306</length></recording></track><track id=\"ca28eb0e-6f44-4122-b916-7397ace8c595\"><position>2</position><number>2</number><length>199000</length><recording id=\"bdbe27f5-d5d4-46df-96aa-bf4f2b03445e\"><title>My Generation</title><length>199000</length></recording></track><track id=\"832dd455-33f2-44fa-a21c-1f8c2045acce\"><position>3</position><number>3</number><length>205000</length><recording id=\"f6655c59-8b0f-475e-8962-516ee897e7bb\"><title>Because the Night</title><length>202066</length></recording></track><track id=\"014dd6b5-5315-4d12-8115-685ca454441d\"><position>4</position><number>4</number><length>351000</length><recording id=\"7b5dd8c9-c0fd-455c-9d29-e628434dc52e\"><title>Politicians in My Eyes</title><length>351000</length></recording></track><track id=\"9d663012-3954-4576-9c8b-ded43bacdbc6\"><position>5</position><number>5</number><length>379000</length><recording id=\"bdfa6c6b-ad6f-4c01-b85f-5453de61369a\"><title>Hero</title><length>379000</length></recording></track><track id=\"c4b764d0-ff14-49a2-bb9f-c953491b1d7d\"><position>6</position><number>6</number><title>Fire Engine</title><length>193000</length><recording id=\"58a02fb6-6919-491a-9c10-85f716f0503a\"><title>Fire Engine (studio: 1975-08-xx: New York City, NY, USA)</title><length>193000</length></recording></track><track id=\"14c0a761-eb49-4fc0-8b53-7c8dda08b9cc\"><position>7</position><number>7</number><length>152000</length><recording id=\"332375ec-053b-48c9-b24b-7318db248470\"><title>The KKK Took My Baby Away</title><length>151506</length></recording></track><track id=\"c7615d1a-4692-41e1-837f-1de69efb558b\"><position>8</position><number>8</number><length>261000</length><recording id=\"21d31982-6f60-4383-bdf7-c72d0449a527\"><title>TV Eye</title><length>261000</length></recording></track><track id=\"470bced8-5117-4815-adf1-7a8dcca98a03\"><position>9</position><number>9</number><length>216000</length><recording id=\"4356bba2-853c-4ac0-b43f-c6e8f6bc9735\"><title>Transmission</title><length>216266</length></recording></track><track id=\"f22985d2-0957-4630-8b61-accebd27d61a\"><position>10</position><number>10</number><length>149000</length><recording id=\"a34b277f-ef7d-4d5f-822e-1a9556f7b0d9\"><title>P38</title><length>149000</length></recording></track><track id=\"b33390e4-6a1b-4de3-b8f4-f8d9083669bb\"><position>11</position><number>11</number><length>142000</length><recording id=\"d74d5fe9-d7a7-473f-9dbe-f0de2750e0be\"><title>Identity</title><length>142773</length></recording></track><track id=\"db4f1b75-6659-4e1e-a002-9fbae1f8fcf7\"><position>12</position><number>12</number><length>186000</length><recording id=\"483df073-f889-4f01-ac45-8974035e00f4\"><title>Warhead</title><length>185640</length><disambiguation>single version</disambiguation></recording></track><track id=\"a3409450-285f-4532-9e0c-5bc6f8295469\"><position>13</position><number>13</number><length>158000</length><recording id=\"1834646c-cb01-4fc3-bfbf-ae678248e09a\"><title>One Chord Wonders</title><length>155000</length></recording></track><track id=\"31c25b22-2542-4f3a-b9e0-6a744fbe64c7\"><position>14</position><number>14</number><length>120000</length><recording id=\"008a05ac-883c-44f8-88a4-f3e3d6580aad\"><title>We’re Desperate</title><length>120066</length></recording></track><track id=\"18b09cd2-2489-4f76-99e7-51531bf0b319\"><position>15</position><number>15</number><length>127000</length><recording id=\"ea5d6ab0-4c25-4892-926a-a7ac49f2e74d\"><title>Lexicon Devil</title><length>127000</length></recording></track><track id=\"9e0c7483-03fd-4fe2-b573-6c7b9f47a28c\"><position>16</position><number>16</number><length>124000</length><recording id=\"b948bbcd-bd26-4a73-84e6-9b04c6b0d75f\"><title>Parece que somos lo que no somos pero queremos ser</title><length>124000</length></recording></track><track id=\"5e9edff2-c610-4d43-89f0-7a2f5698d031\"><position>17</position><number>17</number><length>175000</length><recording id=\"07c61783-9328-4d70-b7d8-4bc71ddc46db\"><title>Utopia</title><length>175000</length></recording></track><track id=\"f519dcd0-5031-4fa7-b2c6-c2c73ada4719\"><position>18</position><number>18</number><length>114000</length><recording id=\"b9c2d4a7-5280-4d5c-8dea-7d2a83475754\"><title>System Fails but the Law Prevails</title><length>114000</length></recording></track><track id=\"04422a8c-9afa-41e9-8d1f-253f9a90e052\"><position>19</position><number>19</number><length>286000</length><recording id=\"165a2db8-120e-4736-8e5c-08ef6eb5d02b\"><title>This Land</title><length>286000</length></recording></track><track id=\"a89da022-157e-4d0b-9766-731c2120bf36\"><position>20</position><number>20</number><length>197000</length><recording id=\"d915097c-66c8-4f0c-8cfc-4cac79c8b25f\"><title>Berkertex Bribe</title><length>197000</length></recording></track><track id=\"24719c51-aa99-4797-97f0-36a5ba40e776\"><position>21</position><number>21</number><length>108000</length><recording id=\"e1a5657b-fd77-4756-9f5e-5ac206433419\"><title>Beautiful Pictures</title><length>108000</length></recording></track><track id=\"dd8e82c7-c610-48d4-8782-64a97684bfb0\"><position>22</position><number>22</number><length>100000</length><recording id=\"6ef28892-6de7-4b2d-9516-745a94ea040e\"><title>Toilet Stories</title><length>100000</length></recording></track><track id=\"201d90d3-e6b6-49b0-8714-b59e1175c906\"><position>23</position><number>23</number><length>106000</length><recording id=\"cc8389c8-33cb-4cbe-8ae3-37e6a06622fa\"><title>שמיקה</title><length>106000</length></recording></track><track id=\"6c3a4a80-f648-44c9-8f5c-534e99a83e7f\"><position>24</position><number>24</number><length>145000</length><recording id=\"d5df5f49-2218-4fab-948a-0870a89c5f01\"><title>Venganza</title><length>145000</length></recording></track><track id=\"a6c92a8f-4c4e-4417-82f3-84fc69be06e6\"><position>25</position><number>25</number><length>195000</length><recording id=\"dec62b18-8f10-4775-8417-7e26f14be297\"><title>Romeo’s Distress</title><length>195000</length></recording></track><track id=\"cec7edc0-b05f-4e5e-b503-6d8304b5a478\"><position>26</position><number>26</number><title>Marian</title><length>344000</length><recording id=\"a110ef30-4199-44b6-8a53-0f79a0a3e974\"><title>Marian (version)</title><length>344866</length><disambiguation>1985 original mix</disambiguation></recording></track><track id=\"61eb9aca-3043-4380-902a-b5f3d5aca34e\"><position>27</position><number>27</number><length>243000</length><recording id=\"18dafdb9-8122-49ed-a972-3a8a744a7405\"><title>This Time</title><length>242760</length></recording></track><track id=\"5ca09ac9-0ba5-45e1-a40f-98f64cb3dde3\"><position>28</position><number>28</number><length>249000</length><recording id=\"2db5fbe8-03ab-46da-a3fe-c17e749ec0d2\"><title>Eve at the Mansion</title><length>249000</length></recording></track><track id=\"e8a73600-c33d-47ec-84cd-5e62fdcaf40b\"><position>29</position><number>29</number><length>228000</length><recording id=\"31ff89c3-102f-4a6f-93ba-13edbea1e66b\"><title>La ciega</title><length>228000</length></recording></track><track id=\"7c038b9f-396e-461e-ba9a-24c0e5aca6d9\"><position>30</position><number>30</number><length>284000</length><recording id=\"4191934f-7f41-4754-917a-5a3ce1c328eb\"><title>Siren</title><length>284000</length></recording></track><track id=\"46e5266e-0557-4b06-a42d-9898d69aaf40\"><position>31</position><number>31</number><length>171000</length><recording id=\"da36eae8-a78a-4c04-a93e-68ec956ad97a\"><title>All Women Are Bitches</title><length>171000</length></recording></track><track id=\"463c79df-6d18-4793-8979-8b7fbf52991b\"><position>32</position><number>32</number><length>230000</length><recording id=\"d2a32c6b-627c-4238-b204-78a79ae1249e\"><title>Ask Nicely</title><length>230000</length></recording></track><track id=\"5d5c15c9-7af5-4bb3-9cae-07021d8fe098\"><position>33</position><number>33</number><length>147000</length><recording id=\"19961861-f2bf-4b64-b555-c6cd49c6a659\"><title>Eating Toothpaste</title><length>146946</length></recording></track><track id=\"d9254083-3a63-432a-9e6e-df1307da9ae7\"><position>34</position><number>34</number><length>93000</length><recording id=\"f3e367fc-e361-4be8-a295-428885011f3b\"><title>No Make Up Tips</title><length>93000</length></recording></track><track id=\"4631c50d-2745-4c58-a788-b23c60822abe\"><position>35</position><number>35</number><length>100000</length><recording id=\"db2acbab-f293-46ad-a65e-f61304cf6db7\"><title>Coffee, Tea, and Misery</title><length>100000</length></recording></track><track id=\"6ba00172-2032-4e38-900a-1fdaf2780cba\"><position>36</position><number>36</number><length>174000</length><recording id=\"66cde715-ed3a-4970-83a4-e2b58f840de6\"><title>141</title><length>174000</length></recording></track><track id=\"81675a34-0065-486e-b0d7-90b71870837d\"><position>37</position><number>37</number><length>181000</length><recording id=\"ef45e2f7-12e5-4095-9338-e045726a1d09\"><title>Pressure Drop</title><length>179000</length></recording></track><track id=\"3aefa3db-3402-4e46-861b-193b30321e35\"><position>38</position><number>38</number><length>239000</length><recording id=\"98607ec9-ba33-4244-a0aa-1830c8476117\"><title>I Heard It Through the Grapevine</title><length>239000</length></recording></track><track id=\"2adfa1af-16a3-4ccd-b485-c29373e5c039\"><position>39</position><number>39</number><length>244000</length><recording id=\"48b55f29-90e1-46ba-b008-3ea5a58140a7\"><title>(White Man) In Hammersmith Palais</title><length>241000</length></recording></track><track id=\"d48a89b8-2b67-4abf-8139-3f289a530e26\"><position>40</position><number>40</number><length>127000</length><recording id=\"fc64e353-34f6-42bc-b4fc-5e03990af2a9\"><title>Reclaim the Streets</title><length>127000</length></recording></track><track id=\"5acdb139-55f5-4607-b60d-40e099800127\"><position>41</position><number>41</number><length>230000</length><recording id=\"be8b66a0-e4c9-493f-8eb4-a294ae9acf56\"><title>City City</title><length>230000</length></recording></track><track id=\"84f5d924-1cc6-4256-89c0-01ae8f38d33d\"><position>42</position><number>42</number><length>347000</length><recording id=\"2905bc9a-6e07-47b8-b5f3-a241467dc6d4\"><title>Murder on the Orange St.</title><length>347000</length></recording></track><track id=\"729bbdf3-1da9-4d79-b845-edc9675a6520\"><position>43</position><number>43</number><length>173000</length><recording id=\"5bf665ee-79ff-4be8-b2d6-db608e379113\"><title>A Message to You Rudy</title><length>173226</length></recording></track><track id=\"63204bd7-34c9-4cf3-8726-d5bfc452f8e1\"><position>44</position><number>44</number><length>188000</length><recording id=\"c22e5366-0e2e-4e74-aa24-c5d40fe6e7b8\"><title>Too Nice to Talk To</title><length>187893</length></recording></track><track id=\"bca6c322-af5d-40f0-bb9c-0ecc4b0901d2\"><position>45</position><number>45</number><length>201000</length><recording id=\"bff74e93-2d3f-438f-b506-1ddc59e549b1\"><title>Missing Words</title><length>201000</length></recording></track><track id=\"c4ec0987-5716-4dbc-8c2f-485b0d0399c9\"><position>46</position><number>46</number><length>347000</length><recording id=\"180f2f7d-5c6a-4064-9260-93f096576bdc\"><title>Setki dwie...</title><length>347000</length></recording></track><track id=\"d00cbc1b-69e5-4a0f-a227-77dbd8429e1b\"><position>47</position><number>47</number><length>147000</length><recording id=\"9f6c6d1a-1371-43c9-b948-df59874371aa\"><title>POD</title><length>147000</length></recording></track><track id=\"cfb91fd9-6400-44a1-859d-5d9709756884\"><position>48</position><number>48</number><length>156000</length><recording id=\"c126c666-0521-4fc5-9483-89def3ad6a9a\"><title>Looking Back</title><length>156000</length></recording></track><track id=\"fb232922-dbf3-42a2-846d-bd4b157a0d32\"><position>49</position><number>49</number><length>375000</length><recording id=\"dc0ce768-b74c-460f-9aae-89fd8507d1cf\"><title>Go to a War</title><length>375000</length></recording></track><track id=\"8e8aed56-0ca7-4723-b390-21c38c847886\"><position>50</position><number>50</number><length>116000</length><recording id=\"5cade112-5fe6-4796-bef2-b1e0c3b8480c\"><title>X</title><length>115720</length></recording></track><track id=\"86eaf79d-3b1a-45ab-87dc-f58638e46782\"><position>51</position><number>51</number><length>287000</length><recording id=\"e6222cfb-6234-4835-8ea8-54cacc93cdfe\"><title>British Justice</title><length>287000</length></recording></track><track id=\"66ebf9ef-bc43-4994-a489-eba8cc96fd2a\"><position>52</position><number>52</number><length>445000</length><recording id=\"1058cb0f-9bd2-48c6-bbc3-9287acb2f9b3\"><title>Loonitsch</title><length>445000</length></recording></track><track id=\"37781b0f-6c3b-41a4-b7bb-df305866ef66\"><position>53</position><number>53</number><length>163000</length><recording id=\"a08025ca-93ed-49ad-873a-2712a53f0993\"><title>Back to the Bark</title><length>163000</length></recording></track><track id=\"b6602480-6d2d-4945-94ee-86140ab3f25e\"><position>54</position><number>54</number><length>345000</length><recording id=\"1cd1042d-3221-4630-819e-35ddbfec2445\"><title>Black Vomit</title><length>345000</length></recording></track><track id=\"709a1b24-8fe7-45da-a3b8-60d81f6bf666\"><position>55</position><number>55</number><length>140000</length><recording id=\"42847fbf-d820-47ef-976a-671a72a7daf7\"><title>Six Pack</title><length>140440</length></recording></track><track id=\"12682481-c85e-4691-8215-eca9773c66da\"><position>56</position><number>56</number><length>120000</length><recording id=\"6580e06c-6fd1-47b6-8acd-d18e602a4815\"><title>Riot Squad</title><length>119666</length><disambiguation>1991 remaster</disambiguation></recording></track><track id=\"dfc8ac51-7e04-404a-8dd6-9f99dcd868c1\"><position>57</position><number>57</number><length>181000</length><recording id=\"e734120c-aab0-475f-a70a-af4814ed2a10\"><title>California über alles</title><length>182466</length></recording></track><track id=\"a9f148f9-5d13-4273-995b-85c4965a2463\"><position>58</position><number>58</number><length>116000</length><recording id=\"48568676-b082-4c11-94e9-e20d6d7c1370\"><title>I Remember</title><length>118640</length></recording></track><track id=\"ba9e6205-043b-459e-9825-08fbd8e7eb3a\"><position>59</position><number>59</number><length>121000</length><recording id=\"aa5d4002-0eb5-4f82-b6d0-b39a43d32dcc\"><title>Young ’til I Die</title><length>121000</length></recording></track><track id=\"5bd669c3-6d75-47fd-9520-aeaa3f637aa4\"><position>60</position><number>60</number><length>140000</length><recording id=\"9c21a140-773d-44d7-9a6a-556997115811\"><title>Good Guys (Don't Wear White)</title><length>140000</length></recording></track><track id=\"79d385cb-8d3d-46b7-b59b-ce58ff5ef024\"><position>61</position><number>61</number><length>288000</length><recording id=\"990e2dce-04cb-41f1-aaa6-08e14ac6c4b3\"><title>No Fuckin' War</title><length>288000</length></recording></track><track id=\"2ac1e296-02d1-405a-96ff-23ceb05b3158\"><position>62</position><number>62</number><length>165000</length><recording id=\"dcdff258-b395-418a-a16b-785ad2509449\"><title>Dura Rotina</title><length>165000</length></recording></track><track id=\"767acf83-db27-4fbc-abd1-74b2f0331ac1\"><position>63</position><number>63</number><length>143000</length><recording id=\"50844b4a-6506-429d-ad09-47221cda881b\"><title>Sally</title><length>143000</length></recording></track><track id=\"695a4f92-4c74-4db9-a3c2-a7f06f9c61a9\"><position>64</position><number>64</number><length>123000</length><recording id=\"2ece725f-9539-4a58-91d0-4fb4f82cc333\"><title>Gata</title><length>123000</length></recording></track><track id=\"ae565c86-58ff-4859-9f1e-91276bf08f9c\"><position>65</position><number>65</number><length>132000</length><recording id=\"ca7e986a-1926-4dcf-a665-dbdc3ceecf09\"><title>Borstal Breakout</title><length>131000</length></recording></track><track id=\"a465536e-f3eb-4284-b960-832af9f279b6\"><position>66</position><number>66</number><length>224000</length><recording id=\"fac0c3e3-43af-44ce-ac59-f8c2f480757a\"><title>We Are the Firm</title><length>224000</length></recording></track><track id=\"d257ecbd-728c-4803-a84f-f9e6de748fb7\"><position>67</position><number>67</number><length>192000</length><recording id=\"72a26927-172a-42af-9f3c-025fd38871b6\"><title>Self Conscious Over You</title><length>192000</length></recording></track><track id=\"fe69ef65-443c-4569-b486-2aeb95494e0f\"><position>68</position><number>68</number><title>La victoire sommeille</title><length>205000</length><recording id=\"fcc86799-1b97-4285-a21f-cf43f1a053d5\"><title>La Victoire sommeille</title><length>205000</length></recording></track><track id=\"492bee56-f92d-479c-997c-bdf421d67fe3\"><position>69</position><number>69</number><length>135000</length><recording id=\"a87609dd-0ca6-4bce-ae01-c5d3835b9270\"><title>Latinos migrantes</title><length>135000</length></recording></track><track id=\"203f03b1-bb2a-4912-b4c0-26c72a5eda19\"><position>70</position><number>70</number><length>186000</length><recording id=\"a518df23-1691-4ad3-8c5f-f46ef877dde2\"><title>Vi odio</title><length>186000</length></recording></track><track id=\"61ab7c86-e200-41ac-9b02-b00ae2270c28\"><position>71</position><number>71</number><length>125000</length><recording id=\"76133de0-f371-41d8-a6cc-1b0029aca063\"><title>You</title><length>125000</length></recording></track><track id=\"e5adf1cc-a25c-4250-ba46-c020b6f234b5\"><position>72</position><number>72</number><length>327000</length><recording id=\"9168bf9d-ae15-486d-936c-d16b28984882\"><title>Last Will &amp; Testament</title><length>327000</length></recording></track><track id=\"8e85a9e2-62da-40ef-9985-c61b98d5af64\"><position>73</position><number>73</number><length>188000</length><recording id=\"748f527e-daef-46ba-8aab-ea416549f88f\"><title>Out of My Mind</title><length>187906</length></recording></track><track id=\"7908fb4d-2e65-4b60-a487-faf06f474375\"><position>74</position><number>74</number><length>154000</length><recording id=\"1ab5a9bd-57b9-4598-989f-992e9a538cf6\"><title>Oak Tree</title><length>154000</length></recording></track><track id=\"57ae4851-1c73-49bf-86d9-e068fda7a17f\"><position>75</position><number>75</number><length>90000</length><recording id=\"f3416b3d-d173-41fd-8f62-7bb42dd05872\"><title>La plaga desplazadora</title><length>90000</length></recording></track><track id=\"dd3def54-6e09-4f8c-9f79-fb911886768a\"><position>76</position><number>76</number><length>170000</length><recording id=\"adfd96e2-5b4b-486d-be7e-b10d0ad6e40e\"><title>Alting går i sort</title><length>170000</length></recording></track><track id=\"5b899612-0686-414b-a530-35be48794ccd\"><position>77</position><number>77</number><length>345000</length><recording id=\"3292eced-1eaf-4b75-b1e1-8a1ba9d5ff9a\"><title>Coming Home</title><length>344666</length></recording></track><track id=\"3dbc44b9-d0fa-4f24-9399-4b6791d1d4dd\"><position>78</position><number>78</number><length>183000</length><recording id=\"6ad03605-6ab8-4a89-b7d2-25741fd84c59\"><title>Here Today</title><length>182000</length></recording></track><track id=\"52b4a028-080e-4f08-9254-0f519ea1dd0b\"><position>79</position><number>79</number><length>92000</length><recording id=\"07dc2503-b613-4510-a1b0-f7e356628e73\"><title>Police Bastard</title><length>92000</length></recording></track><track id=\"c61dfe53-5e11-48cc-9b95-76bca5eaa02b\"><position>80</position><number>80</number><length>99000</length><recording id=\"f6eadfcd-9b61-4ae4-8134-f6d068126b12\"><title>Traitor</title><length>99000</length></recording></track><track id=\"215e3149-202d-4c77-9506-5cf51b3b037d\"><position>81</position><number>81</number><length>172000</length><recording id=\"f02a0d89-d68f-4a4d-8213-3d24d4bdb2f6\"><title>Complacency Is Dead</title><length>172000</length></recording></track><track id=\"069cc5e1-b707-4450-9a27-b806d0fe50a8\"><position>82</position><number>82</number><length>142000</length><recording id=\"9296962f-1772-44e3-9e55-3b3122107e6d\"><title>Ums Ganze</title><length>142000</length></recording></track><track id=\"4958633d-ec0e-4593-a419-8f76b3d88a71\"><position>83</position><number>83</number><length>82000</length><recording id=\"4db53851-dd74-4048-9a83-0c649bf479f8\"><title>Nazi Punks Fuck Off</title><length>81000</length></recording></track><track id=\"c0de8f13-590d-49ec-8115-5845169005ff\"><position>84</position><number>84</number><length>161000</length><recording id=\"23e758aa-1729-47b3-9b90-9dff7bd34750\"><title>I'm a Bloody Fool</title><length>161000</length></recording></track><track id=\"79603b96-bd0f-4cde-b238-feb2909c9726\"><position>85</position><number>85</number><length>185000</length><recording id=\"df292ecb-9079-4d63-93df-ee154636ca6b\"><title>Dead Smart</title><length>184506</length></recording></track><track id=\"f3829600-cf7b-44a2-a9a5-1daf48a6e4cc\"><position>86</position><number>86</number><length>82000</length><recording id=\"82dafdd6-0e47-4eb1-85c7-025c46360e7c\"><title>Evacuation</title><length>82000</length></recording></track><track id=\"3ad84a5e-c426-48fc-82c7-b19751669cd1\"><position>87</position><number>87</number><length>142000</length><recording id=\"899f11c8-12a3-44c4-aed5-b3640797625c\"><title>Jeden cel a tak daleko</title><length>142000</length></recording></track><track id=\"2692af53-edbd-417e-8c93-5999822c79e2\"><position>88</position><number>88</number><length>51000</length><recording id=\"5833996f-6a51-44f9-b6ff-05a82f78fc14\"><title>Social Nihilism</title><length>51000</length></recording></track><track id=\"65e1ad24-9f40-4047-a3ec-bdfb3748b010\"><position>89</position><number>89</number><length>160000</length><recording id=\"7434c70c-bc35-4472-a499-2d15f5a96c4e\"><title>Still Jolly After All These Years</title><length>160000</length></recording></track><track id=\"011677b0-160a-4c0c-8bbb-5f3277e39c95\"><position>90</position><number>90</number><length>185000</length><recording id=\"0c0df351-fdd5-49bd-980c-a1d868c1af25\"><title>Sequoia Song</title><length>185000</length></recording></track><track id=\"f5a23806-2319-42fc-8934-2c252a037823\"><position>91</position><number>91</number><length>126000</length><recording id=\"c04cf343-bedb-4d19-9a08-a8ea91d48079\"><title>June Flew</title><length>126000</length></recording></track><track id=\"655cb864-b276-40b3-87e3-25ab89f2a32d\"><position>92</position><number>92</number><length>236000</length><recording id=\"46f33302-3e1d-4ac2-a09c-81c22f1e4199\"><title>Nosebleed of Dawn</title><length>236000</length></recording></track><track id=\"8f4264ef-7011-4444-bc7b-893348a31213\"><position>93</position><number>93</number><length>186000</length><recording id=\"40173313-b2d9-4c13-aea7-cc58f1191aae\"><title>No One Dies Alone</title><length>186000</length></recording></track><track id=\"66a30f17-36b8-488f-87f8-d842290d5c25\"><position>94</position><number>94</number><length>37000</length><recording id=\"e115fe7a-eeb3-487b-b772-ed3c6074eef8\"><title>Youth Attack!</title><length>37000</length></recording></track><track id=\"1bbaa85e-f0b2-402b-9dd9-1edcb7d43d8b\"><position>95</position><number>95</number><length>89000</length><recording id=\"fb568b0c-466a-4d10-956c-e1238683f3d6\"><title>Eran Profit, Våran Död</title><length>89000</length></recording></track><track id=\"37580f38-2612-4897-9bfe-83d0d877bf26\"><position>96</position><number>96</number><length>82000</length><recording id=\"921f1d23-dd6e-4b49-8210-da9b93b198f2\"><title>Kom</title><length>82000</length></recording></track><track id=\"afe7d215-ddb1-4ebb-bb57-64c606eed8ec\"><position>97</position><number>97</number><length>50000</length><recording id=\"77da7ebd-c9bd-4900-8f32-fd097c229e5b\"><title>Meatman</title><length>47000</length></recording></track><track id=\"5cb743de-f12d-44eb-bb5e-dfe6aabb985e\"><position>98</position><number>98</number><length>90000</length><recording id=\"bd5f7779-6ff4-4594-94ff-a71d9f5c3edc\"><title>Hardcore by the Book</title><length>90000</length></recording></track><track id=\"84cf840b-b7a4-40d1-ad8b-467c40cc6a28\"><position>99</position><number>99</number><length>357000</length><recording id=\"c97a47f2-ee65-4684-82d2-7019b45b1adb\"><title>Civilized Worm</title><length>357000</length></recording></track><track id=\"9011683e-a69a-4ed7-8023-dcc3b719beb5\"><position>100</position><number>100</number><length>484000</length><recording id=\"493852d5-8dc7-4667-b032-7d922ab64ec5\"><title>The Beginning and the End</title><length>481960</length></recording></track><track id=\"64957f4b-cae1-48d4-9061-235182ccf33d\"><position>101</position><number>101</number><length>263000</length><recording id=\"9ea43c5f-09f4-4fee-82a3-597b5baef9a2\"><title>To Walk Alone</title><length>262000</length></recording></track><track id=\"c39488e5-96b9-46cd-b8e0-d0e38e642e6e\"><position>102</position><number>102</number><length>408000</length><recording id=\"8cec625d-1e89-4623-987f-79329a9a0199\"><title>Angel Ranger</title><length>408000</length></recording></track><track id=\"1ac5f87b-68c9-42e6-8ce9-c6b49ec2f4ed\"><position>103</position><number>103</number><length>268000</length><recording id=\"4fa7a11f-1ff4-4a3a-b12d-9c04d7d64b1c\"><title>Zakrztuś Się Władzą</title><length>268000</length></recording></track><track id=\"3fcce0c1-2656-4084-974f-7853f9d6d9aa\"><position>104</position><number>104</number><length>146000</length><recording id=\"e8f4edd2-5737-417b-8e6b-98d3dbeab7c1\"><title>Inquisition</title><length>146000</length></recording></track><track id=\"7f429ad4-5e30-47bb-9ca2-85faec27e0b3\"><position>105</position><number>105</number><length>230000</length><recording id=\"0f25a70c-8251-46c5-8b96-13a5b4da809b\"><title>Waiting for Mary</title><length>230000</length></recording></track><track id=\"8de0bb06-bd07-4108-917f-0ab258f45e2b\"><position>106</position><number>106</number><length>275000</length><recording id=\"99fd2fa0-4802-45e1-b769-beb75cadd154\"><title>Sacrifice</title><length>275000</length></recording></track><track id=\"5348f737-6494-4717-bc3e-19c710a7f41f\"><position>107</position><number>107</number><length>309000</length><recording id=\"c5d005f8-37eb-4fa6-a228-d11b51d3801d\"><title>Now</title><length>309000</length></recording></track><track id=\"09805cb6-8fea-40ef-99e4-ef091a031c90\"><position>108</position><number>108</number><length>294000</length><recording id=\"e5369816-f085-4472-a941-879133f41963\"><title>Jassica</title><length>294000</length></recording></track><track id=\"c895e778-5b83-4ffc-bf70-b13c3a1c9e19\"><position>109</position><number>109</number><length>296000</length><recording id=\"9fdbca3c-0adf-4d43-8464-c71317d4245c\"><title>TV Show (Hang the Police)</title><length>296000</length></recording></track><track id=\"6c81e235-7bfe-486d-8d60-efc156b2869c\"><position>110</position><number>110</number><length>254000</length><recording id=\"70ca906f-4671-46d2-bd1e-f5d74e00375e\"><title>Whoever Has Such a Treasure Is Not Always Worried About Those Who Do Not</title><length>254000</length></recording></track><track id=\"698b7083-f277-4584-8415-4ae316cfd901\"><position>111</position><number>111</number><length>138000</length><recording id=\"e4212fea-3486-4962-940a-9e6ffdce68f1\"><title>Deeper Than Inside</title><length>137400</length></recording></track><track id=\"7ded2621-aa56-47a8-b5ea-b61062c7e443\"><position>112</position><number>112</number><length>158000</length><recording id=\"4dfb821b-c3f1-4625-99db-d211d7f46a84\"><title>Money</title><length>157893</length></recording></track><track id=\"ecd79a91-d342-4ca7-93dd-f0d638f8616a\"><position>113</position><number>113</number><length>256000</length><recording id=\"3f0bd23d-0f71-40a8-8407-5fb31d9421ba\"><title>Turnover</title><length>256026</length></recording></track><track id=\"8f7b3171-c153-4c03-b5c8-031b7032864b\"><position>114</position><number>114</number><length>202000</length><recording id=\"a571b325-fed8-48c3-82ab-7b0d4a2c3055\"><title>Wiederholungszwang</title><length>202000</length></recording></track><track id=\"1d6593e4-da45-4033-bf3d-e40876dd8feb\"><position>115</position><number>115</number><length>324000</length><recording id=\"10e1db67-0a00-432f-9230-c868902e1c5e\"><title>Dad's Wings</title><length>324000</length></recording></track><track id=\"5944ecd5-755b-498f-b80a-2a959e7d6792\"><position>116</position><number>116</number><length>173000</length><recording id=\"554d52de-323a-4693-86a1-5bcf799b4093\"><title>Choose</title><length>173000</length></recording></track><track id=\"b3088251-bf78-4d2f-88f6-38e4ae8aa6c7\"><position>117</position><number>117</number><length>181000</length><recording id=\"0a0232c3-6a70-4f4a-b3b9-9c235397effd\"><title>Left Hand</title><length>181000</length></recording></track><track id=\"5ae8c16c-1fdf-4326-b1d1-e0ec8b1456c1\"><position>118</position><number>118</number><length>134000</length><recording id=\"7a660ae3-975b-4713-9115-065642d1de5b\"><title>New Jersey vs. Valhalla</title><length>134000</length></recording></track><track id=\"a677d64d-e628-4edb-a5f0-44bcd5248dbd\"><position>119</position><number>119</number><length>158000</length><recording id=\"551818a2-3f82-4d45-81a5-2fc105fb504a\"><title>Wishful Thinking</title><length>158000</length></recording></track><track id=\"1d8872b3-c98d-4e41-907a-999022368e7e\"><position>120</position><number>120</number><length>92000</length><recording id=\"9a06b5ba-9cd9-41eb-8410-fa1f96b4f241\"><title>Above Grey Clouds</title><length>92000</length></recording></track><track id=\"f1a952ba-3344-4e95-aa37-001e2ab4937f\"><position>121</position><number>121</number><length>231000</length><recording id=\"ab1b1588-40b1-4ea4-ad51-36b501edd381\"><title>What Do You Mean?</title><length>231000</length></recording></track><track id=\"0b4b68a2-5804-46a6-b05c-34879302fd5e\"><position>122</position><number>122</number><length>240000</length><recording id=\"2969b85b-afe9-43a5-b7db-0db2fe13ffce\"><title>Невозможно молчать</title><length>240000</length></recording></track><track id=\"363d7c89-db81-469a-89ab-072069a42304\"><position>123</position><number>123</number><length>193000</length><recording id=\"3ddfedd5-a3e3-447f-9f9e-d44324e5cd5a\"><title>Under the Radar</title><length>193000</length></recording></track><track id=\"9bb55c40-b779-4822-a258-532034519455\"><position>124</position><number>124</number><length>209000</length><recording id=\"62cb3cca-4b0c-48eb-a81d-5479073ca3d5\"><title>Dreaming Drowning</title><length>209000</length></recording></track><track id=\"787a2106-c03d-4f16-96b8-a62cbd9b8a9d\"><position>125</position><number>125</number><length>276000</length><recording id=\"017d8e08-4b7c-4378-99b5-6c010e558f53\"><title>El último aliento</title><length>276000</length></recording></track><track id=\"e173d7fc-9acb-444d-bd68-335306231768\"><position>126</position><number>126</number><length>147000</length><recording id=\"d290bb02-9341-4162-8b6e-9341bbf28c7b\"><title>Half Lit World</title><length>147000</length></recording></track><track id=\"c4e240bc-c823-49ac-b1a1-a5a4ce1904cf\"><position>127</position><number>127</number><length>156000</length><recording id=\"d970f2c9-eda8-4385-97f4-a7bb828a9d83\"><title>Τελευταίες Κραυγές</title><length>156000</length></recording></track><track id=\"3df13ad0-71d3-48e8-93c2-e46a1e8c95c3\"><position>128</position><number>128</number><length>209000</length><recording id=\"bf232ed1-cfdd-4414-a9e8-ffdb7ff3aa36\"><title>The End Is Near</title><length>209000</length></recording></track><track id=\"e37db415-4a4f-4746-8183-672bfd0a19da\"><position>129</position><number>129</number><length>134000</length><recording id=\"04b911a5-72db-4b02-a043-e86ce81b674d\"><title>Caravan</title><length>134000</length></recording></track><track id=\"f80a711e-97fd-447e-83c3-a46cbfa6d480\"><position>130</position><number>130</number><length>137000</length><recording id=\"3965cfe5-d2f8-4b80-8264-f390785bac4a\"><title>Banzai Washout</title><length>137000</length></recording></track><track id=\"e7dbbfdb-38af-43c9-bf97-486f790dab81\"><position>131</position><number>131</number><length>150000</length><recording id=\"031b4de6-2879-45e8-8cc3-788004ad5b82\"><title>Moon Dawg</title><length>150000</length></recording></track><track id=\"d60f5275-1df0-4956-84f2-fc41840eab98\"><position>132</position><number>132</number><length>158000</length><recording id=\"997eef3d-9295-4ab7-a193-710484c2d535\"><title>Nessuno mi può giudicare</title><length>158000</length></recording></track><track id=\"d380cd23-7b15-4a7e-9d2d-e315cf7d3d8a\"><position>133</position><number>133</number><length>155000</length><recording id=\"6859252e-acab-4e6c-ba31-9bce96f93724\"><title>Escape From Gulag 17</title><length>155000</length></recording></track><track id=\"172fe8af-a3f5-4e26-896c-b73584692fb3\"><position>134</position><number>134</number><length>152000</length><recording id=\"9eb62259-21e0-4276-9101-284097889a27\"><title>Hochzeit in Bistritja</title><length>152000</length></recording></track><track id=\"22462cfb-1ddd-442a-a81c-02c2693692da\"><position>135</position><number>135</number><length>160000</length><recording id=\"ad590691-4a38-4241-a998-087cac6418c8\"><title>The Witch</title><length>161000</length></recording></track><track id=\"0b65b983-b928-4fca-92b3-b640c39295bf\"><position>136</position><number>136</number><length>150000</length><recording id=\"f0cd9be0-eebf-4896-80a3-a7c6d0ac187d\"><title>Heart Full of Soul</title><length>149000</length></recording></track><track id=\"cd1ddaeb-3f90-4dbe-bdff-947de899a991\"><position>137</position><number>137</number><length>87000</length><recording id=\"c6009c0a-611a-4bde-afba-616a329a4aea\"><title>Boys Are Boys and Girls Are Choice</title><length>86000</length></recording></track><track id=\"e5290f3b-c941-4e70-ba59-14533ba83a4a\"><position>138</position><number>138</number><length>120000</length><recording id=\"ced9a020-92f4-4129-8861-1f62ba3594ab\"><title>Nonverbal Adjective Agreement</title><length>120000</length></recording></track><track id=\"b1c0572a-3c28-4d36-b196-f5855e5c6c32\"><position>139</position><number>139</number><length>239000</length><recording id=\"24c0f365-2e37-4ad8-97de-6d25c3a24cf6\"><title>Soul Hunters</title><length>239000</length></recording></track><track id=\"d481d178-0d46-473b-a2e3-99fa445233e3\"><position>140</position><number>140</number><length>186000</length><recording id=\"d683c528-2dc1-4447-a7bf-0fea8971f5ac\"><title>The Walnut Tree</title><length>186000</length></recording></track><track id=\"94715531-5a8c-480a-9c50-75efdcd572d3\"><position>141</position><number>141</number><length>231000</length><recording id=\"b07e51c6-5254-411a-8871-1f5dc20ebde1\"><title>Queen of Pain</title><length>230360</length></recording></track><track id=\"0e25ef94-3cfa-4fbd-947a-bd9de1c23a2e\"><position>142</position><number>142</number><length>183000</length><recording id=\"c9a4cc9f-d265-47d1-ac97-0c2e81bac3c3\"><title>When Death Rides a Horse</title><length>183000</length></recording></track><track id=\"ef0fff21-babd-40c4-b8b0-17eb3c9df27d\"><position>143</position><number>143</number><length>179000</length><recording id=\"d302e165-c16d-4411-af45-e807ef950426\"><title>Rot in Hell!</title><length>177200</length></recording></track><track id=\"9631df75-d7aa-4a49-b94d-b6fefeeccfe9\"><position>144</position><number>144</number><length>338000</length><recording id=\"a859c255-4e77-4a93-aa90-6138ef250ad7\"><title>Born, Raised, Passed Away (In East L.A.)</title><length>338000</length></recording></track><track id=\"77662fbb-f939-4282-8a76-b98484e7c3a5\"><position>145</position><number>145</number><length>149000</length><recording id=\"934dc2e0-735d-4e47-b22a-f8a5721791a4\"><title>8 Millions God</title><length>149000</length></recording></track><track id=\"0dbd6d3b-ab58-44b7-961d-7ce581b1650f\"><position>146</position><number>146</number><length>239000</length><recording id=\"4e9df5f9-0ea9-4e60-9a07-5af68fdb2f8d\"><title>Lonely Old Soul</title><length>239000</length></recording></track><track id=\"a0cfc264-7c3c-4daa-aef2-1452d88772e0\"><position>147</position><number>147</number><length>311000</length><recording id=\"b4daf744-47fd-491d-ba06-14d5ac9a9af7\"><title>Dracula Mountain</title><length>311000</length></recording></track><track id=\"2d9e4029-9929-4a1c-b1da-989c6dfb54e7\"><position>148</position><number>148</number><length>260000</length><recording id=\"2b7fd4f4-d994-4706-90e8-575b34911187\"><title>To Parter</title><length>260000</length></recording></track><track id=\"55361bd4-10ab-40c3-96fd-4ea4ecee6227\"><position>149</position><number>149</number><length>72000</length><recording id=\"b3c092eb-37d1-4e07-8a68-d9c999d3d703\"><title>Moth‐Eaten Deer Head</title><length>72000</length></recording></track><track id=\"e0240cdc-9e3f-4283-bec4-bd8b63d4e839\"><position>150</position><number>150</number><length>104000</length><recording id=\"f5ab4e10-efea-4c81-a9a8-87a858b2fae0\"><title>Itsuwari</title><length>104000</length></recording></track><track id=\"687bdbff-392a-4401-9536-ab696fcf36a1\"><position>151</position><number>151</number><length>173000</length><recording id=\"ab92a178-0df9-4d15-b7f0-dcdbbc37fbfa\"><title>La saponatrice di ferrara</title><length>173000</length></recording></track><track id=\"55dc2cfa-6be1-4b2e-a114-d65b2a554db8\"><position>152</position><number>152</number><length>135000</length><recording id=\"9d928ac0-d398-4494-a695-e186ee632db0\"><title>Nightmares on Crack St.</title><length>135000</length></recording></track><track id=\"fe5f46c0-387f-4250-8769-001a1ef6e2dd\"><position>153</position><number>153</number><length>157000</length><recording id=\"d856b38b-11a4-4464-9455-2af7daeadc6e\"><title>Promises</title><length>155000</length></recording></track><track id=\"7139802f-a8d2-4034-a2fd-2b425a03086f\"><position>154</position><number>154</number><length>119000</length><recording id=\"06cfdbd7-72ef-424e-a94d-678b5aa33a3c\"><title>I Hate You, I Love You</title><length>119000</length></recording></track><track id=\"79e4a218-2d3b-4488-92ec-886aa5bfa451\"><position>155</position><number>155</number><length>177000</length><recording id=\"63c38959-dbd1-4aae-b7b6-ed24311b9e90\"><title>My Right</title><length>177000</length></recording></track><track id=\"6d6ed63c-8840-4c03-a5ca-abeb37efdf77\"><position>156</position><number>156</number><length>186000</length><recording id=\"b81cc028-09f6-41b9-83bc-2a780afa38d7\"><title>Not Happiness</title><length>186000</length></recording></track><track id=\"db5cb663-a486-4e3e-9469-acfbbb724ff9\"><position>157</position><number>157</number><length>188000</length><recording id=\"0163e0f0-2a27-4ffc-a4d1-4312806449a6\"><title>Blind</title><length>188000</length></recording></track><track id=\"e87734fd-30d1-4243-8e35-60549c2e7bb6\"><position>158</position><number>158</number><length>73000</length><recording id=\"2bcac15d-3f90-458e-b1fd-5322e3691276\"><title>Desquicio</title><length>73000</length></recording></track><track id=\"a9de7f9b-3f3d-4caa-83e4-dd12b731324a\"><position>159</position><number>159</number><length>345000</length><recording id=\"746633f1-0e5a-4bd8-b103-d993efe36c78\"><title>Wipeout Beat</title><length>345000</length></recording></track><track id=\"1159dd28-7aa9-481b-84ea-1f8da5b67fda\"><position>160</position><number>160</number><length>215000</length><recording id=\"3cc2a8c0-d75a-420c-91d0-ab9c928b4b90\"><title>Mongoloid</title><length>215000</length></recording></track><track id=\"58b8bbe5-6c01-42cf-8b4a-7ad166c4843f\"><position>161</position><number>161</number><length>196000</length><recording id=\"f04e86b5-6164-4008-b1ac-28e5f7282839\"><title>Assassin</title><length>196200</length></recording></track><track id=\"e0bd93d9-c8c2-4ba9-90db-9e54092b19ca\"><position>162</position><number>162</number><length>168000</length><recording id=\"5bed600f-8fe9-402b-ac68-c3a759205774\"><title>Siniaki</title><length>168000</length></recording></track><track id=\"762ebc95-32d8-4eaf-966e-a13332c475b4\"><position>163</position><number>163</number><length>226000</length><recording id=\"5eec7c23-5469-4ba5-a3ab-6c8e138cb4ce\"><title>Flooded Grass</title><length>226000</length></recording></track><track id=\"35ccdf95-53ba-4445-904b-28a3a03519d7\"><position>164</position><number>164</number><length>262000</length><recording id=\"e9646989-80f4-4ea5-82c4-8543fe6b8832\"><title>Намести фризура и гладувај</title><length>261866</length></recording></track><track id=\"c5205028-aae4-4090-a23c-0a2727d1f3c8\"><position>165</position><number>165</number><length>153000</length><recording id=\"acf0777f-356f-4f22-8dd4-97143bb10f41\"><title>Streams of Whiskey</title><length>152960</length></recording></track><track id=\"8e565ae8-2762-421c-83dd-365af6253629\"><position>166</position><number>166</number><length>176000</length><recording id=\"f5370d5d-62bf-4cfa-943f-441ff0f2c121\"><title>Girlz on the Fiddle</title><length>176000</length></recording></track><track id=\"ad55d409-65f6-4a4d-a947-91a74b9619aa\"><position>167</position><number>167</number><length>190000</length><recording id=\"59f992ca-ef3e-4872-ad15-31aca2e0b073\"><title>Are You Drinkin’ With Me Jesus</title><length>190000</length></recording></track><track id=\"b8e90356-2d84-42c9-a0eb-3b2e6d07c15b\"><position>168</position><number>168</number><length>226000</length><recording id=\"5bc00034-005f-4663-9abd-b740a37a387d\"><title>Warsaw Is Khelm</title><length>225000</length></recording></track><track id=\"b593448a-0905-4149-8f65-d282cc8a1cb2\"><position>169</position><number>169</number><length>330000</length><recording id=\"ebfcca78-1bfc-452b-b6f1-2b5e414dd75e\"><title>I Can't Love This Country</title><length>330000</length></recording></track><track id=\"382ac653-74be-4d73-8681-3b51e3b19760\"><position>170</position><number>170</number><length>299000</length><recording id=\"d7207feb-244d-4afe-a448-6f4ecad2a9ee\"><title>Самокрутка</title><length>299000</length></recording></track><track id=\"c8cadb09-ff96-4c78-9526-ee6164b29e19\"><position>171</position><number>171</number><length>95000</length><recording id=\"ba4d0d09-fb4e-41e4-ac51-e98a94675c68\"><title>All You Fascists</title><length>95000</length></recording></track><track id=\"79c2325c-dd57-439c-b5d7-300833ac1653\"><position>172</position><number>172</number><length>171000</length><recording id=\"50f68013-0cd7-4c58-86b3-f600951411df\"><title>Bratříčku, zavírej vrátka</title><length>171000</length></recording></track><track id=\"62bdd1a9-2789-445b-bc7e-1825a9036e71\"><position>173</position><number>173</number><length>164000</length><recording id=\"ae43dbbf-41c2-473c-95e2-ae170faddd47\"><title>Особый резон</title><length>164000</length></recording></track><track id=\"6a082119-35c6-4efc-93bb-822dfb4f4155\"><position>174</position><number>174</number><length>154000</length><recording id=\"ce2279da-ac69-4585-87ca-55206856c055\"><title>To Have and to Have Not</title><length>153493</length></recording></track><track id=\"16c209c4-f0d9-43e0-ad51-3500f76873cf\"><position>175</position><number>175</number><length>265000</length><recording id=\"20ae5081-442c-4c7b-b554-ffd833f7f817\"><title>Forever at Sea</title><length>265000</length></recording></track><track id=\"9030815d-f32a-4fd2-a9ce-b4784a6cb497\"><position>176</position><number>176</number><length>346000</length><recording id=\"9545e74b-65ef-40c6-91eb-ed86db74a999\"><title>Amor Enkapuchado</title><length>346000</length></recording></track><track id=\"2ac38d81-53a2-443e-80b3-11fb48ec8cf6\"><position>177</position><number>177</number><length>143000</length><recording id=\"80f60e7a-27ed-4560-b3b6-23893c786ed8\"><title>I Wouldn't Want to Live in a World Without Grudges</title><length>143000</length></recording></track><track id=\"064a008e-8050-42f2-93af-8615001e2614\"><position>178</position><number>178</number><length>274000</length><recording id=\"d1aac4f5-bf27-40e7-8bc0-766e4305dd38\"><title>Sex Changes</title><length>274000</length></recording></track><track id=\"eee53c62-d2bf-41af-a897-90da4c60589f\"><position>179</position><number>179</number><length>190000</length><recording id=\"fc50c007-01a3-4036-999e-0ae10d4d5971\"><title>Hystérie connective</title><length>190000</length></recording></track><track id=\"c6435688-b34b-4a09-af98-9bfa1b2803bd\"><position>180</position><number>180</number><length>165000</length><recording id=\"628e17f0-fdfd-4033-8f60-883f42b7766c\"><title>J'suis punk</title><length>165000</length></recording></track><track id=\"9951e042-b220-4e21-ac43-c7df693a8f1b\"><position>181</position><number>181</number><length>106000</length><recording id=\"6c97543f-cd12-40c5-b3d5-8524e5d3b512\"><title>Killer Man</title><length>106000</length></recording></track><track id=\"6b2f8977-f079-46e6-975f-f8fe63f38f0a\"><position>182</position><number>182</number><length>281000</length><recording id=\"fab32d63-51f7-42c0-bbd4-769d1f361ee9\"><title>Hôpital (live)</title><length>281000</length></recording></track><track id=\"bb1a0773-bb16-4e1f-910c-90be57c8afe2\"><position>183</position><number>183</number><length>212000</length><recording id=\"7736341c-932f-48b2-a9d0-162e11a87376\"><title>Edith Nylon</title><length>212000</length></recording></track><track id=\"52feb395-2d15-4111-9f77-2856195c8176\"><position>184</position><number>184</number><length>221000</length><recording id=\"ac4c1080-06fe-4a75-8899-6894cba3fed9\"><title>Né pour crever</title><length>221000</length></recording></track><track id=\"392a5ae9-20cd-42b5-bb08-05539391f334\"><position>185</position><number>185</number><length>94000</length><recording id=\"b823f1ea-baa8-4006-a0ed-f0b1a30dd407\"><title>Ton meilleur ami</title><length>94000</length></recording></track><track id=\"aed8f071-e71e-463f-9285-070b7ac049f4\"><position>186</position><number>186</number><length>231000</length><recording id=\"9d43e9ed-9dbd-47bb-a527-e4e21d4f2d83\"><title>Espoirs déçus</title><length>231000</length></recording></track><track id=\"2d7be0f1-16e8-439a-b024-30f56c4bab5f\"><position>187</position><number>187</number><length>96000</length><recording id=\"cb3702d7-dc5f-4861-bc00-de839534632a\"><title>Varsovie</title><length>93773</length></recording></track><track id=\"85e1de58-35b8-4e94-9a86-931c66ebdfa6\"><position>188</position><number>188</number><length>213000</length><recording id=\"03ad1807-c619-48e9-a685-39c030471be8\"><title>Crazy Voodoo Woman</title><length>213000</length></recording></track><track id=\"c3431735-ded5-49be-9e5b-c5a59f74e633\"><position>189</position><number>189</number><length>166000</length><recording id=\"e09fe3e6-bfbe-4837-9dcb-6bc7aa730da2\"><title>Pile ou face</title><length>164000</length></recording></track><track id=\"cf8b2560-6103-40e0-9931-c698e517189f\"><position>190</position><number>190</number><length>207000</length><recording id=\"e0ea0872-7c29-4add-8238-be9eeef16c23\"><title>Qui jettera la dernière pierre ?</title><length>207000</length></recording></track><track id=\"22fde526-b0fe-41e7-b061-0461aa9c5905\"><position>191</position><number>191</number><length>243000</length><recording id=\"277286f8-fd4b-4009-bd7f-17bc348db325\"><title>Okinawa</title><length>242800</length></recording></track><track id=\"b7a5a3d6-f93b-4cf9-81e6-d3bdd9eea436\"><position>192</position><number>192</number><length>199000</length><recording id=\"a6b19bc4-ae65-4eaa-900b-c0469a6788b2\"><title>Leyla</title><length>199000</length></recording></track><track id=\"7599e8f4-42fd-4461-82f6-3fa533b53d41\"><position>193</position><number>193</number><length>197000</length><recording id=\"0a763b90-01e0-41d6-bc54-bc89bd7b288b\"><title>L'amour est enfant de bohême</title><length>197000</length></recording></track><track id=\"2a09e0c7-f714-4293-83b5-5d58ce5851c7\"><position>194</position><number>194</number><length>204000</length><recording id=\"b60e09c6-fd39-43a3-b07d-6ffb5c6eaac3\"><title>Avorter n’est pas tuer</title><length>204000</length></recording></track><track id=\"8d538483-5645-45cd-953d-d551534c5489\"><position>195</position><number>195</number><length>289000</length><recording id=\"32f0af10-4591-4582-b1af-9bfd49bafdb6\"><title>Atlantique Nord</title><length>289000</length></recording></track><track id=\"f950efef-4878-403c-8d7b-b3960b58f68a\"><position>196</position><number>196</number><length>123000</length><recording id=\"eea90481-d485-4b97-a150-550e087dfc37\"><title>Espèce humaine</title><length>123000</length></recording></track><track id=\"8074491c-baa0-4da9-a943-c522f43f2562\"><position>197</position><number>197</number><length>254000</length><recording id=\"8718fe3f-c1c8-4b72-8a63-ac803335599c\"><title>Exilés</title><length>254000</length></recording></track><track id=\"0f1c0588-4d82-4da4-a964-93bd668b90b6\"><position>198</position><number>198</number><title>Radio Paris</title><length>119000</length><recording id=\"93a6ac56-6757-419c-ae7a-c7d88864b4a7\"><title>Radio-Paris</title><length>119000</length></recording></track></data-track-list></medium></medium-list></release></metadata>"
  },
  {
    "path": "test/data/release/a81f3c15-2f36-47c7-9b0f-f684a8b0530f-recordings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><release id=\"a81f3c15-2f36-47c7-9b0f-f684a8b0530f\"><title>Bored Bored</title><status>Official</status><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><date>1978</date><country>GB</country><medium-list count=\"1\"><medium><position>1</position><track-list count=\"2\" offset=\"0\"><track><position>1</position><number>A</number><recording id=\"537be2e7-3dcd-48dc-98ca-f4bc0fb8f573\"><title>Bored Bored</title></recording></track><track><position>2</position><number>B</number><recording id=\"03f1eba5-f447-4dff-b125-2971534e0900\"><title>Time Warp</title></recording></track></track-list></medium></medium-list></release></metadata>"
  },
  {
    "path": "test/data/release/b66ebe6d-a577-4af8-9a2e-a029b2147716-recordings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><release id=\"b66ebe6d-a577-4af8-9a2e-a029b2147716\"><title>My Album</title><quality>normal</quality><medium-list count=\"1\"><medium><position>1</position><track-list count=\"4\" offset=\"0\"><track><position>1</position><number>1</number><recording id=\"68d364bc-9046-4ec7-887e-c8db094d3161\"><title>Some track</title><length>180000</length></recording></track><track><position>2</position><number>2</number><length>279000</length><recording id=\"9ec880e5-ecdf-4bf4-825b-53118d0bbd4f\"><title>Another track</title><length>279000</length></recording></track><track><position>3</position><number>3</number><length>60000</length><recording id=\"d359986c-12f1-4c89-b822-55c791d6d601\"><title>One more</title><length>80000</length></recording></track><track><position>4</position><number>4</number><recording id=\"b48cf74d-4a84-4717-a291-6993e4d88c22\"><title>Last track</title></recording></track></track-list></medium></medium-list></release></metadata>"
  },
  {
    "path": "test/data/release/fbe4490e-e366-4da2-a37a-82162d2f41a9-recordings+artist-credits.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><release id=\"fbe4490e-e366-4da2-a37a-82162d2f41a9\"><title>Suzuki Piano School, Volume 2 (feat. piano: Haruko Katakoa)</title><status>Official</status><packaging>Jewel Case</packaging><quality>normal</quality><text-representation><language>eng</language><script>Latn</script></text-representation><artist-credit><name-credit><artist id=\"08809019-2a31-4b5c-928a-d57b7742b224\"><name>Suzuki Method International</name><sort-name>Suzuki Method International</sort-name></artist></name-credit></artist-credit><country>US</country><barcode>029156150346</barcode><asin>087487498X</asin><medium-list count=\"1\"><medium><position>1</position><track-list count=\"14\" offset=\"0\"><track><position>1</position><number>1</number><length>195040</length><artist-credit><name-credit><name>J. A. Hummel</name><artist id=\"f7ef501b-2bc0-4083-ac52-3518255883a2\"><name>Johann Nepomuk Hummel</name><sort-name>Hummel, Johann Nepomuk</sort-name></artist></name-credit></artist-credit><recording id=\"c66bda20-4efe-4589-b643-f247c17de337\"><title>Ecossaise</title><length>195000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>2</position><number>2</number><length>211133</length><artist-credit><name-credit><name>H. Lichner</name><artist id=\"e3877cf0-6855-41cf-85b2-fcbac3780552\"><name>Heinrich Lichner</name><sort-name>Lichner, Heinrich</sort-name><disambiguation>German composer</disambiguation></artist></name-credit></artist-credit><recording id=\"1160e71c-8514-412a-a52f-b03e7ce080e4\"><title>A Short Story</title><length>211000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>3</position><number>3</number><length>176960</length><artist-credit><name-credit><name>R. Schumann</name><artist id=\"3cd3882c-00f8-4362-a0c2-ad89ed248533\"><name>Robert Schumann</name><sort-name>Schumann, Robert</sort-name><disambiguation>German classical composer</disambiguation></artist></name-credit></artist-credit><recording id=\"08226eba-964f-4fdd-bb88-9aecafca712c\"><title>The Happy Farmer</title><length>177000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>4</position><number>4</number><length>286040</length><artist-credit><name-credit><name>J.S. Bach</name><artist id=\"24f1766e-9635-4d58-a4d4-9413f9f98a4c\"><name>Johann Sebastian Bach</name><sort-name>Bach, Johann Sebastian</sort-name></artist></name-credit></artist-credit><recording id=\"2bb629e9-d1c5-49b3-9b64-e82a38bb608e\"><title>Minuet 1</title><length>286000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>5</position><number>5</number><length>434200</length><artist-credit><name-credit><name>J.S. Bach</name><artist id=\"24f1766e-9635-4d58-a4d4-9413f9f98a4c\"><name>Johann Sebastian Bach</name><sort-name>Bach, Johann Sebastian</sort-name></artist></name-credit></artist-credit><recording id=\"0db8335f-a605-435f-84dd-419680e3a562\"><title>Minuet 2</title><length>434000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>6</position><number>6</number><length>379600</length><artist-credit><name-credit><name>J.S. Bach</name><artist id=\"24f1766e-9635-4d58-a4d4-9413f9f98a4c\"><name>Johann Sebastian Bach</name><sort-name>Bach, Johann Sebastian</sort-name></artist></name-credit></artist-credit><recording id=\"2c3a2f09-da5c-4669-a05b-8f45ebfc97bc\"><title>Minuet 3</title><length>380000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>7</position><number>7</number><length>217333</length><artist-credit><name-credit><name>J. S. Bach</name><artist id=\"24f1766e-9635-4d58-a4d4-9413f9f98a4c\"><name>Johann Sebastian Bach</name><sort-name>Bach, Johann Sebastian</sort-name></artist></name-credit></artist-credit><recording id=\"b79a6925-6ba5-40e7-81e2-0a8bb1af77ff\"><title>Minuet</title><length>217000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>8</position><number>8</number><length>126360</length><artist-credit><name-credit><name>C.M. von Weber</name><artist id=\"c2d17829-1424-435b-9386-c77d3a920abe\"><name>Carl Maria von Weber</name><sort-name>Weber, Carl Maria von</sort-name></artist></name-credit></artist-credit><recording id=\"8703e5b8-4027-4fee-ba42-d1cad9b4850b\"><title>Cradle Song</title><length>126000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>9</position><number>9</number><length>177800</length><artist-credit><name-credit><name>W.A. Mozart</name><artist id=\"b972f589-fb0e-474e-b64a-803b0364fa75\"><name>Wolfgang Amadeus Mozart</name><sort-name>Mozart, Wolfgang Amadeus</sort-name><disambiguation>classical composer</disambiguation></artist></name-credit></artist-credit><recording id=\"f52932c0-67c0-4519-8272-fec1ced750f8\"><title>Minuet</title><length>178000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>10</position><number>10</number><length>280173</length><artist-credit><name-credit><name>W.A. Mozart</name><artist id=\"b972f589-fb0e-474e-b64a-803b0364fa75\"><name>Wolfgang Amadeus Mozart</name><sort-name>Mozart, Wolfgang Amadeus</sort-name><disambiguation>classical composer</disambiguation></artist></name-credit></artist-credit><recording id=\"191db933-904b-4763-9e49-4b54d9b31993\"><title>Arietta</title><length>280000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>11</position><number>11</number><length>232333</length><artist-credit><name-credit><name>R. Schumann</name><artist id=\"3cd3882c-00f8-4362-a0c2-ad89ed248533\"><name>Robert Schumann</name><sort-name>Schumann, Robert</sort-name><disambiguation>German classical composer</disambiguation></artist></name-credit></artist-credit><recording id=\"3a48d185-39e2-44e6-aaae-daacce0e039b\"><title>Melody</title><length>232000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>12</position><number>12</number><length>807293</length><artist-credit><name-credit><name>L. van Beethoven</name><artist id=\"1f9df192-a621-4f54-8850-2c5373b7eac9\"><name>Ludwig van Beethoven</name><sort-name>Beethoven, Ludwig van</sort-name></artist></name-credit></artist-credit><recording id=\"14e0499e-bfc3-473a-8153-26eb20a6b807\"><title>Sonatina</title><length>807000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>13</position><number>13</number><length>257106</length><artist-credit><name-credit><name>J.S. Bach</name><artist id=\"24f1766e-9635-4d58-a4d4-9413f9f98a4c\"><name>Johann Sebastian Bach</name><sort-name>Bach, Johann Sebastian</sort-name></artist></name-credit></artist-credit><recording id=\"2279e151-7133-475f-88a7-078242160d06\"><title>Musette</title><length>257000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track><track><position>14</position><number>14</number><length>388760</length><artist-credit><name-credit><name>J.S. Bach</name><artist id=\"24f1766e-9635-4d58-a4d4-9413f9f98a4c\"><name>Johann Sebastian Bach</name><sort-name>Bach, Johann Sebastian</sort-name></artist></name-credit></artist-credit><recording id=\"4883b242-898c-4d11-abe4-6b1fb62406bc\"><title>Minuet</title><length>389000</length><artist-credit><name-credit><name>Haruko Kataoka</name><artist id=\"3d2a6f68-62db-4798-9cf8-7a6a745f51b0\"><name>片岡春子</name><sort-name>Kataoka, Haruko</sort-name></artist></name-credit></artist-credit></recording></track></track-list></medium></medium-list></release></metadata>"
  },
  {
    "path": "test/data/release/fe29e7f0-eb46-44ba-9348-694166f47885-recordings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><release id=\"fe29e7f0-eb46-44ba-9348-694166f47885\"><title>Urk</title><status>Official</status><quality>normal</quality><packaging>Digipak</packaging><text-representation><language>eng</language><script>Latn</script></text-representation><date>2007-02-02</date><country>DE</country><release-event-list count=\"1\"><release-event><date>2007-02-02</date><area id=\"85752fda-13c4-31a3-bee5-0e5cb1f51dad\"><name>Germany</name><sort-name>Germany</sort-name><iso-3166-1-code-list><iso-3166-1-code>DE</iso-3166-1-code></iso-3166-1-code-list></area></release-event></release-event-list><barcode>886970007092</barcode><asin>B000LXHGR6</asin><cover-art-archive><artwork>false</artwork><count>0</count><front>false</front><back>false</back></cover-art-archive><medium-list count=\"3\"><medium><position>1</position><track-list count=\"14\" offset=\"0\"><track id=\"58a1aa51-1b34-3182-9d71-91dc0e6db368\"><position>1</position><number>1</number><length>184000</length><recording id=\"f0718b28-1e48-4b8e-8e5e-0596cc8ff515\"><title>The Train</title><length>184000</length></recording></track><track id=\"130e94e5-e08f-3c22-96a3-ac79cae131b5\"><position>2</position><number>2</number><length>298466</length><recording id=\"21c268a2-d5c6-4065-8a41-1de68fc2e047\"><title>Adieu Sweet Bahnhof</title><length>298466</length></recording></track><track id=\"ee61415c-02a4-304b-9824-9ff761deb074\"><position>3</position><number>3</number><length>197960</length><recording id=\"649b4b3c-4626-42d7-bd6a-20acd3c131b9\"><title>J.O.S. Days</title><length>197960</length></recording></track><track id=\"f179ffea-fcb3-3d1e-9594-4880820b8f34\"><position>4</position><number>4</number><length>299666</length><recording id=\"7b468c87-81c3-4746-879d-2a067149fa72\"><title>Sketches of Spain</title><length>299666</length></recording></track><track id=\"4a37cccc-5fa4-3216-ad74-7de4c79427e5\"><position>5</position><number>5</number><length>215400</length><recording id=\"7ea24eb6-5326-4ff4-8259-e821d69e55c0\"><title>In the Dutch Mountains</title><length>215400</length></recording></track><track id=\"c278486a-fcec-372f-8eb2-0c64e2827f03\"><position>6</position><number>6</number><length>264400</length><recording id=\"19a18514-f238-45da-87a2-78dd5c69b8c3\"><title>The Dream</title><length>264400</length></recording></track><track id=\"6f6db0cc-c56e-3320-aae6-8614490101cd\"><position>7</position><number>7</number><length>310466</length><recording id=\"f502e847-467e-4a30-b895-13553944cabf\"><title>The Swimmer</title><length>310466</length></recording></track><track id=\"6a6eaa88-b72d-384e-83b5-ba7c6f9f0644\"><position>8</position><number>8</number><length>242133</length><recording id=\"986242b6-3917-4e66-9dcf-5bc28b945ab1\"><title>The House</title><length>242133</length></recording></track><track id=\"4d9483e5-517e-336b-a640-aa49b8010d5d\"><position>9</position><number>9</number><length>451373</length><recording id=\"509c0f21-3b6c-4cc9-a9ed-3858dc2e234c\"><title>Two Skaters</title><length>451373</length></recording></track><track id=\"323c99ec-d96d-356c-91af-1b05def72488\"><position>10</position><number>10</number><length>198800</length><recording id=\"780ceea2-4969-4642-9383-a9822ab32c36\"><title>Cabins</title><length>198800</length></recording></track><track id=\"99a7bb69-0a31-3032-8039-c55b9fae712d\"><position>11</position><number>11</number><length>356493</length><recording id=\"a836a48a-95bb-4778-9e2a-9e2fe56b61fb\"><title>Nescio</title><length>356493</length></recording></track><track id=\"1f874aa1-12ea-31a6-81e3-07cea3722c10\"><position>12</position><number>12</number><length>272306</length><recording id=\"3756aa43-c1ac-4b3b-bf93-6281bffdd48d\"><title>Pelican &amp; Penguin</title><length>272306</length></recording></track><track id=\"d6549ef0-0822-3fb2-be06-67da51f68e0b\"><position>13</position><number>13</number><length>157026</length><recording id=\"647740fe-58bf-42ab-90ca-1b842a06f3b8\"><title>Telephone Song</title><length>157026</length></recording></track><track id=\"500d80b5-aee6-3033-a094-98e50f127be4\"><position>14</position><number>14</number><length>296666</length><recording id=\"92d76ae6-ca4b-4cd2-9bad-a9d041dd646e\"><title>Dapperstreet</title><length>296666</length></recording></track></track-list></medium><medium><position>2</position><track-list count=\"15\" offset=\"0\"><track id=\"ced21052-14fd-326d-ad17-813c7d0e64dc\"><position>1</position><number>1</number><length>259000</length><recording id=\"6fa74997-07bf-49a1-8afa-f7451e9ccc9e\"><title>Port of Amsterdam</title><length>259000</length></recording></track><track id=\"2d30e13b-9320-3ba2-b9bd-ead2542ec2f4\"><position>2</position><number>2</number><length>279133</length><recording id=\"dd9759f0-25e9-4ab3-9977-4b61d2ae04fb\"><title>Bike in Head</title><length>279133</length></recording></track><track id=\"13d74ec7-a6a4-3000-b110-daf793c69e3a\"><position>3</position><number>3</number><length>276000</length><recording id=\"20709a6b-098d-4750-90dc-5560f6816aec\"><title>Mountain Jan</title><length>276000</length></recording></track><track id=\"c1176767-f9cb-3f86-b3e7-dc1de040551a\"><position>4</position><number>4</number><length>212493</length><recording id=\"78796087-899b-4c63-b565-7e3af328e20c\"><title>Walter &amp; Connie</title><length>212493</length></recording></track><track id=\"e0c0ddf5-2e83-3c53-8a2e-70b536f04176\"><position>5</position><number>5</number><length>217306</length><recording id=\"2584a234-799c-4350-ad37-918867f2f725\"><title>A Touch of Henry Moore</title><length>217306</length></recording></track><track id=\"3fab7491-3540-375d-808a-7289188d57e6\"><position>6</position><number>6</number><length>185666</length><recording id=\"e032bac1-0ba8-42dd-84f3-f8e74d9d4138\"><title>The Bauhaus Chair</title><length>185666</length></recording></track><track id=\"2242a470-1379-3b04-b763-e4825bdd5c4e\"><position>7</position><number>7</number><length>251666</length><recording id=\"f11524be-844f-479c-8274-e8303b47043c\"><title>Under a Canoe</title><length>251666</length></recording></track><track id=\"d8ffc275-331c-3f6d-a628-1f86c6180187\"><position>8</position><number>8</number><length>195826</length><recording id=\"abd59639-d5f5-4981-a401-39a084283a6a\"><title>Shadow of a Doubt</title><length>195826</length></recording></track><track id=\"a4c3f8c9-606c-3988-82d5-53837cd12c7a\"><position>9</position><number>9</number><length>351000</length><recording id=\"55bff738-5a17-47a0-8957-f01fd1df4430\"><title>Mask</title><length>351000</length></recording></track><track id=\"48961c45-4bd9-3b20-b90e-59ebd2150587\"><position>10</position><number>10</number><length>205000</length><recording id=\"41cf3b87-8c1c-4d7c-ae49-082326de9a74\"><title>Home Before Dark</title><length>205000</length></recording></track><track id=\"4c5ad4eb-2a70-3b3f-b266-81b0d1db2a21\"><position>11</position><number>11</number><length>239240</length><recording id=\"00d4692b-64b9-4d4d-8b9d-7bea3d8966bd\"><title>The Panorama Man</title><length>239240</length></recording></track><track id=\"410ade2d-aa93-3907-8409-470d46360a72\"><position>12</position><number>12</number><length>232026</length><recording id=\"de9999d0-3117-4f52-8cdd-8979df33d802\"><title>Slip of the Tongue</title><length>232026</length></recording></track><track id=\"8886938d-ce29-3dca-90b0-c02d691bf2f2\"><position>13</position><number>13</number><length>280840</length><recording id=\"97ee2947-2e68-4f47-8150-641f9b59c8f0\"><title>An Eating House</title><length>280840</length></recording></track><track id=\"f16fefd1-285d-37d1-865e-6c586663706e\"><position>14</position><number>14</number><length>139426</length><recording id=\"4d67d091-0c4a-4b73-b316-4df85b5b6c07\"><title>Red Tape</title><length>139426</length></recording></track><track id=\"4405b6dc-3010-3fc7-b410-dda83b34f0dd\"><position>15</position><number>15</number><length>208706</length><recording id=\"cd493e8b-6452-4544-b4fe-32725c449b5e\"><title>Tons of Ink</title><length>208706</length></recording></track></track-list></medium><medium><position>3</position><track-list count=\"19\" offset=\"0\"><track id=\"bcd34b62-907c-3c41-9438-08f0a4d4a307\"><position>1</position><number>1</number><length>69000</length><recording id=\"15ed5a60-55b1-4edf-bcd1-130dbf7bca74\"><title>[intro]</title><length>69000</length><video>true</video></recording></track><track id=\"97885127-0ab4-3ac3-b0e1-5082844c03a9\"><position>2</position><number>2</number><length>265000</length><recording id=\"a8ed266e-da86-4c2a-8a4c-59485bdf73e2\"><title>The Dream</title><length>265000</length><video>true</video></recording></track><track id=\"788008ed-6fca-3c41-9277-e2be05cf4648\"><position>3</position><number>3</number><length>446000</length><recording id=\"b3a535bb-aba0-4840-a6c4-2e1a9d89cbfa\"><title>Two Skaters</title><length>446000</length><video>true</video></recording></track><track id=\"eaabb267-f593-3823-81a8-52c9165cda95\"><position>4</position><number>4</number><length>295000</length><recording id=\"32634cd9-0cc5-413f-bb89-3abea36adc11\"><title>Sketches of Spain</title><length>295000</length><video>true</video></recording></track><track id=\"1cedc994-a1ee-32a1-b1be-d01051c2e1a7\"><position>5</position><number>5</number><length>297000</length><recording id=\"4cea304b-072a-4c14-9c57-9bff038aba01\"><title>Adieu Sweet Bahnhof</title><length>297000</length><video>true</video></recording></track><track id=\"fe53cef7-7182-32c3-814e-5b6800200bbf\"><position>6</position><number>6</number><length>241000</length><recording id=\"dbea19d1-eaeb-4023-89f7-2b4799f4aa6b\"><title>A Touch of Henry Moore</title><length>241000</length><video>true</video></recording></track><track id=\"efae0ab4-a909-3ffc-b226-880d13ce4d30\"><position>7</position><number>7</number><length>279000</length><recording id=\"dcf78edf-cf77-4d46-a499-d3070ea1b3ef\"><title>An Eating House</title><length>279000</length><video>true</video></recording></track><track id=\"223be7aa-81d6-39c6-b4bd-28b9ab88358e\"><position>8</position><number>8</number><length>281000</length><recording id=\"e15ae94e-2cf0-4afc-aeb2-c24489153b96\"><title>Nescio</title><length>281000</length><video>true</video></recording></track><track id=\"53fafeeb-ef07-305f-a81c-694d72df672f\"><position>9</position><number>9</number><length>269000</length><recording id=\"612e5b36-9cf3-46a1-81dc-a6d6c8463999\"><title>The Hat</title><length>269000</length><video>true</video></recording></track><track id=\"04cca2b1-1d4d-3dc7-89f8-6f10062167ee\"><position>10</position><number>10</number><length>243000</length><recording id=\"d7dbcb0b-397d-4d33-9a9a-aae1e62b421a\"><title>Port of Amsterdam</title><length>243000</length><video>true</video></recording></track><track id=\"b6bdc5b0-7a2f-3182-84db-19ff412582b2\"><position>11</position><number>11</number><length>361000</length><recording id=\"cdbd9ba2-0c07-427f-a23c-ae8e8bd88a45\"><title>Mask</title><length>361000</length><video>true</video></recording></track><track id=\"6d2ff0ad-900a-3ca2-8d27-98a3010879fb\"><position>12</position><number>12</number><length>330000</length><recording id=\"3c64338c-5f7c-48aa-b3fa-550bd8c79a10\"><title>In the Dutch Mountains</title><length>330000</length><video>true</video></recording></track><track id=\"e874e04f-4375-3bf2-ad55-df436bcba6d0\"><position>13</position><number>13</number><length>202000</length><recording id=\"d8593f6d-e584-4280-929c-33738dbb70ff\"><title>Cabins</title><length>202000</length><video>true</video></recording></track><track id=\"af79aa34-bdc0-37ed-b769-d50e5e3d0ffe\"><position>14</position><number>14</number><length>305000</length><recording id=\"418c69f6-e9f5-435d-ab59-22806fd78909\"><title>Tons of Ink</title><length>305000</length><video>true</video></recording></track><track id=\"0efb4b45-d837-3c54-97af-17302dbd84ea\"><position>15</position><number>15</number><length>303000</length><recording id=\"e6a8c0c4-f217-4499-8011-c32934ac897b\"><title>The Swimmer</title><length>303000</length><video>true</video></recording></track><track id=\"c5c1df11-739a-350d-9e35-bad8599bd010\"><position>16</position><number>16</number><length>255000</length><recording id=\"862d0414-849e-4a41-9c34-5af9505e9001\"><title>Blue</title><length>255000</length><video>true</video></recording></track><track id=\"f0f7046f-952c-34ff-8be4-a7200dfab609\"><position>17</position><number>17</number><length>231000</length><recording id=\"0e201a1b-ea0c-4603-bdb5-c68bc477aee5\"><title>Slip of the Tongue</title><length>231000</length><video>true</video></recording></track><track id=\"2a786c74-dc19-3a18-826f-92787c5411d1\"><position>18</position><number>18</number><length>227000</length><recording id=\"497cba4a-0708-412e-92f0-bea2a28eedba\"><title>The House</title><length>227000</length><video>true</video></recording></track><track id=\"3dd1e3d5-e7fb-3d24-b800-f90761da4405\"><position>19</position><number>19</number><length>168000</length><recording id=\"a85cb82b-f9cf-448a-8fe1-f6a0a02cd867\"><title>Telephone Songs</title><length>168000</length><video>true</video></recording></track></track-list></medium></medium-list></release></metadata>"
  },
  {
    "path": "test/data/release-group/f52bc6a1-c848-49e6-85de-f8f53459a624.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><release-group type=\"Soundtrack\" id=\"f52bc6a1-c848-49e6-85de-f8f53459a624\"><title>Super Meat Boy!</title><first-release-date>2010-10-27</first-release-date><primary-type>Album</primary-type><secondary-type-list><secondary-type>Soundtrack</secondary-type></secondary-type-list></release-group></metadata>"
  },
  {
    "path": "test/data/search-artist.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\" xmlns:ext=\"http://musicbrainz.org/ns/ext#-2.0\">\n  <artist-list offset=\"0\" count=\"349\">\n    <artist ext:score=\"100\" type=\"Group\" id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n      <name>Dynamo Go</name>\n      <sort-name>Dynamo Go</sort-name>\n      <country>NZ</country>\n      <life-span>\n        <begin>2005-06</begin>\n      </life-span>\n      <alias-list>\n        <alias>Dynamo Go</alias>\n      </alias-list>\n      <tag-list>\n        <tag count=\"1\">\n          <name>testfoo</name>\n        </tag>\n      </tag-list>\n    </artist>\n    <artist ext:score=\"44\" type=\"Group\" id=\"af51cc9a-43f5-4be4-ac1a-a24ae12ff8f1\">\n      <name>Dynamo</name>\n      <sort-name>Dynamo</sort-name>\n      <alias-list>\n        <alias>Dynamo</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"44\" type=\"Group\" id=\"ee768530-0582-41ff-b461-f52a9d81ba14\">\n      <name>Dynamo</name>\n      <sort-name>Dynamo</sort-name>\n      <country>FI</country>\n      <disambiguation>Finnish punk band</disambiguation>\n      <alias-list>\n        <alias>Dynamo</alias>\n      </alias-list>\n      <tag-list>\n        <tag count=\"1\">\n          <name>punk</name>\n        </tag>\n        <tag count=\"1\">\n          <name>finland</name>\n        </tag>\n      </tag-list>\n    </artist>\n    <artist ext:score=\"44\" type=\"Person\" id=\"4e7d4d87-88bb-43c5-b6ef-e6b4b263f490\">\n      <name>Dynamo</name>\n      <sort-name>Dynamo</sort-name>\n      <country>DE</country>\n      <disambiguation>german DIN label owner Torsten Pröfrock</disambiguation>\n      <alias-list>\n        <alias>Dynamo</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"35\" id=\"779c8b5a-9401-40ec-a73d-d545875ffec8\">\n      <name>Dynamo</name>\n      <sort-name>Dynamo</sort-name>\n      <disambiguation>designer</disambiguation>\n    </artist>\n    <artist ext:score=\"35\" id=\"beaeda13-4d65-423b-97fe-4bcac28fa837\">\n      <name>Dynamo Productions</name>\n      <sort-name>Dynamo Productions</sort-name>\n      <alias-list>\n        <alias>Dynamo Producions</alias>\n        <alias>Dynamo Productions</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" type=\"Group\" id=\"7d30b5fa-3579-464d-a5dc-2f577bf0c200\">\n      <name>Dynamo City</name>\n      <sort-name>Dynamo City</sort-name>\n      <alias-list>\n        <alias>Dynamo City</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" id=\"3d0a456a-2880-4e9f-a4eb-2fa3e3c9314b\">\n      <name>Dynamo 5</name>\n      <sort-name>Dynamo 5</sort-name>\n      <alias-list>\n        <alias>Dynamo 5</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" type=\"Group\" id=\"462e7bbd-10a3-4d81-b457-82fc8733e5f5\">\n      <name>Kruunuhaan Dynamo</name>\n      <sort-name>Kruunuhaan Dynamo</sort-name>\n      <alias-list>\n        <alias>Kruunuhaan Dynamo</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" id=\"9ddd1b83-bdba-4a07-923a-ba0000b73885\">\n      <name>Kidd Dynamo</name>\n      <sort-name>Kidd Dynamo</sort-name>\n      <alias-list>\n        <alias>Kidd Dynamo</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" type=\"Group\" id=\"9cccafc8-d488-4c2d-b18b-40326b620253\">\n      <name>Onslaught Dynamo</name>\n      <sort-name>Onslaught Dynamo</sort-name>\n      <alias-list>\n        <alias>Onslaught Dynamo</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" id=\"fdf1914e-6dce-4c74-b37c-e85750418488\">\n      <name>Dynamo Electrix</name>\n      <sort-name>Dynamo Electrix</sort-name>\n      <alias-list>\n        <alias>Dynamo Electrix</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" id=\"4ecd84db-9f81-4ddd-9515-474187697cea\">\n      <name>Dynamo Ska</name>\n      <sort-name>Dynamo Ska</sort-name>\n      <alias-list>\n        <alias>Dynamo Ska</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" id=\"ed0c313b-d380-4663-b312-5a94a2c02375\">\n      <name>Dynamo Chapel</name>\n      <sort-name>Dynamo Chapel</sort-name>\n      <alias-list>\n        <alias>Dynamo Chapel</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" type=\"Person\" id=\"78190fd1-cc51-4d0c-a9f1-07446e493a59\">\n      <name>Johnny Dynamo</name>\n      <sort-name>Dynamo, Johnny</sort-name>\n      <alias-list>\n        <alias>Johnny Dynamo</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"31\" type=\"Group\" id=\"80ec2075-07f6-469d-adda-09f7cd656c29\">\n      <name>Dynamo Früchtebonus</name>\n      <sort-name>Dynamo Früchtebonus</sort-name>\n      <country>AT</country>\n      <alias-list>\n        <alias>Dynamo Früchtebonus</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"26\" id=\"8b35216f-e33e-4b35-bdfd-fae8ba5d60dc\">\n      <name>Dynamo and JP</name>\n      <sort-name>Dynamo and JP</sort-name>\n      <alias-list>\n        <alias>Dynamo and JP</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"26\" type=\"Group\" id=\"623b808a-7876-4b46-a3db-379c20e30886\">\n      <name>The Driven Dynamo</name>\n      <sort-name>Driven Dynamo, The</sort-name>\n      <alias-list>\n        <alias>The Driven Dynamo</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"26\" id=\"efa2f94a-9556-49d9-a61c-69f3469fa01b\">\n      <name>Tuttle &amp; Dynamo Laboratory</name>\n      <sort-name>Tuttle &amp; Laboratory, Dynamo</sort-name>\n      <alias-list>\n        <alias>Tuttle &amp; Dynamo Laboratory</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"26\" id=\"65206b6b-fc2a-4c13-8e2a-3f82240592c2\">\n      <name>The Dynamo Hymn</name>\n      <sort-name>Dynamo Hymn, The</sort-name>\n      <alias-list>\n        <alias>The Dynamo Hymn</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"26\" type=\"Group\" id=\"33d6d86a-6337-48ff-9dff-7c0ce0a3d895\">\n      <name>Go!</name>\n      <sort-name>Go!</sort-name>\n      <country>US</country>\n      <alias-list>\n        <alias>Go!</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"26\" type=\"Group\" id=\"bda37da8-f7b8-43f8-8ef8-b4cf2c74188d\">\n      <name>Go</name>\n      <sort-name>Go</sort-name>\n      <alias-list>\n        <alias>Go</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"26\" type=\"Group\" id=\"b87963a8-451b-4b19-b200-e6e91113bd0f\">\n      <name>GO!GO!7188</name>\n      <sort-name>GO!GO!7188</sort-name>\n      <country>JP</country>\n      <life-span>\n        <begin>1998-06</begin>\n        <end>2012-02-10</end>\n      </life-span>\n      <alias-list>\n        <alias>GOGO7188</alias>\n        <alias>GO! GO! 7188</alias>\n        <alias>GO!GO!7188</alias>\n        <alias>GOGO 7188</alias>\n      </alias-list>\n      <tag-list>\n        <tag count=\"1\">\n          <name>rock</name>\n        </tag>\n        <tag count=\"1\">\n          <name>japanese</name>\n        </tag>\n      </tag-list>\n    </artist>\n    <artist ext:score=\"22\" id=\"ec62f0af-b02d-4de7-82e8-7523c65bc481\">\n      <name>Go Robot, Go!</name>\n      <sort-name>Go Robot, Go!</sort-name>\n      <alias-list>\n        <alias>Go Robot, Go!</alias>\n      </alias-list>\n    </artist>\n    <artist ext:score=\"22\" id=\"cbf817d4-171d-4c0a-af12-82569607b5fb\">\n      <name>Gaijin A Go Go</name>\n      <sort-name>Gaijin A Go Go</sort-name>\n      <alias-list>\n        <alias>Gaijin A Go Go</alias>\n      </alias-list>\n    </artist>\n  </artist-list>\n</metadata>\n"
  },
  {
    "path": "test/data/search-event.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><metadata created=\"2016-01-18T12:04:48.934Z\" xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\" xmlns:ext=\"http://musicbrainz.org/ns/ext#-2.0\"><event-list count=\"3\" offset=\"0\"><event id=\"e79263d8-3399-48c0-b4a9-e17f1ffc757f\" ext:score=\"100\"><name>Woodstock 1999</name><life-span/></event><event id=\"b0e1901e-da48-4aea-8f1b-190ee86b5ce9\" type=\"Festival\" ext:score=\"70\"><name>Woodstock Music &amp; Art Fair</name><disambiguation>1969</disambiguation><life-span><begin>1969-08-15</begin><end>1969-08-18</end></life-span><relation-list target-type=\"place\"><relation type=\"held at\"><direction>backward</direction><place id=\"ccb89c39-07d8-4ad2-8c18-1976773fcf63\"><name>Yasgur's Farm</name></place></relation></relation-list></event><event id=\"e49198e9-af3e-40e9-bee5-40f8e24da4b0\" ext:score=\"59\"><name>Woodstock 1999, Day 3, East Stage</name><life-span><begin>1999-07-24</begin><end>1999-07-24</end></life-span><relation-list target-type=\"artist\"><relation type=\"main performer\"><direction>backward</direction><artist id=\"8f9d6bb2-dba4-4cca-9967-cc02b9f4820c\"><name>Limp Bizkit</name><sort-name>Limp Bizkit</sort-name></artist></relation></relation-list></event></event-list></metadata>"
  },
  {
    "path": "test/data/search-instrument.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><metadata created=\"2015-11-18T20:10:35.821Z\" xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\" xmlns:ext=\"http://musicbrainz.org/ns/ext#-2.0\"><instrument-list count=\"23\" offset=\"0\"><instrument id=\"6505f98c-f698-4406-8bf4-8ca43d05c36f\" type=\"Other instrument\" ext:score=\"100\"><name>bass</name><description>Bass is a common but generic credit which refers to more than one instrument, the most common being the bass guitar and the double bass (a.k.a. contrabass, acoustic upright bass, wood bass). Please use the correct instrument if you know which one is intended.</description><alias-list><alias locale=\"ja\" sort-name=\"ベース\" type=\"Instrument name\" primary=\"primary\">ベース</alias><alias locale=\"pt_BR\" sort-name=\"baixo\" type=\"Instrument name\" primary=\"primary\">baixo</alias><alias locale=\"es\" sort-name=\"bajo (genérico, no usar)\" type=\"Instrument name\" primary=\"primary\">bajo (genérico, no usar)</alias><alias locale=\"nl\" sort-name=\"bas\" type=\"Instrument name\" primary=\"primary\">bas</alias><alias locale=\"da\" sort-name=\"bas\" type=\"Instrument name\" primary=\"primary\">bas</alias><alias locale=\"hr\" sort-name=\"bas\" type=\"Instrument name\" primary=\"primary\">bas</alias><alias locale=\"tr\" sort-name=\"bas\" type=\"Instrument name\" primary=\"primary\">bas</alias><alias locale=\"en\" sort-name=\"bass\" type=\"Instrument name\" primary=\"primary\">bass</alias><alias locale=\"et\" sort-name=\"bass\" type=\"Instrument name\" primary=\"primary\">bass</alias><alias locale=\"de\" sort-name=\"Bass\" type=\"Instrument name\" primary=\"primary\">Bass</alias><alias locale=\"fr\" sort-name=\"basses\" type=\"Instrument name\" primary=\"primary\">basses</alias><alias locale=\"fi\" sort-name=\"basso\" type=\"Instrument name\" primary=\"primary\">basso</alias><alias locale=\"it\" sort-name=\"Basso\" type=\"Instrument name\" primary=\"primary\">Basso</alias><alias locale=\"el\" sort-name=\"μπάσο\" type=\"Instrument name\" primary=\"primary\">μπάσο</alias></alias-list><tag-list><tag count=\"1\"><name>fixme</name></tag><tag count=\"0\"><name>never use this</name></tag><tag count=\"0\"><name>please don't use this</name></tag></tag-list></instrument><instrument id=\"3ac17d91-feb7-4c2e-9b74-5aa7c73c8e16\" type=\"Electronic instrument\" ext:score=\"78\"><name>keyboard bass</name><alias-list><alias locale=\"es\" sort-name=\"bajo teclado\" type=\"Instrument name\" primary=\"primary\">bajo teclado</alias><alias locale=\"nl\" sort-name=\"baskeyboard\" type=\"Instrument name\" primary=\"primary\">baskeyboard</alias><alias locale=\"et\" sort-name=\"bassklahvpill\" type=\"Instrument name\" primary=\"primary\">bassklahvpill</alias><alias locale=\"fr\" sort-name=\"clavier basse\" type=\"Instrument name\" primary=\"primary\">clavier basse</alias><alias locale=\"en\" sort-name=\"keyboard bass\" type=\"Instrument name\" primary=\"primary\">keyboard bass</alias><alias locale=\"de\" sort-name=\"Keyboard-Bass\" type=\"Instrument name\" primary=\"primary\">Keyboard-Bass</alias><alias locale=\"fi\" sort-name=\"kosketinbasso\" type=\"Instrument name\" primary=\"primary\">kosketinbasso</alias><alias locale=\"el\" sort-name=\"πλήκτρα μπάσο\" type=\"Instrument name\" primary=\"primary\">πλήκτρα μπάσο</alias></alias-list></instrument><instrument id=\"17f9f065-2312-4a24-8309-6f6dd63e2e33\" type=\"String instrument\" ext:score=\"78\"><name>bass guitar</name><description>Bass (modern, typically electrical, but not always)</description><alias-list><alias locale=\"ja\" sort-name=\"ベースギター\" type=\"Instrument name\" primary=\"primary\">ベースギター</alias><alias locale=\"es\" sort-name=\"bajo\" type=\"Instrument name\" primary=\"primary\">bajo</alias><alias locale=\"nl\" sort-name=\"basgitaar\" type=\"Instrument name\" primary=\"primary\">basgitaar</alias><alias locale=\"tr\" sort-name=\"bas gitar\" type=\"Instrument name\" primary=\"primary\">bas gitar</alias><alias locale=\"hr\" sort-name=\"bas gitara\" type=\"Instrument name\" primary=\"primary\">bas gitara</alias><alias sort-name=\"bass\" type=\"Search hint\">bass</alias><alias locale=\"de\" sort-name=\"Bassgitarre\" type=\"Instrument name\" primary=\"primary\">Bassgitarre</alias><alias locale=\"en\" sort-name=\"bass guitar\" type=\"Instrument name\" primary=\"primary\">bass guitar</alias><alias locale=\"et\" sort-name=\"basskitarr\" type=\"Instrument name\" primary=\"primary\">basskitarr</alias><alias locale=\"fi\" sort-name=\"bassokitara\" type=\"Instrument name\" primary=\"primary\">bassokitara</alias><alias locale=\"pl\" sort-name=\"gitara basowa\" type=\"Instrument name\" primary=\"primary\">gitara basowa</alias><alias locale=\"fr\" sort-name=\"guitare basse\" type=\"Instrument name\" primary=\"primary\">guitare basse</alias><alias locale=\"el\" sort-name=\"μπάσο κιθάρα\" type=\"Instrument name\" primary=\"primary\">μπάσο κιθάρα</alias></alias-list></instrument><instrument id=\"e6571d23-5d79-4216-99d6-06e14e737da1\" type=\"Electronic instrument\" ext:score=\"78\"><name>bass synthesizer</name><description>A bass synthesizer is used to create sounds in the bass range.</description><alias-list><alias locale=\"ja\" sort-name=\"ベースシンセサイザー\" type=\"Instrument name\" primary=\"primary\">ベースシンセサイザー</alias><alias locale=\"hr\" sort-name=\"bas sintisajzer\" type=\"Instrument name\" primary=\"primary\">bas sintisajzer</alias><alias locale=\"et\" sort-name=\"bassisüntesaator\" type=\"Instrument name\" primary=\"primary\">bassisüntesaator</alias><alias locale=\"fi\" sort-name=\"bassosyntetisaattori\" type=\"Instrument name\" primary=\"primary\">bassosyntetisaattori</alias><alias locale=\"en\" sort-name=\"bass synthesizer\" type=\"Instrument name\" primary=\"primary\">bass synthesizer</alias><alias locale=\"de\" sort-name=\"Bass-Synthesizer\" type=\"Instrument name\" primary=\"primary\">Bass-Synthesizer</alias><alias locale=\"nl\" sort-name=\"bassynthesizer\" type=\"Instrument name\" primary=\"primary\">bassynthesizer</alias><alias locale=\"tr\" sort-name=\"bas synthesizer\" type=\"Instrument name\" primary=\"primary\">bas synthesizer</alias><alias locale=\"fr\" sort-name=\"synthétiseur basse\" type=\"Instrument name\" primary=\"primary\">synthétiseur basse</alias><alias locale=\"el\" sort-name=\"μπάσο συνθεσάιζερ\" type=\"Instrument name\" primary=\"primary\">μπάσο συνθεσάιζερ</alias><alias locale=\"ru\" sort-name=\"басовый синтезатор\" type=\"Instrument name\" primary=\"primary\">басовый синтезатор</alias></alias-list></instrument><instrument id=\"e78b40c0-acc8-4db8-911a-adf991e0c73d\" type=\"Percussion instrument\" ext:score=\"78\"><name>bass drum</name><alias-list><alias locale=\"ja\" sort-name=\"フィンガースナップ\" type=\"Instrument name\" primary=\"primary\">フィンガースナップ</alias><alias locale=\"hr\" sort-name=\"bas bubanj\" type=\"Instrument name\" primary=\"primary\">bas bubanj</alias><alias locale=\"tr\" sort-name=\"bass davul\" type=\"Instrument name\" primary=\"primary\">bass davul</alias><alias locale=\"en\" sort-name=\"bass drum\" type=\"Instrument name\" primary=\"primary\">bass drum</alias><alias locale=\"fi\" sort-name=\"bassorumpu\" type=\"Instrument name\" primary=\"primary\">bassorumpu</alias><alias locale=\"et\" sort-name=\"basstrumm\" type=\"Instrument name\" primary=\"primary\">basstrumm</alias><alias locale=\"es\" sort-name=\"bombo\" type=\"Instrument name\" primary=\"primary\">bombo</alias><alias locale=\"fr\" sort-name=\"grosse caisse\" type=\"Instrument name\" primary=\"primary\">grosse caisse</alias><alias locale=\"de\" sort-name=\"große Trommel\" type=\"Instrument name\" primary=\"primary\">große Trommel</alias><alias locale=\"nl\" sort-name=\"grote trom\" type=\"Instrument name\" primary=\"primary\">grote trom</alias><alias locale=\"el\" sort-name=\"μπάσο τύμπανο\" type=\"Instrument name\" primary=\"primary\">μπάσο τύμπανο</alias></alias-list></instrument><instrument id=\"9447c0af-5569-48f2-b4c5-241105d58c91\" type=\"Wind instrument\" ext:score=\"78\"><name>bass saxophone</name><description>The bass saxophone is the second largest existing member of the saxophone family (not counting the subcontrabass tubax). It is similar in design to a baritone saxophone, but it is larger, with a longer loop near the mouthpiece.</description><alias-list><alias locale=\"ja\" sort-name=\"バスサクソフォーン\" type=\"Instrument name\" primary=\"primary\">バスサクソフォーン</alias><alias locale=\"tr\" sort-name=\"bas saksofon\" type=\"Instrument name\" primary=\"primary\">bas saksofon</alias><alias locale=\"hr\" sort-name=\"bas saksofon\" type=\"Instrument name\" primary=\"primary\">bas saksofon</alias><alias locale=\"nl\" sort-name=\"bassaxofoon\" type=\"Instrument name\" primary=\"primary\">bassaxofoon</alias><alias locale=\"fi\" sort-name=\"bassosaksofoni\" type=\"Instrument name\" primary=\"primary\">bassosaksofoni</alias><alias locale=\"et\" sort-name=\"bass-saksofon\" type=\"Instrument name\" primary=\"primary\">bass-saksofon</alias><alias locale=\"de\" sort-name=\"Basssaxophon\" type=\"Instrument name\" primary=\"primary\">Basssaxophon</alias><alias locale=\"en\" sort-name=\"bass saxophone\" type=\"Instrument name\" primary=\"primary\">bass saxophone</alias><alias locale=\"es\" sort-name=\"saxofón bajo\" type=\"Instrument name\" primary=\"primary\">saxofón bajo</alias><alias locale=\"fr\" sort-name=\"Saxophone basse\" type=\"Instrument name\" primary=\"primary\">Saxophone basse</alias><alias locale=\"el\" sort-name=\"μπάσο σαξόφωνο\" type=\"Instrument name\" primary=\"primary\">μπάσο σαξόφωνο</alias></alias-list></instrument><instrument id=\"7bd32b95-416f-4244-a98b-1311ec69c7db\" type=\"String instrument\" ext:score=\"78\"><name>double bass</name><description>The double bass, also known as contrabass or upright bass as well as many other names, is the largest and lowest-pitched bowed string instrument of the violin family in the modern symphony orchestra.</description><alias-list><alias sort-name=\"ウッドベース\">ウッドベース</alias><alias sort-name=\"ストリングベース\">ストリングベース</alias><alias sort-name=\"acoustic upright bass\">acoustic upright bass</alias><alias locale=\"nl\" sort-name=\"bas\" type=\"Instrument name\">bas</alias><alias sort-name=\"bass fiddle\">bass fiddle</alias><alias sort-name=\"bass viol\">bass viol</alias><alias sort-name=\"bass violin\">bass violin</alias><alias sort-name=\"bull fiddle\">bull fiddle</alias><alias locale=\"es\" sort-name=\"contrabajo\" type=\"Instrument name\" primary=\"primary\">contrabajo</alias><alias locale=\"nl\" sort-name=\"contrabas\" type=\"Instrument name\" primary=\"primary\">contrabas</alias><alias sort-name=\"contrabass\">contrabass</alias><alias locale=\"fr\" sort-name=\"contrebasse\" type=\"Instrument name\" primary=\"primary\">contrebasse</alias><alias sort-name=\"doghouse bass\">doghouse bass</alias><alias locale=\"nl\" sort-name=\"doublebass\" type=\"Instrument name\">doublebass</alias><alias locale=\"en\" sort-name=\"double bass\" type=\"Instrument name\" primary=\"primary\">double bass</alias><alias locale=\"et\" sort-name=\"kontrabass\" type=\"Instrument name\" primary=\"primary\">kontrabass</alias><alias locale=\"de\" sort-name=\"Kontrabass\" type=\"Instrument name\" primary=\"primary\">Kontrabass</alias><alias locale=\"nl\" sort-name=\"staande bas\" type=\"Instrument name\">staande bas</alias><alias sort-name=\"stand-up bass\">stand-up bass</alias><alias sort-name=\"string bass\">string bass</alias><alias sort-name=\"upright bass\">upright bass</alias><alias sort-name=\"wood bass\">wood bass</alias><alias locale=\"el\" sort-name=\"κοντραμπάσο\" type=\"Instrument name\" primary=\"primary\">κοντραμπάσο</alias><alias locale=\"el\" sort-name=\"όρθιο μπάσο\" type=\"Instrument name\">όρθιο μπάσο</alias></alias-list></instrument><instrument id=\"1787a64f-f495-4829-96c6-39b000cbe6b0\" type=\"Wind instrument\" ext:score=\"78\"><name>bass recorder</name><alias-list><alias locale=\"ja\" sort-name=\"バス・リコーダー\" type=\"Instrument name\" primary=\"primary\">バス・リコーダー</alias><alias locale=\"nl\" sort-name=\"basblokfluit\" type=\"Instrument name\" primary=\"primary\">basblokfluit</alias><alias locale=\"hr\" sort-name=\"bas kljunasta flauta / f -bas kljunasta flauta\" type=\"Instrument name\" primary=\"primary\">bas kljunasta flauta / f -bas kljunasta flauta</alias><alias locale=\"de\" sort-name=\"Bassblockflöte\" type=\"Instrument name\" primary=\"primary\">Bassblockflöte</alias><alias locale=\"de\" sort-name=\"Bass-Blockflöte\" type=\"Instrument name\">Bass-Blockflöte</alias><alias locale=\"de\" sort-name=\"Baßblockflöte\" type=\"Instrument name\">Baßblockflöte</alias><alias locale=\"de\" sort-name=\"Baß-Blockflöte\" type=\"Instrument name\">Baß-Blockflöte</alias><alias locale=\"et\" sort-name=\"bassplokkflööt\" type=\"Instrument name\" primary=\"primary\">bassplokkflööt</alias><alias locale=\"en\" sort-name=\"bass recorder\" type=\"Instrument name\" primary=\"primary\">bass recorder</alias><alias locale=\"fi\" sort-name=\"f-bassonokkahuilu\" type=\"Instrument name\" primary=\"primary\">f-bassonokkahuilu</alias><alias locale=\"en\" sort-name=\"F-bass recorder\" type=\"Instrument name\">F-bass recorder</alias><alias locale=\"es\" sort-name=\"flautín bajo (en fa)\" type=\"Instrument name\" primary=\"primary\">flautín bajo (en fa)</alias><alias locale=\"fr\" sort-name=\"flûte à bec basse\" type=\"Instrument name\" primary=\"primary\">flûte à bec basse</alias></alias-list></instrument><instrument id=\"a9658be0-ffeb-4b64-ba96-bbe4e3c6db84\" type=\"Wind instrument\" ext:score=\"78\"><name>bass harmonica</name><description>The bass harmonica is a type of octave harmonica where the lowest note (E) is the same as that on a bass guitar.</description><alias-list><alias locale=\"es\" sort-name=\"armónica bajo\" type=\"Instrument name\" primary=\"primary\">armónica bajo</alias><alias locale=\"hr\" sort-name=\"bas harmonika\" type=\"Instrument name\" primary=\"primary\">bas harmonika</alias><alias locale=\"tr\" sort-name=\"bas harmonika\" type=\"Instrument name\" primary=\"primary\">bas harmonika</alias><alias locale=\"nl\" sort-name=\"basmondharmonica\" type=\"Instrument name\" primary=\"primary\">basmondharmonica</alias><alias locale=\"en\" sort-name=\"bass harmonica\" type=\"Instrument name\" primary=\"primary\">bass harmonica</alias><alias locale=\"de\" sort-name=\"Bass-Mundharmonika\" type=\"Instrument name\" primary=\"primary\">Bass-Mundharmonika</alias><alias locale=\"fi\" sort-name=\"bassohuuliharppu\" type=\"Instrument name\" primary=\"primary\">bassohuuliharppu</alias><alias locale=\"et\" sort-name=\"bass-suupill\" type=\"Instrument name\" primary=\"primary\">bass-suupill</alias><alias locale=\"fr\" sort-name=\"harmonica basse\" type=\"Instrument name\" primary=\"primary\">harmonica basse</alias><alias locale=\"el\" sort-name=\"μπάσο φυσαρμόνικα\" type=\"Instrument name\" primary=\"primary\">μπάσο φυσαρμόνικα</alias></alias-list></instrument><instrument id=\"27dfceab-1f17-4e62-a300-834836f77ae7\" type=\"Wind instrument\" ext:score=\"72\"><name>great bass recorder / c-bass recorder</name><alias-list><alias locale=\"ja\" sort-name=\"グレートバス・リコーダー\" type=\"Instrument name\" primary=\"primary\">グレートバス・リコーダー</alias><alias locale=\"fi\" sort-name=\"c-bassonokkahuilu\" type=\"Instrument name\" primary=\"primary\">c-bassonokkahuilu</alias><alias locale=\"en_US\" sort-name=\"C-bass recorder\" type=\"Instrument name\" primary=\"primary\">C-bass recorder</alias><alias locale=\"fr\" sort-name=\"flûte à bec grande basse\" type=\"Instrument name\" primary=\"primary\">flûte à bec grande basse</alias><alias locale=\"en_GB\" sort-name=\"great bass recorder\" type=\"Instrument name\" primary=\"primary\">great bass recorder</alias><alias locale=\"en\" sort-name=\"great bass recorder / c-bass recorder\" type=\"Instrument name\" primary=\"primary\">great bass recorder / c-bass recorder</alias><alias locale=\"nl\" sort-name=\"grootbasblokfluit\" type=\"Instrument name\" primary=\"primary\">grootbasblokfluit</alias><alias locale=\"de\" sort-name=\"Großbassblockflöte\" type=\"Instrument name\" primary=\"primary\">Großbassblockflöte</alias><alias locale=\"de\" sort-name=\"Großbass-Blockflöte\" type=\"Instrument name\">Großbass-Blockflöte</alias><alias locale=\"de\" sort-name=\"Großbaßblockflöte\" type=\"Instrument name\">Großbaßblockflöte</alias><alias locale=\"de\" sort-name=\"Großbaß-Blockflöte\" type=\"Instrument name\">Großbaß-Blockflöte</alias><alias locale=\"et\" sort-name=\"suur bassplokkflööt\" type=\"Instrument name\" primary=\"primary\">suur bassplokkflööt</alias></alias-list></instrument><instrument id=\"0b9d87fa-93fa-4956-8b6a-a419566cc915\" type=\"String instrument\" ext:score=\"71\"><name>electric bass guitar</name><alias-list><alias locale=\"ja\" sort-name=\"エレクトリックベース\" type=\"Instrument name\" primary=\"primary\">エレクトリックベース</alias><alias locale=\"pt_BR\" sort-name=\"baixo elétrico\" type=\"Instrument name\" primary=\"primary\">baixo elétrico</alias><alias locale=\"es\" sort-name=\"bajo eléctrico\" type=\"Instrument name\" primary=\"primary\">bajo eléctrico</alias><alias locale=\"de\" sort-name=\"E-Bass\" type=\"Instrument name\" primary=\"primary\">E-Bass</alias><alias locale=\"da\" sort-name=\"el-basguitar\" type=\"Instrument name\" primary=\"primary\">el-basguitar</alias><alias locale=\"en\" sort-name=\"electric bass guitar\" type=\"Instrument name\" primary=\"primary\">electric bass guitar</alias><alias locale=\"et\" sort-name=\"elektribasskitarr\" type=\"Instrument name\" primary=\"primary\">elektribasskitarr</alias><alias locale=\"nl\" sort-name=\"elektrische basgitaar\" type=\"Instrument name\" primary=\"primary\">elektrische basgitaar</alias><alias locale=\"pl\" sort-name=\"elektryczna gitara basowa\" type=\"Instrument name\" primary=\"primary\">elektryczna gitara basowa</alias><alias locale=\"fr\" sort-name=\"guitare basse\" type=\"Instrument name\" primary=\"primary\">guitare basse</alias><alias locale=\"fi\" sort-name=\"sähköbasso\" type=\"Instrument name\" primary=\"primary\">sähköbasso</alias><alias locale=\"el\" sort-name=\"ηλεκτρικό μπάσο\" type=\"Instrument name\" primary=\"primary\">ηλεκτρικό μπάσο</alias></alias-list></instrument><instrument id=\"b8471d2e-9b9d-4f52-822e-b19a37cd30ac\" type=\"String instrument\" ext:score=\"66\"><name>washtub bass</name><alias-list><alias locale=\"fr\" sort-name=\"Contrebassine\" type=\"Instrument name\" primary=\"primary\">Contrebassine</alias><alias locale=\"de\" sort-name=\"Waschwannenbass\" type=\"Instrument name\" primary=\"primary\">Waschwannenbass</alias><alias locale=\"en\" sort-name=\"washtub bass\" type=\"Instrument name\" primary=\"primary\">washtub bass</alias><alias locale=\"nl\" sort-name=\"wastobbe-bas\" type=\"Instrument name\" primary=\"primary\">wastobbe-bas</alias></alias-list></instrument><instrument id=\"bc826dde-9200-43ad-81af-6ef2c52ca37b\" type=\"Electronic instrument\" ext:score=\"66\"><name>bass pedals</name><alias-list><alias locale=\"hr\" sort-name=\"bas pedale\" type=\"Instrument name\" primary=\"primary\">bas pedale</alias><alias locale=\"nl\" sort-name=\"baspedalen\" type=\"Instrument name\" primary=\"primary\">baspedalen</alias><alias locale=\"et\" sort-name=\"bassipedaalid\" type=\"Instrument name\" primary=\"primary\">bassipedaalid</alias><alias locale=\"fi\" sort-name=\"bassopedaalit\" type=\"Instrument name\" primary=\"primary\">bassopedaalit</alias><alias locale=\"de\" sort-name=\"Basspedal\" type=\"Instrument name\" primary=\"primary\">Basspedal</alias><alias locale=\"en\" sort-name=\"bass pedals\" type=\"Instrument name\" primary=\"primary\">bass pedals</alias><alias locale=\"fr\" sort-name=\"Pédales basses\" type=\"Instrument name\" primary=\"primary\">Pédales basses</alias></alias-list></instrument><instrument id=\"e659d40f-50b4-4726-b8d5-a3e254e8008b\" type=\"Wind instrument\" ext:score=\"66\"><name>bass trombone</name><alias-list><alias locale=\"ja\" sort-name=\"バストロンボーン\" type=\"Instrument name\" primary=\"primary\">バストロンボーン</alias><alias locale=\"fi\" sort-name=\"bassopasuuna\" type=\"Instrument name\" primary=\"primary\">bassopasuuna</alias><alias locale=\"de\" sort-name=\"Bassposaune\" type=\"Instrument name\" primary=\"primary\">Bassposaune</alias><alias locale=\"en\" sort-name=\"bass trombone\" type=\"Instrument name\" primary=\"primary\">bass trombone</alias><alias locale=\"et\" sort-name=\"basstromboon\" type=\"Instrument name\" primary=\"primary\">basstromboon</alias><alias locale=\"hr\" sort-name=\"bas trombon\" type=\"Instrument name\" primary=\"primary\">bas trombon</alias><alias locale=\"tr\" sort-name=\"bas trombon\" type=\"Instrument name\" primary=\"primary\">bas trombon</alias><alias locale=\"nl\" sort-name=\"bastrombone\" type=\"Instrument name\" primary=\"primary\">bastrombone</alias><alias locale=\"es\" sort-name=\"trombón bajo\" type=\"Instrument name\" primary=\"primary\">trombón bajo</alias><alias locale=\"fr\" sort-name=\"trombone basse\" type=\"Instrument name\" primary=\"primary\">trombone basse</alias><alias locale=\"el\" sort-name=\"μπάσο τρομπόνι\" type=\"Instrument name\" primary=\"primary\">μπάσο τρομπόνι</alias></alias-list></instrument><instrument id=\"96bec768-bee7-4b67-816e-3b4743df98ec\" type=\"String instrument\" ext:score=\"66\"><name>fretless bass</name><description>variety of bass guitars without frets</description><alias-list><alias locale=\"ja\" sort-name=\"フレットレスベース\" type=\"Instrument name\" primary=\"primary\">フレットレスベース</alias><alias locale=\"et\" sort-name=\"astmetraatideta (krihvideta) basskitarr\" type=\"Instrument name\" primary=\"primary\">astmetraatideta (krihvideta) basskitarr</alias><alias locale=\"fr\" sort-name=\"basse fretless\" type=\"Instrument name\" primary=\"primary\">basse fretless</alias><alias locale=\"en\" sort-name=\"fretless bass\" type=\"Instrument name\" primary=\"primary\">fretless bass</alias><alias locale=\"nl\" sort-name=\"fretloze basgitaar\" type=\"Instrument name\" primary=\"primary\">fretloze basgitaar</alias><alias locale=\"fi\" sort-name=\"nauhaton basso\" type=\"Instrument name\" primary=\"primary\">nauhaton basso</alias><alias locale=\"tr\" sort-name=\"perdesiz bas\" type=\"Instrument name\" primary=\"primary\">perdesiz bas</alias><alias locale=\"el\" sort-name=\"άταστο μπάσο\" type=\"Instrument name\" primary=\"primary\">άταστο μπάσο</alias></alias-list></instrument><instrument id=\"b7d71e02-e76c-4483-b394-b29057888131\" type=\"Wind instrument\" ext:score=\"66\"><name>bass clarinet</name><description>The bass clarinet is a clarinet, typically pitched an octave below the soprano B♭ clarinet.</description><alias-list><alias locale=\"ja\" sort-name=\"バス・クラリネット\" type=\"Instrument name\" primary=\"primary\">バス・クラリネット</alias><alias locale=\"nl\" sort-name=\"basklarinet\" type=\"Instrument name\" primary=\"primary\">basklarinet</alias><alias locale=\"hr\" sort-name=\"bas klarinet\" type=\"Instrument name\" primary=\"primary\">bas klarinet</alias><alias locale=\"tr\" sort-name=\"bas klarnet\" type=\"Instrument name\" primary=\"primary\">bas klarnet</alias><alias locale=\"en\" sort-name=\"bass clarinet\" type=\"Instrument name\" primary=\"primary\">bass clarinet</alias><alias locale=\"de\" sort-name=\"Bassklarinette\" type=\"Instrument name\" primary=\"primary\">Bassklarinette</alias><alias locale=\"et\" sort-name=\"bassklarnet\" type=\"Instrument name\" primary=\"primary\">bassklarnet</alias><alias locale=\"fi\" sort-name=\"bassoklarinetti\" type=\"Instrument name\" primary=\"primary\">bassoklarinetti</alias><alias locale=\"es\" sort-name=\"clarinete bajo\" type=\"Instrument name\" primary=\"primary\">clarinete bajo</alias><alias locale=\"fr\" sort-name=\"clarinette basse\" type=\"Instrument name\" primary=\"primary\">clarinette basse</alias><alias locale=\"el\" sort-name=\"μπάσο κλαρινέτο\" type=\"Instrument name\" primary=\"primary\">μπάσο κλαρινέτο</alias></alias-list></instrument><instrument id=\"c3fddfb8-100a-4e25-897f-9129d5a6c39f\" type=\"Wind instrument\" ext:score=\"66\"><name>bass flute</name><description>The bass flute is a flute, pitched one octave below the C concert flute, with a tube about 1.5 meters long.</description><alias-list><alias locale=\"ja\" sort-name=\"バス・フルート\" type=\"Instrument name\" primary=\"primary\">バス・フルート</alias><alias locale=\"hr\" sort-name=\"bas flauta\" type=\"Instrument name\" primary=\"primary\">bas flauta</alias><alias locale=\"nl\" sort-name=\"basfluit\" type=\"Instrument name\" primary=\"primary\">basfluit</alias><alias locale=\"tr\" sort-name=\"bas flüt\" type=\"Instrument name\" primary=\"primary\">bas flüt</alias><alias locale=\"et\" sort-name=\"bassflööt\" type=\"Instrument name\" primary=\"primary\">bassflööt</alias><alias locale=\"de\" sort-name=\"Bassflöte\" type=\"Instrument name\" primary=\"primary\">Bassflöte</alias><alias locale=\"en\" sort-name=\"bass flute\" type=\"Instrument name\" primary=\"primary\">bass flute</alias><alias locale=\"fi\" sort-name=\"bassohuilu\" type=\"Instrument name\" primary=\"primary\">bassohuilu</alias><alias locale=\"es\" sort-name=\"flauta bajo\" type=\"Instrument name\" primary=\"primary\">flauta bajo</alias><alias locale=\"fr\" sort-name=\"flûte basse\" type=\"Instrument name\" primary=\"primary\">flûte basse</alias><alias locale=\"el\" sort-name=\"μπάσο φλάουτο\" type=\"Instrument name\" primary=\"primary\">μπάσο φλάουτο</alias></alias-list></instrument><instrument id=\"6ba5268f-766e-48b4-9d23-f378a7559f99\" type=\"String instrument\" ext:score=\"58\"><name>electric upright bass</name><alias-list><alias locale=\"ja\" sort-name=\"エレクトリック・アップライト・ベース\" type=\"Instrument name\" primary=\"primary\">エレクトリック・アップライト・ベース</alias><alias locale=\"es\" sort-name=\"contrabajo eléctrico\" type=\"Instrument name\" primary=\"primary\">contrabajo eléctrico</alias><alias locale=\"fr\" sort-name=\"contrebasse électrique\" type=\"Instrument name\" primary=\"primary\">contrebasse électrique</alias><alias locale=\"de\" sort-name=\"E-Kontrabass\" type=\"Instrument name\" primary=\"primary\">E-Kontrabass</alias><alias locale=\"en\" sort-name=\"electric upright bass\" type=\"Instrument name\" primary=\"primary\">electric upright bass</alias><alias locale=\"et\" sort-name=\"elektrikontrabass\" type=\"Instrument name\" primary=\"primary\">elektrikontrabass</alias><alias locale=\"nl\" sort-name=\"elektrische contrabas\" type=\"Instrument name\" primary=\"primary\">elektrische contrabas</alias><alias locale=\"da\" sort-name=\"el-kontrabas\" type=\"Instrument name\" primary=\"primary\">el-kontrabas</alias><alias locale=\"el\" sort-name=\"ηλεκτρικό όρθιο μπάσο\" type=\"Instrument name\" primary=\"primary\">ηλεκτρικό όρθιο μπάσο</alias></alias-list></instrument><instrument id=\"af48ce3d-80de-40cb-8cc9-e8acc138d19d\" type=\"Percussion instrument\" ext:score=\"58\"><name>gong bass drum</name><description>A gong bass drum is a large single drumhead which resembles a gong.</description><alias-list><alias locale=\"en\" sort-name=\"gong bass drum\" type=\"Instrument name\" primary=\"primary\">gong bass drum</alias><alias sort-name=\"gong drum\">gong drum</alias><alias locale=\"nl\" sort-name=\"grote gongtrom\" type=\"Instrument name\" primary=\"primary\">grote gongtrom</alias><alias locale=\"fr\" sort-name=\"tambour gong\" type=\"Instrument name\" primary=\"primary\">tambour gong</alias></alias-list></instrument><instrument id=\"15861569-249d-4b24-8ce4-d0b001b1f978\" type=\"String instrument\" ext:score=\"58\"><name>acoustic bass guitar</name><alias-list><alias locale=\"ja\" sort-name=\"アコースティック・ベース・ギター\" type=\"Instrument name\" primary=\"primary\">アコースティック・ベース・ギター</alias><alias locale=\"en\" sort-name=\"acoustic bass guitar\" type=\"Instrument name\" primary=\"primary\">acoustic bass guitar</alias><alias locale=\"nl\" sort-name=\"akoestische basgitaar\" type=\"Instrument name\" primary=\"primary\">akoestische basgitaar</alias><alias locale=\"hr\" sort-name=\"akustična bas gitara\" type=\"Instrument name\" primary=\"primary\">akustična bas gitara</alias><alias locale=\"tr\" sort-name=\"akustik bas gitar\" type=\"Instrument name\" primary=\"primary\">akustik bas gitar</alias><alias locale=\"et\" sort-name=\"akustiline basskitarr\" type=\"Instrument name\" primary=\"primary\">akustiline basskitarr</alias><alias locale=\"fi\" sort-name=\"akustinen bassokitara\" type=\"Instrument name\" primary=\"primary\">akustinen bassokitara</alias><alias locale=\"de\" sort-name=\"akustische Bassgitarre\" type=\"Instrument name\" primary=\"primary\">akustische Bassgitarre</alias><alias locale=\"da\" sort-name=\"akustisk basguitar\" type=\"Instrument name\" primary=\"primary\">akustisk basguitar</alias><alias locale=\"pl\" sort-name=\"akustyczna gitara basowa\" type=\"Instrument name\" primary=\"primary\">akustyczna gitara basowa</alias><alias locale=\"pt_BR\" sort-name=\"baixo acústico\" type=\"Instrument name\" primary=\"primary\">baixo acústico</alias><alias locale=\"es\" sort-name=\"bajo acústico\" type=\"Instrument name\" primary=\"primary\">bajo acústico</alias><alias locale=\"it\" sort-name=\"Basso acustico\" type=\"Instrument name\" primary=\"primary\">Basso acustico</alias><alias locale=\"fr\" sort-name=\"guitare basse acoustique\" type=\"Instrument name\" primary=\"primary\">guitare basse acoustique</alias><alias locale=\"el\" sort-name=\"ακουστικό μπάσο\" type=\"Instrument name\" primary=\"primary\">ακουστικό μπάσο</alias></alias-list></instrument><instrument id=\"92ed7e3f-0892-4440-b747-3b987632ecd7\" type=\"Wind instrument\" ext:score=\"36\"><name>bass trumpet</name><description>The bass trumpet is a type of low trumpet similar to the valve trombone.</description></instrument><instrument id=\"d3667988-a354-4fc4-9c1e-9baea9a43c06\" type=\"Wind instrument\" ext:score=\"36\"><name>bass oboe</name><description>The bass oboe is a double reed woodwind instrument which is about twice the size of a regular oboe.</description><alias-list><alias sort-name=\"baritone oboe\">baritone oboe</alias><alias locale=\"fr\" sort-name=\"hautbois baryton\">hautbois baryton</alias></alias-list></instrument><instrument id=\"1156c575-2165-4799-be3f-023ff1fc7655\" type=\"String instrument\" ext:score=\"29\"><name>daruan</name><description>The daruan is a Chinese plucked lute.</description><alias-list><alias sort-name=\"bass ruan\">bass ruan</alias><alias locale=\"fr\" sort-name=\"daruan\" type=\"Instrument name\" primary=\"primary\">daruan</alias><alias locale=\"nl\" sort-name=\"daruan\" type=\"Instrument name\" primary=\"primary\">daruan</alias><alias locale=\"en\" sort-name=\"daruan\" type=\"Instrument name\" primary=\"primary\">daruan</alias><alias locale=\"de\" sort-name=\"Daruan\" type=\"Instrument name\" primary=\"primary\">Daruan</alias><alias sort-name=\"dàruǎn\">dàruǎn</alias><alias locale=\"et\" sort-name=\"dàruǎn\" type=\"Instrument name\" primary=\"primary\">dàruǎn</alias><alias sort-name=\"大阮\">大阮</alias></alias-list></instrument></instrument-list></metadata>"
  },
  {
    "path": "test/data/search-label.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\" xmlns:ext=\"http://musicbrainz.org/ns/ext#-2.0\">\n  <label-list offset=\"0\" count=\"1\">\n    <label ext:score=\"100\" type=\"Original Production\" id=\"aab2e720-bdd2-4565-afc2-460743585f16\">\n      <name>Waysafe</name>\n      <sort-name>Waysafe</sort-name>\n      <country>NZ</country>\n      <life-span>\n        <begin>2001</begin>\n      </life-span>\n    </label>\n  </label-list>\n</metadata>\n"
  },
  {
    "path": "test/data/search-place.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><metadata created=\"2016-01-18T11:57:20.771Z\" xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\" xmlns:ext=\"http://musicbrainz.org/ns/ext#-2.0\"><place-list count=\"14\" offset=\"0\"><place id=\"923d73e6-cb58-4ed1-aeb7-421f952dccb2\" type=\"Venue\" ext:score=\"100\"><name>O2 Academy Newcastle</name><address>O2 Academy Newcastle, Westgate Road, NE1 1SW</address><coordinates><latitude>54.97042</latitude><longitude>-1.618654</longitude></coordinates><area id=\"80a26267-4f75-4976-ae82-aad848ec096a\"><name>Newcastle upon Tyne</name><sort-name>Newcastle upon Tyne</sort-name></area><life-span><begin>2005</begin><ended>false</ended></life-span></place><place id=\"ee07746e-440b-4ceb-8c92-bebf62a38dab\" type=\"Venue\" ext:score=\"63\"><name>O2 Guildhall</name><disambiguation>Southampton</disambiguation><address>West Marlands Road, Civic Centre, SO14 7LP</address><coordinates><latitude>50.908154</latitude><longitude>-1.406003</longitude></coordinates><area id=\"32950a38-9edd-42fd-aec9-26128507ff06\"><name>Southampton</name><sort-name>Southampton</sort-name></area><life-span><begin>1937</begin><ended>false</ended></life-span><alias-list><alias locale=\"en\" sort-name=\"Southampton Guildhall\" type=\"Place name\">Southampton Guildhall</alias></alias-list></place><place id=\"d8394564-7e73-476c-bcb9-8e274f39d50e\" type=\"Indoor arena\" ext:score=\"59\"><name>O₂ Arena</name><disambiguation>Prague, formerly Sazka Arena</disambiguation><address>Ocelářská 460, 190 00 Praha 9, Czech Republic</address><coordinates><latitude>50.10675</latitude><longitude>14.496647</longitude></coordinates><area id=\"0a65a727-7465-4e6c-8b15-ed4d09e021ee\"><name>Praha</name><sort-name>Praha</sort-name></area><life-span><begin>2004-03-27</begin><ended>false</ended></life-span><alias-list><alias sort-name=\"O2 Arena\" type=\"Search hint\">O2 Arena</alias><alias sort-name=\"Sazka Arena\" type=\"Place name\" begin-date=\"2004-03-27\" end-date=\"2008-03\">Sazka Arena</alias></alias-list></place><place id=\"2716fbb2-2f08-469f-a5eb-8ddf96c26a56\" type=\"Venue\" ext:score=\"59\"><name>O₂ Academy Islington</name><address>Angel Central, 16 Parkfield Street, Islington, N1 0PS</address><coordinates><latitude>51.534805</latitude><longitude>-0.105733</longitude></coordinates><area id=\"e3b25e1c-0adf-4773-820e-533b4f245d01\"><name>Islington</name><sort-name>Islington</sort-name></area><life-span><ended>false</ended></life-span><alias-list><alias sort-name=\"O2 Academy Islington\" type=\"Search hint\">O2 Academy Islington</alias></alias-list></place><place id=\"df819e2a-dc63-4b85-a95a-80a9aabfc53a\" type=\"Venue\" ext:score=\"59\"><name>O₂ Apollo Manchester</name><address>Stockport Road Ardwick Green Manchester M12 6AP</address><coordinates><latitude>53.469566</latitude><longitude>-2.222393</longitude></coordinates><area id=\"3ac03db8-15aa-4892-b13d-bf1e64168c29\"><name>Ardwick</name><sort-name>Ardwick</sort-name></area><life-span><begin>1938-08-29</begin><ended>false</ended></life-span><alias-list><alias sort-name=\"O2 Apollo Manchester\" type=\"Search hint\">O2 Apollo Manchester</alias></alias-list></place><place id=\"27afd0dd-179b-478b-b55e-dd4da34830b9\" type=\"Venue\" ext:score=\"50\"><name>O2 Shepherd's Bush Empire</name><address>Shepherd's Bush Green, London, W12 8TT</address><coordinates><latitude>51.50349</latitude><longitude>-0.22433</longitude></coordinates><area id=\"3c254244-166a-474c-85b5-938698ebbf28\"><name>Hammersmith and Fulham</name><sort-name>Hammersmith and Fulham</sort-name></area><life-span><ended>false</ended></life-span></place><place id=\"43e166a5-a024-4cbb-9a1f-d4947b4ff489\" type=\"Indoor arena\" ext:score=\"50\"><name>The O2 Arena</name><address>Drawdock Road, North Greenwich, London, SE10 0BB England, UK</address><coordinates><latitude>51.503</latitude><longitude>0.003133</longitude></coordinates><area id=\"4020f085-9caf-433d-b8aa-2ee86f0c7589\"><name>Greenwich</name><sort-name>Greenwich</sort-name></area><life-span><begin>2007-06-24</begin><ended>false</ended></life-span><alias-list><alias sort-name=\"North Greenwich Arena\" type=\"Place name\" begin-date=\"2012\" end-date=\"2012\">North Greenwich Arena</alias></alias-list></place><place id=\"b9d97238-6aaa-4845-a333-f01bafe53312\" type=\"Venue\" ext:score=\"50\"><name>O2 Academy Glasgow</name><address>121 Eglinton St, Glasgow G5 9NT</address><coordinates><latitude>55.8505</latitude><longitude>-4.25906</longitude></coordinates><area id=\"c279f805-01f8-46f5-99cf-51f165a1adad\"><name>Glasgow</name><sort-name>Glasgow</sort-name></area><life-span><ended>false</ended></life-span></place><place id=\"0ab6207f-7ea4-462f-80ea-2d775a7f47d5\" type=\"Venue\" ext:score=\"50\"><name>O2 Academy Oxford</name><disambiguation>previously called The Zodiac</disambiguation><address>190 Cowley Road, Oxford OX4 1UE</address><coordinates><latitude>51.74691</latitude><longitude>-1.234472</longitude></coordinates><area id=\"33587495-c775-4483-b819-931c4cf438cd\"><name>Oxford</name><sort-name>Oxford</sort-name></area><life-span><begin>1995</begin><ended>false</ended></life-span><alias-list><alias sort-name=\"Carling Academy Oxford\" type=\"Place name\" begin-date=\"2007\" end-date=\"2009-01-01\">Carling Academy Oxford</alias><alias sort-name=\"Zodiac, The\" type=\"Place name\" begin-date=\"1995\" end-date=\"2007\">The Zodiac</alias></alias-list></place><place id=\"b420c88c-959f-4266-9f66-ce48e896ffdf\" type=\"Venue\" ext:score=\"50\"><name>O2 Academy Leeds</name><disambiguation>formerly Town and Country Club &amp; Creation Nightclub</disambiguation><address>Cookridge Street, Leeds, West Yorkshire, England</address><coordinates><latitude>53.802044</latitude><longitude>-1.547069</longitude></coordinates><area id=\"400bdd75-a3a0-48e2-a6ae-c4733366aff3\"><name>Leeds</name><sort-name>Leeds</sort-name></area><life-span><begin>1992</begin><ended>false</ended></life-span><alias-list><alias sort-name=\"Creation Nightclub\" type=\"Place name\" begin-date=\"2001\" end-date=\"2007-02\">Creation Nightclub</alias><alias sort-name=\"Leeds Academy\" type=\"Place name\" begin-date=\"2008-10-08\" end-date=\"2008-11-06\">Leeds Academy</alias><alias sort-name=\"Town and Country Club\" type=\"Place name\" begin-date=\"1992\" end-date=\"2000\">Town and Country Club</alias></alias-list></place><place id=\"3c3cebfc-8609-4ad7-a73c-39db059f62fa\" type=\"Venue\" ext:score=\"50\"><name>O2 Academy Bournemouth</name><address>570 Christchurch Rd, Bournemouth, BH1 4BH</address><coordinates><latitude>50.72671</latitude><longitude>-1.839658</longitude></coordinates><area id=\"e7316723-22d9-4472-8a81-5c89425923ae\"><name>Bournemouth</name><sort-name>Bournemouth</sort-name></area><life-span><begin>1895-05-17</begin><ended>false</ended></life-span><alias-list><alias sort-name=\"Academy Nightclub\" type=\"Place name\" begin-date=\"1982\" end-date=\"1997\">Academy Nightclub</alias><alias sort-name=\"Boscombe Grand Theatre\" type=\"Place name\" begin-date=\"1895-05-17\" end-date=\"1902\">Boscombe Grand Theatre</alias><alias sort-name=\"Boscombe Hippodrome\" type=\"Place name\" begin-date=\"1902\" end-date=\"1960\">Boscombe Hippodrome</alias><alias sort-name=\"Opera House\" type=\"Place name\" begin-date=\"1997\" end-date=\"2009-07\">Opera House</alias><alias sort-name=\"Starkers Royal Arcade Ballrooms\" type=\"Place name\" begin-date=\"1960\" end-date=\"1982\">Starkers Royal Arcade Ballrooms</alias></alias-list></place><place id=\"aef2210f-8d38-40e3-84ed-bd6c338b96cc\" type=\"Venue\" ext:score=\"50\"><name>O2 Academy Birmingham</name><address>16-18 Horsefair, Birmingham B1 1DB</address><coordinates><latitude>52.473267</latitude><longitude>-1.900201</longitude></coordinates><area id=\"226c4dca-ef2a-4d4b-ba25-4118d116557a\"><name>Birmingham</name><sort-name>Birmingham</sort-name></area><life-span><begin>2009-09-10</begin><ended>false</ended></life-span></place><place id=\"fdebe2ec-b549-40a0-8bb1-fdb88103e383\" ext:score=\"41\"><name>Brooklyn Bowl London</name><address>Brooklyn Bowl London, The O2, Peninsula Square, London SE10 0DX</address><coordinates><latitude>51.50303</latitude><longitude>0.003139</longitude></coordinates><area id=\"4020f085-9caf-433d-b8aa-2ee86f0c7589\"><name>Greenwich</name><sort-name>Greenwich</sort-name></area><life-span><begin>2014-01-17</begin><ended>false</ended></life-span></place><place id=\"04b7787d-db6c-4a29-af2f-ec3a89d961c4\" type=\"Indoor arena\" ext:score=\"29\"><name>Barclaycard Arena</name><disambiguation>Hamburg, formerly \"Color Line Arena\" and \"O₂ World Hamburg\"</disambiguation><address>Sylvesterallee 10, 22525 Hamburg, Germany</address><coordinates><latitude>53.58917</latitude><longitude>9.899167</longitude></coordinates><area id=\"11a44e18-a2e5-43a9-bee9-aa4f7c83f967\"><name>Hamburg</name><sort-name>Hamburg</sort-name></area><life-span><begin>2002-11-08</begin><ended>false</ended></life-span><alias-list><alias sort-name=\"Colorline Arena\" type=\"Search hint\">Colorline Arena</alias><alias sort-name=\"Color Line Arena\" type=\"Place name\" begin-date=\"2002\" end-date=\"2010\">Color Line Arena</alias><alias sort-name=\"O2 World Hamburg\" type=\"Search hint\">O2 World Hamburg</alias><alias sort-name=\"O₂ World Hamburg\" type=\"Place name\" begin-date=\"2010\" end-date=\"2015\">O₂ World Hamburg</alias></alias-list></place></place-list></metadata>"
  },
  {
    "path": "test/data/search-recording.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\" xmlns:ext=\"http://musicbrainz.org/ns/ext#-2.0\">\n  <recording-list offset=\"0\" count=\"1258\">\n    <recording ext:score=\"100\" id=\"cb4d4d70-930c-4d1a-a157-776de18be66a\">\n      <title>Thief of Hearts</title>\n      <length>198586</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\">\n          <title>Folly, Vice &amp; Madness</title>\n          <status>Official</status>\n          <release-group type=\"EP\"/>\n          <date>2006-11-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>5</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"3\" count=\"5\">\n                <track>\n                  <title>Thief of Hearts</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"ac78e2cd-720c-48be-b79f-d6d6ed5a05c4\">\n      <title>Waiting My Turn</title>\n      <length>187706</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\">\n          <title>Folly, Vice &amp; Madness</title>\n          <status>Official</status>\n          <release-group type=\"EP\"/>\n          <date>2006-11-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>5</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"1\" count=\"5\">\n                <track>\n                  <title>Waiting My Turn</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"fc167a9c-7aca-4e27-a266-7d04b07004d6\">\n      <title>Just a Victim</title>\n      <length>226000</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\">\n          <title>Folly, Vice &amp; Madness</title>\n          <status>Official</status>\n          <release-group type=\"EP\"/>\n          <date>2006-11-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>5</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"0\" count=\"5\">\n                <track>\n                  <title>Just a Victim</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"35421254-0c57-40d0-a527-76709363f210\">\n      <title>Retail Guru</title>\n      <length>114493</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\">\n          <title>Folly, Vice &amp; Madness</title>\n          <status>Official</status>\n          <release-group type=\"EP\"/>\n          <date>2006-11-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>5</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"4\" count=\"5\">\n                <track>\n                  <title>Retail Guru</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"dc644a8d-6640-4117-8d96-5b9504c40cf1\">\n      <title>If this Beard Had Wings</title>\n      <length>253346</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\">\n          <title>Folly, Vice &amp; Madness</title>\n          <status>Official</status>\n          <release-group type=\"EP\"/>\n          <date>2006-11-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>5</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"2\" count=\"5\">\n                <track>\n                  <title>If this Beard Had Wings</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"6f039458-796d-4e04-887c-5e8aa50fccb1\">\n      <title>Headrush</title>\n      <length>45973</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"5\" count=\"12\">\n                <track>\n                  <title>Headrush</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"e459c762-69b3-433a-8584-0bb88d0a3eb4\">\n      <title>Final Reunion</title>\n      <length>193253</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"11\" count=\"12\">\n                <track>\n                  <title>Final Reunion</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"f6e5c2f6-fd65-43b5-9e51-5d153d2cba02\">\n      <title>Nothing Ever Happens</title>\n      <length>92013</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"9\" count=\"12\">\n                <track>\n                  <title>Nothing Ever Happens</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"fba85059-d6c0-49a9-be1f-267fa9d4d614\">\n      <title>Johnny the Punk</title>\n      <length>190640</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"6\" count=\"12\">\n                <track>\n                  <title>Johnny the Punk</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"7ae51bcb-8a9b-47c9-a06d-19106f7070a5\">\n      <title>Already Met Your Mother</title>\n      <length>231706</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"4\" count=\"12\">\n                <track>\n                  <title>Already Met Your Mother</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"b547acbc-58c6-4a31-9806-e2348db3a167\">\n      <title>Route 17</title>\n      <length>205106</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"2\" count=\"12\">\n                <track>\n                  <title>Route 17</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"e4cf738e-699c-4331-880a-3db462a8e91e\">\n      <title>Sad Again</title>\n      <length>181053</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"7\" count=\"12\">\n                <track>\n                  <title>Sad Again</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"6a47088b-d9e0-4088-868a-394ee3c6cd33\">\n      <title>Fountain City</title>\n      <length>172760</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"1\" count=\"12\">\n                <track>\n                  <title>Fountain City</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"f70bbd32-2f10-440a-a59a-8cd829078a9f\">\n      <title>Crying On My Street</title>\n      <length>144306</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"0\" count=\"12\">\n                <track>\n                  <title>Crying On My Street</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"621fcc74-4ab0-45cc-a0a1-9348ccca1f7b\">\n      <title>Frozen to the Bone</title>\n      <length>166920</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"3\" count=\"12\">\n                <track>\n                  <title>Frozen to the Bone</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"428bffe8-3c84-41d4-a3de-5b7ee5a23061\">\n      <title>What Went Wrong?</title>\n      <length>148826</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"10\" count=\"12\">\n                <track>\n                  <title>What Went Wrong?</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"5bef501f-c91b-4055-a59f-903fe617d4d2\">\n      <title>You Fell From The Sky</title>\n      <length>194826</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"8ec178f4-a8e8-4f22-bcba-1964466ef214\">\n          <title>The Fool of Fountain City</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2009-04-03</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>12</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"8\" count=\"12\">\n                <track>\n                  <title>You Fell From The Sky</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"93468a09-9662-4886-a227-56a2ad1c5246\">\n      <title>Poor Alfred</title>\n      <length>151000</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"c15b2c70-2dc1-4bc6-bbf7-ed05b8cc1d51\">\n          <title>Poor Alfred</title>\n          <status>Official</status>\n          <release-group type=\"Single\"/>\n          <date>2010</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>2</track-count>\n            <medium>\n              <position>1</position>\n              <format>Digital Media</format>\n              <track-list offset=\"0\" count=\"2\">\n                <track>\n                  <title>Poor Alfred</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"1ae48879-48e6-4be8-a80c-0cf673c70734\">\n      <title>Talk Quickly</title>\n      <length>120000</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"c15b2c70-2dc1-4bc6-bbf7-ed05b8cc1d51\">\n          <title>Poor Alfred</title>\n          <status>Official</status>\n          <release-group type=\"Single\"/>\n          <date>2010</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>2</track-count>\n            <medium>\n              <position>1</position>\n              <format>Digital Media</format>\n              <track-list offset=\"1\" count=\"2\">\n                <track>\n                  <title>Talk Quickly</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"91af2b87-e048-4415-92c0-2b7a396298be\">\n      <title>Sad Again</title>\n      <length>275426</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"e94757ff-2655-4690-b369-4012beba6114\">\n          <title>Affordable Pop Music</title>\n          <status>Official</status>\n          <release-group type=\"EP\"/>\n          <date>2008-07-04</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>4</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"1\" count=\"4\">\n                <track>\n                  <title>Sad Again</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"ad5a48b4-c304-4080-85a8-dd2b0d96c359\">\n      <title>Dead By Morning</title>\n      <length>115933</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"e94757ff-2655-4690-b369-4012beba6114\">\n          <title>Affordable Pop Music</title>\n          <status>Official</status>\n          <release-group type=\"EP\"/>\n          <date>2008-07-04</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>4</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"2\" count=\"4\">\n                <track>\n                  <title>Dead By Morning</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"b073a71e-493e-421a-b6ff-1cbf5fe3a616\">\n      <title>New Bed Science</title>\n      <length>204613</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"e94757ff-2655-4690-b369-4012beba6114\">\n          <title>Affordable Pop Music</title>\n          <status>Official</status>\n          <release-group type=\"EP\"/>\n          <date>2008-07-04</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>4</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"3\" count=\"4\">\n                <track>\n                  <title>New Bed Science</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"41\" id=\"103e3fd2-e1cf-4f24-9fb1-c34f7a9fe3c1\">\n      <title>Middle Class</title>\n      <length>200360</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"e94757ff-2655-4690-b369-4012beba6114\">\n          <title>Affordable Pop Music</title>\n          <status>Official</status>\n          <release-group type=\"EP\"/>\n          <date>2008-07-04</date>\n          <country>NZ</country>\n          <medium-list>\n            <track-count>4</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"0\" count=\"4\">\n                <track>\n                  <title>Middle Class</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"16\" id=\"5d93c09f-e20c-4518-a94a-cb91207c6a3c\">\n      <title>Thief</title>\n      <length>294826</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"93585c1b-ec0f-4d47-9cae-bd8ebcc52e9f\">\n            <name>Third Day</name>\n            <sort-name>Third Day</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"853888ce-714b-4310-886e-ae133dbacbb1\">\n          <title>Offerings</title>\n          <status>Official</status>\n          <release-group type=\"Album\"/>\n          <date>2000-07-11</date>\n          <country>US</country>\n          <medium-list>\n            <track-count>11</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"7\" count=\"11\">\n                <track>\n                  <title>Thief</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n    </recording>\n    <recording ext:score=\"16\" id=\"b47c4a38-a130-484a-83cd-810e7b627ddf\">\n      <title>Thief</title>\n      <length>306333</length>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"13501c7d-d181-45ba-af52-5f101d8516a0\">\n            <name>CAN</name>\n            <sort-name>CAN</sort-name>\n            <disambiguation>German rock band</disambiguation>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list>\n        <release id=\"11dc3456-3d5d-43ea-a061-8fd1f5612e44\">\n          <title>Delay 1968</title>\n          <status>Official</status>\n          <release-group type=\"Compilation\"/>\n          <date>1981</date>\n          <country>US</country>\n          <medium-list>\n            <track-count>7</track-count>\n            <medium>\n              <position>1</position>\n              <track-list offset=\"3\" count=\"7\">\n                <track>\n                  <title>Thief</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n        <release id=\"4ccb5e95-90dd-3b4c-9a3e-57f866dbf10d\">\n          <title>Delay 1968</title>\n          <status>Official</status>\n          <release-group type=\"Compilation\"/>\n          <date>2006-05-29</date>\n          <country>GB</country>\n          <medium-list>\n            <track-count>7</track-count>\n            <medium>\n              <position>1</position>\n              <format>SACD</format>\n              <track-list offset=\"3\" count=\"7\">\n                <track>\n                  <title>Thief</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n        <release id=\"297f494a-8e80-349e-bae4-61fa32079ec6\">\n          <title>Delay 1968</title>\n          <status>Official</status>\n          <release-group type=\"Compilation\"/>\n          <date>1981</date>\n          <country>DE</country>\n          <medium-list>\n            <track-count>7</track-count>\n            <medium>\n              <position>1</position>\n              <format>Vinyl</format>\n              <track-list offset=\"3\" count=\"7\">\n                <track>\n                  <title>Thief</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n        <release id=\"2508e4a2-7149-3e93-91d9-46e0f6ea2206\">\n          <title>Delay 1968</title>\n          <status>Official</status>\n          <release-group type=\"Compilation\"/>\n          <date>1989</date>\n          <country>CH</country>\n          <medium-list>\n            <track-count>7</track-count>\n            <medium>\n              <position>1</position>\n              <format>CD</format>\n              <track-list offset=\"3\" count=\"7\">\n                <track>\n                  <title>Thief</title>\n                </track>\n              </track-list>\n            </medium>\n          </medium-list>\n        </release>\n      </release-list>\n      <tag-list>\n        <tag count=\"1\">\n          <name>to radiohead stop ruining can</name>\n        </tag>\n      </tag-list>\n    </recording>\n  </recording-list>\n</metadata>\n"
  },
  {
    "path": "test/data/search-release-group.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\" xmlns:ext=\"http://musicbrainz.org/ns/ext#-2.0\">\n  <release-group-list offset=\"0\" count=\"14641\">\n    <release-group ext:score=\"100\" type=\"EP\" id=\"6561c223-18e6-3b88-9adc-a701700fc91e\">\n      <title>Affordable Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"e94757ff-2655-4690-b369-4012beba6114\">\n          <title>Affordable Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"29\" id=\"a02d29b6-a05e-358b-9d95-dede07717949\">\n      <title>Affordable Art</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"6dcf3c49-6293-4bd3-bcff-ddaefc967089\">\n            <name>Steve Goodman</name>\n            <sort-name>Goodman, Steve</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"89637b55-1b5c-4943-bf7f-08a47da20d3d\">\n          <title>Affordable Art</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"29\" type=\"EP\" id=\"23e02d55-522e-36a7-9b7c-3b47b3282609\">\n      <title>Affordable Luxury</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"4ee34d2b-97d0-4854-b7ee-4e96d343ad7c\">\n            <name>Spielerfrau</name>\n            <sort-name>Spielerfrau</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"ae8106f8-6ec6-476e-a7b3-56cb1d06dd53\">\n          <title>Affordable Luxury</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"25\" type=\"Album\" id=\"3f2c2479-5582-390a-8038-b48c979c0e16\">\n      <title>Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"bd2d100b-aecd-4639-8c9a-5581a63ec64f\">\n            <name>Eva Braun</name>\n            <sort-name>Eva Braun</sort-name>\n            <disambiguation>Serbian pop-rock band</disambiguation>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"e0aec712-3893-4b2a-ab59-d57927dbd949\">\n          <title>Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"25\" type=\"Album\" id=\"7faef577-d60c-3edc-a48c-37e0e074ee29\">\n      <title>Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"425c778c-88ba-4bca-bb1e-d170b77d0047\">\n            <name>Thierry Hazard</name>\n            <sort-name>Hazard, Thierry</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"2\">\n        <release id=\"07e7cc34-21f8-4aba-b287-9766f60834bd\">\n          <title>Pop Music</title>\n        </release>\n        <release id=\"aaa6e088-ef43-3809-bffa-b771ed6b25c2\">\n          <title>Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"25\" type=\"Album\" id=\"69e9d2a9-65e2-422b-a6fb-c295265772d8\">\n      <title>Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"5a244dd8-546d-4ab4-9651-90c974737ad2\">\n            <name>Todor Kobakov</name>\n            <sort-name>Kobakov, Todor</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"83703bdb-2df3-4883-a536-5a073b2ec80f\">\n          <title>Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"25\" type=\"Compilation\" id=\"a839cc6e-e5a7-3659-91d9-73d05cc41445\">\n      <title>Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"f37b3f31-b1f8-4b88-8cb5-b34f709b17d7\">\n            <name>Iggy Pop</name>\n            <sort-name>Pop, Iggy</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"d7519ee9-ed66-4573-a8d8-814e729e1ea3\">\n          <title>Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" id=\"324c318d-4fde-3389-a3cc-fc6b82099085\">\n      <title>Stereophonic Pop Art Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"797d927d-c4e8-4908-932a-238b8a09294b\">\n            <name>Alpha Stone</name>\n            <sort-name>Alpha Stone</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"2d502144-81be-4eb5-a977-cf82063499b7\">\n          <title>Stereophonic Pop Art Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"Album\" id=\"9a5d1c34-e96f-3951-b308-25a3d4853d34\">\n      <title>Pop Music for Dancing</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"acb19bfc-0a7c-49ab-910c-c3d915dd082e\">\n            <name>Ted Atking &amp; His Orchestra</name>\n            <sort-name>Ted Atking &amp; His Orchestra</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"52900377-39bd-4c31-9c85-d05b71eaf1a7\">\n          <title>Pop Music for Dancing</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" id=\"2a3f93f7-5dd7-3982-b111-e638d35b2685\">\n      <title>This Is Pop Music.</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"eb7e6de0-8da8-4739-b9e5-7267c194b92e\">\n          <title>This Is Pop Music.</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"Single\" id=\"27f59a9a-3c94-3e64-9cee-19956b3ffcae\">\n      <title>Pop The Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"38370358-9813-491c-af5a-df9087f9664b\">\n            <name>Triim</name>\n            <sort-name>Triim</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"411d64dc-075a-4802-96b1-42eae17935b1\">\n          <title>Pop The Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"Compilation\" id=\"144bd616-38ad-4b48-8433-fd96f4e2da31\">\n      <title>Better Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"a5406591-fa42-45e0-87e2-84a7b17a49b3\">\n          <title>Better Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"Other\" id=\"9b4d7297-289a-4542-9828-2dccea7b3bd4\">\n      <title>Dance / Pop Music</title>\n      <artist-credit>\n        <name-credit joinphrase=\" &amp; \">\n          <artist id=\"d5d5c3e5-2976-4ac7-acd7-b8bdb9ec7559\">\n            <name>Neil Watson</name>\n            <sort-name>Watson, Neil</sort-name>\n          </artist>\n        </name-credit>\n        <name-credit>\n          <artist id=\"a57ae220-e088-47d1-83ec-fda2c963d14a\">\n            <name>Mark Sandell</name>\n            <sort-name>Sandell, Mark</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"c466130c-c286-49b8-b7ae-e868ac1e7042\">\n          <title>Dance / Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"Compilation\" id=\"3bbb7210-3548-464e-b775-06d904ec5626\">\n      <title>Pepsi Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"11220cf7-32df-40e2-9dfe-bb37b4387770\">\n          <title>Pepsi Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"Compilation\" id=\"50cfc374-4912-4de8-9a1d-db41a6b4f54c\">\n      <title>Kellogg's Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"a568035c-3f4c-4c74-96f7-95b99e47c281\">\n          <title>Kellogg's Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"Compilation\" id=\"b1611666-e997-49c1-94b5-dabcc0551db9\">\n      <title>Swedish Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"97a19cfd-022c-46b8-8651-00766a1719a0\">\n          <title>Swedish Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"Compilation\" id=\"b76048e2-965c-40ad-b410-8576276a055a\">\n      <title>Pop Music Highlights</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"0\"/>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"EP\" id=\"2547fafe-a82c-49a7-bf4f-c1690badc196\">\n      <title>Pop Music United EP</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"530d045f-5517-4be8-99d9-683dc30b3271\">\n            <name>Paul Avion</name>\n            <sort-name>Avion, Paul</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"d923e7b5-6f31-4da4-9f23-22a9b3fc2607\">\n          <title>Pop Music United</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"20\" type=\"Album\" id=\"25cdc194-9d11-3dfd-a127-54d0200bc539\">\n      <title>This Is Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"75806efb-b691-4472-8484-e44e7f5d4770\">\n            <name>Espen Lind</name>\n            <sort-name>Lind, Espen</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"2\">\n        <release id=\"9bb15c41-fbfd-4b5b-a563-67ac5c85a11b\">\n          <title>This Is Pop Music</title>\n        </release>\n        <release id=\"3f7e7a1f-8a1a-459c-83fd-fe99080b9dff\">\n          <title>This Is Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"19\" type=\"Compilation\" id=\"855075e5-3ace-3e28-b3eb-902f4db8aa2a\">\n      <title>Pop! Justice: 100% Solid Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"1f08c98d-7bfe-43f9-82d3-74c9ac139d62\">\n          <title>Pop! Justice: 100% Solid Pop Music</title>\n        </release>\n      </release-list>\n      <tag-list>\n        <tag count=\"1\">\n          <name>barbadian</name>\n        </tag>\n      </tag-list>\n    </release-group>\n    <release-group ext:score=\"17\" type=\"Compilation\" id=\"c15656d6-c322-3565-a5d2-9ef695d9907a\">\n      <title>20 Years of Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"b922ff57-9289-4ea4-999e-cd4ddb986614\">\n          <title>20 Years of Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"17\" type=\"Compilation\" id=\"ea43c228-8956-3e32-968c-645b04dc7491\">\n      <title>Proiect Special OMV: Pop Music</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"3fcc4cf7-bed8-49d8-ae78-e06483e9b2a6\">\n          <title>Proiect Special OMV: Pop Music</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"17\" type=\"Other\" id=\"476821e8-ba85-4f91-8b1f-9662a473d3a7\">\n      <title>Dance / Pop Music 4</title>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"da721dd5-5e5f-4733-b785-8b230c6982f6\">\n          <title>Dance / Pop Music 4</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"17\" type=\"Other\" id=\"41a3c6a0-3303-4f69-92bc-b6090f99f962\">\n      <title>Dance / Pop Music 2</title>\n      <artist-credit>\n        <name-credit joinphrase=\" &amp; \">\n          <artist id=\"d5d5c3e5-2976-4ac7-acd7-b8bdb9ec7559\">\n            <name>Neil Watson</name>\n            <sort-name>Watson, Neil</sort-name>\n          </artist>\n        </name-credit>\n        <name-credit>\n          <artist id=\"a57ae220-e088-47d1-83ec-fda2c963d14a\">\n            <name>Mark Sandell</name>\n            <sort-name>Sandell, Mark</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"9f58b873-70e4-462d-a435-d26d14809dae\">\n          <title>Dance / Pop Music 2</title>\n        </release>\n      </release-list>\n    </release-group>\n    <release-group ext:score=\"17\" type=\"Other\" id=\"a839fb84-f8a9-4cef-ae74-1a4e83c7d67a\">\n      <title>Dance / Pop Music 3</title>\n      <artist-credit>\n        <name-credit joinphrase=\" &amp; \">\n          <artist id=\"d5d5c3e5-2976-4ac7-acd7-b8bdb9ec7559\">\n            <name>Neil Watson</name>\n            <sort-name>Watson, Neil</sort-name>\n          </artist>\n        </name-credit>\n        <name-credit>\n          <artist id=\"a57ae220-e088-47d1-83ec-fda2c963d14a\">\n            <name>Mark Sandell</name>\n            <sort-name>Sandell, Mark</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-list count=\"1\">\n        <release id=\"f101d6c4-4dd1-487d-b172-986da04ebf03\">\n          <title>Dance / Pop Music 3</title>\n        </release>\n      </release-list>\n    </release-group>\n  </release-group-list>\n</metadata>\n"
  },
  {
    "path": "test/data/search-release.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\" xmlns:ext=\"http://musicbrainz.org/ns/ext#-2.0\">\n  <release-list offset=\"0\" count=\"16739\">\n    <release ext:score=\"100\" id=\"e94757ff-2655-4690-b369-4012beba6114\">\n      <title>Affordable Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"952a4205-023d-4235-897c-6fdb6f58dfaa\">\n            <name>Dynamo Go</name>\n            <sort-name>Dynamo Go</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"EP\" id=\"6561c223-18e6-3b88-9adc-a701700fc91e\"/>\n      <date>2008-07-04</date>\n      <country>NZ</country>\n      <barcode>9421021463277</barcode>\n      <label-info-list>\n        <label-info>\n          <catalog-number>WS06</catalog-number>\n          <label id=\"aab2e720-bdd2-4565-afc2-460743585f16\">\n            <name>Waysafe</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>4</track-count>\n        <medium>\n          <format>CD</format>\n          <disc-list count=\"1\"/>\n          <track-list count=\"4\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"29\" id=\"ae8106f8-6ec6-476e-a7b3-56cb1d06dd53\">\n      <title>Affordable Luxury</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"4ee34d2b-97d0-4854-b7ee-4e96d343ad7c\">\n            <name>Spielerfrau</name>\n            <sort-name>Spielerfrau</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"EP\" id=\"23e02d55-522e-36a7-9b7c-3b47b3282609\"/>\n      <date>2005</date>\n      <country>US</country>\n      <medium-list count=\"1\">\n        <track-count>5</track-count>\n        <medium>\n          <disc-list count=\"0\"/>\n          <track-list count=\"5\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"29\" id=\"89637b55-1b5c-4943-bf7f-08a47da20d3d\">\n      <title>Affordable Art</title>\n      <text-representation>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"6dcf3c49-6293-4bd3-bcff-ddaefc967089\">\n            <name>Steve Goodman</name>\n            <sort-name>Goodman, Steve</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group id=\"a02d29b6-a05e-358b-9d95-dede07717949\"/>\n      <date>1983</date>\n      <asin>B000000DLV</asin>\n      <medium-list count=\"1\">\n        <track-count>12</track-count>\n        <medium>\n          <disc-list count=\"1\"/>\n          <track-list count=\"12\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"25\" id=\"07e7cc34-21f8-4aba-b287-9766f60834bd\">\n      <title>Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>fra</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"425c778c-88ba-4bca-bb1e-d170b77d0047\">\n            <name>Thierry Hazard</name>\n            <sort-name>Hazard, Thierry</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Album\" id=\"7faef577-d60c-3edc-a48c-37e0e074ee29\"/>\n      <date>1990-11</date>\n      <country>FR</country>\n      <barcode>5099746735425</barcode>\n      <asin>B00004UI3D</asin>\n      <label-info-list>\n        <label-info>\n          <catalog-number>467354 2</catalog-number>\n          <label id=\"ad6f8706-c95e-443b-8579-8e3ecd27126c\">\n            <name>Columbia Records</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>12</track-count>\n        <medium>\n          <format>CD</format>\n          <disc-list count=\"1\"/>\n          <track-list count=\"12\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"25\" id=\"aaa6e088-ef43-3809-bffa-b771ed6b25c2\">\n      <title>Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>fra</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"425c778c-88ba-4bca-bb1e-d170b77d0047\">\n            <name>Thierry Hazard</name>\n            <sort-name>Hazard, Thierry</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Album\" id=\"7faef577-d60c-3edc-a48c-37e0e074ee29\"/>\n      <date>1990-11</date>\n      <country>FR</country>\n      <barcode>5099746735449</barcode>\n      <label-info-list>\n        <label-info>\n          <catalog-number>467354 4</catalog-number>\n          <label id=\"ad6f8706-c95e-443b-8579-8e3ecd27126c\">\n            <name>Columbia Records</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>12</track-count>\n        <medium>\n          <format>Cassette</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"12\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"25\" id=\"83703bdb-2df3-4883-a536-5a073b2ec80f\">\n      <title>Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"5a244dd8-546d-4ab4-9651-90c974737ad2\">\n            <name>Todor Kobakov</name>\n            <sort-name>Kobakov, Todor</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Album\" id=\"69e9d2a9-65e2-422b-a6fb-c295265772d8\"/>\n      <date>2009-10-13</date>\n      <country>CA</country>\n      <asin>B002MED6QW</asin>\n      <medium-list count=\"1\">\n        <track-count>11</track-count>\n        <medium>\n          <disc-list count=\"0\"/>\n          <track-list count=\"11\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"25\" id=\"d7519ee9-ed66-4573-a8d8-814e729e1ea3\">\n      <title>Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"f37b3f31-b1f8-4b88-8cb5-b34f709b17d7\">\n            <name>Iggy Pop</name>\n            <sort-name>Pop, Iggy</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Compilation\" id=\"a839cc6e-e5a7-3659-91d9-73d05cc41445\"/>\n      <asin>B0000072ZP</asin>\n      <medium-list count=\"1\">\n        <track-count>20</track-count>\n        <medium>\n          <disc-list count=\"2\"/>\n          <track-list count=\"20\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"25\" id=\"e0aec712-3893-4b2a-ab59-d57927dbd949\">\n      <title>Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>srp</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"bd2d100b-aecd-4639-8c9a-5581a63ec64f\">\n            <name>Eva Braun</name>\n            <sort-name>Eva Braun</sort-name>\n            <disambiguation>Serbian pop-rock band</disambiguation>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Album\" id=\"3f2c2479-5582-390a-8038-b48c979c0e16\"/>\n      <date>1995</date>\n      <country>CS</country>\n      <label-info-list>\n        <label-info>\n          <label id=\"ca119df7-ebdf-4a31-a829-bd2c37f39103\">\n            <name>B92</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>15</track-count>\n        <medium>\n          <format>Cassette</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"15\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"9bb15c41-fbfd-4b5b-a563-67ac5c85a11b\">\n      <title>This Is Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"75806efb-b691-4472-8484-e44e7f5d4770\">\n            <name>Espen Lind</name>\n            <sort-name>Lind, Espen</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Album\" id=\"25cdc194-9d11-3dfd-a127-54d0200bc539\"/>\n      <date>2000</date>\n      <country>NO</country>\n      <asin>B00005L90U</asin>\n      <label-info-list>\n        <label-info>\n          <label id=\"7a37872d-8ead-432a-ab7e-40725fcb943c\">\n            <name>Universal Music A/S</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>10</track-count>\n        <medium>\n          <format>CD</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"10\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"411d64dc-075a-4802-96b1-42eae17935b1\">\n      <title>Pop The Music</title>\n      <status>Promotion</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"38370358-9813-491c-af5a-df9087f9664b\">\n            <name>Triim</name>\n            <sort-name>Triim</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Single\" id=\"27f59a9a-3c94-3e64-9cee-19956b3ffcae\"/>\n      <date>2005</date>\n      <country>FR</country>\n      <medium-list count=\"1\">\n        <track-count>1</track-count>\n        <medium>\n          <disc-list count=\"0\"/>\n          <track-list count=\"1\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"3f7e7a1f-8a1a-459c-83fd-fe99080b9dff\">\n      <title>This Is Pop Music</title>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"75806efb-b691-4472-8484-e44e7f5d4770\">\n            <name>Espen Lind</name>\n            <sort-name>Lind, Espen</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Album\" id=\"25cdc194-9d11-3dfd-a127-54d0200bc539\"/>\n      <date>2001</date>\n      <country>JP</country>\n      <asin>B00005L90U</asin>\n      <medium-list count=\"1\">\n        <track-count>11</track-count>\n        <medium>\n          <format>CD</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"11\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"2d502144-81be-4eb5-a977-cf82063499b7\">\n      <title>Stereophonic Pop Art Music</title>\n      <status>Official</status>\n      <text-representation>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"797d927d-c4e8-4908-932a-238b8a09294b\">\n            <name>Alpha Stone</name>\n            <sort-name>Alpha Stone</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group id=\"324c318d-4fde-3389-a3cc-fc6b82099085\"/>\n      <asin>B000003JGG</asin>\n      <medium-list count=\"1\">\n        <track-count>8</track-count>\n        <medium>\n          <disc-list count=\"0\"/>\n          <track-list count=\"8\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"11220cf7-32df-40e2-9dfe-bb37b4387770\">\n      <title>Pepsi Pop Music</title>\n      <status>Promotion</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Compilation\" id=\"3bbb7210-3548-464e-b775-06d904ec5626\"/>\n      <medium-list count=\"1\">\n        <track-count>8</track-count>\n        <medium>\n          <disc-list count=\"0\"/>\n          <track-list count=\"8\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"97a19cfd-022c-46b8-8651-00766a1719a0\">\n      <title>Swedish Pop Music</title>\n      <status>Promotion</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Compilation\" id=\"b1611666-e997-49c1-94b5-dabcc0551db9\"/>\n      <date>2009</date>\n      <country>SE</country>\n      <medium-list count=\"1\">\n        <track-count>20</track-count>\n        <medium>\n          <format>CD</format>\n          <disc-list count=\"1\"/>\n          <track-list count=\"20\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"a5406591-fa42-45e0-87e2-84a7b17a49b3\">\n      <title>Better Pop Music</title>\n      <status>Promotion</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Compilation\" id=\"144bd616-38ad-4b48-8433-fd96f4e2da31\"/>\n      <date>2010-05-20</date>\n      <country>GB</country>\n      <label-info-list>\n        <label-info>\n          <label id=\"e66c5203-0c79-4ea1-9395-535097b87ca9\">\n            <name>Something in Construction</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>19</track-count>\n        <medium>\n          <format>Digital Media</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"19\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"a568035c-3f4c-4c74-96f7-95b99e47c281\">\n      <title>Kellogg's Pop Music</title>\n      <status>Promotion</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Compilation\" id=\"50cfc374-4912-4de8-9a1d-db41a6b4f54c\"/>\n      <date>1998</date>\n      <country>US</country>\n      <barcode>634133052492</barcode>\n      <label-info-list>\n        <label-info>\n          <catalog-number>DPSM 5249</catalog-number>\n          <label id=\"dd9b460c-c27b-424c-8e25-7bb441ed8618\">\n            <name>PolyGram Records Inc.</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>2</track-count>\n        <medium>\n          <format>CD</format>\n          <disc-list count=\"1\"/>\n          <track-list count=\"2\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"eb7e6de0-8da8-4739-b9e5-7267c194b92e\">\n      <title>This Is Pop Music.</title>\n      <status>Promotion</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group id=\"2a3f93f7-5dd7-3982-b111-e638d35b2685\"/>\n      <medium-list count=\"1\">\n        <track-count>5</track-count>\n        <medium>\n          <disc-list count=\"1\"/>\n          <track-list count=\"5\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"d923e7b5-6f31-4da4-9f23-22a9b3fc2607\">\n      <title>Pop Music United</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"530d045f-5517-4be8-99d9-683dc30b3271\">\n            <name>Paul Avion</name>\n            <sort-name>Avion, Paul</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"EP\" id=\"2547fafe-a82c-49a7-bf4f-c1690badc196\"/>\n      <date>2006</date>\n      <country>US</country>\n      <barcode>837101239905</barcode>\n      <asin>B000K97S8I</asin>\n      <label-info-list>\n        <label-info>\n          <label id=\"157afde4-4bf5-4039-8ad2-5a15acc85176\">\n            <name>[no label]</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>8</track-count>\n        <medium>\n          <format>CD</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"8\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"c466130c-c286-49b8-b7ae-e868ac1e7042\">\n      <title>Dance / Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit joinphrase=\" &amp; \">\n          <artist id=\"d5d5c3e5-2976-4ac7-acd7-b8bdb9ec7559\">\n            <name>Neil Watson</name>\n            <sort-name>Watson, Neil</sort-name>\n          </artist>\n        </name-credit>\n        <name-credit>\n          <artist id=\"a57ae220-e088-47d1-83ec-fda2c963d14a\">\n            <name>Mark Sandell</name>\n            <sort-name>Sandell, Mark</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Other\" id=\"9b4d7297-289a-4542-9828-2dccea7b3bd4\"/>\n      <country>US</country>\n      <label-info-list>\n        <label-info>\n          <catalog-number>CHAPAV 47</catalog-number>\n          <label id=\"fe50ac68-115f-4377-9dd8-124ec3fc1dbd\">\n            <name>Chappell AV</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>17</track-count>\n        <medium>\n          <format>Digital Media</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"17\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"20\" id=\"52900377-39bd-4c31-9c85-d05b71eaf1a7\">\n      <title>Pop Music for Dancing</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"acb19bfc-0a7c-49ab-910c-c3d915dd082e\">\n            <name>Ted Atking &amp; His Orchestra</name>\n            <sort-name>Ted Atking &amp; His Orchestra</sort-name>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Album\" id=\"9a5d1c34-e96f-3951-b308-25a3d4853d34\"/>\n      <date>1970</date>\n      <country>FR</country>\n      <label-info-list>\n        <label-info>\n          <catalog-number>SPS 1311</catalog-number>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>12</track-count>\n        <medium>\n          <format>Vinyl</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"12\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"19\" id=\"1f08c98d-7bfe-43f9-82d3-74c9ac139d62\">\n      <title>Pop! Justice: 100% Solid Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Compilation\" id=\"855075e5-3ace-3e28-b3eb-902f4db8aa2a\"/>\n      <date>2006-10-23</date>\n      <country>GB</country>\n      <asin>B000JCESCU</asin>\n      <medium-list count=\"1\">\n        <track-count>23</track-count>\n        <medium>\n          <disc-list count=\"1\"/>\n          <track-list count=\"23\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"17\" id=\"3fcc4cf7-bed8-49d8-ae78-e06483e9b2a6\">\n      <title>Proiect Special OMV: Pop Music</title>\n      <status>Promotion</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Compilation\" id=\"ea43c228-8956-3e32-968c-645b04dc7491\"/>\n      <date>2007</date>\n      <country>RO</country>\n      <label-info-list>\n        <label-info>\n          <label id=\"8b16b66c-18b7-4e61-956c-cbae64b41f3c\">\n            <name>Roton</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>16</track-count>\n        <medium>\n          <format>CD</format>\n          <disc-list count=\"1\"/>\n          <track-list count=\"16\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"17\" id=\"b922ff57-9289-4ea4-999e-cd4ddb986614\">\n      <title>20 Years of Pop Music</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Compilation\" id=\"c15656d6-c322-3565-a5d2-9ef695d9907a\"/>\n      <date>2001-07-03</date>\n      <country>US</country>\n      <asin>B00005LNIL</asin>\n      <medium-list count=\"1\">\n        <track-count>15</track-count>\n        <medium>\n          <disc-list count=\"1\"/>\n          <track-list count=\"15\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"17\" id=\"1a65b888-d398-44ef-a812-61e1edd9f49f\">\n      <title>Cairo Cafe: Arabic Pop Music</title>\n      <text-representation>\n        <language>ara</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"125ec42a-7229-4250-afc5-e057484327fe\">\n            <name>[unknown]</name>\n            <sort-name>[unknown]</sort-name>\n            <disambiguation>Special Purpose Artist - Do not add releases here, if possible.</disambiguation>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Compilation\" id=\"6f03e007-9e9d-44e3-b703-23968051c674\"/>\n      <date>2008</date>\n      <label-info-list>\n        <label-info>\n          <label id=\"c37dfc99-794e-43f7-b7ea-6d65261c69d6\">\n            <name>Pyramedia</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>12</track-count>\n        <medium>\n          <format>CD</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"12\"/>\n        </medium>\n      </medium-list>\n    </release>\n    <release ext:score=\"17\" id=\"da721dd5-5e5f-4733-b785-8b230c6982f6\">\n      <title>Dance / Pop Music 4</title>\n      <status>Official</status>\n      <text-representation>\n        <language>eng</language>\n        <script>Latn</script>\n      </text-representation>\n      <artist-credit>\n        <name-credit>\n          <artist id=\"89ad4ac3-39f7-470e-963a-56509c546377\">\n            <name>Various Artists</name>\n            <sort-name>Various Artists</sort-name>\n            <disambiguation>add compilations to this artist</disambiguation>\n            <alias-list>\n              <alias>Various Artists</alias>\n            </alias-list>\n          </artist>\n        </name-credit>\n      </artist-credit>\n      <release-group type=\"Other\" id=\"476821e8-ba85-4f91-8b1f-9662a473d3a7\"/>\n      <country>US</country>\n      <label-info-list>\n        <label-info>\n          <catalog-number>CHAPAV 102</catalog-number>\n          <label id=\"fe50ac68-115f-4377-9dd8-124ec3fc1dbd\">\n            <name>Chappell AV</name>\n          </label>\n        </label-info>\n      </label-info-list>\n      <medium-list count=\"1\">\n        <track-count>44</track-count>\n        <medium>\n          <format>Digital Media</format>\n          <disc-list count=\"0\"/>\n          <track-list count=\"44\"/>\n        </medium>\n      </medium-list>\n    </release>\n  </release-list>\n</metadata>\n"
  },
  {
    "path": "test/data/search-work.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\" xmlns:ext=\"http://musicbrainz.org/ns/ext#-2.0\">\n  <work-list offset=\"0\" count=\"174\">\n    <work ext:score=\"100\" id=\"94321b2f-d71d-320a-a44c-c1f1769c0515\">\n      <title>My Best Friend</title>\n      <alias-list>\n        <alias>My Best Friend (short cut)</alias>\n      </alias-list>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"f72a79cd-4ded-49ae-88b3-dad39d11f64b\">\n            <name>Marusha</name>\n            <sort-name>Marusha</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"lyricist\">\n          <direction>backward</direction>\n          <artist id=\"f72a79cd-4ded-49ae-88b3-dad39d11f64b\">\n            <name>Marusha</name>\n            <sort-name>Marusha</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"91\" id=\"4b99c181-da5e-357d-9781-a2e9dee7eb42\">\n      <title>The Girl of My Best Friend</title>\n      <alias-list>\n        <alias>Girl of My Best Friend</alias>\n      </alias-list>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"d7a509f9-593b-4ce6-b978-0d4470375ad7\">\n            <name>Sam Bobrick</name>\n            <sort-name>Bobrick, Sam</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"6539c07b-5337-468f-be6c-9a70c8246a9b\">\n            <name>Ross Butler</name>\n            <sort-name>Butler, Ross</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"81\" id=\"5b7278a8-0033-3352-89ea-3f3b1ab6b992\">\n      <title>(At Your Best) You Are Love</title>\n      <alias-list>\n        <alias>At Your Best (You Are Love)</alias>\n      </alias-list>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"4a76400d-283f-492e-9754-18ef41755f81\">\n            <name>The Isley Brothers</name>\n            <sort-name>Isley Brothers, The</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"lyricist\">\n          <direction>backward</direction>\n          <artist id=\"4a76400d-283f-492e-9754-18ef41755f81\">\n            <name>The Isley Brothers</name>\n            <sort-name>Isley Brothers, The</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"70\" id=\"de8db806-5789-3d6d-93b9-11558bc804ee\">\n      <title>Best</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"7c1cdfab-b962-401a-883d-0ce1bcfb94df\">\n            <name>양정승</name>\n            <sort-name>Yang, Jung-Seung</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"lyricist\">\n          <direction>backward</direction>\n          <artist id=\"7c1cdfab-b962-401a-883d-0ce1bcfb94df\">\n            <name>양정승</name>\n            <sort-name>Yang, Jung-Seung</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"49\" id=\"3511c7ea-e919-38e2-bd44-7f0670b130a9\">\n      <title>Best Guess at Best</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"acf39956-d2b5-4caa-a9f8-7f0c67325e8b\">\n            <name>Stephen Rippy</name>\n            <sort-name>Rippy, Stephen</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"eb43355d-db84-352e-b880-90a3dcf11e94\">\n      <title>Best Believe</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"1f1f6737-b930-46fc-8d25-110bb99f7490\">\n            <name>Redman</name>\n            <sort-name>Redman</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"39a973f2-0785-4ef6-90d9-551378864f89\">\n            <name>Pete Rock</name>\n            <sort-name>Rock, Pete</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"fdbbb8d2-f814-32a8-82f0-27bd3f6bb0c5\">\n      <title>The Best</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"fa4461c1-518c-4046-bb71-7b8fcab47c10\">\n            <name>Holly Knight</name>\n            <sort-name>Knight, Holly</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"97ad1a53-c037-41c5-998e-2085e923bcb2\">\n            <name>Michael Chapman</name>\n            <sort-name>Chapman, Michael</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"3331ea41-adbd-3485-9e1f-9130856fb6d0\">\n      <title>Best Forgotten</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"714b8d4f-673a-47cd-a0fc-cc001f67c7fd\">\n            <name>Minco Eggersman</name>\n            <sort-name>Eggersman, Minco</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"1b2fe240-cf3b-3499-b448-762883d52e91\">\n      <title>Best Pain</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"3edb52fd-1472-40db-a30f-abdcf1fb1f62\">\n            <name>[K]</name>\n            <sort-name>[K]</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"lyricist\">\n          <direction>backward</direction>\n          <artist id=\"3edb52fd-1472-40db-a30f-abdcf1fb1f62\">\n            <name>[K]</name>\n            <sort-name>[K]</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"aba937fc-87ce-3e70-a580-8d4fe1c6e287\">\n      <title>Best Friend</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"9ea64d8d-8216-4ca4-95b0-4c19cc82dc04\">\n            <name>HIRO</name>\n            <sort-name>HIRO</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"lyricist\">\n          <direction>backward</direction>\n          <artist id=\"9ea64d8d-8216-4ca4-95b0-4c19cc82dc04\">\n            <name>HIRO</name>\n            <sort-name>HIRO</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"e86b8a5b-02ed-333f-ad27-8d76c0a2b61f\">\n      <title>Best Friends</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"e6de1f3b-6484-491c-88dd-6d619f142abc\">\n            <name>Hans Zimmer</name>\n            <sort-name>Zimmer, Hans</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"00a1afe3-79c6-44a5-a666-c77e281ee7fe\">\n            <name>Heitor Pereira</name>\n            <sort-name>Pereira, Heitor</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"6f460841-9917-451d-838d-0d8bb19c3ea8\">\n            <name>Ryeland Allison</name>\n            <sort-name>Allison, Ryeland</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"505604ee-556c-402a-b5eb-0441fd153037\">\n            <name>James S. Levine</name>\n            <sort-name>Levine, James S.</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"4bba5bff-d2bc-32f6-9028-29c1869d0ee0\">\n      <title>Sunday Best</title>\n    </work>\n    <work ext:score=\"43\" id=\"9bda30cc-57e3-3a73-abbe-c382812678c2\">\n      <title>Best Friend</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"3c8a8696-e176-4c46-a2d3-48b6b1525c7f\">\n            <name>Toni Braxton</name>\n            <sort-name>Braxton, Toni</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"e88c77f7-a6db-4a1e-91e1-ee3d4c5134f8\">\n            <name>Vance Taylor</name>\n            <sort-name>Taylor, Vance</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"7f64f048-2ada-3933-9691-937b16545f98\">\n      <title>Best Man</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"fe73aa73-4e0f-439e-97dc-3bf0bfaecbe2\">\n            <name>Bryan-Michael Cox</name>\n            <sort-name>Cox, Bryan-Michael</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"1a3c7caa-d2e3-3adb-98aa-a6ca2a35dfb2\">\n      <title>Best Thing</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"1ea11cd7-08ce-4324-b35a-1788e0e4d43e\">\n            <name>James Young</name>\n            <sort-name>Young, James</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"9da87628-95a0-4820-93c7-7b1609d9bce7\">\n            <name>Dennis DeYoung</name>\n            <sort-name>DeYoung, Dennis</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"7a52b1a4-8150-3813-8a66-9776abef6778\">\n      <title>Best Friends</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"2361b5da-e1a9-402b-8f8d-fd216df1bc16\">\n            <name>Timothy Mosley</name>\n            <sort-name>Mosley, Timothy</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"4f9c5a19-68b2-4d89-b3d1-d52581e69af3\">\n            <name>Melissa Elliott</name>\n            <sort-name>Elliott, Melissa</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"e1c38a1a-02ab-334e-a067-32f63d275c46\">\n      <title>Best Dress</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"31930c85-3e0e-488e-8407-46a0d73fa816\">\n            <name>Jann Arden</name>\n            <sort-name>Arden, Jann</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"4bbc0a25-cb3c-4d95-b4f9-2612caacce82\">\n            <name>Russell Broom</name>\n            <sort-name>Broom, Russell</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"eeba3a6c-a6dc-328d-aad1-199dc521fe48\">\n      <title>Best Defense</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"41195b8a-14be-4f94-a5d3-66cb52c99c9d\">\n            <name>James Gulotta</name>\n            <sort-name>Gulotta, James</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"b4a0b93a-eca8-4df0-b512-8de7169ee7ec\">\n            <name>Chris Lykins</name>\n            <sort-name>Lykins, Chris</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"ca75a578-346c-3798-b9ef-84001179e0d8\">\n      <title>Best Future</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"writer\">\n          <direction>backward</direction>\n          <artist id=\"ce56d216-e136-408d-9aa0-30e7dda4bac5\">\n            <name>Brad Laner</name>\n            <sort-name>Laner, Brad</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" type=\"Song\" id=\"24e012aa-1a03-4a2f-b90d-01842c12dec4\">\n      <title>My Best</title>\n      <iswc>T-702.448.462-8</iswc>\n      <relation-list target-type=\"artist\">\n        <relation type=\"writer\">\n          <direction>backward</direction>\n          <artist id=\"41956707-262a-41c5-b89f-c60145a95d51\">\n            <name>Nili Hadida</name>\n            <sort-name>Hadida, Nili</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"writer\">\n          <direction>backward</direction>\n          <artist id=\"880ede4d-ae19-48f2-b2d8-72203ca29c27\">\n            <name>Benjamin Cotto</name>\n            <sort-name>Cotto, Benjamin</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"80877850-7b9a-3ce3-90ef-7d958ad30a46\">\n      <title>2nd Best</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"df037292-4455-45fd-b24a-52d2a81bce5e\">\n            <name>Mark Charles Heidinger</name>\n            <sort-name>Heidinger, Mark Charles</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"29b91280-49d3-4361-aee7-9d3c858e5de2\">\n      <title>Best Friend</title>\n      <iswc>T-101.813.896-8</iswc>\n      <relation-list target-type=\"artist\">\n        <relation type=\"lyricist\">\n          <direction>backward</direction>\n          <artist id=\"c3c8a5b8-3b41-46c7-9e11-2a7d00c69676\">\n            <name>玉城千春</name>\n            <sort-name>Tamashiro, Chiharu</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"c3c8a5b8-3b41-46c7-9e11-2a7d00c69676\">\n            <name>玉城千春</name>\n            <sort-name>Tamashiro, Chiharu</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" id=\"a801092e-418b-378b-8d37-8e6d45f6926a\">\n      <title>Best friends</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"composer\">\n          <direction>backward</direction>\n          <artist id=\"431766ed-4f4c-47f6-a903-66e65385341c\">\n            <name>齋藤真也</name>\n            <sort-name>Saito, Shinya</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"lyricist\">\n          <direction>backward</direction>\n          <artist id=\"7b8c4e81-9ec7-400f-abf5-7be8da80487b\">\n            <name>黒崎真音</name>\n            <sort-name>Kurosaki, Maon</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n    <work ext:score=\"43\" type=\"Song\" id=\"e5125980-40b8-43f9-a0be-3da9236b99f4\">\n      <title>Best Friends</title>\n      <disambiguation>Adam WarRock song</disambiguation>\n    </work>\n    <work ext:score=\"43\" type=\"Song\" id=\"ee02ef6a-90e8-4364-a6e3-3651827e197b\">\n      <title>Second Best</title>\n      <relation-list target-type=\"artist\">\n        <relation type=\"writer\">\n          <direction>backward</direction>\n          <artist id=\"42cdf49d-3c50-4596-95bb-23e48dca050f\">\n            <name>Kevin Hearn</name>\n            <sort-name>Hearn, Kevin</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"writer\">\n          <direction>backward</direction>\n          <artist id=\"6837f020-f677-4438-ae4e-24467811d309\">\n            <name>Steven Page</name>\n            <sort-name>Page, Steven</sort-name>\n          </artist>\n        </relation>\n        <relation type=\"writer\">\n          <direction>backward</direction>\n          <artist id=\"ac560686-5bdc-4101-aa97-6f4f4993edaa\">\n            <name>Ed Robertson</name>\n            <sort-name>Robertson, Ed</sort-name>\n          </artist>\n        </relation>\n      </relation-list>\n    </work>\n  </work-list>\n</metadata>\n"
  },
  {
    "path": "test/data/work/3d7c7cd2-da79-37f4-98b8-ccfb1a4ac6c4-aliases.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><work id=\"3d7c7cd2-da79-37f4-98b8-ccfb1a4ac6c4\"><title>Symphony No. 2 in E minor, Op. 27: III. Adagio</title><alias-list count=\"10\"><alias sort-name=\"Adagio from Symphony No. 2 in E minor, Op. 27\">Adagio from Symphony No. 2 in E minor, Op. 27</alias><alias sort-name=\"Adagio from Symphony No. 2 in E minor, Op. 27\">Adagio from Symphony No. 2 in E minor, Op. 27</alias><alias sort-name=\"III. Adagio from Symphony No. 2 in E minor, Op. 27\">III. Adagio from Symphony No. 2 in E minor, Op. 27</alias><alias sort-name=\"Sinfonie Nr. 2 e-moll, Op. 27: III. Adagio\">Sinfonie Nr. 2 e-moll, Op. 27: III. Adagio</alias><alias sort-name=\"Symphonie No. 2 in E minor, Op. 27: III. Adagio\">Symphonie No. 2 in E minor, Op. 27: III. Adagio</alias><alias sort-name=\"Symphony No. 2 in E minor, Op. 27: III. Adagio\">Symphony No. 2 in E minor, Op. 27: III. Adagio</alias><alias sort-name=\"Symphony No. 2 in E minor, Op. 27: III. Adagio\">Symphony No. 2 in E minor, Op. 27: III. Adagio</alias><alias sort-name=\"Symphony No. 2 in E minor, Op. 27: III. Adagio\">Symphony No. 2 in E minor, Op. 27: III. Adagio</alias><alias sort-name=\"Symphony No. 3 in A minor, Op. 44: II. Adagio ma non troppo\">Symphony No. 3 in A minor, Op. 44: II. Adagio ma non troppo</alias><alias sort-name=\"교향곡 2번 3악장 &quot;아다지오&quot; [Symphony No. 2 in E minor, Op. 27: III. Adagio]\">교향곡 2번 3악장 &quot;아다지오&quot; [Symphony No. 2 in E minor, Op. 27: III. Adagio]</alias></alias-list></work></metadata>"
  },
  {
    "path": "test/data/work/72c9aad2-3c95-4e3e-8a01-3974f8fef8eb-series-rels.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><work type=\"Cantata\" id=\"72c9aad2-3c95-4e3e-8a01-3974f8fef8eb\"><title>Cantata, BuxWV 1 &quot;Accedite gentes, accurite populi&quot;</title><language>lat</language><relation-list target-type=\"series\"><relation type=\"part of\" type-id=\"b0d44366-cdf0-3acb-bee6-0f65a77a6ef0\"><target>0790fa51-15d9-40a2-bca9-9c8eaaa96bef</target><ordering-key>1</ordering-key><direction>backward</direction><attribute-list><attribute value=\"BuxWV 1\">number</attribute></attribute-list><series type=\"Catalogue\" id=\"0790fa51-15d9-40a2-bca9-9c8eaaa96bef\"><name>Buxtehude-Werke-Verzeichnis</name></series></relation></relation-list></work></metadata>"
  },
  {
    "path": "test/data/work/80737426-8ef3-3a9c-a3a6-9507afb93e93-aliases.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><work type=\"Symphony\" id=\"80737426-8ef3-3a9c-a3a6-9507afb93e93\"><title>Symphony no. 3 in E-flat major, op. 55 \"Eroica\"</title><language>zxx</language><attribute-list><attribute type=\"Key\">E-flat major</attribute></attribute-list><alias-list count=\"2\"><alias sort-name=\"Symphonie Nr. 3 Es-Dur, Op. 55 &quot;Eroica&quot;\">Symphonie Nr. 3 Es-Dur, Op. 55 \"Eroica\"</alias><alias sort-name=\"Symphony No. 3, Op. 55 &quot;Eroica&quot;\">Symphony No. 3, Op. 55 \"Eroica\"</alias></alias-list></work></metadata>"
  },
  {
    "path": "test/data/work/8e134b32-99b8-4e96-ae5c-426f3be85f4c-attributes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><metadata xmlns=\"http://musicbrainz.org/ns/mmd-2.0#\"><work id=\"8e134b32-99b8-4e96-ae5c-426f3be85f4c\"><title>Hüzzam Peşrev</title><language>zxx</language><attribute-list><attribute type=\"Makam (Ottoman, Turkish)\">Hüzzam</attribute><attribute type=\"Form (Ottoman, Turkish)\">Peşrev</attribute><attribute type=\"Usul (Ottoman, Turkish)\">Fahte</attribute></attribute-list></work></metadata>"
  },
  {
    "path": "test/test_browse.py",
    "content": "import unittest\n\nimport musicbrainzngs\nfrom test import _common\n\n\nclass BrowseTest(unittest.TestCase):\n\n    def setUp(self):\n        self.opener = _common.FakeOpener()\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n\n        musicbrainzngs.set_useragent(\"a\", \"1\")\n        musicbrainzngs.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainzngs.set_rate_limit(True)\n\n    def test_browse(self):\n        area = \"74e50e58-5deb-4b99-93a2-decbb365c07f\"\n        musicbrainzngs.browse_events(area=area)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/?area=74e50e58-5deb-4b99-93a2-decbb365c07f\", self.opener.get_url())\n\n    def test_browse_includes(self):\n        area = \"74e50e58-5deb-4b99-93a2-decbb365c07f\"\n        musicbrainzngs.browse_events(area=area, includes=[\"aliases\", \"area-rels\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/?area=74e50e58-5deb-4b99-93a2-decbb365c07f&inc=aliases+area-rels\", self.opener.get_url())\n\n    def test_browse_single_include(self):\n        area = \"74e50e58-5deb-4b99-93a2-decbb365c07f\"\n        musicbrainzngs.browse_events(area=area, includes=\"aliases\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/?area=74e50e58-5deb-4b99-93a2-decbb365c07f&inc=aliases\", self.opener.get_url())\n\n    def test_browse_multiple_by(self):\n        \"\"\"It is an error to choose multiple entities to browse by\"\"\"\n        self.assertRaises(Exception,\n                musicbrainzngs.browse_artists, recording=\"1\", release=\"2\")\n\n    def test_browse_limit_offset(self):\n        \"\"\"Limit and offset values\"\"\"\n        area = \"74e50e58-5deb-4b99-93a2-decbb365c07f\"\n        musicbrainzngs.browse_events(area=area, limit=50, offset=100)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/?area=74e50e58-5deb-4b99-93a2-decbb365c07f&limit=50&offset=100\", self.opener.get_url())\n\n    def test_browse_artist(self):\n        release = \"9ace7c8c-55b4-4c5d-9aa8-e573a5dde9ad\"\n        musicbrainzngs.browse_artists(release=release)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/artist/?release=9ace7c8c-55b4-4c5d-9aa8-e573a5dde9ad\", self.opener.get_url())\n\n        recording = \"6da2cc31-9b12-4b66-9e26-074150f73406\"\n        musicbrainzngs.browse_artists(recording=recording)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/artist/?recording=6da2cc31-9b12-4b66-9e26-074150f73406\", self.opener.get_url())\n\n        release_group = \"44c90c72-76b5-3c13-890e-3d37f21c10c9\"\n        musicbrainzngs.browse_artists(release_group=release_group)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/artist/?release-group=44c90c72-76b5-3c13-890e-3d37f21c10c9\", self.opener.get_url())\n\n        work = \"deb27b88-cf41-4f7c-b3aa-bc3268bc3c02\"\n        musicbrainzngs.browse_artists(work=work)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/artist/?work=deb27b88-cf41-4f7c-b3aa-bc3268bc3c02\", self.opener.get_url())\n\n    def test_browse_event(self):\n        area = \"f03d09b3-39dc-4083-afd6-159e3f0d462f\"\n        musicbrainzngs.browse_events(area=area)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/?area=f03d09b3-39dc-4083-afd6-159e3f0d462f\", self.opener.get_url())\n\n        artist = \"0383dadf-2a4e-4d10-a46a-e9e041da8eb3\"\n        musicbrainzngs.browse_events(artist=artist)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/?artist=0383dadf-2a4e-4d10-a46a-e9e041da8eb3\", self.opener.get_url())\n\n        place = \"8a6161bb-fb50-4234-82c5-1e24ab342499\"\n        musicbrainzngs.browse_events(place=place)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/?place=8a6161bb-fb50-4234-82c5-1e24ab342499\", self.opener.get_url())\n\n    def test_browse_label(self):\n        release = \"c9550260-b7ae-4670-ac24-731c19e76b59\"\n        musicbrainzngs.browse_labels(release=release)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/label/?release=c9550260-b7ae-4670-ac24-731c19e76b59\", self.opener.get_url())\n\n    def test_browse_recording(self):\n        artist = \"47f67b22-affe-4fe1-9d25-853d69bc0ee3\"\n        musicbrainzngs.browse_recordings(artist=artist)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/recording/?artist=47f67b22-affe-4fe1-9d25-853d69bc0ee3\", self.opener.get_url())\n\n        release = \"438042ef-7ccc-4d03-9391-4f66427b2055\"\n        musicbrainzngs.browse_recordings(release=release)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/recording/?release=438042ef-7ccc-4d03-9391-4f66427b2055\", self.opener.get_url())\n\n    def test_browse_place(self):\n        area = \"74e50e58-5deb-4b99-93a2-decbb365c07f\"\n        musicbrainzngs.browse_places(area=area)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/place/?area=74e50e58-5deb-4b99-93a2-decbb365c07f\", self.opener.get_url())\n\n    def test_browse_release(self):\n        artist = \"47f67b22-affe-4fe1-9d25-853d69bc0ee3\"\n        musicbrainzngs.browse_releases(artist=artist)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release/?artist=47f67b22-affe-4fe1-9d25-853d69bc0ee3\", self.opener.get_url())\n        musicbrainzngs.browse_releases(track_artist=artist)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release/?track_artist=47f67b22-affe-4fe1-9d25-853d69bc0ee3\", self.opener.get_url())\n\n        label = \"713c4a95-6616-442b-9cf6-14e1ddfd5946\"\n        musicbrainzngs.browse_releases(label=label)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release/?label=713c4a95-6616-442b-9cf6-14e1ddfd5946\", self.opener.get_url())\n\n        recording = \"7484fcfd-1968-4401-a44d-d1edcc580518\"\n        musicbrainzngs.browse_releases(recording=recording)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release/?recording=7484fcfd-1968-4401-a44d-d1edcc580518\", self.opener.get_url())\n\n        release_group = \"1c1b54f7-e56a-3ce8-b62c-e45c378e7f76\"\n        musicbrainzngs.browse_releases(release_group=release_group)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release/?release-group=1c1b54f7-e56a-3ce8-b62c-e45c378e7f76\", self.opener.get_url())\n\n    def test_browse_release_group(self):\n        artist = \"47f67b22-affe-4fe1-9d25-853d69bc0ee3\"\n        musicbrainzngs.browse_release_groups(artist=artist)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release-group/?artist=47f67b22-affe-4fe1-9d25-853d69bc0ee3\", self.opener.get_url())\n\n        release = \"438042ef-7ccc-4d03-9391-4f66427b2055\"\n        musicbrainzngs.browse_release_groups(release=release)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release-group/?release=438042ef-7ccc-4d03-9391-4f66427b2055\", self.opener.get_url())\n\n        release = \"438042ef-7ccc-4d03-9391-4f66427b2055\"\n        rel_type = \"ep\"\n        musicbrainzngs.browse_release_groups(release=release, release_type=rel_type)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release-group/?release=438042ef-7ccc-4d03-9391-4f66427b2055&type=ep\", self.opener.get_url())\n\n    def test_browse_url(self):\n        resource = \"http://www.queenonline.com\"\n        musicbrainzngs.browse_urls(resource=resource)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/url/?resource=http%3A%2F%2Fwww.queenonline.com\", self.opener.get_url())\n\n        # Resource is urlencoded, including ? and =\n        resource = \"http://www.splendidezine.com/review.html?reviewid=1109588405202831\"\n        musicbrainzngs.browse_urls(resource=resource)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/url/?resource=http%3A%2F%2Fwww.splendidezine.com%2Freview.html%3Freviewid%3D1109588405202831\", self.opener.get_url())\n\n    def test_browse_work(self):\n        artist = \"0383dadf-2a4e-4d10-a46a-e9e041da8eb3\"\n        musicbrainzngs.browse_works(artist=artist)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/work/?artist=0383dadf-2a4e-4d10-a46a-e9e041da8eb3\", self.opener.get_url())\n\n    def test_browse_includes_is_subset_of_includes(self):\n        \"\"\"Check that VALID_BROWSE_INCLUDES is a strict subset of\n           VALID_INCLUDES\"\"\"\n        for entity, includes in musicbrainzngs.VALID_BROWSE_INCLUDES.items():\n            for i in includes:\n                self.assertTrue(i in musicbrainzngs.VALID_INCLUDES[entity], \"entity %s, %s in BROWSE_INCLUDES but not VALID_INCLUDES\" % (entity, i))\n"
  },
  {
    "path": "test/test_caa.py",
    "content": "import unittest\n\nfrom musicbrainzngs import caa\nfrom musicbrainzngs import compat\nfrom musicbrainzngs.musicbrainz import _version\nimport musicbrainzngs\nfrom test import _common\n\n\nclass CaaTest(unittest.TestCase):\n\n    def test_get_list(self):\n        # check the url and response for a listing\n        resp = b'{\"images\":[]}'\n        self.opener = _common.FakeOpener(resp)\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        res = caa.get_image_list(\"8ec178f4-a8e8-4f22-bcba-1964466ef214\")\n        self.assertEqual(\"https://coverartarchive.org/release/8ec178f4-a8e8-4f22-bcba-1964466ef214\", self.opener.myurl)\n        self.assertEqual(1, len(res))\n        self.assertTrue(\"images\" in res)\n\n    def test_get_release_group_list(self):\n        # check the url and response for a listing\n        resp = b'{\"images\":[], \"release\": \"foo\"}'\n        self.opener = _common.FakeOpener(resp)\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        res = caa.get_release_group_image_list(\"8ec178f4-a8e8-4f22-bcba-1964466ef214\")\n        self.assertEqual(\"https://coverartarchive.org/release-group/8ec178f4-a8e8-4f22-bcba-1964466ef214\", self.opener.myurl)\n        self.assertEqual(2, len(res))\n        self.assertTrue(\"images\" in res)\n        self.assertEqual(\"foo\", res[\"release\"])\n\n    def test_list_none(self):\n        \"\"\" When CAA gives a 404 error, pass it through.\"\"\"\n\n        exc = compat.HTTPError(\"\", 404, \"\", \"\", _common.StringIO.StringIO(\"\"))\n        self.opener = _common.FakeOpener(exception=musicbrainzngs.ResponseError(cause=exc))\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        try:\n            res = caa.get_image_list(\"8ec178f4-a8e8-4f22-bcba-19644XXXXXX\")\n            self.assertTrue(False, \"Expected an exception\")\n        except musicbrainzngs.ResponseError as e:\n            self.assertEqual(e.cause.code, 404)\n\n    def test_list_baduuid(self):\n        exc = compat.HTTPError(\"\", 400, \"\", \"\", _common.StringIO.StringIO(\"\"))\n        self.opener = _common.FakeOpener(exception=musicbrainzngs.ResponseError(cause=exc))\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        try:\n            res = caa.get_image_list(\"8ec178f4-a8e8-4f22-bcba-19644XXXXXX\")\n            self.assertTrue(False, \"Expected an exception\")\n        except musicbrainzngs.ResponseError as e:\n            self.assertEqual(e.cause.code, 400)\n\n    def test_set_useragent(self):\n        \"\"\" When a useragent is set it is sent with the request \"\"\"\n        musicbrainzngs.set_useragent(\"caa-test\", \"0.1\")\n\n        resp = b'{\"images\":[]}'\n        self.opener = _common.FakeOpener(resp)\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        res = caa.get_image_list(\"8ec178f4-a8e8-4f22-bcba-1964466ef214\")\n\n        headers = dict(self.opener.headers)\n        self.assertTrue(\"User-agent\" in headers)\n        self.assertEqual(\"caa-test/0.1 python-musicbrainzngs/%s\" % _version, headers[\"User-agent\"])\n\n    def test_coverid(self):\n        resp = b'some_image'\n        self.opener = _common.FakeOpener(resp)\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        res = caa.get_image(\"8ec178f4-a8e8-4f22-bcba-1964466ef214\", \"1234\")\n\n        self.assertEqual(\"https://coverartarchive.org/release/8ec178f4-a8e8-4f22-bcba-1964466ef214/1234\", self.opener.myurl)\n        self.assertEqual(resp, res)\n\n    def test_get_size(self):\n        resp = b'some_image'\n        self.opener = _common.FakeOpener(resp)\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        res = caa.get_image(\"8ec178f4-a8e8-4f22-bcba-1964466ef214\", \"1234\", 250)\n\n        self.assertEqual(\"https://coverartarchive.org/release/8ec178f4-a8e8-4f22-bcba-1964466ef214/1234-250\", self.opener.myurl)\n        self.assertEqual(resp, res)\n\n    def test_front(self):\n        resp = b'front_image'\n        self.opener = _common.FakeOpener(resp)\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        res = caa.get_image_front(\"8ec178f4-a8e8-4f22-bcba-1964466ef214\")\n\n        self.assertEqual(\"https://coverartarchive.org/release/8ec178f4-a8e8-4f22-bcba-1964466ef214/front\", self.opener.myurl)\n        self.assertEqual(resp, res)\n\n    def test_release_group_front(self):\n        resp = b'front_image'\n        self.opener = _common.FakeOpener(resp)\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        res = caa.get_release_group_image_front(\"8ec178f4-a8e8-4f22-bcba-1964466ef214\")\n\n        self.assertEqual(\"https://coverartarchive.org/release-group/8ec178f4-a8e8-4f22-bcba-1964466ef214/front\", self.opener.myurl)\n        self.assertEqual(resp, res)\n\n    def test_back(self):\n        resp = b'back_image'\n        self.opener = _common.FakeOpener(resp)\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        res = caa.get_image_back(\"8ec178f4-a8e8-4f22-bcba-1964466ef214\")\n\n        self.assertEqual(\"https://coverartarchive.org/release/8ec178f4-a8e8-4f22-bcba-1964466ef214/back\", self.opener.myurl)\n        self.assertEqual(resp, res)\n\n"
  },
  {
    "path": "test/test_collection.py",
    "content": "import unittest\nimport musicbrainzngs\nfrom musicbrainzngs import compat\nfrom test import _common\n\n\nclass CollectionTest(unittest.TestCase):\n    \"\"\" Test that requesting collections works properly \"\"\"\n\n    def setUp(self):\n        musicbrainzngs.set_useragent(\"a\", \"1\")\n        musicbrainzngs.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainzngs.set_rate_limit(True)\n\n    def test_auth_required(self):\n        \"\"\" Check the auth_required method in isolation \"\"\"\n        ar = musicbrainzngs.musicbrainz._get_auth_type(\"collection\", \"\", [])\n        self.assertEqual(musicbrainzngs.musicbrainz.AUTH_YES, ar)\n\n        ar = musicbrainzngs.musicbrainz._get_auth_type(\"collection\",\n                \"foo/releases\", [])\n        self.assertEqual(musicbrainzngs.musicbrainz.AUTH_IFSET, ar)\n\n        ar = musicbrainzngs.musicbrainz._get_auth_type(\"artist\", \"5b11f4ce-a62d-471e-81fc-a69a8278c7da\", [])\n        self.assertEqual(musicbrainzngs.musicbrainz.AUTH_NO, ar)\n\n        ar = musicbrainzngs.musicbrainz._get_auth_type(\"artist\", \"5b11f4ce-a62d-471e-81fc-a69a8278c7da\", [\"user-tags\"])\n        self.assertEqual(musicbrainzngs.musicbrainz.AUTH_YES, ar)\n\n        ar = musicbrainzngs.musicbrainz._get_auth_type(\"artist\", \"5b11f4ce-a62d-471e-81fc-a69a8278c7da\", [\"aliases\", \"user-genres\", \"artist-rels\"])\n        self.assertEqual(musicbrainzngs.musicbrainz.AUTH_YES, ar)\n\n    def test_my_collections(self):\n        \"\"\" If you ask for your collections, you need to have\n        authenticated first.\"\"\"\n\n        old_mb_request = musicbrainzngs.musicbrainz._mb_request\n\n        params = {}\n        def local_mb_request(path, method='GET',\n                auth_required=musicbrainzngs.musicbrainz.AUTH_NO,\n                client_required=False, args=None, data=None, body=None):\n            params[\"auth_required\"] = auth_required\n\n        musicbrainzngs.musicbrainz._mb_request = local_mb_request\n        musicbrainzngs.get_collections()\n        self.assertEqual(musicbrainzngs.musicbrainz.AUTH_YES,\n            params[\"auth_required\"])\n\n        musicbrainzngs.musicbrainz._mb_request = old_mb_request\n\n    def test_other_collection(self):\n        \"\"\" If you ask for someone else's collection, you don't\n        need to be authenticated.\"\"\"\n\n        old_mb_request = musicbrainzngs.musicbrainz._mb_request\n\n        params = {}\n        def local_mb_request(path, method='GET',\n                auth_required=musicbrainzngs.musicbrainz.AUTH_NO,\n                client_required=False, args=None, data=None, body=None):\n            params[\"auth_required\"] = auth_required\n\n        musicbrainzngs.musicbrainz._mb_request = local_mb_request\n        musicbrainzngs.get_releases_in_collection(\n                \"17905fdb-102d-40f0-91d3-eabcabc64fd3\")\n        # If _get_auth_type() returns AUTH_IFSET, then _mb_request()\n        # should send the user credentials if they are set by auth()\n        # i.e., We use whether auth() has been executed to determine if\n        # the requested collection belongs to the user or not.\n        self.assertEqual(musicbrainzngs.musicbrainz.AUTH_IFSET,\n                params[\"auth_required\"])\n\n        musicbrainzngs.musicbrainz._mb_request = old_mb_request\n\n    def test_no_collection(self):\n        \"\"\" If a collection doesn't exist, you get a 404 \"\"\"\n\n        exc = compat.HTTPError(\"\", 404, \"\", \"\", _common.StringIO.StringIO(\"\"))\n        self.opener = _common.FakeOpener(exception=musicbrainzngs.ResponseError(cause=exc))\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        try:\n            res = musicbrainzngs.get_releases_in_collection(\"17905fdb-102d-40f0-91d3-eabcabc64f44\")\n            self.assertTrue(False, \"Expected an exception\")\n        except musicbrainzngs.ResponseError as e:\n            self.assertEqual(e.cause.code, 404)\n\n    def test_private_collection(self):\n        \"\"\" If you ask for a collection that is private, you should\n        get a 401\"\"\"\n\n        exc = compat.HTTPError(\"\", 401, \"\", \"\", _common.StringIO.StringIO(\"\"))\n        self.opener = _common.FakeOpener(exception=musicbrainzngs.AuthenticationError(cause=exc))\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        try:\n            res = musicbrainzngs.get_releases_in_collection(\"17905fdb-102d-40f0-91d3-eabcabc64fd3\")\n            self.assertTrue(False, \"Expected an exception\")\n        except musicbrainzngs.AuthenticationError as e:\n            self.assertEqual(e.cause.code, 401)\n"
  },
  {
    "path": "test/test_getentity.py",
    "content": "import unittest\nimport musicbrainzngs\nfrom test import _common\n\n\nclass UrlTest(unittest.TestCase):\n    \"\"\" Test that the correct URL is generated when a search query is made \"\"\"\n\n    def setUp(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n\n        musicbrainzngs.set_useragent(\"a\", \"1\")\n        musicbrainzngs.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainzngs.set_rate_limit(True)\n\n    def testGetArtist(self):\n        artistid = \"952a4205-023d-4235-897c-6fdb6f58dfaa\"\n        musicbrainzngs.get_artist_by_id(artistid)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/artist/952a4205-023d-4235-897c-6fdb6f58dfaa\", self.opener.get_url())\n\n        # Test an include\n        musicbrainzngs.get_artist_by_id(artistid, \"recordings\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/artist/952a4205-023d-4235-897c-6fdb6f58dfaa?inc=recordings\", self.opener.get_url())\n\n        # More than one include\n        musicbrainzngs.get_artist_by_id(artistid, [\"recordings\", \"aliases\"])\n        expected =\"https://musicbrainz.org/ws/2/artist/952a4205-023d-4235-897c-6fdb6f58dfaa?inc=recordings+aliases\"\n        self.assertEqual(expected, self.opener.get_url())\n\n        # with valid filters\n        musicbrainzngs.get_artist_by_id(artistid, [\"release-groups\"],\n                release_type=[\"album\"])\n        self.assertTrue(\"type=album\" in self.opener.get_url())\n\n        # with invalid filters\n        self.assertRaises(musicbrainzngs.UsageError,\n                musicbrainzngs.get_artist_by_id,\n                artistid, [\"release-groups\"], release_status=[\"official\"])\n\n    def testGetEvent(self):\n        event_id = \"a4a0927c-8ad7-48dd-883c-7126cc0b9c6b\"\n        musicbrainzngs.get_event_by_id(event_id)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/a4a0927c-8ad7-48dd-883c-7126cc0b9c6b\", self.opener.get_url())\n\n        # one include\n        musicbrainzngs.get_event_by_id(event_id, [\"artist-rels\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/a4a0927c-8ad7-48dd-883c-7126cc0b9c6b?inc=artist-rels\", self.opener.get_url())\n\n        musicbrainzngs.get_event_by_id(event_id, [\"artist-rels\", \"event-rels\", \"ratings\", \"tags\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/a4a0927c-8ad7-48dd-883c-7126cc0b9c6b?inc=artist-rels+event-rels+ratings+tags\", self.opener.get_url())\n\n    def testGetPlace(self):\n        place_id = \"43e166a5-a024-4cbb-9a1f-d4947b4ff489\"\n        musicbrainzngs.get_place_by_id(place_id)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/place/43e166a5-a024-4cbb-9a1f-d4947b4ff489\", self.opener.get_url())\n\n        musicbrainzngs.get_place_by_id(place_id, [\"event-rels\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/place/43e166a5-a024-4cbb-9a1f-d4947b4ff489?inc=event-rels\", self.opener.get_url())\n\n    def testGetLabel(self):\n        label_id = \"aab2e720-bdd2-4565-afc2-460743585f16\"\n        musicbrainzngs.get_label_by_id(label_id)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/label/aab2e720-bdd2-4565-afc2-460743585f16\", self.opener.get_url())\n\n        # one include\n        musicbrainzngs.get_label_by_id(label_id, \"releases\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/label/aab2e720-bdd2-4565-afc2-460743585f16?inc=releases\", self.opener.get_url())\n\n        # with valid filters\n        musicbrainzngs.get_label_by_id(label_id, [\"releases\"],\n                release_type=[\"ep\", \"single\"], release_status=[\"official\"])\n        self.assertTrue(\"type=ep%7Csingle\" in self.opener.get_url())\n        self.assertTrue(\"status=official\" in self.opener.get_url())\n\n    def testGetRecording(self):\n        musicbrainzngs.get_recording_by_id(\"93468a09-9662-4886-a227-56a2ad1c5246\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/recording/93468a09-9662-4886-a227-56a2ad1c5246\", self.opener.get_url())\n\n        # one include\n        musicbrainzngs.get_recording_by_id(\"93468a09-9662-4886-a227-56a2ad1c5246\", includes=[\"artists\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/recording/93468a09-9662-4886-a227-56a2ad1c5246?inc=artists\", self.opener.get_url())\n\n\n    def testGetReleasegroup(self):\n        musicbrainzngs.get_release_group_by_id(\"9377d65d-ffd5-35d6-b64d-43f86ef9188d\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release-group/9377d65d-ffd5-35d6-b64d-43f86ef9188d\", self.opener.get_url())\n\n        # one include\n        release_group_id = \"9377d65d-ffd5-35d6-b64d-43f86ef9188d\"\n        musicbrainzngs.get_release_group_by_id(release_group_id,\n                includes=[\"artists\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release-group/9377d65d-ffd5-35d6-b64d-43f86ef9188d?inc=artists\", self.opener.get_url())\n\n        # with valid filters\n        musicbrainzngs.get_release_group_by_id(release_group_id,\n                release_type=[\"compilation\", \"live\"])\n        self.assertTrue(\"type=compilation%7Clive\" in self.opener.get_url())\n\n        # with invalid filters\n        self.assertRaises(musicbrainzngs.UsageError,\n                musicbrainzngs.get_release_group_by_id,\n                release_group_id, release_status=[\"official\", \"promotion\"])\n\n\n    def testGetWork(self):\n        musicbrainzngs.get_work_by_id(\"c6dfad5a-f915-41c7-a1c0-e2b606948e69\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/work/c6dfad5a-f915-41c7-a1c0-e2b606948e69\", self.opener.get_url())\n\n    def testGetByDiscid(self):\n        musicbrainzngs.get_releases_by_discid(\"I5l9cCSFccLKFEKS.7wqSZAorPU-\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/discid/I5l9cCSFccLKFEKS.7wqSZAorPU-\", self.opener.get_url())\n\n        includes = [\"artists\"]\n        musicbrainzngs.get_releases_by_discid(\"I5l9cCSFccLKFEKS.7wqSZAorPU-\", includes)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/discid/I5l9cCSFccLKFEKS.7wqSZAorPU-?inc=artists\", self.opener.get_url())\n\n        musicbrainzngs.get_releases_by_discid(\"discid\", toc=\"toc\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/discid/discid?toc=toc\", self.opener.get_url())\n\n        musicbrainzngs.get_releases_by_discid(\"discid\", toc=\"toc\", cdstubs=False)\n        self.assertEqual(\"https://musicbrainz.org/ws/2/discid/discid?cdstubs=no&toc=toc\", self.opener.get_url())\n\n\n    def testGetInstrument(self):\n\n        musicbrainzngs.get_instrument_by_id(\"6505f98c-f698-4406-8bf4-8ca43d05c36f\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/instrument/6505f98c-f698-4406-8bf4-8ca43d05c36f\", self.opener.get_url())\n\n        # Tags\n        musicbrainzngs.get_instrument_by_id(\"6505f98c-f698-4406-8bf4-8ca43d05c36f\", includes=\"tags\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/instrument/6505f98c-f698-4406-8bf4-8ca43d05c36f?inc=tags\", self.opener.get_url())\n\n        # some rels\n        musicbrainzngs.get_instrument_by_id(\"6505f98c-f698-4406-8bf4-8ca43d05c36f\", includes=[\"instrument-rels\", \"url-rels\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/instrument/6505f98c-f698-4406-8bf4-8ca43d05c36f?inc=instrument-rels+url-rels\", self.opener.get_url())\n\n        # alias, annotation\n        musicbrainzngs.get_instrument_by_id(\"d00cec5f-f9bc-4235-a54f-6639a02d4e4c\", includes=[\"aliases\", \"annotation\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/instrument/d00cec5f-f9bc-4235-a54f-6639a02d4e4c?inc=aliases+annotation\", self.opener.get_url())\n\n        # Ratings are used on almost all other entites but instrument\n        self.assertRaises(musicbrainzngs.UsageError,\n                musicbrainzngs.get_instrument_by_id,\n                \"dabdeb41-560f-4d84-aa6a-cf22349326fe\", includes=[\"ratings\"])\n\n"
  },
  {
    "path": "test/test_mbxml.py",
    "content": "import unittest\nfrom musicbrainzngs import mbxml\n\n\nclass MbXML(unittest.TestCase):\n\n    def testMakeBarcode(self):\n        expected = (b'<ns0:metadata xmlns:ns0=\"http://musicbrainz.org/ns/mmd-2.0#\">'\n                    b'<ns0:release-list><ns0:release ns0:id=\"trid\"><ns0:barcode>12345</ns0:barcode>'\n                    b'</ns0:release></ns0:release-list></ns0:metadata>')\n        xml = mbxml.make_barcode_request({'trid':'12345'})\n        self.assertEqual(expected, xml)\n\n    def test_make_tag_request(self):\n        expected = (b'<ns0:metadata xmlns:ns0=\"http://musicbrainz.org/ns/mmd-2.0#\">'\n                    b'<ns0:artist-list><ns0:artist ns0:id=\"mbid\">'\n                    b'<ns0:user-tag-list>'\n                    b'<ns0:user-tag><ns0:name>one</ns0:name></ns0:user-tag>'\n                    b'<ns0:user-tag><ns0:name>two</ns0:name></ns0:user-tag>'\n                    b'</ns0:user-tag-list></ns0:artist>'\n                    b'</ns0:artist-list></ns0:metadata>')\n        xml = mbxml.make_tag_request(artist_tags={\"mbid\": [\"one\", \"two\"]})\n        self.assertEqual(expected, xml)\n\n    def test_read_error(self):\n        error = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><error><text>Invalid mbid.</text><text>For usage, please see: http://musicbrainz.org/development/mmd</text></error>'\n        parts = mbxml.get_error_message(error)\n        self.assertEqual(2, len(parts))\n        self.assertEqual(\"Invalid mbid.\", parts[0])\n        self.assertEqual(True, parts[1].startswith(\"For usage\"))\n"
  },
  {
    "path": "test/test_mbxml_artist.py",
    "content": "# Tests for parsing of artist queries\n\nimport unittest\nimport os\nfrom test import _common\n\n\nclass GetArtistTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"artist\")\n\n    def testArtistAliases(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"0e43fe9d-c472-4b62-be9e-55f971a023e1-aliases.xml\")\n        aliases = res[\"artist\"][\"alias-list\"]\n        self.assertEqual(len(aliases), 28)\n\n        a0 = aliases[0]\n        self.assertEqual(a0[\"alias\"], \"Prokofief\")\n        self.assertEqual(a0[\"sort-name\"], \"Prokofief\")\n\n        a17 = aliases[17]\n        self.assertEqual(a17[\"alias\"], \"Sergei Sergeyevich Prokofiev\")\n        self.assertEqual(a17[\"sort-name\"], \"Prokofiev, Sergei Sergeyevich\")\n        self.assertEqual(a17[\"locale\"], \"en\")\n        self.assertEqual(a17[\"primary\"], \"primary\")\n\n        res = _common.open_and_parse_test_data(self.datadir, \"2736bad5-6280-4c8f-92c8-27a5e63bbab2-aliases.xml\")\n        self.assertFalse(\"alias-list\" in res[\"artist\"])\n    \n    def testArtistTargets(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"b3785a55-2cf6-497d-b8e3-cfa21a36f997-artist-rels.xml\")\n        self.assertTrue('target-credit' in res['artist']['artist-relation-list'][0])\n        self.assertEqual(res['artist']['artist-relation-list'][0][\"target-credit\"], \"TAO\")\n"
  },
  {
    "path": "test/test_mbxml_collection.py",
    "content": "# Tests for parsing of collection queries\n\nimport unittest\nimport os\nimport musicbrainzngs\nfrom test import _common\n\n\nclass UrlTest(unittest.TestCase):\n    \"\"\" Test that the correct URL is generated when a query is made \"\"\"\n\n    def setUp(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n\n        musicbrainzngs.set_useragent(\"test\", \"1\")\n        musicbrainzngs.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainzngs.set_rate_limit(True)\n\n    def testGetCollection(self):\n        musicbrainzngs.get_releases_in_collection(\"0b15c97c-8eb8-4b4f-81c3-0eb24266a2ac\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/collection/0b15c97c-8eb8-4b4f-81c3-0eb24266a2ac/releases\", self.opener.get_url())\n\n        musicbrainzngs.get_works_in_collection(\"898676a6-bc79-4fe2-98ae-79c5940fe1a2\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/collection/898676a6-bc79-4fe2-98ae-79c5940fe1a2/works\", self.opener.get_url())\n\n        musicbrainzngs.get_events_in_collection(\"65cb5dda-44aa-44a8-9c0d-4f99a14ab944\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/collection/65cb5dda-44aa-44a8-9c0d-4f99a14ab944/events\", self.opener.get_url())\n\n        musicbrainzngs.get_places_in_collection(\"9dde4c3c-520a-4bfd-9aae-446c3a04ce0c\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/collection/9dde4c3c-520a-4bfd-9aae-446c3a04ce0c/places\", self.opener.get_url())\n\n        musicbrainzngs.get_recordings_in_collection(\"42bc6dd9-8deb-4bd7-83eb-5dacdb218b38\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/collection/42bc6dd9-8deb-4bd7-83eb-5dacdb218b38/recordings\", self.opener.get_url())\n\n        musicbrainzngs.get_artists_in_collection(\"7e582256-b3ce-421f-82ba-451b0ab080eb\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/collection/7e582256-b3ce-421f-82ba-451b0ab080eb/artists\", self.opener.get_url())\n\n\nclass GetCollectionTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"collection\")\n\n    def testCollectionInfo(self):\n        \"\"\"\n        Test that the id, name and author are given.\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"0b15c97c-8eb8-4b4f-81c3-0eb24266a2ac-releases.xml\")\n\n    def testCollectionReleases(self):\n        \"\"\"\n        Test that the list of releases is given.\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"0b15c97c-8eb8-4b4f-81c3-0eb24266a2ac-releases.xml\")\n        coll = res[\"collection\"]\n        self.assertEqual(coll[\"id\"], \"0b15c97c-8eb8-4b4f-81c3-0eb24266a2ac\")\n        self.assertEqual(coll[\"name\"], \"My Collection\")\n        self.assertEqual(coll[\"editor\"], \"JonnyJD\")\n        self.assertEqual(coll[\"entity-type\"], \"release\")\n        self.assertEqual(coll[\"type\"], \"Release\")\n        self.assertEqual(coll[\"release-count\"], 400)\n        self.assertTrue(\"release-list\" in res[\"collection\"])\n\n    def testCollectionWorks(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"2326c2e8-be4b-4300-acc6-dbd0adf5645b-works.xml\")\n        coll = res[\"collection\"]\n        self.assertEqual(coll[\"id\"], \"2326c2e8-be4b-4300-acc6-dbd0adf5645b\")\n        self.assertEqual(coll[\"name\"], \"work collection\")\n        self.assertEqual(coll[\"editor\"], \"alastairp\")\n        self.assertEqual(coll[\"entity-type\"], \"work\")\n        self.assertEqual(coll[\"type\"], \"Work\")\n        self.assertEqual(coll[\"work-count\"], 1)\n        self.assertEqual(len(coll[\"work-list\"]), 1)\n\n    def testCollectionArtists(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"29611d8b-b3ad-4ffb-acb5-27f77342a5b0-artists.xml\")\n        coll = res[\"collection\"]\n        self.assertEqual(coll[\"id\"], \"29611d8b-b3ad-4ffb-acb5-27f77342a5b0\")\n        self.assertEqual(coll[\"name\"], \"artist collection\")\n        self.assertEqual(coll[\"editor\"], \"alastairp\")\n        self.assertEqual(coll[\"entity-type\"], \"artist\")\n        self.assertEqual(coll[\"type\"], \"Artist\")\n        self.assertEqual(coll[\"artist-count\"], 1)\n        self.assertEqual(len(coll[\"artist-list\"]), 1)\n\n    def testCollectionEvents(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"20562e36-c7cc-44fb-96b4-486d51a1174b-events.xml\")\n        coll = res[\"collection\"]\n        self.assertEqual(coll[\"id\"], \"20562e36-c7cc-44fb-96b4-486d51a1174b\")\n        self.assertEqual(coll[\"name\"], \"event collection\")\n        self.assertEqual(coll[\"editor\"], \"alastairp\")\n        self.assertEqual(coll[\"entity-type\"], \"event\")\n        self.assertEqual(coll[\"type\"], \"Event\")\n        self.assertEqual(coll[\"event-count\"], 1)\n        self.assertEqual(len(coll[\"event-list\"]), 1)\n\n    def testCollectionPlaces(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"855b134e-9a3b-4717-8df8-8c4838d89924-places.xml\")\n        coll = res[\"collection\"]\n        self.assertEqual(coll[\"id\"], \"855b134e-9a3b-4717-8df8-8c4838d89924\")\n        self.assertEqual(coll[\"name\"], \"place collection\")\n        self.assertEqual(coll[\"editor\"], \"alastairp\")\n        self.assertEqual(coll[\"entity-type\"], \"place\")\n        self.assertEqual(coll[\"type\"], \"Place\")\n        self.assertEqual(coll[\"place-count\"], 1)\n        self.assertEqual(len(coll[\"place-list\"]), 1)\n\n    def testCollectionRecordings(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"a91320b2-fd2f-4a93-9e4e-603d16d514b6-recordings.xml\")\n        coll = res[\"collection\"]\n        self.assertEqual(coll[\"id\"], \"a91320b2-fd2f-4a93-9e4e-603d16d514b6\")\n        self.assertEqual(coll[\"name\"], \"recording collection\")\n        self.assertEqual(coll[\"editor\"], \"alastairp\")\n        self.assertEqual(coll[\"entity-type\"], \"recording\")\n        self.assertEqual(coll[\"type\"], \"Recording\")\n        self.assertEqual(coll[\"recording-count\"], 1)\n        self.assertEqual(len(coll[\"recording-list\"]), 1)\n"
  },
  {
    "path": "test/test_mbxml_discid.py",
    "content": "# Tests for parsing of discid queries\n\nimport unittest\nimport os\nimport musicbrainzngs\nfrom test import _common\n\n\nclass UrlTest(unittest.TestCase):\n    \"\"\" Test that the correct URL is generated when a search query is made \"\"\"\n\n    def setUp(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n\n        musicbrainzngs.set_useragent(\"test\", \"1\")\n        musicbrainzngs.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainzngs.set_rate_limit(True)\n\n    def testGetDiscId(self):\n        musicbrainzngs.get_releases_by_discid(\"xp5tz6rE4OHrBafj0bLfDRMGK48-\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/discid/xp5tz6rE4OHrBafj0bLfDRMGK48-\", self.opener.get_url())\n\n        # one include\n        musicbrainzngs.get_releases_by_discid(\"xp5tz6rE4OHrBafj0bLfDRMGK48-\",\n                includes=[\"recordings\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/discid/xp5tz6rE4OHrBafj0bLfDRMGK48-?inc=recordings\", self.opener.get_url())\n\n        # more than one include\n        musicbrainzngs.get_releases_by_discid(\"xp5tz6rE4OHrBafj0bLfDRMGK48-\", includes=[\"artists\", \"recordings\", \"artist-credits\"])\n        expected = \"https://musicbrainz.org/ws/2/discid/xp5tz6rE4OHrBafj0bLfDRMGK48-?inc=artists+recordings+artist-credits\"\n        self.assertEqual(expected, self.opener.get_url())\n\n\nclass GetDiscIdTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"discid\")\n\n    def testDiscId(self):\n        \"\"\"\n        Test that the id attribute of the disc is read.\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"xp5tz6rE4OHrBafj0bLfDRMGK48-.xml\")\n        self.assertEqual(res[\"disc\"][\"id\"], \"xp5tz6rE4OHrBafj0bLfDRMGK48-\")\n\n    def testTrackCount(self):\n        \"\"\"\n        Test that the number of tracks (offset-count) is returned.\n        \"\"\"\n\n        # discid without pregap track\n        res = _common.open_and_parse_test_data(self.datadir, \"xp5tz6rE4OHrBafj0bLfDRMGK48-.xml\")\n        self.assertEqual(res[\"disc\"][\"offset-count\"], 8)\n\n        # discid with pregap track\n        # (the number of tracks does not count the pregap \"track\")\n        res = _common.open_and_parse_test_data(self.datadir, \"f7agNZK1HMQ2WUWq9bwDymw9aHA-.xml\")\n        self.assertEqual(res[\"disc\"][\"offset-count\"], 13)\n\n    def testOffsets(self):\n        \"\"\"\n        Test that the correct list of offsets is returned.\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"xp5tz6rE4OHrBafj0bLfDRMGK48-.xml\")\n        offsets_res = res[\"disc\"][\"offset-list\"]\n        offsets_correct = [182, 33322, 52597, 73510, 98882, 136180, 169185, 187490]\n        for i in range(len(offsets_correct)):\n            self.assertEqual(offsets_res[i], offsets_correct[i])\n            self.assertTrue(isinstance(offsets_res[i], int))\n\n    def testReleaseList(self):\n        \"\"\"\n        Test that a release list of correct size is given.\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"xp5tz6rE4OHrBafj0bLfDRMGK48-.xml\")\n        self.assertEqual(res[\"disc\"][\"release-count\"], 3)\n        self.assertEqual(res[\"disc\"][\"release-count\"], len(res[\"disc\"][\"release-list\"]))\n"
  },
  {
    "path": "test/test_mbxml_event.py",
    "content": "# Tests for parsing of event results\n\nimport unittest\nimport os\nfrom test import _common\n\n\nclass EventTest(unittest.TestCase):\n\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"event\")\n\n    def testCorrectId(self):\n        event_id = \"770fb0b4-0ad8-4774-9275-099b66627355\"\n        res = _common.open_and_parse_test_data(self.datadir, \"%s-place-rels.xml\" % event_id)\n        self.assertEqual(event_id, res[\"event\"][\"id\"])\n\n    def testPlace(self):\n        event_id = \"770fb0b4-0ad8-4774-9275-099b66627355\"\n        res = _common.open_and_parse_test_data(self.datadir, \"%s-place-rels.xml\" % event_id)\n        place = res[\"event\"][\"place-relation-list\"][0][\"place\"]\n        self.assertEqual(\"7643f13a-dcda-4db4-8196-3ffcc1b99ab7\", place[\"id\"])\n        self.assertEqual(\"50.33556\", place[\"coordinates\"][\"latitude\"])\n        self.assertEqual(\"6.9475\", place[\"coordinates\"][\"longitude\"])\n\n    def testType(self):\n        event_id = \"770fb0b4-0ad8-4774-9275-099b66627355\"\n        res = _common.open_and_parse_test_data(self.datadir, \"%s-place-rels.xml\" % event_id)\n        self.assertEqual(\"Concert\", res[\"event\"][\"type\"])\n\n    def testEventElements(self):\n        filename = \"e921686d-ba86-4122-bc3b-777aec90d231-tags-artist-rels.xml\"\n        res = _common.open_and_parse_test_data(self.datadir, filename)\n        e = res[\"event\"]\n        keys = [\"name\", \"life-span\", \"time\", \"setlist\", \"artist-relation-list\", \"tag-list\"]\n        for k in keys:\n            self.assertTrue(k in e, \"key %s in dict\" % (k, ))\n"
  },
  {
    "path": "test/test_mbxml_instrument.py",
    "content": "# -*- coding: UTF-8 -*-\n# Tests for parsing instrument queries\n\nimport unittest\nimport os\nfrom test import _common\n\n\nclass GetInstrumentTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"instrument\")\n\n    def testData(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"9447c0af-5569-48f2-b4c5-241105d58c91.xml\")\n        inst = res[\"instrument\"]\n\n        self.assertEqual(inst[\"id\"], \"9447c0af-5569-48f2-b4c5-241105d58c91\")\n        self.assertEqual(inst[\"name\"], \"bass saxophone\")\n        self.assertEqual(inst[\"type\"], \"Wind instrument\")\n        self.assertTrue(inst[\"description\"].startswith(\"The bass saxophone\"))\n\n    def testAliases(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"6505f98c-f698-4406-8bf4-8ca43d05c36f-aliases.xml\")\n        inst = res[\"instrument\"]\n\n        aliases = inst[\"alias-list\"]\n        self.assertEqual(len(aliases), 14)\n        self.assertEqual(aliases[1][\"locale\"], \"it\")\n        self.assertEqual(aliases[1][\"type\"], \"Instrument name\")\n        self.assertEqual(aliases[1][\"primary\"], \"primary\")\n        self.assertEqual(aliases[1][\"sort-name\"], \"Basso\")\n        self.assertEqual(aliases[1][\"alias\"], \"Basso\")\n\n\n    def testTags(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"6505f98c-f698-4406-8bf4-8ca43d05c36f-tags.xml\")\n        inst = res[\"instrument\"]\n\n        tags = inst[\"tag-list\"]\n        self.assertEqual(len(tags), 3)\n        self.assertEqual(tags[0][\"name\"], \"fixme\")\n        self.assertEqual(tags[0][\"count\"], \"1\")\n\n    def testUrlRels(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"d00cec5f-f9bc-4235-a54f-6639a02d4e4c-url-rels.xml\")\n        inst = res[\"instrument\"]\n\n        rels = inst[\"url-relation-list\"]\n        self.assertEqual(len(rels), 3)\n        self.assertEqual(rels[0][\"type\"], \"information page\")\n        self.assertEqual(rels[0][\"type-id\"], \"0e62afec-12f3-3d0f-b122-956207839854\")\n        self.assertTrue(rels[0][\"target\"].startswith(\"http://en.wikisource\"))\n\n    def testAnnotations(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"d00cec5f-f9bc-4235-a54f-6639a02d4e4c-annotation.xml\")\n        inst = res[\"instrument\"]\n        self.assertEqual(inst[\"annotation\"][\"text\"], \"Hornbostel-Sachs: 412.22\")\n\n    def testInstrumentRels(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"01ba56a2-4306-493d-8088-c7e9b671c74e-instrument-rels.xml\")\n        inst = res[\"instrument\"]\n\n        rels = inst[\"instrument-relation-list\"]\n        self.assertEqual(len(rels), 3)\n        self.assertEqual(rels[1][\"type\"], \"children\")\n        self.assertEqual(rels[1][\"type-id\"], \"12678b88-1adb-3536-890e-9b39b9a14b2d\")\n        self.assertEqual(rels[1][\"target\"], \"ad09a4ed-d1b6-47c3-ac85-acb531244a4d\")\n        self.assertEqual(rels[1][\"instrument\"][\"id\"], \"ad09a4ed-d1b6-47c3-ac85-acb531244a4d\")\n        self.assertTrue(rels[1][\"instrument\"][\"name\"].startswith(b\"kemen\\xc3\\xa7e\".decode(\"utf-8\")))\n\n    def testDisambiguation(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"dabdeb41-560f-4d84-aa6a-cf22349326fe.xml\")\n        inst = res[\"instrument\"]\n        self.assertEqual(inst[\"disambiguation\"], \"lute\")\n"
  },
  {
    "path": "test/test_mbxml_label.py",
    "content": "# Tests for parsing of label queries\n\nimport unittest\nimport os\nfrom test import _common\n\n\nclass GetLabelTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"label\")\n\n    def testLabelAliases(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"022fe361-596c-43a0-8e22-bad712bb9548-aliases.xml\")\n        aliases = res[\"label\"][\"alias-list\"]\n        self.assertEqual(len(aliases), 4)\n\n        a0 = aliases[0]\n        self.assertEqual(a0[\"alias\"], \"EMI\")\n        self.assertEqual(a0[\"sort-name\"], \"EMI\")\n\n        a1 = aliases[1]\n        self.assertEqual(a1[\"alias\"], \"EMI Records (UK)\")\n        self.assertEqual(a1[\"sort-name\"], \"EMI Records (UK)\")\n\n        res = _common.open_and_parse_test_data(self.datadir, \"e72fabf2-74a3-4444-a9a5-316296cbfc8d-aliases.xml\")\n        aliases = res[\"label\"][\"alias-list\"]\n        self.assertEqual(len(aliases), 1)\n\n        a0 = aliases[0]\n        self.assertEqual(a0[\"alias\"], \"Ki/oon Records Inc.\")\n        self.assertEqual(a0[\"sort-name\"], \"Ki/oon Records Inc.\")\n        self.assertEqual(a0[\"begin-date\"], \"2001-10\")\n        self.assertEqual(a0[\"end-date\"], \"2012-04\")\n\n\n"
  },
  {
    "path": "test/test_mbxml_place.py",
    "content": "# Tests for parsing of place results\n\nimport unittest\nimport os\nfrom test import _common\n\n\nclass PlaceTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"place\")\n\n    def testPlace(self):\n        filename = \"0c79cdbb-acd6-4e30-aaa3-a5c8d6b36a48-aliases-tags.xml\"\n        res = _common.open_and_parse_test_data(self.datadir, filename)\n\n        p = res[\"place\"]\n        self.assertEqual(\"All Saints' Church\", p[\"name\"])\n        self.assertEqual(\"East Finchley, Durham Road\", p[\"disambiguation\"])\n        self.assertEqual(\"38 Durham Road, London N2 9DP, United Kingdom\", p[\"address\"])\n        self.assertEqual({\"latitude\": \"51.591812\", \"longitude\": \"-0.159699\"}, p[\"coordinates\"])\n        self.assertEqual(\"f03d09b3-39dc-4083-afd6-159e3f0d462f\", p[\"area\"][\"id\"])\n        self.assertEqual(\"1891\", p[\"life-span\"][\"begin\"])\n        self.assertEqual(\"All Saints' Durham Road\", p[\"alias-list\"][0][\"alias\"])\n        self.assertEqual(\"type=church\", p[\"tag-list\"][0][\"name\"])\n        self.assertEqual(\"1\", p[\"tag-list\"][0][\"count\"])\n\n    def testListFromBrowse(self):\n        filename = \"browse-area-74e50e58-5deb-4b99-93a2-decbb365c07f-annotation.xml\"\n        res = _common.open_and_parse_test_data(self.datadir, filename)\n\n        self.assertEqual(395, res[\"place-count\"])\n        self.assertEqual(25, len(res[\"place-list\"]))\n\n        self.assertTrue(res[\"place-list\"][13][\"annotation\"][\"text\"].startswith(\"was later renamed\"))\n"
  },
  {
    "path": "test/test_mbxml_recording.py",
    "content": "# coding=utf-8\n# Tests for parsing of recording queries\n\nimport unittest\nimport os\nfrom test import _common\n\n\nclass GetRecordingTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"recording\")\n\n    def testRecordingRelationCreditedAs(self):\n        # some performance relations have a \"credited-as\" attribute\n        res = _common.open_and_parse_test_data(self.datadir, \"f606f733-c1eb-43f3-93c1-71994ea611e3-artist-rels.xml\")\n\n        recording = res[\"recording\"]\n        rels = recording[\"artist-relation-list\"]\n\n        self.assertEqual(4, len(rels))\n        # Original attributes\n        attributes = rels[2][\"attribute-list\"]\n        self.assertEqual(\"piano\", attributes[0])\n\n        # New attribute dict format\n        attributes = rels[2][\"attributes\"]\n        expected = {\"attribute\": \"piano\", \"credited-as\": \"Yamaha and Steinway pianos\"}\n        self.assertEqual(expected, attributes[0])\n"
  },
  {
    "path": "test/test_mbxml_release.py",
    "content": "# Tests for parsing of release queries\n\nimport unittest\nimport os\nimport musicbrainzngs\nfrom test import _common\n\n\nclass UrlTest(unittest.TestCase):\n    \"\"\" Test that the correct URL is generated when a search query is made \"\"\"\n\n    def setUp(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n\n        musicbrainzngs.set_useragent(\"test\", \"1\")\n        musicbrainzngs.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainzngs.set_rate_limit(True)\n\n    def testGetRelease(self):\n        musicbrainzngs.get_release_by_id(\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release/5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\", self.opener.get_url())\n\n        # one include\n        musicbrainzngs.get_release_by_id(\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\", includes=[\"artists\"])\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release/5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b?inc=artists\", self.opener.get_url())\n\n        # more than one include\n        musicbrainzngs.get_release_by_id(\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\", includes=[\"artists\", \"recordings\", \"artist-credits\"])\n        expected = \"https://musicbrainz.org/ws/2/release/5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b?inc=artists+recordings+artist-credits\"\n        self.assertEqual(expected, self.opener.get_url())\n\n\nclass GetReleaseTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"release\")\n\n    def testArtistCredit(self):\n        \"\"\"\n        If the artist credit is the same in the track and recording, make sure that\n        the information is replicated in both objects, otherwise have distinct ones.\n        \"\"\"\n\n        # If no artist-credit in the track, copy in the recording one\n        res = _common.open_and_parse_test_data(self.datadir, \"833d4c3a-2635-4b7a-83c4-4e560588f23a-recordings+artist-credits.xml\")\n        tracks = res[\"release\"][\"medium-list\"][0][\"track-list\"]\n        t1 = tracks[1]\n        self.assertEqual(t1[\"artist-credit\"], t1[\"recording\"][\"artist-credit\"])\n        self.assertEqual(\"JT Bruce\", t1[\"artist-credit-phrase\"])\n        self.assertEqual(t1[\"recording\"][\"artist-credit-phrase\"], t1[\"artist-credit-phrase\"])\n\n        # Recording AC is different to track AC\n        res = _common.open_and_parse_test_data(self.datadir, \"fbe4490e-e366-4da2-a37a-82162d2f41a9-recordings+artist-credits.xml\")\n        tracks = res[\"release\"][\"medium-list\"][0][\"track-list\"]\n        t1 = tracks[1]\n        self.assertNotEqual(t1[\"artist-credit\"], t1[\"recording\"][\"artist-credit\"])\n        self.assertEqual(\"H. Lichner\", t1[\"artist-credit-phrase\"])\n        self.assertNotEqual(t1[\"recording\"][\"artist-credit-phrase\"], t1[\"artist-credit-phrase\"])\n\n    def testTrackId(self):\n        \"\"\"\n        Test that the id attribute of tracks is read.\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"212895ca-ee36-439a-a824-d2620cd10461-recordings.xml\")\n        tracks = res[\"release\"][\"medium-list\"][0][\"track-list\"]\n        map(lambda t: self.assertTrue(\"id\" in t), tracks)\n\n    def testTrackLength(self):\n        \"\"\"\n        Test that if there is a track length, then `track_or_recording_length` has\n        that, but if not then fill the value from the recording length\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"b66ebe6d-a577-4af8-9a2e-a029b2147716-recordings.xml\")\n        tracks = res[\"release\"][\"medium-list\"][0][\"track-list\"]\n\n        # No track length and recording length\n        t1 = tracks[0]\n        self.assertTrue(\"length\" not in t1)\n        self.assertEqual(\"180000\", t1[\"recording\"][\"length\"])\n        self.assertEqual(\"180000\", t1[\"track_or_recording_length\"])\n\n        # Track length and recording length same\n        t2 = tracks[1]\n        self.assertEqual(\"279000\", t2[\"length\"])\n        self.assertEqual(\"279000\", t2[\"recording\"][\"length\"])\n        self.assertEqual(\"279000\", t2[\"track_or_recording_length\"])\n\n        # Track length and recording length different\n        t3 = tracks[2]\n        self.assertEqual(\"60000\", t3[\"length\"])\n        self.assertEqual(\"80000\", t3[\"recording\"][\"length\"])\n        self.assertEqual(\"60000\", t3[\"track_or_recording_length\"])\n\n        # No track lengths\n        t4 = tracks[3]\n        self.assertTrue(\"length\" not in t4[\"recording\"])\n        self.assertTrue(\"length\" not in t4)\n        self.assertTrue(\"track_or_recording_length\" not in t4)\n\n    def testTrackTitle(self):\n        pass\n\n    def testTrackNumber(self):\n        \"\"\"\n        Test that track number (number or text) and track position (always an increasing number)\n        are both read properly\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"212895ca-ee36-439a-a824-d2620cd10461-recordings.xml\")\n        tracks = res[\"release\"][\"medium-list\"][0][\"track-list\"]\n        # This release doesn't number intro tracks as numbered tracks,\n        # so position and number get 'out of sync'\n        self.assertEqual(['1', '2', '3'], [t[\"position\"] for t in tracks[:3]])\n        self.assertEqual(['', '1', '2'], [t[\"number\"] for t in tracks[:3]])\n\n        res = _common.open_and_parse_test_data(self.datadir, \"a81f3c15-2f36-47c7-9b0f-f684a8b0530f-recordings.xml\")\n        tracks = res[\"release\"][\"medium-list\"][0][\"track-list\"]\n        self.assertEqual(['1', '2'], [t[\"position\"] for t in tracks])\n        self.assertEqual(['A', 'B'], [t[\"number\"] for t in tracks])\n\n        res = _common.open_and_parse_test_data(self.datadir, \"9ce41d09-40e4-4d33-af0c-7fed1e558dba-recordings.xml\")\n        tracks = res[\"release\"][\"medium-list\"][0][\"data-track-list\"]\n        self.assertEqual(list(map(str, range(1, 199))), [t[\"position\"] for t in tracks])\n        self.assertEqual(list(map(str, range(1, 199))), [t[\"number\"] for t in tracks])\n\n    def testVideo(self):\n        \"\"\"\n        Test that the video attribute is parsed.\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"fe29e7f0-eb46-44ba-9348-694166f47885-recordings.xml\")\n        trackswithoutvideo = res[\"release\"][\"medium-list\"][0][\"track-list\"]\n        trackswithvideo = res[\"release\"][\"medium-list\"][2][\"track-list\"]\n        map(lambda t: self.assertTrue(\"video\" not in [\"recording\"]), trackswithoutvideo)\n        map(lambda t: self.assertEqual(\"true\", t[\"recording\"][\"video\"]), trackswithvideo)\n\n    def testPregapTrack(self):\n        \"\"\"\n        Test that the pregap track is parsed if it exists.\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"8eb2b179-643d-3507-b64c-29fcc6745156-recordings.xml\")\n        medium = res[\"release\"][\"medium-list\"][0]\n        self.assertTrue(\"pregap\" in medium)\n        self.assertEqual(\"0\", medium[\"pregap\"][\"position\"])\n        self.assertEqual(\"0\", medium[\"pregap\"][\"number\"])\n        self.assertEqual(\"35000\", medium[\"pregap\"][\"length\"])\n        self.assertEqual(\"[untitled]\", medium[\"pregap\"][\"recording\"][\"title\"])\n\n    def testDataTracklist(self):\n        \"\"\"\n        Test that data tracklist are parsed.\n        \"\"\"\n        res = _common.open_and_parse_test_data(self.datadir, \"9ce41d09-40e4-4d33-af0c-7fed1e558dba-recordings.xml\")\n        medium = res[\"release\"][\"medium-list\"][0]\n        self.assertTrue(\"data-track-list\" in medium)\n        self.assertEqual(198, len(medium[\"data-track-list\"]))\n"
  },
  {
    "path": "test/test_mbxml_release_group.py",
    "content": "# Tests for parsing of release queries\n\nimport unittest\nimport os\nfrom test import _common\n\n\nclass GetReleaseGroupTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\",\n                \"release-group\")\n\n    def testTypesExist(self):\n        res = _common.open_and_parse_test_data(self.datadir,\n                          \"f52bc6a1-c848-49e6-85de-f8f53459a624.xml\")\n        rg = res[\"release-group\"]\n        self.assertTrue(\"type\" in rg)\n        self.assertTrue(\"primary-type\" in rg)\n        self.assertTrue(\"secondary-type-list\" in rg)\n\n    def testTypesResult(self):\n        res = _common.open_and_parse_test_data(self.datadir,\n                          \"f52bc6a1-c848-49e6-85de-f8f53459a624.xml\")\n        rg = res[\"release-group\"]\n        self.assertEqual(\"Soundtrack\", rg[\"type\"])\n        self.assertEqual(\"Album\", rg[\"primary-type\"])\n        self.assertEqual([\"Soundtrack\"], rg[\"secondary-type-list\"])\n"
  },
  {
    "path": "test/test_mbxml_search.py",
    "content": "import unittest\nimport os\nfrom musicbrainzngs import mbxml\n\n\nDATA_DIR = os.path.join(os.path.dirname(__file__), \"data\")\n\n\nclass SearchArtistTest(unittest.TestCase):\n    def testFields(self):\n        fn = os.path.join(DATA_DIR, \"search-artist.xml\")\n        with open(fn, 'rb') as msg:\n            res = mbxml.parse_message(msg)\n        self.assertEqual(25, len(res[\"artist-list\"]))\n        self.assertEqual(349, res[\"artist-count\"])\n        one = res[\"artist-list\"][0]\n        self.assertEqual(9, len(one.keys()))\n        # Score is a key that is only in search results -\n        # so check for it here\n        self.assertEqual(\"100\", one[\"ext:score\"])\n\n\nclass SearchReleaseTest(unittest.TestCase):\n    def testFields(self):\n        fn = os.path.join(DATA_DIR, \"search-release.xml\")\n        with open(fn, 'rb') as msg:\n            res = mbxml.parse_message(msg)\n        self.assertEqual(25, len(res[\"release-list\"]))\n        self.assertEqual(16739, res[\"release-count\"])\n        one = res[\"release-list\"][0]\n        self.assertEqual(\"100\", one[\"ext:score\"])\n\n        # search results have a medium-list/track-count element\n        self.assertEqual(4, one[\"medium-track-count\"])\n        self.assertEqual(1, one[\"medium-count\"])\n        self.assertEqual(\"CD\", one[\"medium-list\"][0][\"format\"])\n\n\nclass SearchReleaseGroupTest(unittest.TestCase):\n    def testFields(self):\n        fn = os.path.join(DATA_DIR, \"search-release-group.xml\")\n        with open(fn, 'rb') as msg:\n            res = mbxml.parse_message(msg)\n        self.assertEqual(25, len(res[\"release-group-list\"]))\n        self.assertEqual(14641, res[\"release-group-count\"])\n        one = res[\"release-group-list\"][0]\n        self.assertEqual(\"100\", one[\"ext:score\"])\n\n\nclass SearchWorkTest(unittest.TestCase):\n    def testFields(self):\n        fn = os.path.join(DATA_DIR, \"search-work.xml\")\n        with open(fn, 'rb') as msg:\n            res = mbxml.parse_message(msg)\n        self.assertEqual(25, len(res[\"work-list\"]))\n        self.assertEqual(174, res[\"work-count\"])\n        one = res[\"work-list\"][0]\n        self.assertEqual(\"100\", one[\"ext:score\"])\n\n\nclass SearchLabelTest(unittest.TestCase):\n    def testFields(self):\n        fn = os.path.join(DATA_DIR, \"search-label.xml\")\n        with open(fn, 'rb') as msg:\n            res = mbxml.parse_message(msg)\n        self.assertEqual(1, len(res[\"label-list\"]))\n        self.assertEqual(1, res[\"label-count\"])\n        one = res[\"label-list\"][0]\n        self.assertEqual(\"100\", one[\"ext:score\"])\n\n\nclass SearchRecordingTest(unittest.TestCase):\n    def testFields(self):\n        fn = os.path.join(DATA_DIR, \"search-recording.xml\")\n        with open(fn, 'rb') as msg:\n            res = mbxml.parse_message(msg)\n        self.assertEqual(25, len(res[\"recording-list\"]))\n        self.assertEqual(1258, res[\"recording-count\"])\n        one = res[\"recording-list\"][0]\n        self.assertEqual(\"100\", one[\"ext:score\"])\n\n\nclass SearchInstrumentTest(unittest.TestCase):\n    def testFields(self):\n        fn = os.path.join(DATA_DIR, \"search-instrument.xml\")\n        with open(fn, 'rb') as msg:\n            res = mbxml.parse_message(msg)\n        self.assertEqual(23, len(res[\"instrument-list\"]))\n        self.assertEqual(23, res[\"instrument-count\"])\n        one = res[\"instrument-list\"][0]\n        self.assertEqual(\"100\", one[\"ext:score\"])\n        end = res[\"instrument-list\"][-1]\n        self.assertEqual(\"29\", end[\"ext:score\"])\n\n\nclass SearchPlaceTest(unittest.TestCase):\n    def testFields(self):\n        fn = os.path.join(DATA_DIR, \"search-place.xml\")\n        with open(fn, 'rb') as msg:\n            res = mbxml.parse_message(msg)\n        self.assertEqual(14, res[\"place-count\"])\n        self.assertEqual(14, len(res[\"place-list\"]))\n        one = res[\"place-list\"][0]\n        self.assertEqual(\"100\", one[\"ext:score\"])\n        two = res[\"place-list\"][1]\n        self.assertEqual(\"63\", two[\"ext:score\"])\n        self.assertEqual(\"Southampton\", two[\"disambiguation\"])\n\n\nclass SearchEventTest(unittest.TestCase):\n    def testFields(self):\n        fn = os.path.join(DATA_DIR, \"search-event.xml\")\n        with open(fn, 'rb') as msg:\n            res = mbxml.parse_message(msg)\n        self.assertEqual(3, res[\"event-count\"])\n        self.assertEqual(3, len(res[\"event-list\"]))\n        one = res[\"event-list\"][0]\n        self.assertEqual(\"100\", one[\"ext:score\"])\n        two = res[\"event-list\"][1]\n        self.assertEqual(1, len(two[\"place-relation-list\"]))\n"
  },
  {
    "path": "test/test_mbxml_work.py",
    "content": "# coding=utf-8\n# Tests for parsing of work queries\n\nimport unittest\nimport os\nfrom test import _common\n\n\nclass GetWorkTest(unittest.TestCase):\n    def setUp(self):\n        self.datadir = os.path.join(os.path.dirname(__file__), \"data\", \"work\")\n\n    def testWorkAliases(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"80737426-8ef3-3a9c-a3a6-9507afb93e93-aliases.xml\")\n        aliases = res[\"work\"][\"alias-list\"]\n        self.assertEqual(len(aliases), 2)\n\n        a0 = aliases[0]\n        self.assertEqual(a0[\"alias\"], 'Symphonie Nr. 3 Es-Dur, Op. 55 \"Eroica\"')\n        self.assertEqual(a0[\"sort-name\"], 'Symphonie Nr. 3 Es-Dur, Op. 55 \"Eroica\"')\n\n        a1 = aliases[1]\n        self.assertEqual(a1[\"alias\"], 'Symphony No. 3, Op. 55 \"Eroica\"')\n        self.assertEqual(a1[\"sort-name\"], 'Symphony No. 3, Op. 55 \"Eroica\"')\n\n\n        res = _common.open_and_parse_test_data(self.datadir, \"3d7c7cd2-da79-37f4-98b8-ccfb1a4ac6c4-aliases.xml\")\n        aliases = res[\"work\"][\"alias-list\"]\n        self.assertEqual(len(aliases), 10)\n\n        a0 = aliases[0]\n        self.assertEqual(a0[\"alias\"], \"Adagio from Symphony No. 2 in E minor, Op. 27\")\n        self.assertEqual(a0[\"sort-name\"], \"Adagio from Symphony No. 2 in E minor, Op. 27\")\n\n    def testWorkAttributes(self):\n        res = _common.open_and_parse_test_data(self.datadir, \"80737426-8ef3-3a9c-a3a6-9507afb93e93-aliases.xml\")\n        work_attrs = res[\"work\"][\"attribute-list\"]\n        self.assertEqual(len(work_attrs), 1)\n        attr = work_attrs[0]\n\n        expected = {\"attribute\": \"Key\", \"value\": \"E-flat major\"}\n        self.assertEqual(expected, attr)\n\n        res = _common.open_and_parse_test_data(self.datadir, \"8e134b32-99b8-4e96-ae5c-426f3be85f4c-attributes.xml\")\n        work_attrs = res[\"work\"][\"attribute-list\"]\n        self.assertEqual(len(work_attrs), 3)\n        expected = {\"attribute\": \"Makam (Ottoman, Turkish)\", \"value\": b\"H\\xc3\\xbczzam\".decode(\"utf-8\")}\n        self.assertEqual(expected, work_attrs[0])\n        expected = {\"attribute\": \"Form (Ottoman, Turkish)\", \"value\": b\"Pe\\xc5\\x9frev\".decode(\"utf-8\")}\n        self.assertEqual(expected, work_attrs[1])\n        expected = {\"attribute\": \"Usul (Ottoman, Turkish)\", \"value\": \"Fahte\"}\n        self.assertEqual(expected, work_attrs[2])\n\n    def testWorkRelationAttributes(self):\n        # Some relation attributes can contain attributes as well as text\n        res = _common.open_and_parse_test_data(self.datadir, \"72c9aad2-3c95-4e3e-8a01-3974f8fef8eb-series-rels.xml\")\n\n        work = res[\"work\"]\n        rels = work[\"series-relation-list\"]\n\n        self.assertEqual(1, len(rels))\n        # Original attributes\n        attributes = rels[0][\"attribute-list\"]\n        self.assertEqual(\"number\", attributes[0])\n\n        # New attribute dict format\n        attributes = rels[0][\"attributes\"]\n        expected = {\"attribute\": \"number\", \"value\": \"BuxWV 1\"}\n        self.assertEqual(expected, attributes[0])\n"
  },
  {
    "path": "test/test_ratelimit.py",
    "content": "import unittest\nimport time\nimport musicbrainzngs\nfrom musicbrainzngs import musicbrainz\nfrom test._common import Timecop\n\n\nclass RateLimitArgumentTest(unittest.TestCase):\n    def test_invalid_args(self):\n        \"\"\" Passing invalid arguments to set_rate_limit should throw\n            an exception \"\"\"\n        try:\n            musicbrainzngs.set_rate_limit(1, 0)\n            self.fail(\"Required exception wasn't raised\")\n        except ValueError as e:\n            self.assertTrue(\"new_requests\" in str(e))\n\n        try:\n            musicbrainzngs.set_rate_limit(0, 1)\n            self.fail(\"Required exception wasn't raised\")\n        except ValueError as e:\n            self.assertTrue(\"limit_or_interval\" in str(e))\n\n        try:\n            musicbrainzngs.set_rate_limit(1, -1)\n            self.fail(\"Required exception wasn't raised\")\n        except ValueError as e:\n            self.assertTrue(\"new_requests\" in str(e))\n\n        try:\n            musicbrainzngs.set_rate_limit(0, -1)\n            self.fail(\"Required exception wasn't raised\")\n        except ValueError as e:\n            self.assertTrue(\"limit_or_interval\" in str(e))\n\nclass RateLimitingTest(unittest.TestCase):\n    def setUp(self):\n        self.cop = Timecop()\n        self.cop.install()\n\n        @musicbrainz._rate_limit\n        def limited():\n            pass\n        self.func = limited\n\n    def tearDown(self):\n        self.cop.restore()\n\n    def test_do_not_wait_initially(self):\n        time1 = time.time()\n        self.func()\n        time2 = time.time()\n        self.assertAlmostEqual(time1, time2)\n\n    def test_second_rapid_query_waits(self):\n        \"\"\" Performing 2 queries should force a wait \"\"\"\n        self.func()\n        time1 = time.time()\n        self.func()\n        time2 = time.time()\n        self.assertTrue(time2 - time1 >= 1.0)\n\n    def test_second_distant_query_does_not_wait(self):\n        \"\"\" If there is a gap between queries, don't force a wait \"\"\"\n        self.func()\n        time.sleep(1.0)\n        time1 = time.time()\n        self.func()\n        time2 = time.time()\n        self.assertAlmostEqual(time1, time2)\n\nclass BatchedRateLimitingTest(unittest.TestCase):\n    def setUp(self):\n        musicbrainzngs.set_rate_limit(3, 3)\n\n        self.cop = Timecop()\n        self.cop.install()\n\n        @musicbrainz._rate_limit\n        def limited():\n            pass\n        self.func = limited\n\n    def tearDown(self):\n        musicbrainzngs.set_rate_limit(1, 1)\n\n        self.cop.restore()\n\n    def test_initial_rapid_queries_not_delayed(self):\n        time1 = time.time()\n        self.func()\n        self.func()\n        self.func()\n        time2 = time.time()\n        self.assertAlmostEqual(time1, time2)\n\n    def test_overage_query_delayed(self):\n        time1 = time.time()\n        self.func()\n        self.func()\n        self.func()\n        self.func()\n        time2 = time.time()\n        self.assertTrue(time2 - time1 >= 1.0)\n\nclass NoRateLimitingTest(unittest.TestCase):\n    \"\"\" Disable rate limiting \"\"\"\n    def setUp(self):\n        musicbrainzngs.set_rate_limit(False)\n\n        self.cop = Timecop()\n        self.cop.install()\n\n        @musicbrainz._rate_limit\n        def limited():\n            pass\n        self.func = limited\n\n    def tearDown(self):\n        musicbrainzngs.set_rate_limit(True)\n\n        self.cop.restore()\n\n    def test_initial_rapid_queries_not_delayed(self):\n        time1 = time.time()\n        self.func()\n        self.func()\n        self.func()\n        time2 = time.time()\n        self.assertAlmostEqual(time1, time2)\n"
  },
  {
    "path": "test/test_requests.py",
    "content": "import unittest\nimport musicbrainzngs\nfrom musicbrainzngs import musicbrainz\nfrom test import _common\n\n\nclass ArgumentTest(unittest.TestCase):\n    \"\"\"Tests request methods to ensure they're enforcing general parameters\n    (useragent, authentication).\"\"\"\n\n    def setUp(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener.add_handlers_and_return(args)\n        musicbrainz.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainz.set_rate_limit(True)\n\n    def test_no_client(self):\n        musicbrainzngs.set_useragent(\"testapp\", \"0.1\", \"test@example.org\")\n        musicbrainz._mb_request(path=\"foo\", client_required=False)\n        self.assertFalse(\"testapp\" in self.opener.myurl)\n\n    def test_client(self):\n        musicbrainzngs.set_useragent(\"testapp\", \"0.1\", \"test@example.org\")\n        musicbrainz._mb_request(path=\"foo\", client_required=True)\n        self.assertTrue(\"testapp\" in self.opener.myurl)\n\n    def test_false_useragent(self):\n        self.assertRaises(ValueError, musicbrainzngs.set_useragent, \"\", \"0.1\",\n                \"test@example.org\")\n        self.assertRaises(ValueError, musicbrainzngs.set_useragent, \"test\", \"\",\n                \"test@example.org\")\n\n    def test_missing_auth(self):\n        musicbrainz.auth(\"\", \"\")\n        musicbrainz._useragent = \"test\"\n        self.assertRaises(musicbrainzngs.UsageError,\n                musicbrainz._mb_request, path=\"foo\",\n                auth_required=musicbrainz.AUTH_YES)\n\n    def test_missing_useragent(self):\n        musicbrainz._useragent = \"\"\n        self.assertRaises(musicbrainzngs.musicbrainz.UsageError,\n                musicbrainz._mb_request, path=\"foo\")\n\n    def test_auth_headers(self):\n        musicbrainz._useragent = \"test\"\n        musicbrainz.auth(\"user\", \"password\")\n        req = musicbrainz._mb_request(path=\"foo\", auth_required=musicbrainz.AUTH_YES)\n        assert(any([isinstance(handler, musicbrainz._DigestAuthHandler) for handler in self.opener.handlers]))\n\n    def test_auth_headers_ifset(self):\n        musicbrainz._useragent = \"test\"\n        musicbrainz.auth(\"user\", \"password\")\n        req = musicbrainz._mb_request(path=\"foo\", auth_required=musicbrainz.AUTH_IFSET)\n        assert(any([isinstance(handler, musicbrainz._DigestAuthHandler) for handler in self.opener.handlers]))\n\n    def test_auth_headers_ifset_no_user(self):\n        musicbrainz._useragent = \"test\"\n        musicbrainz.auth(\"\", \"\")\n        # if no user and password, auth is not set for AUTH_IFSET\n        req = musicbrainz._mb_request(path=\"foo\", auth_required=musicbrainz.AUTH_IFSET)\n        assert(not any([isinstance(handler, musicbrainz._DigestAuthHandler) for handler in self.opener.handlers]))\n\n\nclass MethodTest(unittest.TestCase):\n    \"\"\"Tests the various _do_mb_* methods to ensure they're setting the\n    using the correct HTTP method.\"\"\"\n\n    def setUp(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n\n        musicbrainz.auth(\"user\", \"password\")\n        musicbrainz.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainz.set_rate_limit(False)\n\n    def test_invalid_method(self):\n        self.assertRaises(ValueError, musicbrainz._mb_request, path=\"foo\",\n                          method=\"HUG\")\n\n    def test_delete(self):\n        musicbrainz._do_mb_delete(\"foo\")\n        self.assertEqual(\"DELETE\", self.opener.request.get_method())\n\n    def test_put(self):\n        musicbrainz._do_mb_put(\"foo\")\n        self.assertEqual(\"PUT\", self.opener.request.get_method())\n\n    def test_post(self):\n        musicbrainz._do_mb_post(\"foo\", \"body\")\n        self.assertEqual(\"POST\", self.opener.request.get_method())\n\n    def test_get(self):\n        musicbrainz._do_mb_query(\"artist\", 1234, [], [])\n        self.assertEqual(\"GET\", self.opener.request.get_method())\n\n\nclass HostnameTest(unittest.TestCase):\n    \"\"\"Test that the protocol, hostname, and port are set as expected\"\"\"\n\n    def setUp(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        musicbrainz.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainz.set_rate_limit(True)\n        musicbrainzngs.set_hostname(\"musicbrainz.org\", use_https=True)\n\n    def test_default_musicbrainz_https(self):\n        musicbrainzngs.get_release_by_id(\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release/5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\", self.opener.get_url())\n\n    def test_set_http(self):\n        musicbrainzngs.set_hostname(\"beta.musicbrainz.org\")\n\n        musicbrainzngs.get_release_by_id(\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\")\n        self.assertEqual(\"http://beta.musicbrainz.org/ws/2/release/5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\", self.opener.get_url())\n\n    def test_set_https(self):\n        musicbrainzngs.set_hostname(\"mbmirror.org\", use_https=True)\n\n        musicbrainzngs.get_release_by_id(\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\")\n        self.assertEqual(\"https://mbmirror.org/ws/2/release/5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\", self.opener.get_url())\n\n    def test_set_port(self):\n        musicbrainzngs.set_hostname(\"localhost:8000\", use_https=False)\n\n        musicbrainzngs.get_release_by_id(\"5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\")\n        self.assertEqual(\"http://localhost:8000/ws/2/release/5e3524ca-b4a1-4e51-9ba5-63ea2de8f49b\", self.opener.get_url())\n"
  },
  {
    "path": "test/test_search.py",
    "content": "import unittest\n\nimport musicbrainzngs\nfrom test import _common\n\n\nclass SearchUrlTest(unittest.TestCase):\n    \"\"\" Test that the correct URL is generated when a search query is made \"\"\"\n\n    def setUp(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n\n        musicbrainzngs.set_useragent(\"a\", \"1\")\n        musicbrainzngs.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainzngs.set_rate_limit(True)\n\n    def test_search_annotations(self):\n        musicbrainzngs.search_annotations(\"Pieds\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/annotation/?query=Pieds\", self.opener.get_url())\n\n        # Query fields\n        musicbrainzngs.search_annotations(entity=\"bdb24cb5-404b-4f60-bba4-7b730325ae47\")\n        # TODO: We escape special characters and then urlencode all query parameters, which may\n        # not be necessary, but MusicBrainz accepts it and appears to return the same value as without\n        expected_query = r'entity:(bdb24cb5\\-404b\\-4f60\\-bba4\\-7b730325ae47)'\n        expected = 'https://musicbrainz.org/ws/2/annotation/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)\n        self.assertEqual(expected, self.opener.get_url())\n\n        # Invalid query field\n        with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):\n            musicbrainzngs.search_annotations(foo=\"value\")\n\n    def test_search_artists(self):\n        musicbrainzngs.search_artists(\"Dynamo Go\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/artist/?query=Dynamo+Go\", self.opener.get_url())\n\n        musicbrainzngs.search_artists(artist=\"Dynamo Go\")\n        expected_query = 'artist:(dynamo go)'\n        expected = 'https://musicbrainz.org/ws/2/artist/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)\n        self.assertEqual(expected, self.opener.get_url())\n\n        # Invalid query field\n        with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):\n            musicbrainzngs.search_artists(foo=\"value\")\n\n    def test_search_events(self):\n        musicbrainzngs.search_events(\"woodstock\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/event/?query=woodstock\", self.opener.get_url())\n\n        musicbrainzngs.search_events(event=\"woodstock\")\n        expected_query = 'event:(woodstock)'\n        expected = 'https://musicbrainz.org/ws/2/event/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)\n        self.assertEqual(expected, self.opener.get_url())\n\n        # Invalid query field\n        with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):\n            musicbrainzngs.search_events(foo=\"value\")\n\n    def test_search_labels(self):\n        musicbrainzngs.search_labels(\"Waysafe\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/label/?query=Waysafe\", self.opener.get_url())\n\n        musicbrainzngs.search_labels(label=\"Waysafe\")\n        expected_query = 'label:(waysafe)'\n        expected = 'https://musicbrainz.org/ws/2/label/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)\n        self.assertEqual(expected, self.opener.get_url())\n\n        # Invalid query field\n        with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):\n            musicbrainzngs.search_labels(foo=\"value\")\n\n    def test_search_places(self):\n        musicbrainzngs.search_places(\"Fillmore\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/place/?query=Fillmore\", self.opener.get_url())\n\n        musicbrainzngs.search_places(place=\"Fillmore\")\n        expected_query = 'place:(fillmore)'\n        expected = 'https://musicbrainz.org/ws/2/place/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)\n        self.assertEqual(expected, self.opener.get_url())\n\n        # Invalid query field\n        with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):\n            musicbrainzngs.search_places(foo=\"value\")\n\n    def test_search_releases(self):\n        musicbrainzngs.search_releases(\"Affordable Pop Music\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release/?query=Affordable+Pop+Music\", self.opener.get_url())\n\n        musicbrainzngs.search_releases(release=\"Affordable Pop Music\")\n        expected_query = 'release:(affordable pop music)'\n        expected = 'https://musicbrainz.org/ws/2/release/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)\n        self.assertEqual(expected, self.opener.get_url())\n\n        # Invalid query field\n        with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):\n            musicbrainzngs.search_releases(foo=\"value\")\n\n    def test_search_release_groups(self):\n        musicbrainzngs.search_release_groups(\"Affordable Pop Music\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/release-group/?query=Affordable+Pop+Music\", self.opener.get_url())\n\n        musicbrainzngs.search_release_groups(releasegroup=\"Affordable Pop Music\")\n        expected_query = 'releasegroup:(affordable pop music)'\n        expected = 'https://musicbrainz.org/ws/2/release-group/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)\n        self.assertEqual(expected, self.opener.get_url())\n\n        # Invalid query field\n        with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):\n            musicbrainzngs.search_release_groups(foo=\"value\")\n\n    def test_search_recordings(self):\n        musicbrainzngs.search_recordings(\"Thief of Hearts\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/recording/?query=Thief+of+Hearts\", self.opener.get_url())\n\n        musicbrainzngs.search_recordings(recording=\"Thief of Hearts\")\n        expected_query = 'recording:(thief of hearts)'\n        expected = 'https://musicbrainz.org/ws/2/recording/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)\n        self.assertEqual(expected, self.opener.get_url())\n\n        # Invalid query field\n        with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):\n            musicbrainzngs.search_recordings(foo=\"value\")\n\n    def test_search_works(self):\n        musicbrainzngs.search_works(\"Fountain City\")\n        self.assertEqual(\"https://musicbrainz.org/ws/2/work/?query=Fountain+City\", self.opener.get_url())\n\n        musicbrainzngs.search_works(work=\"Fountain City\")\n        expected_query = 'work:(fountain city)'\n        expected = 'https://musicbrainz.org/ws/2/work/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)\n        self.assertEqual(expected, self.opener.get_url())\n\n        # Invalid query field\n        with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):\n            musicbrainzngs.search_works(foo=\"value\")\n"
  },
  {
    "path": "test/test_submit.py",
    "content": "import unittest\nimport musicbrainzngs\nfrom musicbrainzngs import musicbrainz\nfrom test import _common\n\n\nclass SubmitTest(unittest.TestCase):\n\n    def setUp(self):\n        self.orig_opener = musicbrainzngs.compat.build_opener\n        musicbrainz.set_useragent(\"test_client\", \"1.0\")\n        musicbrainz.auth(\"user\", \"password\")\n        musicbrainz.set_rate_limit(False)\n\n    def tearDown(self):\n        musicbrainzngs.compat.build_opener = self.orig_opener\n        musicbrainz._useragent = \"\"\n        musicbrainz._client = \"\"\n        musicbrainz.user = \"\"\n        musicbrainz.password = \"\"\n        musicbrainz.set_rate_limit(True)\n\n    def test_submit_tags(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        def make_xml(**kwargs):\n            self.assertEqual({'artist_tags': {'mbid': ['one', 'two']}}, kwargs)\n        oldmake_tag_request = musicbrainz.mbxml.make_tag_request\n        musicbrainz.mbxml.make_tag_request = make_xml\n\n        musicbrainz.submit_tags(artist_tags={\"mbid\": [\"one\", \"two\"]})\n        musicbrainz.mbxml.make_tag_request = oldmake_tag_request\n\n    def test_submit_single_tag(self):\n        self.opener = _common.FakeOpener(\"<response/>\")\n        musicbrainzngs.compat.build_opener = lambda *args: self.opener\n        def make_xml(**kwargs):\n            self.assertEqual({'artist_tags': {'mbid': ['single']}}, kwargs)\n        oldmake_tag_request = musicbrainz.mbxml.make_tag_request\n        musicbrainz.mbxml.make_tag_request = make_xml\n\n        musicbrainz.submit_tags(artist_tags={\"mbid\": \"single\"})\n        musicbrainz.mbxml.make_tag_request = oldmake_tag_request\n\n"
  },
  {
    "path": "tox.ini",
    "content": "[tox]\nenvlist=py27,py37,py38,py39,py310\n\n[testenv]\ncommands=pytest\ndeps=pytest\n\n[gh-actions]\npython =\n    2.7: py27\n    3.7: py37\n    3.8: py38\n    3.9: py39\n    3.10: py310\n\n"
  }
]